Skip to content

Commit 5d198a3

Browse files
Merge pull request #72 from Satvik-Singh192/feat/sudo-solver
feat: implemented sudoku solver by recursion and backtracking
2 parents 4d3daed + e56b30a commit 5d198a3

File tree

4 files changed

+143
-0
lines changed

4 files changed

+143
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
function isSafe(board, r, c, num) {
2+
for (let x = 0; x < 9; x++) {
3+
if (board[r][x] === num || board[x][c] === num) return false;
4+
}
5+
6+
const startRow = r - (r % 3);
7+
const startCol = c - (c % 3);
8+
for (let i = 0; i < 3; i++) {
9+
for (let j = 0; j < 3; j++) {
10+
if (board[startRow + i][startCol + j] === num) return false;
11+
}
12+
}
13+
14+
return true;
15+
}
16+
17+
export async function solveSudoku(board, visualizeStep, r = 0, c = 0) {
18+
if (r === 9) return true;
19+
if (c === 9) return await solveSudoku(board, visualizeStep, r + 1, 0);
20+
if (board[r][c] !== 0) return await solveSudoku(board, visualizeStep, r, c + 1);
21+
22+
for (let num = 1; num <= 9; num++) {
23+
if (isSafe(board, r, c, num)) {
24+
board[r][c] = num;
25+
visualizeStep(r, c, num, "filled");
26+
await sleep(50);
27+
28+
if (await solveSudoku(board, visualizeStep, r, c + 1)) return true;
29+
30+
31+
board[r][c] = 0;
32+
visualizeStep(r, c, 0, "backtrack");
33+
await sleep(50);
34+
} else {
35+
visualizeStep(r, c, num, "trying");
36+
await sleep(20);
37+
}
38+
}
39+
return false;
40+
}
41+
42+
function sleep(ms) {
43+
return new Promise((resolve) => setTimeout(resolve, ms));
44+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// src/components/Recursion/SudokuVisualizer.jsx
2+
import React, { useState } from "react";
3+
import { solveSudoku } from "../../algorithms/Recursion/sudokuSolver";
4+
5+
export default function SudokuVisualizer() {
6+
const initialBoard = [
7+
[5, 3, 0, 0, 7, 0, 0, 0, 0],
8+
[6, 0, 0, 1, 9, 5, 0, 0, 0],
9+
[0, 9, 8, 0, 0, 0, 0, 6, 0],
10+
[8, 0, 0, 0, 6, 0, 0, 0, 3],
11+
[4, 0, 0, 8, 0, 3, 0, 0, 1],
12+
[7, 0, 0, 0, 2, 0, 0, 0, 6],
13+
[0, 6, 0, 0, 0, 0, 2, 8, 0],
14+
[0, 0, 0, 4, 1, 9, 0, 0, 5],
15+
[0, 0, 0, 0, 8, 0, 0, 7, 9],
16+
];
17+
18+
const [grid, setGrid] = useState(initialBoard);
19+
const [cellStatus, setCellStatus] = useState({});
20+
const [solving, setSolving] = useState(false);
21+
22+
const visualizeStep = (r, c, val, status) => {
23+
setGrid((prev) => {
24+
const copy = prev.map((row) => row.slice());
25+
copy[r][c] = val;
26+
return copy;
27+
});
28+
29+
setCellStatus((prev) => ({
30+
...prev,
31+
[`${r}-${c}`]: status,
32+
}));
33+
};
34+
35+
const handleSolve = async () => {
36+
setSolving(true);
37+
const copy = grid.map((row) => row.slice());
38+
await solveSudoku(copy, visualizeStep);
39+
setSolving(false);
40+
};
41+
42+
return (
43+
<div className="flex flex-col items-center p-4">
44+
<h2 className="text-xl font-bold mb-4 text-white">Sudoku Solver Visualizer </h2>
45+
46+
<div
47+
className="grid"
48+
style={{
49+
gridTemplateColumns: "repeat(9, 40px)",
50+
gridTemplateRows: "repeat(9, 40px)",
51+
gap: "2px",
52+
}}
53+
>
54+
{grid.map((row, r) =>
55+
row.map((val, c) => {
56+
const status = cellStatus[`${r}-${c}`];
57+
let bg = "bg-gray-800";
58+
59+
if (status === "filled") bg = "bg-green-500";
60+
else if (status === "trying") bg = "bg-yellow-400";
61+
else if (status === "backtrack") bg = "bg-red-500";
62+
63+
return (
64+
<div
65+
key={`${r}-${c}`}
66+
className={`w-10 h-10 flex justify-center items-center text-white text-lg font-medium border border-gray-600 ${bg}`}
67+
>
68+
{val !== 0 ? val : ""}
69+
</div>
70+
);
71+
})
72+
)}
73+
</div>
74+
75+
<button
76+
onClick={handleSolve}
77+
disabled={solving}
78+
className="mt-6 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium disabled:opacity-50"
79+
>
80+
{solving ? "Solving..." : "Start Visualization"}
81+
</button>
82+
</div>
83+
);
84+
}

src/pages/Recursion/RecursionPage.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useState } from "react";
22
import { X, Menu } from "lucide-react";
33
import MazeSolver from "./MazeSolver";
44
import NQueens from "./NQueens";
5+
import Sudoku from "./sudokuSolver";
56
export default function RecursionPage() {
67
const [selectedAlgo, setSelectedAlgo] = useState("");
78
const [sidebarOpen, setSidebarOpen] = useState(true);
@@ -20,6 +21,13 @@ export default function RecursionPage() {
2021
<NQueens />
2122
</div>
2223
);
24+
case "SudokuSolver":
25+
return(
26+
<div className="w-full p-4 overflow-auto">
27+
<Sudoku />
28+
</div>
29+
);
30+
2331
default:
2432
return (
2533
<div className="flex flex-col items-center justify-center text-center p-6 min-h-screen bg-gray-900 text-gray-300">
@@ -62,6 +70,7 @@ export default function RecursionPage() {
6270
<option value="">Select Algorithm</option>
6371
<option value="MazeSolver">Maze Solver</option>
6472
<option value="NQueens">NQueens</option>
73+
<option value="SudokuSolver">Sudoku Solver</option>
6574
</select>
6675

6776
<button
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import React from "react";
2+
import SudokuVisualizer from "../../components/Recursion/sudokuSolver";
3+
4+
export default function Sudoku(){
5+
return <SudokuVisualizer />
6+
}

0 commit comments

Comments
 (0)