logic-puzzle-generator 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +221 -0
- package/dist/Clue.d.ts +81 -0
- package/dist/Clue.js +37 -0
- package/dist/Generator.d.ts +58 -0
- package/dist/Generator.js +433 -0
- package/dist/LogicGrid.d.ts +70 -0
- package/dist/LogicGrid.js +188 -0
- package/dist/Solver.d.ts +29 -0
- package/dist/Solver.js +242 -0
- package/dist/examples/benchmark.d.ts +1 -0
- package/dist/examples/benchmark.js +129 -0
- package/dist/examples/cli.d.ts +1 -0
- package/dist/examples/cli.js +84 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +21 -0
- package/dist/run_generator.d.ts +1 -0
- package/dist/run_generator.js +84 -0
- package/dist/src/defaults.d.ts +5 -0
- package/dist/src/defaults.js +24 -0
- package/dist/src/engine/BoundsCalculator.d.ts +6 -0
- package/dist/src/engine/BoundsCalculator.js +40 -0
- package/dist/src/engine/Clue.d.ts +75 -0
- package/dist/src/engine/Clue.js +10 -0
- package/dist/src/engine/DifficultyBounds.d.ts +12 -0
- package/dist/src/engine/DifficultyBounds.js +67 -0
- package/dist/src/engine/GenerativeSession.d.ts +32 -0
- package/dist/src/engine/GenerativeSession.js +109 -0
- package/dist/src/engine/Generator.d.ts +119 -0
- package/dist/src/engine/Generator.js +1058 -0
- package/dist/src/engine/LogicGrid.d.ts +70 -0
- package/dist/src/engine/LogicGrid.js +190 -0
- package/dist/src/engine/Solver.d.ts +30 -0
- package/dist/src/engine/Solver.js +613 -0
- package/dist/src/errors.d.ts +12 -0
- package/dist/src/errors.js +23 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.js +24 -0
- package/dist/src/scripts/GenerateBoundsDeprecated.d.ts +1 -0
- package/dist/src/scripts/GenerateBoundsDeprecated.js +27 -0
- package/dist/src/scripts/StressTestBacktracking.d.ts +1 -0
- package/dist/src/scripts/StressTestBacktracking.js +49 -0
- package/dist/src/types.d.ts +86 -0
- package/dist/src/types.js +58 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.js +13 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Logic Puzzle Generator
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
A TypeScript library for generating, solving, and verifying "Zebra Puzzle" style logic grid puzzles.
|
|
10
|
+
|
|
11
|
+
Unlike standard generators, this library creates **goal-oriented puzzles**: you can specify a "Target Fact" (e.g., "What snack does David eat?") that will be the final deduction required to complete the puzzle. The generator ensures a step-by-step logical path exists to reach this conclusion when facts are presented in a specific order.
|
|
12
|
+
|
|
13
|
+
The intention is for this library to empower narrative designers to create mysteries that are both solvable and engaging.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **Goal-Oriented Generation**: Targeted generation ensures the puzzle builds towards a specific revelation. (Note: A target is naturally selected if none is provided, ensuring every puzzle behaves as a coherent mystery.)
|
|
18
|
+
- **Rich Clue Types**:
|
|
19
|
+
- **Binary**: IS / IS NOT
|
|
20
|
+
- **Ordinal**: Older/Younger + Negative (Not Before/After)
|
|
21
|
+
- **Cross-Ordinal**: Transitive relationships across different ordinal axes + Negated (Match/Not Match).
|
|
22
|
+
- **Superlative**: Extremes (Oldest/Youngest) + Negative (Not Oldest).
|
|
23
|
+
- **Unary**: Properties (Even/Odd). Requires at least one ordinal category that contains a mix of both odd and even numeric values.
|
|
24
|
+
- **Complexity Variance**: The generator intelligently varies clue complexity to create a balanced puzzle flow.
|
|
25
|
+
- **Clue Constraints**: Filter which clue types are allowed (e.g., disable Ordinal clues) for custom difficulty.
|
|
26
|
+
- **Proof Chain**: Generates a full step-by-step solution path ("Proof Chain").
|
|
27
|
+
- **Type-Safe**: Written in TypeScript with comprehensive type definitions.
|
|
28
|
+
- **Configurable**: Define your own categories, values, and constraints.
|
|
29
|
+
- **Reproducible**: Seed-based RNG ensures deterministic results. The seed controls:
|
|
30
|
+
- **Solution Generation**: The underlying logic grid truth.
|
|
31
|
+
- **Target Selection**: Which fact serves as the mystery focus.
|
|
32
|
+
- **Clue Template Variation**: Randomization of names, values, and sentence structures.
|
|
33
|
+
- **Search & Scoring**: The order in which candidates are evaluated.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install logic-puzzle-generator
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
Here's how to generate a simple puzzle where you want to find out what "David" is eating.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { Generator, CategoryType, Puzzle } from 'logic-puzzle-generator';
|
|
47
|
+
|
|
48
|
+
// 1. Define your categories
|
|
49
|
+
const categories = [
|
|
50
|
+
{ id: 'Name', type: CategoryType.NOMINAL, values: ['Alice', 'Bob', 'David'] },
|
|
51
|
+
{ id: 'Snack', type: CategoryType.NOMINAL, values: ['Chips', 'Popcorn', 'Candy'] },
|
|
52
|
+
{ id: 'Age', type: CategoryType.ORDINAL, values: [20, 30, 40] }, // Ordinal allows for 'older/younger' clues
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
// 2. Define the target fact (The "Goal" of the puzzle)
|
|
56
|
+
// We want the solver to deduce that 'Name: David' is linked to a specific value in 'Snack'.
|
|
57
|
+
// Note: If you omit this, the generator will pick a random mystery for you.
|
|
58
|
+
const targetFact = {
|
|
59
|
+
category1Id: 'Name',
|
|
60
|
+
value1: 'David',
|
|
61
|
+
category2Id: 'Snack',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// 3. Generate the puzzle
|
|
65
|
+
const generator = new Generator(12345); // Seed controls solution generation, target selection, and clue variation.
|
|
66
|
+
const puzzle: Puzzle = generator.generatePuzzle(categories, targetFact);
|
|
67
|
+
|
|
68
|
+
// 4. View the results
|
|
69
|
+
console.log('The Clues:');
|
|
70
|
+
puzzle.clues.forEach((clue, i) => console.log(`${i + 1}.`, clue));
|
|
71
|
+
|
|
72
|
+
// 5. Inspect the Logic
|
|
73
|
+
console.log('\nThe Solution Path:');
|
|
74
|
+
console.log(JSON.stringify(puzzle.proofChain[0], null, 2));
|
|
75
|
+
// Example Output:
|
|
76
|
+
// {
|
|
77
|
+
// "clue": { "type": "binary", "cat1": "Name", "val1": "Alice", "cat2": "Snack", "val2": "Popcorn", "operator": "is" },
|
|
78
|
+
// "deductions": 2
|
|
79
|
+
// }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Core Concepts
|
|
83
|
+
|
|
84
|
+
### Categories
|
|
85
|
+
- **Nominal**: Categories where order doesn't matter (e.g., Names, Colors, Snacks).
|
|
86
|
+
- **Ordinal**: Categories that have an inherent order (e.g., Age, Price, Floor Number). These unlock special clues like "The person eating Chips is older than Alice".
|
|
87
|
+
> **Note**: Ordinal values must be numbers. ConfigurationError will be thrown if strings are provided.
|
|
88
|
+
|
|
89
|
+
## Configuration
|
|
90
|
+
|
|
91
|
+
The `generatePuzzle` method takes an array of `CategoryConfig` objects.
|
|
92
|
+
|
|
93
|
+
| Field | Type | Description |
|
|
94
|
+
| :--- | :--- | :--- |
|
|
95
|
+
| `id` | `string` | Unique identifier for the category (e.g., "Color"). |
|
|
96
|
+
| `type` | `CategoryType` | `NOMINAL` (unordered) or `ORDINAL` (ordered integers). |
|
|
97
|
+
| `values` | `(string\|number)[]` | Array of possible values. Must be unique. If `ORDINAL`, must be sorted numbers. |
|
|
98
|
+
|
|
99
|
+
### Error Handling
|
|
100
|
+
|
|
101
|
+
The library provides strict validation. A `ConfigurationError` is thrown in the following scenarios:
|
|
102
|
+
1. **Invalid Ordinals**: Providing non-numeric values for a category marked as `ORDINAL`.
|
|
103
|
+
2. **Duplicate Values**: Categories contain duplicate value entries.
|
|
104
|
+
3. **Invalid Target**: The requested `Target Fact` refers to a category or value that does not exist.
|
|
105
|
+
4. **Impossible Constraints**: A custom constraint or seed results in immediate contradiction.
|
|
106
|
+
5. **Ambiguous Constraints**: Providing *only* "Weak" clue types (`UNARY`, `SUPERLATIVE`) results in an unsolvable puzzle. The configuration must include at least one "Strong" type (`BINARY`, `ORDINAL`, or `CROSS_ORDINAL`) to uniquely resolve identities.
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { ConfigurationError } from 'logic-puzzle-generator';
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const puzzle = generator.generatePuzzle(invalidConfig, target);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
if (err instanceof ConfigurationError) {
|
|
115
|
+
console.error("Config Error:", err.message);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## How It Works
|
|
121
|
+
|
|
122
|
+
### The Algorithm
|
|
123
|
+
The generator uses a **Forward-Chaining Heuristic Search** to build the puzzle:
|
|
124
|
+
|
|
125
|
+
1. **Solution Seeding**: A valid, consistent solution grid is randomly generated based on the seed.
|
|
126
|
+
2. **Clue Generation**: Every possible true clue (Binary, Ordinal, etc.) is generated based on this solution.
|
|
127
|
+
3. **Heuristic Selection**: The solver iteratively selects the "best" clue to add to the puzzle. The "best" clue is determined by a scoring function that balances:
|
|
128
|
+
* **Synergy**: Does it lead to new deductions when combined with existing clues?
|
|
129
|
+
* **Completeness**: Does it help eliminate impossible options?
|
|
130
|
+
* **Complexity**: Is it an interesting clue type (e.g., `Superlative` > `Binary`)?
|
|
131
|
+
4. **Penalties**: To ensure variety, the score is penalized if:
|
|
132
|
+
* The clue refers to **Solution Groups** (specific entity combinations) that are already mentioned frequently.
|
|
133
|
+
* The clue type is repeated (preventing boring lists of "IS/IS NOT" clues).
|
|
134
|
+
* The clue is redundant (adds no new information).
|
|
135
|
+
5. **Termination**: The process repeats until the `Target Fact` is logically deducible from the selected clues alone.
|
|
136
|
+
|
|
137
|
+
## Performance & Scalability
|
|
138
|
+
|
|
139
|
+
The library is optimized for performance and uses heuristic sampling.
|
|
140
|
+
|
|
141
|
+
| Dimensions | Approx Time | Notes |
|
|
142
|
+
| :--- | :--- | :--- |
|
|
143
|
+
| **3 cats, 4 vals** | ~20ms | Instant generation. |
|
|
144
|
+
| **4 cats, 5 vals** | ~600ms | Standard logic puzzle size. |
|
|
145
|
+
| **5 cats, 5 vals** | ~3s | Large, complex grid. |
|
|
146
|
+
| **8 cats, 5 vals** | ~8s | Extreme. Use `maxCandidates: 50` for speed. |
|
|
147
|
+
|
|
148
|
+
### Large Puzzles
|
|
149
|
+
For puzzles with 6+ categories or high complexity, use the `maxCandidates` option in `generatePuzzle`. This limits the search space at each step (e.g. only check random 50 clues instead of 1000s) to keep generation fast while maintaining solvability.
|
|
150
|
+
|
|
151
|
+
### Controlling Clue Count
|
|
152
|
+
By default, the generator produces the most efficient puzzle it can find. To target a specific difficulty or length, you can request an exact number of clues.
|
|
153
|
+
|
|
154
|
+
1. **Estimate Feasibility**:
|
|
155
|
+
```typescript
|
|
156
|
+
const bounds = generator.getClueCountBounds(categories, target);
|
|
157
|
+
// -> { min: 4, max: 12 }
|
|
158
|
+
```
|
|
159
|
+
2. **Generate**:
|
|
160
|
+
```typescript
|
|
161
|
+
const puzzle = generator.generatePuzzle(categories, target, {
|
|
162
|
+
targetClueCount: 8, // Must be within feasible range
|
|
163
|
+
maxCandidates: 100,
|
|
164
|
+
timeoutMs: 180000 // Recommended: Give it time (3 mins) to find exact matches
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
> **Note**: This uses a **Hybrid Iterative Correction** algorithm. If the generator detects it is falling behind or solving too fast, it switches strategies (Stall vs Speed) and commits to them ("Sticky Strategy") to navigate complex search spaces. This ensures effective pathfinding for hard targets (e.g., 26 clues on 4x4).
|
|
169
|
+
|
|
170
|
+
### Clues
|
|
171
|
+
The generator produces four types of clues:
|
|
172
|
+
1. **Binary**: Direct relationships. "Alice eats Chips" or "Bob does NOT eat Popcorn".
|
|
173
|
+
2. **Ordinal**: Comparisons. "The person eating Chips is younger than Bob" or "Alice is NOT older than Charlie".
|
|
174
|
+
3. **Cross-Ordinal**: Complex relativity. "The item before Alice (Age) is the item after Bob (Cost)".
|
|
175
|
+
4. **Superlative**: Extremes. "Alice is the oldest" or "Bob is NOT the youngest".
|
|
176
|
+
5. **Unary**: Properties. "The person eating Chips is an even age".
|
|
177
|
+
|
|
178
|
+
### The Proof Chain
|
|
179
|
+
The generator solves the puzzle as it builds it. The `puzzle.proofChain` array contains the optimal order of clues to solve the grid. This is useful for building hint systems or verify difficulty.
|
|
180
|
+
|
|
181
|
+
## API Reference
|
|
182
|
+
|
|
183
|
+
### `Generator`
|
|
184
|
+
The main class. Use `new Generator(seed)` to initialize.
|
|
185
|
+
|
|
186
|
+
- `generatePuzzle(categories, target, options)`: Returns a `Puzzle` object.
|
|
187
|
+
- `options.targetClueCount`: Attempt to find exact solution length.
|
|
188
|
+
- `options.maxCandidates`: Performance tuning (default 50).
|
|
189
|
+
- `options.onTrace`: **(Debug)** Callback `(msg: string) => void`. Receives real-time logs about the generation process (e.g., "Backtracking", "Pruning", "Solution Found"). Useful for debugging timeouts or understanding the generator's decision making.
|
|
190
|
+
- `getClueCountBounds(categories, target)`: Returns plausible Min/Max clue counts.
|
|
191
|
+
- `startSession(categories, target?)`: [Beta] Starts a `GenerativeSession` for step-by-step interactive generation (useful for "Builder Mode" UIs).
|
|
192
|
+
|
|
193
|
+
### Extensibility
|
|
194
|
+
The `Generator` class is designed to be extensible. Key methods like `calculateClueScore` are `public`, allowing you to extend the class and inject custom heuristics.
|
|
195
|
+
|
|
196
|
+
### `LogicGrid`
|
|
197
|
+
Manages the state of the puzzle grid (possibility matrix).
|
|
198
|
+
- `isPossible(cat1, val1, cat2, val2)`: Returns true if a connection is possible.
|
|
199
|
+
- `setPossibility(...)`: Manually set states (useful for custom solvers).
|
|
200
|
+
|
|
201
|
+
### `Solver`
|
|
202
|
+
The logical engine.
|
|
203
|
+
- `applyClue(grid, clue)`: Applies a clue and cascades deductions.
|
|
204
|
+
|
|
205
|
+
## AI Disclosure & Liability Policy
|
|
206
|
+
|
|
207
|
+
### Transparency Statement
|
|
208
|
+
This project utilizes artificial intelligence (AI) tools to assist in the generation of code, logic algorithms, and documentation. While human oversight is rigorously applied, portions of the codebase are AI-generated.
|
|
209
|
+
|
|
210
|
+
### Copyright and Licensing
|
|
211
|
+
- **Human Contribution**: The project structure, architectural decisions, core logic verification, and test suites are human-authored and covered by the standard project license.
|
|
212
|
+
- **AI-Generated Content**: To the extent that AI-generated content is not eligible for copyright protection, it is dedicated to the public domain. Where copyrightable, it is licensed under the MIT license alongside human contributions.
|
|
213
|
+
|
|
214
|
+
### "AS IS" and Liability Waiver
|
|
215
|
+
This software is provided "AS IS", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.
|
|
216
|
+
|
|
217
|
+
### Accuracy Warning
|
|
218
|
+
While all code is reviewed and tested, complete accuracy cannot be guaranteed. Users are responsible for verifying that the puzzle generation logic meets the strict requirements of their specific use cases.
|
|
219
|
+
|
|
220
|
+
## License
|
|
221
|
+
MIT
|
package/dist/Clue.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { ValueLabel } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Enumeration of all supported clue types.
|
|
4
|
+
*/
|
|
5
|
+
export declare enum ClueType {
|
|
6
|
+
/** Expresses a direct relationship (IS or IS NOT) between two values. */
|
|
7
|
+
BINARY = 0,
|
|
8
|
+
/** Expresses a comparison (GREATER THAN or LESS THAN) between two values based on an ordinal category. */
|
|
9
|
+
ORDINAL = 1,
|
|
10
|
+
/** Expresses an extreme value relationship (MIN or MAX) within an ordinal category. */
|
|
11
|
+
SUPERLATIVE = 2,
|
|
12
|
+
/** Expresses a property of a single value (e.g., IS EVEN) relative to an ordinal category. */
|
|
13
|
+
UNARY = 3
|
|
14
|
+
}
|
|
15
|
+
export declare enum BinaryOperator {
|
|
16
|
+
IS = 0,
|
|
17
|
+
IS_NOT = 1
|
|
18
|
+
}
|
|
19
|
+
export declare enum OrdinalOperator {
|
|
20
|
+
GREATER_THAN = 0,
|
|
21
|
+
LESS_THAN = 1
|
|
22
|
+
}
|
|
23
|
+
export declare enum SuperlativeOperator {
|
|
24
|
+
MIN = 0,
|
|
25
|
+
MAX = 1
|
|
26
|
+
}
|
|
27
|
+
export declare enum UnaryFilter {
|
|
28
|
+
IS_ODD = 0,
|
|
29
|
+
IS_EVEN = 1
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A clue that establishes a direct link or separation between two specific values.
|
|
33
|
+
* Example: "Alice likes Horror movies." (IS)
|
|
34
|
+
* Example: "Bob does not like Comedy." (IS_NOT)
|
|
35
|
+
*/
|
|
36
|
+
export interface BinaryClue {
|
|
37
|
+
type: ClueType.BINARY;
|
|
38
|
+
operator: BinaryOperator;
|
|
39
|
+
cat1: string;
|
|
40
|
+
val1: ValueLabel;
|
|
41
|
+
cat2: string;
|
|
42
|
+
val2: ValueLabel;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A clue that compares two entities based on a third ordinal category.
|
|
46
|
+
* Example: "The person who likes Horror is older than Alice."
|
|
47
|
+
*/
|
|
48
|
+
export interface OrdinalClue {
|
|
49
|
+
type: ClueType.ORDINAL;
|
|
50
|
+
operator: OrdinalOperator;
|
|
51
|
+
item1Cat: string;
|
|
52
|
+
item1Val: ValueLabel;
|
|
53
|
+
item2Cat: string;
|
|
54
|
+
item2Val: ValueLabel;
|
|
55
|
+
/** The ordinal category used for comparison (e.g., "Age"). */
|
|
56
|
+
ordinalCat: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A clue that identifies an entity as having an extreme value in an ordinal category.
|
|
60
|
+
* Example: "The person who likes Popcorn is the oldest."
|
|
61
|
+
*/
|
|
62
|
+
export interface SuperlativeClue {
|
|
63
|
+
type: ClueType.SUPERLATIVE;
|
|
64
|
+
operator: SuperlativeOperator;
|
|
65
|
+
targetCat: string;
|
|
66
|
+
targetVal: ValueLabel;
|
|
67
|
+
/** The ordinal category (e.g., "Age") where the value is extreme. */
|
|
68
|
+
ordinalCat: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A clue that filters a value based on a property of its associated ordinal value.
|
|
72
|
+
* Example: "The person who likes Chips has an even age."
|
|
73
|
+
*/
|
|
74
|
+
export interface UnaryClue {
|
|
75
|
+
type: ClueType.UNARY;
|
|
76
|
+
filter: UnaryFilter;
|
|
77
|
+
targetCat: string;
|
|
78
|
+
targetVal: ValueLabel;
|
|
79
|
+
ordinalCat: string;
|
|
80
|
+
}
|
|
81
|
+
export type Clue = BinaryClue | OrdinalClue | SuperlativeClue | UnaryClue;
|
package/dist/Clue.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UnaryFilter = exports.SuperlativeOperator = exports.OrdinalOperator = exports.BinaryOperator = exports.ClueType = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Enumeration of all supported clue types.
|
|
6
|
+
*/
|
|
7
|
+
var ClueType;
|
|
8
|
+
(function (ClueType) {
|
|
9
|
+
/** Expresses a direct relationship (IS or IS NOT) between two values. */
|
|
10
|
+
ClueType[ClueType["BINARY"] = 0] = "BINARY";
|
|
11
|
+
/** Expresses a comparison (GREATER THAN or LESS THAN) between two values based on an ordinal category. */
|
|
12
|
+
ClueType[ClueType["ORDINAL"] = 1] = "ORDINAL";
|
|
13
|
+
/** Expresses an extreme value relationship (MIN or MAX) within an ordinal category. */
|
|
14
|
+
ClueType[ClueType["SUPERLATIVE"] = 2] = "SUPERLATIVE";
|
|
15
|
+
/** Expresses a property of a single value (e.g., IS EVEN) relative to an ordinal category. */
|
|
16
|
+
ClueType[ClueType["UNARY"] = 3] = "UNARY";
|
|
17
|
+
})(ClueType || (exports.ClueType = ClueType = {}));
|
|
18
|
+
var BinaryOperator;
|
|
19
|
+
(function (BinaryOperator) {
|
|
20
|
+
BinaryOperator[BinaryOperator["IS"] = 0] = "IS";
|
|
21
|
+
BinaryOperator[BinaryOperator["IS_NOT"] = 1] = "IS_NOT";
|
|
22
|
+
})(BinaryOperator || (exports.BinaryOperator = BinaryOperator = {}));
|
|
23
|
+
var OrdinalOperator;
|
|
24
|
+
(function (OrdinalOperator) {
|
|
25
|
+
OrdinalOperator[OrdinalOperator["GREATER_THAN"] = 0] = "GREATER_THAN";
|
|
26
|
+
OrdinalOperator[OrdinalOperator["LESS_THAN"] = 1] = "LESS_THAN";
|
|
27
|
+
})(OrdinalOperator || (exports.OrdinalOperator = OrdinalOperator = {}));
|
|
28
|
+
var SuperlativeOperator;
|
|
29
|
+
(function (SuperlativeOperator) {
|
|
30
|
+
SuperlativeOperator[SuperlativeOperator["MIN"] = 0] = "MIN";
|
|
31
|
+
SuperlativeOperator[SuperlativeOperator["MAX"] = 1] = "MAX";
|
|
32
|
+
})(SuperlativeOperator || (exports.SuperlativeOperator = SuperlativeOperator = {}));
|
|
33
|
+
var UnaryFilter;
|
|
34
|
+
(function (UnaryFilter) {
|
|
35
|
+
UnaryFilter[UnaryFilter["IS_ODD"] = 0] = "IS_ODD";
|
|
36
|
+
UnaryFilter[UnaryFilter["IS_EVEN"] = 1] = "IS_EVEN";
|
|
37
|
+
})(UnaryFilter || (exports.UnaryFilter = UnaryFilter = {}));
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { CategoryConfig, Solution, TargetFact } from './types';
|
|
2
|
+
import { Clue } from './Clue';
|
|
3
|
+
/**
|
|
4
|
+
* Represents a single step in the logical deduction path.
|
|
5
|
+
*/
|
|
6
|
+
export interface ProofStep {
|
|
7
|
+
/** The clue applied at this step. */
|
|
8
|
+
clue: Clue;
|
|
9
|
+
/** The number of logical eliminations that resulted immediately from this clue. */
|
|
10
|
+
deductions: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The complete result of the puzzle generation process.
|
|
14
|
+
*/
|
|
15
|
+
export interface Puzzle {
|
|
16
|
+
/** The solution grid (Category -> Value -> Corresponding Value). */
|
|
17
|
+
solution: Solution;
|
|
18
|
+
/** The list of clues needed to solve the puzzle, in no particular order. */
|
|
19
|
+
clues: Clue[];
|
|
20
|
+
/** An ordered list of clues that demonstrates a step-by-step logical solution. */
|
|
21
|
+
proofChain: ProofStep[];
|
|
22
|
+
/** The configuration used to generate this puzzle. */
|
|
23
|
+
categories: CategoryConfig[];
|
|
24
|
+
/** The specific fact that the puzzle is designed to reveal at the end. */
|
|
25
|
+
targetFact: TargetFact;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The main class responsible for generating logic puzzles.
|
|
29
|
+
*
|
|
30
|
+
* It handles the creation of a consistent solution, the generation of all possible clues,
|
|
31
|
+
* and the selection of an optimal set of clues to form a solvable puzzle with a specific target.
|
|
32
|
+
*/
|
|
33
|
+
export declare class Generator {
|
|
34
|
+
private seed;
|
|
35
|
+
private random;
|
|
36
|
+
private solver;
|
|
37
|
+
private solution;
|
|
38
|
+
private valueMap;
|
|
39
|
+
private reverseSolution;
|
|
40
|
+
/**
|
|
41
|
+
* Creates a new Generator instance.
|
|
42
|
+
*
|
|
43
|
+
* @param seed - A numeric seed for the random number generator to ensure reproducibility.
|
|
44
|
+
*/
|
|
45
|
+
constructor(seed: number);
|
|
46
|
+
/**
|
|
47
|
+
* Generates a fully solvable logic puzzle based on the provided configuration.
|
|
48
|
+
*
|
|
49
|
+
* @param categories - The categories and values to include in the puzzle.
|
|
50
|
+
* @param target - The specific fact that should be the final deduction of the puzzle.
|
|
51
|
+
* @returns A complete Puzzle object containing the solution, clues, and proof chain.
|
|
52
|
+
*/
|
|
53
|
+
generatePuzzle(categories: CategoryConfig[], target: TargetFact): Puzzle;
|
|
54
|
+
private createSolution;
|
|
55
|
+
private generateAllPossibleClues;
|
|
56
|
+
private calculateScore;
|
|
57
|
+
private isPuzzleSolved;
|
|
58
|
+
}
|