package hanabi import "core:math/rand" VALUES :: []u8{1, 1, 1, 2, 2, 3, 3, 4, 4, 5} COLORS :: enum u8 { RED = 0b000001, GREEN = 0b000010, WHITE = 0b000100, BLUE = 0b001000, YELLOW = 0b010000, RAINBOW = 0b100000, } Card :: bit_field u8 { value: u8 | 3, color: COLORS | 3, _player: u8 | 2, } Hand :: distinct []Card // 6 piles, one for each in COLORS. // u8 between 0-5, representing highest card in pile. // player can only place card of value `played[color]+1`. Played_Card_Piles :: distinct [6]u8 Belief_State :: []bit_field u16 { // `11111` can be any value 1-5. // `00010` must be value 4. value: u8 | 5, // `111111` can be any color. // `100001` can be red or rainbow. color: u8 | 6, } Game :: struct { num_players: int, num_hints: int, num_lives: int, hand_size: int, played: Played_Card_Piles, player_hands: []Hand, player_beliefs: []Belief_State, deck: [dynamic]Card, } create_deck :: proc() -> (deck: [dynamic]Card) { for c in COLORS { for v in VALUES { append(&deck, Card{value = v, color = c}) } } rand.shuffle(deck[:]) return } deal_hands :: proc( deck: ^[dynamic]Card, num_players, hand_size: int, allocator := context.allocator, ) -> []Hand { player_hands: [dynamic]Hand for i in 0 ..< num_players { start := len(deck) - hand_size hand := Hand(deck[start:]) append(&player_hands, hand) resize(deck, start) } return player_hands[:] } init_beliefs :: proc( num_players, hand_size: int, allocator := context.allocator, ) -> []Belief_State { player_beliefs: [dynamic]Belief_State for p in 0 ..< num_players { bs: Belief_State for c in 0 ..< hand_size { bs[c].value = 0b11111 bs[c].color = 0b111111 } append(&player_beliefs, bs) } return player_beliefs[:] } create_game :: proc(hint_tokens, lives_left, num_players: int) -> (s: Game) { assert(num_players >= 2 && num_players <= 5) s.num_players = num_players s.num_hints = hint_tokens s.num_lives = lives_left s.hand_size = num_players <= 3 ? 5 : 4 s.deck = create_deck() s.player_hands = deal_hands(&s.deck, num_players, s.hand_size) s.player_beliefs = init_beliefs(num_players, s.hand_size) return } delete_game :: proc(g: ^Game) { delete(g.deck) delete(g.player_hands) }