Skip to content

Commit

Permalink
fix: unique solution board generation
Browse files Browse the repository at this point in the history
  • Loading branch information
komeilmehranfar committed Dec 7, 2023
1 parent d74cea4 commit ddcf833
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 15 deletions.
33 changes: 32 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ export { type AnalyzeData, type Board, type Difficulty, type SolvingStep };

export function generate(difficulty: Difficulty): Board {
const { getBoard } = createSudokuInstance({ difficulty });
return getBoard();
const board = getBoard();
if (hasUniqueSolution(board)) {
return board;
}
return generate(difficulty);
}

export function analyze(Board: Board): AnalyzeData {
Expand All @@ -25,3 +29,30 @@ export function solve(Board: Board): {
const board = solveAll();
return { board, steps: solvingSteps };
}

export function hasUniqueSolution(Board: Board): boolean {
const slicedBoard = [...Board];
const solvingAttempts: { board: Board; steps: SolvingStep[] }[] = [];
let index = 0;
while (slicedBoard.some((item) => !Boolean(item))) {
if (solvingAttempts[index - 1]) {
const { steps } = solvingAttempts[index - 1];
const step = steps.find((step) => {
if (step.type === "value") {
return true;
}
});
if (!step) {
break;
}
step.updates.forEach((update) => {
slicedBoard[update.index] = update.filledValue;
});
}
solvingAttempts.push(solve(slicedBoard));
index++;
}
return solvingAttempts[0].board.every(
(item, index) => slicedBoard[index] === item,
);
}
28 changes: 14 additions & 14 deletions tests/sudoku.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { generate, analyze, solve } from "../src/index"; // Import the createSudokuInstance module (update path as needed)
import {
generate,
analyze,
solve,
Board,
SolvingStep,
hasUniqueSolution,
} from "../src/index"; // Import the createSudokuInstance module (update path as needed)
import {
EASY_SUDOKU_BOARD_FOR_TEST,
EXPERT_SUDOKU_BOARD_FOR_TEST,
Expand All @@ -12,23 +19,25 @@ describe("sudoku-core", () => {
it("should generate a valid easy difficulty board", () => {
//Arrange
const sudokuBoard = generate("easy");

//Act
const data = analyze(sudokuBoard);

// Assert
expect(data.difficulty).toBe("easy");
expect(sudokuBoard.filter(Boolean).length).toBe(40);
expect(hasUniqueSolution(sudokuBoard)).toBe(true);
});
it("should generate a valid medium difficulty board", () => {
//Arrange
const sudokuBoard = generate("medium");

//Act
const data = analyze(sudokuBoard);

// Assert
expect(data.difficulty).toBe("medium");
expect(sudokuBoard.filter(Boolean).length).toBe(30);
expect(hasUniqueSolution(sudokuBoard)).toBe(true);
});
it("should generate a valid hard difficulty board", () => {
//Arrange
Expand All @@ -39,6 +48,7 @@ describe("sudoku-core", () => {

// Assert
expect(data.difficulty).toBe("hard");
expect(hasUniqueSolution(sudokuBoard)).toBe(true);
});
it("should generate a valid expert difficulty board", () => {
//Arrange
Expand All @@ -49,6 +59,7 @@ describe("sudoku-core", () => {

// Assert
expect(data.difficulty).toBe("expert");
expect(hasUniqueSolution(sudokuBoard)).toBe(true);
});
it("should generate a valid master difficulty board", () => {
//Arrange
Expand All @@ -59,23 +70,12 @@ describe("sudoku-core", () => {

// Assert
expect(data.difficulty).toBe("master");
expect(hasUniqueSolution(sudokuBoard)).toBe(true);
});
});

describe("solve method", () => {
it("should solve the board", () => {
//Arrange
const sudokuBoard = generate("expert");

//Act
const { board: solvedBoard } = solve(sudokuBoard);

// Assert
expect(solvedBoard.every((cell) => cell !== null)).toBe(true);
});
});
describe("solveStep method", () => {
it("should solve one more step", () => {
//Arrange
const sudokuBoard = generate("master");
const unfilledCellsLength = sudokuBoard.filter(
Expand Down

0 comments on commit ddcf833

Please sign in to comment.