1package game
2
3import (
4 "github.com/zikaeroh/codies/internal/words"
5)
6
7// Team number, starting at zero.
8type Team int
9
10func (t Team) next(numTeams int) Team {
11 return (t + 1) % Team(numTeams)
12}
13
14type Tile struct {
15 // Immutable
16 Word string
17 Team Team
18 Neutral bool
19 Bomb bool
20
21 // Mutable
22 Revealed bool
23}
24
25type Board struct {
26 Rows, Cols int
27 WordCounts []int
28 tiles []*Tile // len(items)=rows*cols, access via items[row*rows + col]
29}
30
31func newBoard(rows, cols int, words words.List, startingTeam Team, numTeams int, rand Rand) *Board {
32 if startingTeam < 0 || int(startingTeam) >= numTeams {
33 panic("invalid starting team")
34 }
35
36 n := rows * cols
37 layout, ok := layouts[layoutKey{boardSize: n, numTeams: numTeams}]
38 if !ok {
39 panic("invalid board dimension")
40 }
41
42 // Copy and rotate teams to give the first team the most words.
43 old := layout.teams
44 layout.teams = append([]int(nil), old[startingTeam:]...)
45 layout.teams = append(layout.teams, old[:startingTeam]...)
46 wordCounts := append([]int(nil), layout.teams...)
47
48 items := make([]*Tile, n)
49 seen := make(map[int]struct{}, n)
50
51 for i := range items {
52 var w string
53 for {
54 j := rand.Intn(words.Len())
55 if _, ok := seen[j]; !ok {
56 seen[j] = struct{}{}
57 w = words.Get(j)
58 break
59 }
60 }
61
62 item := &Tile{Word: w}
63
64 ItemSwitch:
65 switch {
66 case layout.bomb > 0:
67 layout.bomb--
68 item.Bomb = true
69
70 case layout.neutral > 0:
71 layout.neutral--
72 item.Neutral = true
73
74 default:
75 for t, c := range layout.teams {
76 if c == 0 {
77 continue
78 }
79
80 layout.teams[t]--
81 item.Team = Team(t)
82 break ItemSwitch
83 }
84
85 panic("unreachable")
86 }
87
88 items[i] = item
89 }
90
91 rand.Shuffle(len(items), func(i, j int) {
92 items[i], items[j] = items[j], items[i]
93 })
94
95 return &Board{
96 Rows: rows,
97 Cols: cols,
98 WordCounts: wordCounts,
99 tiles: items,
100 }
101}
102
103func (b *Board) Get(row, col int) *Tile {
104 switch {
105 case row < 0:
106 case col < 0:
107 case row >= b.Rows:
108 case col >= b.Cols:
109 default:
110 i := row*b.Rows + col
111 return b.tiles[i]
112 }
113
114 return nil
115}