Implement Scrabble move generator (DAWG) with English and Russian rules
A Go library that returns every legal play ranked by score and scores or validates plays, using the Appel-Jacobson DAWG algorithm over github.com/iliadenisov/dafsa v1.1.0. - DAWG move generation (across / down / both), full tournament scoring with a per-tile breakdown; public Solver: GenerateMoves (ranked), ScorePlay, ValidatePlay. - Rulesets: English Scrabble, Russian Scrabble, Эрудит (parameterizable Ruleset). - cmd/builddict (build the DAWG from the dictionaries submodule), cmd/stress (self-play benchmark), selfplay engine; brute-force test oracle. - A GADDAG was implemented, benchmarked and removed (the DAWG was smaller and faster for a scoring solver); see RESULTS.md and ALGORITHM.md.
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
// Package scrabble is the public library: it builds a move generator over a dictionary
|
||||
// and a ruleset, generates every legal play for a position ranked by score, and scores
|
||||
// or validates arbitrary plays. The generator is the DAWG algorithm (Appel-Jacobson).
|
||||
package scrabble
|
||||
|
||||
// Direction is the orientation of a play's main word.
|
||||
type Direction uint8
|
||||
|
||||
const (
|
||||
// Horizontal is an across play (left to right along a row).
|
||||
Horizontal Direction = iota
|
||||
// Vertical is a down play (top to bottom along a column).
|
||||
Vertical
|
||||
)
|
||||
|
||||
// String renders the direction for diagnostics.
|
||||
func (d Direction) String() string {
|
||||
if d == Vertical {
|
||||
return "vertical"
|
||||
}
|
||||
return "horizontal"
|
||||
}
|
||||
|
||||
// Mode selects which orientations GenerateMoves produces. Russian "Эрудит" requires a
|
||||
// single orientation per turn, which OnlyHorizontal / OnlyVertical express.
|
||||
type Mode uint8
|
||||
|
||||
const (
|
||||
// Both generates across plays (on the board) and down plays (on its transpose).
|
||||
Both Mode = iota
|
||||
// OnlyHorizontal generates across plays only.
|
||||
OnlyHorizontal
|
||||
// OnlyVertical generates down plays only.
|
||||
OnlyVertical
|
||||
)
|
||||
|
||||
// Includes reports whether the mode produces plays in direction d.
|
||||
func (m Mode) Includes(d Direction) bool {
|
||||
switch m {
|
||||
case Both:
|
||||
return true
|
||||
case OnlyHorizontal:
|
||||
return d == Horizontal
|
||||
case OnlyVertical:
|
||||
return d == Vertical
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Placement is a single newly-placed tile.
|
||||
type Placement struct {
|
||||
Row, Col int
|
||||
Letter byte // alphabet letter index
|
||||
Blank bool // placed from a blank tile, so it scores 0
|
||||
}
|
||||
|
||||
// Word is a word formed by a play, with its location and score.
|
||||
type Word struct {
|
||||
Row, Col int // square of the word's first letter
|
||||
Dir Direction // orientation of the word
|
||||
Letters []byte // alphabet indices of the whole word (existing + new tiles)
|
||||
Blanks []bool // per letter: true if that tile is a blank (scores 0)
|
||||
Score int // the word's score, with premiums from newly-placed tiles
|
||||
}
|
||||
|
||||
// Move is a complete legal play with a full scoring breakdown.
|
||||
type Move struct {
|
||||
Dir Direction // orientation of the main word
|
||||
Tiles []Placement // the newly-placed tiles, in main-word order
|
||||
Main Word // the main word formed along Dir
|
||||
Cross []Word // perpendicular words formed by the new tiles
|
||||
Bonus int // all-tiles (bingo) bonus included in Score, or 0
|
||||
Score int // total: Main.Score + Σ Cross.Score + Bonus
|
||||
}
|
||||
Reference in New Issue
Block a user