106 lines
2.2 KiB
Odin
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)
|
|
}
|