Files
odin-road-pathfinding/src/infrastructure_helpers.odin
Marto 05b7b28f5c Replaced all u32 instances with uint, implemented road length,
implemented basic pathing checks/algorithms, implemented entities id
display for easier debugging
2026-04-27 22:24:06 +02:00

146 lines
4.2 KiB
Odin

package main
import "core:math"
import rl "vendor:raylib"
import "core:math/rand"
import "common"
import inf "infrastructure"
import v "vehicles"
// This function only returns the index to the node or if it doesn't exist bool in the tuple is false
@private
get_node_index_if_exists :: proc(self: ^Simulator, pos: rl.Vector2) -> (uint, bool) {
for &node, index in self.nodes {
if inf.node_within_snapping_radius(&node, pos) do return uint(index), true
}
return 0, false
}
// Given position, the function will attempt the return the pointer to the node in near vicinity,
// or if unsuccesful manually creating the node based on the position in the list and then returning the pointer to it
@private
get_node_or_new :: proc(self: ^Simulator, pos: rl.Vector2) -> uint {
if node, ok := get_node_index_if_exists(self, pos); ok do return node
node := inf.node_init(pos)
append(&self.nodes, node)
return uint(len(self.nodes) - 1)
}
// Attempts to update node reference to the road;
// Returns false if the old reference doesn't exist
@private
update_node_reference :: proc(self: ^Simulator, road_to_update: uint, old_ref: uint, new_ref: uint) -> bool {
road := &self.roads[road_to_update]
for i in 0..<len(road.nodes) {
if road.nodes[i] != old_ref do continue
road.nodes[i] = new_ref
inf.node_unreference_road(&self.nodes[old_ref], road_to_update)
append(&self.nodes[new_ref].roads, road_to_update)
return true
}
return false
}
// Function that allows deleting of any entity within the entity list (nodes, roads, etc.) while ensuring valid references
// Returns swapped entities if they exist
@private
delete_entity :: proc(self: ^Simulator, entity_index: uint, type: common.Entity) -> ([2]uint, bool) {
mlen: uint
// Stores data about old and new index in case the deleted index is not last, meaning the swap occurs
index_change: [2]uint
// Tracks whether the removal of node/road will cause a swap in the (dynamic) array
// and thus forcing the pre-swapped reference to be updated
swap_made: bool
switch type {
case .Node:
mlen = uint(len(self.nodes))
case .Road:
mlen = uint(len(self.roads))
case .Car:
mlen = uint(len(self.cars))
}
last := mlen - 1
if entity_index != last {
index_change = {last, entity_index}
swap_made = true
}
switch type {
case .Node:
// get cars that are on that node
for i in 0..<len(self.cars) {
pos := self.cars[i].pos
if pos.type != .Node || pos.ref != entity_index do continue
delete_entity(self, uint(i), .Car)
}
unordered_remove(&self.nodes, entity_index)
if !swap_made do return {}, false
for &road in self.roads do inf.road_update_node_reference(&road, index_change[0], index_change[1])
for &car in self.cars do v.car_update_node_reference(&car, index_change[0], index_change[1])
return index_change, true
case .Road:
// get cars that are on that road
for i in 0..<len(self.cars) {
pos := self.cars[i].pos
if pos.type != .Road || pos.ref != entity_index do continue
delete_entity(self, uint(i), .Car)
}
unordered_remove(&self.roads, entity_index)
if !swap_made do return {}, false
for &node in self.nodes do inf.node_update_road_reference(&node, index_change[0], index_change[1])
return index_change, true
case .Car:
unordered_remove(&self.cars, entity_index)
if !swap_made do return {}, false
// So far NOT needed as we don't reference the cars anywhere YET
// In the future this might be the cause for failure!!!
}
return {}, false
}
// Returns a random node that has no cars on it
get_free_node :: proc(self: ^Simulator) -> Maybe(uint) {
car_occupied_nodes: [dynamic]uint
for car in self.cars {
if car.pos.type != .Node do continue
if common.list_contains(car_occupied_nodes[:], car.pos.ref) do continue
append(&car_occupied_nodes, car.pos.ref)
}
if len(car_occupied_nodes) == len(self.nodes) do return nil
for {
node := rand.uint_max(uint(len(self.nodes)))
if !common.list_contains(car_occupied_nodes[:], node) do return node
}
}
calculate_road_length :: proc(self: ^Simulator, start: uint, end: uint) -> f32 {
start_pos := self.nodes[start].pos
end_pos := self.nodes[end].pos
x_diff := end_pos.x - start_pos.x
y_diff := end_pos.y - start_pos.y
len := math.sqrt(x_diff * x_diff - y_diff * y_diff)
return len
}