Remove bounded array

master
Louis Pearson 2022-08-04 12:11:29 -06:00
parent d27051e526
commit 8c7a6b096f
6 changed files with 168 additions and 61 deletions

View File

@ -190,27 +190,36 @@ const MAXLOGIC = 40;
pub const CellData = struct { level: u8 = 0, tile: u8 }; pub const CellData = struct { level: u8 = 0, tile: u8 };
const BridgeState = struct { cells: [2]Cell, id: usize, enabled: bool }; pub const BridgeState = struct { cells: [2]Cell, id: usize, enabled: bool };
const DoorState = struct { cell: Cell, enabled: bool }; pub const DoorState = struct { cell: Cell, enabled: bool };
/// Tile id of the tiles /// Tile id of the tiles
map: []u8, map: []u8,
/// Logic levels of the tiles /// Logic levels of the tiles
levels: []u8, levels: []u8,
map_size: Vec2, map_size: Vec2,
bridges: std.BoundedArray(BridgeState, MAXBRIDGES), bridges: util.Buffer(BridgeState),
sources: std.BoundedArray(Cell, MAXSOURCES), sources: util.Buffer(Cell),
doors: std.BoundedArray(DoorState, MAXDOORS), doors: util.Buffer(DoorState),
pub fn init(map: []u8, levels: []u8, map_size: Vec2) !@This() { pub const Options = struct {
std.debug.assert(map.len == levels.len); 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(){ var this = @This(){
.map = map, .map = opt.map,
.levels = levels, .levels = opt.levels,
.map_size = map_size, .map_size = opt.map_size,
.bridges = try std.BoundedArray(BridgeState, MAXBRIDGES).init(0), .bridges = util.Buffer(BridgeState).init(opt.bridges),
.sources = try std.BoundedArray(Cell, MAXSOURCES).init(0), .sources = util.Buffer(Cell).init(opt.sources),
.doors = try std.BoundedArray(DoorState, MAXDOORS).init(0), .doors = util.Buffer(DoorState).init(opt.doors),
}; };
return this; return this;
} }
@ -245,20 +254,22 @@ pub fn addDoor(this: *@This(), cell: Cell) !void {
} }
} }
pub fn enabledBridges(this: @This()) !std.BoundedArray(usize, MAXBRIDGES) { pub fn enabledBridges(this: @This(), alloc: std.mem.Allocator) !util.Buffer(usize) {
var items = try std.BoundedArray(usize, MAXBRIDGES).init(0); var items = try alloc.alloc(usize, this.bridges.len);
for (this.bridges.constSlice()) |b| { var buffer = util.Buffer(usize).init(items);
if (b.enabled) try items.append(b.id); 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) { pub fn enabledDoors(this: @This(), alloc: std.mem.Allocator) !util.Buffer(Cell) {
var items = try std.BoundedArray(Cell, MAXDOORS).init(0); var items = try alloc.alloc(Cell, this.doors.len);
for (this.doors.constSlice()) |d| { var buffer = util.buffer(Cell).init(items);
if (d.enabled) try items.append(d.cell); for (this.doors.items) |d| {
if (d.enabled) buffer.append(d.cell);
} }
return items; return buffer;
} }
pub fn isEnabled(this: @This(), cell: Cell) bool { pub fn isEnabled(this: @This(), cell: Cell) bool {
@ -294,9 +305,14 @@ pub fn reset(this: *@This()) void {
const w4 = @import("wasm4.zig"); const w4 = @import("wasm4.zig");
const Queue = util.Queue(Cell, MAXCELLS); const Queue = util.Queue(Cell, MAXCELLS);
// Returns number of cells filled // 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 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(); var q = try Queue.init();
for (this.sources.slice()) |source| { for (this.sources.slice()) |source| {
try q.insert(source); try q.insert(source);

View File

@ -38,7 +38,7 @@ export fn update() void {
switch (newState) { switch (newState) {
.Menu => menu.start(), .Menu => menu.start(),
.Game => game.start() catch |e| switch (e) { .Game => game.start() catch |e| switch (e) {
error.Overflow => showErr(@errorName(e)), // error.Overflow => showErr(@errorName(e)),
// error.OutOfBounds => showErr(@errorName(e)), // error.OutOfBounds => showErr(@errorName(e)),
error.EndOfStream => showErr(@errorName(e)), error.EndOfStream => showErr(@errorName(e)),
error.OutOfMemory => showErr(@errorName(e)), error.OutOfMemory => showErr(@errorName(e)),

View File

@ -107,17 +107,35 @@ fn getTile(this: @This(), x: i32, y: i32) ?u8 {
return this.tiles[@intCast(u32, i)]; 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 top_left = rect.pos / tile_sizef;
const bot_right = (rect.pos + rect.size) / 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]); var i: isize = @floatToInt(i32, top_left[0]);
while (i <= @floatToInt(i32, bot_right[0])) : (i += 1) { while (i <= @floatToInt(i32, bot_right[0])) : (i += 1) {
var a: isize = @floatToInt(i32, top_left[1]); var a: isize = @floatToInt(i32, top_left[1]);
while (a <= @floatToInt(i32, bot_right[1])) : (a += 1) { while (a <= @floatToInt(i32, bot_right[1])) : (a += 1) {
if (this.isSolid(Cell{ i, a })) { if (this.isSolid(Cell{ i, a })) {
try collisions.append(util.AABB{ collisions.append(util.AABB{
.pos = Vec2f{ .pos = Vec2f{
@intToFloat(f32, i * tile_width), @intToFloat(f32, i * tile_width),
@intToFloat(f32, a * tile_height), @intToFloat(f32, a * tile_height),

View File

@ -30,8 +30,6 @@ pub const Sfx = struct {
flags: w4.ToneFlags, flags: w4.ToneFlags,
}; };
pub const MusicCommand = std.BoundedArray(Sfx, 4);
pub const Intensity = enum(u8) { pub const Intensity = enum(u8) {
calm = 0, calm = 0,
active = 1, active = 1,
@ -91,8 +89,9 @@ pub const Procedural = struct {
this.collect = .{ .score = score, .start = beatTotal + 1, .end = beatTotal + (this.beatsPerBar * length) + 1 }; this.collect = .{ .score = score, .start = beatTotal + 1, .end = beatTotal + (this.beatsPerBar * length) + 1 };
} }
pub fn getNext(this: *@This(), dt: u32) !MusicCommand { pub fn getNext(this: *@This(), dt: u32) MusicCommand {
var cmd = try MusicCommand.init(0); var i = 0;
var cmd: [4]Sfx = undefined;
const beatProgress = this.tick % this.beat; const beatProgress = this.tick % this.beat;
const beatTotal = @divTrunc(this.tick, this.beat); const beatTotal = @divTrunc(this.tick, this.beat);
const beat = beatTotal % this.beatsPerBar; 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; 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) { if (beatTotal >= collect.start and beatTotal < collect.end and playNote and beatProgress == 0) {
// const notelen = @intCast(u8, this.beat * this.beatsPerBar); // const notelen = @intCast(u8, this.beat * this.beatsPerBar);
try cmd.append(Sfx{ cmd[i] = (Sfx{
.freq = .{ .start = this.nextNote(this.note) }, .freq = .{ .start = this.nextNote(this.note) },
.duration = .{ .sustain = 5, .release = 5 }, .duration = .{ .sustain = 5, .release = 5 },
.volume = 25, .volume = 25,
.flags = .{ .channel = .pulse2, .mode = .p25 }, .flags = .{ .channel = .pulse2, .mode = .p25 },
}); });
i += 1;
this.note += 1; this.note += 1;
} }
if (bar > collect.end) { if (bar > collect.end) {
@ -116,24 +116,33 @@ pub const Procedural = struct {
this.collect = null; this.collect = null;
} }
} }
if (this.intensity.atLeast(.calm) and beat == 0 and beatProgress == 0) try cmd.append(.{ if (this.intensity.atLeast(.calm) and beat == 0 and beatProgress == 0) {
cmd[i] = (.{
.freq = .{ .start = 220, .end = 110 }, .freq = .{ .start = 220, .end = 110 },
.duration = .{ .release = 3 }, .duration = .{ .release = 3 },
.volume = 100, .volume = 100,
.flags = .{ .channel = .triangle }, .flags = .{ .channel = .triangle },
}); });
if (this.intensity.atLeast(.active) and beat == this.beatsPerBar / 2 and beatProgress == 0) try cmd.append(.{ i += 1;
}
if (this.intensity.atLeast(.active) and beat == this.beatsPerBar / 2 and beatProgress == 0) {
cmd[i] = (.{
.freq = .{ .start = 110, .end = 55 }, .freq = .{ .start = 110, .end = 55 },
.duration = .{ .release = 3 }, .duration = .{ .release = 3 },
.volume = 100, .volume = 100,
.flags = .{ .channel = .triangle }, .flags = .{ .channel = .triangle },
}); });
if (this.walking and beat % 3 == 1 and beatProgress == 7) try cmd.append(.{ i += 1;
}
if (this.walking and beat % 3 == 1 and beatProgress == 7) {
cmd[i] = (.{
.freq = .{ .start = 1761, .end = 1 }, .freq = .{ .start = 1761, .end = 1 },
.duration = .{ .release = 5 }, .duration = .{ .release = 5 },
.volume = 25, .volume = 25,
.flags = .{ .channel = .noise }, .flags = .{ .channel = .noise },
}); });
i += 1;
}
return cmd; return cmd;
} }
}; };

View File

@ -7,9 +7,14 @@ const State = @import("main.zig").State;
const std = @import("std"); const std = @import("std");
const w4 = @import("wasm4.zig"); const w4 = @import("wasm4.zig");
const world = @import("world.zig"); const world = @import("world.zig");
const util = @import("util.zig");
const Vec2 = w4.Vec2; 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_buf: [4096]u8 = undefined;
var frame_fba = std.heap.FixedBufferAllocator.init(&frame_fba_buf); var frame_fba = std.heap.FixedBufferAllocator.init(&frame_fba_buf);
var frame_alloc = frame_fba.allocator(); 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_buf: [400]u8 = undefined;
var circuit: Circuit = undefined; var circuit: Circuit = undefined;
var circuit_options: Circuit.Options = undefined;
var level_size = Vec2{ 20, 20 }; var level_size = Vec2{ 20, 20 };
pub fn start() !void { 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); map = Map.init(&map_buf, level_size);
var stream = std.io.FixedBufferStream([]const u8){ var stream = std.io.FixedBufferStream([]const u8){

View File

@ -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 { return struct {
data: std.BoundedArray(T, len), begin: usize,
pub fn init() !@This() { end: usize,
data: []T,
pub fn init(slice: []T) @This() {
return @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 { fn next(this: @This(), idx: usize) usize {
try this.data.insert(0, t); return ((idx + 1) % this.data.len);
} }
pub fn remove(this: *@This()) ?Cell { pub fn insert(this: *@This(), t: T) !void {
return this.data.popOrNull(); 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;
} }
}; };
} }