From 6f42b35e1408872a780ae7442a7f8dcbe39220cc Mon Sep 17 00:00:00 2001 From: geemili Date: Tue, 27 Feb 2024 00:27:09 -0700 Subject: [PATCH] only activate "New Meld" when a valid meld is marked --- src/main.zig | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/main.zig b/src/main.zig index 412a08d..fd30b7b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -23,7 +23,7 @@ const GameState = struct { discard_pile: std.ArrayListUnmanaged(Card), hands: []std.ArrayListUnmanaged(Card), - marked_cards: std.AutoHashMapUnmanaged(Card, void), + marked_cards: std.AutoArrayHashMapUnmanaged(Card, void), pub fn init(allocator: std.mem.Allocator, seed: u64, num_players: usize) !@This() { var draw_pile = std.ArrayListUnmanaged(Card).fromOwnedSlice(try makeStandardDeck(allocator)); @@ -968,10 +968,11 @@ fn playerTurnHandler(arena: std.mem.Allocator, request: Request) HandlerError!Re var new_game_state = try request.game_state.clone(arena); if (new_game_state.marked_cards.contains(card)) { - _ = new_game_state.marked_cards.remove(card); + _ = new_game_state.marked_cards.swapRemove(card); } else { try new_game_state.marked_cards.put(arena, card, {}); } + new_game_state.marked_cards.sort(ArrayHashMapRummyHandSort{ .keys = new_game_state.marked_cards.keys() }); return Response{ .transition = .{ .game_state = new_game_state, @@ -982,8 +983,11 @@ fn playerTurnHandler(arena: std.mem.Allocator, request: Request) HandlerError!Re var new_meld_text = try TextElement.create(arena, .{ .text = "New Meld", - .command = "new-meld", + .command = null, }); + if (isValidRummyMeld(request.game_state.marked_cards.keys())) { + new_meld_text.command = "new-meld"; + } var melds_hbox = try HBox.create(arena); try melds_hbox.addElement(new_meld_text.element()); @@ -1015,6 +1019,48 @@ fn playerTurnHandler(arena: std.mem.Allocator, request: Request) HandlerError!Re return Response{ .page = page.element() }; } +fn isValidRummyMeld(cards: []const Card) bool { + std.debug.assert(std.sort.isSorted(Card, cards, {}, rummyHandSort)); + if (cards.len < 3) { + return false; + } + + const expected_rank = cards[0].rank; + var is_valid_set = true; + for (cards) |card| { + if (card.rank != expected_rank) { + is_valid_set = false; + break; + } + } + + const expected_suit = cards[0].suit; + var is_valid_run = true; + for (cards[0 .. cards.len - 1], cards[1..]) |prev_card, card| { + if (card.suit != expected_suit or card.rank != (prev_card.rank + 1)) { + is_valid_run = false; + break; + } + } + + return is_valid_set or is_valid_run; +} + +pub fn rummyHandSort(_: void, lhs: Card, rhs: Card) bool { + if (lhs.rank < rhs.rank) return true; + if (lhs.rank > rhs.rank) return false; + + return @intFromEnum(lhs.suit) < @intFromEnum(rhs.suit); +} + +const ArrayHashMapRummyHandSort = struct { + keys: []const Card, + + pub fn lessThan(this: @This(), lhs_index: usize, rhs_index: usize) bool { + return rummyHandSort({}, this.keys[lhs_index], this.keys[rhs_index]); + } +}; + fn glfw_framebuffer_size_callback(window: ?*seizer.backend.glfw.c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { _ = window; gl.viewport(