diff --git a/discription.md b/discription.md new file mode 100644 index 0000000..2b7060e --- /dev/null +++ b/discription.md @@ -0,0 +1,43 @@ +## Algorithms Visualizer + +Algorithms Visualizer is a comprehensive web application designed to visualize various algorithms without relying on any specific UI library. It's built using React and offers an interactive platform to understand and observe the behaviors of different algorithms in real-time. + +### Features: + +1. **Path Finding:** + + - **Concepts:** Representing a grid as an implicit graph where each cell denotes a node. + - **Search Algorithms:** Implementations of Depth-First Search, Breadth-First Search, A\* Search, and Dijkstra. + - **Pattern Generation Algorithms:** Includes Basic random, Randomized DFS, Recursive division, Kruskal's Algorithm, and Prim's Algorithm. + - **User Interaction:** Users can draw wall nodes, drag and drop source/target nodes, and control animation speed. + +2. **Sorting:** + + - **Concepts:** Bars representing positive integer values compared for ascending order. + - **Sorting Algorithms:** Bubble sort, Selection sort, Insertion sort, Quick sort, Merge sort. + - **User Controls:** Adjust bar sizes, generate new random bars, and control animation speed. + +3. **Spiral Prime:** + + - **Concepts:** Grid displaying positive integer numbers checked for primality. + - **Features:** Counting total prime numbers, creating a spiral from the center of the grid. + +4. **N Queen Problem:** + - **Concepts:** Chess board representation where queens are placed and checked for mutual attacks. + - **Features:** Resize the chess board and control animation speed. + +### How to Use: + +The visualizer is accessible via [Live Demo](https://suaebahmed.github.io/algorithms-visualizer/), offering an interactive experience to explore and understand various algorithms visually. + +### Installation: + +Detailed installation instructions can be found in the project repository to set up the visualizer locally and explore its functionalities. + +### Challenges Faced: + +The development process involved tackling complexities in algorithm implementation while ensuring a seamless and intuitive user interface for effective visualization. + +### Future Enhancements: + +Plans include expanding the range of algorithms and optimizing the user experience to offer a more intuitive and informative platform for algorithm exploration. diff --git a/src/Pages/PathfindingVS.jsx b/src/Pages/PathfindingVS.jsx index f0a2978..601a47b 100644 --- a/src/Pages/PathfindingVS.jsx +++ b/src/Pages/PathfindingVS.jsx @@ -8,7 +8,7 @@ import Dijkstra from "../algorithm/path/dijkstra"; import Randomized_dfs from "../algorithm/maze/randomized_dfs"; import recursiveDivision from "../algorithm/maze/recursive_division"; import Navbar from "../components/Navbar"; -import Modal from "../components/Modal"; +// import Modal from "../components/Modal"; import { KruskalAlgorithm } from "../algorithm/maze/kruskal-algorithm"; import { PrimsAlgorithm } from "../algorithm/maze/prim's-algorithm"; import { CostomCheckBox } from "../components/Costom-checkbox.tsx"; @@ -19,11 +19,14 @@ super(props);// call the super class constructor and pass in the props parameter */ var rows = 13; var cols = 31; - const CELL_SIZE = 30; -const PADDING = 200; -const MAX_ROW = Math.floor((window.innerHeight - PADDING) / CELL_SIZE); -if (MAX_ROW > rows) rows = MAX_ROW >= 19 ? 19 : MAX_ROW; // Rows = [13, 19] +const PADDING_Y = 200; +const PADDING_X = 300; + +rows = Math.floor((window.innerHeight - PADDING_Y) / CELL_SIZE); +if (rows > 50) rows = 51; // Rows = [13, 50] +cols = Math.floor((window.innerWidth - PADDING_X) / CELL_SIZE); +if (cols > 50) cols = 51; // cols = [31, 50] var START_NODE_ROW = 4, START_NODE_COL = 6; @@ -35,21 +38,22 @@ var INT_END_ROW = END_NODE_ROW, INIT_END_COL = END_NODE_COL; const FAST = 5; -const AVERAGE = 15; -const SLOW = 50; -var animateTime = AVERAGE; // default +const AVERAGE = 30; +const SLOW = 80; +var SPEED = AVERAGE; // default // old value: 8,35,80 function App() { const [Grid, setGrid] = useState([]); // array destructuring const [isMousePress, setIsMousePress] = useState(false); const [animateType, setAnimateTimeType] = useState(2); - const [mazeID, setMazeID] = useState(0); + const [cellSize, setCellSize] = useState(CELL_SIZE); // [20, 35] + const [mazeID, setMazeID] = useState(2); const [pathID, setPathID] = useState(0); useEffect(() => { gridInitialize(); - }, []); + }, [cellSize]); const gridInitialize = () => { var grid = new Array(rows); @@ -72,7 +76,14 @@ function App() { async function animateVisitedNodes(visitedNodes) { for (let i = 0; i < visitedNodes.length; i++) { const node = visitedNodes[i]; - await waitForAnimatoin(animateTime); + await waitForAnimate(SPEED); + document.getElementById( + `row${node.x}_col${node.y}` + ).style.width = `${cellSize}px`; + document.getElementById( + `row${node.x}_col${node.y}` + ).style.height = `${cellSize}px`; + if (node.x === START_NODE_ROW && node.y === START_NODE_COL) document.getElementById(`row${node.x}_col${node.y}`).className = "node-visited START_NODE cursor-grab"; @@ -88,7 +99,14 @@ function App() { pathNode.reverse(); for (let i = 0; i < pathNode.length; i++) { const node = pathNode[i]; - await waitForAnimatoin(animateTime); + await waitForAnimate(SPEED); + document.getElementById( + `row${node.x}_col${node.y}` + ).style.width = `${cellSize}px`; + document.getElementById( + `row${node.x}_col${node.y}` + ).style.height = `${cellSize}px`; + if (i === 0) document.getElementById(`row${node.x}_col${node.y}`).className = "shortestPath START_NODE cursor-grab"; @@ -148,7 +166,7 @@ function App() { (ar[i].r === END_NODE_ROW && ar[i].c === END_NODE_COL) ) continue; - await waitForAnimatoin(animateTime); + await waitForAnimate(SPEED); createWall(ar[i].r, ar[i].c); } }; @@ -250,10 +268,11 @@ function App() { setIsMousePress(() => false); }; const animationTimeHandle = (type) => { - if (type === 1) animateTime = FAST; - else if (type === 2) animateTime = AVERAGE; - else animateTime = SLOW; + if (type === 1) SPEED = FAST; + else if (type === 2) SPEED = AVERAGE; + else SPEED = SLOW; setAnimateTimeType(type); + console.log(SPEED); }; const setStartEndNode = (id, r, c) => { @@ -280,11 +299,20 @@ function App() { } }; - console.log(window.innerHeight, MAX_ROW, rows); + const rangeValueHandle = (event) => { + let value = parseInt(event.target.value); // [0, 15] + setCellSize(value + 20); // [20, 35] + + rows = Math.floor((window.innerHeight - PADDING_Y) / (value + 20)); + if (rows > 50) rows = 50; // Rows = [13, 50] + cols = Math.floor((window.innerWidth - PADDING_X) / (value + 20)); + if (cols > 50) cols = 50; // cols = [31, 50] + (END_NODE_ROW = rows - 6), (END_NODE_COL = cols - 6); + }; return ( <> - + {/*

