@fgv/ts-sudoku-lib 5.0.1-0 → 5.0.1-2

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 (82) hide show
  1. package/debug_killer.js +50 -0
  2. package/debug_test.js +88 -0
  3. package/dist/ts-sudoku-lib.d.ts +1505 -42
  4. package/lib/index.d.ts +3 -2
  5. package/lib/index.js +5 -3
  6. package/lib/packlets/collections/collections.d.ts +15 -8
  7. package/lib/packlets/collections/collections.js +41 -11
  8. package/lib/packlets/collections/data/puzzles.json +28 -33
  9. package/lib/packlets/common/common.d.ts +15 -0
  10. package/lib/packlets/common/common.js +25 -0
  11. package/lib/packlets/common/converters.d.ts +0 -6
  12. package/lib/packlets/common/converters.js +17 -22
  13. package/lib/packlets/common/ids.d.ts +8 -1
  14. package/lib/packlets/common/ids.js +83 -10
  15. package/lib/packlets/common/index.d.ts +3 -2
  16. package/lib/packlets/common/index.js +5 -2
  17. package/lib/packlets/common/logging.d.ts +7 -0
  18. package/lib/packlets/common/logging.js +35 -0
  19. package/lib/packlets/common/puzzle.d.ts +23 -13
  20. package/lib/packlets/common/puzzle.js +51 -25
  21. package/lib/packlets/common/puzzleDefinitions.d.ts +127 -0
  22. package/lib/packlets/common/puzzleDefinitions.js +251 -0
  23. package/lib/packlets/common/puzzleSession.d.ts +8 -0
  24. package/lib/packlets/common/puzzleSession.js +12 -0
  25. package/lib/packlets/common/puzzleState.js +3 -0
  26. package/lib/packlets/files/converters.d.ts +27 -0
  27. package/lib/packlets/files/converters.js +71 -0
  28. package/lib/packlets/{file/converters.d.ts → files/filesystem.d.ts} +3 -8
  29. package/lib/packlets/{file/converters.js → files/filesystem.js} +5 -14
  30. package/lib/packlets/files/index.d.ts +5 -0
  31. package/lib/packlets/{file → files}/index.js +3 -1
  32. package/lib/packlets/files/model.d.ts +32 -0
  33. package/lib/packlets/hints/baseHintProvider.d.ts +103 -0
  34. package/lib/packlets/hints/baseHintProvider.js +203 -0
  35. package/lib/packlets/hints/explanations.d.ts +105 -0
  36. package/lib/packlets/hints/explanations.js +276 -0
  37. package/lib/packlets/hints/hiddenSingles.d.ts +81 -0
  38. package/lib/packlets/hints/hiddenSingles.js +237 -0
  39. package/lib/packlets/hints/hintRegistry.d.ts +95 -0
  40. package/lib/packlets/hints/hintRegistry.js +226 -0
  41. package/lib/packlets/hints/hints.d.ts +144 -0
  42. package/lib/packlets/hints/hints.js +316 -0
  43. package/lib/packlets/hints/index.d.ts +10 -0
  44. package/lib/packlets/hints/index.js +55 -0
  45. package/lib/packlets/hints/interfaces.d.ts +121 -0
  46. package/lib/packlets/{file/model.js → hints/interfaces.js} +1 -1
  47. package/lib/packlets/hints/nakedSingles.d.ts +57 -0
  48. package/lib/packlets/hints/nakedSingles.js +202 -0
  49. package/lib/packlets/hints/puzzleSessionHints.d.ts +306 -0
  50. package/lib/packlets/hints/puzzleSessionHints.js +499 -0
  51. package/lib/packlets/hints/types.d.ts +102 -0
  52. package/lib/packlets/hints/types.js +46 -0
  53. package/lib/packlets/puzzles/anyPuzzle.d.ts +3 -3
  54. package/lib/packlets/puzzles/anyPuzzle.js +1 -1
  55. package/lib/packlets/puzzles/index.d.ts +4 -2
  56. package/lib/packlets/puzzles/index.js +20 -3
  57. package/lib/packlets/puzzles/internal/combinationCache.d.ts +29 -0
  58. package/lib/packlets/puzzles/internal/combinationCache.js +79 -0
  59. package/lib/packlets/puzzles/internal/combinationGenerator.d.ts +34 -0
  60. package/lib/packlets/puzzles/internal/combinationGenerator.js +146 -0
  61. package/lib/packlets/puzzles/internal/possibilityAnalyzer.d.ts +25 -0
  62. package/lib/packlets/puzzles/internal/possibilityAnalyzer.js +125 -0
  63. package/lib/packlets/puzzles/killerCombinations.d.ts +90 -0
  64. package/lib/packlets/puzzles/killerCombinations.js +226 -0
  65. package/lib/packlets/puzzles/killerCombinationsTypes.d.ts +17 -0
  66. package/lib/packlets/puzzles/killerCombinationsTypes.js +26 -0
  67. package/lib/packlets/puzzles/killerSudokuPuzzle.d.ts +2 -2
  68. package/lib/packlets/puzzles/killerSudokuPuzzle.js +15 -11
  69. package/lib/packlets/puzzles/sudokuPuzzle.d.ts +2 -2
  70. package/lib/packlets/puzzles/sudokuXPuzzle.d.ts +2 -2
  71. package/lib/packlets/puzzles/sudokuXPuzzle.js +8 -4
  72. package/package.json +5 -5
  73. package/sample-12x12-puzzle.js +72 -0
  74. package/sample-4x4-puzzles.js +68 -0
  75. package/sample-6x6-puzzle.js +61 -0
  76. package/temp_12x12_cells.txt +12 -0
  77. package/temp_correct.txt +12 -0
  78. package/test-grid-sizes.js +132 -0
  79. package/lib/packlets/common/model.d.ts +0 -15
  80. package/lib/packlets/file/index.d.ts +0 -4
  81. package/lib/packlets/file/model.d.ts +0 -9
  82. /package/lib/packlets/{common → files}/model.js +0 -0
