diff --git a/src/main.zig b/src/main.zig index 75c6db6..4feb37d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -12,7 +12,7 @@ pub fn main() !void { var not1 = try circuit.addComponent(Not); not1.invert_output = false; - not1.component.inputs.items[0] = &input; // manually set the input here + not1.component.inputs.items[0] = .{ .signal = &input }; // manually set the input here var battery1 = try circuit.addComponent(Battery); var battery2 = try circuit.addComponent(Battery); @@ -72,25 +72,40 @@ pub fn main() !void { or7.component.connect(0, &and2.component, 1); and2.component.connect(0, &or2.component, 2); - battery1.component.process(); - battery2.component.process(); - battery3.component.process(); - not1.component.process(); - or3.component.process(); - or6.component.process(); - and1.component.process(); - or1.component.process(); - or4.component.process(); - or7.component.process(); - and2.component.process(); - or2.component.process(); - or5.component.process(); - or8.component.process(); + try circuit.tick(); - std.debug.print("Input:\n{}\n\n", .{input}); - std.debug.print("{}\n{}\n\n", .{ or1.component.outputs.items[0], or2.component.outputs.items[0] }); - std.debug.print("{}\n{}\n{}\n\n", .{ or3.component.outputs.items[0], or4.component.outputs.items[0], or5.component.outputs.items[0] }); - std.debug.print("{}\n{}\n{}\n{}\n{}\n\n", .{ or6.component.outputs.items[0], and1.component.outputs.items[0], or7.component.outputs.items[0], and2.component.outputs.items[0], or8.component.outputs.items[0] }); + // battery1.component.process(); + // battery2.component.process(); + // battery3.component.process(); + // not1.component.process(); + // or3.component.process(); + // or6.component.process(); + // and1.component.process(); + // or1.component.process(); + // or4.component.process(); + // or7.component.process(); + // and2.component.process(); + // or2.component.process(); + // or5.component.process(); + // or8.component.process(); + + // std.debug.print("Input:\n{}\n\n", .{input}); + // std.debug.print("{}\n{}\n\n", .{ + // or1.component.outputs.items[0].signal, + // or2.component.outputs.items[0].signal, + // }); + // std.debug.print("{}\n{}\n{}\n\n", .{ + // or3.component.outputs.items[0].signal, + // or4.component.outputs.items[0].signal, + // or5.component.outputs.items[0].signal, + // }); + // std.debug.print("{}\n{}\n{}\n{}\n{}\n\n", .{ + // or6.component.outputs.items[0].signal, + // and1.component.outputs.items[0].signal, + // or7.component.outputs.items[0].signal, + // and2.component.outputs.items[0].signal, + // or8.component.outputs.items[0].signal, + // }); } pub const Circuit = struct { @@ -116,11 +131,61 @@ pub const Circuit = struct { var c = try T.init(self.allocator); errdefer c.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 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; + } + const Components = std.ArrayListUnmanaged(Component); const SourceComponents = std.ArrayListUnmanaged(*Component); + + const ProcessOrder = []*Component; + const ProcessOrderSolver = struct { + circuit: *Circuit, + solved: []bool, + + pub fn init(circuit: *Circuit) !ProcessOrderSolver { + return .{ + .circuit = circuit, + .solved = try circuit.allocator.alloc(bool, circuit.components.items.len), + }; + } + + 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(); + self.solved[self.componentIndex(component).?] = true; + component = component.outputs.items[0].connection.?; + std.debug.print("{any}\n", .{component}); + // } + } + 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 }); + if (component == &c) { + std.debug.print("component index {d}\n", .{i}); + return i; + } + } + return null; + // return std.mem.indexOfScalar(Component, self.circuit.components.items, component.*); + } + }; }; var null_signal = Signal{}; @@ -135,12 +200,12 @@ pub const Component = struct { var inputs = Inputs.empty; errdefer inputs.deinit(allocator); try inputs.resize(allocator, inputs_len); - for (0..inputs.items.len) |i| inputs.items[i] = &null_signal; + for (0..inputs.items.len) |i| inputs.items[i] = .{}; var outputs = Outputs.empty; errdefer outputs.deinit(allocator); try outputs.resize(allocator, outputs_len); - for (0..outputs.items.len) |i| outputs.items[i] = Signal{}; + for (0..outputs.items.len) |i| outputs.items[i] = .{}; return .{ .inputs = inputs, @@ -159,32 +224,53 @@ pub const Component = struct { } // TODO allow inserting the new elements at an arbitrary index + // TODO ensure this won't break the opposide side's connections pub fn setNumInputs(self: *Component, allocator: std.mem.Allocator, new_len: usize) !void { const old_len = self.inputs.items.len; try self.inputs.resize(allocator, new_len); if (new_len > old_len) for (old_len..new_len) |i| { - self.inputs.items[i] = &null_signal; + self.inputs.items[i] = .{}; }; } // TODO allow inserting the new elements at an arbitrary index // TODO is this allocating the new output Signals on the stack or dumbthing? + // TODO ensure this won't break the opposide side's connections pub fn setNumOutputs(self: *Component, allocator: std.mem.Allocator, new_len: usize) !void { const old_len = self.outputs.items.len; try self.outputs.resize(allocator, new_len); if (new_len > old_len) for (old_len..new_len) |i| { - self.outputs.items[i] = Signal{}; + self.outputs.items[i] = .{}; }; } pub fn connect(self: *Component, self_idx: usize, to: *Component, to_idx: usize) void { - to.inputs.items[to_idx] = &self.outputs.items[self_idx]; + to.inputs.items[to_idx] = .{ + .signal = &self.outputs.items[self_idx].signal, + .connection = self, + .idx = self_idx, + }; } - pub const Input = *Signal; - pub const Output = Signal; + pub const Input = struct { + signal: *Signal = &null_signal, + connection: ?*Component = null, + idx: usize = 0, + }; + pub const Output = struct { + signal: Signal = .{}, + connection: ?*Component = null, + idx: usize = 0, + }; const Inputs = std.ArrayListUnmanaged(Input); const Outputs = std.ArrayListUnmanaged(Output); + + // const Connection = struct { + // from: *Component, + // from_idx: usize, + // to: *Component, + // to_idx: usize, + // }; }; pub const Signal = struct { @@ -225,8 +311,8 @@ pub const Battery = struct { pub fn process(component: *Component) void { const self: *Battery = @fieldParentPtr("component", component); - component.outputs.items[0].digital = @intFromFloat(std.math.sign(self.value)); - component.outputs.items[0].analog = self.value; + component.outputs.items[0].signal.digital = @intFromFloat(std.math.sign(self.value)); + component.outputs.items[0].signal.analog = self.value; } }; @@ -248,13 +334,13 @@ pub const Not = struct { pub fn process(component: *Component) void { const self: *Not = @fieldParentPtr("component", component); if (self.invert_output) { - component.outputs.items[0].digital = 1 - @as(i2, @intCast(@abs(component.inputs.items[0].digital))); - component.outputs.items[0].analog = 1.0 - @abs(component.inputs.items[0].analog); + component.outputs.items[0].signal.digital = 1 - @as(i2, @intCast(@abs(component.inputs.items[0].signal.digital))); + component.outputs.items[0].signal.analog = 1.0 - @abs(component.inputs.items[0].signal.analog); } else { - component.outputs.items[0].digital = component.inputs.items[0].digital; - component.outputs.items[0].analog = component.inputs.items[0].analog; + component.outputs.items[0].signal.digital = component.inputs.items[0].signal.digital; + component.outputs.items[0].signal.analog = component.inputs.items[0].signal.analog; } - component.outputs.items[0].analog = std.math.clamp(component.outputs.items[0].analog, -1.0, 1.0); + component.outputs.items[0].signal.analog = std.math.clamp(component.outputs.items[0].signal.analog, -1.0, 1.0); } }; @@ -279,25 +365,25 @@ pub const And = struct { pub fn process(component: *Component) void { const self: *And = @fieldParentPtr("component", component); if (self.arithmetic_mode) { - component.outputs.items[0].digital = component.inputs.items[0].digital; - component.outputs.items[0].analog = component.inputs.items[0].analog; + component.outputs.items[0].signal.digital = component.inputs.items[0].signal.digital; + component.outputs.items[0].signal.analog = component.inputs.items[0].signal.analog; for (component.inputs.items[1..]) |input| { - component.outputs.items[0].digital = 0; // TODO - component.outputs.items[0].analog *= input.analog; + component.outputs.items[0].signal.digital = 0; // TODO + component.outputs.items[0].signal.analog *= input.signal.analog; } } else { - component.outputs.items[0].digital = component.inputs.items[0].digital; - component.outputs.items[0].analog = component.inputs.items[0].analog; + component.outputs.items[0].signal.digital = component.inputs.items[0].signal.digital; + component.outputs.items[0].signal.analog = component.inputs.items[0].signal.analog; for (component.inputs.items[1..]) |input| { - component.outputs.items[0].digital = 0; // TODO - component.outputs.items[0].analog = switch (std.math.order(@abs(component.outputs.items[0].analog), @abs(input.analog))) { - .lt => component.outputs.items[0].analog, - .eq => @min(component.outputs.items[0].analog, input.analog), // TODO what does this *actually* do? - .gt => input.analog, + component.outputs.items[0].signal.digital = 0; // TODO + component.outputs.items[0].signal.analog = switch (std.math.order(@abs(component.outputs.items[0].signal.analog), @abs(input.signal.analog))) { + .lt => component.outputs.items[0].signal.analog, + .eq => @min(component.outputs.items[0].signal.analog, input.signal.analog), // TODO what does this *actually* do? + .gt => input.signal.analog, }; } } - component.outputs.items[0].analog = std.math.clamp(component.outputs.items[0].analog, -1.0, 1.0); + component.outputs.items[0].signal.analog = std.math.clamp(component.outputs.items[0].signal.analog, -1.0, 1.0); } }; @@ -339,25 +425,25 @@ pub const Or = struct { pub fn process(component: *Component) void { const self: *Or = @fieldParentPtr("component", component); if (self.arithmetic_mode) { - component.outputs.items[0].digital = component.inputs.items[0].digital; - component.outputs.items[0].analog = component.inputs.items[0].analog; + component.outputs.items[0].signal.digital = component.inputs.items[0].signal.digital; + component.outputs.items[0].signal.analog = component.inputs.items[0].signal.analog; for (component.inputs.items[1..]) |input| { - component.outputs.items[0].digital = 0; // TODO - component.outputs.items[0].analog += input.analog; + component.outputs.items[0].signal.digital = 0; // TODO + component.outputs.items[0].signal.analog += input.signal.analog; } } else { - component.outputs.items[0].digital = component.inputs.items[0].digital; - component.outputs.items[0].analog = component.inputs.items[0].analog; + component.outputs.items[0].signal.digital = component.inputs.items[0].signal.digital; + component.outputs.items[0].signal.analog = component.inputs.items[0].signal.analog; for (component.inputs.items[1..]) |input| { - component.outputs.items[0].digital = 0; // TODO - component.outputs.items[0].analog = switch (std.math.order(@abs(component.outputs.items[0].analog), @abs(input.analog))) { - .lt => input.analog, - .eq => @max(component.outputs.items[0].analog, input.analog), // TODO what does this *actually* do? - .gt => component.outputs.items[0].analog, + component.outputs.items[0].signal.digital = 0; // TODO + component.outputs.items[0].signal.analog = switch (std.math.order(@abs(component.outputs.items[0].signal.analog), @abs(input.signal.analog))) { + .lt => input.signal.analog, + .eq => @max(component.outputs.items[0].signal.analog, input.signal.analog), // TODO what does this *actually* do? + .gt => component.outputs.items[0].signal.analog, }; } } - component.outputs.items[0].analog = std.math.clamp(component.outputs.items[0].analog, -1.0, 1.0); + component.outputs.items[0].signal.analog = std.math.clamp(component.outputs.items[0].signal.analog, -1.0, 1.0); } };