import { describe, expect, it } from "vitest"; import { calculateResidual, fortyFiveRuleResidual, inequalityPairs, kropkiPairs, relationPairs, xvPairs, } from "../../src/helpers"; describe("relation pair tables", () => { it("builds white and black Kropki tables", () => { expect(kropkiPairs("white", 4)).toEqual([ [1, 2], [2, 1], [2, 3], [3, 2], [3, 4], [4, 3], ]); expect(kropkiPairs("black", 4)).toEqual([ [1, 2], [2, 1], [2, 4], [4, 2], ]); }); it("builds XV and directed inequality tables with candidate filtering", () => { expect(xvPairs(5, 4)).toEqual([ [1, 4], [2, 3], [3, 2], [4, 1], ]); expect(inequalityPairs("<", 4, [2, 4], [1, 3])).toEqual([[2, 3]]); expect( relationPairs({ type: "difference", difference: 2 }, 4), ).toContainEqual([1, 3]); }); }); describe("45-rule helpers", () => { it("calculates a residual and its combinations", () => { const result = calculateResidual({ knownSums: [10, 20], unknownCount: 2 }); expect(result.residual).toBe(15); expect(result.analysis?.combinations).toEqual([ [6, 9], [7, 8], ]); }); it("subtracts complete cages and values but reports crossing cages", () => { const result = fortyFiveRuleResidual({ unitCells: [0, 1, 2, 3, 4, 5, 6, 7, 8], cages: [ { cells: [0, 1], sum: 3 }, { cells: [8, 17], sum: 10 }, ], knownValues: { 2: 4 }, }); expect(result.accounted).toBe(7); expect(result.residual).toBe(38); expect(result.residualCells).toEqual([3, 4, 5, 6, 7, 8]); expect(result.crossingCages).toEqual([{ cells: [8, 17], sum: 10 }]); }); });