From fdf672de4bf08ec71ef80e3f998780843cf831a3 Mon Sep 17 00:00:00 2001 From: Marto Date: Fri, 1 May 2026 20:46:09 +0200 Subject: [PATCH] Fixed splitting quirks when only one intersection is found and the intersection itself is origin node --- src/common/structures.zig | 14 +++++++++++++- src/simulator.zig | 35 +++++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/common/structures.zig b/src/common/structures.zig index ad2bc6a..96c64ac 100644 --- a/src/common/structures.zig +++ b/src/common/structures.zig @@ -3,7 +3,12 @@ const Vector2 = @import("raylib").Vector2; const Road = @import("../infrastructure/road.zig").Road; const Node = @import("../infrastructure/node.zig").Node; -/// Can point to either entity type (node, road, etc.) +/// This is a simple equivalent to something like abstract class, so the simulator class has only one variable +/// which tracks which object is highlighted and the logic that seeks to find the current highlighted class doesn't need +/// to figure out which highlighted entity has priority in case of overlap; +/// given that car can be on node and road, and node itself is on road(s) +/// +/// TLDR: Can point to either entity type (node, road, etc.) pub const Entity = union(enum) { node: *Node, road: *Road, @@ -16,4 +21,11 @@ pub const IntersectionData = struct { pos: Vector2, /// Points to the road where the intersection occured road: *Road, + /// Tracks whether this intersection is actually an origin point + /// (In simple terms this means whether the point/node that intersects is also the start/end node) + /// + /// We do this because the referencing logic is very strict and will return an error + /// if we try to reference something that is already referenced, due to stricter approach helping with + /// earlier bug and error detection + origin: bool, }; \ No newline at end of file diff --git a/src/simulator.zig b/src/simulator.zig index 1790102..2470716 100644 --- a/src/simulator.zig +++ b/src/simulator.zig @@ -239,6 +239,7 @@ pub const Simulator = struct { try intersections.append(self.allocator, .{ .road = road, .pos = start.pos, + .origin = true, }); } @@ -252,6 +253,7 @@ pub const Simulator = struct { const intersection = st.IntersectionData { .road = road, .pos = collision_point, + .origin = false, }; // We put a 0 here, just to satisfy the constructor function, @@ -275,6 +277,7 @@ pub const Simulator = struct { try intersections.append(self.allocator, .{ .road = road, .pos = end.pos, + .origin = true, }); } @@ -295,13 +298,30 @@ pub const Simulator = struct { return; } - // Here we connect the start node with the first intersection node (via road) const first_node = self.node_man.getSelectedNode(self.allocator, intersections[0].pos) catch |err| { std.debug.panic("Failed to add the first node of the intersection: {}\n", .{err}); }; - self.road_man.addRoad(self.allocator, start, first_node) catch |err| { - std.debug.panic("Failed to add a road of origin (start) node and the first intersection node: {}\n", .{err}); - }; + + var override_node: ?*Node = null; + // This if statement essentially checks that IF we only have one intersection and that one is one of the origin nodes, + // it means that we have to enable one of start => intersection, or, end => intersection road building logic + // + // However due to the possibility that we link the road to itself (intersection[0] is start that we then connect + // that one to start node; so intersection[0] => start = start => start), + // we have to essentially realise which node is that first intersection and essentially store that info and only + // let the opposite node form a road with the intersection + // and that is what override_node, override_start and override_end variables are all about + if (intersections.len == 1 and intersections[0].origin) { + override_node = if (first_node == start) end else start; + } + + const override_start = override_node != null and override_node.? == start; + if (!intersections[0].origin or override_start) { + // Here we connect the start node with the first intersection node (via road) + self.road_man.addRoad(self.allocator, start, first_node) catch |err| { + std.debug.panic("Failed to add a road of origin (start) node and the first intersection node: {}\n", .{err}); + }; + } for (0..intersections.len) |i| { const intersection = intersections[i]; @@ -355,12 +375,15 @@ pub const Simulator = struct { }; } + const override_end = override_node != null and override_node.? == end; + // Finally we create final road by connecting last intersection node to the end origin node - const final_intersection_pos = intersections[intersections.len - 1].pos; - const final_intersection_node = self.node_man.getSelectedNode(self.allocator, final_intersection_pos) catch |err| { + const final_intersection = intersections[intersections.len - 1]; + const final_intersection_node = self.node_man.getSelectedNode(self.allocator, final_intersection.pos) catch |err| { std.debug.panic("Failed to create node based on last intersection position: {}\n", .{err}); }; + if (final_intersection.origin and !override_end) return; self.road_man.addRoad(self.allocator, final_intersection_node, end) catch |err| { std.debug.panic("Failed to create a road of final intersection and end origin node: {}\n", .{err}); };