diff --git a/public/graph.png b/public/graph.png
new file mode 100644
index 0000000..95eaef6
Binary files /dev/null and b/public/graph.png differ
diff --git a/src/App.jsx b/src/App.jsx
index bb325e8..f4a6d32 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,15 +1,18 @@
import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
-import UnionFindPage from "../src/pages/graph/UnionFind.jsx"; // ✅ Import Union-Find Page
+// import UnionFindPage from "../src/pages/graph/UnionFind.jsx"; // ✅ Import Union-Find Page
import SortingPage from "./pages/sorting/SortingPage";
+import GraphPage from "./pages/graph/GraphPage";
import Homepage from "./pages/Homepage.jsx";
+
function App() {
return (
} />
- } /> {/* ✅ Added route */}
+ {/* } /> */}
} />
+ } />
);
diff --git a/src/algorithms/graph/bellmanFord.js b/src/algorithms/graph/bellmanFord.js
new file mode 100644
index 0000000..e89e302
--- /dev/null
+++ b/src/algorithms/graph/bellmanFord.js
@@ -0,0 +1,37 @@
+export default function runBellmanFord(nodes, edges, source) {
+ const dist = {};
+ nodes.forEach(n => dist[n] = Infinity);
+ dist[source] = 0;
+
+ const steps = [];
+
+ // Relax edges |V|-1 times
+ for (let i = 0; i < nodes.length - 1; i++) {
+ for (const edge of edges) {
+ const { from, to, weight } = edge;
+ const step = {
+ type: "relax",
+ iteration: i + 1,
+ edge,
+ prevDistance: dist[to]
+ };
+
+ if (dist[from] + weight < dist[to]) {
+ dist[to] = dist[from] + weight;
+ step.updatedDistance = dist[to];
+ }
+
+ steps.push(step);
+ }
+ }
+
+ // Check for negative weight cycles
+ for (const edge of edges) {
+ const { from, to, weight } = edge;
+ if (dist[from] + weight < dist[to]) {
+ steps.push({ type: "negativeCycle", edge });
+ }
+ }
+
+ return steps;
+}
diff --git a/src/components/graph/BellmanFordGraph.jsx b/src/components/graph/BellmanFordGraph.jsx
new file mode 100644
index 0000000..023b19e
--- /dev/null
+++ b/src/components/graph/BellmanFordGraph.jsx
@@ -0,0 +1,317 @@
+import React, { useState, useEffect, useMemo } from "react";
+
+export default function BellmanFordGraph({ nodes = [], edges = [], distances = {}, highlight = {} }) {
+ const [positions, setPositions] = useState({});
+
+ // Arrange nodes in a circle when nodes change
+ useEffect(() => {
+ if (nodes.length === 0) return;
+
+ const radius = 180;
+ const centerX = 300;
+ const centerY = 250;
+ const newPositions = {};
+ nodes.forEach((node, index) => {
+ const angle = (2 * Math.PI * index) / nodes.length;
+ newPositions[node] = {
+ x: centerX + radius * Math.cos(angle),
+ y: centerY + radius * Math.sin(angle),
+ };
+ });
+ setPositions(newPositions);
+ }, [nodes]);
+
+ // ✅ Memoize dummy nodes and edges at top level
+ const dummyGraph = useMemo(() => {
+ const dummyNodes = Array.from({ length: 6 }).map((_, i) => {
+ const radius = 180;
+ const centerX = 300;
+ const centerY = 250;
+ const angle = (2 * Math.PI * i) / 6;
+ return {
+ id: i,
+ x: centerX + radius * Math.cos(angle),
+ y: centerY + radius * Math.sin(angle),
+ };
+ });
+
+ const dummyEdges = Array.from({ length: 8 }).map(() => {
+ const u = Math.floor(Math.random() * 6);
+ const v = (u + 1 + Math.floor(Math.random() * 5)) % 6;
+ return { u, v };
+ });
+
+ return { dummyNodes, dummyEdges };
+ }, []); // runs only once
+
+ return (
+
+
+
+
+
+ {/* Result / Details Panel */}
+
+
📊 Algorithm Details
+
+ {Object.keys(distances).length === 0 ? (
+
+ Run the algorithm to see node distances and steps here.
+
+ ) : (
+ <>
+ {highlight && highlight.type && (
+
+ {highlight.type === "relax" && (
+
+ Iteration {highlight.iteration}: Relaxing edge{" "}
+ {highlight.edge.u} → {highlight.edge.v}
+
+ )}
+ {highlight.type === "skip" && (
+
+ Iteration {highlight.iteration}: Skipped edge{" "}
+ {highlight.edge.u} → {highlight.edge.v}
+
+ )}
+ {highlight.type === "negative-cycle" && (
+
+ ❌ Negative weight cycle detected on edge{" "}
+ {highlight.edge.u} → {highlight.edge.v}
+
+ )}
+ {highlight.type === "done" && (
+
+ ✅ Algorithm finished. Final distances updated!
+
+ )}
+
+ )}
+
+
+ {nodes.map((n) => (
+
+ Node {n}
+
+ {distances[n] === undefined || distances[n] === Infinity ? "∞" : distances[n]}
+
+
+ ))}
+
+ >
+ )}
+
+
+
+
+ );
+}
diff --git a/src/pages/Homepage.jsx b/src/pages/Homepage.jsx
index a846dc8..a1ecca0 100644
--- a/src/pages/Homepage.jsx
+++ b/src/pages/Homepage.jsx
@@ -36,10 +36,9 @@ const sections = [
description:
"Explore BFS, DFS, Kruskal’s, Prim’s, and now Union-Find — all brought to life interactively.",
phase: "Phase 2",
- img: "",
- route: "/graph/union-find", // ✅ Route to Union-Find page
- link: "/graphs",
- flag: true
+ img: "/graph.png",
+ link: "/graph",
+ flag: false
},
{
title: "Recursion & Backtracking",
diff --git a/src/pages/graph/BellmanFord.jsx b/src/pages/graph/BellmanFord.jsx
new file mode 100644
index 0000000..43ad0e8
--- /dev/null
+++ b/src/pages/graph/BellmanFord.jsx
@@ -0,0 +1,248 @@
+import React, { useState } from "react";
+import { Toaster, toast } from "react-hot-toast";
+import BellmanFordGraph from "../../components/graph/BellmanFordGraph";
+
+// Bellman-Ford generator function
+function* bellmanFord(nodes, edges, source) {
+ const dist = {};
+ nodes.forEach((n) => (dist[n] = Infinity));
+ dist[source] = 0;
+
+ for (let i = 0; i < nodes.length - 1; i++) {
+ let updated = false;
+ for (let { u, v, w } of edges) {
+ if (dist[u] !== Infinity && dist[u] + w < dist[v]) {
+ dist[v] = dist[u] + w;
+ updated = true;
+ yield { type: "relax", iteration: i + 1, edge: { u, v, w }, dist: { ...dist } };
+ } else {
+ yield { type: "skip", iteration: i + 1, edge: { u, v, w }, dist: { ...dist } };
+ }
+ }
+ if (!updated) break;
+ }
+
+ // Negative cycle check
+ for (let { u, v, w } of edges) {
+ if (dist[u] !== Infinity && dist[u] + w < dist[v]) {
+ yield { type: "negative-cycle", edge: { u, v, w } };
+ return;
+ }
+ }
+
+ yield { type: "done", dist };
+}
+
+export default function BellmanFord() {
+ const [numNodes, setNumNodes] = useState(0);
+ const [nodes, setNodes] = useState([]);
+ const [edges, setEdges] = useState([]);
+ const [source, setSource] = useState(null);
+ const [distances, setDistances] = useState({});
+ const [highlight, setHighlight] = useState(null);
+ const [isRunning, setIsRunning] = useState(false);
+
+ // Edge input state
+ const [fromNode, setFromNode] = useState("");
+ const [toNode, setToNode] = useState("");
+ const [weight, setWeight] = useState("");
+
+ // Generate nodes automatically
+ const handleGenerateNodes = () => {
+ if (numNodes < 2) {
+ toast.error("Please select at least 2 nodes!");
+ return;
+ }
+ const generated = Array.from({ length: numNodes }, (_, i) =>
+ String.fromCharCode(65 + i)
+ );
+ setNodes(generated);
+ setEdges([]);
+ setSource(generated[0]);
+ setDistances({});
+ setHighlight(null);
+ };
+
+ // Add or edit edge
+ const handleAddEdge = () => {
+ if (!fromNode || !toNode || !weight) {
+ toast.error("Fill all edge fields!");
+ return;
+ }
+ const existingIndex = edges.findIndex(
+ (e) => e.u === fromNode && e.v === toNode
+ );
+ const newEdge = { u: fromNode, v: toNode, w: parseInt(weight) };
+ if (existingIndex >= 0) {
+ const updatedEdges = [...edges];
+ updatedEdges[existingIndex] = newEdge;
+ setEdges(updatedEdges);
+ } else {
+ setEdges([...edges, newEdge]);
+ }
+ setFromNode("");
+ setToNode("");
+ setWeight("");
+ };
+
+ // Run Bellman-Ford visualization
+ const handleStart = async () => {
+ if (isRunning) return;
+ if (!source) {
+ toast.error("Select a source node!");
+ return;
+ }
+
+ setIsRunning(true);
+ const gen = bellmanFord(nodes, edges, source);
+ for (let step of gen) {
+ setHighlight(step);
+ if (step.dist) setDistances(step.dist);
+ await new Promise((r) => setTimeout(r, 800));
+ if (step.type === "negative-cycle") {
+ toast.error(`Negative cycle detected on edge ${step.edge.u} → ${step.edge.v}`);
+ break;
+ }
+ }
+ setIsRunning(false);
+ };
+
+ const handleReset = () => {
+ setDistances({});
+ setHighlight(null);
+ setEdges([]);
+ };
+
+ // Load example graph
+ const handleLoadExample = () => {
+ const exampleNodes = ["A", "B", "C", "D", "E", "F"];
+ const exampleEdges = [
+ { u: "A", v: "B", w: 2 },
+ { u: "A", v: "C", w: 5 },
+ { u: "B", v: "C", w: 1 },
+ { u: "B", v: "D", w: 2 },
+ { u: "C", v: "E", w: 3 },
+ { u: "D", v: "E", w: 1 },
+ { u: "E", v: "F", w: 2 },
+ ];
+ setNodes(exampleNodes);
+ setEdges(exampleEdges);
+ setSource("A");
+ setDistances({});
+ setHighlight(null);
+ setNumNodes(6);
+ };
+
+ return (
+
+
+
+ Bellman–Ford Visualizer 🚀
+
+
+
+ setNumNodes(parseInt(e.target.value))}
+ className="p-2 rounded-lg text-purple-900 bg-gray-100"
+ />
+
+
+
+
+ {nodes.length > 0 && (
+
+
+ {nodes.map((n, idx) => (
+
+ {n}
+
+ ))}
+
+
+
+
+
+ setWeight(e.target.value)}
+ className="p-2 rounded-lg text-gray-900 bg-white"
+ />
+
+
+
+
+
+
+
+
+ )}
+
+
+
+
+ );
+}
diff --git a/src/pages/graph/GraphPage.jsx b/src/pages/graph/GraphPage.jsx
new file mode 100644
index 0000000..f70ccd9
--- /dev/null
+++ b/src/pages/graph/GraphPage.jsx
@@ -0,0 +1,98 @@
+import React, { useState } from "react";
+import { Network, Compass, Rocket } from "lucide-react";
+import BellmanFord from "./BellmanFord";
+import UnionFindPage from "./UnionFind";
+// import Dijkstra from "./Dijkstra";
+// import Kruskal from "./Kruskal";
+
+export default function GraphPage() {
+ const [selectedAlgo, setSelectedAlgo] = useState("");
+
+ const renderAlgorithm = () => {
+ switch (selectedAlgo) {
+ case "bellman-ford":
+ return (
+
+
+
+ );
+ case "union-find":
+ return (
+
+
+
+ );
+ // case "dijkstra":
+ // return ;
+ // case "kruskal":
+ // return ;
+ default:
+ return (
+
+
+
+
+
+
+
+ Graph Algorithm Visualizer
+
+
+ Select a graph algorithm from the sidebar to begin visualization.
+ Watch how edges, nodes, and distances transform step by step! 🧠✨
+
+
+
+
+
+
+
+
+ );
+ }
+ };
+
+ return (
+
+ {/* Sidebar */}
+
+
+ Graph Panel
+
+
+
+
+
+
+
+
+ ← Back to Home
+
+
+
+ {/* Visualization Area */}
+
+
+ {renderAlgorithm()}
+
+
+
+ );
+}