From ee3b09191aadaa516fd34b9b5e147ed559d7b08a Mon Sep 17 00:00:00 2001 From: Jeeves Date: Wed, 30 Apr 2025 08:16:36 -0600 Subject: [PATCH] improve code, tests, and break Selector --- src/main.zig | 172 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 130 insertions(+), 42 deletions(-) diff --git a/src/main.zig b/src/main.zig index e619da2..8634d95 100644 --- a/src/main.zig +++ b/src/main.zig @@ -544,7 +544,7 @@ pub const Not = struct { pub fn update(component: *Component) AllocatorError!void { const self: *Not = @fieldParentPtr("component", component); const output = component.getOutput(0); - const input = if (component.getInput(0)) |s| s else &Signal{}; + const input = component.getInput(0) orelse &Signal{}; if (self.invert_output) { output.digital = 1 - @as(i2, @intCast(@abs(input.digital))); output.analog = 1.0 - @abs(input.analog); @@ -580,12 +580,12 @@ pub const And = struct { pub fn update(component: *Component) AllocatorError!void { const self: *And = @fieldParentPtr("component", component); const output = component.getOutput(0); - const input0 = if (component.getInput(0)) |s| s else &Signal{}; + const input0 = component.getInput(0) orelse &Signal{}; if (self.arithmetic_mode) { output.digital = input0.digital; output.analog = input0.analog; for (component.inputs.items[1..]) |opt_input| { - const input = if (opt_input.signal) |s| s else &Signal{}; + const input = opt_input.signal orelse &Signal{}; output.digital = 0; // TODO output.analog *= input.analog; } @@ -593,7 +593,7 @@ pub const And = struct { output.digital = input0.digital; output.analog = input0.analog; for (component.inputs.items[1..]) |opt_input| { - const input = if (opt_input.signal) |s| s else &Signal{}; + const input = opt_input.signal orelse &Signal{}; output.digital = 0; // TODO output.analog = switch (std.math.order(@abs(output.analog), @abs(input.analog))) { .lt => output.analog, @@ -606,15 +606,20 @@ pub const And = struct { } }; -test "min" { - var a = Signal{ .analog = 0.0 }; - var b = Signal{ .analog = 1.0 }; +test "And" { + var a = Signal{}; + var b = Signal{}; var and1 = try And.init(std.testing.allocator); defer and1.component.deinit(std.testing.allocator); and1.component.inputs.items[0].signal = &a; and1.component.inputs.items[1].signal = &b; + // TODO test digital part + + // if arithmetic_mode is false, should output the input value furthest from 0 + a.analog = 0.0; + b.analog = 1.0; try and1.component.update(); try std.testing.expectEqual(0.0, and1.component.outputs.items[0].signal.analog); @@ -622,6 +627,14 @@ test "min" { b.analog = -0.2; try and1.component.update(); try std.testing.expectEqual(-0.2, and1.component.outputs.items[0].signal.analog); + + // if arithmetic_mode is true, should output the product of all inputs + and1.arithmetic_mode = true; + + a.analog = 0.1; + b.analog = 0.1; + try and1.component.update(); + try std.testing.expectApproxEqAbs(0.01, and1.component.outputs.items[0].signal.analog, 0.00001); } pub const Or = struct { @@ -648,12 +661,12 @@ pub const Or = struct { pub fn update(component: *Component) AllocatorError!void { const self: *Or = @fieldParentPtr("component", component); const output = component.getOutput(0); - const input0 = if (component.getInput(0)) |s| s else &Signal{}; + const input0 = component.getInput(0) orelse &Signal{}; if (self.arithmetic_mode) { output.digital = input0.digital; output.analog = input0.analog; for (component.inputs.items[1..]) |opt_input| { - const input = if (opt_input.signal) |s| s else &Signal{}; + const input = opt_input.signal orelse &Signal{}; output.digital = 0; // TODO output.analog += input.analog; } @@ -661,7 +674,7 @@ pub const Or = struct { output.digital = input0.digital; output.analog = input0.analog; for (component.inputs.items[1..]) |opt_input| { - const input = if (opt_input.signal) |s| s else &Signal{}; + const input = opt_input.signal orelse &Signal{}; output.digital = 0; // TODO output.analog = switch (std.math.order(@abs(output.analog), @abs(input.analog))) { .lt => input.analog, @@ -674,7 +687,7 @@ pub const Or = struct { } }; -test "max" { +test "Or" { var a = Signal{ .analog = 0.0 }; var b = Signal{ .analog = 1.0 }; @@ -683,6 +696,8 @@ test "max" { or1.component.inputs.items[0].signal = &a; or1.component.inputs.items[1].signal = &b; + // TODO test digital part + try or1.component.update(); try std.testing.expectEqual(1.0, or1.component.getOutput(0).analog); @@ -690,6 +705,8 @@ test "max" { b.analog = -0.2; try or1.component.update(); try std.testing.expectEqual(-0.5, or1.component.getOutput(0).analog); + + // TODO arithmetic mode } pub const Selector = struct { @@ -702,7 +719,7 @@ pub const Selector = struct { var self = try allocator.create(Selector); errdefer allocator.destroy(self); self.* = .{ .component = undefined }; - try Component.init(&self.component, allocator, "Selector", 2, 2, &update, &deinit); + try Component.init(&self.component, allocator, "Selector", 5, 4, &update, &deinit); return self; } @@ -712,55 +729,126 @@ pub const Selector = struct { } // TODO check implementation + // TODO broken, needs to be completely rewritten pub fn update(component: *Component) AllocatorError!void { const self: *Selector = @fieldParentPtr("component", component); - var last_idx: ?usize = null; - for (component.inputs.items, 0..) |input, idx| { - if (input.signal) |signal| { - if (signal.digital == 1) last_idx = idx; + + const cycle = component.getInput(0) orelse &Signal{}; + + std.debug.print("len {d}\n", .{component.inputs.items.len}); + + if (cycle.digital > 0) { + self.increment(); + } else if (cycle.digital < 0) { + self.decrement(); + } else { + var last_idx: ?usize = null; + for (component.inputs.items[1..], 0..) |input, idx| { + if (input.signal) |signal| { + if (signal.digital == 1) last_idx = idx; + } + } + if (last_idx) |lidx| { + for (component.outputs.items[0..], 0..) |*output, idx| { + const flip = if (self.invert_output) + idx != lidx + else + idx == lidx; + + output.signal = if (flip) + .{ .digital = 1, .analog = 1.0 } + else + .{ .digital = 0, .analog = 0.0 }; + } + } else { + for (component.outputs.items[0..], 0..) |*output, idx| { + const flip = if (self.invert_output) + idx != self.current_output + else + idx == self.current_output; + + std.debug.print("{d} flip {}\n", .{ idx, flip }); + + output.signal = if (flip) + .{ .digital = 1, .analog = 1.0 } + else + .{ .digital = 0, .analog = 0.0 }; + } } } - if (last_idx) |lidx| { - for (component.outputs.items, 0..) |*output, idx| { - output.signal = if (if (self.invert_output) idx != lidx else idx == lidx) - .{ .digital = 1, .analog = 1.0 } - else - .{ .digital = 0, .analog = 0.0 }; - } + + std.debug.print("final values", .{}); + for (component.outputs.items) |output| { + std.debug.print(" {}", .{output.signal}); } + std.debug.print("\n", .{}); + } + + pub fn resize(self: *Selector, allocator: std.mem.Allocator, new_len: usize) !void { + try self.component.resizeInputs(allocator, new_len + 1); + try self.component.resizeOutputs(allocator, new_len); + } + + fn increment(self: *Selector) void { + const len = self.component.outputs.items.len; + if (self.current_output >= len) + self.current_output = 0 + else + self.current_output += 1; + } + + fn decrement(self: *Selector) void { + const len = self.component.outputs.items.len; + if (self.current_output >= 0) + self.current_output = len + else + self.current_output -= 1; } }; -test "selector" { - var a = Signal{ .digital = 0 }; - var b = Signal{ .digital = 1 }; +test "Selector" { + var a = Signal{}; + var b = Signal{}; + var c = Signal{}; var selector = try Selector.init(std.testing.allocator); defer selector.component.deinit(std.testing.allocator); - selector.component.inputs.items[0].signal = &a; - selector.component.inputs.items[1].signal = &b; + try selector.resize(std.testing.allocator, 3); - try selector.component.update(); - try std.testing.expectEqual(Signal{ .digital = 0, .analog = 0.0 }, selector.component.getOutput(0).*); - try std.testing.expectEqual(Signal{ .digital = 1, .analog = 1.0 }, selector.component.getOutput(1).*); - - a.digital = 0; - b.digital = 0; - try selector.component.update(); - try selector.component.update(); - try std.testing.expectEqual(Signal{ .digital = 0, .analog = 0.0 }, selector.component.getOutput(0).*); - try std.testing.expectEqual(Signal{ .digital = 1, .analog = 1.0 }, selector.component.getOutput(1).*); - - a.digital = 1; - b.digital = 0; + // default state, output 0 should be active try selector.component.update(); try std.testing.expectEqual(Signal{ .digital = 1, .analog = 1.0 }, selector.component.getOutput(0).*); try std.testing.expectEqual(Signal{ .digital = 0, .analog = 0.0 }, selector.component.getOutput(1).*); + try std.testing.expectEqual(Signal{ .digital = 0, .analog = 0.0 }, selector.component.getOutput(2).*); - selector.invert_output = true; + // should remember last active output + selector.component.inputs.items[1].signal = &a; + selector.component.inputs.items[2].signal = &b; + selector.component.inputs.items[3].signal = &c; + + a.digital = 0; + b.digital = 1; + c.digital = 0; try selector.component.update(); try std.testing.expectEqual(Signal{ .digital = 0, .analog = 0.0 }, selector.component.getOutput(0).*); try std.testing.expectEqual(Signal{ .digital = 1, .analog = 1.0 }, selector.component.getOutput(1).*); + try std.testing.expectEqual(Signal{ .digital = 0, .analog = 0.0 }, selector.component.getOutput(2).*); + + a.digital = 0; + b.digital = 0; + c.digital = 0; + try selector.component.update(); + try std.testing.expectEqual(Signal{ .digital = 0, .analog = 0.0 }, selector.component.getOutput(0).*); + try std.testing.expectEqual(Signal{ .digital = 1, .analog = 1.0 }, selector.component.getOutput(1).*); + try std.testing.expectEqual(Signal{ .digital = 0, .analog = 0.0 }, selector.component.getOutput(2).*); + + selector.invert_output = true; + try selector.component.update(); + try std.testing.expectEqual(Signal{ .digital = 1, .analog = 1.0 }, selector.component.getOutput(0).*); + try std.testing.expectEqual(Signal{ .digital = 0, .analog = 0.0 }, selector.component.getOutput(1).*); + try std.testing.expectEqual(Signal{ .digital = 1, .analog = 1.0 }, selector.component.getOutput(2).*); + + // TODO cycle input } const AllocatorError = std.mem.Allocator.Error;