Files
sudoku-tools/tests/solver/logical.test.ts
T

60 lines
1.8 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("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);
});
});