diff --git a/src/circuit.zig b/src/circuit.zig index 4d0c4d1..5377f26 100644 --- a/src/circuit.zig +++ b/src/circuit.zig @@ -190,27 +190,36 @@ const MAXLOGIC = 40; 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 }; +pub const BridgeState = struct { cells: [2]Cell, id: usize, enabled: bool }; +pub const DoorState = struct { cell: Cell, enabled: bool }; /// Tile id of the tiles map: []u8, /// Logic levels of the tiles levels: []u8, map_size: Vec2, -bridges: std.BoundedArray(BridgeState, MAXBRIDGES), -sources: std.BoundedArray(Cell, MAXSOURCES), -doors: std.BoundedArray(DoorState, MAXDOORS), +bridges: util.Buffer(BridgeState), +sources: util.Buffer(Cell), +doors: util.Buffer(DoorState), -pub fn init(map: []u8, levels: []u8, map_size: Vec2) !@This() { - std.debug.assert(map.len == levels.len); +pub const Options = struct { + map: []u8, + levels: []u8, + map_size: Vec2, + bridges: []BridgeState, + sources: []Cell, + doors: []DoorState, +}; + +pub fn init(opt: Options) @This() { + std.debug.assert(opt.map.len == opt.levels.len); var this = @This(){ - .map = map, - .levels = levels, - .map_size = map_size, - .bridges = try std.BoundedArray(BridgeState, MAXBRIDGES).init(0), - .sources = try std.BoundedArray(Cell, MAXSOURCES).init(0), - .doors = try std.BoundedArray(DoorState, MAXDOORS).init(0), + .map = opt.map, + .levels = opt.levels, + .map_size = opt.map_size, + .bridges = util.Buffer(BridgeState).init(opt.bridges), + .sources = util.Buffer(Cell).init(opt.sources), + .doors = util.Buffer(DoorState).init(opt.doors), }; return this; } @@ -245,20 +254,22 @@ pub fn addDoor(this: *@This(), cell: Cell) !void { } } -pub fn enabledBridges(this: @This()) !std.BoundedArray(usize, MAXBRIDGES) { - var items = try std.BoundedArray(usize, MAXBRIDGES).init(0); - for (this.bridges.constSlice()) |b| { - if (b.enabled) try items.append(b.id); +pub fn enabledBridges(this: @This(), alloc: std.mem.Allocator) !util.Buffer(usize) { + var items = try alloc.alloc(usize, this.bridges.len); + var buffer = util.Buffer(usize).init(items); + for (this.bridges.items) |b| { + if (b.enabled) buffer.append(b.id); } - return items; + return buffer; } -pub fn enabledDoors(this: @This()) !std.BoundedArray(Cell, MAXDOORS) { - var items = try std.BoundedArray(Cell, MAXDOORS).init(0); - for (this.doors.constSlice()) |d| { - if (d.enabled) try items.append(d.cell); +pub fn enabledDoors(this: @This(), alloc: std.mem.Allocator) !util.Buffer(Cell) { + var items = try alloc.alloc(Cell, this.doors.len); + var buffer = util.buffer(Cell).init(items); + for (this.doors.items) |d| { + if (d.enabled) buffer.append(d.cell); } - return items; + return buffer; } pub fn isEnabled(this: @This(), cell: Cell) bool { @@ -294,9 +305,14 @@ pub fn reset(this: *@This()) void { const w4 = @import("wasm4.zig"); const Queue = util.Queue(Cell, MAXCELLS); // Returns number of cells filled -pub fn fill(this: *@This()) !usize { +pub fn fill(this: *@This(), alloc: std.mem.Allocator) !usize { var count: usize = 0; - var visited = try std.BoundedArray(usize, MAXCELLS).init(0); + + var items = try alloc.alloc(usize, MAXCELLS); + defer alloc.free(items); + + var visited = util.Buffer(usize).init(items); + var q = try Queue.init(); for (this.sources.slice()) |source| { try q.insert(source); diff --git a/src/main.zig b/src/main.zig index 0b966c8..a5ef268 100644 --- a/src/main.zig +++ b/src/main.zig @@ -38,7 +38,7 @@ export fn update() void { switch (newState) { .Menu => menu.start(), .Game => game.start() catch |e| switch (e) { - error.Overflow => showErr(@errorName(e)), + // error.Overflow => showErr(@errorName(e)), // error.OutOfBounds => showErr(@errorName(e)), error.EndOfStream => showErr(@errorName(e)), error.OutOfMemory => showErr(@errorName(e)), diff --git a/src/map.zig b/src/map.zig index d1051c1..d30f8d8 100644 --- a/src/map.zig +++ b/src/map.zig @@ -107,17 +107,35 @@ fn getTile(this: @This(), x: i32, y: i32) ?u8 { return this.tiles[@intCast(u32, i)]; } -pub fn collide(this: @This(), rect: util.AABB) !std.BoundedArray(util.AABB, 9) { +pub const CollisionInfo = struct { + len: usize, + items: [9]util.AABB, + + pub fn init() CollisionInfo { + return CollisionInfo { + .len = 0, + .items = undefined, + }; + } + + pub fn append(col: CollisionInfo, item: util.AABB) void { + std.debug.assert(col.len < 9); + col.items[col.len] = item; + col.len += 1; + } +}; + +pub fn collide(this: @This(), rect: util.AABB) CollisionInfo { const top_left = rect.pos / tile_sizef; const bot_right = (rect.pos + rect.size) / tile_sizef; - var collisions = try std.BoundedArray(util.AABB, 9).init(0); + var collisions = CollisionInfo.init(); var i: isize = @floatToInt(i32, top_left[0]); while (i <= @floatToInt(i32, bot_right[0])) : (i += 1) { var a: isize = @floatToInt(i32, top_left[1]); while (a <= @floatToInt(i32, bot_right[1])) : (a += 1) { if (this.isSolid(Cell{ i, a })) { - try collisions.append(util.AABB{ + collisions.append(util.AABB{ .pos = Vec2f{ @intToFloat(f32, i * tile_width), @intToFloat(f32, a * tile_height), diff --git a/src/music.zig b/src/music.zig index 83843f4..21bb252 100644 --- a/src/music.zig +++ b/src/music.zig @@ -30,8 +30,6 @@ pub const Sfx = struct { flags: w4.ToneFlags, }; -pub const MusicCommand = std.BoundedArray(Sfx, 4); - pub const Intensity = enum(u8) { calm = 0, active = 1, @@ -91,8 +89,9 @@ pub const Procedural = struct { this.collect = .{ .score = score, .start = beatTotal + 1, .end = beatTotal + (this.beatsPerBar * length) + 1 }; } - pub fn getNext(this: *@This(), dt: u32) !MusicCommand { - var cmd = try MusicCommand.init(0); + pub fn getNext(this: *@This(), dt: u32) MusicCommand { + var i = 0; + var cmd: [4]Sfx = undefined; const beatProgress = this.tick % this.beat; const beatTotal = @divTrunc(this.tick, this.beat); const beat = beatTotal % this.beatsPerBar; @@ -103,12 +102,13 @@ pub const Procedural = struct { const playNote = if (collect.score < 6) beat % 2 == 0 else beat % 4 != 3; if (beatTotal >= collect.start and beatTotal < collect.end and playNote and beatProgress == 0) { // const notelen = @intCast(u8, this.beat * this.beatsPerBar); - try cmd.append(Sfx{ + cmd[i] = (Sfx{ .freq = .{ .start = this.nextNote(this.note) }, .duration = .{ .sustain = 5, .release = 5 }, .volume = 25, .flags = .{ .channel = .pulse2, .mode = .p25 }, }); + i += 1; this.note += 1; } if (bar > collect.end) { @@ -116,24 +116,33 @@ pub const Procedural = struct { this.collect = null; } } - if (this.intensity.atLeast(.calm) and beat == 0 and beatProgress == 0) try cmd.append(.{ - .freq = .{ .start = 220, .end = 110 }, - .duration = .{ .release = 3 }, - .volume = 100, - .flags = .{ .channel = .triangle }, - }); - if (this.intensity.atLeast(.active) and beat == this.beatsPerBar / 2 and beatProgress == 0) try cmd.append(.{ - .freq = .{ .start = 110, .end = 55 }, - .duration = .{ .release = 3 }, - .volume = 100, - .flags = .{ .channel = .triangle }, - }); - if (this.walking and beat % 3 == 1 and beatProgress == 7) try cmd.append(.{ - .freq = .{ .start = 1761, .end = 1 }, - .duration = .{ .release = 5 }, - .volume = 25, - .flags = .{ .channel = .noise }, - }); + if (this.intensity.atLeast(.calm) and beat == 0 and beatProgress == 0) { + cmd[i] = (.{ + .freq = .{ .start = 220, .end = 110 }, + .duration = .{ .release = 3 }, + .volume = 100, + .flags = .{ .channel = .triangle }, + }); + i += 1; + } + if (this.intensity.atLeast(.active) and beat == this.beatsPerBar / 2 and beatProgress == 0) { + cmd[i] = (.{ + .freq = .{ .start = 110, .end = 55 }, + .duration = .{ .release = 3 }, + .volume = 100, + .flags = .{ .channel = .triangle }, + }); + i += 1; + } + if (this.walking and beat % 3 == 1 and beatProgress == 7) { + cmd[i] = (.{ + .freq = .{ .start = 1761, .end = 1 }, + .duration = .{ .release = 5 }, + .volume = 25, + .flags = .{ .channel = .noise }, + }); + i += 1; + } return cmd; } }; diff --git a/src/rewrite.zig b/src/rewrite.zig index 4aa8c4c..c177540 100644 --- a/src/rewrite.zig +++ b/src/rewrite.zig @@ -7,9 +7,14 @@ const State = @import("main.zig").State; const std = @import("std"); const w4 = @import("wasm4.zig"); const world = @import("world.zig"); +const util = @import("util.zig"); const Vec2 = w4.Vec2; +var fba_buf: [1024]u8 = undefined; +var fba = std.heap.FixedBufferAllocator.init(&fba_buf); +var alloc = fba.allocator(); + var frame_fba_buf: [4096]u8 = undefined; var frame_fba = std.heap.FixedBufferAllocator.init(&frame_fba_buf); var frame_alloc = frame_fba.allocator(); @@ -21,10 +26,21 @@ var circuit_lvl_buf: [400]u8 = undefined; var circuit_buf: [400]u8 = undefined; var circuit: Circuit = undefined; +var circuit_options: Circuit.Options = undefined; + var level_size = Vec2{ 20, 20 }; pub fn start() !void { - circuit = try Circuit.init(&circuit_buf, &circuit_lvl_buf, level_size); + circuit_options = .{ + .map = &circuit_buf, + .levels = &circuit_lvl_buf, + .map_size = level_size, + .bridges = try alloc.alloc(Circuit.BridgeState, 5), + .sources = try alloc.alloc(util.Cell, 5), + .doors = try alloc.alloc(Circuit.DoorState, 5), + }; + circuit = Circuit.init(circuit_options); + map = Map.init(&map_buf, level_size); var stream = std.io.FixedBufferStream([]const u8){ diff --git a/src/util.zig b/src/util.zig index e2dc763..b331384 100644 --- a/src/util.zig +++ b/src/util.zig @@ -64,19 +64,67 @@ pub const AABB = struct { } }; -pub fn Queue(comptime T: type, len: usize) type { +pub fn Queue(comptime T: type) type { return struct { - data: std.BoundedArray(T, len), - pub fn init() !@This() { + begin: usize, + end: usize, + data: []T, + pub fn init(slice: []T) @This() { return @This(){ - .data = try std.BoundedArray(T, len).init(0), + .begin = 0, + .end = 0, + .data = slice, }; } - pub fn insert(this: *@This(), t: T) !void { - try this.data.insert(0, t); + fn next(this: @This(), idx: usize) usize { + return ((idx + 1) % this.data.len); } - pub fn remove(this: *@This()) ?Cell { - return this.data.popOrNull(); + pub fn insert(this: *@This(), t: T) !void { + const n = this.next(this.end); + if (n == this.begin) return error.OutOfMemory; + this.data[this.end] = t; + this.end = n; + } + pub fn remove(this: *@This()) ?T { + if (this.begin == this.end) return null; + const datum = this.data[this.begin]; + this.begin = this.next(this.begin); + return datum; + } + }; +} + +test "Queue" { + var items: [3]usize = undefined; + var q = Queue(usize).init(&items); + try q.insert(1); + try q.insert(2); + try std.testing.expectError(error.OutOfMemory, q.insert(3)); + try std.testing.expectEqual(@as(?usize, 1), q.remove()); + try std.testing.expectEqual(@as(?usize, 2), q.remove()); + try std.testing.expectEqual(@as(?usize, null), q.remove()); +} + +pub fn Buffer(comptime T: type) type { + return struct { + len: usize, + items: []T, + + pub fn init(slice: []T) @This() { + return @This(){ + .len = 0, + .items = slice, + }; + } + + pub fn reset(buf: @This()) void { + buf.len = 0; + } + + pub fn append(buf: @This(), item: T) void { + std.debug.assert(buf.len < buf.items.len); + buf.items[buf.len] = item; + buf.len += 1; } }; }