// 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
}

// PlayOptions tunes optional rule variations applied when evaluating, validating or
// generating plays. The zero value is standard Scrabble.
type PlayOptions struct {
	// IgnoreCrossWords makes a play's perpendicular cross-words irrelevant: they are not
	// formed, validated, scored or used to constrain move generation. It expresses the
	// "single word per turn" house rule, under which only the main word along the play
	// direction must be a valid word. That main word must still connect by running through
	// an existing tile along its line — a tile that only abuts the board perpendicular to
	// that line does not connect — and the first-move centre rule still applies.
	IgnoreCrossWords bool
}
