Stage 7 (wip): UI shell, libs, mock transport, screens (lobby->game), e2e smoke
- plain Svelte 5 + TS + Vite (no SvelteKit); CSS-token design system (Telegram-ready), hash router, IndexedDB session - pure libs: domain model, premium/value maps ported from solver, board replay, placement state machine, i18n en/ru - in-memory mock transport + seed data; pnpm start runs lobby->active game->board with no backend - board: pointer-drag + tap placement, MakeMove (popup / 1s-hold commit), two-state zoom, blank chooser, exchange, hint, word-check, chat - Playwright smoke (mock) green; svelte-check clean; mock bundle ~37 KB gzip
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
// Pure board reconstruction. The wire carries no board (StateView is summary + rack
|
||||
// only), so the live grid is rebuilt by replaying the decoded move journal — exactly
|
||||
// the dictionary-independent history invariant (ARCHITECTURE §9.1): apply each play's
|
||||
// placed tiles onto an empty grid.
|
||||
|
||||
import type { MoveRecord, Tile } from './model';
|
||||
import { BOARD_SIZE } from './premiums';
|
||||
|
||||
export interface BoardCell {
|
||||
letter: string;
|
||||
blank: boolean;
|
||||
}
|
||||
|
||||
export type Board = (BoardCell | null)[][];
|
||||
|
||||
export function emptyBoard(): Board {
|
||||
return Array.from({ length: BOARD_SIZE }, () =>
|
||||
Array.from({ length: BOARD_SIZE }, () => null as BoardCell | null),
|
||||
);
|
||||
}
|
||||
|
||||
function inBounds(r: number, c: number): boolean {
|
||||
return r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE;
|
||||
}
|
||||
|
||||
/** replay folds every play move's tiles onto an empty board (pass/exchange/resign
|
||||
* change no squares). */
|
||||
export function replay(moves: MoveRecord[]): Board {
|
||||
const b = emptyBoard();
|
||||
for (const m of moves) {
|
||||
if (m.action !== 'play') continue;
|
||||
for (const t of m.tiles) {
|
||||
if (inBounds(t.row, t.col)) b[t.row][t.col] = { letter: t.letter, blank: t.blank };
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/** lastPlayTiles returns the tiles of the most recent play (for highlighting). */
|
||||
export function lastPlayTiles(moves: MoveRecord[]): Tile[] {
|
||||
for (let i = moves.length - 1; i >= 0; i--) {
|
||||
if (moves[i].action === 'play') return moves[i].tiles;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
Reference in New Issue
Block a user