@@ -22,14 +22,31 @@
22
22
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
23
  * SOFTWARE.
24
24
  */
25
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ var desc = Object.getOwnPropertyDescriptor(m, k);
28
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
29
+ desc = { enumerable: true, get: function() { return m[k]; } };
30
+ }
31
+ Object.defineProperty(o, k2, desc);
32
+ }) : (function(o, m, k, k2) {
33
+ if (k2 === undefined) k2 = k;
34
+ o[k2] = m[k];
35
+ }));
36
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
37
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
38
+ };
25
39
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.SudokuX = exports.Sudoku = exports.Killer = exports.Any = void 0;
27
- const anyPuzzle_1 = require("./anyPuzzle");
28
- Object.defineProperty(exports, "Any", { enumerable: true, get: function () { return anyPuzzle_1.AnyPuzzle; } });
40
+ exports.SudokuX = exports.Sudoku = exports.KillerCombinations = exports.Killer = exports.Any = void 0;
29
41
  const killerSudokuPuzzle_1 = require("./killerSudokuPuzzle");
30
42
  Object.defineProperty(exports, "Killer", { enumerable: true, get: function () { return killerSudokuPuzzle_1.KillerSudokuPuzzle; } });
31
43
  const sudokuPuzzle_1 = require("./sudokuPuzzle");
32
44
  Object.defineProperty(exports, "Sudoku", { enumerable: true, get: function () { return sudokuPuzzle_1.SudokuPuzzle; } });
33
45
  const sudokuXPuzzle_1 = require("./sudokuXPuzzle");
34
46
  Object.defineProperty(exports, "SudokuX", { enumerable: true, get: function () { return sudokuXPuzzle_1.SudokuXPuzzle; } });
