116 lines
2.0 KiB
Go
116 lines
2.0 KiB
Go
package game
|
|
|
|
import (
|
|
"github.com/zikaeroh/codies/internal/words"
|
|
)
|
|
|
|
// Team number, starting at zero.
|
|
type Team int
|
|
|
|
func (t Team) next(numTeams int) Team {
|
|
return (t + 1) % Team(numTeams)
|
|
}
|
|
|
|
type Tile struct {
|
|
// Immutable
|
|
Word string
|
|
Team Team
|
|
Neutral bool
|
|
Bomb bool
|
|
|
|
// Mutable
|
|
Revealed bool
|
|
}
|
|
|
|
type Board struct {
|
|
Rows, Cols int
|
|
WordCounts []int
|
|
tiles []*Tile // len(items)=rows*cols, access via items[row*rows + col]
|
|
}
|
|
|
|
func newBoard(rows, cols int, words words.List, startingTeam Team, numTeams int, rand Rand) *Board {
|
|
if startingTeam < 0 || int(startingTeam) >= numTeams {
|
|
panic("invalid starting team")
|
|
}
|
|
|
|
n := rows * cols
|
|
layout, ok := layouts[layoutKey{boardSize: n, numTeams: numTeams}]
|
|
if !ok {
|
|
panic("invalid board dimension")
|
|
}
|
|
|
|
// Copy and rotate teams to give the first team the most words.
|
|
old := layout.teams
|
|
layout.teams = append([]int(nil), old[startingTeam:]...)
|
|
layout.teams = append(layout.teams, old[:startingTeam]...)
|
|
wordCounts := append([]int(nil), layout.teams...)
|
|
|
|
items := make([]*Tile, n)
|
|
seen := make(map[int]struct{}, n)
|
|
|
|
for i := range items {
|
|
var w string
|
|
for {
|
|
j := rand.Intn(words.Len())
|
|
if _, ok := seen[j]; !ok {
|
|
seen[j] = struct{}{}
|
|
w = words.Get(j)
|
|
break
|
|
}
|
|
}
|
|
|
|
item := &Tile{Word: w}
|
|
|
|
ItemSwitch:
|
|
switch {
|
|
case layout.bomb > 0:
|
|
layout.bomb--
|
|
item.Bomb = true
|
|
|
|
case layout.neutral > 0:
|
|
layout.neutral--
|
|
item.Neutral = true
|
|
|
|
default:
|
|
for t, c := range layout.teams {
|
|
if c == 0 {
|
|
continue
|
|
}
|
|
|
|
layout.teams[t]--
|
|
item.Team = Team(t)
|
|
break ItemSwitch
|
|
}
|
|
|
|
panic("unreachable")
|
|
}
|
|
|
|
items[i] = item
|
|
}
|
|
|
|
rand.Shuffle(len(items), func(i, j int) {
|
|
items[i], items[j] = items[j], items[i]
|
|
})
|
|
|
|
return &Board{
|
|
Rows: rows,
|
|
Cols: cols,
|
|
WordCounts: wordCounts,
|
|
tiles: items,
|
|
}
|
|
}
|
|
|
|
func (b *Board) Get(row, col int) *Tile {
|
|
switch {
|
|
case row < 0:
|
|
case col < 0:
|
|
case row >= b.Rows:
|
|
case col >= b.Cols:
|
|
default:
|
|
i := row*b.Rows + col
|
|
return b.tiles[i]
|
|
}
|
|
|
|
return nil
|
|
}
|