@fgv/ts-sudoku-lib 5.0.1-9 → 5.0.2-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.
Files changed (55) hide show
  1. package/dist/index.browser.js +37 -0
  2. package/dist/index.js +30 -0
  3. package/dist/packlets/collections/collections.js +136 -0
  4. package/dist/packlets/collections/data/puzzles.json +56 -0
  5. package/dist/packlets/collections/index.js +25 -0
  6. package/dist/packlets/common/cage.js +83 -0
  7. package/dist/packlets/common/cell.js +88 -0
  8. package/dist/packlets/common/common.js +70 -0
  9. package/dist/packlets/common/converters.js +65 -0
  10. package/dist/packlets/common/ids.js +152 -0
  11. package/dist/packlets/common/index.js +36 -0
  12. package/dist/packlets/common/logging.js +32 -0
  13. package/dist/packlets/common/public.js +25 -0
  14. package/dist/packlets/common/puzzle.js +411 -0
  15. package/dist/packlets/common/puzzleDefinitions.js +247 -0
  16. package/dist/packlets/common/puzzleSession.js +369 -0
  17. package/dist/packlets/common/puzzleState.js +99 -0
  18. package/dist/packlets/files/converters.js +67 -0
  19. package/dist/packlets/files/fileTreeHelpers.js +37 -0
  20. package/dist/packlets/files/filesystem.js +37 -0
  21. package/dist/packlets/files/index.browser.js +32 -0
  22. package/dist/packlets/files/index.js +30 -0
  23. package/dist/packlets/files/model.js +25 -0
  24. package/dist/packlets/hints/baseHintProvider.js +199 -0
  25. package/dist/packlets/hints/explanations.js +270 -0
  26. package/dist/packlets/hints/hiddenSingles.js +233 -0
  27. package/dist/packlets/hints/hintRegistry.js +222 -0
  28. package/dist/packlets/hints/hints.js +311 -0
  29. package/dist/packlets/hints/index.js +39 -0
  30. package/dist/packlets/hints/interfaces.js +25 -0
  31. package/dist/packlets/hints/nakedSingles.js +198 -0
  32. package/dist/packlets/hints/puzzleSessionHints.js +495 -0
  33. package/dist/packlets/hints/types.js +43 -0
  34. package/dist/packlets/puzzles/anyPuzzle.js +47 -0
  35. package/dist/packlets/puzzles/index.js +31 -0
  36. package/dist/packlets/puzzles/internal/combinationCache.js +75 -0
  37. package/dist/packlets/puzzles/internal/combinationGenerator.js +142 -0
  38. package/dist/packlets/puzzles/internal/possibilityAnalyzer.js +121 -0
  39. package/dist/packlets/puzzles/killerCombinations.js +222 -0
  40. package/dist/packlets/puzzles/killerCombinationsTypes.js +25 -0
  41. package/dist/packlets/puzzles/killerSudokuPuzzle.js +136 -0
  42. package/dist/packlets/puzzles/sudokuPuzzle.js +43 -0
  43. package/dist/packlets/puzzles/sudokuXPuzzle.js +65 -0
  44. package/dist/test/unit/helpers/puzzleBuilders.js +149 -0
  45. package/dist/ts-sudoku-lib.d.ts +12 -7
  46. package/dist/tsdoc-metadata.json +1 -1
  47. package/lib/index.browser.d.ts +7 -0
  48. package/lib/index.browser.js +78 -0
  49. package/lib/packlets/files/fileTreeHelpers.d.ts +13 -0
  50. package/lib/packlets/files/fileTreeHelpers.js +40 -0
  51. package/lib/packlets/files/index.browser.d.ts +5 -0
  52. package/lib/packlets/files/index.browser.js +70 -0
  53. package/lib/packlets/files/index.d.ts +3 -2
  54. package/lib/packlets/files/index.js +7 -4
  55. package/package.json +23 -5
