Begin circuit simulation

master
Louis Pearson 2022-01-19 20:55:27 -07:00
parent c780095d1b
commit 878665056c
4 changed files with 93 additions and 54 deletions

View File

@ -1,5 +0,0 @@
const std = @import("std");
const Vec2 = std.meta.Vector(2,i32);
pub const solid: [400]u8 = .{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 1, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 1, 19, 52, 1, 50, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 1, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 39, 1, 50, 19, 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 39, 1, 1, 1, 1, 1, 50, 19, 52, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 39, 1, 50, 19, 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 39, 1, 1, 1, 1, 1, 50, 19, 52, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 1, 39, 1, 50, 19, 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37, 1, 54, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 33, 54, 1, 1, 1, 1, 1, 1, 1, 50, 19, 52, 1, 1, 1, 1, 1, 1, 1, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 51, 1, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
pub const conduit: [400]u8 = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 131, 180, 0, 0, 0, 0, 0, 0, 178, 180, 0, 0, 0, 0, 0, 0, 178, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
pub const wire: [2][2]Vec2 = [_][2]Vec2{.{.{ 20, 20 },.{ 76, 20 },}, .{.{ 84, 19 },.{ 134, 30 },}, };

View File

@ -5,7 +5,7 @@ fn is_circuit(tile: u8) bool {
return is_plug(tile) or is_conduit(tile) or is_switch(tile);
}
fn is_plug(tile: u8) bool {
pub fn is_plug(tile: u8) bool {
return (tile >= 149 and tile <= 153) or tile == 147;
}
@ -103,39 +103,78 @@ fn dir(s: Side) Cell {
};
}
fn get_cell(c: Cell) ?u8 {
if (c[0] < 0 or c[0] >= 20 or c[1] >= 20 or c[1] < 0) return null;
const i = @intCast(usize, (c[0] % 20) + (c[1] * 20));
return assets.conduit[i];
pub fn get_cell(c: Cell) ?u8 {
if (c[0] < 0 or c[0] > 19 or c[1] > 19 or c[1] < 0) return null;
const i = @intCast(usize, @mod(c[0], 20) + (c[1] * 20));
return if (assets.conduit[i] != 0) assets.conduit[i] - 1 else null;
// return assets.conduit[i];
}
fn index2cell(i: usize) Cell {
return Vec2{ i % 20, @divTrunc(i, 20) };
}
pub const Circuit = struct {
switches: std.BoundedArray(8, cell),
plugs: std.BoundedArray(8, cell),
enabled: bool = false,
};
fn cell2index(c: Cell) ?usize {
if (c[0] < 0 or c[0] >= 20 or c[1] >= 20 or c[1] < 0) return null;
return @intCast(usize, @mod(c[0], 20) + (c[1] * 20));
}
pub fn createCircuitChunks() void {
var items = std.BoundedArray(100, u8).init(0);
for (assets.conduit) |tile, i| {
if (is_circuit(tile)) items.append(index2cell(i));
}
for (items.slice()) |cell| {
// TODO: iterate over the cells and create components
const CellState = bool;
const MAXCELLS = 400;
const CellMap = [MAXCELLS]CellState; // std.AutoHashMap(Cell, CellState);
offset: Cell,
cells: CellMap,
pub fn init() @This() {
return @This(){
.offset = Cell{ 0, 0 },
.cells = [1]CellState{false} ** 400,
};
}
pub fn indexOf(this: @This(), cell: Cell) ?usize {
return cell2index(cell - this.offset);
}
pub fn enable(this: *@This(), cell: Cell) void {
if (this.indexOf(cell)) |c| {
this.cells[c] = true;
}
}
var circuits = std.BoundedArray(20, Circuit).init(0);
pub fn toggleSwitch(cell: Cell) void {
for (circuits) |circuit| {
for (circuit.switches) |switchCell| {
if (switchCell == cell) {
// TODO: do a search and disable circuit if a source is not found
}
const Queue = struct {
data: std.BoundedArray(Cell, MAXCELLS),
pub fn init() @This() {
return @This(){
.data = std.BoundedArray(Cell, MAXCELLS).init(0) catch unreachable,
};
}
pub fn insert(this: *@This(), c: Cell) void {
this.data.insert(0, c) catch unreachable;
}
pub fn remove(this: *@This()) ?Cell {
return this.data.popOrNull();
}
};
const w4 = @import("wasm4.zig");
pub fn fill(this: *@This(), root: Cell) void {
var visited = std.StaticBitSet(MAXCELLS).initEmpty();
var q = Queue.init();
q.insert(root);
while (q.remove()) |cell| {
const index = this.indexOf(cell) orelse continue;
const tile = get_cell(cell) orelse continue;
if (visited.isSet(index)) continue;
visited.set(index);
this.enable(cell);
for (get_inputs(tile)) |conductor, i| {
if (!conductor) continue;
const s = @intToEnum(Side, i);
const delta = dir(s);
// w4.trace("side {} ({}), delta {}", .{ s, i, delta });
q.insert(cell + delta);
}
}
}

View File

@ -3,6 +3,7 @@ const w4 = @import("wasm4.zig");
const ecs = @import("ecs.zig");
const assets = @import("assets");
const input = @import("input.zig");
const Circuit = @import("circuit.zig");
const Vec2 = std.meta.Vector(2, i32);
const Vec2f = std.meta.Vector(2, f32);
@ -114,6 +115,7 @@ const KB = 1024;
var heap: [8 * KB]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&heap);
var world: World = World.init(fba.allocator());
var circuit = Circuit.init();
const anim_store = struct {
const stand = Anim.frame(0);
@ -173,6 +175,10 @@ export fn start() void {
.wire = w,
}) catch showErr("Adding wire entity");
}
for (assets.sources) |source| {
circuit.fill(source);
}
}
var indicator: ?struct { pos: Vec2, t: enum { wire, plug } } = null;
@ -198,12 +204,15 @@ export fn update() void {
const t = w4.Vec2{ @intCast(i32, (tile % 16) * 8), @intCast(i32, (tile / 16) * 8) };
const pos = w4.Vec2{ @intCast(i32, (i % 20) * 8), @intCast(i32, (i / 20) * 8) };
w4.blitSub(&assets.tiles, pos, .{ 8, 8 }, t, 128, .{ .bpp = .b2 });
const conduitRaw = assets.conduit[i];
if (conduitRaw != 0) {
const conduittile = conduitRaw - 1;
const tconduit = w4.Vec2{ @intCast(i32, (conduittile % 16) * 8), @intCast(i32, (conduittile / 16) * 8) };
w4.blitSub(&assets.tiles, pos, .{ 8, 8 }, tconduit, 128, .{ .bpp = .b2 });
}
}
for (assets.conduit) |tilePlus, i| {
if (tilePlus == 0) continue;
if (circuit.cells[i]) w4.DRAW_COLORS.* = 0x0210 else w4.DRAW_COLORS.* = 0x0310;
const tile = tilePlus - 1;
const t = w4.Vec2{ @intCast(i32, (tile % 16) * 8), @intCast(i32, (tile / 16) * 8) };
const pos = w4.Vec2{ @intCast(i32, (i % 20) * 8), @intCast(i32, (i / 20) * 8) };
w4.blitSub(&assets.tiles, pos, .{ 8, 8 }, t, 128, .{ .bpp = .b2 });
}
world.process(1, &.{.wire}, wireDrawProcess);
@ -232,10 +241,6 @@ export fn update() void {
time += 1;
}
fn is_plug(tile: u8) bool {
return (tile >= 149 and tile <= 153) or tile == 147;
}
/// pos should be in tile coordinates, not world coordinates
fn get_conduit(vec: Vec2) ?u8 {
const x = vec[0];
@ -272,7 +277,7 @@ fn wireManipulationProcess(_: f32, id: usize, pos: *Pos, control: *Control) void
}
var mapPos = vec2ftovec2((pos.pos + offset) / @splat(2, @as(f32, 8)));
if (is_plug(get_conduit(mapPos) orelse 0)) {
if (Circuit.is_plug(Circuit.get_cell(mapPos) orelse 0)) {
indicator = .{ .t = .plug, .pos = mapPos * @splat(2, @as(i32, 8)) + Vec2{ 4, 4 } };
if (input.btnp(.one, .two)) {
e.wire.?.nodes.slice()[details.which].pinned = true;
@ -286,7 +291,7 @@ fn wireManipulationProcess(_: f32, id: usize, pos: *Pos, control: *Control) void
}
world.set(details.id, e);
} else {
const interactDistance = 8;
const interactDistance = 4;
var minDistance: f32 = interactDistance;
var wireIter = world.iter(World.Query.require(&.{.wire}));
var interactWireID: ?usize = null;

View File

@ -336,21 +336,21 @@ pub extern fn diskw(src: [*]const u8, size: u32) u32;
/// Prints a message to the debug console.
/// Disabled in release builds.
pub fn trace(comptime fmt: []const u8, args: anytype) void {
if (@import("builtin").mode != .Debug) @compileError("trace not allowed in release builds.");
// stack size is [8192]u8
var buffer: [100]u8 = undefined;
var fbs = std.io.fixedBufferStream(&buffer);
const writer = fbs.writer();
writer.print(fmt, args) catch {
const err_msg = switch (@import("builtin").mode) {
.Debug => "[trace err] " ++ fmt,
else => "[trace err]", // max 100 bytes in trace message.
if (@import("builtin").mode == .Debug) {
// stack size is [8192]u8
var buffer: [100]u8 = undefined;
var fbs = std.io.fixedBufferStream(&buffer);
const writer = fbs.writer();
writer.print(fmt, args) catch {
const err_msg = switch (@import("builtin").mode) {
.Debug => "[trace err] " ++ fmt,
else => "[trace err]", // max 100 bytes in trace message.
};
return traceUtf8(err_msg, err_msg.len);
};
return traceUtf8(err_msg, err_msg.len);
};
traceUtf8(&buffer, fbs.pos);
traceUtf8(&buffer, fbs.pos);
}
}
extern fn traceUtf8(str_ptr: [*]const u8, str_len: usize) void;