diff --git a/showcase/carts/blobs/build.zig b/showcase/carts/blobs/build.zig index 8d9c212..68d2e65 100644 --- a/showcase/carts/blobs/build.zig +++ b/showcase/carts/blobs/build.zig @@ -2,9 +2,9 @@ const std = @import("std"); const sycl_badge = @import("sycl_badge"); pub const author_name = "Jonathan Marler"; -pub const author_handle = "marler"; +pub const author_handle = "marler8997"; pub const cart_title = "blobs"; -pub const description = ": get Marler to give a description"; +pub const description = "Little Blob, Eat Blob, Big Blob"; pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); diff --git a/showcase/carts/neopixelpuzzle/build.zig b/showcase/carts/neopixelpuzzle/build.zig new file mode 100644 index 0000000..fb6b00b --- /dev/null +++ b/showcase/carts/neopixelpuzzle/build.zig @@ -0,0 +1,19 @@ +const std = @import("std"); +const sycl_badge = @import("sycl_badge"); + +pub const author_name = "Jonathan Marler"; +pub const author_handle = "marler8997"; +pub const cart_title = "neopixelpuzzle"; +pub const description = "Light up all the neo pixels in this simple puzzle game!"; + +pub fn build(b: *std.Build) void { + const optimize = b.standardOptimizeOption(.{}); + const sycl_badge_dep = b.dependency("sycl_badge", .{}); + + const cart = sycl_badge.add_cart(sycl_badge_dep, b, .{ + .name = "neopixelpuzzle", + .optimize = optimize, + .root_source_file = b.path("src/main.zig"), + }); + cart.install(b); +} diff --git a/showcase/carts/neopixelpuzzle/build.zig.zon b/showcase/carts/neopixelpuzzle/build.zig.zon new file mode 100644 index 0000000..c1d7130 --- /dev/null +++ b/showcase/carts/neopixelpuzzle/build.zig.zon @@ -0,0 +1,12 @@ +.{ + .name = "neopixelpuzzle", + .version = "0.0.0", + .dependencies = .{ + .sycl_badge = .{ .path = "../../.." }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/showcase/carts/neopixelpuzzle/src/main.zig b/showcase/carts/neopixelpuzzle/src/main.zig new file mode 100644 index 0000000..216ae80 --- /dev/null +++ b/showcase/carts/neopixelpuzzle/src/main.zig @@ -0,0 +1,188 @@ +const std = @import("std"); +const cart = @import("cart-api"); + +const StartMenu = struct { + seed: u32, + start_pressed: bool = false, +}; +const Play = struct { + pos: u3, + grid: [5][2]bool, + left_pressed: bool = false, + right_pressed: bool = false, + a_pressed: bool = false, + b_pressed: bool = false, + start_pressed: bool = false, +}; +const Win = struct { + frame: u32 = 0, + start_pressed: bool = false, +}; +const Mode = union(enum) { + start_menu: StartMenu, + play: Play, + win: Win, +}; +const global = struct { + pub var mode = Mode{ + .start_menu = .{ .seed = 0 }, + }; +}; + +const Button = enum { + start, + a, b, + up, down, left, right, + pub fn isDown(self: Button) bool { + switch (self) { + .start => return cart.controls.start, + .a => return cart.controls.a, + .b => return cart.controls.b, + .up => return cart.controls.up, + .down => return cart.controls.down, + .left => return cart.controls.left, + .right => return cart.controls.right, + } + } +}; + +// Used to tell if a button is "triggered". +// Prevents the "down" state from triggering multiple events. +fn isButtonTriggered( + button: Button, + released_state_ref: *bool, +) bool { + const pressed = button.isDown(); + if (released_state_ref.*) { + if (pressed) released_state_ref.* = false; + return pressed; + } else { + if (!pressed) { + released_state_ref.* = true; + } + return false; + } +} + +fn clear() void { + cart.neopixels.* = .{ + .{ .r = 0, .g = 0, .b = 0 }, + .{ .r = 0, .g = 0, .b = 0 }, + .{ .r = 0, .g = 0, .b = 0 }, + .{ .r = 0, .g = 0, .b = 0 }, + .{ .r = 0, .g = 0, .b = 0 }, + }; +} + +export fn start() void { + clear(); +} + +export fn update() void { + switch (global.mode) { + .start_menu => updateStartMenu(&global.mode.start_menu), + .play => updatePlayMode(&global.mode.play), + .win => updateWinMode(&global.mode.win), + } +} + +const on = cart.NeopixelColor{ .r = 1, .g = 1, .b = 1 }; +const off = cart.NeopixelColor{ .r = 0, .g = 0, .b = 0 }; + +const on_selected = cart.NeopixelColor{ .r = 1, .g = 1, .b = 0 }; +const off_selected = cart.NeopixelColor{ .r = 0, .g = 0, .b = 1 }; + +fn newGame(seed: u32) void { + clear(); + global.mode = Mode{ + .play = .{ + .pos = 2, + .grid = [5][2]bool{ + [2]bool{ false, true }, + [2]bool{ false, true }, + [2]bool{ false, true }, + [2]bool{ false, true }, + [2]bool{ false, true }, + }, + }, + }; + + var rand = std.rand.DefaultPrng.init(seed); + for (0 .. 100) |_| { + var buf: [1]u8 = undefined; + rand.fill(&buf); + rotate(&global.mode.play.grid, @intCast(buf[0] % 5)); + } +} + +fn updateStartMenu(start_menu: *StartMenu) void { + start_menu.seed +%= 1; + if (isButtonTriggered(.start, &start_menu.start_pressed)) { + const seed = start_menu.seed; + newGame(seed); + return; + } + cart.neopixels[(start_menu.seed +% 4) % 5] = off; + cart.neopixels[start_menu.seed % 5] = on; +} + +fn updatePlayMode(play: *Play) void { + + if (isButtonTriggered(.a, &play.a_pressed)) { + rotate(&play.grid, play.pos); + } else if (isButtonTriggered(.b, &play.b_pressed)) { + for (0 .. 3) |_| { + rotate(&play.grid, play.pos); + } + } else if (isButtonTriggered(.right, &play.right_pressed)) { + play.pos = (play.pos + 1) % 5; + } else if (isButtonTriggered(.left, &play.left_pressed)) { + play.pos = @intCast((@as(usize, play.pos) + 4) % 5); + } else if (isButtonTriggered(.start, &play.start_pressed)) { + clear(); + global.mode = Mode{ .start_menu = .{ .seed = 0 } }; + } + + var win = true; + for (0 .. 5) |i| { + if (!play.grid[i][1]) { + win = false; + break; + } + } + + if (win) { + clear(); + global.mode = Mode{ .win = .{} }; + return; + } + + for (0 .. 5) |i| { + if (play.pos == i or i == ((play.pos + 1) % 5)) { + cart.neopixels[i] = if (play.grid[i][1]) on_selected else off_selected; + } else { + cart.neopixels[i] = if (play.grid[i][1]) on else off; + } + } +} + +fn updateWinMode(win: *Win) void { + if (isButtonTriggered(.start, &win.start_pressed)) { + const seed = win.frame; + newGame(seed); + return; + } + + win.frame +%= 1; + cart.neopixels[(win.frame +% 4) % 5] = off; + cart.neopixels[win.frame % 5] = on_selected; +} + +fn rotate(grid: *[5][2]bool, pos: u3) void { + const t = grid[pos][0]; + const pos2 = (pos + 1) % 5; + grid[pos][0] = grid[pos][1]; + grid[pos][1] = grid[pos2][1]; + grid[pos2][1] = grid[pos2][0]; + grid[pos2][0] = t; +}