Files
hanabi/src/game.odin
T
2026-06-06 14:21:09 +02:00

106 lines
2.2 KiB
Odin

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)
}