server: create/send payload

This commit is contained in:
2026-05-24 20:19:18 +02:00
parent f3314587d8
commit da51c5871b
3 changed files with 108 additions and 17 deletions
+15 -7
View File
@@ -31,8 +31,8 @@ Game :: struct {
deck: [dynamic]Card,
}
hand_size :: proc(s: Game) -> int {
return s.num_players <= 3 ? 5 : 4
hand_size :: proc(g: Game) -> int {
return g.num_players <= 3 ? 5 : 4
}
create_deck :: proc() -> (deck: [dynamic]Card) {
@@ -45,9 +45,9 @@ create_deck :: proc() -> (deck: [dynamic]Card) {
return
}
create_player :: proc(s: ^Game) -> (p: Player) {
for i in 0 ..< hand_size(s^) {
append(&p.hand, pop(&s.deck))
create_player :: proc(g: ^Game) -> (p: Player) {
for i in 0 ..< hand_size(g^) {
append(&p.hand, pop(&g.deck))
}
return
}
@@ -63,8 +63,16 @@ create_game :: proc(hint_tokens, lives_left, num_players: int) -> (s: Game) {
return
}
print_game :: proc(s: Game) {
for p in s.players {
delete_game :: proc(g: ^Game) {
delete(g.deck)
for &p in g.players {
delete(p.hand)
}
delete(g.players)
}
print_game :: proc(g: Game) {
for p in g.players {
fmt.println("---")
for c in p.hand {
fmt.println(c.value, c.color)
+1 -1
View File
@@ -37,7 +37,7 @@ main :: proc() {
if !endpoint_ok do panic(fmt.tprintln("failed to parse endpoint:", os.args[2]))
num_players, int_ok := strconv.parse_int(os.args[3])
if !int_ok do panic(fmt.tprintln("failed to parse number of players:", os.args[3]))
if num_players < 2 || num_players > 5 do return
if num_players < 1 || num_players > 5 do return
run_server(addr, num_players)
case:
return
+92 -9
View File
@@ -1,23 +1,106 @@
package hanabi
import "core:fmt"
import "core:math/rand"
import "core:net"
run_server :: proc(listen_addr: net.Endpoint, num_players: int) {
Comm_World :: struct {
sockets: [dynamic]net.TCP_Socket,
}
create_comm_world :: proc(
listener: net.TCP_Socket,
num_conn: int,
) -> (
w: Comm_World,
err: net.Network_Error,
) {
for len(w.sockets) < num_conn {
client_sock, source := net.accept_tcp(listener) or_return
append(&w.sockets, client_sock)
fmt.println("player connected:", net.to_string(source))
}
return
}
delete_comm_world :: proc(w: ^Comm_World) {
for sock in w.sockets {
net.close(sock)
}
delete(w.sockets)
}
/*
emulates Card, but packs the fields more neatly
*/
Bit_Card :: bit_field u8 {
value: int | 3,
color: COLORS | 3,
}
Payload :: struct #packed {
num_hints: u8,
num_lives: u8,
num_cards: u8,
cards: []Bit_Card,
}
create_payload :: proc(g: Game, player: int, allocator := context.allocator) -> Payload {
cards: [dynamic]Bit_Card
for i in 0 ..< g.num_players {
if i == player do continue
hand := g.players[i].hand[:]
for c in hand {
append(&cards, Bit_Card{value = c.value, color = c.color})
}
}
return {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
defer delete(data)
append(&data, 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
}
DEFAULT_HINT_TOKENS :: 8
DEFAULT_LIVES :: 3
run_server :: proc(
listen_addr: net.Endpoint,
num_players: int,
num_hints := DEFAULT_HINT_TOKENS,
num_lives := DEFAULT_LIVES,
) {
listener, list_err := net.listen_tcp(listen_addr)
if list_err != nil do panic(fmt.tprintln("failed to listen:", net.to_string(listen_addr)))
defer net.close(listener)
players: [dynamic]net.TCP_Socket
defer delete(players)
w, comm_err := create_comm_world(listener, num_players)
if comm_err != nil do panic(fmt.tprintln("failed to create comm world:", comm_err))
defer delete_comm_world(&w)
for len(players) < num_players {
client_sock, source, err := net.accept_tcp(listener)
if err != nil {
fmt.eprintln("failed to connect:", err, source)
g := create_game(num_hints, num_lives, num_players)
defer delete_game(&g)
current_player := rand.int_max(num_players)
game_loop: for {
for i in 0 ..< num_players {
pl := create_payload(g, i, context.temp_allocator)
send_err := send_payload(w.sockets[i], pl)
if send_err != nil do panic("failed to send payload")
}
append(&players, client_sock)
fmt.println("player connected:", net.to_string(source))
fmt.printfln("player %s's turn!", current_player)
// body
current_player = (current_player + 1) % num_players
free_all(context.temp_allocator)
}
}