feat(offline): local game source (Phase B3.1)
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 17s
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
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 17s
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
A GatewayClient-shaped facade over the offline engine, so the same game screen can drive a local vs_ai game with no backend (the wiring into Game.svelte is B3.2). - source.ts: LocalSource implements the game-loop subset (GameLoopSource) for a local game id — gameState/gameHistory via replay, submitPlay/pass/exchange/resign apply the human move then run the robot (decide(generateMoves)) synchronously, persisting both and delivering the robot's move through a per-game event emitter (no live stream). hint is gated to >30 min since the robot's last move; evaluate/checkWord are local. It translates the UI's glyph space to the engine's index space with the static letters table. - ruleset.ts: add the static per-variant letters (glyphs), pinned to the Go alphabet — offline is now fully self-contained (no reliance on a warm server alphabet cache). - engine.ts: submitPlay (infers the direction like the server SubmitPlay), evaluatePlay + dictionaryHas for the move preview / word check, and record the main-word coordinate + the words on a play (for the history MoveRecord). - source.test.ts: create -> human pass -> synchronous robot reply via the event, the hint gate, decoded history, and a whole game driven to completion. Pure additive library code; no runtime behavior change (bundle unchanged).
This commit is contained in:
@@ -22,6 +22,9 @@ export interface VariantRuleset {
|
||||
values: readonly number[];
|
||||
/** Bag tile count per letter index (how many of each letter the bag holds). */
|
||||
counts: readonly number[];
|
||||
/** Display glyph per letter index, upper-cased (matching lib/alphabet.ts). Offline needs these
|
||||
* to translate the engine's index space to/from the glyphs the game UI shows, with no server. */
|
||||
letters: readonly string[];
|
||||
}
|
||||
|
||||
/** RULESETS is the static ruleset table, one entry per variant, mirrored from rules.go. */
|
||||
@@ -34,6 +37,7 @@ export const RULESETS: Record<Variant, VariantRuleset> = {
|
||||
// a b c d e f g h i j k l m n o p q r s t u v w x y z
|
||||
values: [1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10],
|
||||
counts: [9, 2, 2, 4, 12, 2, 3, 2, 9, 1, 1, 4, 2, 6, 8, 2, 1, 6, 4, 6, 4, 2, 2, 1, 2, 1],
|
||||
letters: [...'ABCDEFGHIJKLMNOPQRSTUVWXYZ'],
|
||||
},
|
||||
scrabble_ru: {
|
||||
size: 33,
|
||||
@@ -43,6 +47,7 @@ export const RULESETS: Record<Variant, VariantRuleset> = {
|
||||
// а б в г д е ё ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я
|
||||
values: [1, 3, 1, 3, 2, 1, 3, 5, 5, 1, 4, 2, 2, 2, 1, 1, 2, 1, 1, 1, 2, 10, 5, 5, 5, 8, 10, 10, 4, 3, 8, 8, 3],
|
||||
counts: [8, 2, 4, 2, 4, 8, 1, 1, 2, 5, 1, 4, 4, 3, 5, 10, 4, 5, 5, 5, 4, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2],
|
||||
letters: [...'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'],
|
||||
},
|
||||
erudit_ru: {
|
||||
size: 33,
|
||||
@@ -52,5 +57,6 @@ export const RULESETS: Record<Variant, VariantRuleset> = {
|
||||
// а б в г д е ё ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я
|
||||
values: [1, 3, 2, 3, 2, 1, 0, 5, 5, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 3, 10, 5, 10, 5, 10, 10, 10, 5, 5, 10, 10, 3],
|
||||
counts: [10, 3, 5, 3, 5, 9, 0, 2, 2, 8, 4, 6, 4, 5, 8, 10, 6, 6, 6, 5, 3, 1, 2, 1, 2, 1, 1, 1, 2, 2, 1, 1, 3],
|
||||
letters: [...'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'],
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user