package scrabble import ( "scrabble-solver/board" "scrabble-solver/rack" "scrabble-solver/rules" ) // generateBoth runs an across-generator on the board (for horizontal plays) and on its // transpose (for vertical plays), as selected by mode, then scores and de-duplicates the // results. runAcross reports placements in the coordinates of the board it is given; for // the transpose pass they are mapped back to the real board. func generateBoth(b *board.Board, rs *rules.Ruleset, rk rack.Rack, mode Mode, runAcross func(bd *board.Board, rk rack.Rack, emit func([]Placement))) []Move { rk = rk.Clone() // generation mutates the rack in place and restores it var moves []Move seen := make(map[string]struct{}) emit := func(dir Direction, placements []Placement) { key := moveKey(dir, placements) if _, dup := seen[key]; dup { return } m, err := Evaluate(b, rs, dir, placements) if err != nil { return } seen[key] = struct{}{} moves = append(moves, m) } if mode.Includes(Horizontal) { runAcross(b, rk, func(p []Placement) { emit(Horizontal, p) }) } if mode.Includes(Vertical) { tb := b.Transpose() runAcross(tb, rk, func(p []Placement) { rp := make([]Placement, len(p)) for i, pl := range p { rp[i] = Placement{Row: pl.Col, Col: pl.Row, Letter: pl.Letter, Blank: pl.Blank} } emit(Vertical, rp) }) } return moves } // centerFor returns the centre square in bd's coordinates. bd is either the real board // or its transpose; the ruleset stores the centre on the real board. func centerFor(bd *board.Board, rs *rules.Ruleset) (row, col int) { r, c := rs.Center/rs.Cols, rs.Center%rs.Cols if bd.Rows() == rs.Rows && bd.Cols() == rs.Cols { return r, c } return c, r // transposed }