Show current day and month

Also check win state
This commit is contained in:
2026-03-15 14:23:40 +01:00
parent 13c118d819
commit d50c21c1e6
+153 -45
View File
@@ -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;
}