@@ -0,0 +1,99 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2023 Erik Fortune
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ import { fail, succeed } from '@fgv/ts-utils';
25
+ /**
26
+ * @public
27
+ */
28
+ export class PuzzleState {
29
+ /**
30
+ * @internal
31
+ */
32
+ constructor(from, updates) {
33
+ const entries = [...Array.from(from.entries()), ...PuzzleState._toEntries(updates)];
34
+ this._cells = new Map(entries);
35
+ }
36
+ /**
37
+ * Constructs a new {@link PuzzleState | PuzzleState}.
38
+ * @param cells - An array of {@link ICellState | CellState} used to initialize the state.
39
+ * @returns The new {@link PuzzleState | PuzzleState}.
40
+ */
41
+ static create(cells) {
42
+ return succeed(new PuzzleState(new Map(), cells));
43
+ }
44
+ /**
45
+ * Convert {@link ICellContents | CellContents} to `[`{@link CellId | CellId}`,` {@link ICellContents | CellContents}`]`
46
+ * tuple for `Map` construction.
47
+ * @param states - An array of {@link ICellContents | CellContents} to be converted.
48
+ * @returns The corresponding array of `[`{@link CellId | CellId}`,` {@link ICellContents | CellContents}`]`
49
+ * @internal
50
+ */
51
+ static _toEntries(states) {
52
+ /* c8 ignore next 3 - defense in depth */
53
+ if (!states) {
54
+ return [];
55
+ }
56
+ return states.map((state) => {
57
+ const { id, value, notes } = state;
58
+ return [id, { value, notes }];
59
+ });
60
+ }
61
+ /**
62
+ * Gets the contents of a cell specified by {@link CellId | id}.
63
+ * @param id - The {@link CellId | id} of the cell to be retrieved.
64
+ * @returns A {@link ICellContents | CellContents} with the contents of
65
+ * the requested cell.
66
+ */
67
+ getCellContents(id) {
68
+ const cell = this._cells.get(id);
69
+ return cell ? succeed(cell) : fail(`cell ${id} not found`);
70
+ }
71
+ /**
72
+ * Determines if some cell has an assigned value.
73
+ * @param id - The {@link CellId | id} of the cell to be tested.
74
+ * @returns `true` if the cell has a value, `false` if the cell
75
+ * is empty or invalid.
76
+ */
77
+ hasValue(id) {
78
+ const cell = this._cells.get(id);
79
+ /* c8 ignore next 1 - defense in depth, tested but coverage fails */
80
+ return (cell === null || cell === void 0 ? void 0 : cell.value) !== undefined;
81
+ }
82
+ /**
83
+ * Creates a new {@link PuzzleState | PuzzleState} which corresponds
84
+ * to this state with updates applied.
85
+ * @param updates - An array of {@link ICellState | CellState} to be
86
+ * applied.
87
+ * @returns A new {@link PuzzleState} with updates applied.
88
+ */
89
+ update(updates) {
90
+ const updated = new PuzzleState(this._cells, updates);
91
+ /* c8 ignore next 3 - functional code tested but coverage intermittently missed */
92
+ if (updated._cells.size > this._cells.size) {
93
+ return fail(`update added cells`);
94
+ }
95
+ return succeed(updated);
96
+ }
97
+ }
98
+ /* c8 ignore next 7 - functional code tested but coverage intermittently missed */
99
+ //# sourceMappingURL=puzzleState.js.map
@@ -0,0 +1,67 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2023 Erik Fortune
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ import { Converters, succeed } from '@fgv/ts-utils';
25
+ import { Converters as CommonConverters } from '../common';
26
+ /**
27
+ * Converts puzzle file dimensions from JSON format
28
+ * @public
29
+ */
30
+ export const puzzleFileDimensions = Converters.strictObject({
31
+ cageWidthInCells: Converters.number,
32
+ cageHeightInCells: Converters.number,
33
+ boardWidthInCages: Converters.number,
34
+ boardHeightInCages: Converters.number
35
+ });
36
+ /**
37
+ * Converts puzzle file data from JSON format
38
+ * @public
39
+ */
40
+ export const puzzleFileData = Converters.strictObject({
41
+ id: Converters.string,
42
+ description: Converters.string,
43
+ type: CommonConverters.puzzleType,
44
+ level: Converters.number,
45
+ cells: Converters.oneOf([Converters.string, Converters.stringArray.map((s) => succeed(s.join('')))]),
46
+ dimensions: puzzleFileDimensions
47
+ }, {
48
+ optionalFields: ['id']
49
+ });
50
+ /**
51
+ * Converts an arbitrary object to a {@link Files.Model.IPuzzlesFile | IPuzzlesFile}.
52
+ * @public
53
+ */
54
+ export const puzzlesFile = Converters.strictObject({
55
+ puzzles: Converters.arrayOf(puzzleFileData)
56
+ });
57
+ /**
58
+ * Loads a puzzles file from a `IFileTreeFileItem`.
59
+ * @param file - The `IFileTreeFileItem` to load.
60
+ * @returns `Success` with the resulting {@link Files.Model.IPuzzlesFile | IPuzzlesFile}, or `Failure` with
61
+ * details if an error occurs.
62
+ * @public
63
+ */
64
+ export function loadPuzzlesFile(file) {
65
+ return file.getContents(puzzlesFile);
66
+ }
67
+ //# sourceMappingURL=converters.js.map
@@ -0,0 +1,37 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2025 Erik Fortune
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ import { puzzlesFile } from './converters';
25
+ import { JsonFile } from '@fgv/ts-json-base';
26
+ /**
27
+ * Loads a puzzles file from a {@link FileTree.FileTree | FileTree}.
28
+ * @param fileTree - FileTree containing the file
29
+ * @param filePath - Path within the FileTree to the puzzles file
30
+ * @returns `Success` with the resulting file, or `Failure` with details if an
31
+ * error occurs.
32
+ * @public
33
+ */
34
+ export function loadJsonPuzzlesFromTree(fileTree, filePath) {
35
+ return JsonFile.DefaultJsonTreeHelper.convertJsonFromTree(fileTree, filePath, puzzlesFile);
36
+ }
37
+ //# sourceMappingURL=fileTreeHelpers.js.map
@@ -0,0 +1,37 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2025 Erik Fortune
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ import { puzzlesFile } from './converters';
25
+ import { JsonFile } from '@fgv/ts-json-base';
26
+ /**
27
+ * Loads an arbitrary JSON file and parses it to return a validated
28
+ * {@link Files.Model.IPuzzlesFile | IPuzzlesFile}.
29
+ * @param path - String path to the file
30
+ * @returns `Success` with the resulting file, or `Failure` with details if an
31
+ * error occurs.
32
+ * @public
33
+ */
34
+ export function loadJsonPuzzlesFileSync(path) {
35
+ return JsonFile.convertJsonFileSync(path, puzzlesFile);
36
+ }
37
+ //# sourceMappingURL=filesystem.js.map
@@ -0,0 +1,32 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2025 Erik Fortune
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ // Browser-safe files exports - includes FileTree functions, excludes Node.js filesystem functions
25
+ import * as Converters from './converters';
26
+ import * as Model from './model';
27
+ export { Converters, Model };
28
+ // Re-export browser-compatible FileTree helpers
29
+ export { loadJsonPuzzlesFromTree } from './fileTreeHelpers';
30
+ // Excluded from browser:
31
+ // - loadJsonPuzzlesFileSync (requires Node.js fs via JsonFile.convertJsonFileSync)
32
+ //# sourceMappingURL=index.browser.js.map
@@ -0,0 +1,30 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2025 Erik Fortune
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ import * as Converters from './converters';
25
+ import * as Model from './model';
26
+ export { Converters, Model };
27
+ // Export both filesystem and FileTree helpers
28
+ export { loadJsonPuzzlesFileSync } from './filesystem';
29
+ export { loadJsonPuzzlesFromTree } from './fileTreeHelpers';
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,25 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2023 Erik Fortune
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ export {};
25
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1,199 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2023 Erik Fortune
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ import { fail, succeed } from '@fgv/ts-utils';
25
+ import { ConfidenceLevels } from './types';
26
+ /**
27
+ * Abstract base class providing common functionality for hint providers.
28
+ * @public
29
+ */
30
+ export class BaseHintProvider {
31
+ constructor(config) {
32
+ var _a;
33
+ this.techniqueId = config.techniqueId;
34
+ this.techniqueName = config.techniqueName;
35
+ this.difficulty = config.difficulty;
36
+ this.priority = config.priority;
37
+ this.defaultConfidence = (_a = config.defaultConfidence) !== null && _a !== void 0 ? _a : ConfidenceLevels.MEDIUM;
38
+ }
39
+ /**
40
+ * Utility method to create a hint with consistent structure.
41
+ * @param cellActions - The actions to be performed on cells
42
+ * @param relevantCells - The cells relevant to understanding the hint
43
+ * @param explanations - The explanations for the hint
44
+ * @param confidence - The confidence level for this hint
45
+ * @returns A complete hint object
46
+ */
47
+ createHint(cellActions, relevantCells, explanations, confidence) {
48
+ /* c8 ignore next 1 - defense in depth */
49
+ confidence = confidence !== null && confidence !== void 0 ? confidence : this.defaultConfidence;
50
+ return {
51
+ techniqueId: this.techniqueId,
52
+ techniqueName: this.techniqueName,
53
+ difficulty: this.difficulty,
54
+ confidence,
55
+ cellActions,
56
+ relevantCells,
57
+ explanations,
58
+ priority: this.priority
59
+ };
60
+ }
61
+ /**
62
+ * Utility method to create cell actions.
63
+ * @param cellId - The ID of the cell to act upon
64
+ * @param action - The type of action to perform
65
+ * @param value - Optional value for set-value actions
66
+ * @param reason - Optional reason for the action
67
+ * @returns A cell action object
68
+ */
69
+ createCellAction(cellId, action, value, reason) {
70
+ return {
71
+ cellId,
72
+ action,
73
+ value,
74
+ reason
75
+ };
76
+ }
77
+ /**
78
+ * Utility method to create relevant cells grouping.
79
+ * @param primary - Primary cells that are the focus of the hint
80
+ * @param secondary - Secondary cells that provide context
81
+ * @param affected - Cells that will be affected by applying the hint
82
+ * @returns A relevant cells object
83
+ */
84
+ createRelevantCells(primary, secondary = [], affected = []) {
85
+ return {
86
+ primary,
87
+ secondary,
88
+ affected
89
+ };
90
+ }
91
+ /**
92
+ * Utility method to create hint explanations.
93
+ * @param level - The level of detail for the explanation
94
+ * @param title - The title of the explanation
95
+ * @param description - The main description
96
+ * @param steps - Optional step-by-step instructions
97
+ * @param tips - Optional tips for understanding the technique
98
+ * @returns A hint explanation object
99
+ */
100
+ createExplanation(level, title, description, steps, tips) {
101
+ return {
102
+ level,
103
+ title,
104
+ description,
105
+ steps,
106
+ tips
107
+ };
108
+ }
109
+ /**
110
+ * Filters hints based on generation options.
111
+ * @param hints - The hints to filter
112
+ * @param options - The filtering options
113
+ * @returns Filtered array of hints
114
+ */
115
+ filterHints(hints, options) {
116
+ if (!options) {
117
+ return hints;
118
+ }
119
+ let filtered = [...hints];
120
+ // Filter by minimum confidence
121
+ if (options.minConfidence) {
122
+ filtered = filtered.filter((hint) => hint.confidence >= options.minConfidence);
123
+ }
124
+ // Filter by enabled techniques
125
+ if (options.enabledTechniques && options.enabledTechniques.length > 0) {
126
+ filtered = filtered.filter((hint) => options.enabledTechniques.includes(hint.techniqueId));
127
+ }
128
+ // Limit number of hints
129
+ if (options.maxHints && options.maxHints > 0) {
130
+ // Sort by confidence (descending) then priority (ascending)
131
+ filtered.sort((a, b) => {
132
+ if (a.confidence !== b.confidence) {
133
+ return b.confidence - a.confidence;
134
+ }
135
+ return a.priority - b.priority;
136
+ });
137
+ filtered = filtered.slice(0, options.maxHints);
138
+ }
139
+ return filtered;
140
+ }
141
+ /**
142
+ * Validates generation options for consistency.
143
+ * @param options - The options to validate
144
+ * @returns Result indicating validation success or failure
145
+ */
146
+ validateOptions(options) {
147
+ if (!options) {
148
+ return succeed(undefined);
149
+ }
150
+ if (options.maxHints !== undefined && options.maxHints < 0) {
151
+ return fail('maxHints cannot be negative');
152
+ }
153
+ if (options.minConfidence !== undefined && (options.minConfidence < 1 || options.minConfidence > 5)) {
154
+ return fail('minConfidence must be between 1 and 5');
155
+ }
156
+ return succeed(undefined);
157
+ }
158
+ /**
159
+ * Gets all empty cells in the puzzle.
160
+ * @param puzzle - The puzzle structure
161
+ * @param state - The puzzle state to analyze
162
+ * @returns Array of cell IDs that are empty
163
+ */
164
+ getEmptyCells(puzzle, state) {
165
+ return puzzle.getEmptyCells(state).map((cell) => cell.id);
166
+ }
167
+ /**
168
+ * Gets the possible candidate values for a specific cell using cage-based constraints.
169
+ * This implementation works with any puzzle variant by checking all applicable cages.
170
+ * @param cellId - The cell to analyze
171
+ * @param puzzle - The puzzle structure containing constraints
172
+ * @param state - The current puzzle state
173
+ * @returns Array of possible values for the cell
174
+ */
175
+ getCandidates(cellId, puzzle, state) {
176
+ if (state.hasValue(cellId)) {
177
+ return [];
178
+ }
179
+ // Get maximum value based on grid size (typically sqrt of total cells)
180
+ const maxValue = Math.sqrt(puzzle.numRows * puzzle.numColumns);
181
+ // Find all cages that contain this cell
182
+ const applicableCages = puzzle.cages.filter((cage) => cage.containsCell(cellId));
183
+ // Collect all values that are forbidden due to cage constraints
184
+ const usedValues = new Set();
185
+ for (const cage of applicableCages) {
186
+ const cageValues = cage.containedValues(state);
187
+ cageValues.forEach((value) => usedValues.add(value));
188
+ }
189
+ // Generate candidates (values not used in any applicable cage)
190
+ const candidates = [];
191
+ for (let value = 1; value <= maxValue; value++) {
192
+ if (!usedValues.has(value)) {
193
+ candidates.push(value);
194
+ }
195
+ }
196
+ return candidates;
197
+ }
198
+ }
199
+ //# sourceMappingURL=baseHintProvider.js.map