diff --git a/src/client.odin b/src/client.odin index 31703f5..f715c5a 100644 --- a/src/client.odin +++ b/src/client.odin @@ -4,58 +4,51 @@ import "core:fmt" import "core:net" Client_View :: struct { - num_hints: int, - num_lives: int, - players: []Player, + num_players: int, + num_hints: int, + num_lives: int, + other_players: []Player, } -unpack_card :: proc(c: Bit_Card) -> Card { - return {value = c.value, color = c.color} -} - -recv_payload :: proc(sock: net.TCP_Socket, allocator := context.allocator) -> Payload { - header: [3]byte +recv_payload :: proc(sock: net.TCP_Socket, allocator := context.allocator) -> (pl: Payload) { + header: [4]u8 net.recv(sock, header[:]) - num_cards := header[2] - body := make([]byte, num_cards) + num_cards := header[3] + body := make([]u8, num_cards) net.recv(sock, body) - return {header[0], header[1], header[2], transmute([]Bit_Card)body} -} - -num_players :: proc(num_cards: int) -> int { - switch num_cards { - case 5: - return 2 - case 10: - return 3 - case 12: - return 4 - case 16: - return 5 - case: - return -1 - } + pl = {header[0], header[1], header[2], header[3], transmute([]Card)body} + // sanity checks + assert(2 <= pl.num_players && pl.num_players <= 5) + assert(pl.num_hints >= 0 && pl.num_lives >= 0) + for c in pl.cards do assert(1 <= c.value && c.value <= 5) + return } create_view :: proc(pl: Payload, allocator := context.allocator) -> Client_View { - n := num_players(int(pl.num_cards)) - assert(n > 0) - players := make([]Player, n) - for i in 0 ..< n - 1 { - cards_per_hand := int(pl.num_cards) / (n - 1) + cards_per_hand := pl.num_cards / (pl.num_players - 1) + players: [dynamic]Player + i := 0 + for cast(u8)len(players) < pl.num_players - 1 { hand: [dynamic]Card - for c in 0 ..< cards_per_hand { - append(&hand, unpack_card(pl.cards[i * cards_per_hand + c])) + for cast(u8)len(hand) < cards_per_hand { + append(&hand, pl.cards[i]) + i += 1 } - players[i].hand = hand + append(&players, Player{hand = hand}) + } + + return { + num_players = int(pl.num_players), + num_hints = int(pl.num_hints), + num_lives = int(pl.num_lives), + other_players = players[:], } - return {num_hints = int(pl.num_hints), num_lives = int(pl.num_lives), players = players} } render_view :: proc(view: Client_View) { fmt.println("number of hints left:", view.num_hints) fmt.println("number of lives left:", view.num_lives) - for p in view.players { + for p in view.other_players { fmt.println() for c in p.hand { fmt.println(c.value, c.color) diff --git a/src/game.odin b/src/game.odin index 1dbb51b..f1ce3e5 100644 --- a/src/game.odin +++ b/src/game.odin @@ -3,21 +3,21 @@ package hanabi import "core:fmt" import "core:math/rand" -COLORS :: enum { - RED, - GREEN, - WHITE, - BLUE, - YELLOW, - RAINBOW, +COLORS :: enum u8 { + RED = 0b000, + GREEN = 0b001, + WHITE = 0b010, + BLUE = 0b011, + YELLOW = 0b100, + RAINBOW = 0b101, } -Card :: struct { - value: int, - color: COLORS, +Card :: bit_field u8 { + value: u8 | 3, + color: COLORS | 3, } -VALUES: []int : {1, 1, 1, 2, 2, 3, 3, 4, 4, 5} +VALUES: []u8 : {1, 1, 1, 2, 2, 3, 3, 4, 4, 5} Player :: struct { hand: [dynamic]Card, @@ -38,7 +38,7 @@ hand_size :: proc(g: Game) -> int { create_deck :: proc() -> (deck: [dynamic]Card) { for c in COLORS { for v in VALUES { - append(&deck, Card{v, c}) + append(&deck, Card{value = v, color = c}) } } rand.shuffle(deck[:]) diff --git a/src/server.odin b/src/server.odin index 49c4af8..0af881e 100644 --- a/src/server.odin +++ b/src/server.odin @@ -30,47 +30,34 @@ delete_comm_world :: proc(w: ^Comm_World) { delete(w.sockets) } - -/* -emulates Card, but packs the fields more neatly -*/ -Bit_Card :: bit_field u8 { - value: int | 3, - color: COLORS | 3, -} - -pack_card :: proc(c: Card) -> Bit_Card { - return {value = c.value, color = c.color} -} - Payload :: struct #packed { - num_hints: u8, - num_lives: u8, - num_cards: u8, - cards: []Bit_Card, + num_players: u8, + num_hints: u8, + num_lives: u8, + num_cards: u8, + cards: []Card, } create_payload :: proc(g: Game, player: int, allocator := context.allocator) -> Payload { - cards: [dynamic]Bit_Card + cards: [dynamic]Card for i in 0 ..< g.num_players { if i == player do continue hand := g.players[i].hand[:] - for c in hand { - append(&cards, pack_card(c)) - } + for c in hand do append(&cards, c) } - return {u8(g.hint_tokens), u8(g.lives_left), u8(len(cards)), cards[:]} + return {u8(g.num_players), u8(g.hint_tokens), u8(g.lives_left), u8(len(cards)), cards[:]} } send_payload :: proc(sock: net.TCP_Socket, pl: Payload) -> net.Network_Error { - data: [dynamic]byte + data: [dynamic]u8 defer delete(data) - append(&data, pl.num_hints, pl.num_lives, pl.num_cards) + append(&data, pl.num_players, pl.num_hints, pl.num_lives, pl.num_cards) for c in pl.cards do append(&data, transmute(u8)c) net.send(sock, data[:]) or_return return nil } +// TODO: add cli input for these DEFAULT_HINT_TOKENS :: 8 DEFAULT_LIVES :: 3