diff --git a/src/algorithms/Recursion/NQueens.js b/src/algorithms/Recursion/NQueens.js
new file mode 100644
index 0000000..2889781
--- /dev/null
+++ b/src/algorithms/Recursion/NQueens.js
@@ -0,0 +1,101 @@
+export function nQueensVisualizerSteps(N) {
+ const steps = [];
+ const board = Array.from({ length: N }, () => Array(N).fill(0));
+ const solutions = [];
+ const cols = Array(N).fill(false);
+ const diag1 = Array(2 * N).fill(false);
+ const diag2 = Array(2 * N).fill(false);
+ const stack = [];
+
+ function cloneBoard(b) {
+ return b.map(r => [...r]);
+ }
+
+ function solve(row) {
+ if (row === N) {
+ steps.push({
+ type: "solution",
+ board: cloneBoard(board),
+ message: `Found valid solution!`,
+ stack: [...stack],
+ safe: true,
+ solutionCount: solutions.length + 1
+ });
+ solutions.push(cloneBoard(board));
+ return;
+ }
+
+ for (let col = 0; col < N; col++) {
+ steps.push({
+ type: "try",
+ board: cloneBoard(board),
+ row,
+ col,
+ message: `Trying to place Queen at (${row}, ${col})`,
+ safe: null,
+ stack: [...stack]
+ });
+
+ if (!cols[col] && !diag1[row - col + N] && !diag2[row + col]) {
+ steps.push({
+ type: "check",
+ board: cloneBoard(board),
+ row,
+ col,
+ safe: true,
+ message: `Position (${row}, ${col}) is safe.`,
+ stack: [...stack]
+ });
+
+ board[row][col] = 1;
+ cols[col] = diag1[row - col + N] = diag2[row + col] = true;
+ stack.push({ row, col });
+
+ steps.push({
+ type: "place",
+ board: cloneBoard(board),
+ row,
+ col,
+ message: `Placed Queen at (${row}, ${col}). Moving to next row.`,
+ safe: true,
+ stack: [...stack]
+ });
+
+ solve(row + 1);
+
+ board[row][col] = 0;
+ cols[col] = diag1[row - col + N] = diag2[row + col] = false;
+ stack.pop();
+
+ steps.push({
+ type: "remove",
+ board: cloneBoard(board),
+ row,
+ col,
+ message: `Backtracking: Removed Queen from (${row}, ${col}).`,
+ safe: false,
+ stack: [...stack]
+ });
+ } else {
+ steps.push({
+ type: "check",
+ board: cloneBoard(board),
+ row,
+ col,
+ safe: false,
+ message: `Conflict at (${row}, ${col}). Cannot place Queen here.`,
+ stack: [...stack]
+ });
+ }
+ }
+ }
+
+ solve(0);
+
+ return {
+ steps,
+ solutions,
+ solutionCount: solutions.length,
+ solvable: solutions.length > 0,
+ };
+}
diff --git a/src/components/Recursion/NQueensVisualizer.jsx b/src/components/Recursion/NQueensVisualizer.jsx
new file mode 100644
index 0000000..81982b1
--- /dev/null
+++ b/src/components/Recursion/NQueensVisualizer.jsx
@@ -0,0 +1,277 @@
+import React, { useState, useEffect, useRef } from "react";
+import { nQueensVisualizerSteps } from "../../algorithms/Recursion/NQueens";
+
+const DEFAULT_N = 5;
+const MIN_N = 4;
+const MAX_N = 10;
+const DEFAULT_SPEED = 500;
+
+function Chessboard({ board, step, N }) {
+ if (
+ !board ||
+ board.length !== N ||
+ board.some((row) => !row || row.length !== N)
+ ) {
+ return (
+
+ Loading chessboard...
+
+ );
+ }
+ const BOARD_SIZE = 440;
+ const cellSize = BOARD_SIZE / N;
+
+ return (
+
+ {Array.from({ length: N }).map((_, row) =>
+ Array.from({ length: N }).map((_, col) => {
+ const cell = board[row][col];
+ const isQueen = cell === 1;
+
+ let color = (row + col) % 2 === 0 ? "bg-gray-100" : "bg-gray-400";
+
+ if (step) {
+ if (step.type === "try" && step.row === row && step.col === col)
+ color = "bg-blue-300";
+ else if (step.type === "check" && step.row === row && step.col === col)
+ color = step.safe === false ? "bg-yellow-300" : "bg-green-300";
+ else if (step.type === "place" && step.row === row && step.col === col)
+ color = "bg-green-500";
+ else if (step.type === "remove" && step.row === row && step.col === col)
+ color = "bg-gray-500";
+ else if (step.type === "solution" && board[row][col] === 1)
+ color = "bg-lime-400";
+ }
+
+ return (
+
+ {isQueen && (
+
+ ♛
+
+ )}
+
+ );
+ })
+ )}
+
+ );
+}
+
+function StackTrace({ stack }) {
+ return (
+
+
+ Recursion Stack
+
+ {stack.length === 0 ? (
+
Stack empty
+ ) : (
+
+ {stack.map((pos, idx) => (
+
+ Row-{pos.row}, Col-{pos.col}
+
+ ))}
+
+ )}
+
+ );
+}
+
+function Legend({ color, text, symbol }) {
+ return (
+
+
+ {symbol}
+
+
{text}
+
+ );
+}
+
+export default function NQueensVisualizer() {
+ const [N, setN] = useState(DEFAULT_N);
+ const [speed, setSpeed] = useState(DEFAULT_SPEED);
+ const [steps, setSteps] = useState([]);
+ const [currentStepIdx, setCurrentStepIdx] = useState(0);
+ const [isPlaying, setIsPlaying] = useState(false);
+ const [solutionCount, setSolutionCount] = useState(0);
+ const [solvable, setSolvable] = useState(null);
+ const timerRef = useRef(null);
+
+ const runSolver = () => {
+ const result = nQueensVisualizerSteps(N);
+ setSteps(result.steps);
+ setSolutionCount(result.solutionCount);
+ setSolvable(result.solvable);
+ setCurrentStepIdx(0);
+ setIsPlaying(false);
+ };
+
+ useEffect(() => {
+ setSteps([]);
+ setCurrentStepIdx(0);
+ setSolvable(null);
+ setSolutionCount(0);
+ runSolver();
+ }, [N]);
+
+ useEffect(() => {
+ if (isPlaying && currentStepIdx < steps.length - 1) {
+ timerRef.current = setTimeout(() => {
+ setCurrentStepIdx((idx) => idx + 1);
+ }, speed);
+ } else {
+ clearTimeout(timerRef.current);
+ setIsPlaying(false);
+ }
+ return () => clearTimeout(timerRef.current);
+ }, [isPlaying, currentStepIdx, steps, speed]);
+
+ const step = steps[currentStepIdx] || {};
+ const board = step.board || Array.from({ length: N }, () => Array(N).fill(0));
+
+ return (
+
+
+
+ ♛ N-Queens Visualizer
+
+
+ {/* Controls */}
+
+
+
+
+ setN(Math.max(MIN_N, Math.min(MAX_N, Number(e.target.value))))
+ }
+ className="w-20 mt-1 p-2 rounded-md bg-gray-700 text-white border border-gray-600"
+ />
+
+
+
+
+
+ setSpeed(Math.max(100, Math.min(2000, Number(e.target.value))))
+ }
+ className="w-20 mt-1 p-2 rounded-md bg-gray-700 text-white border border-gray-600"
+ />
+
+
+
+
+
+
+
+
+ {/* Main Layout*/}
+
+ {/*Chessboard*/}
+
+
+
+ Step {currentStepIdx + 1}/{steps.length} • Solutions Found:{" "}
+
{solutionCount}
+ {solvable === false && (
+
+ No solution for N={N}
+
+ )}
+
+
+
+
+
+
+ Step Explanation
+
+
+ {step.message || "Start solving N-Queens..."}
+
+
+
+
+
+
+
+ Color Meanings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/pages/Recursion/NQueens.jsx b/src/pages/Recursion/NQueens.jsx
new file mode 100644
index 0000000..aff8d53
--- /dev/null
+++ b/src/pages/Recursion/NQueens.jsx
@@ -0,0 +1,6 @@
+import React from "react";
+import NQueensVisualizer from "../../components/recursion/NQueensVisualizer";
+
+export default function NQueens() {
+ return ;
+}
\ No newline at end of file
diff --git a/src/pages/Recursion/RecursionPage.jsx b/src/pages/Recursion/RecursionPage.jsx
index 22ae46e..3e2bbc8 100644
--- a/src/pages/Recursion/RecursionPage.jsx
+++ b/src/pages/Recursion/RecursionPage.jsx
@@ -1,7 +1,7 @@
import React, { useState } from "react";
import { X, Menu } from "lucide-react";
import MazeSolver from "./MazeSolver";
-
+import NQueens from "./NQueens";
export default function RecursionPage() {
const [selectedAlgo, setSelectedAlgo] = useState("");
const [sidebarOpen, setSidebarOpen] = useState(true);
@@ -14,6 +14,12 @@ export default function RecursionPage() {
);
+ case "NQueens":
+ return (
+
+
+
+ );
default:
return (
@@ -55,6 +61,7 @@ export default function RecursionPage() {
>
+