working graph traversal

This commit is contained in:
Jeeves 2025-04-29 06:42:58 -06:00
parent 9836866ec5
commit ef86001b04

View file

@ -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,
};