From 3c3c9b4ddcbbe1a514b0dbbfd97dcfafc1c7562f Mon Sep 17 00:00:00 2001 From: LeRoyce Pearson Date: Sun, 23 Jan 2022 17:17:59 -0700 Subject: [PATCH] Use grid of levels to improve performance Makes Wired run at full speed on the RG351M. --- src/circuit.zig | 59 ++++++++++++++++--------------------------------- src/main.zig | 5 ++++- src/util.zig | 36 ------------------------------ 3 files changed, 23 insertions(+), 77 deletions(-) diff --git a/src/circuit.zig b/src/circuit.zig index 5040da1..3c05bea 100644 --- a/src/circuit.zig +++ b/src/circuit.zig @@ -172,16 +172,14 @@ fn get_plugs(tile: u8) Plugs { } pub fn get_cell(this: @This(), cell: Cell) ?u8 { - if (this.cell_map.get_const(cell)) |c| return c.tile; - const c = cell; - if (c[0] < 0 or c[0] > this.map_size[0] or c[1] > this.map_size[1] or c[1] < 0) return null; - const i = @intCast(usize, @mod(c[0], this.map_size[0]) + (c[1] * this.map_size[1])); + const i = this.indexOf(cell) orelse return null; return if (this.map[i] != 0) this.map[i] - 1 else null; } pub fn set_cell(this: *@This(), cell: Cell, tile: u8) void { - var cellData = CellData{ .tile = tile }; - this.cell_map.set(cell, cellData); + const i = this.indexOf(cell) orelse return; + this.map[i] = tile + 1; + this.levels[i] = 0; } const MAXCELLS = 400; @@ -190,38 +188,30 @@ const MAXSOURCES = 10; const MAXDOORS = 40; const MAXLOGIC = 40; -const CellData = struct { level: u8 = 0, tile: u8 }; -const CellMap = util.Map(Cell, CellData, MAXCELLS); +pub const CellData = struct { level: u8 = 0, tile: u8 }; const BridgeState = struct { cells: [2]Cell, id: usize, enabled: bool }; const DoorState = struct { cell: Cell, enabled: bool }; -map: []const u8, +/// Tile id of the tiles +map: []u8, +/// Logic levels of the tiles +levels: []u8, map_size: Vec2, -cell_map: CellMap, bridges: std.BoundedArray(BridgeState, MAXBRIDGES), sources: std.BoundedArray(Cell, MAXSOURCES), doors: std.BoundedArray(DoorState, MAXDOORS), -logic_map: std.BoundedArray(Cell, MAXLOGIC), -pub fn init(map: []const u8, map_size: Vec2) @This() { +pub fn init(map: []u8, levels: []u8, map_size: Vec2) @This() { + std.debug.assert(map.len == levels.len); var this = @This(){ .map = map, + .levels = levels, .map_size = map_size, - .cell_map = CellMap.init(), .bridges = std.BoundedArray(BridgeState, MAXBRIDGES).init(0) catch unreachable, .sources = std.BoundedArray(Cell, MAXSOURCES).init(0) catch unreachable, .doors = std.BoundedArray(DoorState, MAXDOORS).init(0) catch unreachable, - .logic_map = std.BoundedArray(Cell, MAXLOGIC).init(0) catch unreachable, }; - for (map) |tile, index| { - if (is_logic(tile)) { - const i = @intCast(i32, index); - const cell = Cell{ @mod(i, this.map_size[0]), @divTrunc(i, this.map_size[0]) }; - // w4.tracef("%d, %d: %d", cell[0], cell[1], this.logic_map.len); - this.logic_map.append(cell) catch unreachable; - } - } return this; } @@ -231,12 +221,8 @@ pub fn indexOf(this: @This(), cell: Cell) ?usize { } pub fn enable(this: *@This(), cell: Cell) void { - if (this.cell_map.get(cell)) |c| { - c.level += 1; - return; - } - const t = this.get_cell(cell) orelse return; - this.cell_map.set(cell, .{ .tile = t, .level = 1 }); + const i = this.indexOf(cell) orelse return; + this.levels[i] += 1; } pub fn bridge(this: *@This(), cells: [2]Cell, bridgeID: usize) void { @@ -276,10 +262,8 @@ pub fn enabledDoors(this: @This()) std.BoundedArray(Cell, MAXDOORS) { } pub fn isEnabled(this: @This(), cell: Cell) bool { - if (this.cell_map.get_const(cell)) |c| { - return c.level >= 1; - } - return false; + const i = this.indexOf(cell) orelse return false; + return this.levels[i] >= 1; } pub fn toggle(this: *@This(), c: Cell) void { @@ -293,9 +277,7 @@ pub fn toggle(this: *@This(), c: Cell) void { } pub fn clear(this: *@This()) void { - for (this.cell_map.values.slice()) |*cell| { - cell.level = 0; - } + std.mem.set(u8, this.levels, 0); for (this.doors.slice()) |*door| { door.enabled = false; } @@ -335,11 +317,8 @@ pub fn fill(this: *@This()) usize { if (get_logic(tile)) |logic| { // TODO: implement other logic (though I'm pretty sure that requires a graph...) if (logic != .And) continue; - if (this.cell_map.get(cell)) |data| { - // Skip current loop if and isn't high enough - if (data.level < 2) continue; - q.insert(cell + util.Dir.up); - } + if (this.levels[index] < 2) continue; + q.insert(cell + util.Dir.up); } for (get_outputs(tile)) |conductor, i| { if (!conductor) continue; diff --git a/src/main.zig b/src/main.zig index 004bd52..81f9ead 100644 --- a/src/main.zig +++ b/src/main.zig @@ -173,6 +173,8 @@ const Coin = struct { pos: Pos, sprite: Sprite, anim: Anim, area: AABB }; var coins = std.BoundedArray(Coin, 20).init(0) catch unreachable; var score: u8 = 0; var solids_mutable = assets.solid; +var conduit_mutable = assets.conduit; +var conduitLevels_mutable: [conduit_mutable.len]u8 = undefined; const anim_store = struct { const stand = Anim.frame(8); @@ -203,7 +205,8 @@ fn showErr(msg: []const u8) noreturn { export fn start() void { particles = ParticleSystem.init(); - circuit = Circuit.init(&assets.conduit, assets.conduit_size); + std.mem.set(u8, &conduitLevels_mutable, 0); + circuit = Circuit.init(&conduit_mutable, &conduitLevels_mutable, assets.conduit_size); map = Map.init(&solids_mutable, assets.solid_size); camera = @divTrunc(assets.spawn, @splat(2, @as(i32, 20))) * @splat(2, @as(i32, 20)); diff --git a/src/util.zig b/src/util.zig index bc0d062..d754bc3 100644 --- a/src/util.zig +++ b/src/util.zig @@ -81,39 +81,3 @@ pub fn Queue(comptime T: type, len: usize) type { }; } -pub fn Map(comptime K: type, comptime V: type, len: usize) type { - return struct { - keys: std.BoundedArray(K, len), - values: std.BoundedArray(V, len), - pub fn init() @This() { - return @This(){ - .keys = std.BoundedArray(K, len).init(0) catch unreachable, - .values = std.BoundedArray(V, len).init(0) catch unreachable, - }; - } - pub fn get(this: *@This(), key: K) ?*V { - for (this.keys.slice()) |k, i| { - if (@reduce(.And, key == k)) { - return &this.values.slice()[i]; - } - } - return null; - } - pub fn get_const(this: @This(), key: Cell) ?V { - for (this.keys.constSlice()) |k, i| { - if (@reduce(.And, key == k)) { - return this.values.constSlice()[i]; - } - } - return null; - } - pub fn set(this: *@This(), key: K, new: V) void { - if (this.get(key)) |v| { - v.* = new; - } else { - this.keys.append(key) catch unreachable; - this.values.append(new) catch unreachable; - } - } - }; -}