diff --git a/src/main.zig b/src/main.zig index d31c910..82bf85f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -43,34 +43,34 @@ pub fn main() !void { and1.arithmetic_mode = true; and2.arithmetic_mode = true; - battery1.component.connect(0, &or3.component, 1); - battery1.component.connect(0, &or4.component, 1); - battery1.component.connect(0, &or5.component, 1); + try circuit.connectComponents(&battery1.component, 0, &or3.component, 1); + try circuit.connectComponents(&battery1.component, 0, &or4.component, 1); + try circuit.connectComponents(&battery1.component, 0, &or5.component, 1); - battery2.component.connect(0, &or6.component, 0); - battery2.component.connect(0, &or7.component, 0); - battery2.component.connect(0, &or8.component, 0); + try circuit.connectComponents(&battery2.component, 0, &or6.component, 0); + try circuit.connectComponents(&battery2.component, 0, &or7.component, 0); + try circuit.connectComponents(&battery2.component, 0, &or8.component, 0); - battery3.component.connect(0, &and1.component, 0); - battery3.component.connect(0, &and2.component, 0); + try circuit.connectComponents(&battery3.component, 0, &and1.component, 0); + try circuit.connectComponents(&battery3.component, 0, &and2.component, 0); - not1.component.connect(0, &or3.component, 0); - not1.component.connect(0, &or1.component, 0); - not1.component.connect(0, &or1.component, 1); + try circuit.connectComponents(¬1.component, 0, &or3.component, 0); + try circuit.connectComponents(¬1.component, 0, &or1.component, 0); + try circuit.connectComponents(¬1.component, 0, &or1.component, 1); - or1.component.connect(0, &or4.component, 0); - or1.component.connect(0, &or2.component, 0); - or1.component.connect(0, &or2.component, 1); - or2.component.connect(0, &or5.component, 0); + try circuit.connectComponents(&or1.component, 0, &or4.component, 0); + try circuit.connectComponents(&or1.component, 0, &or2.component, 0); + try circuit.connectComponents(&or1.component, 0, &or2.component, 1); + try circuit.connectComponents(&or2.component, 0, &or5.component, 0); - or3.component.connect(0, &or6.component, 1); - or4.component.connect(0, &or7.component, 1); - or5.component.connect(0, &or8.component, 1); + try circuit.connectComponents(&or3.component, 0, &or6.component, 1); + try circuit.connectComponents(&or4.component, 0, &or7.component, 1); + try circuit.connectComponents(&or5.component, 0, &or8.component, 1); - or6.component.connect(0, &and1.component, 1); - and1.component.connect(0, &or1.component, 2); - or7.component.connect(0, &and2.component, 1); - and2.component.connect(0, &or2.component, 2); + try circuit.connectComponents(&or6.component, 0, &and1.component, 1); + try circuit.connectComponents(&and1.component, 0, &or1.component, 2); + try circuit.connectComponents(&or7.component, 0, &and2.component, 1); + try circuit.connectComponents(&and2.component, 0, &or2.component, 2); try circuit.tick(); @@ -111,20 +111,21 @@ pub fn main() !void { pub const Circuit = struct { allocator: std.mem.Allocator, components: Components, - source_components: Components, + + process_order: ?ProcessOrder = null, const Components = std.ArrayListUnmanaged(*Component); + const ComponentIndex = u32; pub fn init(allocator: std.mem.Allocator) Circuit { return .{ .allocator = allocator, .components = Components.empty, - .source_components = Components.empty, }; } pub fn deinit(self: *Circuit) void { - self.source_components.deinit(self.allocator); + 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); } @@ -133,68 +134,154 @@ pub const Circuit = struct { var c = try T.init(self.allocator); errdefer c.component.deinit(self.allocator); try self.components.append(self.allocator, &c.component); - if (T == Battery) try self.source_components.append(self.allocator, &c.component); return c; } + pub fn connectComponents(self: *Circuit, from: *Component, from_idx: usize, to: *Component, to_idx: usize) !void { + try from.connect(self.allocator, from_idx, to, to_idx); + } + pub fn tick(self: *Circuit) !void { - var process_order_solver = try ProcessOrderSolver.init(self); - defer process_order_solver.deinit(); - const process_order = process_order_solver.solve(); - _ = process_order; + if (self.process_order == null) try self.updateProcessOrder(); + for (self.process_order.?) |component| { + std.log.debug("processing component: {}", .{component}); + component.process(); + } + } + + fn updateProcessOrder(self: *Circuit) !void { + var process_order = std.ArrayList(*Component).init(self.allocator); + errdefer process_order.deinit(); + + const visited = try self.allocator.alloc(bool, self.components.items.len); + defer self.allocator.free(visited); + + // find components with nonexistant or disconnected inputs + var source_components = std.ArrayList(ComponentIndex).init(self.allocator); + defer source_components.deinit(); + source: for (self.components.items) |component| { + for (component.inputs.items) |input| + if (input.connection != null) + continue :source; + + const idx = self.componentIndex(component).?; + try process_order.append(component); + visited[idx] = true; + try source_components.append(idx); + } + + // do multiple Depth First Searches (with extra steps) once per source component + for (source_components.items) |source_component_idx| { + var stack = std.ArrayList(ComponentIndex).init(self.allocator); + defer stack.deinit(); + + 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}); + } + } + + // 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("{any}\n", .{visited}); + + if (self.process_order) |p| self.allocator.free(p); + self.process_order = try process_order.toOwnedSlice(); + } + + fn componentIndex(self: *Circuit, component: *Component) ?ComponentIndex { + const idx = std.mem.indexOfScalar(*Component, self.components.items, component); + if (idx) |i| + return @intCast(i) + else + return null; } const ProcessOrder = []*Component; - const ProcessOrderSolver = struct { - circuit: *Circuit, - solved: []bool, + // 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{}; + // } - pub fn init(circuit: *Circuit) !ProcessOrderSolver { - return .{ - .circuit = circuit, - .solved = try circuit.allocator.alloc(bool, circuit.components.items.len), - }; - } + // /// 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; + // } - pub fn deinit(self: *ProcessOrderSolver) void { - self.circuit.allocator.free(self.solved); - } - - pub fn solve(self: *ProcessOrderSolver) ProcessOrder { - for (self.circuit.source_components.items) |source_component| { - var component = source_component; - // while (true) blk: { - // 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.?; - // } - } - return &[_]*Component{}; - } - - 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); - } - }; + // // 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{}; @@ -215,8 +302,13 @@ pub const Component = struct { }; pub const Output = struct { signal: Signal = .{}, - connection: ?*Component = null, - idx: usize = 0, + connections: Connections = .empty, + + pub const Connections = std.ArrayListUnmanaged(Connection); + pub const Connection = struct { + component: *Component, + idx: usize, + }; }; const Inputs = std.ArrayListUnmanaged(Input); const Outputs = std.ArrayListUnmanaged(Output); @@ -249,6 +341,8 @@ pub const Component = struct { pub fn deinit(self: *Component, allocator: std.mem.Allocator) void { self.inputs.deinit(allocator); + for (self.outputs.items) |*output| + output.connections.deinit(allocator); self.outputs.deinit(allocator); self.deinitFn(self, allocator); } @@ -277,12 +371,17 @@ pub const Component = struct { }; } - pub fn connect(self: *Component, self_idx: usize, to: *Component, to_idx: usize) void { - to.inputs.items[to_idx] = .{ - .signal = &self.outputs.items[self_idx].signal, - .connection = self, - .idx = self_idx, - }; + fn connect(self: *Component, allocator: std.mem.Allocator, self_idx: usize, to: *Component, to_idx: usize) !void { + const input = &to.inputs.items[to_idx]; + input.signal = &self.outputs.items[self_idx].signal; + input.connection = self; + input.idx = self_idx; + + const output = &self.outputs.items[self_idx]; + try output.connections.append(allocator, .{ + .component = to, + .idx = to_idx, + }); } pub fn format(