97 lines
2.6 KiB
TypeScript
97 lines
2.6 KiB
TypeScript
import fc from "fast-check";
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
analyzeKillerCage,
|
|
calculateKillerCombinations,
|
|
} from "../../src/helpers";
|
|
|
|
describe("killer cage combinations", () => {
|
|
it("enumerates the familiar two-cell sum 10 combinations", () => {
|
|
expect(calculateKillerCombinations({ cellCount: 2, sum: 10 })).toEqual([
|
|
[1, 9],
|
|
[2, 8],
|
|
[3, 7],
|
|
[4, 6],
|
|
]);
|
|
});
|
|
|
|
it("supports allowed, required, excluded and repeated digits", () => {
|
|
expect(
|
|
calculateKillerCombinations({
|
|
cellCount: 3,
|
|
sum: 10,
|
|
allowedDigits: [1, 2, 3, 4, 5],
|
|
excludedDigits: [1],
|
|
requiredDigits: [5],
|
|
}),
|
|
).toEqual([[2, 3, 5]]);
|
|
expect(
|
|
calculateKillerCombinations({
|
|
cellCount: 2,
|
|
sum: 10,
|
|
allowRepeats: true,
|
|
}),
|
|
).toContainEqual([5, 5]);
|
|
});
|
|
|
|
it("filters assignments through per-cell candidates", () => {
|
|
const result = analyzeKillerCage({
|
|
cellCount: 2,
|
|
sum: 10,
|
|
candidates: [
|
|
[1, 2],
|
|
[8, 9],
|
|
],
|
|
});
|
|
expect(result.combinations).toEqual([
|
|
[1, 9],
|
|
[2, 8],
|
|
]);
|
|
expect(result.assignments).toEqual([
|
|
[1, 9],
|
|
[2, 8],
|
|
]);
|
|
expect(result.possibleByCell).toEqual([
|
|
[1, 2],
|
|
[8, 9],
|
|
]);
|
|
expect(result.necessaryDigits).toEqual([]);
|
|
});
|
|
|
|
it("reports digits necessary in every surviving combination", () => {
|
|
const result = analyzeKillerCage({ cellCount: 3, sum: 6 });
|
|
expect(result.combinations).toEqual([[1, 2, 3]]);
|
|
expect(result.necessaryDigits).toEqual([1, 2, 3]);
|
|
});
|
|
|
|
it("satisfies combination invariants for generated inputs", () => {
|
|
fc.assert(
|
|
fc.property(
|
|
fc.integer({ min: 4, max: 12 }),
|
|
fc.integer({ min: 1, max: 5 }),
|
|
fc.integer({ min: 1, max: 60 }),
|
|
(size, count, sum) => {
|
|
if (count > size || sum > size * count) return;
|
|
const result = calculateKillerCombinations({
|
|
size,
|
|
cellCount: count,
|
|
sum,
|
|
});
|
|
const keys = new Set<string>();
|
|
for (const combination of result) {
|
|
expect(combination).toHaveLength(count);
|
|
expect(combination.reduce((total, digit) => total + digit, 0)).toBe(
|
|
sum,
|
|
);
|
|
expect(combination).toEqual([...combination].sort((a, b) => a - b));
|
|
expect(new Set(combination).size).toBe(count);
|
|
keys.add(combination.join(","));
|
|
}
|
|
expect(keys.size).toBe(result.length);
|
|
},
|
|
),
|
|
{ numRuns: 100 },
|
|
);
|
|
});
|
|
});
|