diff --git a/src/algorithms/Recursion/permutation.js b/src/algorithms/Recursion/permutation.js new file mode 100644 index 0000000..d5aa643 --- /dev/null +++ b/src/algorithms/Recursion/permutation.js @@ -0,0 +1,57 @@ +export function generatePermutations(arr) { + const steps = []; + const result = []; + + function swap(a, i, j) { + const temp = a[i]; + a[i] = a[j]; + a[j] = temp; + } + + function backtrack(a, index, depth) { + steps.push({ + type: "recurse", + array: [...a], + index, + depth + }); + + if (index === a.length) { + result.push([...a]); + steps.push({ + type: "output", + array: [...a], + depth + }); + return; + } + + for (let i = index; i < a.length; i++) { + steps.push({ + type: "swap", + array: [...a], + i: index, + j: i, + depth + }); + swap(a, index, i); + backtrack(a, index + 1, depth + 1); + steps.push({ + type: "backtrack", + array: [...a], + i: index, + j: i, + depth + }); + + swap(a, index, i); + } + } + steps.push({ + type: "start", + array: [...arr], + depth: 0 + }); +backtrack([...arr], 0, 0); + return { steps, permutations: result }; +} diff --git a/src/components/Recursion/PermutationsVisualizer.jsx b/src/components/Recursion/PermutationsVisualizer.jsx new file mode 100644 index 0000000..bbac8ed --- /dev/null +++ b/src/components/Recursion/PermutationsVisualizer.jsx @@ -0,0 +1,209 @@ +import React, { useState, useEffect, useRef } from "react"; +import { generatePermutations } from "@/algorithms/Recursion/permutation"; + +export default function PermutationsVisualizer() { + const [inputText, setInputText] = useState("A,B,C"); + const [array, setArray] = useState(["A", "B", "C"]); + const [steps, setSteps] = useState([]); + const [permutations, setPermutations] = useState([]); + const [index, setIndex] = useState(0); + const [playing, setPlaying] = useState(false); + const [speed, setSpeed] = useState(600); + + const timerRef = useRef(null); + + useEffect(() => { + const arr = inputText.split(",").map(x => x.trim()).filter(Boolean); + setArray(arr.length ? arr : []); + }, [inputText]); + + useEffect(() => { + if (!playing) return; + if (index >= steps.length) { + setPlaying(false); + return; + } + timerRef.current = setTimeout(() => { + setIndex(i => Math.min(i + 1, steps.length)); + }, speed); + + return () => clearTimeout(timerRef.current); + }, [playing, index, steps.length, speed]); + + function build() { + const arr = inputText.split(",").map(x => x.trim()).filter(Boolean); + const { steps: s, permutations: p } = generatePermutations(arr); + + setSteps(s); + setPermutations(p); + setIndex(0); + setPlaying(false); + } + + function stepForward() { + setIndex(i => Math.min(i + 1, steps.length)); + } + + function stepBackward() { + setIndex(i => Math.max(i - 1, 0)); + } + + function reset() { + setIndex(0); + setPlaying(false); + } + + const currentStep = index > 0 ? steps[index - 1] : null; + const displayedArray = currentStep ? currentStep.array : array; + + let highlight = { i: null, j: null }; + let status = "Idle"; + let depth = currentStep ? currentStep.depth : "-"; + + if (currentStep) { + if (["swap", "backtrack"].includes(currentStep.type)) { + highlight.i = currentStep.i; + highlight.j = currentStep.j; + status = + currentStep.type === "swap" + ? `Swap ${currentStep.i} ↔ ${currentStep.j}` + : `Backtrack ${currentStep.i} ↔ ${currentStep.j}`; + } else if (currentStep.type === "recurse") { + status = `Recurse → index ${currentStep.index}`; + } else if (currentStep.type === "output") { + status = "Output permutation"; + } else if (currentStep.type === "start") { + status = "Start"; + } + } + + return ( +
+
+

+ Permutations Visualizer (Recursion) +

+ + {/* INPUT CARD */} +
+ + setInputText(e.target.value)} + className="w-full p-3 rounded-lg bg-[#111] border border-gray-700 focus:border-blue-500 outline-none text-gray-200" + placeholder="A,B,C" + /> + +
+ + + + + + + + + + +
+ + setSpeed(Number(e.target.value))} + /> + {speed}ms +
+
+
+ +
+ +
+

Array State

+ +
+ {displayedArray.map((v, i) => ( +
+ {v} +
+ ))} +
+ +
+
Step: {index} / {steps.length}
+
Status: {status}
+
Depth: {depth}
+
+
+
+

Generated Permutations

+ +
+ {permutations.map((p, i) => ( +
+ {p.join(", ")} +
+ ))} +
+
+
+
+

All Steps

+ + {steps.map((s, i) => ( +
+ {i + 1}. {s.type} — [{s.array.join(", ")}] (depth {s.depth}) +
+ ))} +
+
+
+ ); +} diff --git a/src/components/dynamic-programming/kmpSearchAlgovisual.jsx b/src/components/dynamic-programming/kmpSearchAlgovisual.jsx index fcdb7d6..1820d39 100644 --- a/src/components/dynamic-programming/kmpSearchAlgovisual.jsx +++ b/src/components/dynamic-programming/kmpSearchAlgovisual.jsx @@ -1,5 +1,5 @@ import React, { useState, useMemo, useEffect, useRef } from "react"; -import { computeLPSSteps, kmpSearchSteps } from "@/algorithms/string/kmpAlgo"; +//import { computeLPSSteps, kmpSearchSteps } from "@/algorithms/string/kmpAlgo"; const LPSDisplay = ({ pattern, lpsState }) => { const { lps, highlight, message } = lpsState; diff --git a/src/pages/Recursion/RecursionPage.jsx b/src/pages/Recursion/RecursionPage.jsx index 1053409..cab59e6 100644 --- a/src/pages/Recursion/RecursionPage.jsx +++ b/src/pages/Recursion/RecursionPage.jsx @@ -6,6 +6,7 @@ import Sudoku from "./sudokuSolver"; import TowerOfHanoi from "./towerOfHanoi"; import SubsetSum from "./SubsetSum"; import FloodFillPage from "./FloodFill"; +import PermutationsPage from "./permutations"; export default function RecursionPage() { const [selectedAlgo, setSelectedAlgo] = useState(""); const [sidebarOpen, setSidebarOpen] = useState(true); @@ -48,6 +49,12 @@ export default function RecursionPage() { ) + case "Permutations": + return( +
+ +
+ ) default: return (
@@ -94,6 +101,7 @@ export default function RecursionPage() { +
+ ); +}