82 lines
2.4 KiB
TypeScript
82 lines
2.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { classicRegions, type PuzzleDefinition } from "../../src/domain";
|
|
import { killerDigitCombinations, solveLogically } from "../../src/solver";
|
|
|
|
const easy: PuzzleDefinition = {
|
|
version: 1,
|
|
size: 9,
|
|
givens: [
|
|
5, 3, 0, 0, 7, 0, 0, 0, 0, 6, 0, 0, 1, 9, 5, 0, 0, 0, 0, 9, 8, 0, 0, 0, 0,
|
|
6, 0, 8, 0, 0, 0, 6, 0, 0, 0, 3, 4, 0, 0, 8, 0, 3, 0, 0, 1, 7, 0, 0, 0, 2,
|
|
0, 0, 0, 6, 0, 6, 0, 0, 0, 0, 2, 8, 0, 0, 0, 0, 4, 1, 9, 0, 0, 5, 0, 0, 0,
|
|
0, 8, 0, 0, 7, 9,
|
|
],
|
|
regions: classicRegions(9),
|
|
constraints: [],
|
|
};
|
|
|
|
describe("logical solver", () => {
|
|
it("solves a standard puzzle and emits inspectable steps", () => {
|
|
const result = solveLogically(easy);
|
|
expect(result.status).toBe("solved");
|
|
expect(result.values.every((value) => value > 0)).toBe(true);
|
|
expect(result.steps.length).toBeGreaterThan(0);
|
|
expect(result.steps.every((step) => step.explanation.length > 0)).toBe(
|
|
true,
|
|
);
|
|
expect(
|
|
result.steps.some(
|
|
({ technique }) =>
|
|
technique === "naked-single" || technique === "hidden-single",
|
|
),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("stops safely at the configured step bound", () => {
|
|
const result = solveLogically(easy, { maxSteps: 1 });
|
|
expect(result.status).toBe("step-limit");
|
|
expect(result.steps).toHaveLength(1);
|
|
});
|
|
|
|
it("does not apply positive cage reductions to a false cage", () => {
|
|
const result = solveLogically({
|
|
version: 1,
|
|
size: 4,
|
|
givens: Array<number>(16).fill(0),
|
|
regions: classicRegions(4),
|
|
constraints: [
|
|
{
|
|
type: "killer-cage",
|
|
cells: [0, 1],
|
|
sum: 3,
|
|
noRepeat: false,
|
|
negated: true,
|
|
},
|
|
],
|
|
});
|
|
|
|
expect(result.status).toBe("stuck");
|
|
expect(result.steps).toEqual([]);
|
|
expect(result.candidates[0]).toEqual([1, 2, 3, 4]);
|
|
});
|
|
|
|
it("returns bounded killer combinations", () => {
|
|
expect(
|
|
killerDigitCombinations({ size: 9, count: 2, sum: 10 }).combinations,
|
|
).toEqual([
|
|
[1, 9],
|
|
[2, 8],
|
|
[3, 7],
|
|
[4, 6],
|
|
]);
|
|
expect(
|
|
killerDigitCombinations({ size: 9, count: 2, sum: 10, noRepeat: false })
|
|
.combinations,
|
|
).toContainEqual([5, 5]);
|
|
expect(
|
|
killerDigitCombinations({ size: 16, count: 8, sum: 68, maxResults: 1 })
|
|
.truncated,
|
|
).toBe(true);
|
|
});
|
|
});
|