From 620d3b56e05ccb66128db432ba3a2ec7bb7a61b3 Mon Sep 17 00:00:00 2001 From: Marto Date: Mon, 27 Apr 2026 09:42:50 +0200 Subject: [PATCH] Pathfinding initial implementation [2 errors] --- src/common/utils.odin | 15 ++++++++++++ src/infrastructure_helpers.odin | 15 ++++++++++++ src/pathfinding.odin | 43 +++++++++++++++++++++++++++++++++ src/system/pathfinding.odin | 11 --------- src/vehicles/car.odin | 23 +++++++++--------- 5 files changed, 84 insertions(+), 23 deletions(-) create mode 100644 src/common/utils.odin create mode 100644 src/pathfinding.odin delete mode 100644 src/system/pathfinding.odin diff --git a/src/common/utils.odin b/src/common/utils.odin new file mode 100644 index 0000000..885b36b --- /dev/null +++ b/src/common/utils.odin @@ -0,0 +1,15 @@ +package common + +// Generic contains function for an (dynamic) array +list_contains :: proc(list: []$T, element: T) -> bool { + for el in list do if el == element do return true + + return false +} + +// Inserts element into the list after asserting that element is not already within +insert_if_not_exists :: proc(list: ^[]$T, element: T) { + if list_contains(list, element) do return + + append(list, element) +} \ No newline at end of file diff --git a/src/infrastructure_helpers.odin b/src/infrastructure_helpers.odin index df974c2..b8ce09b 100644 --- a/src/infrastructure_helpers.odin +++ b/src/infrastructure_helpers.odin @@ -1,6 +1,7 @@ package main import rl "vendor:raylib" +import "core:math/rand" import "common" import inf "infrastructure" @@ -99,5 +100,19 @@ delete_entity :: proc(self: ^Simulator, entity_index: u32, type: common.Entity) // Returns a random node that has no cars on it get_free_node :: proc(self: ^Simulator) -> u32 { + car_occupied_nodes: [dynamic]u32 + for car in self.cars { + node, ok := car.node_pos.? + if !ok do continue + + if common.list_contains(car_occupied_nodes[:], node) do continue + append(&car_occupied_nodes, node) + } + + for { + node := rand.uint32_max(u32(len(self.nodes))) + + if !common.list_contains(car_occupied_nodes[:], node) do return node + } } \ No newline at end of file diff --git a/src/pathfinding.odin b/src/pathfinding.odin new file mode 100644 index 0000000..5235044 --- /dev/null +++ b/src/pathfinding.odin @@ -0,0 +1,43 @@ +package main + +import "common" +import inf "infrastructure" + +// Returns path to destination node => road => node +get_path_to_destination :: proc(self: ^Simulator, source: u32, destination: u32) -> []u32 { + source_node := self.nodes[source] + destination_node := self.nodes[destination] + + return nil +} + +// Returns if path is reachable from node => destination +get_destination_reachable :: proc(self: ^Simulator, node_to_search: u32, destination: u32, nodes_to_ignore: ^[]u32) -> bool { + if !self.nodes[node_to_search].enabled || common.list_contains(nodes_to_ignore[:], node_to_search) do return false + append(nodes_to_ignore, node_to_search) + + if node_to_search == destination do return true + for node in get_neighbouring_nodes(self, node_to_search) { + if get_destination_reachable(self, node, destination, nodes_to_ignore) do return true + } + + return false +} + +@(private="file") +get_neighbouring_nodes :: proc(self: ^Simulator, node_index: u32) -> []u32 { + node := self.nodes[node_index] + neighbour_nodes := make([dynamic]u32, 0, len(node.roads)) + + for road_index in node.roads { + road := self.roads[road_index] + + // We pick the node that is not the original node with which we reached the node + // But rather the other node, on the end + next_node := road.nodes[0] == node_index ? road.nodes[1] : road.nodes[0] + + if !common.list_contains(neighbour_nodes[:], next_node) do append(&neighbour_nodes, next_node) + } + + return neighbour_nodes[:] +} \ No newline at end of file diff --git a/src/system/pathfinding.odin b/src/system/pathfinding.odin deleted file mode 100644 index c43bc05..0000000 --- a/src/system/pathfinding.odin +++ /dev/null @@ -1,11 +0,0 @@ -package system - -import inf "../infrastructure" - -get_path_to_destination :: proc(source: u32, destination: u32, nodes: []inf.Node) { - source_node := nodes[source] - destination_node := nodes[destination] - - -} - diff --git a/src/vehicles/car.odin b/src/vehicles/car.odin index 45c295e..330f797 100644 --- a/src/vehicles/car.odin +++ b/src/vehicles/car.odin @@ -19,32 +19,31 @@ Car :: struct { // Car's destination node destination: Maybe(u32), // Tracks on which node car has been last - node_pos: u32, + // + // if null car is not on node + node_pos: Maybe(u32), + // if null car is not on road road_pos: Maybe(u32), + // tracks absolute pos actual_pos: rl.Vector2, } // Constructor -car_init :: proc(nodes: []inf.Node) -> Car { - rand_origin := rand.uint32_max(nodes_len) - +car_init :: proc(node: u32, nodes: []inf.Node) -> Car { return { fuel_level = common.FUEL_MAX, max_speed = common.CAR_MAX_SPEED, - origin = rand_origin, - node_pos = rand_origin, - actual_pos = + origin = node, + node_pos = node, + actual_pos = nodes[node].pos } } // Sets a (valid) route for the car // -// Does NOT guarantee the route is reachable (TODO?) +// Does NOT guarantee the route is reachable (TODO!) car_set_route :: proc(self: ^Car, nodes_len: u32) { - for self.origin == self.destination { - self.destination = rand.uint32_max(nodes_len) - } - + for self.origin == self.destination do self.destination = rand.uint32_max(nodes_len) } // Updates (origin and destination) node reference