import { type Gaddag } from '@kamilmielnik/gaddag'; import { type Board, type Config, type ResultJson, type Tile } from '@scrabble-solver/types'; /** * Anchor-based move generation over a {@link Gaddag} (Gordon, 1994). * * For every anchor (an empty cell adjacent to a tile, or the board center when * the board is empty) the generator extends leftwards from the anchor through * the reversed-prefix part of the GADDAG, crosses the separator, and extends * rightwards — validating perpendicular words with precomputed cross-check * masks. Both directions run the same code path: the vertical pass remaps * (line, position) to transposed coordinates. Each placement is scored and * emitted as a compact {@link ResultJson} — placed tiles plus placement — from * which {@link Result.fromJson} rebuilds the full cells and collisions against * the board. */ export declare class MoveGenerator { private readonly gaddag; private readonly config; private readonly width; private readonly height; private readonly cellsCount; private readonly alphaSize; private readonly alphaChars; private readonly alphaLetter1; private readonly alphaLetter2; private readonly alphaPoints; private readonly leftAlphaStart; private readonly leftAlphaList; private readonly rightAlphaStart; private readonly rightAlphaList; private readonly alphaSecondLeft; private readonly alphaSecondRight; private readonly rackCounts; private blanksLeft; private rackTotal; private readonly bonusType; private readonly bonusMult; private readonly bonusReq; private readonly boardFilled; private readonly boardChar; private readonly boardIsBlank; private readonly boardScore; private readonly boardLetter1; private readonly boardLetter2; private readonly anchor; private boardIsEmpty; private isHorizontal; private lineLength; private linesCount; private readonly passFilled; private readonly passLetter1; private readonly passLetter2; private readonly passScore; private readonly passGlobal; private readonly passAnchor; private readonly maskLo; private readonly maskHi; private readonly crossBase; private readonly hasCross; private line; private lineBase; private anchorPos; private limit; private anchorRightOpen; private leftMost; private readonly placedAt; private readonly placedBlankAt; private placedCount; private readonly digraphs; private readonly blankScore; private readonly rackSize; private readonly seenSingleTiles; private readonly results; private readonly sortKeys; private readonly rankKeys; private readonly alphaFirstRackIndex; private blankRackIndex; constructor(gaddag: Gaddag, config: Config, board: Board, tiles: Tile[]); run(): ResultJson[]; private runPass; private setupPass; /** * For every empty cell with perpendicular neighbors, computes the set of * placeable tile characters (as a 64-bit mask), the sum of the existing * perpendicular tiles' scores, and the perpendicular word span. */ private computeCrossChecks; /** * A digraph must be played as its single tile, so a candidate that would * spell a digraph with the adjacent perpendicular tile is not placeable. * {@link record} enforces the same rule along the main word. */ private spellsDigraphWithNeighbor; private isOpen; private generateLeft; private generateRight; /** * Tries every rack tile (and blank interpretation) at an empty cell, * recursing further. Iterates the state's arcs instead of the alphabet: * deep GADDAG states have very few arcs, so this is much cheaper than * probing every letter. */ private placeAt; private pushPlacement; private popPlacement; private afterPlacement; /** * Records a word that ends at the anchor (a pure reversed-word GADDAG path). * Words spanning a single cell are skipped: a lone tile's word is the * perpendicular one, generated by the other pass. */ private recordLeftIfWord; private record; private hasInvalidDigraph; private characterAt; }