// Package rack represents a player's rack as per-letter tile counts plus blanks. package rack // Rack holds tile counts: one slot per alphabet letter index plus a final slot for // blanks. Like a Go slice or map, a Rack value shares its underlying storage with its // copies; use Clone for an independent rack. The move generator mutates a single Rack // in place (removing a tile, recursing, putting it back). type Rack struct { counts []int } // New returns an empty rack for an alphabet of the given size. func New(alphabetSize int) Rack { return Rack{counts: make([]int, alphabetSize+1)} } func (r Rack) blankIdx() int { return len(r.counts) - 1 } // Count returns how many tiles of the given letter index are on the rack. func (r Rack) Count(letter byte) int { return r.counts[letter] } // Has reports whether at least one tile of the given letter index is on the rack. func (r Rack) Has(letter byte) bool { return r.counts[letter] > 0 } // Blanks returns the number of blank tiles on the rack. func (r Rack) Blanks() int { return r.counts[r.blankIdx()] } // Total returns the number of tiles on the rack, blanks included. func (r Rack) Total() int { n := 0 for _, c := range r.counts { n += c } return n } // Empty reports whether the rack holds no tiles. func (r Rack) Empty() bool { return r.Total() == 0 } // Add puts a tile of the given letter index onto the rack. func (r Rack) Add(letter byte) { r.counts[letter]++ } // AddBlank puts a blank tile onto the rack. func (r Rack) AddBlank() { r.counts[r.blankIdx()]++ } // Remove takes one tile of the given letter index off the rack. func (r Rack) Remove(letter byte) { r.counts[letter]-- } // RemoveBlank takes one blank tile off the rack. func (r Rack) RemoveBlank() { r.counts[r.blankIdx()]-- } // Clone returns an independent copy of the rack. func (r Rack) Clone() Rack { c := make([]int, len(r.counts)) copy(c, r.counts) return Rack{counts: c} }