From d50c21c1e64322496e8f9aa2016b763dfb5b03cb Mon Sep 17 00:00:00 2001 From: Simen Kirkvik Date: Sun, 15 Mar 2026 14:23:40 +0100 Subject: [PATCH] Show current day and month Also check win state --- src/root.zig | 198 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 153 insertions(+), 45 deletions(-) diff --git a/src/root.zig b/src/root.zig index 7cacd66..107eca3 100644 --- a/src/root.zig +++ b/src/root.zig @@ -2,6 +2,9 @@ const std = @import("std"); const builtin = @import("builtin"); +const epoch = std.time.epoch; +const MonthAndDay = epoch.MonthAndDay; + pub const platform = @import("platform.zig"); const V2 = @import("V2.zig"); @@ -26,17 +29,27 @@ const Camera = struct { offset: V2, }; +const MonthOrDayTag = enum { + month, + day_index, +}; + +const MonthOrDay = union(MonthOrDayTag) { + month: epoch.Month, + day_index: u5, +}; + const BoardTile = struct { - blocked: bool, taken: bool, hovering: bool, + type: MonthOrDay, label: []const u8, - fn init(label: []const u8, blocked: bool) BoardTile { + fn init(label: []const u8, month_or_day: MonthOrDay) BoardTile { const result: BoardTile = .{ - .blocked = blocked, .taken = false, .hovering = false, + .type = month_or_day, .label = label, }; @@ -49,7 +62,7 @@ const Board = struct { width: u32, height: u32, tile_size: V2, - tiles: [7][7]BoardTile, + tiles: [7][7]?BoardTile, fn getTilePos(self: Board, i: usize, j: usize) V2 { const tile_pos = V2{ @@ -137,7 +150,9 @@ const State = struct { camera: Camera, font_image: Image, font: Font, + has_won: bool, draw_bounding_rects: bool, + month_and_day: MonthAndDay, grabbed_brick_index: ?usize, bricks: [8]Brick, board: Board, @@ -427,11 +442,10 @@ fn drawImage(buffer: platform.OffscreenBuffer, image: Image, pos: V2, scale: f32 } } -fn drawString(buffer: platform.OffscreenBuffer, font: Font, pos: V2, str: []const u8) void { +fn drawString(buffer: platform.OffscreenBuffer, font: Font, pos: V2, scale: f32, str: []const u8) void { const image = font.image; var current_pos = pos; const font_size = 32; - const scale = 0.5; const font_width_scaled = scale * font_size; for (str) |c| { const char_image_pos = font.findCharImagePos(c); @@ -500,6 +514,16 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu .y = @floatFromInt(@divTrunc(buffer.height, 2)), }; if (!memory.initialized) { + state.has_won = false; + + const timestamp = std.time.timestamp(); + const epoch_seconds = epoch.EpochSeconds{ .secs = @intCast(timestamp) }; + const epoch_day = epoch_seconds.getEpochDay(); + const year_and_day = epoch_day.calculateYearDay(); + const day: MonthAndDay = year_and_day.calculateMonthDay(); + + state.month_and_day = day; + state.camera.offset = mid; state.grabbed_brick_index = null; @@ -642,15 +666,26 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu .{ "29", "30", "31", null, null, null, null }, }; - var tiles: [7][7]BoardTile = undefined; + const tile_types = [7][7]?MonthOrDay{ + .{ .{ .month = epoch.Month.jan }, .{ .month = epoch.Month.feb }, .{ .month = epoch.Month.mar }, .{ .month = epoch.Month.apr }, .{ .month = epoch.Month.may }, .{ .month = epoch.Month.jun }, null }, + .{ .{ .month = epoch.Month.jul }, .{ .month = epoch.Month.aug }, .{ .month = epoch.Month.sep }, .{ .month = epoch.Month.oct }, .{ .month = epoch.Month.nov }, .{ .month = epoch.Month.dec }, null }, + .{ .{ .day_index = 0 }, .{ .day_index = 1 }, .{ .day_index = 2 }, .{ .day_index = 3 }, .{ .day_index = 4 }, .{ .day_index = 5 }, .{ .day_index = 6 } }, + .{ .{ .day_index = 7 }, .{ .day_index = 8 }, .{ .day_index = 9 }, .{ .day_index = 10 }, .{ .day_index = 11 }, .{ .day_index = 12 }, .{ .day_index = 13 } }, + .{ .{ .day_index = 14 }, .{ .day_index = 15 }, .{ .day_index = 16 }, .{ .day_index = 17 }, .{ .day_index = 18 }, .{ .day_index = 19 }, .{ .day_index = 20 } }, + .{ .{ .day_index = 21 }, .{ .day_index = 22 }, .{ .day_index = 23 }, .{ .day_index = 24 }, .{ .day_index = 25 }, .{ .day_index = 26 }, .{ .day_index = 27 } }, + .{ .{ .day_index = 28 }, .{ .day_index = 29 }, .{ .day_index = 30 }, null, null, null, null }, + }; + + var tiles: [7][7]?BoardTile = undefined; for (tile_names, 0..) |row, i| { for (row, 0..) |opt, j| { + tiles[i][j] = null; + if (opt) |tile| { - tiles[i][j] = BoardTile.init(tile, false); - } else { - tiles[i][j] = BoardTile.init("", true); - } + const tile_type = tile_types[i][j]; + tiles[i][j] = BoardTile.init(tile, tile_type.?); + } } } @@ -671,7 +706,9 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu memory.initialized = true; } + // // Update + // const mouse_pos = V2{ .x = @floatCast(input.mouse_x), .y = @floatCast(input.mouse_y) }; const mouse_world_pos = mouse_pos.sub(state.camera.pos); @@ -685,8 +722,11 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu } for (&state.board.tiles) |*board_row| { - for (board_row) |*board_tile| { - board_tile.hovering = false; + for (board_row) |*opt| { + if (opt.*) |*board_tile| { + board_tile.hovering = false; + board_tile.taken = false; + } } } @@ -717,17 +757,19 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu } for (&state.board.tiles, 0..) |*board_row, k| { - for (board_row, 0..) |*board_tile, l| { - const board_tile_pos = state.board.getTilePos(k, l); + for (board_row, 0..) |*opt, l| { + if (opt.*) |*board_tile| { + const board_tile_pos = state.board.getTilePos(k, l); - const in_tile = pointInsideRect(tile_mid, board_tile_pos, state.board.tile_size); - if (in_tile and !board_tile.blocked and !board_tile.taken) { - tile_board_index.* = BoardIndex.init(k, l); - // board_tile.taken = true; - } + const in_tile = pointInsideRect(tile_mid, board_tile_pos, state.board.tile_size); + if (in_tile and !board_tile.taken) { + tile_board_index.* = BoardIndex.init(k, l); + board_tile.taken = true; + } - if (!board_tile.hovering) { - board_tile.hovering = in_tile; + if (!board_tile.hovering) { + board_tile.hovering = in_tile; + } } } } @@ -775,6 +817,29 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu } } + // Check if player has won + var has_won = true; + for (state.board.tiles) |board_row| { + for (board_row) |opt| { + if (opt) |board_tile| { + const is_day_or_month = blk: { + switch (board_tile.type) { + .month => |m| { + break :blk state.month_and_day.month == m; + }, + .day_index => |d| { + break :blk state.month_and_day.day_index == d; + }, + } + }; + const valid = (board_tile.taken and !is_day_or_month) or (!board_tile.taken and is_day_or_month); + has_won = has_won and valid; + } + } + } + + state.has_won = has_won; + if (input.mouse_left_down and state.grabbed_brick_index == null) { const diff = mouse_pos.sub(state.mouse_pos); state.camera.pos = state.camera.pos.add(diff); @@ -782,7 +847,9 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu state.mouse_pos = mouse_pos; + // // Render + // fillRect(buffer, 0, 0, buffer.width, buffer.height, 0xFFFFFFFF); // Draw board @@ -790,32 +857,52 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu const board = state.board; for (board.tiles, 0..) |row, i| { - for (row, 0..) |tile, j| { - const tile_pos = board.getTilePos(i, j); - const width: i32 = @intFromFloat(board.tile_size.x); - const height: i32 = @intFromFloat(board.tile_size.y); + for (row, 0..) |opt, j| { + if (opt) |tile| { + const tile_pos = board.getTilePos(i, j); + const width: i32 = @intFromFloat(board.tile_size.x); + const height: i32 = @intFromFloat(board.tile_size.y); - const str_width = @divFloor(TILE_SIZE * tile.label.len, 4); - const str_height = @divFloor(32, 4); - const str_size = V2.initUSize(str_width, str_height); - const string_pos = tile_pos.add(board.tile_size.mul(0.5)).sub(str_size.mul(0.5)); + const str_width = @divFloor(TILE_SIZE * tile.label.len, 4); + const str_height = @divFloor(32, 4); + const str_size = V2.initUSize(str_width, str_height); + const string_pos = tile_pos.add(board.tile_size.mul(0.5)).sub(str_size.mul(0.5)); - var color: u32 = 0xFF000000; - if (tile.blocked) { - color = 0xFFFFFFFF; - } else if (tile.hovering) { - color = 0xFF00FF00; + var color: u32 = 0xFF000000; + + if (tile.hovering) { + color = 0xFF00FF00; + } + + const camera_pos = tile_pos.add(state.camera.pos); + const pos_x: i32 = @intFromFloat(camera_pos.x); + const pos_y: i32 = @intFromFloat(camera_pos.y); + + fillRect(buffer, pos_x, pos_y, width, height, color); + + var outline_color: u32 = 0xFFFFFFFF; + var outline_width: i32 = 2; + const is_day_color = 0xFFDA983C; + switch (tile.type) { + .month => |m| { + if (state.month_and_day.month == m) { + outline_color = is_day_color; + outline_width = 4; + } + }, + .day_index => |d| { + if (state.month_and_day.day_index == d) { + outline_color = is_day_color; + outline_width = 4; + } + }, + } + drawRect(buffer, camera_pos, board.tile_size, outline_color, outline_width); + + const string_camera_pos = string_pos.add(state.camera.pos); + const scale = 0.5; + drawString(buffer, state.font, string_camera_pos, scale, tile.label); } - - const camera_pos = tile_pos.add(state.camera.pos); - const pos_x: i32 = @intFromFloat(camera_pos.x); - const pos_y: i32 = @intFromFloat(camera_pos.y); - - fillRect(buffer, pos_x, pos_y, width, height, color); - drawRect(buffer, camera_pos, board.tile_size, 0xFFFFFFFF, 2); - - const string_camera_pos = string_pos.add(state.camera.pos); - drawString(buffer, state.font, string_camera_pos, tile.label); } } } @@ -873,6 +960,27 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu } } } + // + // UI + // + if (state.has_won) { + const scale = 1.0; + const text = "YOU WON"; + const str_len = @as(i32, @intCast(text.len)) * state.font.glyph_width; + const half = @divFloor(buffer.width, 2); + const width = half - @divFloor(str_len, 2); + + drawString(buffer, state.font, V2.initI32(width, 32), scale, text); + } + + { + const scale = 0.5; + const height = buffer.height - state.font.glyph_height; + + drawString(buffer, state.font, V2.initI32(8, height - state.font.glyph_height), scale, "Flip: w"); + + drawString(buffer, state.font, V2.initI32(8, height - 8), scale, "Rotate: e"); + } state.frame_count += 1; }