@sudobility/sudojo_lib 0.0.4
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/dist/hooks/index.d.ts +27 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +27 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useDailyGame.d.ts +64 -0
- package/dist/hooks/useDailyGame.d.ts.map +1 -0
- package/dist/hooks/useDailyGame.js +120 -0
- package/dist/hooks/useDailyGame.js.map +1 -0
- package/dist/hooks/useGame.d.ts +104 -0
- package/dist/hooks/useGame.d.ts.map +1 -0
- package/dist/hooks/useGame.js +546 -0
- package/dist/hooks/useGame.js.map +1 -0
- package/dist/hooks/useGamePersistence.d.ts +63 -0
- package/dist/hooks/useGamePersistence.d.ts.map +1 -0
- package/dist/hooks/useGamePersistence.js +124 -0
- package/dist/hooks/useGamePersistence.js.map +1 -0
- package/dist/hooks/useGameTeaching.d.ts +89 -0
- package/dist/hooks/useGameTeaching.d.ts.map +1 -0
- package/dist/hooks/useGameTeaching.js +230 -0
- package/dist/hooks/useGameTeaching.js.map +1 -0
- package/dist/hooks/useGameTimer.d.ts +43 -0
- package/dist/hooks/useGameTimer.d.ts.map +1 -0
- package/dist/hooks/useGameTimer.js +68 -0
- package/dist/hooks/useGameTimer.js.map +1 -0
- package/dist/hooks/useHint.d.ts +105 -0
- package/dist/hooks/useHint.d.ts.map +1 -0
- package/dist/hooks/useHint.js +179 -0
- package/dist/hooks/useHint.js.map +1 -0
- package/dist/hooks/useLearning.d.ts +100 -0
- package/dist/hooks/useLearning.d.ts.map +1 -0
- package/dist/hooks/useLearning.js +127 -0
- package/dist/hooks/useLearning.js.map +1 -0
- package/dist/hooks/useLevelGame.d.ts +68 -0
- package/dist/hooks/useLevelGame.d.ts.map +1 -0
- package/dist/hooks/useLevelGame.js +128 -0
- package/dist/hooks/useLevelGame.js.map +1 -0
- package/dist/hooks/useLevels.d.ts +93 -0
- package/dist/hooks/useLevels.d.ts.map +1 -0
- package/dist/hooks/useLevels.js +98 -0
- package/dist/hooks/useLevels.js.map +1 -0
- package/dist/hooks/useLocalStorage.d.ts +26 -0
- package/dist/hooks/useLocalStorage.d.ts.map +1 -0
- package/dist/hooks/useLocalStorage.js +75 -0
- package/dist/hooks/useLocalStorage.js.map +1 -0
- package/dist/hooks/useSudoku.d.ts +125 -0
- package/dist/hooks/useSudoku.d.ts.map +1 -0
- package/dist/hooks/useSudoku.js +655 -0
- package/dist/hooks/useSudoku.js.map +1 -0
- package/dist/hooks/useTechniques.d.ts +92 -0
- package/dist/hooks/useTechniques.d.ts.map +1 -0
- package/dist/hooks/useTechniques.js +108 -0
- package/dist/hooks/useTechniques.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/test/setup.d.ts +2 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/dist/test/setup.js +35 -0
- package/dist/test/setup.js.map +1 -0
- package/dist/types/display.d.ts +142 -0
- package/dist/types/display.d.ts.map +1 -0
- package/dist/types/display.js +94 -0
- package/dist/types/display.js.map +1 -0
- package/dist/types/game.d.ts +201 -0
- package/dist/types/game.d.ts.map +1 -0
- package/dist/types/game.js +26 -0
- package/dist/types/game.js.map +1 -0
- package/dist/types/gamePersistence.d.ts +31 -0
- package/dist/types/gamePersistence.d.ts.map +1 -0
- package/dist/types/gamePersistence.js +15 -0
- package/dist/types/gamePersistence.js.map +1 -0
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +11 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/progress.d.ts +43 -0
- package/dist/types/progress.d.ts.map +1 -0
- package/dist/types/progress.js +19 -0
- package/dist/types/progress.js.map +1 -0
- package/dist/types/settings.d.ts +19 -0
- package/dist/types/settings.d.ts.map +1 -0
- package/dist/types/settings.js +12 -0
- package/dist/types/settings.js.map +1 -0
- package/dist/types/subscription.d.ts +27 -0
- package/dist/types/subscription.d.ts.map +1 -0
- package/dist/types/subscription.js +8 -0
- package/dist/types/subscription.js.map +1 -0
- package/dist/types/sudoku.d.ts +147 -0
- package/dist/types/sudoku.d.ts.map +1 -0
- package/dist/types/sudoku.js +125 -0
- package/dist/types/sudoku.js.map +1 -0
- package/dist/utils/auth.d.ts +25 -0
- package/dist/utils/auth.d.ts.map +1 -0
- package/dist/utils/auth.js +47 -0
- package/dist/utils/auth.js.map +1 -0
- package/dist/utils/board.d.ts +116 -0
- package/dist/utils/board.d.ts.map +1 -0
- package/dist/utils/board.js +291 -0
- package/dist/utils/board.js.map +1 -0
- package/dist/utils/index.d.ts +18 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +23 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/progress.d.ts +44 -0
- package/dist/utils/progress.d.ts.map +1 -0
- package/dist/utils/progress.js +104 -0
- package/dist/utils/progress.js.map +1 -0
- package/dist/utils/scramble.d.ts +35 -0
- package/dist/utils/scramble.d.ts.map +1 -0
- package/dist/utils/scramble.js +270 -0
- package/dist/utils/scramble.js.map +1 -0
- package/dist/utils/subscription.d.ts +82 -0
- package/dist/utils/subscription.d.ts.map +1 -0
- package/dist/utils/subscription.js +117 -0
- package/dist/utils/subscription.js.map +1 -0
- package/dist/utils/sudokuPresenter.d.ts +62 -0
- package/dist/utils/sudokuPresenter.d.ts.map +1 -0
- package/dist/utils/sudokuPresenter.js +403 -0
- package/dist/utils/sudokuPresenter.js.map +1 -0
- package/dist/utils/sudokuScrambler.d.ts +61 -0
- package/dist/utils/sudokuScrambler.d.ts.map +1 -0
- package/dist/utils/sudokuScrambler.js +223 -0
- package/dist/utils/sudokuScrambler.js.map +1 -0
- package/dist/utils/technique.d.ts +41 -0
- package/dist/utils/technique.d.ts.map +1 -0
- package/dist/utils/technique.js +106 -0
- package/dist/utils/technique.js.map +1 -0
- package/dist/utils/theme.d.ts +31 -0
- package/dist/utils/theme.d.ts.map +1 -0
- package/dist/utils/theme.js +40 -0
- package/dist/utils/theme.js.map +1 -0
- package/dist/utils/time.d.ts +22 -0
- package/dist/utils/time.d.ts.map +1 -0
- package/dist/utils/time.js +41 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/validation.d.ts +107 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +248 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sudokuScrambler.d.ts","sourceRoot":"","sources":["../../src/utils/sudokuScrambler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMnE,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,EAAE,CAAC;CAC3C;AA2BD;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,iBAsBvB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,iBAI1B,CAAC;AAsBF,MAAM,WAAW,cAAc;IAC7B,4BAA4B;IAC5B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,2DAA2D;IAC3D,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,uDAAuD;IACvD,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,iBAAiB,EAC5B,KAAK,EAAE,UAAU,EAAE,EACnB,WAAW,GAAE,OAAe,GAC3B,cAAc,CAuChB;AAkCD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAChB,UAAU,EAAE,CA2Bd;AAYD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAE/D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAI9D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAE9D;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAUpE"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sudoku board scrambler - ported from renderable/utils/Scrambler.kt
|
|
3
|
+
*
|
|
4
|
+
* Generates permutations for rows, columns, and digits to create unique puzzles
|
|
5
|
+
* while preserving Sudoku validity.
|
|
6
|
+
*/
|
|
7
|
+
import { columnOf, rowOf } from '../types/sudoku';
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// Random Utilities
|
|
10
|
+
// =============================================================================
|
|
11
|
+
/**
|
|
12
|
+
* Simple seeded random number generator
|
|
13
|
+
*/
|
|
14
|
+
class SeededRandom {
|
|
15
|
+
constructor(seed) {
|
|
16
|
+
this.seed = seed;
|
|
17
|
+
}
|
|
18
|
+
nextInt() {
|
|
19
|
+
// Linear congruential generator
|
|
20
|
+
this.seed = (this.seed * 1664525 + 1013904223) >>> 0;
|
|
21
|
+
return this.seed;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Main Scrambler
|
|
26
|
+
// =============================================================================
|
|
27
|
+
/**
|
|
28
|
+
* Scrambler implementation that matches the Kotlin version
|
|
29
|
+
*/
|
|
30
|
+
export const Scrambler = {
|
|
31
|
+
scramble9(symmetrical) {
|
|
32
|
+
const random = new SeededRandom(Math.floor(Date.now() / 1000));
|
|
33
|
+
const block0 = scramble3(symmetrical, random);
|
|
34
|
+
const block1 = scramble3(symmetrical, random);
|
|
35
|
+
const block2 = symmetrical ? block0 : scramble3(symmetrical, random);
|
|
36
|
+
const blocks = [block0, block1, block2];
|
|
37
|
+
const board = scramble3(symmetrical, random);
|
|
38
|
+
const result = [];
|
|
39
|
+
for (let i = 0; i < 3; i++) {
|
|
40
|
+
const target = board[i] ?? 0;
|
|
41
|
+
const block = blocks[i] ?? [0, 1, 2];
|
|
42
|
+
for (let j = 0; j < 3; j++) {
|
|
43
|
+
result.push(target * 3 + (block[j] ?? 0));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Non-scrambler that returns identity permutation
|
|
51
|
+
*/
|
|
52
|
+
export const NonScrambler = {
|
|
53
|
+
scramble9(_symmetrical) {
|
|
54
|
+
return [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Generates a permutation of [0, 1, 2]
|
|
59
|
+
*/
|
|
60
|
+
function scramble3(symmetrical, random) {
|
|
61
|
+
if (symmetrical) {
|
|
62
|
+
const seed = random.nextInt();
|
|
63
|
+
// 50% chance for identity or reverse
|
|
64
|
+
return seed % 2 === 0 ? [0, 1, 2] : [2, 1, 0];
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// Generate 3 random values and sort to get permutation
|
|
68
|
+
const values = [random.nextInt(), random.nextInt(), random.nextInt()];
|
|
69
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
70
|
+
return sorted.map(v => values.indexOf(v));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Scramble a board using the given scrambler
|
|
75
|
+
*
|
|
76
|
+
* @param scrambler - Scrambler protocol implementation
|
|
77
|
+
* @param cells - Original 81 cells
|
|
78
|
+
* @param symmetrical - Whether to use symmetrical scrambling
|
|
79
|
+
* @returns Scrambled cells and digit mapping
|
|
80
|
+
*/
|
|
81
|
+
export function scrambleBoard(scrambler, cells, symmetrical = false) {
|
|
82
|
+
const rows = scrambler.scramble9(symmetrical);
|
|
83
|
+
const columns = scrambler.scramble9(symmetrical);
|
|
84
|
+
const numbers = scrambler.scramble9(symmetrical);
|
|
85
|
+
// Create digit mapping (1-based to 1-based)
|
|
86
|
+
const digitMapping = new Map();
|
|
87
|
+
const reverseDigitMapping = new Map();
|
|
88
|
+
for (let i = 0; i < 9; i++) {
|
|
89
|
+
const original = i + 1;
|
|
90
|
+
const scrambled = (numbers[i] ?? i) + 1;
|
|
91
|
+
digitMapping.set(original, scrambled);
|
|
92
|
+
reverseDigitMapping.set(scrambled, original);
|
|
93
|
+
}
|
|
94
|
+
const scrambledCells = Array.from({ length: 81 }, (_, index) => {
|
|
95
|
+
const x = columnOf(index);
|
|
96
|
+
const y = rowOf(index);
|
|
97
|
+
const scrambledY = rows[y] ?? y;
|
|
98
|
+
const scrambledX = columns[x] ?? x;
|
|
99
|
+
const existing = cells[scrambledY * 9 + scrambledX];
|
|
100
|
+
if (!existing) {
|
|
101
|
+
throw new Error(`Missing cell at index ${scrambledY * 9 + scrambledX}`);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
index,
|
|
105
|
+
solution: mapDigit(existing.solution, numbers),
|
|
106
|
+
given: mapDigit(existing.given, numbers),
|
|
107
|
+
input: mapDigit(existing.input, numbers),
|
|
108
|
+
pencilmarks: mapPencilmarks(existing.pencilmarks, numbers),
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
cells: scrambledCells,
|
|
113
|
+
digitMapping,
|
|
114
|
+
reverseDigitMapping,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Map a digit using the lookup array
|
|
119
|
+
* @param digit - Original digit (1-9) or null
|
|
120
|
+
* @param lookup - Permutation array (0-indexed, returns 0-indexed)
|
|
121
|
+
* @returns Mapped digit (1-9) or null
|
|
122
|
+
*/
|
|
123
|
+
function mapDigit(digit, lookup) {
|
|
124
|
+
if (digit === null || digit === 0)
|
|
125
|
+
return null;
|
|
126
|
+
// digit is 1-based, lookup is 0-indexed
|
|
127
|
+
const mapped = lookup[digit - 1];
|
|
128
|
+
return mapped !== undefined ? mapped + 1 : digit;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Map pencilmarks array using the lookup array
|
|
132
|
+
* Matches Kotlin: map(digits: Array<Int>?, lookup: Array<Int>?): Array<Int>?
|
|
133
|
+
*/
|
|
134
|
+
function mapPencilmarks(pencilmarks, lookup) {
|
|
135
|
+
if (pencilmarks === null)
|
|
136
|
+
return null;
|
|
137
|
+
return pencilmarks
|
|
138
|
+
.map(digit => mapDigit(digit, lookup))
|
|
139
|
+
.filter((d) => d !== null)
|
|
140
|
+
.sort((a, b) => a - b);
|
|
141
|
+
}
|
|
142
|
+
// =============================================================================
|
|
143
|
+
// Board Parsing
|
|
144
|
+
// =============================================================================
|
|
145
|
+
/**
|
|
146
|
+
* Parse a puzzle string (81 chars of 0-9 or .) into cells
|
|
147
|
+
*
|
|
148
|
+
* @param puzzle - 81 character string
|
|
149
|
+
* @param solution - 81 character solution string (optional)
|
|
150
|
+
* @returns Array of 81 cells
|
|
151
|
+
*/
|
|
152
|
+
export function parsePuzzleString(puzzle, solution) {
|
|
153
|
+
if (puzzle.length !== 81) {
|
|
154
|
+
throw new Error(`Invalid puzzle string length: ${puzzle.length}`);
|
|
155
|
+
}
|
|
156
|
+
if (solution && solution.length !== 81) {
|
|
157
|
+
throw new Error(`Invalid solution string length: ${solution.length}`);
|
|
158
|
+
}
|
|
159
|
+
return Array.from({ length: 81 }, (_, index) => {
|
|
160
|
+
const givenChar = puzzle[index];
|
|
161
|
+
if (givenChar === undefined) {
|
|
162
|
+
throw new Error(`Missing puzzle character at index ${index}`);
|
|
163
|
+
}
|
|
164
|
+
const givenDigit = parseDigit(givenChar);
|
|
165
|
+
const solutionChar = solution?.[index];
|
|
166
|
+
const solutionDigit = solutionChar ? parseDigit(solutionChar) : null;
|
|
167
|
+
return {
|
|
168
|
+
index,
|
|
169
|
+
solution: solutionDigit,
|
|
170
|
+
given: givenDigit,
|
|
171
|
+
input: null,
|
|
172
|
+
pencilmarks: null,
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Parse a character to a digit (1-9) or null
|
|
178
|
+
*/
|
|
179
|
+
function parseDigit(char) {
|
|
180
|
+
if (char === '0' || char === '.')
|
|
181
|
+
return null;
|
|
182
|
+
const digit = parseInt(char, 10);
|
|
183
|
+
if (digit >= 1 && digit <= 9)
|
|
184
|
+
return digit;
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Convert cells to puzzle string
|
|
189
|
+
*/
|
|
190
|
+
export function cellsToPuzzleString(cells) {
|
|
191
|
+
return cells.map(cell => cell.given?.toString() ?? '0').join('');
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Convert cells to current state string (given + input)
|
|
195
|
+
*/
|
|
196
|
+
export function cellsToStateString(cells) {
|
|
197
|
+
return cells
|
|
198
|
+
.map(cell => (cell.given ?? cell.input)?.toString() ?? '0')
|
|
199
|
+
.join('');
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Convert cells to input-only string
|
|
203
|
+
*/
|
|
204
|
+
export function cellsToInputString(cells) {
|
|
205
|
+
return cells.map(cell => cell.input?.toString() ?? '0').join('');
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Convert cells to pencilmarks string (comma-separated)
|
|
209
|
+
* Matches Kotlin: pencilmarksParam - returns empty string for null pencilmarks
|
|
210
|
+
*/
|
|
211
|
+
export function cellsToPencilmarksString(cells) {
|
|
212
|
+
return cells
|
|
213
|
+
.map(cell => {
|
|
214
|
+
if (cell.pencilmarks !== null) {
|
|
215
|
+
return cell.pencilmarks.join('');
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
return '';
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
.join(',');
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=sudokuScrambler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sudokuScrambler.js","sourceRoot":"","sources":["../../src/utils/sudokuScrambler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Technique-related utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Convert technique title to icon filename
|
|
6
|
+
*
|
|
7
|
+
* @param title - Technique title (e.g., "Full House", "X-Wing")
|
|
8
|
+
* @returns Icon URL path
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* getTechniqueIconUrl("Full House") // "/technique.full.house.svg"
|
|
12
|
+
* getTechniqueIconUrl("X-Wing") // "/technique.x.wing.svg"
|
|
13
|
+
* getTechniqueIconUrl("XY-Wing") // "/technique.xy.wing.svg"
|
|
14
|
+
*/
|
|
15
|
+
export declare function getTechniqueIconUrl(title: string): string;
|
|
16
|
+
/** Map technique titles to HTML help file paths */
|
|
17
|
+
export declare const TECHNIQUE_TO_HELP_FILE: Record<string, string>;
|
|
18
|
+
/** Reverse mapping: HTML file name (lowercase) -> technique title */
|
|
19
|
+
export declare const HELP_FILE_TO_TECHNIQUE: Record<string, string>;
|
|
20
|
+
/**
|
|
21
|
+
* Get help file URL for a technique
|
|
22
|
+
*
|
|
23
|
+
* @param techniqueTitle - Technique title
|
|
24
|
+
* @returns Help file URL path or generated path if not in mapping
|
|
25
|
+
*/
|
|
26
|
+
export declare function getHelpFileUrl(techniqueTitle: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Get technique title from help file name
|
|
29
|
+
*
|
|
30
|
+
* @param fileName - Help file name (e.g., "Full_House.html")
|
|
31
|
+
* @returns Technique title or undefined if not found
|
|
32
|
+
*/
|
|
33
|
+
export declare function getTechniqueFromHelpFile(fileName: string): string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Extract body content from HTML and clean up navigation links
|
|
36
|
+
*
|
|
37
|
+
* @param html - Raw HTML string
|
|
38
|
+
* @returns Cleaned HTML body content
|
|
39
|
+
*/
|
|
40
|
+
export declare function extractBodyContent(html: string): string;
|
|
41
|
+
//# sourceMappingURL=technique.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"technique.d.ts","sourceRoot":"","sources":["../../src/utils/technique.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED,mDAAmD;AACnD,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAyBzD,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQzD,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE7E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyBvD"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Technique-related utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Convert technique title to icon filename
|
|
6
|
+
*
|
|
7
|
+
* @param title - Technique title (e.g., "Full House", "X-Wing")
|
|
8
|
+
* @returns Icon URL path
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* getTechniqueIconUrl("Full House") // "/technique.full.house.svg"
|
|
12
|
+
* getTechniqueIconUrl("X-Wing") // "/technique.x.wing.svg"
|
|
13
|
+
* getTechniqueIconUrl("XY-Wing") // "/technique.xy.wing.svg"
|
|
14
|
+
*/
|
|
15
|
+
export function getTechniqueIconUrl(title) {
|
|
16
|
+
const normalized = title
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.replace(/\s+/g, '.') // spaces to dots
|
|
19
|
+
.replace(/-/g, '.'); // hyphens to dots
|
|
20
|
+
return `/technique.${normalized}.svg`;
|
|
21
|
+
}
|
|
22
|
+
/** Map technique titles to HTML help file paths */
|
|
23
|
+
export const TECHNIQUE_TO_HELP_FILE = {
|
|
24
|
+
'Full House': 'Full_House.html',
|
|
25
|
+
'Naked Single': 'Naked_Single.html',
|
|
26
|
+
'Hidden Single': 'Hidden_Single.html',
|
|
27
|
+
'Naked Pair': 'Naked_Pair.html',
|
|
28
|
+
'Hidden Pair': 'Hidden_Pair.html',
|
|
29
|
+
'Locked Candidates': 'Locked_Candidates.html',
|
|
30
|
+
'Naked Triple': 'Naked_Triple.html',
|
|
31
|
+
'Hidden Triple': 'Hidden_Triple.html',
|
|
32
|
+
'Naked Quad': 'Nakded_Quad.html', // Note: typo in original file name
|
|
33
|
+
'Hidden Quad': 'Hidden_Quad.html',
|
|
34
|
+
'X-Wing': 'X-Wing.html',
|
|
35
|
+
Swordfish: 'Swordfish.html',
|
|
36
|
+
Jellyfish: 'Jellyfish.html',
|
|
37
|
+
Squirmbag: 'Squirmbag.html',
|
|
38
|
+
'XY-Wing': 'XY-Wing.html',
|
|
39
|
+
'XYZ-Wing': 'XYZ-Wing.html',
|
|
40
|
+
'WXYZ-Wing': 'WXYZ-Wing.html',
|
|
41
|
+
'Finned X-Wing': 'Finned_X-Wing.html',
|
|
42
|
+
'Finned Swordfish': 'Finned_Swordfish.html',
|
|
43
|
+
'Finned Jellyfish': 'Finned_Jellyfish.html',
|
|
44
|
+
'Finned Squirmbag': 'Finned_Squirmbag.html',
|
|
45
|
+
'Almost Locked Sets': 'Almost_Locked_Sets.html',
|
|
46
|
+
'ALS Chain': 'ALS-Chain.html',
|
|
47
|
+
'ALS-Chain': 'ALS-Chain.html',
|
|
48
|
+
};
|
|
49
|
+
/** Reverse mapping: HTML file name (lowercase) -> technique title */
|
|
50
|
+
export const HELP_FILE_TO_TECHNIQUE = Object.entries(TECHNIQUE_TO_HELP_FILE).reduce((acc, [title, file]) => {
|
|
51
|
+
acc[file.toLowerCase()] = title;
|
|
52
|
+
return acc;
|
|
53
|
+
}, {});
|
|
54
|
+
/**
|
|
55
|
+
* Get help file URL for a technique
|
|
56
|
+
*
|
|
57
|
+
* @param techniqueTitle - Technique title
|
|
58
|
+
* @returns Help file URL path or generated path if not in mapping
|
|
59
|
+
*/
|
|
60
|
+
export function getHelpFileUrl(techniqueTitle) {
|
|
61
|
+
const fileName = TECHNIQUE_TO_HELP_FILE[techniqueTitle];
|
|
62
|
+
if (fileName) {
|
|
63
|
+
return `/help/${fileName}`;
|
|
64
|
+
}
|
|
65
|
+
// Try to generate file name from title (spaces to underscores, preserve hyphens)
|
|
66
|
+
const generatedFileName = `${techniqueTitle.replace(/\s+/g, '_')}.html`;
|
|
67
|
+
return `/help/${generatedFileName}`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get technique title from help file name
|
|
71
|
+
*
|
|
72
|
+
* @param fileName - Help file name (e.g., "Full_House.html")
|
|
73
|
+
* @returns Technique title or undefined if not found
|
|
74
|
+
*/
|
|
75
|
+
export function getTechniqueFromHelpFile(fileName) {
|
|
76
|
+
return HELP_FILE_TO_TECHNIQUE[fileName.toLowerCase()];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Extract body content from HTML and clean up navigation links
|
|
80
|
+
*
|
|
81
|
+
* @param html - Raw HTML string
|
|
82
|
+
* @returns Cleaned HTML body content
|
|
83
|
+
*/
|
|
84
|
+
export function extractBodyContent(html) {
|
|
85
|
+
const parser = new DOMParser();
|
|
86
|
+
const doc = parser.parseFromString(html, 'text/html');
|
|
87
|
+
// Remove "Back to Course Catalog" links
|
|
88
|
+
const links = doc.querySelectorAll('a[href="index.html"]');
|
|
89
|
+
links.forEach(link => {
|
|
90
|
+
const parent = link.closest('tr') ?? link.closest('td') ?? link.parentElement;
|
|
91
|
+
if (parent) {
|
|
92
|
+
parent.remove();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
// Fix image paths - convert relative paths to absolute /help/ paths
|
|
96
|
+
const images = doc.querySelectorAll('img');
|
|
97
|
+
images.forEach(img => {
|
|
98
|
+
const src = img.getAttribute('src');
|
|
99
|
+
if (src && !src.startsWith('/') && !src.startsWith('http')) {
|
|
100
|
+
img.setAttribute('src', `/help/${src}`);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
// Get the body content
|
|
104
|
+
return doc.body.innerHTML;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=technique.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"technique.js","sourceRoot":"","sources":["../../src/utils/technique.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme utilities
|
|
3
|
+
*/
|
|
4
|
+
/** Available theme options */
|
|
5
|
+
export type ThemePreference = 'light' | 'dark' | 'system';
|
|
6
|
+
/** Resolved theme (without system option) */
|
|
7
|
+
export type ResolvedTheme = 'light' | 'dark';
|
|
8
|
+
/** Storage key for theme preference */
|
|
9
|
+
export declare const THEME_STORAGE_KEY = "sudojo-theme";
|
|
10
|
+
/**
|
|
11
|
+
* Detect system color scheme preference
|
|
12
|
+
*
|
|
13
|
+
* @returns 'dark' if system prefers dark mode, 'light' otherwise
|
|
14
|
+
*/
|
|
15
|
+
export declare function getSystemTheme(): ResolvedTheme;
|
|
16
|
+
/**
|
|
17
|
+
* Resolve theme preference to actual theme
|
|
18
|
+
*
|
|
19
|
+
* @param preference - User's theme preference
|
|
20
|
+
* @param systemTheme - Current system theme
|
|
21
|
+
* @returns Resolved theme ('light' or 'dark')
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveTheme(preference: ThemePreference, systemTheme: ResolvedTheme): ResolvedTheme;
|
|
24
|
+
/**
|
|
25
|
+
* Check if a value is a valid theme preference
|
|
26
|
+
*
|
|
27
|
+
* @param value - Value to check
|
|
28
|
+
* @returns Whether value is a valid theme preference
|
|
29
|
+
*/
|
|
30
|
+
export declare function isValidThemePreference(value: unknown): value is ThemePreference;
|
|
31
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/utils/theme.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,8BAA8B;AAC9B,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE1D,6CAA6C;AAC7C,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAE7C,uCAAuC;AACvC,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,aAAa,CAK9C;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,eAAe,EAC3B,WAAW,EAAE,aAAa,GACzB,aAAa,CAKf;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,eAAe,CAE1B"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme utilities
|
|
3
|
+
*/
|
|
4
|
+
/** Storage key for theme preference */
|
|
5
|
+
export const THEME_STORAGE_KEY = 'sudojo-theme';
|
|
6
|
+
/**
|
|
7
|
+
* Detect system color scheme preference
|
|
8
|
+
*
|
|
9
|
+
* @returns 'dark' if system prefers dark mode, 'light' otherwise
|
|
10
|
+
*/
|
|
11
|
+
export function getSystemTheme() {
|
|
12
|
+
if (typeof window === 'undefined')
|
|
13
|
+
return 'light';
|
|
14
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
15
|
+
? 'dark'
|
|
16
|
+
: 'light';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve theme preference to actual theme
|
|
20
|
+
*
|
|
21
|
+
* @param preference - User's theme preference
|
|
22
|
+
* @param systemTheme - Current system theme
|
|
23
|
+
* @returns Resolved theme ('light' or 'dark')
|
|
24
|
+
*/
|
|
25
|
+
export function resolveTheme(preference, systemTheme) {
|
|
26
|
+
if (preference === 'system') {
|
|
27
|
+
return systemTheme;
|
|
28
|
+
}
|
|
29
|
+
return preference;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if a value is a valid theme preference
|
|
33
|
+
*
|
|
34
|
+
* @param value - Value to check
|
|
35
|
+
* @returns Whether value is a valid theme preference
|
|
36
|
+
*/
|
|
37
|
+
export function isValidThemePreference(value) {
|
|
38
|
+
return value === 'light' || value === 'dark' || value === 'system';
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/utils/theme.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,uCAAuC;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAEhD;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,OAAO,CAAC;IAClD,OAAO,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,OAAO;QAC9D,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,OAAO,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,UAA2B,EAC3B,WAA0B;IAE1B,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,KAAc;IAEd,OAAO,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,QAAQ,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Format seconds into MM:SS or HH:MM:SS string
|
|
6
|
+
*
|
|
7
|
+
* @param seconds - Total seconds to format
|
|
8
|
+
* @returns Formatted time string
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* formatTime(65) // "1:05"
|
|
12
|
+
* formatTime(3665) // "1:01:05"
|
|
13
|
+
*/
|
|
14
|
+
export declare function formatTime(seconds: number): string;
|
|
15
|
+
/**
|
|
16
|
+
* Parse a time string back to seconds
|
|
17
|
+
*
|
|
18
|
+
* @param timeString - Time string in MM:SS or HH:MM:SS format
|
|
19
|
+
* @returns Total seconds
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseTime(timeString: string): number;
|
|
22
|
+
//# sourceMappingURL=time.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASlD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAWpD"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Format seconds into MM:SS or HH:MM:SS string
|
|
6
|
+
*
|
|
7
|
+
* @param seconds - Total seconds to format
|
|
8
|
+
* @returns Formatted time string
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* formatTime(65) // "1:05"
|
|
12
|
+
* formatTime(3665) // "1:01:05"
|
|
13
|
+
*/
|
|
14
|
+
export function formatTime(seconds) {
|
|
15
|
+
const hours = Math.floor(seconds / 3600);
|
|
16
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
17
|
+
const secs = seconds % 60;
|
|
18
|
+
if (hours > 0) {
|
|
19
|
+
return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
|
20
|
+
}
|
|
21
|
+
return `${minutes}:${secs.toString().padStart(2, '0')}`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Parse a time string back to seconds
|
|
25
|
+
*
|
|
26
|
+
* @param timeString - Time string in MM:SS or HH:MM:SS format
|
|
27
|
+
* @returns Total seconds
|
|
28
|
+
*/
|
|
29
|
+
export function parseTime(timeString) {
|
|
30
|
+
const parts = timeString.split(':').map(Number);
|
|
31
|
+
if (parts.length === 2) {
|
|
32
|
+
const [minutes, secs] = parts;
|
|
33
|
+
return (minutes ?? 0) * 60 + (secs ?? 0);
|
|
34
|
+
}
|
|
35
|
+
if (parts.length === 3) {
|
|
36
|
+
const [hours, minutes, secs] = parts;
|
|
37
|
+
return (hours ?? 0) * 3600 + (minutes ?? 0) * 60 + (secs ?? 0);
|
|
38
|
+
}
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time.js","sourceRoot":"","sources":["../../src/utils/time.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,OAAO,GAAG,EAAE,CAAC;IAE1B,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,OAAO,GAAG,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IAC/F,CAAC;IACD,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,UAAkB;IAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;QAC9B,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;QACrC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Game validation utilities for checking mistakes, completion, and game state
|
|
3
|
+
*/
|
|
4
|
+
import type { GameBoard, GameState } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Checks if a cell value matches the solution
|
|
7
|
+
* @param board - GameBoard
|
|
8
|
+
* @param solution - 81-character solution string
|
|
9
|
+
* @param row - Row index
|
|
10
|
+
* @param col - Column index
|
|
11
|
+
* @returns true if the cell value matches the solution (or is empty)
|
|
12
|
+
*/
|
|
13
|
+
export declare function isCellCorrect(board: GameBoard, solution: string, row: number, col: number): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Checks if a specific value would be correct for a cell
|
|
16
|
+
* @param solution - 81-character solution string
|
|
17
|
+
* @param row - Row index
|
|
18
|
+
* @param col - Column index
|
|
19
|
+
* @param value - Value to check (1-9)
|
|
20
|
+
* @returns true if the value matches the solution
|
|
21
|
+
*/
|
|
22
|
+
export declare function isValueCorrect(solution: string, row: number, col: number, value: number): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Gets all cells with incorrect values
|
|
25
|
+
* @param board - GameBoard
|
|
26
|
+
* @param solution - 81-character solution string
|
|
27
|
+
* @returns Array of {row, column} positions with incorrect values
|
|
28
|
+
*/
|
|
29
|
+
export declare function getIncorrectCells(board: GameBoard, solution: string): Array<{
|
|
30
|
+
row: number;
|
|
31
|
+
column: number;
|
|
32
|
+
}>;
|
|
33
|
+
/**
|
|
34
|
+
* Updates the error state of all cells based on the solution
|
|
35
|
+
* @param board - GameBoard to update
|
|
36
|
+
* @param solution - 81-character solution string
|
|
37
|
+
* @param showErrors - Whether to show errors
|
|
38
|
+
* @returns Updated GameBoard
|
|
39
|
+
*/
|
|
40
|
+
export declare function updateCellErrors(board: GameBoard, solution: string, showErrors: boolean): GameBoard;
|
|
41
|
+
/**
|
|
42
|
+
* Checks if the game is complete (all cells filled correctly)
|
|
43
|
+
* @param board - GameBoard
|
|
44
|
+
* @param solution - 81-character solution string
|
|
45
|
+
* @returns true if all cells are filled with correct values
|
|
46
|
+
*/
|
|
47
|
+
export declare function isGameComplete(board: GameBoard, solution: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Checks if the board is fully filled (regardless of correctness)
|
|
50
|
+
* @param board - GameBoard
|
|
51
|
+
* @returns true if all cells have values
|
|
52
|
+
*/
|
|
53
|
+
export declare function isBoardFilled(board: GameBoard): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Counts the number of mistakes in the current board
|
|
56
|
+
* @param board - GameBoard
|
|
57
|
+
* @param solution - 81-character solution string
|
|
58
|
+
* @returns Number of incorrect cells
|
|
59
|
+
*/
|
|
60
|
+
export declare function countMistakes(board: GameBoard, solution: string): number;
|
|
61
|
+
/**
|
|
62
|
+
* Updates highlight state for all cells based on selected cell
|
|
63
|
+
* @param board - GameBoard
|
|
64
|
+
* @param selectedRow - Selected row (or null if nothing selected)
|
|
65
|
+
* @param selectedCol - Selected column (or null if nothing selected)
|
|
66
|
+
* @param highlightRelated - Whether to highlight related cells
|
|
67
|
+
* @param highlightSameValue - Whether to highlight cells with same value
|
|
68
|
+
* @returns Updated GameBoard
|
|
69
|
+
*/
|
|
70
|
+
export declare function updateCellHighlights(board: GameBoard, selectedRow: number | null, selectedCol: number | null, highlightRelated: boolean, highlightSameValue: boolean): GameBoard;
|
|
71
|
+
/**
|
|
72
|
+
* Clears all highlights from the board
|
|
73
|
+
* @param board - GameBoard
|
|
74
|
+
* @returns Board with no highlights
|
|
75
|
+
*/
|
|
76
|
+
export declare function clearHighlights(board: GameBoard): GameBoard;
|
|
77
|
+
/**
|
|
78
|
+
* Auto-removes pencilmarks from related cells when a value is placed
|
|
79
|
+
* @param board - GameBoard
|
|
80
|
+
* @param row - Row where value was placed
|
|
81
|
+
* @param col - Column where value was placed
|
|
82
|
+
* @param value - Value that was placed
|
|
83
|
+
* @returns Updated GameBoard with pencilmarks removed
|
|
84
|
+
*/
|
|
85
|
+
export declare function autoRemovePencilmarks(board: GameBoard, row: number, col: number, value: number): GameBoard;
|
|
86
|
+
/**
|
|
87
|
+
* Gets the progress percentage (filled cells / total empty cells in original puzzle)
|
|
88
|
+
* @param board - GameBoard
|
|
89
|
+
* @returns Progress percentage (0-100)
|
|
90
|
+
*/
|
|
91
|
+
export declare function getProgressPercentage(board: GameBoard): number;
|
|
92
|
+
/**
|
|
93
|
+
* Validates the entire game state
|
|
94
|
+
* @param state - GameState
|
|
95
|
+
* @returns Object with validation results
|
|
96
|
+
*/
|
|
97
|
+
export declare function validateGameState(state: GameState): {
|
|
98
|
+
isComplete: boolean;
|
|
99
|
+
isFilled: boolean;
|
|
100
|
+
mistakeCount: number;
|
|
101
|
+
progressPercentage: number;
|
|
102
|
+
incorrectCells: Array<{
|
|
103
|
+
row: number;
|
|
104
|
+
column: number;
|
|
105
|
+
}>;
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,OAAO,CAST;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,OAAO,CAGT;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,MAAM,GACf,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBxC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,OAAO,GAClB,SAAS,CAoBX;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAe1E;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CASvD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,gBAAgB,EAAE,OAAO,EACzB,kBAAkB,EAAE,OAAO,GAC1B,SAAS,CA2CX;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAS3D;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,SAAS,CAwBX;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAqB9D;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG;IACnD,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD,CAQA"}
|