90eaf4964b
Tests · Go / test (push) Successful in 10s
Tests · Integration / integration (push) Successful in 12s
Tests · UI / test (push) Successful in 19s
Tests · Go / test (pull_request) Successful in 9s
Tests · Integration / integration (pull_request) Successful in 12s
Tests · UI / test (pull_request) Successful in 19s
Live play now exchanges per-variant alphabet indices instead of concrete letters (rack out; submit-play, evaluate, exchange, word-check in). The client caches each variant's (index, letter, value) table behind StateRequest.include_alphabet and renders the rack and blank chooser from it, dropping the hardcoded value/alphabet tables. History, the durable journal and GCG stay decoded concrete characters (ARCHITECTURE §9.1, unchanged). - pkg/fbs: new AlphabetEntry + PlayTile; StateView.rack -> [ubyte] + alphabet; StateRequest.include_alphabet; SubmitPlay/Eval tiles -> [PlayTile]; Exchange tiles + CheckWord word -> [ubyte] (committed Go + TS regenerated). - engine: AlphabetTable + a cached per-variant codec (LetterForIndex/EncodeRack/ DecodeTiles/DecodeWord) + BlankIndex sentinel; Go parity test. - backend server edge maps index<->letter (new thin game.Service.GameVariant); game.Service domain methods, engine.Game and the robot keep one letter-based play path. The gateway forwards indices verbatim (no alphabet table). - ui: lib/alphabet.ts in-memory cache; codec encodes/decodes indices; premiums.ts is geometry-only; the mock seeds a fixture table; the UI normalises display to upper case (codec + cache), leaving placement/board/checkword unchanged. Parity moved to the Go engine.AlphabetTable test; premiums.ts loses its value tables. Discharges TODO-4.
90 lines
2.5 KiB
TypeScript
90 lines
2.5 KiB
TypeScript
// Board premium layout — the 15x15 premium-square geometry, ported from the engine source
|
|
// of truth, scrabble-solver/rules/rules.go (standardBoard / eruditBoard). The board is not
|
|
// transmitted on the wire (StateView has no board), so the client renders the premiums
|
|
// locally; only the centre differs by variant. A Vitest parity test pins the geometry.
|
|
// Tile values and the alphabet moved to the server-sent per-variant table in Stage 13 (see
|
|
// lib/alphabet.ts), so this file is geometry only.
|
|
|
|
import type { Variant } from './model';
|
|
|
|
export const BOARD_SIZE = 15;
|
|
|
|
export type Premium = '' | 'TW' | 'DW' | 'TL' | 'DL';
|
|
|
|
// Legend (rules.go): T=triple word, D=double word, t=triple letter, d=double
|
|
// letter, .=plain, *=centre (a double word), +=centre with no premium.
|
|
const standardBoard = [
|
|
'T..d...T...d..T',
|
|
'.D...t...t...D.',
|
|
'..D...d.d...D..',
|
|
'd..D...d...D..d',
|
|
'....D.....D....',
|
|
'.t...t...t...t.',
|
|
'..d...d.d...d..',
|
|
'T..d...*...d..T',
|
|
'..d...d.d...d..',
|
|
'.t...t...t...t.',
|
|
'....D.....D....',
|
|
'd..D...d...D..d',
|
|
'..D...d.d...D..',
|
|
'.D...t...t...D.',
|
|
'T..d...T...d..T',
|
|
];
|
|
|
|
// Эрудит: the standard layout but a non-doubling centre ('+').
|
|
const eruditBoard = [
|
|
'T..d...T...d..T',
|
|
'.D...t...t...D.',
|
|
'..D...d.d...D..',
|
|
'd..D...d...D..d',
|
|
'....D.....D....',
|
|
'.t...t...t...t.',
|
|
'..d...d.d...d..',
|
|
'T..d...+...d..T',
|
|
'..d...d.d...d..',
|
|
'.t...t...t...t.',
|
|
'....D.....D....',
|
|
'd..D...d...D..d',
|
|
'..D...d.d...D..',
|
|
'.D...t...t...D.',
|
|
'T..d...T...d..T',
|
|
];
|
|
|
|
function template(variant: Variant): string[] {
|
|
return variant === 'erudit' ? eruditBoard : standardBoard;
|
|
}
|
|
|
|
function premiumOf(ch: string): Premium {
|
|
switch (ch) {
|
|
case 'T':
|
|
return 'TW';
|
|
case 'D':
|
|
case '*':
|
|
return 'DW';
|
|
case 't':
|
|
return 'TL';
|
|
case 'd':
|
|
return 'DL';
|
|
default:
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/** premiumGrid returns the 15x15 premium layout for a variant (row-major). */
|
|
export function premiumGrid(variant: Variant): Premium[][] {
|
|
return template(variant).map((line) => Array.from(line, premiumOf));
|
|
}
|
|
|
|
/** centre returns the first-move anchor square (row, col). */
|
|
export function centre(variant: Variant): { row: number; col: number } {
|
|
const lines = template(variant);
|
|
for (let r = 0; r < lines.length; r++) {
|
|
const c = lines[r].search(/[*+]/);
|
|
if (c >= 0) return { row: r, col: c };
|
|
}
|
|
return { row: 7, col: 7 };
|
|
}
|
|
|
|
// Tile values and the per-variant alphabet now arrive from the server (lib/alphabet.ts,
|
|
// Stage 13); the board geometry above is all this module owns.
|