e4cf143e9f
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 15s
CI / ui (pull_request) Successful in 1m9s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m39s
The offline vs_ai game engine — a faithful TS port of backend/internal/engine that drives a whole local game with no backend. Composes with the move generator (#188) and robot strategy (#189) from Phase A; not yet wired into the UI (Phase B2/B3). - ui/src/lib/localgame/ruleset.ts: static per-variant tile values / bag counts / blank count, mirrored from rules.go (offline scoring is self-contained; online uses the server alphabet). Pinned by ruleset.parity.test.ts against a Go fixture. - bag.ts: the tile bag (fill from counts/blanks, draw-from-end, return+reshuffle) on a deterministic in-house PRNG — a game replays from its seed, not bit-identical to a server game (per plan). - board.ts: the mutable board, satisfying the validator/generator read view + set(). - engine.ts: LocalGame — deal / play (reusing validate.ts) / pass / exchange / resign, scoreless(6) & out-of-tiles end detection, end-of-game rack penalties, winner; mirrors game.go. The end-game math is exported as pure functions, pinned against the Go engine (engine.parity.test.ts, 9 constructed positions). - engine.test.ts: a full-loop smoke — two robots play a whole vs_ai game to completion via generateMoves + decide, and it is reproducible from the seed. - backend: movegen now dumps the per-variant rulesets; a new in-package engine emitter (endfixture_test.go, env-gated) produces the end-game golden. Pure additive library code; no runtime behavior change (unused at runtime, bundle unchanged).
38 lines
1.2 KiB
TypeScript
38 lines
1.2 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { readFileSync } from 'node:fs';
|
|
import { RULESETS } from './ruleset';
|
|
import type { Variant } from '../model';
|
|
|
|
// The offline engine is self-contained: it carries each variant's tile values, bag counts and
|
|
// blank count in ruleset.ts (these are not otherwise on the client — online scoring uses the
|
|
// server-sent alphabet). This pins that hand-copied table to the Go rulesets
|
|
// (scrabble-solver/rules), whose values the movegen tool dumps to testdata/rulesets.json.
|
|
interface RulesetFix {
|
|
size: number;
|
|
rackSize: number;
|
|
bingo: number;
|
|
blanks: number;
|
|
values: number[];
|
|
counts: number[];
|
|
}
|
|
|
|
const fx = JSON.parse(
|
|
readFileSync(new URL('./testdata/rulesets.json', import.meta.url), 'utf8'),
|
|
) as Record<Variant, RulesetFix>;
|
|
|
|
describe('offline ruleset table parity vs Go rules', () => {
|
|
for (const variant of Object.keys(fx) as Variant[]) {
|
|
it(variant, () => {
|
|
const rs = RULESETS[variant];
|
|
expect({
|
|
size: rs.size,
|
|
rackSize: rs.rackSize,
|
|
bingo: rs.bingo,
|
|
blanks: rs.blanks,
|
|
values: [...rs.values],
|
|
counts: [...rs.counts],
|
|
}).toEqual(fx[variant]);
|
|
});
|
|
}
|
|
});
|