From ef86001b04e6f46aee40711356ea096195adb04d Mon Sep 17 00:00:00 2001 From: Jeeves Date: Tue, 29 Apr 2025 06:42:58 -0600 Subject: [PATCH] working graph traversal --- src/main.zig | 108 +++++++++++++-------------------------------------- 1 file changed, 27 insertions(+), 81 deletions(-) diff --git a/src/main.zig b/src/main.zig index 82bf85f..60d646f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -125,6 +125,7 @@ pub const Circuit = struct { } pub fn deinit(self: *Circuit) void { + // std.debug.print("process_order.len {d}\n", .{self.process_order.?.len}); if (self.process_order) |p| self.allocator.free(p); for (0..self.components.items.len) |i| self.components.items[i].deinit(self.allocator); self.components.deinit(self.allocator); @@ -144,7 +145,7 @@ pub const Circuit = struct { pub fn tick(self: *Circuit) !void { if (self.process_order == null) try self.updateProcessOrder(); for (self.process_order.?) |component| { - std.log.debug("processing component: {}", .{component}); + std.log.debug("processing component: {}@{d}", .{ component, self.componentIndex(component).? }); component.process(); } } @@ -178,39 +179,39 @@ pub const Circuit = struct { var component_idx = source_component_idx; dfs: while (true) { - visited[component_idx] = true; - // check each output of the current component for (self.components.items[component_idx].outputs.items) |output| { // check each connection of the current output - for (output.connections.items) |connection| { - std.debug.print("{}\n", .{connection}); + connections: for (output.connections.items) |connection| { + const new_idx = self.componentIndex(connection.component).?; + // std.debug.print("{}@{d}\n", .{ connection, new_idx }); + + // check if component is "ready" + // i.e. it hasn't already been added to the process list, but all its inputs have. + if (visited[new_idx]) continue :connections; + for (connection.component.inputs.items) |input| { + if (input.connection) |input_component| { + if (!visited[self.componentIndex(input_component).?]) { + continue :connections; + } + } + } + + // component is ready, continue the DFS down that branch + try process_order.append(connection.component); + try stack.append(new_idx); + visited[new_idx] = true; + component_idx = new_idx; + continue :dfs; } } - // for (self.components.items[source_component_idx].outputs.items) |output| { - // if (output.connection) |output_to| { - // std.debug.print("checking output {?d}\n", .{self.componentIndex(output_to)}); - // for (output_to.inputs.items) |other_input| { - // const other_idx = self.componentIndex(other_input.connection.?).?; - // std.debug.print("other_idx is visited: {}\n", .{visited[other_idx]}); - // if (!visited[other_idx]) { - // try process_order.append(self.components.items[other_idx]); - // try stack.append(other_idx); - // component_idx = other_idx; - // std.debug.print("continue with {}\n", .{component_idx}); - // continue :dfs; - // } - // } - // } - // } - component_idx = stack.pop() orelse break :dfs; - std.debug.print("backtracking to {}\n", .{component_idx}); + // std.debug.print("backtracking to {}\n", .{component_idx}); } } - std.debug.print("{any}\n", .{visited}); + // std.debug.print("{any}\n", .{visited}); if (self.process_order) |p| self.allocator.free(p); self.process_order = try process_order.toOwnedSlice(); @@ -225,63 +226,6 @@ pub const Circuit = struct { } const ProcessOrder = []*Component; - // pub fn solve(self: *ProcessOrderSolver) ProcessOrder { - // for (self.solved) |*s| s.* = false; - // for (self.circuit.source_components.items) |source_component| { - // var component = source_component; - // while (true) { - // // component.process(); - // // std.debug.print("source component {any}\n\n", .{source_component}); - // const idx = self.componentIndex(component); - // self.solved[idx.?] = true; - // std.debug.print("{}\n", .{component}); - // // std.debug.print("{any}\n", .{component.outputs.items}); - // _ = &component; - // // component = component.outputs.items[0].connection.?; - // next: for (component.outputs.items) |output| { - // if (output.connection) |connection| - // if (self.solved[self.componentIndex(connection).?] == false) - // if (self.componentReady(connection)) { - // component = connection; - // } else { - // continue :next; - // }; - // } - // } - // } - // return &[_]*Component{}; - // } - - // /// whether a component is ready to be solved - // fn componentReady(self: ProcessOrderSolver, component: *Component) bool { - // for (component.inputs.items) |input| { - // if (input.connection) |c| { - // if (self.solved[self.componentIndex(c).?]) - // return false; - // } - // } - // return true; - // } - - // // TODO this is probably broken - // fn componentIndex(self: ProcessOrderSolver, component: *Component) ?usize { - // // for (self.circuit.components.items, 0..) |c, i| { - // // // std.debug.print("{any} == {any}\n", .{ component, &c }); - // // std.debug.print("{*} == {*}\n", .{ component, &c }); - // // // std.debug.print("{s}\n{s}\n{any}\n\n", .{ - // // // std.fmt.fmtSliceHexLower(std.mem.asBytes(component)), - // // // std.fmt.fmtSliceHexLower(std.mem.asBytes(&c)), - // // // std.mem.eql(u8, std.mem.asBytes(component), std.mem.asBytes(&c)), - // // // }); - // // // if (std.mem.eql(u8, std.mem.asBytes(component), std.mem.asBytes(&c))) { - // // if (component == c) { - // // return i; - // // } - // // } - // // return null; - // return std.mem.indexOfScalar(*Component, self.circuit.components.items, component); - // } - // }; }; var null_signal = Signal{}; @@ -296,7 +240,9 @@ pub const Component = struct { deinitFn: *const fn (*Component, std.mem.Allocator) void, pub const Input = struct { + // TODO just allow this to be null and handle that codepath in a user-configurable way signal: *Signal = &null_signal, + // TODO update this to match the Output.Connection interface (without the ArrayList) connection: ?*Component = null, idx: usize = 0, };