@my-games/sudoku-core 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -6
- package/dist/board.d.ts +63 -0
- package/dist/board.d.ts.map +1 -0
- package/dist/game.d.ts +95 -0
- package/dist/game.d.ts.map +1 -0
- package/dist/generator.d.ts +28 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/index.cjs +821 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +14 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.iife.js +821 -14
- package/dist/index.iife.js.map +1 -1
- package/dist/index.js +786 -13
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +821 -14
- package/dist/index.umd.js.map +1 -1
- package/dist/solver.d.ts +13 -0
- package/dist/solver.d.ts.map +1 -0
- package/dist/storage.d.ts +26 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/types.d.ts +130 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/board.ts +182 -0
- package/src/game.ts +510 -0
- package/src/generator.ts +113 -0
- package/src/index.ts +67 -11
- package/src/solver.ts +95 -0
- package/src/storage.ts +115 -0
- package/src/style.css +366 -8
- package/src/types.ts +146 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @my-games/sudoku-core —— `0.0.0` 占位实现。\n *\n * 这是一个「空包」骨架:目的仅是把 monorepo 的\n * `build → verify:dist → typecheck → test` 门禁与 npm Trusted Publisher 链路跑通,\n * 好让首版(可信发布者无法发某包的第一个版本)能先手工种进 registry。\n *\n * 真实数独引擎 —— 棋盘校验、回溯求解器、唯一解题生成、`Sudoku` 状态机\n * (选格/填数/擦除/笔记/提示/撤销/计时)、注入式存档与最佳用时 —— 已在占位包\n * 发布前按同一三层结构写好并暂存,待 `0.0.0` 上线后作为后续提交补回。\n */\n\n/** 包标识占位。 */\nexport const SUDOKU_PACKAGE = 'sudoku-core' as const;\n\n/** 占位版本,与 package.json 的 version 对齐,便于确认发的是 stage 包。 */\nexport const SUDOKU_STAGE = '0.0.0' as const;\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAa,iBAAiB;;AAG9B,IAAa,eAAe"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/board.ts","../src/solver.ts","../src/generator.ts","../src/storage.ts","../src/game.ts"],"sourcesContent":["import type { Cell, ConflictMask, Digit, Grid } from './types';\n\n/**\n * 纯函数棋盘工具:只用 `Grid`(`Cell[][]`,0 = 空),不涉及对局可变态。\n *\n * 设计原则:所有「产出新棋盘」的函数都返回新数组,不原地修改输入。\n * solver / generator / Sudoku 类都建立在这套底层原语上。\n *\n * 严格模式(noUncheckedIndexedAccess):读取一律走 `cellAt`(越界/空返回 0),\n * 派生 9×9 结构时用 `makeMask` / `setAt` 保证行存在后再写下标。\n */\n\n/** 数独边长(标准 9×9)。 */\nexport const SIZE = 9 as const;\n/** 宫的边长(3×3 宫,共 9 宫)。 */\nexport const BOX = 3 as const;\n\n/** 数字 1..9 常量表(升序)。 */\nexport const DIGITS: readonly Digit[] = [1, 2, 3, 4, 5, 6, 7, 8, 9];\n\n/** 生成 SIZE×SIZE 全 0 空棋盘。 */\nexport function createEmptyGrid(): Grid {\n return Array.from({ length: SIZE }, () => Array<Cell>(SIZE).fill(0));\n}\n\n/** 深拷贝棋盘。 */\nexport function cloneGrid(grid: Grid): Grid {\n return grid.map((row) => row.slice());\n}\n\n/** 生成 SIZE×SIZE 掩码,初值由 `fill` 决定。 */\nexport function makeMask(fill: boolean): ConflictMask {\n return Array.from({ length: SIZE }, () => Array<boolean>(SIZE).fill(fill));\n}\n\n/** 安全读取:越界返回 0。 */\nexport function cellAt(grid: Grid, row: number, col: number): Cell {\n return grid[row]?.[col] ?? 0;\n}\n\n/** 安全写入:仅在行存在时写入(返回同一引用,供链式)。 */\nexport function setCell(grid: Grid, row: number, col: number, value: Cell): Grid {\n const line = grid[row];\n if (line) line[col] = value;\n return grid;\n}\n\n/** 返回把 (row,col) 设为 value 后的新棋盘(不改动入参)。 */\nexport function withCell(grid: Grid, row: number, col: number, value: Cell): Grid {\n const next = cloneGrid(grid);\n return setCell(next, row, col, value);\n}\n\n/** (row,col) 所属宫的左上角坐标。 */\nexport function boxOrigin(row: number, col: number): { r: number; c: number } {\n return { r: Math.floor(row / BOX) * BOX, c: Math.floor(col / BOX) * BOX };\n}\n\n/** 与 (row,col) 同处一行、一列、一宫(不含自身)的所有坐标,去重后共 20 个。 */\nexport function peers(row: number, col: number): Array<[number, number]> {\n const seen = new Set<number>();\n const out: Array<[number, number]> = [];\n const push = (r: number, c: number): void => {\n if (r === row && c === col) return;\n const key = r * SIZE + c;\n if (seen.has(key)) return;\n seen.add(key);\n out.push([r, c]);\n };\n for (let i = 0; i < SIZE; i++) {\n push(row, i);\n push(i, col);\n }\n const { r, c } = boxOrigin(row, col);\n for (let dr = 0; dr < BOX; dr++) {\n for (let dc = 0; dc < BOX; dc++) {\n push(r + dr, c + dc);\n }\n }\n return out;\n}\n\n/**\n * 数字 digit 能否放到 (row,col):检查所有 peer 是否已占用同值。\n * 不关心 (row,col) 当前值(用于「换个值是否合法」判断)。\n */\nexport function isSafe(grid: Grid, row: number, col: number, digit: Digit): boolean {\n for (const [pr, pc] of peers(row, col)) {\n if (cellAt(grid, pr, pc) === digit) return false;\n }\n return true;\n}\n\n/** 空格 (row,col) 的所有合法候选数字;非空格返回 []。 */\nexport function candidates(grid: Grid, row: number, col: number): Digit[] {\n if (cellAt(grid, row, col) !== 0) return [];\n const out: Digit[] = [];\n for (const d of DIGITS) {\n if (isSafe(grid, row, col, d)) out.push(d);\n }\n return out;\n}\n\n/** 所有空格坐标(行优先)。 */\nexport function emptyCells(grid: Grid): Array<[number, number]> {\n const out: Array<[number, number]> = [];\n for (let r = 0; r < SIZE; r++) {\n for (let c = 0; c < SIZE; c++) {\n if (cellAt(grid, r, c) === 0) out.push([r, c]);\n }\n }\n return out;\n}\n\n/** 是否填满(无 0)。 */\nexport function isFull(grid: Grid): boolean {\n for (let r = 0; r < SIZE; r++) {\n for (let c = 0; c < SIZE; c++) {\n if (cellAt(grid, r, c) === 0) return false;\n }\n }\n return true;\n}\n\n/**\n * 计算冲突掩码:某格为非 0 且与任一 peer 同值 → true。\n * 供 UI 标红「当前矛盾」的格,允许存在空格(部分填写)。\n */\nexport function findConflicts(grid: Grid): ConflictMask {\n const mask = makeMask(false);\n for (let r = 0; r < SIZE; r++) {\n for (let c = 0; c < SIZE; c++) {\n const v = cellAt(grid, r, c);\n if (v === 0) continue;\n for (const [pr, pc] of peers(r, c)) {\n if (cellAt(grid, pr, pc) === v) {\n const line = mask[r];\n if (line) line[c] = true;\n break;\n }\n }\n }\n }\n return mask;\n}\n\n/** 是否存在任意冲突(有重复)。 */\nexport function hasConflict(grid: Grid): boolean {\n for (const row of findConflicts(grid)) {\n for (const v of row) if (v) return true;\n }\n return false;\n}\n\n/**\n * 是否为「合法完成盘」:填满且无冲突。\n * 等价于每行/列/宫都是 1..9 的一个排列。\n */\nexport function isSolved(grid: Grid): boolean {\n return isFull(grid) && !hasConflict(grid);\n}\n\n/** 棋盘相等(逐格比较)。 */\nexport function gridsEqual(a: Grid, b: Grid): boolean {\n for (let r = 0; r < SIZE; r++) {\n for (let c = 0; c < SIZE; c++) {\n if (cellAt(a, r, c) !== cellAt(b, r, c)) return false;\n }\n }\n return true;\n}\n\n/** 数非空格数量(题面线索数)。 */\nexport function countFilled(grid: Grid): number {\n let n = 0;\n for (let r = 0; r < SIZE; r++) {\n for (let c = 0; c < SIZE; c++) {\n if (cellAt(grid, r, c) !== 0) n++;\n }\n }\n return n;\n}\n","import { candidates, cellAt, cloneGrid, hasConflict, setCell } from './board';\nimport type { Digit, Grid } from './types';\n\n/**\n * 数独回溯求解器(MRV 启发式)+ 解个数统计。\n *\n * - `solve`:给定(可能不完整的)合法棋盘,返回一个完整解的副本;无解返回 null。\n * - `countSolutions(grid, limit)`:统计该棋盘有多少个不同完整解,最多数到 `limit`\n * 就早停。生成器用 `limit = 2` 判定「唯一解」(返回 1 → 唯一;≥2 → 多解)。\n *\n * MRV(Minimum Remaining Values):每步优先填「候选数最少」的空格,\n * 一旦某空格候选为 0 立即回溯。标准 9×9 题在毫秒级完成,纯同步、无副作用。\n *\n * 内部对「工作副本」做原地 try/untry(backtracking 需要),但对外一律\n * 先 `cloneGrid`,绝不改动调用者传入的棋盘。\n */\n\n/** 在 grid 上找候选最少的空格;若填满返回 null;若发现死格(0 候选)返回 { dead:true }。 */\nfunction pickCell(grid: Grid): { row: number; col: number; cands: Digit[] } | null {\n let best: { row: number; col: number; cands: Digit[] } | null = null;\n for (let r = 0; r < grid.length; r++) {\n for (let c = 0; c < (grid[r]?.length ?? 0); c++) {\n if (cellAt(grid, r, c) !== 0) continue;\n const cands = candidates(grid, r, c);\n if (cands.length === 0) return null; // 死格 → 由调用方据 filled 判定失败\n if (!best || cands.length < best.cands.length) {\n best = { row: r, col: c, cands };\n if (cands.length === 1) return best; // 已是最优,提前收敛\n }\n }\n }\n return best;\n}\n\n/** 是否已无空格。 */\nfunction isComplete(grid: Grid): boolean {\n for (const row of grid) {\n for (const v of row) if (v === 0) return false;\n }\n return true;\n}\n\n/** 原地回溯填充工作副本;成功返回 true(grid 被填满),失败返回 false 并复原。 */\nfunction fillInPlace(grid: Grid): boolean {\n if (isComplete(grid)) return true;\n const cell = pickCell(grid);\n if (!cell) return false; // 有死格\n for (const d of cell.cands) {\n setCell(grid, cell.row, cell.col, d);\n if (fillInPlace(grid)) return true;\n setCell(grid, cell.row, cell.col, 0);\n }\n return false;\n}\n\n/**\n * 求解:返回完整解的新棋盘;若初始棋盘非法(已冲突)/无解返回 null。\n * 不修改入参。\n */\nexport function solve(grid: Grid): Grid | null {\n if (hasConflict(grid)) return null; // 题面自身已矛盾 → 无合法解\n const work = cloneGrid(grid);\n return fillInPlace(work) ? work : null;\n}\n\n/**\n * 统计解个数,最多数到 `limit` 即早停(默认 2)。\n * 用于唯一性判定:`countSolutions(p) === 1` 表示唯一解。\n * 不修改入参。`limit < 1` 视为 1;题面已冲突则返回 0。\n */\nexport function countSolutions(grid: Grid, limit = 2): number {\n if (hasConflict(grid)) return 0;\n const cap = Math.max(1, limit);\n const work = cloneGrid(grid);\n let solutions = 0;\n\n const rec = (): void => {\n if (solutions >= cap) return;\n if (isComplete(work)) {\n solutions++;\n return;\n }\n const cell = pickCell(work);\n if (!cell) return; // 死格,此分支无解\n for (const d of cell.cands) {\n setCell(work, cell.row, cell.col, d);\n rec();\n setCell(work, cell.row, cell.col, 0);\n if (solutions >= cap) return;\n }\n };\n\n rec();\n return solutions;\n}\n","import { DIGITS, cellAt, createEmptyGrid, isSafe, setCell } from './board';\nimport { countSolutions } from './solver';\nimport type { Difficulty, Grid, RandomSource } from './types';\n\n/**\n * 数独生成器:产出「有唯一解」的题目。\n *\n * 流程:\n * 1. `generateFullGrid` —— 随机回溯填满一张合法终盘(作为 solution)。\n * 2. `digHoles` —— 以随机顺序尝试把格子挖空;每挖一格前用 `countSolutions(limit=2)`\n * 校验:挖掉后仍「唯一解」才保留,否则回填。挖到目标线索数或无格可挖为止。\n *\n * 这样产出的 puzzle 保证唯一解,且 puzzle ⊂ solution(挖掉的都是解里可推出来的格)。\n * rng 注入保证单测可复现;默认 `Math.random`。\n */\n\n/** 各难度目标线索数(题面给定数字个数)。实际可能因唯一性约束略多。 */\nexport const TARGET_CLUES: Record<Difficulty, number> = {\n easy: 45,\n medium: 35,\n hard: 27\n};\n\n/** Fisher–Yates 洗牌(返回新数组,用注入 rng)。 */\nfunction shuffle<T>(input: readonly T[], rng: RandomSource): T[] {\n const arr = input.slice();\n for (let i = arr.length - 1; i > 0; i--) {\n const j = Math.floor(rng() * (i + 1));\n const tmp = arr[i];\n const a = arr[j];\n if (tmp !== undefined && a !== undefined) {\n arr[i] = a;\n arr[j] = tmp;\n }\n }\n return arr;\n}\n\n/** 从 pos 起原地回溯填满 grid(每格用随机顺序的合法数字)。 */\nfunction fillFully(grid: Grid, pos: number, rng: RandomSource): boolean {\n if (pos >= grid.length * grid.length) return true;\n const row = Math.floor(pos / grid.length);\n const col = pos % grid.length;\n if (cellAt(grid, row, col) !== 0) return fillFully(grid, pos + 1, rng);\n for (const d of shuffle(DIGITS, rng)) {\n if (isSafe(grid, row, col, d)) {\n setCell(grid, row, col, d);\n if (fillFully(grid, pos + 1, rng)) return true;\n setCell(grid, row, col, 0);\n }\n }\n return false;\n}\n\n/** 生成一张随机合法终盘(9×9 全填、无冲突)。 */\nexport function generateFullGrid(rng: RandomSource = Math.random): Grid {\n const grid = createEmptyGrid();\n // 空盘的回溯填满总有解(数独解空间非空),fillFully 必返回 true。\n fillFully(grid, 0, rng);\n return grid;\n}\n\n/**\n * 在终盘副本上随机挖洞到目标线索数,保持唯一解。\n * 返回挖洞后的题面(会修改并返回传入的 puzzle 副本,入参 solution 不动)。\n */\nfunction digHoles(solution: Grid, targetClues: number, rng: RandomSource): Grid {\n const puzzle = solution.map((row) => row.slice());\n const total = puzzle.length * puzzle.length;\n // 全部坐标乱序,作为挖除尝试顺序。\n const order: number[] = [];\n for (let i = 0; i < total; i++) order.push(i);\n const shuffled = shuffle(order, rng);\n\n let clues = total;\n for (const idx of shuffled) {\n if (clues <= targetClues) break;\n const r = Math.floor(idx / puzzle.length);\n const c = idx % puzzle.length;\n const backup = cellAt(puzzle, r, c);\n if (backup === 0) continue; // 已挖空\n setCell(puzzle, r, c, 0);\n // 挖掉后是否仍唯一解?不是就回填。\n if (countSolutions(puzzle, 2) === 1) {\n clues--;\n } else {\n setCell(puzzle, r, c, backup);\n }\n }\n return puzzle;\n}\n\nexport interface GeneratedPuzzle {\n /** 题面(含 0 空格),有唯一解。 */\n puzzle: Grid;\n /** 与题面一致的完整解(题面 ⊂ 解)。 */\n solution: Grid;\n difficulty: Difficulty;\n /** 实际线索数(题面给定个数)。 */\n clues: number;\n}\n\n/** 生成一道指定难度、唯一解的数独题。 */\nexport function generatePuzzle(\n difficulty: Difficulty = 'easy',\n rng: RandomSource = Math.random\n): GeneratedPuzzle {\n const solution = generateFullGrid(rng);\n const puzzle = digHoles(solution, TARGET_CLUES[difficulty] ?? TARGET_CLUES.easy, rng);\n let clues = 0;\n for (const row of puzzle) for (const v of row) if (v !== 0) clues++;\n return { puzzle, solution, difficulty, clues };\n}\n","import type { BestTimes, Difficulty, SaveStorage, SerializedSave } from './types';\n\n/**\n * 存档与最佳用时持久化。\n *\n * 版本策略:读到的 version ≠ SAVE_VERSION 时,`isSerializedSave` 守卫失败 →\n * 上层丢弃并开新局。目前仅 v1。\n *\n * best 存的是 `BestTimes`(每个难度历史最佳用时秒数,null = 未通关),\n * 以 JSON 落在单个 bestKey 下,读回时补全缺失难度为 null。\n */\nexport const SAVE_VERSION = 1 as const;\nexport const DEFAULT_SAVE_KEY = 'game-sudoku:save';\nexport const DEFAULT_BEST_KEY = 'game-sudoku:best';\n\nconst DIFFICULTIES: readonly Difficulty[] = ['easy', 'medium', 'hard'];\n\nfunction isDifficulty(x: unknown): x is Difficulty {\n return typeof x === 'string' && (DIFFICULTIES as readonly string[]).includes(x);\n}\n\n/** 9×9 的二维数组守卫(浅校验行数与每行长度)。 */\nfunction isGridLike(x: unknown): boolean {\n return (\n Array.isArray(x) &&\n x.length === 9 &&\n x.every((row) => Array.isArray(row) && row.length === 9)\n );\n}\n\n/** 粗粒度结构守卫:只保证关键字段形状,深层值由 Sudoku 载入时再防御。 */\nexport function isSerializedSave(x: unknown): x is SerializedSave {\n if (typeof x !== 'object' || x === null) return false;\n const o = x as Record<string, unknown>;\n return (\n o['version'] === SAVE_VERSION &&\n isDifficulty(o['difficulty']) &&\n isGridLike(o['puzzle']) &&\n isGridLike(o['solution']) &&\n isGridLike(o['grid']) &&\n (o['status'] === 'playing' || o['status'] === 'won')\n );\n}\n\nexport function loadSave(storage: SaveStorage | null, key: string): SerializedSave | null {\n if (!storage) return null;\n const raw = storage.getItem(key);\n if (!raw) return null;\n try {\n const parsed: unknown = JSON.parse(raw);\n return isSerializedSave(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\nexport function writeSave(storage: SaveStorage | null, key: string, save: SerializedSave): void {\n if (!storage) return;\n try {\n storage.setItem(key, JSON.stringify(save));\n } catch {\n /* quota / 隐私模式静默忽略;不阻断游戏 */\n }\n}\n\nexport function clearSave(storage: SaveStorage | null, key: string): void {\n if (!storage) return;\n try {\n storage.removeItem(key);\n } catch {\n /* ignore */\n }\n}\n\n/** 空的 BestTimes(全 null)。 */\nexport function emptyBestTimes(): BestTimes {\n return { easy: null, medium: null, hard: null };\n}\n\n/** 读回 BestTimes;损坏/缺失字段回落为 null。 */\nexport function loadBest(storage: SaveStorage | null, key: string): BestTimes {\n const result = emptyBestTimes();\n if (!storage) return result;\n const raw = storage.getItem(key);\n if (!raw) return result;\n try {\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed === 'object' && parsed !== null) {\n const o = parsed as Record<string, unknown>;\n for (const d of DIFFICULTIES) {\n const v = o[d];\n if (typeof v === 'number' && Number.isFinite(v) && v >= 0) result[d] = Math.floor(v);\n }\n }\n } catch {\n /* 回落全 null */\n }\n return result;\n}\n\nexport function writeBest(storage: SaveStorage | null, key: string, best: BestTimes): void {\n if (!storage) return;\n try {\n storage.setItem(key, JSON.stringify(best));\n } catch {\n /* ignore */\n }\n}\n\n/** 浏览器默认 Storage;无 DOM 环境返回 null,让 core 在 Node 也能跑。 */\nexport function tryGetGlobalStorage(): SaveStorage | null {\n if (typeof globalThis === 'undefined') return null;\n const s = (globalThis as { localStorage?: SaveStorage }).localStorage;\n return s ?? null;\n}\n","import { SIZE, cellAt, cloneGrid, findConflicts, hasConflict, isSafe, setCell } from './board';\nimport { generatePuzzle } from './generator';\nimport { solve } from './solver';\nimport {\n DEFAULT_BEST_KEY,\n DEFAULT_SAVE_KEY,\n clearSave,\n loadBest,\n loadSave,\n tryGetGlobalStorage,\n writeBest,\n writeSave\n} from './storage';\nimport type {\n BestTimes,\n Difficulty,\n Digit,\n GameOptions,\n GameState,\n GameStatus,\n GivenMask,\n Grid,\n NoteGrid,\n Position,\n RandomSource,\n Clock,\n SaveStorage,\n SerializedSave,\n Snapshot\n} from './types';\n\nexport type { GameOptions } from './types';\n\nconst DEFAULT_DIFFICULTY: Difficulty = 'easy';\nconst DEFAULT_UNDO_LIMIT = 50;\n\n/** 深拷贝笔记网格。 */\nfunction cloneNotes(notes: NoteGrid): NoteGrid {\n return notes.map((row) => row.map((cell) => cell.slice()));\n}\n\n/** 初始化 9×9 全空笔记。 */\nfunction emptyNotes(): NoteGrid {\n return Array.from({ length: SIZE }, () =>\n Array.from({ length: SIZE }, () => [] as Digit[])\n );\n}\n\n/** 由题面推导「给定掩码」。 */\nfunction maskFromPuzzle(puzzle: Grid): GivenMask {\n return puzzle.map((row) => row.map((v) => v !== 0));\n}\n\n/** 升序去重写回某格笔记。 */\nfunction sortedUnique(digits: Digit[]): Digit[] {\n return Array.from(new Set(digits)).sort((a, b) => a - b);\n}\n\n/**\n * Sudoku —— 数独状态机与规则实现,与 UI 完全解耦。\n *\n * - 通过 `subscribe(fn)` 推完整 `GameState` 快照(不推 diff);注册即收到一次。\n * - 每次改变局面的公开操作(input/erase/toggleNote/hint/newGame/undo)成功后\n * 走一次 `commit()`:写存档 + 通知订阅。`select()` 只更新选中并通知,不落盘。\n * - 谜题来源:默认按 `difficulty` 现场生成唯一解题;也可注入 `puzzle`(+可选 solution)\n * 用作固定题/测试。`newGame()` 总是重新随机生成一道。\n * - 计时:注入 `clock`(默认 Date.now);`elapsedMs = baseMs + (clock()-origin)`,\n * 通关瞬间冻结为 `finalMs`。undo 回未到通关的快照会按当时累计值续表。\n * - 存档:注入 storage(默认尝试 globalThis.localStorage);`best` 是分难度最佳用时。\n */\nexport class Sudoku {\n private readonly rng: RandomSource;\n private readonly clock: Clock;\n private readonly storage: SaveStorage | null;\n private readonly saveKey: string;\n private readonly bestKey: string;\n private readonly undoLimit: number;\n private readonly fixedPuzzle: Grid | null;\n private readonly fixedSolution: Grid | null;\n\n private difficulty: Difficulty;\n private puzzle: Grid;\n private solution: Grid;\n // givenMask/grid/notes 由构造函数分派的 startNewGame/loadFromSave 必赋值;\n // selected 默认无选中。\n private givenMask!: GivenMask;\n private grid!: Grid;\n private notes!: NoteGrid;\n private selected: Position | null = null;\n private status: GameStatus = 'playing';\n private hintCount = 0;\n private mistakeCount = 0;\n private moveCount = 0;\n private history: Snapshot[] = [];\n\n // 计时三段量:started=false 时 elapsedMs 恒 0,首次填充(input/hint)才起算。\n private started = false;\n private baseMs = 0;\n private origin = 0;\n private finalMs = 0;\n\n private best: BestTimes;\n\n private listeners = new Set<(state: GameState) => void>();\n private notifying = false;\n\n constructor(opts: GameOptions = {}) {\n this.rng = opts.rng ?? Math.random;\n this.clock = opts.clock ?? Date.now;\n this.storage = opts.storage === undefined ? tryGetGlobalStorage() : opts.storage;\n this.saveKey = opts.saveKey ?? DEFAULT_SAVE_KEY;\n this.bestKey = opts.bestKey ?? DEFAULT_BEST_KEY;\n this.undoLimit = opts.undoLimit ?? DEFAULT_UNDO_LIMIT;\n this.difficulty = opts.difficulty ?? DEFAULT_DIFFICULTY;\n this.best = loadBest(this.storage, this.bestKey);\n\n this.fixedPuzzle = opts.puzzle ? cloneGrid(opts.puzzle) : null;\n this.fixedSolution = opts.solution ? cloneGrid(opts.solution) : null;\n\n // 先给一个合法初值(构造分支会覆盖)。\n this.puzzle = this.fixedPuzzle ?? cloneGrid(generatePuzzle(this.difficulty, this.rng).puzzle);\n this.solution = this.deriveSolution(this.puzzle);\n\n const saved = opts.freshStart ? null : loadSave(this.storage, this.saveKey);\n if (saved && this.canReserve(saved)) {\n this.loadFromSave(saved);\n } else {\n this.startNewGame(this.difficulty);\n }\n }\n\n // ---------- 公共 API ----------\n\n /** 订阅状态变化,返回退订函数;注册后立刻收到一次当前快照。 */\n subscribe(fn: (state: GameState) => void): () => void {\n this.listeners.add(fn);\n try {\n fn(this.getState());\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('[game-sudoku] listener threw on subscribe:', err);\n }\n return () => {\n this.listeners.delete(fn);\n };\n }\n\n getState(): GameState {\n return {\n difficulty: this.difficulty,\n grid: cloneGrid(this.grid),\n givenMask: this.givenMask.map((row) => row.slice()),\n notes: cloneNotes(this.notes),\n selected: this.selected ? { ...this.selected } : null,\n conflicts: findConflicts(this.grid),\n status: this.status,\n elapsedSeconds: Math.floor(this.elapsedMs() / 1000),\n bestSeconds: this.best[this.difficulty],\n hintCount: this.hintCount,\n mistakeCount: this.mistakeCount,\n moveCount: this.moveCount,\n historySize: this.history.length\n };\n }\n\n getGrid(): Grid {\n return cloneGrid(this.grid);\n }\n\n getPuzzle(): Grid {\n return cloneGrid(this.puzzle);\n }\n\n getSolution(): Grid {\n return cloneGrid(this.solution);\n }\n\n canUndo(): boolean {\n return this.history.length > 0;\n }\n\n /** 选中某格(越界则忽略)。仅更新选中并通知订阅,不写存档、不入 undo 栈。 */\n select(row: number, col: number): void {\n if (row < 0 || row >= SIZE || col < 0 || col >= SIZE) return;\n if (this.selected?.row === row && this.selected?.col === col) return;\n this.selected = { row, col };\n this.notify();\n }\n\n /**\n * 在选中格填数字。题面给定格 / 已通关时忽略。\n * 返回 true = 棋盘确有变化。填了与盘面冲突的值会计一次 mistake(仍允许填)。\n */\n input(digit: Digit): boolean {\n if (this.status === 'won') return false;\n const sel = this.selected;\n if (!sel) return false;\n if (this.givenMask[sel.row]?.[sel.col]) return false; // 题面给定,禁改\n if (cellAt(this.grid, sel.row, sel.col) === digit) return false; // 同值,无变化\n\n this.pushHistory();\n this.ensureStarted(); // 首次填充起表\n setCell(this.grid, sel.row, sel.col, digit);\n const notesRow = this.notes[sel.row];\n if (notesRow) notesRow[sel.col] = []; // 有值即清空该格笔记\n this.moveCount++;\n if (!isSafe(this.grid, sel.row, sel.col, digit)) this.mistakeCount++;\n this.checkWin();\n this.commit();\n return true;\n }\n\n /** 擦除选中格(值与笔记一起清)。题面给定 / 已通关忽略。返回是否有变化。 */\n erase(): boolean {\n if (this.status === 'won') return false;\n const sel = this.selected;\n if (!sel) return false;\n if (this.givenMask[sel.row]?.[sel.col]) return false;\n const hadValue = cellAt(this.grid, sel.row, sel.col) !== 0;\n const notesRow = this.notes[sel.row];\n const hadNotes = !!notesRow?.[sel.col]?.length;\n if (!hadValue && !hadNotes) return false; // 本来就空,无变化\n\n this.pushHistory();\n setCell(this.grid, sel.row, sel.col, 0);\n if (notesRow) notesRow[sel.col] = [];\n if (hadValue) this.moveCount++;\n this.commit();\n return true;\n }\n\n /**\n * 切换选中空格的某条铅笔笔记。仅对「非给定且当前为空」的格生效。\n * 返回 true = 笔记集合确有变化。\n */\n toggleNote(digit: Digit): boolean {\n if (this.status === 'won') return false;\n const sel = this.selected;\n if (!sel) return false;\n if (this.givenMask[sel.row]?.[sel.col]) return false;\n if (cellAt(this.grid, sel.row, sel.col) !== 0) return false; // 有值不谈笔记\n\n const notesRow = this.notes[sel.row];\n if (!notesRow) return false;\n const current = notesRow[sel.col] ?? [];\n const has = current.includes(digit);\n this.pushHistory();\n notesRow[sel.col] = has\n ? sortedUnique(current.filter((d) => d !== digit))\n : sortedUnique([...current, digit]);\n this.commit();\n return true;\n }\n\n /**\n * 提示:优先填「选中的空格」,否则填第一个空格;写入解中的正确值并清该格笔记。\n * 返回 true = 确有一格被填。计一次 hint(不单独计 mistake)。\n */\n hint(): boolean {\n if (this.status === 'won') return false;\n const target = this.pickHintTarget();\n if (!target) return false;\n const answer = cellAt(this.solution, target.row, target.col);\n if (answer === 0) return false;\n\n this.pushHistory();\n this.ensureStarted(); // 提示也算开始作答,起表\n setCell(this.grid, target.row, target.col, answer);\n const notesRow = this.notes[target.row];\n if (notesRow) notesRow[target.col] = [];\n this.selected = target;\n this.hintCount++;\n this.moveCount++;\n this.checkWin();\n this.commit();\n return true;\n }\n\n /**\n * 开启新局:随机生成指定难度(默认沿用当前难度)的唯一解题,清空局面与历史,\n * 计时归零,best 保留。会清除旧存档并落一份新局存档。\n */\n newGame(difficulty: Difficulty = this.difficulty): void {\n this.startNewGame(difficulty);\n this.commit();\n }\n\n /** 撤销一步;返回是否成功。 */\n undo(): boolean {\n const s = this.history.pop();\n if (!s) return false;\n this.restoreSnapshot(s);\n this.commit();\n return true;\n }\n\n /** 清除当前存档(不影响 best)。 */\n clearSaved(): void {\n clearSave(this.storage, this.saveKey);\n }\n\n // ---------- 内部 ----------\n\n /** 由(部分)题面推导完整解:优先用注入的 solution,否则用 solve。 */\n private deriveSolution(puzzle: Grid): Grid {\n if (this.fixedSolution && !hasConflict(puzzle) && gridsCompatible(puzzle, this.fixedSolution)) {\n return cloneGrid(this.fixedSolution);\n }\n const solved = solve(puzzle);\n return solved ?? cloneGrid(puzzle);\n }\n\n /** 存档是否可续用:同难度、同题面(防切难度/换题后串档)。 */\n private canReserve(save: SerializedSave): boolean {\n if (save.difficulty !== this.difficulty) return false;\n // 有固定题面时只认同一道题;无固定题面时,允许续任何同难度存档。\n if (this.fixedPuzzle) return gridsCompatible(this.fixedPuzzle, save.puzzle);\n return true;\n }\n\n private startNewGame(difficulty: Difficulty): void {\n this.difficulty = difficulty;\n if (this.fixedPuzzle) {\n this.puzzle = cloneGrid(this.fixedPuzzle);\n this.solution = this.deriveSolution(this.puzzle);\n } else {\n const gen = generatePuzzle(difficulty, this.rng);\n this.puzzle = gen.puzzle;\n this.solution = gen.solution;\n }\n this.givenMask = maskFromPuzzle(this.puzzle);\n this.grid = cloneGrid(this.puzzle);\n this.notes = emptyNotes();\n this.selected = firstEmpty(this.grid);\n this.status = 'playing';\n this.hintCount = 0;\n this.mistakeCount = 0;\n this.moveCount = 0;\n this.history = [];\n this.started = false;\n this.baseMs = 0;\n this.finalMs = 0;\n this.origin = this.clock();\n this.clearSaved();\n }\n\n /** 首次填充(input/hint)时懒起表;未起表前 elapsedMs 恒 0。 */\n private ensureStarted(): void {\n if (this.started) return;\n this.started = true;\n this.baseMs = 0;\n this.origin = this.clock();\n }\n\n private elapsedMs(): number {\n if (this.status === 'won') return this.finalMs;\n if (!this.started) return 0;\n return this.baseMs + (this.clock() - this.origin);\n }\n\n private checkWin(): void {\n if (this.status !== 'playing') return;\n for (let r = 0; r < SIZE; r++) {\n for (let c = 0; c < SIZE; c++) {\n if (cellAt(this.grid, r, c) === 0) return; // 仍有空格\n }\n }\n // 填满后判冲突;无冲突即通关。\n for (const row of findConflicts(this.grid)) {\n for (const v of row) if (v) return; // 填满但有冲突 → 不算通关\n }\n this.finalMs = this.baseMs + (this.clock() - this.origin);\n this.status = 'won';\n const secs = Math.floor(this.finalMs / 1000);\n const cur = this.best[this.difficulty];\n if (cur === null || secs < cur) {\n this.best[this.difficulty] = secs;\n writeBest(this.storage, this.bestKey, this.best);\n }\n }\n\n private pickHintTarget(): Position | null {\n const sel = this.selected;\n if (sel && cellAt(this.grid, sel.row, sel.col) === 0 && !this.givenMask[sel.row]?.[sel.col]) {\n return { ...sel };\n }\n return firstEmpty(this.grid);\n }\n\n private pushHistory(): void {\n const snap: Snapshot = {\n grid: cloneGrid(this.grid),\n notes: cloneNotes(this.notes),\n selected: this.selected ? { ...this.selected } : null,\n status: this.status,\n hintCount: this.hintCount,\n mistakeCount: this.mistakeCount,\n moveCount: this.moveCount,\n elapsedMs: this.elapsedMs(),\n started: this.started\n };\n this.history.push(snap);\n if (this.history.length > this.undoLimit) this.history.shift();\n }\n\n private restoreSnapshot(s: Snapshot): void {\n this.grid = cloneGrid(s.grid);\n this.notes = cloneNotes(s.notes);\n this.selected = s.selected ? { ...s.selected } : null;\n this.status = s.status;\n this.hintCount = s.hintCount;\n this.mistakeCount = s.mistakeCount;\n this.moveCount = s.moveCount;\n this.started = s.started;\n if (s.status === 'won') {\n this.finalMs = s.elapsedMs;\n } else {\n this.baseMs = s.elapsedMs;\n this.origin = this.clock();\n }\n }\n\n private loadFromSave(save: SerializedSave): void {\n this.difficulty = save.difficulty;\n this.puzzle = cloneGrid(save.puzzle);\n this.solution = cloneGrid(save.solution);\n this.givenMask = maskFromPuzzle(this.puzzle);\n this.grid = cloneGrid(save.grid);\n this.notes = save.notes ? cloneNotes(save.notes) : emptyNotes();\n this.status = save.status === 'won' ? 'won' : 'playing';\n this.hintCount = numberOr(save.hintCount, 0);\n this.mistakeCount = numberOr(save.mistakeCount, 0);\n this.moveCount = numberOr(save.moveCount, 0);\n this.history = [];\n this.selected = firstEmpty(this.grid);\n const elapsed = numberOr(save.elapsedMs, 0);\n // 续档时按局面推定是否已起表:通关或已有操作/用时 → 已起表;否则等到首次填充才走。\n this.started = this.status === 'won' || this.moveCount > 0 || elapsed > 0;\n if (this.status === 'won') {\n this.finalMs = elapsed;\n this.baseMs = elapsed;\n this.origin = this.clock();\n } else {\n this.baseMs = elapsed;\n this.finalMs = 0;\n this.origin = this.clock();\n }\n }\n\n private commit(): void {\n writeSave(this.storage, this.saveKey, {\n version: 1,\n difficulty: this.difficulty,\n puzzle: cloneGrid(this.puzzle),\n solution: cloneGrid(this.solution),\n grid: cloneGrid(this.grid),\n notes: cloneNotes(this.notes),\n status: this.status,\n hintCount: this.hintCount,\n mistakeCount: this.mistakeCount,\n moveCount: this.moveCount,\n elapsedMs: this.elapsedMs()\n });\n this.notify();\n }\n\n private notify(): void {\n if (this.notifying) return;\n this.notifying = true;\n try {\n const snapshot = this.getState();\n for (const fn of this.listeners) {\n try {\n fn(snapshot);\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('[game-sudoku] listener threw:', err);\n }\n }\n } finally {\n this.notifying = false;\n }\n }\n}\n\n// ---------- 局部小工具(避免把棋盘遍历细节散进主流程) ----------\n\n/** puzzle ⊂ solution:puzzle 非 0 处 solution 必须同值。 */\nfunction gridsCompatible(puzzle: Grid, solution: Grid): boolean {\n for (let r = 0; r < puzzle.length; r++) {\n for (let c = 0; c < (puzzle[r]?.length ?? 0); c++) {\n const p = cellAt(puzzle, r, c);\n if (p !== 0 && cellAt(solution, r, c) !== p) return false;\n }\n }\n return true;\n}\n\nfunction firstEmpty(grid: Grid): Position | null {\n for (let r = 0; r < SIZE; r++) {\n for (let c = 0; c < SIZE; c++) {\n if (cellAt(grid, r, c) === 0) return { row: r, col: c };\n }\n }\n return null;\n}\n\nfunction numberOr(x: unknown, fallback: number): number {\n return typeof x === 'number' && Number.isFinite(x) ? x : fallback;\n}\n"],"mappings":"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"}
|