47
+ const killerCombinations_1 = require("./killerCombinations");
48
+ Object.defineProperty(exports, "KillerCombinations", { enumerable: true, get: function () { return killerCombinations_1.KillerCombinations; } });
49
+ const anyPuzzle_1 = require("./anyPuzzle");
50
+ Object.defineProperty(exports, "Any", { enumerable: true, get: function () { return anyPuzzle_1.AnyPuzzle; } });
51
+ __exportStar(require("./killerCombinationsTypes"), exports);
35
52
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,29 @@
1
+ import { IKillerConstraints } from '../killerCombinationsTypes';
2
+ /**
3
+ * @internal
4
+ */
5
+ export declare class CombinationCache {
6
+ private static readonly _cache;
7
+ private static readonly _maxCacheSize;
8
+ /**
9
+ * Generate cache key for combination parameters.
10
+ */
11
+ static generateKey(cageSize: number, total: number, constraints?: IKillerConstraints): string;
12
+ /**
13
+ * Get cached combination result.
14
+ */
15
+ static get(key: string): number[][] | undefined;
16
+ /**
17
+ * Store combination result in cache.
18
+ */
19
+ static set(key: string, combinations: number[][]): void;
20
+ /**
21
+ * Clear the entire cache.
22
+ */
23
+ static clear(): void;
24
+ /**
25
+ * Get current cache size (for testing/debugging).
26
+ */
27
+ static size(): number;
28
+ }
29
+ //# sourceMappingURL=combinationCache.d.ts.map
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /*
3
+ * MIT License
4
+ *
5
+ * Copyright (c) 2023 Erik Fortune
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in all
15
+ * copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ * SOFTWARE.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.CombinationCache = void 0;
27
+ /**
28
+ * @internal
29
+ */
30
+ class CombinationCache {
31
+ /**
32
+ * Generate cache key for combination parameters.
33
+ */
34
+ static generateKey(cageSize, total, constraints) {
35
+ var _a, _b, _c, _d;
36
+ const excluded = (_b = (_a = constraints === null || constraints === void 0 ? void 0 : constraints.excludedNumbers) === null || _a === void 0 ? void 0 : _a.slice().sort().join(',')) !== null && _b !== void 0 ? _b : '';
37
+ const required = (_d = (_c = constraints === null || constraints === void 0 ? void 0 : constraints.requiredNumbers) === null || _c === void 0 ? void 0 : _c.slice().sort().join(',')) !== null && _d !== void 0 ? _d : '';
38
+ return `${cageSize}:${total}:${excluded}:${required}`;
39
+ }
40
+ /**
41
+ * Get cached combination result.
42
+ */
43
+ static get(key) {
44
+ const result = this._cache.get(key);
45
+ if (result) {
46
+ // Deep clone to prevent mutation of cached data
47
+ return result.map((combination) => [...combination]);
48
+ }
49
+ return undefined;
50
+ }
51
+ /**
52
+ * Store combination result in cache.
53
+ */
54
+ static set(key, combinations) {
55
+ // Implement simple LRU by clearing cache when it gets too large
56
+ if (this._cache.size >= this._maxCacheSize) {
57
+ this.clear();
58
+ }
59
+ // Deep clone to prevent mutation of cached data
60
+ const clonedCombinations = combinations.map((combination) => [...combination]);
61
+ this._cache.set(key, clonedCombinations);
62
+ }
63
+ /**
64
+ * Clear the entire cache.
65
+ */
66
+ static clear() {
67
+ this._cache.clear();
68
+ }
69
+ /**
70
+ * Get current cache size (for testing/debugging).
71
+ */
72
+ static size() {
73
+ return this._cache.size;
74
+ }
75
+ }
76
+ exports.CombinationCache = CombinationCache;
77
+ CombinationCache._cache = new Map();
78
+ CombinationCache._maxCacheSize = 1000;
79
+ //# sourceMappingURL=combinationCache.js.map
@@ -0,0 +1,34 @@
1
+ import { IKillerConstraints } from '../killerCombinationsTypes';
2
+ /**
3
+ * @internal
4
+ */
5
+ export declare class CombinationGenerator {
6
+ /**
7
+ * Generates all possible combinations of unique numbers that sum to the target total.
8
+ * @param cageSize - Number of cells in the cage
9
+ * @param total - Target sum
10
+ * @param constraints - Optional constraints on included/excluded numbers
11
+ * @param maxValue - Maximum value allowed in cells (defaults to 9)
12
+ * @returns Array of combinations, each sorted in ascending order
13
+ */
14
+ static generate(cageSize: number, total: number, constraints?: IKillerConstraints, maxValue?: number): number[][];
15
+ /**
16
+ * Recursive helper to generate combinations.
17
+ * @param availableNumbers - Numbers that can be used
18
+ * @param targetSize - Number of numbers needed
19
+ * @param targetSum - Target sum for the combination
20
+ * @param startIndex - Starting index in available numbers
21
+ * @param currentCombination - Current partial combination
22
+ * @param results - Array to collect results
23
+ */
24
+ private static _generateCombinations;
25
+ /**
26
+ * Calculate minimum possible sum for remaining slots.
27
+ */
28
+ private static _calculateMinSum;
29
+ /**
30
+ * Calculate maximum possible sum for remaining slots.
31
+ */
32
+ private static _calculateMaxSum;
33
+ }
34
+ //# sourceMappingURL=combinationGenerator.d.ts.map
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ /*
3
+ * MIT License
4
+ *
5
+ * Copyright (c) 2023 Erik Fortune
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in all
15
+ * copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ * SOFTWARE.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.CombinationGenerator = void 0;
27
+ /**
28
+ * @internal
29
+ */
30
+ class CombinationGenerator {
31
+ /**
32
+ * Generates all possible combinations of unique numbers that sum to the target total.
33
+ * @param cageSize - Number of cells in the cage
34
+ * @param total - Target sum
35
+ * @param constraints - Optional constraints on included/excluded numbers
36
+ * @param maxValue - Maximum value allowed in cells (defaults to 9)
37
+ * @returns Array of combinations, each sorted in ascending order
38
+ */
39
+ static generate(cageSize, total, constraints, maxValue = 9) {
40
+ var _a, _b;
41
+ const results = [];
42
+ const excludedSet = new Set((_a = constraints === null || constraints === void 0 ? void 0 : constraints.excludedNumbers) !== null && _a !== void 0 ? _a : []);
43
+ const requiredNumbers = (_b = constraints === null || constraints === void 0 ? void 0 : constraints.requiredNumbers) !== null && _b !== void 0 ? _b : [];
44
+ const requiredSet = new Set(requiredNumbers);
45
+ // Validate that we can satisfy required numbers constraint
46
+ if (requiredNumbers.length > cageSize) {
47
+ return [];
48
+ }
49
+ // Check if required numbers sum is already too high
50
+ const requiredSum = requiredNumbers.reduce((sum, num) => sum + num, 0);
51
+ if (requiredSum > total) {
52
+ return [];
53
+ }
54
+ // Calculate remaining constraints after accounting for required numbers
55
+ const remainingSize = cageSize - requiredNumbers.length;
56
+ const remainingTotal = total - requiredSum;
57
+ if (remainingSize === 0) {
58
+ // Only required numbers should be present
59
+ /* c8 ignore next 3 - edge case: required numbers fill cage but sum doesn't match (tested via KillerCombinations) */
60
+ if (remainingTotal === 0) {
61
+ return [Array.from(requiredNumbers).sort()];
62
+ }
63
+ return [];
64
+ }
65
+ // Generate combinations for the remaining slots
66
+ const availableNumbers = [];
67
+ for (let i = 1; i <= maxValue; i++) {
68
+ if (!excludedSet.has(i) && !requiredSet.has(i)) {
69
+ availableNumbers.push(i);
70
+ }
71
+ }
72
+ this._generateCombinations(availableNumbers, remainingSize, remainingTotal, 0, [], results);
73
+ // Add required numbers to each result and sort
74
+ return results.map((combination) => [...combination, ...requiredNumbers].sort((a, b) => a - b));
75
+ }
76
+ /**
77
+ * Recursive helper to generate combinations.
78
+ * @param availableNumbers - Numbers that can be used
79
+ * @param targetSize - Number of numbers needed
80
+ * @param targetSum - Target sum for the combination
81
+ * @param startIndex - Starting index in available numbers
82
+ * @param currentCombination - Current partial combination
83
+ * @param results - Array to collect results
84
+ */
85
+ static _generateCombinations(availableNumbers, targetSize, targetSum, startIndex, currentCombination, results) {
86
+ // Base case: we have the right number of elements
87
+ if (currentCombination.length === targetSize) {
88
+ const sum = currentCombination.reduce((total, num) => total + num, 0);
89
+ if (sum === targetSum) {
90
+ results.push([...currentCombination]);
91
+ }
92
+ return;
93
+ }
94
+ // Early termination: impossible to reach target
95
+ const remainingSlots = targetSize - currentCombination.length;
96
+ const currentSum = currentCombination.reduce((total, num) => total + num, 0);
97
+ const remainingSum = targetSum - currentSum;
98
+ // Check minimum possible sum with remaining slots
99
+ const minPossible = this._calculateMinSum(availableNumbers, startIndex, remainingSlots);
100
+ if (remainingSum < minPossible) {
101
+ return;
102
+ }
103
+ // Check maximum possible sum with remaining slots
104
+ const maxPossible = this._calculateMaxSum(availableNumbers, startIndex, remainingSlots);
105
+ if (remainingSum > maxPossible) {
106
+ return;
107
+ }
108
+ // Try each available number
109
+ for (let i = startIndex; i < availableNumbers.length; i++) {
110
+ const number = availableNumbers[i];
111
+ // Skip if adding this number would exceed our target
112
+ if (currentSum + number > targetSum) {
113
+ continue;
114
+ }
115
+ currentCombination.push(number);
116
+ this._generateCombinations(availableNumbers, targetSize, targetSum, i + 1, currentCombination, results);
117
+ currentCombination.pop();
118
+ }
119
+ }
120
+ /**
121
+ * Calculate minimum possible sum for remaining slots.
122
+ */
123
+ static _calculateMinSum(availableNumbers, startIndex, remainingSlots) {
124
+ let sum = 0;
125
+ let count = 0;
126
+ for (let i = startIndex; i < availableNumbers.length && count < remainingSlots; i++) {
127
+ sum += availableNumbers[i];
128
+ count++;
129
+ }
130
+ return sum;
131
+ }
132
+ /**
133
+ * Calculate maximum possible sum for remaining slots.
134
+ */
135
+ static _calculateMaxSum(availableNumbers, startIndex, remainingSlots) {
136
+ let sum = 0;
137
+ let count = 0;
138
+ for (let i = availableNumbers.length - 1; i >= startIndex && count < remainingSlots; i--) {
139
+ sum += availableNumbers[i];
140
+ count++;
141
+ }
142
+ return sum;
143
+ }
144
+ }
145
+ exports.CombinationGenerator = CombinationGenerator;
146
+ //# sourceMappingURL=combinationGenerator.js.map
@@ -0,0 +1,25 @@
1
+ import { Result } from '@fgv/ts-utils';
2
+ import { CellId, ICage, Puzzle, PuzzleState } from '../../common';
3
+ /**
4
+ * @internal
5
+ */
6
+ export declare class PossibilityAnalyzer {
7
+ /**
8
+ * Analyze possible values for each cell in a killer cage based on current puzzle state.
9
+ * @param puzzle - The puzzle instance
10
+ * @param state - Current puzzle state
11
+ * @param cage - The killer cage to analyze
12
+ * @param validCombinations - Pre-computed valid combinations for the cage
13
+ * @returns Map of CellId to possible number arrays
14
+ */
15
+ static analyze(puzzle: Puzzle, state: PuzzleState, cage: ICage, validCombinations: number[][]): Result<Map<CellId, number[]>>;
16
+ /**
17
+ * Check if a value can be placed in a cell considering sudoku constraints.
18
+ * @param cell - The cell to check
19
+ * @param value - The value to place
20
+ * @param state - Current puzzle state
21
+ * @returns True if the value can be placed
22
+ */
23
+ private static _canPlaceValueInCell;
24
+ }
25
+ //# sourceMappingURL=possibilityAnalyzer.d.ts.map
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /*
3
+ * MIT License
4
+ *
5
+ * Copyright (c) 2023 Erik Fortune
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in all
15
+ * copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ * SOFTWARE.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.PossibilityAnalyzer = void 0;
27
+ const ts_utils_1 = require("@fgv/ts-utils");
28
+ /**
29
+ * @internal
30
+ */
31
+ class PossibilityAnalyzer {
32
+ /**
33
+ * Analyze possible values for each cell in a killer cage based on current puzzle state.
34
+ * @param puzzle - The puzzle instance
35
+ * @param state - Current puzzle state
36
+ * @param cage - The killer cage to analyze
37
+ * @param validCombinations - Pre-computed valid combinations for the cage
38
+ * @returns Map of CellId to possible number arrays
39
+ */
40
+ static analyze(puzzle, state, cage, validCombinations) {
41
+ const possibilities = new Map();
42
+ // Get current values in the cage
43
+ // We need the concrete Cage class for containedValues method
44
+ const concreteCage = cage;
45
+ const currentValues = concreteCage.containedValues(state);
46
+ const emptyCells = [];
47
+ // Identify empty cells and initialize possibilities
48
+ for (const cellId of cage.cellIds) {
49
+ const cellContents = state.getCellContents(cellId).orDefault();
50
+ /* c8 ignore next 1 - ? is defense in depth */
51
+ if ((cellContents === null || cellContents === void 0 ? void 0 : cellContents.value) !== undefined) {
52
+ // Cell already has a value - set empty possibilities array
53
+ possibilities.set(cellId, []);
54
+ }
55
+ else {
56
+ // Empty cell
57
+ emptyCells.push(cellId);
58
+ possibilities.set(cellId, []);
59
+ }
60
+ }
61
+ // Filter combinations that are compatible with current state
62
+ const compatibleCombinations = validCombinations.filter((combination) => {
63
+ // Check if combination contains all current values
64
+ for (const currentValue of currentValues) {
65
+ if (!combination.includes(currentValue)) {
66
+ return false;
67
+ }
68
+ }
69
+ // Check if combination has the right number of remaining values
70
+ const remainingValues = combination.filter((value) => !currentValues.has(value));
71
+ return remainingValues.length === emptyCells.length;
72
+ });
73
+ // If no compatible combinations exist, return empty possibilities for all cells
74
+ if (compatibleCombinations.length === 0) {
75
+ return (0, ts_utils_1.succeed)(possibilities);
76
+ }
77
+ // For each empty cell, find which values are possible
78
+ for (const cellId of emptyCells) {
79
+ const cellPossibilities = new Set();
80
+ // Get the cell to check sudoku constraints
81
+ const cellResult = puzzle.getCell(cellId);
82
+ /* c8 ignore next 3 - defensive coding: protects against internal cage/puzzle state corruption */
83
+ if (cellResult.isFailure()) {
84
+ continue;
85
+ }
86
+ const cell = cellResult.value;
87
+ // Check each compatible combination
88
+ for (const combination of compatibleCombinations) {
89
+ const remainingValues = combination.filter((value) => !currentValues.has(value));
90
+ // Check if each remaining value could go in this cell
91
+ for (const value of remainingValues) {
92
+ if (this._canPlaceValueInCell(cell, value, state)) {
93
+ cellPossibilities.add(value);
94
+ }
95
+ }
96
+ }
97
+ possibilities.set(cellId, Array.from(cellPossibilities).sort());
98
+ }
99
+ return (0, ts_utils_1.succeed)(possibilities);
100
+ }
101
+ /**
102
+ * Check if a value can be placed in a cell considering sudoku constraints.
103
+ * @param cell - The cell to check
104
+ * @param value - The value to place
105
+ * @param state - Current puzzle state
106
+ * @returns True if the value can be placed
107
+ */
108
+ static _canPlaceValueInCell(cell, value, state) {
109
+ // Check all cages this cell belongs to for sudoku constraints
110
+ for (const cage of cell.cages) {
111
+ if (cage.cageType === 'killer') {
112
+ // Skip killer cage check - we're already analyzing within killer constraints
113
+ continue;
114
+ }
115
+ // Check if value already exists in this constraint cage (row, column, section, etc.)
116
+ const concreteCage = cage;
117
+ if (concreteCage.containsValue(value, state, [cell.id])) {
118
+ return false;
119
+ }
120
+ }
121
+ return true;
122
+ }
123
+ }
124
+ exports.PossibilityAnalyzer = PossibilityAnalyzer;
125
+ //# sourceMappingURL=possibilityAnalyzer.js.map
@@ -0,0 +1,90 @@
1
+ import { Result } from '@fgv/ts-utils';
2
+ import { CellId, ICage, Puzzle, PuzzleState } from '../common';
3
+ import { IKillerConstraints } from './killerCombinationsTypes';
4
+ /**
5
+ * Helper class providing UI assistance functions for killer sudoku puzzle solving.
6
+ * Generates possible totals, number combinations with constraints, and cell-specific
7
+ * possibilities based on current puzzle state.
8
+ * @public
9
+ */
10
+ export declare class KillerCombinations {
11
+ /**
12
+ * Gets all mathematically possible totals for a given cage size.
13
+ *
14
+ * Uses the existing totalsByCageSize constant to determine the valid range
15
+ * of totals for the specified cage size and returns all integers in that range.
16
+ *
17
+ * @param cageSize - The number of cells in the cage (must be 1-9)
18
+ * @returns Result containing array of possible totals in ascending order
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * // Get possible totals for a 3-cell cage
23
+ * const result = KillerCombinations.getPossibleTotals(3);
24
+ * if (result.isSuccess()) {
25
+ * console.log(result.value); // [6, 7, 8, 9, ..., 24]
26
+ * }
27
+ * ```
28
+ */
29
+ static getPossibleTotals(cageSize: number, maxValue?: number): Result<number[]>;
30
+ /**
31
+ * Generates all possible number combinations that sum to the target total.
32
+ *
33
+ * Each combination contains unique numbers from 1-9 that sum exactly to the
34
+ * specified total. Combinations respect both excluded and required number
35
+ * constraints if provided.
36
+ *
37
+ * @param cageSize - The number of cells in the cage (must be 1-9)
38
+ * @param total - The target sum (must be valid for the cage size)
39
+ * @param constraints - Optional constraints on included/excluded numbers
40
+ * @returns Result containing array of combinations, each sorted in ascending order
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * // Get all combinations for a 3-cell cage with total 15
45
+ * const result = KillerCombinations.getCombinations(3, 15);
46
+ * if (result.isSuccess()) {
47
+ * console.log(result.value); // [[1,5,9], [1,6,8], [2,4,9], ...]
48
+ * }
49
+ *
50
+ * // With constraints - exclude 1 and 2, require 9
51
+ * const constrained = KillerCombinations.getCombinations(3, 15, {
52
+ * excludedNumbers: [1, 2],
53
+ * requiredNumbers: [9]
54
+ * });
55
+ * ```
56
+ */
57
+ static getCombinations(cageSize: number, total: number, constraints?: IKillerConstraints, maxValue?: number): Result<number[][]>;
58
+ /**
59
+ * Determines possible values for each cell in a killer cage based on current puzzle state.
60
+ *
61
+ * Analyzes the current state of the puzzle and cage to determine which values
62
+ * are possible for each empty cell, considering both killer cage constraints
63
+ * and standard sudoku constraints (row, column, section uniqueness).
64
+ *
65
+ * @param puzzle - The puzzle instance
66
+ * @param state - Current puzzle state
67
+ * @param cage - The killer cage to analyze (must be of type 'killer')
68
+ * @returns Result containing map of CellId to possible number arrays
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const cage = puzzle.getCage(cageId).orThrow();
73
+ * const possibilities = KillerCombinations.getCellPossibilities(puzzle, state, cage);
74
+ * if (possibilities.isSuccess()) {
75
+ * for (const [cellId, values] of possibilities.value) {
76
+ * console.log(`Cell ${cellId} can have values: ${values.join(', ')}`);
77
+ * }
78
+ * }
79
+ * ```
80
+ */
81
+ static getCellPossibilities(puzzle: Puzzle, state: PuzzleState, cage: ICage): Result<Map<CellId, number[]>>;
82
+ /**
83
+ * Validate constraint parameters.
84
+ * @param constraints - Constraints to validate
85
+ * @param maxValue - Maximum value allowed in cells
86
+ * @returns Result indicating success or failure with error message
87
+ */
88
+ private static _validateConstraints;
89
+ }
90
+ //# sourceMappingURL=killerCombinations.d.ts.map