improve code, tests, and break Selector
This commit is contained in:
parent
1affc9d797
commit
ee3b09191a
1 changed files with 130 additions and 42 deletions
172
src/main.zig
172
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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue