Skip to content

Commit 5142e0d

Browse files
Merge branch 'main' of https://github.com/PresenceOP-Coder/Algo-Visualizer into counting
2 parents 37d6d47 + 73632b0 commit 5142e0d

File tree

4 files changed

+284
-0
lines changed

4 files changed

+284
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
export function generatePermutations(arr) {
2+
const steps = [];
3+
const result = [];
4+
5+
function swap(a, i, j) {
6+
const temp = a[i];
7+
a[i] = a[j];
8+
a[j] = temp;
9+
}
10+
11+
function backtrack(a, index, depth) {
12+
steps.push({
13+
type: "recurse",
14+
array: [...a],
15+
index,
16+
depth
17+
});
18+
19+
if (index === a.length) {
20+
result.push([...a]);
21+
steps.push({
22+
type: "output",
23+
array: [...a],
24+
depth
25+
});
26+
return;
27+
}
28+
29+
for (let i = index; i < a.length; i++) {
30+
steps.push({
31+
type: "swap",
32+
array: [...a],
33+
i: index,
34+
j: i,
35+
depth
36+
});
37+
swap(a, index, i);
38+
backtrack(a, index + 1, depth + 1);
39+
steps.push({
40+
type: "backtrack",
41+
array: [...a],
42+
i: index,
43+
j: i,
44+
depth
45+
});
46+
47+
swap(a, index, i);
48+
}
49+
}
50+
steps.push({
51+
type: "start",
52+
array: [...arr],
53+
depth: 0
54+
});
55+
backtrack([...arr], 0, 0);
56+
return { steps, permutations: result };
57+
}
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import React, { useState, useEffect, useRef } from "react";
2+
import { generatePermutations } from "@/algorithms/Recursion/permutation";
3+
4+
export default function PermutationsVisualizer() {
5+
const [inputText, setInputText] = useState("A,B,C");
6+
const [array, setArray] = useState(["A", "B", "C"]);
7+
const [steps, setSteps] = useState([]);
8+
const [permutations, setPermutations] = useState([]);
9+
const [index, setIndex] = useState(0);
10+
const [playing, setPlaying] = useState(false);
11+
const [speed, setSpeed] = useState(600);
12+
13+
const timerRef = useRef(null);
14+
15+
useEffect(() => {
16+
const arr = inputText.split(",").map(x => x.trim()).filter(Boolean);
17+
setArray(arr.length ? arr : []);
18+
}, [inputText]);
19+
20+
useEffect(() => {
21+
if (!playing) return;
22+
if (index >= steps.length) {
23+
setPlaying(false);
24+
return;
25+
}
26+
timerRef.current = setTimeout(() => {
27+
setIndex(i => Math.min(i + 1, steps.length));
28+
}, speed);
29+
30+
return () => clearTimeout(timerRef.current);
31+
}, [playing, index, steps.length, speed]);
32+
33+
function build() {
34+
const arr = inputText.split(",").map(x => x.trim()).filter(Boolean);
35+
const { steps: s, permutations: p } = generatePermutations(arr);
36+
37+
setSteps(s);
38+
setPermutations(p);
39+
setIndex(0);
40+
setPlaying(false);
41+
}
42+
43+
function stepForward() {
44+
setIndex(i => Math.min(i + 1, steps.length));
45+
}
46+
47+
function stepBackward() {
48+
setIndex(i => Math.max(i - 1, 0));
49+
}
50+
51+
function reset() {
52+
setIndex(0);
53+
setPlaying(false);
54+
}
55+
56+
const currentStep = index > 0 ? steps[index - 1] : null;
57+
const displayedArray = currentStep ? currentStep.array : array;
58+
59+
let highlight = { i: null, j: null };
60+
let status = "Idle";
61+
let depth = currentStep ? currentStep.depth : "-";
62+
63+
if (currentStep) {
64+
if (["swap", "backtrack"].includes(currentStep.type)) {
65+
highlight.i = currentStep.i;
66+
highlight.j = currentStep.j;
67+
status =
68+
currentStep.type === "swap"
69+
? `Swap ${currentStep.i}${currentStep.j}`
70+
: `Backtrack ${currentStep.i}${currentStep.j}`;
71+
} else if (currentStep.type === "recurse") {
72+
status = `Recurse → index ${currentStep.index}`;
73+
} else if (currentStep.type === "output") {
74+
status = "Output permutation";
75+
} else if (currentStep.type === "start") {
76+
status = "Start";
77+
}
78+
}
79+
80+
return (
81+
<div className="min-h-screen bg-[#0f0f0f] text-gray-200 p-6 flex justify-center">
82+
<div className="w-full max-w-5xl">
83+
<h2 className="text-3xl font-bold mb-6 text-center text-blue-400">
84+
Permutations Visualizer (Recursion)
85+
</h2>
86+
87+
{/* INPUT CARD */}
88+
<div className="bg-[#1a1a1a] p-5 rounded-2xl shadow-lg border border-gray-800 mb-6">
89+
<label className="block text-sm font-semibold mb-2 text-gray-300">
90+
Enter Elements (comma separated)
91+
</label>
92+
<input
93+
value={inputText}
94+
onChange={e => setInputText(e.target.value)}
95+
className="w-full p-3 rounded-lg bg-[#111] border border-gray-700 focus:border-blue-500 outline-none text-gray-200"
96+
placeholder="A,B,C"
97+
/>
98+
99+
<div className="flex flex-wrap gap-3 mt-4">
100+
<button
101+
onClick={build}
102+
className="px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-lg transition"
103+
>
104+
Build
105+
</button>
106+
107+
<button
108+
onClick={() => setPlaying(p => !p)}
109+
className="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 rounded-lg transition"
110+
>
111+
{playing ? "Pause" : "Play"}
112+
</button>
113+
114+
<button
115+
onClick={stepBackward}
116+
className="px-4 py-2 bg-gray-700 hover:bg-gray-600 rounded-lg"
117+
>
118+
◀ Step
119+
</button>
120+
121+
<button
122+
onClick={stepForward}
123+
className="px-4 py-2 bg-gray-700 hover:bg-gray-600 rounded-lg"
124+
>
125+
Step ▶
126+
</button>
127+
128+
<button
129+
onClick={reset}
130+
className="px-4 py-2 bg-red-600 hover:bg-red-700 rounded-lg"
131+
>
132+
Reset
133+
</button>
134+
135+
<div className="flex items-center gap-3 ml-auto">
136+
<label className="text-sm text-gray-400">Speed</label>
137+
<input
138+
type="range"
139+
min="50"
140+
max="1500"
141+
value={speed}
142+
onChange={e => setSpeed(Number(e.target.value))}
143+
/>
144+
<span className="text-xs">{speed}ms</span>
145+
</div>
146+
</div>
147+
</div>
148+
149+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
150+
151+
<div className="bg-[#1a1a1a] p-5 rounded-2xl shadow-md border border-gray-800">
152+
<h3 className="text-lg font-semibold text-blue-300">Array State</h3>
153+
154+
<div className="flex gap-3 mt-4">
155+
{displayedArray.map((v, i) => (
156+
<div
157+
key={i}
158+
className={`px-4 py-3 bg-[#111] border rounded-xl text-xl shadow
159+
transition-all duration-200
160+
${
161+
i === highlight.i || i === highlight.j
162+
? "bg-yellow-500 text-black scale-110"
163+
: "border-gray-700"
164+
}`}
165+
>
166+
{v}
167+
</div>
168+
))}
169+
</div>
170+
171+
<div className="mt-4 text-sm text-gray-300 space-y-1">
172+
<div><strong>Step:</strong> {index} / {steps.length}</div>
173+
<div><strong>Status:</strong> {status}</div>
174+
<div><strong>Depth:</strong> {depth}</div>
175+
</div>
176+
</div>
177+
<div className="bg-[#1a1a1a] p-5 rounded-2xl shadow-md border border-gray-800">
178+
<h3 className="text-lg font-semibold text-green-300">Generated Permutations</h3>
179+
180+
<div className="mt-4 flex flex-col gap-2 max-h-64 overflow-auto pr-2">
181+
{permutations.map((p, i) => (
182+
<div key={i} className="text-sm bg-[#111] border border-gray-700 p-2 rounded-lg">
183+
{p.join(", ")}
184+
</div>
185+
))}
186+
</div>
187+
</div>
188+
</div>
189+
<div className="mt-6 bg-[#1a1a1a] p-5 rounded-2xl shadow-md border border-gray-800 max-h-60 overflow-auto">
190+
<h3 className="text-lg font-semibold text-purple-300 mb-3">All Steps</h3>
191+
192+
{steps.map((s, i) => (
193+
<div
194+
key={i}
195+
className={`p-2 rounded-lg mb-1 transition
196+
${
197+
i === index - 1
198+
? "bg-[#333] border-l-4 border-blue-500"
199+
: "bg-[#111]"
200+
}`}
201+
>
202+
<strong>{i + 1}.</strong> {s.type} — [{s.array.join(", ")}] (depth {s.depth})
203+
</div>
204+
))}
205+
</div>
206+
</div>
207+
</div>
208+
);
209+
}

src/pages/Recursion/RecursionPage.jsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Sudoku from "./sudokuSolver";
66
import TowerOfHanoi from "./towerOfHanoi";
77
import SubsetSum from "./SubsetSum";
88
import FloodFillPage from "./FloodFill";
9+
import PermutationsPage from "./permutations";
910
export default function RecursionPage() {
1011
const [selectedAlgo, setSelectedAlgo] = useState("");
1112
const [sidebarOpen, setSidebarOpen] = useState(true);
@@ -48,6 +49,12 @@ export default function RecursionPage() {
4849
<FloodFillPage />
4950
</div>
5051
)
52+
case "Permutations":
53+
return(
54+
<div className="w-full p-4 overflow-auto">
55+
<PermutationsPage />
56+
</div>
57+
)
5158
default:
5259
return (
5360
<div className="flex flex-col items-center justify-center text-center p-6 min-h-screen bg-gray-900 text-gray-300">
@@ -94,6 +101,7 @@ export default function RecursionPage() {
94101
<option value="TowerofHanoi">Tower of Hanoi</option>
95102
<option value="SubsetSum">Subset Sum</option>
96103
<option value="FloodFill">Flood Fill</option>
104+
<option value="Permutations">Permutations</option>
97105
</select>
98106

99107
<button
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from "react";
2+
import PermutationsVisualizer from "../../components/Recursion/PermutationsVisualizer";
3+
4+
export default function PermutationsPage() {
5+
return (
6+
<div className="min-h-screen bg-white p-6">
7+
<PermutationsVisualizer />
8+
</div>
9+
);
10+
}

0 commit comments

Comments
 (0)