Video Tutorial

@@ -296,12 +324,12 @@ function App() { title="myVideo" > -
+
*/} -
+
-
-
+
+
-
+
+
+
+ +
+
@@ -352,9 +394,6 @@ function App() { setMazeID(parseInt(e.target.value)); }} > - @@ -367,18 +406,6 @@ function App() { label="Generate Maze" isBgColor /> -
-
-
+
+
-
+
{ setIsMousePress(false); @@ -403,7 +442,7 @@ function App() { {/* JSX Node Of Grid (2D Array) */} {Grid.map((R, idx_r) => { return ( -
+
{R.map((Value, idx_c) => { const { x, y, isStart, isEnd, isWall } = Value; return ( @@ -420,7 +459,8 @@ function App() { onMouseUp, setStartEndNode, }} - > + cellSize={cellSize} + /> ); })}
@@ -459,7 +499,7 @@ class Spot { } } -function Node({ pv }) { +function Node({ pv, cellSize }) { const { x, y, @@ -493,11 +533,12 @@ function Node({ pv }) { var c = parseInt(e.target.attributes.data_y.value); setStartEndNode(id, r, c); }; - + const START_NODE = "START_NODE bg-contain bg-center cursor-grab"; + const END_NODE = "END_NODE bg-contain bg-center cursor-grab"; var classNode = isStart - ? "START_NODE cursor-grab" + ? START_NODE : isEnd - ? "END_NODE cursor-grab" + ? END_NODE : isWall ? "obtacle" : ""; @@ -506,7 +547,13 @@ function Node({ pv }) { if (isStart || isEnd) { return (
+ /> ); } else { return ( @@ -533,7 +580,13 @@ function Node({ pv }) { e.preventDefault(); onMouseUp(); }} - className={"square " + classNode} + className={classNode} + style={{ + width: `${cellSize}px`, + height: `${cellSize}px`, + outline: "1px solid #afd8f8", + backgroundColor: "#fff", + }} id={"row" + x + "_col" + y} data_x={x} data_y={y} @@ -541,16 +594,17 @@ function Node({ pv }) { wall={isWall.toString()} onDrop={drop} onDragOver={allowDrop} - >
+ /> ); } } -async function waitForAnimatoin(time) { +async function waitForAnimate(sp) { + sp = sp < 5 ? 5 : sp; return new Promise((resolve) => { setTimeout(() => { resolve(""); - }, time); + }, sp); }); } const isValid = (r, c) => { diff --git a/src/Pages/PrimeSpiral.jsx b/src/Pages/PrimeSpiral.jsx index 86dad5b..eb417bd 100644 --- a/src/Pages/PrimeSpiral.jsx +++ b/src/Pages/PrimeSpiral.jsx @@ -80,7 +80,7 @@ function PrimeApp() { label="Show Prime spiral" isBgColor /> -
diff --git a/src/algorithm/maze/kruskal-algorithm.js b/src/algorithm/maze/kruskal-algorithm.js index d49449d..43ac8bb 100644 --- a/src/algorithm/maze/kruskal-algorithm.js +++ b/src/algorithm/maze/kruskal-algorithm.js @@ -1,116 +1,120 @@ -var dx = [+2,-2,0,0] -var dy = [0,0,+2,-2] +var dx = [+2, -2, 0, 0]; +var dy = [0, 0, +2, -2]; var vis = []; // represent grid var visitedNodes = []; -export const KruskalAlgorithm = (N,M)=>{ - visitedNodes = []; - vis = new Array(N); - for(let i=0; i { + visitedNodes = []; + vis = new Array(N); + for (let i = 0; i < N; i++) { + let arr = []; + for (let j = 0; j < M; j++) { + arr.push(false); } - RunKruskal(N,M); - return visitedNodes; -} + vis[i] = arr; + } + RunKruskal(N, M); + return visitedNodes; +}; -const RunKruskal = (N,M) =>{ - let edges = []; - // push all egde of the grid - for(let i=0; i=2) edges.push({x1: i, y1: j-2, x2: i, y2: j}); - if(i>=2) edges.push({x1: i-2, y1: j, x2: i, y2: j}); - } +const RunKruskal = (N, M) => { + let edges = []; + // push all egde of the grid + for (let i = 0; i < N; i += 2) { + for (let j = 0; j < M; j += 2) { + if (j >= 2) edges.push({ x1: i, y1: j - 2, x2: i, y2: j }); + if (i >= 2) edges.push({ x1: i - 2, y1: j, x2: i, y2: j }); } - Build(N*100+M+5); - while(edges.length > 0){ - // select random edge - let id = Math.floor((Math.random()*100)%edges.length); - let px = edges[id].x1; - let py = edges[id].y1; - let cx = edges[id].x2; - let cy = edges[id].y2; + } + Build(N * 100 + M + 5); + while (edges.length > 0) { + // select random edge + let id = Math.floor((Math.random() * 100) % edges.length); + let px = edges[id].x1; + let py = edges[id].y1; + let cx = edges[id].x2; + let cy = edges[id].y2; - edges.splice(id,1); // remove edge from list + edges.splice(id, 1); // remove edge from list - // check if they are in same component - const a = Find(px*100+py); - const b = Find(cx*100+cy); - if(a !== b){ - goForward(px,py,cx,cy); - Union(a,b); - } + // check if they are in same component + const a = Find(px * 100 + py); + const b = Find(cx * 100 + cy); + if (a !== b) { + goForward(px, py, cx, cy); + Union(a, b); } -} + } +}; -export function goForward(pr,pc,r,c){ - if(r===pr){ // same row - if(c < pc) for(let i=pc; i>=c; i--){ - if(vis[r][i]) continue; - visitedNodes.push({r,c:i}); - vis[r][i] = true; - } - else for(let i=pc; i<=c; i++){ - if(vis[r][i]) continue; - visitedNodes.push({r,c:i}); - vis[r][i] = true; - } - } - else{ - if(r < pr) for(let i=pr; i>=r; i--){ - if(vis[i][c]) continue; - visitedNodes.push({r:i,c}); - vis[i][c] = true; - } - else for(let i=pr; i<=r; i++){ - if(vis[i][c]) continue; - visitedNodes.push({r:i,c}); - vis[i][c] = true; - } - } +export function goForward(pr, pc, r, c) { + if (r === pr) { + // same row + if (c < pc) + for (let i = pc; i >= c; i--) { + if (vis[r][i]) continue; + visitedNodes.push({ r, c: i }); + vis[r][i] = true; + } + else + for (let i = pc; i <= c; i++) { + if (vis[r][i]) continue; + visitedNodes.push({ r, c: i }); + vis[r][i] = true; + } + } else { + if (r < pr) + for (let i = pr; i >= r; i--) { + if (vis[i][c]) continue; + visitedNodes.push({ r: i, c }); + vis[i][c] = true; + } + else + for (let i = pr; i <= r; i++) { + if (vis[i][c]) continue; + visitedNodes.push({ r: i, c }); + vis[i][c] = true; + } + } } -export function getNeighbours(top,N,M){ - let arr = []; - for(let i=0; i<4; i++){ - let x = top.x + dx[i]; - let y = top.y + dy[i]; - if(x>=0 && y>=0 && x= 0 && y >= 0 && x < N && y < M && !vis[x][y]) { + arr.push([x, y]); } - return arr; + } + return arr; } /* MXN = 100*Row + Column MOD = 100 - Max Row = 20 + Max Row = 99 Max Column = 99 - So, MAX N = 20 * 100 + 99 = 2099 + So, MAX N = 99 * 100 + 99 = 9999 */ -const MXN = 2100; +const MXN = 10000; var p = new Array(MXN); var sz = new Array(MXN); -const Build = (n) =>{ - for(let i=0; i<=n; i++){ - p[i] = i; - sz[i] = 1; - } -} -const Find = (x) =>{ - return x===p[x]?x:p[x]=Find(p[x]); -} -const Union = (a,b) =>{ - a = Find(a); - b = Find(b); - if(sz[a] < sz[b]) [a,b] = [b,a]; - p[b] = a; - sz[a] += sz[b]; -} +const Build = (n) => { + for (let i = 0; i <= n; i++) { + p[i] = i; + sz[i] = 1; + } +}; +const Find = (x) => { + return x === p[x] ? x : (p[x] = Find(p[x])); +}; +const Union = (a, b) => { + a = Find(a); + b = Find(b); + if (sz[a] < sz[b]) [a, b] = [b, a]; + p[b] = a; + sz[a] += sz[b]; +}; diff --git a/src/components/Btn.tsx b/src/components/Btn.tsx index 4993a12..a34dfa5 100644 --- a/src/components/Btn.tsx +++ b/src/components/Btn.tsx @@ -15,7 +15,7 @@ export const Button = forwardRef( return (