├── .env.example ├── .eslintignore ├── .eslintrc.json ├── .github └── CODEOWNERS ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc.json ├── CHANGELOG.md ├── FAQ.md ├── LICENSE ├── README.md ├── SECURITY.md ├── __test__ └── HomeComponent.test.tsx ├── jest.config.ts ├── jest.setup.ts ├── next.config.mjs ├── package-lock.json ├── package.json ├── postcss.config.mjs ├── public ├── next.svg └── vercel.svg ├── src ├── app │ ├── algorithm │ │ ├── linked-list │ │ │ ├── detectCycle.ts │ │ │ ├── mergeTwoSortedList.ts │ │ │ ├── reverseList.ts │ │ │ └── singlyLinkedListBasics.ts │ │ ├── path-finding │ │ │ ├── noOfValidIslands.ts │ │ │ └── uniquePath.ts │ │ ├── searching │ │ │ ├── binarySearch.ts │ │ │ └── linearSearch.ts │ │ ├── shortest-path │ │ │ ├── bellmanFordShortestPath.ts │ │ │ ├── dijkstraShortestPath.ts │ │ │ └── floydWarshall.ts │ │ ├── sorting │ │ │ ├── bubbleSort.ts │ │ │ ├── heapSort.ts │ │ │ ├── mergeSort.ts │ │ │ ├── quickSort.ts │ │ │ └── selectionSort.ts │ │ ├── sudoku-solver │ │ │ └── sudokuSolver.ts │ │ └── treeTraversalTechnique │ │ │ ├── bfsTraversal.ts │ │ │ ├── inOrderTraversal.ts │ │ │ ├── postOrderTraversal.ts │ │ │ └── preOrderTraversal.ts │ ├── components │ │ ├── Tree │ │ │ └── TreeComponent.tsx │ │ ├── home │ │ │ └── HomeComponent.tsx │ │ ├── layouts │ │ │ ├── footer │ │ │ │ └── FooterComponent.tsx │ │ │ └── header │ │ │ │ └── HeaderComponent.tsx │ │ ├── linked-list │ │ │ ├── DetectCycle.tsx │ │ │ ├── LinkedListBasics.tsx │ │ │ ├── LinkedListComponent.tsx │ │ │ ├── MergeTwoSortedList.tsx │ │ │ └── ReverseLinkedList.tsx │ │ ├── n-queen │ │ │ └── ChessBoard.tsx │ │ ├── pathFind │ │ │ ├── NoOfIslands.tsx │ │ │ ├── PathFind.tsx │ │ │ ├── ShortestPath.tsx │ │ │ └── UniquePath.tsx │ │ ├── searching │ │ │ ├── BinarySearchTreeComponent.tsx │ │ │ ├── LinearSearchComponent.tsx │ │ │ └── SearchingComponent.tsx │ │ ├── sorting │ │ │ ├── BubbleSortComponent.tsx │ │ │ ├── HeapSortComponent.tsx │ │ │ ├── MergeSortComponent.tsx │ │ │ ├── QuickSortComponent.tsx │ │ │ ├── SelectionSortComponent.tsx │ │ │ └── SortingComponent.tsx │ │ └── sudoku-solver │ │ │ ├── SudoKuSolver.tsx │ │ │ └── SudoKuSolverComponent.tsx │ ├── constant.ts │ ├── data-structure │ │ ├── LinkedList │ │ │ └── LinkedList.ts │ │ ├── Tree │ │ │ ├── Node.ts │ │ │ └── TreeNode.ts │ │ └── minHeap │ │ │ └── MinHeap.ts │ ├── data │ │ ├── PathFindingGridData.ts │ │ ├── SortData.ts │ │ ├── dashboardSchemaData.ts │ │ ├── linkedListData.ts │ │ ├── mockData.ts │ │ ├── shortestPathData.ts │ │ └── sudokuData.ts │ ├── favicon.ico │ ├── globals.scss │ ├── layout.tsx │ ├── lib │ │ ├── calculateSvgLinePosition.ts │ │ ├── graph.ts │ │ ├── helpers.ts │ │ ├── mapUtils.ts │ │ ├── nQueens.ts │ │ ├── sleepMethod.ts │ │ ├── sudokuHelperMethod.ts │ │ └── uidGenerator.ts │ ├── linked-list │ │ └── page.tsx │ ├── n-queens │ │ └── page.tsx │ ├── not-found.tsx │ ├── page.tsx │ ├── path-finding │ │ └── page.tsx │ ├── searching │ │ └── page.tsx │ ├── sorting │ │ └── page.tsx │ ├── sudoku-solver │ │ └── page.tsx │ ├── tree │ │ └── page.tsx │ ├── types │ │ ├── NQueensProps.ts │ │ ├── TreeTypeProps.ts │ │ ├── commonProps.ts │ │ ├── linkedListProps.ts │ │ ├── shortestPathProps.ts │ │ ├── sortingProps.ts │ │ ├── sudokyProps.ts │ │ └── uniquePathProps.ts │ └── utils │ │ ├── StatusColorsPlate.tsx │ │ ├── TreeBFSTraversal.tsx │ │ └── TreeDFSTraversal.tsx └── middleware.ts ├── tailwind.config.ts └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlaminPu1007/algorithm-visualizer/21845e972dd8e2378cbcd16accc5ae8cdd37acb2/.env.example -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | coverage/ 4 | *.json 5 | *.css 6 | out -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | /* 2 | Configure eslint for nextJs 3 | Read more about it: https://dev.to/azadshukor/setting-up-nextjs-13-with-typescript-eslint-47an 4 | Read about env : https://eslint.org/docs/latest/use/configure/language-options-deprecated#using-configuration-files 5 | */ 6 | { 7 | "env": { 8 | "browser": true, 9 | "node": true, 10 | "jest": true 11 | }, 12 | "extends": [ 13 | "next/core-web-vitals", 14 | "eslint:recommended", 15 | "plugin:@typescript-eslint/recommended", 16 | "plugin:testing-library/react", // for jest unit testing 17 | "plugin:jest-dom/recommended" // for jest unit testing 18 | ], 19 | "parser": "@typescript-eslint/parser", 20 | "plugins": ["@typescript-eslint"], 21 | "rules": { 22 | // Note: you must disable the base rule as it can report incorrect errors 23 | // instead we enabled -> @typescript-eslint/no-unused-vars 24 | "no-unused-vars": "off", 25 | "@typescript-eslint/no-unused-vars": "error", 26 | "react/jsx-no-bind": [ 27 | "error", 28 | { 29 | "allowArrowFunctions": true, 30 | "allowBind": false, 31 | "ignoreRefs": true 32 | } 33 | ], 34 | "semi": "error", 35 | "prefer-const": "error", 36 | "no-console": "warn", 37 | "react/no-did-update-set-state": "error", 38 | "react/no-unknown-property": "error", 39 | "react/no-unused-prop-types": "error", 40 | "react/prop-types": "error", 41 | "react/react-in-jsx-scope": "off", 42 | "react-hooks/rules-of-hooks": "error", 43 | "react-hooks/exhaustive-deps": "warn", 44 | 45 | // ES6 and Beyond 46 | // "arrow-body-style": ["error", "as-needed"], 47 | // "arrow-parens": ["error", "always"], 48 | "no-var": "error", 49 | "prefer-arrow-callback": "error", 50 | 51 | // Code Readability and Consistency 52 | "indent": ["error", 2], 53 | // "quotes": ["error", "single", "backtick"], 54 | // "camelcase": "error", 55 | 56 | // Error Prevention 57 | "no-undef": "error", 58 | "eqeqeq": "error", 59 | "no-implicit-coercion": "error", 60 | "no-unused-expressions": "error", 61 | "no-extra-boolean-cast": "error", 62 | "no-eval": "error" 63 | }, 64 | "root": true 65 | } 66 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Code owners for the entire repository 2 | * @AlaminPu1007 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | .env*.production 31 | .env*.development 32 | 33 | # vercel 34 | .vercel 35 | 36 | # typescript 37 | *.tsbuildinfo 38 | next-env.d.ts -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npm run format && npm run lint && git add -A . 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "bracketSpacing": true, 4 | "endOfLine": "lf", 5 | "semi": true, 6 | "tabWidth": 2, 7 | "singleQuote": true, 8 | "jsxSingleQuote": true, 9 | "plugins": ["prettier-plugin-tailwindcss"], 10 | "printWidth": 120 11 | } 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.6.0 (Oct 15, 2024) 4 | 5 | - **Floyd Warshall Algorithm:** Implemented the Floyd warshall algorithm for finding the shortest path in a weighted graph. 6 | - **Loading State Management:** Added loading state management during the execution of the algorithm. 7 | - **Error Handling:** Implemented error handling to log errors in development mode. 8 | 9 | ## 1.5.5 (Oct 10, 2024) 10 | 11 | - **Bellman-Ford Algorithm:** Implemented the Bellman-Ford algorithm for finding the shortest path in a weighted graph. 12 | - **Loading State Management:** Added loading state management during the execution of the algorithm. 13 | - **Error Handling:** Implemented error handling to log errors in development mode. 14 | 15 | ## 1.4.4 (Oct 09, 2024) 16 | 17 | Handle error on sudoku solver component. 18 | 19 | ## 1.4.3 (Oct 07, 2024) 20 | 21 | Sudoku solver stop visualization functionality is integrated. 22 | 23 | ## 1.4.2 (Oct 07, 2024) 24 | 25 | Improved some UI in footer component & Home component. 26 | 27 | ## 1.4.0 (Oct 07, 2024) 28 | 29 | ### Added 30 | 31 | - Basic functionality for users to input Sudoku puzzles. 32 | - Visualization of the solving process with step-by-step highlights of cell updates. 33 | - Reset and submit buttons for user interaction. 34 | 35 | ### Changed 36 | 37 | - Updated styles to improve the visual appearance of the Sudoku grid. 38 | - Optimized performance for larger grids to enhance rendering speed. 39 | 40 | ### Fixed 41 | 42 | - Corrected errors in the random number generation function to ensure valid placements. 43 | - Fixed accessibility issues for keyboard navigation in the grid. 44 | 45 | ## 1.3.0 (Oct 03, 2024) 46 | 47 | - **Detect cycle in linked list :** Implemented a new feature for linked lists to visualize if a list contains a cycle. 48 | 49 | ## 1.2.0 (Sep 26, 2024) 50 | 51 | - Home component hero section is integrated. 52 | 53 | ## 1.1.0 (Sep 26, 2024) 54 | 55 | ### New Features: 56 | 57 | - **Dijkstra's Algorithm Visualization:** Added a new visualization for Dijkstra’s shortest path algorithm with interactive graph support. 58 | - **Graph Coupling:** Implemented a feature allowing users to create coupled graphs, enhancing visualization of connected nodes and paths. 59 | 60 | ### Linked List Features: 61 | 62 | - **Create Linked List:** Introduced functionality to create linked lists and interact with nodes dynamically. 63 | - **CRUD Operations for Linked List:** Implemented Create, Read, Update, and Delete (CRUD) operations for managing linked list nodes. 64 | - **Reverse Linked List:** Added a feature to reverse the linked list, showcasing the process step-by-step. 65 | - **Merge Two Sorted Linked Lists:** Developed a feature to merge two sorted linked lists into one while maintaining sorted order. 66 | 67 | ## 1.0.0 (Sep 09, 2024) 68 | 69 | - Initial release with visualizations for unique path finding, N-Queens problem, tree and graph traversals, and sorting algorithms. 70 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | ## How do I install the project? 2 | 3 | Follow the installation instructions in the [README.md](README.md). 4 | 5 | ## How do I run tests? 6 | 7 | Use `npm test` or `yarn test` to run the unit tests. 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024, Md. Al Amin. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algorithm Visualizations 2 | 3 | A Next.js 14 project for visualizing famous algorithms using React, TypeScript, and Tailwind CSS. This project includes visualizations for various algorithms such as unique path finding, N-Queens problem, tree or graph traversals, and more. 4 | 5 | ## Features 6 | 7 | - **Path Finding Visualization**: Visualize algorithms for finding paths in a grid, including: 8 | 9 | 1. **Unique Path Finding**: Solve the unique paths problem in a grid. 10 | 2. **Number of Islands Problem**: Visualize the algorithm to count the number of islands. 11 | 3. **Shortest Path Finding**: Implementations of `Bellman-Ford`, `Floyd Warshall` and `Dijkstra's` algorithms for shortest path calculations. 12 | 13 | - **N-Queens Problem**: Interactive visualization of the N-Queens problem, demonstrating various solutions and techniques. 14 | - **Tree and Graph Traversals**: Visualize traversal algorithms including depth-first search (DFS) with in-order, pre-order, and post-order techniques, as well as breadth-first search (BFS). 15 | - **Sorting Algorithms**: Visualize five sorting algorithms, including merge sort, quick sort, heap sort (with a tree graph visualization), selection sort, and bubble sort. 16 | - **Interactive UI**: Built with React and styled using Tailwind CSS, providing a user-friendly interface for exploring algorithms. 17 | - **Linked List Operations** : 18 | 19 | 1. **Basic Operations** : Create, find, and delete nodes in a linked list. 20 | 2. **Reverse Linked List** : Visualize the reversal of a linked list 21 | 3. **Merge Two Sorted Lists** : Visualize the merging of two sorted linked lists 22 | 4. **Cycle Detection** : Implement and visualize a cycle detection algorithm in linked lists to see if a list contains a cycle. 23 | 24 | - **Sudoku Solver**: Introduced an interactive visualization for the `Sudoku Solver problem`, allowing users to create and customize their own Sudoku boards. 25 | 26 | ## Getting Started 27 | 28 | ### Prerequisites 29 | 30 | - Node.js (v18 or higher) 31 | - npm 32 | 33 | ### Installation 34 | 35 | 1. Clone the repository: 36 | 37 | ```bash {"id":"01J7AT1ZH6GZWCDTK6XKYD4YYK"} 38 | git clone https://github.com/AlaminPu1007/algorithm-visualizer 39 | 40 | ``` 41 | 42 | 2. Navigate to the project directory: 43 | 44 | ```bash {"id":"01J7AT1ZH6GZWCDTK6XQA42VZP"} 45 | cd algorithm-visualizer 46 | 47 | ``` 48 | 49 | 3. Install dependencies: 50 | 51 | ```bash {"id":"01J7AT1ZH6GZWCDTK6XTGEA3YQ"} 52 | npm install 53 | 54 | ``` 55 | 56 | 4. Start the development server: 57 | 58 | ```sh {"id":"01JA7DBZ9NEQ04ND8EJW745P39"} 59 | npm run dev 60 | ``` 61 | 62 | The application will be available at http://localhost:3000. 63 | 64 | ### Usage 65 | 66 | - Navigate to the specific visualization from the home page. 67 | - Use the provided controls to interact with the algorithms and view their visualizations. 68 | 69 | ## License 70 | 71 | This project is licensed under the [MIT License](https://choosealicense.com/licenses/mit/). See the [LICENSE](LICENSE) file for details. 72 | 73 | ## Acknowledgments 74 | 75 | 1. **Next.js**: For providing a powerful React framework. 76 | 2. **Tailwind CSS**: For enabling easy and flexible styling. 77 | 3. **TypeScript**: For adding type safety to the project. 78 | 4. **Jest**: For providing a robust framework for unit testing. 79 | 80 | ## Contact 81 | 82 | For any questions or inquiries, please open an issue on GitHub or contact us at [alamin66.sit@gmail.com](mailto:alamin66.sit@gmail.com). 83 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting Security Issues 2 | 3 | If you discover a security vulnerability, please report it by opening a private issue or contacting us at [alamin66.sit@gmail.com](mailto:alamin66.sit@gmail.com). 4 | 5 | ## Security Practices 6 | 7 | We follow standard security practices to ensure the safety of the project and its users. 8 | -------------------------------------------------------------------------------- /__test__/HomeComponent.test.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Write a test case for home page 3 | */ 4 | 5 | import { render, screen } from '@testing-library/react'; 6 | import Page from '../src/app/page'; 7 | 8 | describe('Home component', () => { 9 | it('Should have a Hello World text', () => { 10 | render(); 11 | const getText = screen.getByText('Hello world!'); 12 | expect(getText).toBeInTheDocument(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | import nextJest from 'next/jest.js'; 3 | 4 | const createJestConfig = nextJest({ 5 | // Provide the path to your Next.js app to load next.config.js and .env files in your test environment 6 | dir: './', 7 | }); 8 | 9 | // Add any custom config to be passed to Jest 10 | const config: Config = { 11 | coverageProvider: 'v8', 12 | testEnvironment: 'jsdom', 13 | // Add more setup options before each test is run 14 | setupFilesAfterEnv: ['/jest.setup.ts'], 15 | }; 16 | 17 | // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async 18 | export default createJestConfig(config); 19 | -------------------------------------------------------------------------------- /jest.setup.ts: -------------------------------------------------------------------------------- 1 | /* 2 | This file contains common setup logic to be executed before running each test file in Jest. 3 | It initializes any necessary configurations, mocks, or environment setups required for testing purposes. 4 | Developers can define global setup functions, such as setting up mock modules or configuring test environments, 5 | to ensure consistent behavior across all tests in the project. 6 | */ 7 | 8 | import '@testing-library/jest-dom'; 9 | 10 | // do setup once, for entire other test files also 11 | //This setup is necessary because IntersectionObserver isn't available in the test environment 12 | 13 | beforeAll(() => { 14 | // IntersectionObserver isn't available in test environment 15 | const mockIntersectionObserver = jest.fn(); 16 | mockIntersectionObserver.mockReturnValue({ 17 | observe: () => null, 18 | unobserve: () => null, 19 | disconnect: () => null, 20 | }); 21 | window.IntersectionObserver = mockIntersectionObserver; 22 | }); 23 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "algorithm-visualizer", 3 | "version": "1.6.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "eslint --fix src && prettier --check .", 10 | "prepare": "husky install", 11 | "format": "prettier --write --ignore-path .gitignore .", 12 | "format:fix": "prettier --write --ignore-path .gitignore .", 13 | "test": "jest", 14 | "test:watch": "jest --watch" 15 | }, 16 | "author": { 17 | "name": "Md. Alamin", 18 | "email": "alamin66.sit@gmail.com", 19 | "url": "https://showcase-alamin.vercel.app/" 20 | }, 21 | "dependencies": { 22 | "next": "14.2.5", 23 | "react": "^18", 24 | "react-dom": "^18", 25 | "react-toastify": "^10.0.5", 26 | "sass": "^1.77.8" 27 | }, 28 | "devDependencies": { 29 | "@testing-library/jest-dom": "^6.4.8", 30 | "@testing-library/react": "^16.0.0", 31 | "@testing-library/user-event": "^14.5.2", 32 | "@types/jest": "^29.5.12", 33 | "@types/node": "^20", 34 | "@types/react": "^18", 35 | "@types/react-dom": "^18", 36 | "@typescript-eslint/eslint-plugin": "^7.17.0", 37 | "@typescript-eslint/parser": "^7.17.0", 38 | "autoprefixer": "^10.4.19", 39 | "eslint": "^8", 40 | "eslint-config-next": "14.2.5", 41 | "eslint-plugin-jest-dom": "^5.4.0", 42 | "eslint-plugin-react-hooks": "^4.6.2", 43 | "eslint-plugin-testing-library": "^6.2.2", 44 | "husky": "^8.0.0", 45 | "jest": "^29.7.0", 46 | "jest-environment-jsdom": "^29.7.0", 47 | "postcss": "^8", 48 | "prettier": "3.3.3", 49 | "prettier-plugin-tailwindcss": "^0.6.5", 50 | "tailwindcss": "^3.4.1", 51 | "ts-jest": "^29.2.3", 52 | "ts-node-dev": "^2.0.0", 53 | "typescript": "^5" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/algorithm/linked-list/mergeTwoSortedList.ts: -------------------------------------------------------------------------------- 1 | import { LINKED_LIST_NODE_START_CY } from '@/app/constant'; 2 | import { TreeNode } from '@/app/data-structure/Tree/Node'; 3 | import { Sleep } from '@/app/lib/sleepMethod'; 4 | import React from 'react'; 5 | 6 | /** 7 | * Visualizes the current node in the given list by setting the isCurrent flag. 8 | * @async 9 | * @param {TreeNode} node - The current node to visualize. 10 | * @param {Function} setListState - The state setter function for the list (setListOne or setListTwo). 11 | * @returns {Promise} 12 | */ 13 | export const visualizeCurrentNode = async ( 14 | node: TreeNode, 15 | setListState: React.Dispatch>, 16 | speedRange: number 17 | ): Promise => { 18 | setListState((previousList: TreeNode | null | undefined) => { 19 | const clonedList = JSON.parse(JSON.stringify(previousList)); 20 | let currentNode: TreeNode | null = clonedList; 21 | 22 | while (currentNode) { 23 | currentNode.isCurrent = currentNode.id === node.id; // Highlight the current node 24 | currentNode = currentNode.next; 25 | } 26 | 27 | return clonedList; 28 | }); 29 | 30 | await Sleep(speedRange); // Delay for visualization 31 | 32 | // Reset the isCurrent flag after visualization 33 | setListState((previousList: TreeNode | null | undefined) => { 34 | const clonedList = JSON.parse(JSON.stringify(previousList)); 35 | let currentNode: TreeNode | null = clonedList; 36 | 37 | while (currentNode) { 38 | currentNode.isCurrent = false; // Reset all nodes to not current 39 | currentNode = currentNode.next; 40 | } 41 | 42 | return clonedList; 43 | }); 44 | }; 45 | 46 | /** 47 | * Processes the remaining nodes in a list and merges them into the merged list. 48 | * @async 49 | * @param {TreeNode} remainingList - The remaining nodes to process. 50 | * @param {Function} setListState - The state setter function for the list (setListOne or setListTwo). 51 | * @param {TreeNode | null} mergedListTail - The current tail of the merged list. 52 | * @param {number} currentXPosition - The current X position for placing the nodes. 53 | * @param {TreeNode} dummyHeadNode - The dummy head node for the merged list. 54 | * @returns {Promise} 55 | */ 56 | export const processRemainingNodes = async ( 57 | remainingList: TreeNode | null, 58 | setListState: React.Dispatch>, 59 | mergedListTail: TreeNode | null, 60 | currentXPosition: number, 61 | dummyHeadNode: TreeNode, 62 | speedRange: number, 63 | setReverseNodes: React.Dispatch> 64 | ): Promise => { 65 | while (remainingList) { 66 | await visualizeCurrentNode(remainingList, setListState, speedRange); 67 | 68 | remainingList.cx = currentXPosition; 69 | remainingList.cy = LINKED_LIST_NODE_START_CY; 70 | 71 | mergedListTail!.next = { ...remainingList, next: null }; // Safely assign the next node 72 | mergedListTail = mergedListTail!.next; // Advance the merged list tail 73 | remainingList = remainingList.next; // Move to the next node 74 | 75 | currentXPosition += 25; // Increment the position for the next node 76 | 77 | if (mergedListTail) { 78 | mergedListTail.isTarget = true; // Mark as target for visualization 79 | } 80 | 81 | setReverseNodes(() => ({ ...(dummyHeadNode.next as TreeNode) })); // Update the merged list visualization 82 | await Sleep(speedRange); // Add delay for visualization 83 | } 84 | }; 85 | 86 | /** 87 | * Resets the status of all nodes in a list by clearing the isCurrent flag. 88 | * @param {Function} setListState - The state setter function for the list (setListOne or setListTwo). 89 | */ 90 | export const resetNodeStatus = ( 91 | setListState: React.Dispatch> 92 | ): void => { 93 | setListState((previousList: TreeNode | null | undefined) => { 94 | const clonedList = JSON.parse(JSON.stringify(previousList)); 95 | let currentNode: TreeNode | null = clonedList; 96 | 97 | while (currentNode) { 98 | currentNode.isCurrent = false; // Reset all nodes to not current 99 | currentNode = currentNode.next; 100 | } 101 | 102 | return clonedList; 103 | }); 104 | }; 105 | -------------------------------------------------------------------------------- /src/app/algorithm/linked-list/reverseList.ts: -------------------------------------------------------------------------------- 1 | import { LINKED_LIST_NODE_START_CX } from '@/app/constant'; 2 | import { TreeNode } from '@/app/data-structure/Tree/Node'; 3 | import { Sleep } from '@/app/lib/sleepMethod'; 4 | import { ITreeNode } from '@/app/types/TreeTypeProps'; 5 | import React from 'react'; 6 | 7 | /** 8 | * Recursively traverses a linked list and highlights each node as it is visited. 9 | * 10 | * @param {TreeNode | null} currentNode - The current node to be processed in the list. 11 | * @param {React.Dispatch>} updateRoot - Function to update the root node for re-rendering. 12 | * @param {number} delayDuration - The delay in milliseconds to visualize the node traversal. 13 | * 14 | * @returns {Promise} - A promise that resolves after all nodes have been processed. 15 | */ 16 | export const traverseLinkedListRecursively = async ( 17 | currentNode: TreeNode | null, 18 | updateRoot: React.Dispatch>, 19 | delayDuration: number 20 | ): Promise => { 21 | // Return early if the node is null 22 | if (!currentNode) return; 23 | 24 | // Highlight the current node 25 | updateRoot((previousRoot) => { 26 | const clonedRoot = JSON.parse(JSON.stringify(previousRoot)); 27 | let nodeIterator: TreeNode | null = clonedRoot as TreeNode; 28 | 29 | while (nodeIterator) { 30 | // Set the isCurrent property of the current node to true, others to false 31 | nodeIterator.isCurrent = nodeIterator.id === currentNode.id; 32 | nodeIterator = nodeIterator.next; 33 | } 34 | return clonedRoot; 35 | }); 36 | 37 | // Delay for visualizing the current node 38 | await Sleep(delayDuration); 39 | 40 | // Reset the current node highlight 41 | currentNode.isCurrent = false; 42 | updateRoot((previousRoot) => { 43 | const clonedRoot = JSON.parse(JSON.stringify(previousRoot)); 44 | let nodeIterator: TreeNode | null = clonedRoot as TreeNode; 45 | 46 | while (nodeIterator) { 47 | // Reset isCurrent property to false 48 | if (nodeIterator.id === currentNode.id) { 49 | nodeIterator.isCurrent = false; 50 | } 51 | nodeIterator = nodeIterator.next; 52 | } 53 | return clonedRoot; 54 | }); 55 | 56 | // Recursively process the next node 57 | await traverseLinkedListRecursively(currentNode.next, updateRoot, delayDuration); 58 | }; 59 | 60 | /** 61 | * Reverses a linked list and updates the visual position of each node. 62 | * 63 | * @param {TreeNode | null} currentNode - The current node to start reversing from. 64 | * @param {number} totalNodes - The total number of nodes in the list. 65 | * @param {React.Dispatch>} setReversedList - Function to update the state of the reversed list for re-rendering. 66 | * @param {number} delayDuration - The delay in milliseconds to visualize each step of reversing. 67 | * 68 | * @returns {Promise} - The new head of the reversed list. 69 | */ 70 | export const reverseLinkedListWithPositions = async ( 71 | currentNode: TreeNode | null, 72 | totalNodes: number, 73 | setReversedList: React.Dispatch>, 74 | delayDuration: number 75 | ): Promise => { 76 | let previousNode: TreeNode | null = null; 77 | let positionIndex = 0; // Track the position index of nodes 78 | const nodeSpacing = 25; // Horizontal spacing between each node 79 | const startXPosition = LINKED_LIST_NODE_START_CX; // Initial x-coordinate for the first node 80 | 81 | // Reverse the linked list and update the position of each node 82 | while (currentNode) { 83 | const nextNode = currentNode.next; // Temporarily store the next node 84 | 85 | // Reverse the current node's next pointer 86 | currentNode.next = previousNode; 87 | 88 | // Update the x-coordinate (cx) of the node based on its new position in the reversed list 89 | currentNode.cx = startXPosition + (totalNodes - positionIndex - 1) * nodeSpacing; 90 | 91 | // Mark the current node as the target node and update the list 92 | previousNode = currentNode; 93 | currentNode.isTarget = true; 94 | setReversedList(JSON.parse(JSON.stringify(previousNode))); 95 | 96 | // Delay to visualize the node reversal process 97 | await Sleep(delayDuration); 98 | 99 | // Un-mark the current node and update the list again 100 | currentNode.isTarget = false; 101 | setReversedList(JSON.parse(JSON.stringify(previousNode))); 102 | 103 | // Move to the next node in the original list 104 | currentNode = nextNode; 105 | 106 | // Increment the position index for the next node 107 | positionIndex++; 108 | } 109 | 110 | // Return the new head of the reversed linked list 111 | return previousNode; 112 | }; 113 | -------------------------------------------------------------------------------- /src/app/algorithm/path-finding/noOfValidIslands.ts: -------------------------------------------------------------------------------- 1 | import { del_col, del_row } from '@/app/constant'; 2 | import { islandColorsPlate } from '@/app/data/mockData'; 3 | import { isValidDirection } from '@/app/lib/helpers'; 4 | import { Sleep } from '@/app/lib/sleepMethod'; 5 | import { GridProps, PathFindingQueueProps } from '@/app/types/uniquePathProps'; 6 | import React from 'react'; 7 | 8 | let counter = 0; 9 | 10 | /** 11 | * Performs a Breadth-First Search (BFS) to find and mark islands in a grid. 12 | * An island is defined as a connected group of cells with value `1`. 13 | * The function modifies the grid to mark visited cells and visualizes the process. 14 | * 15 | * @async 16 | * @function findNoOfIslands 17 | * @param {number} row - The current row index. 18 | * @param {number} col - The current column index. 19 | * @param {GridProps[][]} data - The grid representing land (1) and water (0) cells. 20 | * @param {{ rowIdx: number; colIdx: number }[]} queue - The queue used for BFS traversal. 21 | * @param {React.Dispatch>} setData - React state setter for updating the grid. 22 | * @param {React.Dispatch>} setQueue - React state setter for updating the BFS queue. 23 | * @param {number} speedRange - The delay in milliseconds to control the speed of the BFS visualization. 24 | * @returns {Promise} A Promise that resolves once the island is fully traversed. 25 | */ 26 | export const findNoOfIslands = async ( 27 | row: number, 28 | col: number, 29 | data: GridProps[][], 30 | queue: { rowIdx: number; colIdx: number }[], 31 | setData: React.Dispatch>, 32 | setQueue: React.Dispatch>, 33 | speedRange: number 34 | ): Promise => { 35 | try { 36 | const n: number = data.length; // Number of rows 37 | const m: number = data[0]?.length; // Number of columns 38 | 39 | // Clone data and queue to avoid mutating original state directly 40 | const tempData = [...data]; 41 | const tempQueue = [...queue]; 42 | 43 | // Generate a unique color for this island 44 | const islandColor = islandColorsPlate[counter % 20]; 45 | // update counter 46 | counter++; 47 | 48 | // Add the starting cell to the queue 49 | const newElement = { rowIdx: row, colIdx: col }; 50 | tempQueue.unshift(newElement); 51 | 52 | // Mark the starting cell as visited and as part of a valid path 53 | tempData[row][col].isVisit = true; 54 | tempData[row][col].isValidPath = true; 55 | tempData[row][col].islandColor = islandColor; 56 | 57 | // Update the state with the new grid and queue 58 | setData([...tempData]); 59 | setQueue([...tempQueue]); 60 | 61 | // Wait before continuing to visualize the changes 62 | await Sleep(speedRange); 63 | 64 | // Perform BFS to explore the entire island 65 | while (tempQueue.length > 0) { 66 | // Get the next cell to explore from the front of the queue 67 | const element = tempQueue.shift(); 68 | 69 | if (element !== undefined) { 70 | const { rowIdx, colIdx } = element; 71 | 72 | // Explore the four possible directions (up, down, left, right) 73 | for (let i = 0; i < 4; i++) { 74 | const new_row = del_row[i] + rowIdx; // New row index after moving in the current direction 75 | const new_col = del_col[i] + colIdx; // New column index after moving in the current direction 76 | 77 | // Check if the new position is within bounds and hasn't been visited, and is land (1) 78 | if ( 79 | isValidDirection(new_row, new_col, n, m) && 80 | !tempData[new_row][new_col].isVisit && 81 | tempData[new_row][new_col].data === 1 82 | ) { 83 | // Mark the new cell as visited and as the current cell being processed 84 | tempData[new_row][new_col].isVisit = true; 85 | tempData[new_row][new_col].isCurrent = true; 86 | 87 | // Set the parent cell for potential backtracking 88 | tempData[new_row][new_col].parent = { 89 | rowIdx: row, 90 | colIdx: col, 91 | }; 92 | // Assign the same color to the entire island 93 | tempData[new_row][new_col].islandColor = islandColor; 94 | 95 | // Add the new cell to the queue for further exploration 96 | tempQueue.unshift({ rowIdx: new_row, colIdx: new_col }); 97 | 98 | // Update the state with the new queue and grid 99 | setQueue([...tempQueue]); 100 | setData([...tempData]); 101 | 102 | // Wait to visualize the changes 103 | await Sleep(speedRange); 104 | 105 | // Reset the current cell state after processing 106 | tempData[new_row][new_col].isCurrent = false; 107 | tempData[new_row][new_col].isValidPath = true; 108 | 109 | // Update the state to reflect the reset 110 | setData([...tempData]); 111 | } 112 | } 113 | } 114 | } 115 | } catch (error) { 116 | // Handle errors during development 117 | if (process.env.NODE_ENV === 'development') { 118 | // eslint-disable-next-line no-console 119 | console.log(error, 'Error during BFS traversal'); 120 | } 121 | } 122 | }; 123 | -------------------------------------------------------------------------------- /src/app/algorithm/path-finding/uniquePath.ts: -------------------------------------------------------------------------------- 1 | import { del_col, del_row, directions } from '@/app/constant'; 2 | import { isValidDirection } from '@/app/lib/helpers'; 3 | import { Sleep } from '@/app/lib/sleepMethod'; 4 | import { GridProps } from '@/app/types/uniquePathProps'; 5 | import React from 'react'; 6 | import { toast } from 'react-toastify'; 7 | /** 8 | * Finds unique paths from the top-left to the bottom-right corner of a grid using Depth-First Search (DFS). 9 | * 10 | * This function recursively explores all possible paths in the grid, marking the valid path and updating the state 11 | * of the grid at each step. It also handles visualization by changing the state of each cell and tracing back the path 12 | * once a valid path is found. 13 | * 14 | * @param {GridProps[][]} tempData - The grid data representing the current state of the grid cells. 15 | * @param {string[]} paths - An array to store the unique paths found during the search. 16 | * @param {number} n - The number of rows in the grid. 17 | * @param {number} m - The number of columns in the grid. 18 | * @param {number} row - The current row index in the grid. 19 | * @param {number} col - The current column index in the grid. 20 | * @param {string} path - The current path being explored. 21 | * @param {number} speedRange - The delay in milliseconds for visualization purposes. 22 | * @param {React.Dispatch>} setData - Function to update the state of the grid data. 23 | * 24 | * @returns {Promise} A promise that resolves when the DFS traversal is complete. 25 | */ 26 | 27 | export const DFSFindUniquePathMethod = async ( 28 | tempData: GridProps[][], 29 | paths: string[], 30 | n: number, 31 | m: number, 32 | row: number, 33 | col: number, 34 | path: string, 35 | speedRange: number, 36 | setData: React.Dispatch>, 37 | setValidPaths: React.Dispatch> 38 | ) => { 39 | // Handle the base case: if the destination is reached 40 | if (row === n - 1 && col === m - 1) { 41 | // Reached the destination 42 | paths.push(path.slice(0, path?.length - 2)); 43 | toast.success(`One valid path is found`, { autoClose: 1500, position: 'top-left' }); 44 | 45 | // store into state also 46 | setValidPaths((prv) => [...prv, { id: Math.random() * 99999, path: path.slice(0, path?.length - 2) }]); 47 | 48 | // Trace back the valid path to visualize 49 | let current = { rowIdx: row, colIdx: col }; 50 | 51 | // Create a deep copy of the grid to trace the path 52 | const pathData = tempData.map((row) => row.map((item) => ({ ...item }))); 53 | 54 | // Mark the path as valid 55 | while (current.rowIdx !== -1 && current.colIdx !== -1) { 56 | pathData[current.rowIdx][current.colIdx].isValidPath = true; 57 | current = tempData[current.rowIdx][current.colIdx].parent; 58 | 59 | setData([...pathData]); 60 | await Sleep(speedRange); 61 | } 62 | 63 | await Sleep(speedRange + speedRange); 64 | 65 | // Reset the path marking 66 | current = { rowIdx: row, colIdx: col }; // Reset current to the end of the path 67 | 68 | while (current.rowIdx !== -1 && current.colIdx !== -1) { 69 | pathData[current.rowIdx][current.colIdx].isValidPath = false; 70 | current = pathData[current.rowIdx][current.colIdx].parent; 71 | 72 | setData([...pathData]); // Update state with reset pathData 73 | await Sleep(speedRange); 74 | } 75 | 76 | return; 77 | } 78 | 79 | // Explore all 4 possible directions 80 | for (let i = 0; i < 4; i++) { 81 | const new_row = del_row[i] + row; 82 | const new_col = del_col[i] + col; 83 | 84 | // Check if the new cell is within bounds and not visited 85 | if (isValidDirection(new_row, new_col, n, m) && !tempData[new_row][new_col].isVisit) { 86 | if (!tempData[new_row][new_col].data) { 87 | // Handle cells with no data if needed 88 | } else { 89 | // Move to cells with data 90 | tempData[new_row][new_col].isVisit = true; 91 | tempData[new_row][new_col].isCurrent = true; 92 | 93 | // Set parent for backtracking 94 | tempData[new_row][new_col].parent = { 95 | rowIdx: row, 96 | colIdx: col, 97 | }; 98 | 99 | setData([...tempData]); 100 | await Sleep(speedRange); 101 | 102 | // Use a local path variable to track the current path 103 | const newPath = path + directions[i % 4] + '->'; 104 | 105 | // Recursively explore further 106 | await DFSFindUniquePathMethod( 107 | tempData, 108 | paths, 109 | n, 110 | m, 111 | new_row, 112 | new_col, 113 | newPath, 114 | speedRange, 115 | setData, 116 | setValidPaths 117 | ); 118 | 119 | // Backtrack: Reset the state of the current cell 120 | tempData[new_row][new_col].isCurrent = false; 121 | tempData[new_row][new_col].isVisit = false; 122 | 123 | setData([...tempData]); 124 | } 125 | } 126 | } 127 | }; 128 | -------------------------------------------------------------------------------- /src/app/algorithm/searching/binarySearch.ts: -------------------------------------------------------------------------------- 1 | import { Sleep } from '@/app/lib/sleepMethod'; 2 | import { ITreeNode } from '@/app/types/TreeTypeProps'; 3 | import React from 'react'; 4 | 5 | /** 6 | * Performs a binary search on a binary search tree (BST) and visually updates the state at each step of the search. 7 | * This function highlights the current node being searched and marks nodes that are not part of the search path. 8 | * 9 | * @async 10 | * @function performBST 11 | * @param {ITreeNode | null} data - The root node of the binary search tree. Can be `null` if the tree is empty. 12 | * @param {React.Dispatch>} setData - Function to update the state of the tree data. 13 | * @param {number} speedRange - The delay time (in milliseconds) between each step of the search for visualization purposes. 14 | * @param {number} target - The value to search for in the binary search tree. 15 | * 16 | * @returns {Promise} A promise that resolves after the search is completed or rejected in case of an error. 17 | */ 18 | export const performBST = async ( 19 | data: ITreeNode | null, 20 | setData: React.Dispatch>, 21 | speedRange: number, 22 | target: number 23 | ): Promise => { 24 | try { 25 | // Return if the tree is empty 26 | if (!data) return; 27 | 28 | // Clone the data to avoid directly mutating the state 29 | const updatedData = { ...data }; 30 | 31 | /** 32 | * Helper function that recursively searches the BST for the target value. 33 | * 34 | * @async 35 | * @function searchBST 36 | * @param {ITreeNode | null} node - The current node being searched. 37 | * @param {number} target - The target value to find in the tree. 38 | * @returns {Promise} The node containing the target value, or `null` if not found. 39 | */ 40 | const searchBST = async (node: ITreeNode | null, target: number): Promise => { 41 | if (!node) return null; 42 | 43 | // Mark the current node as being actively searched 44 | node.isCurrent = true; 45 | setData({ ...updatedData }); // Trigger a re-render to visually update the node 46 | await Sleep(speedRange); // Pause to visualize the step 47 | 48 | // If the current node's value matches the target, mark it as the target 49 | if (node.value === target) { 50 | node.isCurrent = false; 51 | node.isTarget = true; 52 | setData({ ...updatedData }); 53 | await Sleep(speedRange); // Pause to visualize the step 54 | 55 | return node; 56 | } 57 | 58 | // If the target value is smaller than the current node, search the left subtree 59 | if (target < Number(node.value)) { 60 | markInvalid(node.right); // Mark the right subtree as invalid 61 | setData({ ...updatedData }); 62 | await Sleep(speedRange); // Pause to visualize the step 63 | 64 | return await searchBST(node.left, target); 65 | } 66 | // Otherwise, search the right subtree 67 | else { 68 | markInvalid(node.left); // Mark the left subtree as invalid 69 | setData({ ...updatedData }); 70 | await Sleep(speedRange); // Pause to visualize the step 71 | 72 | return await searchBST(node.right, target); 73 | } 74 | }; 75 | 76 | // Start the binary search from the root node 77 | await searchBST(updatedData, target); 78 | } catch (error) { 79 | // Log the error only during development 80 | if (process.env.NODE_ENV === 'development') { 81 | // eslint-disable-next-line no-console 82 | console.error(error, 'from bst catch error'); 83 | } 84 | } 85 | }; 86 | 87 | /** 88 | * Marks a node and its subtrees as invalid during the binary search. 89 | * This visually indicates that the node is not part of the correct search path. 90 | * 91 | * @async 92 | * @function markInvalid 93 | * @param {ITreeNode | null} node - The node to mark as invalid. If `null`, the function returns immediately. 94 | */ 95 | const markInvalid = async (node: ITreeNode | null): Promise => { 96 | if (!node) return; 97 | 98 | // Mark the node as invalid 99 | node.isInvalid = true; 100 | 101 | // Recursively mark the left and right subtrees as invalid 102 | if (node.left) markInvalid(node.left); 103 | if (node.right) markInvalid(node.right); 104 | }; 105 | -------------------------------------------------------------------------------- /src/app/algorithm/searching/linearSearch.ts: -------------------------------------------------------------------------------- 1 | import { Sleep } from '@/app/lib/sleepMethod'; 2 | import { LinearSearchDataProps } from '@/app/types/commonProps'; 3 | import React from 'react'; 4 | import { toast } from 'react-toastify'; 5 | 6 | export const LinearSearchToFindTheTarget = async ( 7 | data: LinearSearchDataProps[], 8 | setSteps: React.Dispatch>, 9 | setData: React.Dispatch>, 10 | setSearchItem: React.Dispatch>, 11 | speedRange: number, 12 | searchItem: number 13 | ) => { 14 | // Create a shallow copy of the data for manipulation 15 | const tempData = [...data]; 16 | 17 | // Iterate through the data array to perform the search 18 | for (let i = 0; i < data.length; i++) { 19 | // Increment the step count for each iteration 20 | setSteps((prev) => prev + 1); 21 | 22 | // Check if the current item matches the search item 23 | if (tempData[i].data === searchItem) { 24 | // Highlight the item as the target 25 | setData(() => { 26 | tempData[i].isTarget = true; 27 | return tempData; 28 | }); 29 | 30 | // Wait for the specified speed before proceeding 31 | await Sleep(speedRange); 32 | 33 | // Show success notification 34 | toast.success(`Target is found at index ${i}`); 35 | 36 | // Set a new random search item for the next search iteration 37 | setSearchItem(Math.floor(Math.random() * data.length) % data.length); 38 | return; 39 | } 40 | 41 | // Highlight the current item being compared 42 | setData(() => { 43 | tempData[i].isCurrent = true; 44 | return tempData; 45 | }); 46 | 47 | // Wait for the specified speed to allow visualization 48 | await Sleep(speedRange); 49 | 50 | // Remove the highlight after comparison 51 | setData(() => { 52 | tempData[i].isCurrent = false; 53 | return tempData; 54 | }); 55 | } 56 | 57 | // If the loop completes without finding the target, show error notification 58 | toast.error(`Target is not found`); 59 | }; 60 | -------------------------------------------------------------------------------- /src/app/algorithm/shortest-path/dijkstraShortestPath.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { MinHeap } from '../../data-structure/minHeap/MinHeap'; 3 | import { Sleep } from '../../lib/sleepMethod'; 4 | import { IGraphEdge } from '../../types/shortestPathProps'; 5 | import { GraphNodesProps } from '@/app/types/sortingProps'; 6 | 7 | /** 8 | * Finds the shortest path between a source and a destination node using Dijkstra's algorithm. 9 | * This function visualizes the algorithm's progress by updating the state of the nodes and edges. 10 | * 11 | * @param {number} source - The ID of the source node. 12 | * @param {number} destination - The ID of the destination node. 13 | * @param {number} nodeSizes - The total number of nodes in the graph. 14 | * @param {number} speedRange - The delay time for animations (in milliseconds). 15 | * @param {React.Dispatch>} setNodes - A state setter function for updating the node states. 16 | * @param {IGraphEdge[]} edges - An array of edges representing the graph. 17 | * @param {React.Dispatch>} setShortestPathEdges - A state setter function for tracking the edges that are part of the shortest path. 18 | * 19 | * @returns {Promise} A promise that resolves when the shortest path has been found and visualized. 20 | */ 21 | export const findShortestPathUsingDijkstra = async ( 22 | source: number, 23 | destination: number, 24 | nodeSizes: number, 25 | speedRange: number, 26 | setNodes: React.Dispatch>, 27 | edges: IGraphEdge[], 28 | setShortestPathEdges: React.Dispatch> 29 | ): Promise => { 30 | try { 31 | // initialized a minHeap 32 | const pq = new MinHeap(); 33 | const distances = Array(nodeSizes).fill(Infinity); 34 | const predecessors = Array(nodeSizes).fill(null); // To track the shortest path 35 | 36 | // Put source node into queue 37 | pq.insert(source, 0); 38 | distances[source] = 0; 39 | 40 | // Visualize the current node being processed 41 | setNodes((prev) => 42 | prev.map((node) => 43 | node.id === source 44 | ? { ...node, isCurrentNode: true, isSource: true, distance: 0 } 45 | : node.id === destination 46 | ? { ...node, isDestination: true } 47 | : node 48 | ) 49 | ); 50 | // Animation delay 51 | await Sleep(speedRange); 52 | // Reset isCurrentNode after processing 53 | setNodes((prev) => prev.map((node) => (node.id === source ? { ...node, isCurrentNode: false } : node))); 54 | 55 | while (!pq.isEmpty()) { 56 | const { node: currentNodeId } = pq.extractMin()!; 57 | 58 | // If we reached the destination, break the loop 59 | if (currentNodeId === destination) { 60 | break; 61 | } 62 | 63 | // Iterate through neighbors (edges connected to the current node) 64 | const currentEdges = edges.filter((edge) => edge.source === currentNodeId || edge.target === currentNodeId); 65 | 66 | // iterate over the edges using a for loop to handle async properly 67 | for (const edge of currentEdges) { 68 | const targetNodeId = edge.source === currentNodeId ? edge.target : edge.source; 69 | const newDistance = Math.round(distances[currentNodeId] + edge.weight); 70 | 71 | // If a shorter path to the target node is found 72 | if (newDistance < distances[targetNodeId]) { 73 | // Visualize the current node update 74 | setNodes((prev) => { 75 | return prev.map((node) => 76 | node.id === targetNodeId ? { ...node, isCurrentNode: true, distance: newDistance } : node 77 | ); 78 | }); 79 | 80 | // Wait for some time to simulate animation/visualization delay 81 | await Sleep(speedRange); 82 | 83 | // Optionally reset the node highlight 84 | setNodes((prev) => { 85 | return prev.map((node) => (node.id === targetNodeId ? { ...node, isCurrentNode: false } : node)); 86 | }); 87 | 88 | // Update the distances and insert the new node into the priority queue 89 | distances[targetNodeId] = newDistance; 90 | pq.insert(targetNodeId, newDistance); 91 | // Track the predecessor of the target node 92 | // or keep track of parent node 93 | predecessors[targetNodeId] = currentNodeId; 94 | } 95 | } 96 | } 97 | 98 | // Backtrack to mark the shortest path and edges 99 | let currentNode = destination; 100 | while (currentNode !== null && currentNode !== source) { 101 | const prevNode = predecessors[currentNode]; 102 | if (prevNode !== null) { 103 | // Find the edge that connects currentNode and prevNode 104 | const edge = edges.find( 105 | (e) => 106 | (e.source === currentNode && e.target === prevNode) || (e.source === prevNode && e.target === currentNode) 107 | ); 108 | if (edge) { 109 | setShortestPathEdges((prev) => [...prev, edge]); // Track the edge 110 | } 111 | } 112 | setNodes((prev) => 113 | prev.map((node) => (node.id === currentNode ? { ...node, isShortestPath: true, isDestination: false } : node)) 114 | ); 115 | await Sleep(speedRange); 116 | currentNode = predecessors[currentNode]; 117 | } 118 | setNodes((prev) => 119 | prev.map((node) => (node.id === source ? { ...node, isShortestPath: true, isSource: false } : node)) 120 | ); 121 | } catch (error) { 122 | if (process.env.NODE_ENV === 'development') { 123 | // eslint-disable-next-line no-console 124 | console.log(error); 125 | } 126 | } 127 | }; 128 | -------------------------------------------------------------------------------- /src/app/algorithm/sorting/bubbleSort.ts: -------------------------------------------------------------------------------- 1 | import { Sleep } from '@/app/lib/sleepMethod'; 2 | import { SortingDataProps } from '@/app/types/sortingProps'; 3 | import React from 'react'; 4 | 5 | /** 6 | * A approach of bubble sort algorithm 7 | * 8 | * @async 9 | * @param {SortingDataProps[]} data 10 | * @param {React.Dispatch>} setData 11 | * @param {number} speedRange 12 | * @param {React.Dispatch>} setStep 13 | * @returns {*} 14 | */ 15 | 16 | export const bubbleSortAlgo = async ( 17 | data: SortingDataProps[], 18 | setData: React.Dispatch>, 19 | speedRange: number, 20 | setStep: React.Dispatch> 21 | ) => { 22 | // Create a copy of the data to work with 23 | const tempData: SortingDataProps[] = [...data]; 24 | 25 | for (let i = 0; i < tempData.length; i++) { 26 | for (let j = 0; j < tempData.length - i - 1; j++) { 27 | // Compare two adjacent elements 28 | if (tempData[j].data > tempData[j + 1].data) { 29 | // Swap the elements 30 | [tempData[j], tempData[j + 1]] = [tempData[j + 1], tempData[j]]; 31 | 32 | // Mark the current items as swapped for visualization 33 | setData(() => { 34 | const updatedData = [...tempData]; 35 | updatedData[j].isSwapped = true; 36 | updatedData[j + 1].isSwapped = true; 37 | return updatedData; 38 | }); 39 | 40 | await Sleep(speedRange); 41 | 42 | // After a delay, un-mark the items as swapped 43 | setData(() => { 44 | const updatedData = [...tempData]; 45 | updatedData[j].isSwapped = false; 46 | updatedData[j + 1].isSwapped = false; 47 | return updatedData; 48 | }); 49 | 50 | setStep((prevStep) => prevStep + 1); 51 | } 52 | } 53 | 54 | // Mark the last sorted item as sorted 55 | setData((prv) => { 56 | const tempData = [...prv]; 57 | tempData[prv.length - 1 - i].isSorted = true; 58 | return tempData; 59 | }); 60 | 61 | await Sleep(speedRange); 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /src/app/algorithm/sorting/heapSort.ts: -------------------------------------------------------------------------------- 1 | import { Sleep } from '@/app/lib/sleepMethod'; 2 | import { HeapSortedItemProps } from '@/app/types/sortingProps'; 3 | import { ITreeNode } from '@/app/types/TreeTypeProps'; 4 | import React from 'react'; 5 | 6 | /** 7 | * Performs heap sort on an array of tree nodes. 8 | * 9 | * This function sorts the `tempData` array using the heap sort algorithm, with visualization updates 10 | * at each step to reflect the current, swapped, and sorted states of the nodes. 11 | * 12 | * @param {ITreeNode[]} tempData - The array of tree nodes to be sorted. 13 | * @param {number} n - The number of elements in the array to be sorted. 14 | * @param {number} speedRange - The delay duration (in milliseconds) for visualization updates. 15 | * @param {React.Dispatch>} setData - State setter function for updating the visualization of the tree nodes. 16 | * @param {React.Dispatch>} setSortedData - State setter function for storing the sorted items. 17 | * 18 | * @returns {Promise} A promise that resolves when the heap sort process is complete. 19 | */ 20 | export const HeapSortApproach = async ( 21 | tempData: ITreeNode[], 22 | n: number, 23 | speedRange: number, 24 | setData: React.Dispatch>, 25 | setSortedData: React.Dispatch> 26 | ) => { 27 | /** perform a heap sort */ 28 | // Step 2: Perform heap sort 29 | for (let i = n - 1; i > 0; i--) { 30 | // Swap the root of the heap with the last element 31 | tempData[0].isCurrent = true; 32 | tempData[i].isSwap = true; 33 | 34 | setData([...tempData]); 35 | await Sleep(speedRange); // Delay for visualization 36 | 37 | [tempData[0].value, tempData[i].value] = [tempData[i].value, tempData[0].value]; 38 | 39 | // Mark the last element as sorted 40 | tempData[0].isSwap = false; 41 | tempData[i].isSwap = false; 42 | tempData[i].isSorted = true; 43 | tempData[i].isCurrent = false; 44 | 45 | // stored sorted item 46 | setSortedData((prv) => [{ data: Number(tempData[i].value), id: Number(tempData[i].id) }, ...prv]); 47 | 48 | setData([...tempData]); 49 | await Sleep(speedRange); // Delay for visualization 50 | 51 | // Heapify the root element to get the next largest element 52 | await heapify(tempData, i, 0, speedRange, setData); 53 | 54 | // Reset node states after each iteration 55 | resetNodeStates(tempData); 56 | } 57 | 58 | // Mark the first element as sorted 59 | tempData[0].isSorted = true; 60 | setData([...tempData]); 61 | }; 62 | 63 | /** 64 | * Resets the state of all nodes in the array. 65 | * 66 | * This helper function resets the `isCurrent`, `isSwap`, and `isSorted` states of all nodes 67 | * in the given array. 68 | * 69 | * @param {ITreeNode[]} arr - The array of tree nodes whose states are to be reset. 70 | */ 71 | export const resetNodeStates = (arr: ITreeNode[]) => { 72 | for (const node of arr) { 73 | node.isCurrent = false; 74 | node.isSwap = false; 75 | } 76 | }; 77 | 78 | /** 79 | * Converts the array of tree nodes into a max heap. 80 | * 81 | * This function ensures that the tree nodes in the given array satisfy the max heap property 82 | * by recursively heapifying the affected subtree. 83 | * 84 | * @param {ITreeNode[]} arr - The array of tree nodes to be heapified. 85 | * @param {number} n - The size of the heap. 86 | * @param {number} i - The index of the node to heapify. 87 | * @param {number} speedRange - The delay duration (in milliseconds) for visualization updates. 88 | * @param {React.Dispatch>} setData - State setter function for updating the visualization of the tree nodes. 89 | * 90 | * @returns {Promise} A promise that resolves when the heapify process is complete. 91 | */ 92 | 93 | export const heapify = async ( 94 | arr: ITreeNode[], 95 | n: number, 96 | i: number, 97 | speedRange: number, 98 | setData: React.Dispatch> 99 | ) => { 100 | // get current root node 101 | let largest = i; 102 | 103 | // get it's left child position 104 | const left = 2 * i + 1; 105 | 106 | // get it's right child position 107 | const right = 2 * i + 2; 108 | 109 | if (left < n && Number(arr[left].value) > Number(arr[largest].value)) { 110 | largest = left; 111 | } 112 | 113 | if (right < n && Number(arr[right].value) > Number(arr[largest].value)) { 114 | largest = right; 115 | } 116 | 117 | resetNodeStates(arr); 118 | await Sleep(50); 119 | 120 | if (largest !== i) { 121 | // Mark nodes involved in the swap 122 | arr[i].isSwap = true; 123 | arr[largest].isSwap = true; 124 | setData([...arr]); 125 | await Sleep(speedRange); // Delay for visualization 126 | 127 | // Perform the swap 128 | [arr[i].value, arr[largest].value] = [arr[largest].value, arr[i].value]; 129 | 130 | // Update the visualization with swapped nodes 131 | setData([...arr]); 132 | await Sleep(speedRange); // Delay for visualization 133 | 134 | // Recursively heapify the affected subtree 135 | await heapify(arr, n, largest, speedRange, setData); 136 | } 137 | 138 | // Reset the node states after processing 139 | resetNodeStates(arr); 140 | setData([...arr]); 141 | await Sleep(200); 142 | }; 143 | -------------------------------------------------------------------------------- /src/app/algorithm/sorting/quickSort.ts: -------------------------------------------------------------------------------- 1 | import { Sleep } from '@/app/lib/sleepMethod'; 2 | import { SortingDataProps } from '@/app/types/sortingProps'; 3 | import React from 'react'; 4 | 5 | /** 6 | * Performs the QuickSort algorithm on the provided data array, updating the visualization 7 | * at each step. The algorithm works by recursively partitioning the array around a pivot 8 | * element and sorting the left and right subarrays. 9 | * 10 | * @param {SortingDataProps[]} data - The array of data objects to be sorted, where each object 11 | * contains the data value and visualization state. 12 | * @param {number} low - The starting index of the portion of the array to be sorted. 13 | * @param {number} high - The ending index of the portion of the array to be sorted. 14 | * @param {React.Dispatch>} setStep - Function to update the current step 15 | * in the sorting process, typically used for visualization. 16 | * @param {React.Dispatch>} setData - Function to update the 17 | * state of the data array, reflecting any changes during sorting. 18 | * @param {number} speedRange - The delay in milliseconds for each step of the sorting visualization, 19 | * controlling the speed of the animation. 20 | * @returns {Promise} - A promise that resolves when the sorting process is complete. 21 | */ 22 | 23 | export const quickSortAlgo = async ( 24 | data: SortingDataProps[], 25 | low: number, 26 | high: number, 27 | setStep: React.Dispatch>, 28 | setData: React.Dispatch>, 29 | speedRange: number 30 | ) => { 31 | try { 32 | if (low < high) { 33 | // get current pivot item index 34 | const pivotIdx = await partition(data, low, high, setStep, setData, speedRange); 35 | 36 | // called the left half 37 | await quickSortAlgo(data, low, pivotIdx - 1, setStep, setData, speedRange); 38 | 39 | // called the right half 40 | await quickSortAlgo(data, pivotIdx + 1, high, setStep, setData, speedRange); 41 | } 42 | 43 | // Mark single item as sorted 44 | else if (low === high) { 45 | setData((prevData) => { 46 | const updatedData = [...prevData]; 47 | updatedData[low].isSorted = true; 48 | return updatedData; 49 | }); 50 | 51 | await Sleep(speedRange); 52 | } 53 | 54 | setStep((prev) => prev + 1); 55 | } catch (error) { 56 | if (process.env.NODE_ENV === 'development') { 57 | // eslint-disable-next-line no-console 58 | console.error(error); 59 | } 60 | } 61 | }; 62 | 63 | /** 64 | * Partitions the array around a pivot element, placing elements less than or equal 65 | * to the pivot on the left and elements greater than the pivot on the right. 66 | * 67 | * @param {SortingDataProps[]} dataArray - The array of data objects to be partitioned. 68 | * @param {number} low - The starting index of the portion of the array to be partitioned. 69 | * @param {number} high - The ending index of the portion of the array to be partitioned. 70 | * @param {React.Dispatch>} setStep - Function to update the current step 71 | * in the partitioning process, typically used for visualization. 72 | * @param {React.Dispatch>} setData - Function to update the 73 | * state of the data array, reflecting any changes during partitioning. 74 | * @param {number} speedRange - The delay in milliseconds for each step of the partitioning visualization, 75 | * controlling the speed of the animation. 76 | * @returns {Promise} - A promise that resolves to the index of the pivot element after partitioning. 77 | */ 78 | 79 | const partition = async ( 80 | dataArray: SortingDataProps[], 81 | low: number, 82 | high: number, 83 | setStep: React.Dispatch>, 84 | setData: React.Dispatch>, 85 | speedRange: number 86 | ): Promise => { 87 | let i = low; 88 | let j = high; 89 | const pivot = Number(dataArray[low].data); 90 | 91 | // Clear any previously set pivot as current item 92 | dataArray.forEach((item) => (item.currentItem = false)); 93 | dataArray[low].currentItem = true; 94 | 95 | // Set initial state for the pivot 96 | setData([...dataArray]); 97 | 98 | await Sleep(speedRange); 99 | 100 | while (i < j) { 101 | while (i < high && Number(dataArray[i].data) <= pivot) { 102 | dataArray[i].isLeft = true; 103 | setData([...dataArray]); 104 | await Sleep(speedRange); 105 | 106 | i++; 107 | 108 | dataArray[i - 1].isLeft = false; 109 | setData([...dataArray]); 110 | 111 | setStep((prev) => prev + 1); // Increment comparison count 112 | } 113 | 114 | while (j > low && Number(dataArray[j].data) > pivot) { 115 | dataArray[j].isRight = true; 116 | setData([...dataArray]); 117 | await Sleep(speedRange); 118 | 119 | j--; 120 | 121 | dataArray[j + 1].isRight = false; 122 | setData([...dataArray]); 123 | 124 | setStep((prev) => prev + 1); // Increment comparison count 125 | } 126 | 127 | if (i < j) { 128 | [dataArray[i], dataArray[j]] = [dataArray[j], dataArray[i]]; 129 | setData([...dataArray]); 130 | await Sleep(speedRange); 131 | 132 | setStep((prev) => prev + 1); // Increment swap count 133 | } 134 | } 135 | 136 | [dataArray[low], dataArray[j]] = [dataArray[j], dataArray[low]]; 137 | 138 | // Mark pivot and items in their final position as sorted 139 | dataArray[j].isSorted = true; 140 | setData([...dataArray]); 141 | 142 | await Sleep(speedRange); 143 | 144 | dataArray[j].currentItem = false; 145 | setData([...dataArray]); 146 | 147 | await Sleep(speedRange); 148 | 149 | return j; 150 | }; 151 | -------------------------------------------------------------------------------- /src/app/algorithm/sorting/selectionSort.ts: -------------------------------------------------------------------------------- 1 | import { Sleep } from '@/app/lib/sleepMethod'; 2 | import { SortingDataProps } from '@/app/types/sortingProps'; 3 | import React from 'react'; 4 | 5 | /** 6 | * A selection algorithm visualization to sort the actual data 7 | * 8 | * @async 9 | * @param {SortingDataProps[]} data 10 | * @param {React.Dispatch>} setData 11 | * @param {number} speedRange 12 | * @param {React.Dispatch>} setStep 13 | * @returns {*} 14 | */ 15 | export const selectionSortAlgo = async ( 16 | data: SortingDataProps[], 17 | setData: React.Dispatch>, 18 | speedRange: number, 19 | setStep: React.Dispatch> 20 | ) => { 21 | try { 22 | const tempData: SortingDataProps[] = data; 23 | 24 | for (let i = 0; i < tempData.length; i++) { 25 | let min_idx = i; 26 | 27 | // update current item-index 28 | setData(() => { 29 | const updatedData = [...tempData]; 30 | updatedData[i].currentItem = true; 31 | return updatedData; 32 | }); 33 | 34 | await Sleep(speedRange); 35 | 36 | for (let j = i + 1; j < tempData.length; j++) { 37 | // Increment step for each comparison 38 | setStep((prv) => prv + 1); 39 | 40 | setData(() => { 41 | const updatedData = [...tempData]; 42 | updatedData[j].isCurrentCompareAbleItem = true; 43 | return updatedData; 44 | }); 45 | 46 | await Sleep(speedRange); 47 | 48 | if (tempData[min_idx].data > tempData[j].data) { 49 | // setStep((prv) => prv + 1); 50 | 51 | setData(() => { 52 | const updatedData = [...tempData]; 53 | updatedData[min_idx].isCandidate = false; 54 | 55 | return updatedData; 56 | }); 57 | 58 | await Sleep(speedRange); 59 | 60 | min_idx = j; 61 | 62 | setData(() => { 63 | const updatedData = [...tempData]; 64 | updatedData[min_idx].isCandidate = true; 65 | 66 | return updatedData; 67 | }); 68 | } else { 69 | setData(() => { 70 | const updatedData = [...tempData]; 71 | updatedData[j].isCandidate = false; 72 | 73 | return updatedData; 74 | }); 75 | } 76 | 77 | // do staff for all common thing 78 | setData(() => { 79 | const updatedData = [...tempData]; 80 | updatedData[j].isCurrentCompareAbleItem = false; 81 | 82 | return updatedData; 83 | }); 84 | } 85 | 86 | // new perform a swap operation 87 | if (min_idx !== i) { 88 | // Increment step for the swap operation 89 | setStep((prev) => prev + 1); 90 | 91 | [tempData[i], tempData[min_idx]] = [tempData[min_idx], tempData[i]]; 92 | 93 | setData(() => { 94 | const updateData = [...tempData]; 95 | updateData[i].isSorted = true; 96 | updateData[i].currentItem = false; 97 | updateData[min_idx].currentItem = false; 98 | updateData[i].isCandidate = false; 99 | updateData[min_idx].isCandidate = false; 100 | 101 | return updateData; 102 | }); 103 | } 104 | 105 | setData(() => { 106 | const updatedData = [...tempData]; 107 | updatedData[i].currentItem = false; 108 | updatedData[i].isSorted = true; 109 | return updatedData; 110 | }); 111 | 112 | await Sleep(speedRange); 113 | } 114 | } catch (error) { 115 | if (process.env.NODE_ENV === 'development') { 116 | // eslint-disable-next-line no-console 117 | console.log(error); 118 | } 119 | } 120 | }; 121 | -------------------------------------------------------------------------------- /src/app/algorithm/treeTraversalTechnique/bfsTraversal.ts: -------------------------------------------------------------------------------- 1 | import { TreeNode } from '@/app/data-structure/Tree/Node'; 2 | import { Sleep } from '@/app/lib/sleepMethod'; 3 | import React from 'react'; 4 | 5 | /** 6 | * Performs a Breadth-First Search (BFS) traversal on a binary tree. 7 | * BFS visits each node level by level, starting from the root, and moving horizontally. 8 | * The function uses a queue to explore nodes and updates the state to trigger re-renders for visualization. 9 | * 10 | * @async 11 | * @function traverseBFS 12 | * @param {TreeNode | null} root - The root node of the binary tree. If null, the traversal doesn't start. 13 | * @param {TreeNode | null} currentNode - The current node being visited during traversal. 14 | * @param {React.Dispatch>} setCurrentNode - State setter to update the current node being visited. 15 | * @param {React.Dispatch>>} setVisitedNodes - State setter to update the set of visited nodes by their IDs. 16 | * @param {React.Dispatch>} setCurrentNodes - State setter to update the nodes being visited during BFS for visualization. 17 | * 18 | * @returns {Promise} - A promise that resolves once the traversal is complete. 19 | * 20 | * @example 21 | * // Call BFS traversal starting from the root node and update states for visualization 22 | * traverseBFS(rootNode, null, setCurrentNode, setVisitedNodes, setCurrentNodes); 23 | */ 24 | export const traverseBFS = async ( 25 | root: TreeNode | null, 26 | currentNode: TreeNode | null, 27 | setCurrentNode: React.Dispatch>, 28 | setVisitedNodes: React.Dispatch>>, 29 | setCurrentNodes: React.Dispatch>, 30 | speedRange: number 31 | ) => { 32 | // Queue to manage the BFS order 33 | const queue = [root]; 34 | // Array to keep track of the nodes visited in BFS order 35 | const bfsNodes: TreeNode[] = []; 36 | 37 | // Traverse nodes in a level-wise manner 38 | while (queue.length > 0) { 39 | // Dequeue the first node 40 | const currentNode = queue.shift()!; 41 | bfsNodes.push(currentNode); 42 | 43 | // Update the current node for visualization purposes 44 | setCurrentNode(currentNode); 45 | 46 | // Mark the node as visited and update the visited nodes set 47 | setVisitedNodes((prevVisitedNodes) => new Set(prevVisitedNodes).add(currentNode.id!)); 48 | setCurrentNodes([...bfsNodes]); 49 | 50 | // Introduce a delay to visualize the BFS traversal step by step 51 | await Sleep(speedRange); 52 | 53 | // Enqueue the left and right children for future traversal 54 | if (currentNode.left) queue.push(currentNode.left); 55 | if (currentNode.right) queue.push(currentNode.right); 56 | } 57 | 58 | // Reset the current node once traversal is complete 59 | setCurrentNode(null); 60 | 61 | // Additional delay to show the last node before resetting the visited nodes 62 | await Sleep(speedRange * 3); 63 | 64 | // Reset the visited nodes set after the traversal is done 65 | setVisitedNodes(new Set()); 66 | }; 67 | -------------------------------------------------------------------------------- /src/app/algorithm/treeTraversalTechnique/inOrderTraversal.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Sleep } from '../../lib/sleepMethod'; 3 | import { ITreeNode } from '../../types/TreeTypeProps'; 4 | 5 | /** 6 | * Performs an In-Order Depth First Search (DFS) traversal on a binary tree. 7 | * This function will visit the left subtree first, then the current node, and finally the right subtree. 8 | * It marks the visited nodes and updates the current traversal step in the state, with a delay to visualize the process. 9 | * 10 | * @async 11 | * @function InOrderDFSTraversal 12 | * @param {ITreeNode | null} node - The current node to traverse. If null, the traversal stops (base case). 13 | * @param {Set} visitedNodes - A Set to track the IDs of visited nodes during traversal. 14 | * @param {React.Dispatch>} setCurrentStep - State setter to update the current node's index during traversal. 15 | * @param {React.Dispatch>>} setVisitedNodes - State setter to update the set of visited nodes. 16 | * @param {ITreeNode[]} steps - Array of all nodes representing the traversal steps. Used to determine the current node's index. 17 | * 18 | * @returns {Promise} - A promise that resolves once the traversal is complete. 19 | * 20 | * @example 21 | * // Assume a tree with root node, and use state setters to update the current step and visited nodes 22 | * InOrderDFSTraversal(rootNode, visitedNodes, setCurrentStep, setVisitedNodes, steps); 23 | */ 24 | export const InOrderDFSTraversal = async ( 25 | node: ITreeNode | null, 26 | visitedNodes: Set, 27 | setCurrentStep: React.Dispatch>, 28 | setVisitedNodes: React.Dispatch>>, 29 | steps: ITreeNode[], 30 | speedRange: number 31 | ) => { 32 | // Base case: If the node is null, stop recursion 33 | if (!node) return; 34 | 35 | // Traverse the left subtree first 36 | if (node.left) { 37 | await InOrderDFSTraversal(node.left, visitedNodes, setCurrentStep, setVisitedNodes, steps, speedRange); 38 | } 39 | 40 | // Mark the current node as visited if its id is valid 41 | if (node.id !== null) { 42 | visitedNodes.add(node.id); 43 | } 44 | 45 | // Update the current step state by finding the node's index in the steps array 46 | setCurrentStep(steps.indexOf(node)); 47 | 48 | // Update the state to reflect the visited nodes 49 | setVisitedNodes(new Set(visitedNodes)); 50 | 51 | // Introduce a delay to visualize the traversal process 52 | await Sleep(speedRange); 53 | 54 | // Traverse the right subtree next 55 | if (node.right) { 56 | await InOrderDFSTraversal(node.right, visitedNodes, setCurrentStep, setVisitedNodes, steps, speedRange); 57 | } 58 | 59 | // After traversing the right subtree, backtrack to the current node and update the step 60 | setCurrentStep(steps.indexOf(node)); 61 | 62 | // Add another delay to visualize backtracking 63 | await Sleep(speedRange); 64 | }; 65 | -------------------------------------------------------------------------------- /src/app/algorithm/treeTraversalTechnique/postOrderTraversal.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Sleep } from '../../lib/sleepMethod'; 3 | import { ITreeNode } from '../../types/TreeTypeProps'; 4 | 5 | /** 6 | * Performs a Post-Order Depth First Search (DFS) traversal on a binary tree. 7 | * This function will visit the left subtree, then the right subtree, and finally the current node. 8 | * It marks the visited nodes and updates the current traversal step in the state, with a delay to visualize the process. 9 | * 10 | * @async 11 | * @function PostOrderDFSTraversal 12 | * @param {ITreeNode | null} node - The current node to traverse. If null, the traversal stops (base case). 13 | * @param {Set} visitedNodes - A Set to track the IDs of visited nodes during traversal. 14 | * @param {React.Dispatch>} setCurrentStep - State setter to update the current node's index during traversal. 15 | * @param {React.Dispatch>>} setVisitedNodes - State setter to update the set of visited nodes. 16 | * @param {ITreeNode[]} steps - Array of all nodes representing the traversal steps. Used to determine the current node's index. 17 | * 18 | * @returns {Promise} - A promise that resolves once the traversal is complete. 19 | * 20 | * @example 21 | * // Assume a tree with root node, and use state setters to update the current step and visited nodes 22 | * PostOrderDFSTraversal(rootNode, visitedNodes, setCurrentStep, setVisitedNodes, steps); 23 | */ 24 | export const PostOrderDFSTraversal = async ( 25 | node: ITreeNode | null, 26 | visitedNodes: Set, 27 | setCurrentStep: React.Dispatch>, 28 | setVisitedNodes: React.Dispatch>>, 29 | steps: ITreeNode[], 30 | speedRange: number 31 | ) => { 32 | // Base case: If the node is null, stop recursion 33 | if (!node) return; 34 | 35 | // Traverse the left subtree first 36 | if (node.left) { 37 | await PostOrderDFSTraversal(node.left, visitedNodes, setCurrentStep, setVisitedNodes, steps, speedRange); 38 | } 39 | 40 | // Traverse the right subtree next 41 | if (node.right) { 42 | await PostOrderDFSTraversal(node.right, visitedNodes, setCurrentStep, setVisitedNodes, steps, speedRange); 43 | } 44 | 45 | // Mark the current node as visited if its id is valid 46 | if (node.id !== null) { 47 | visitedNodes.add(node.id); 48 | } 49 | 50 | // Find the current node's index in the steps array and update the current step state 51 | const nodeIndex = steps.findIndex((stepNode) => stepNode.id === node.id); 52 | setCurrentStep(nodeIndex); 53 | 54 | // Update the state to reflect the visited nodes 55 | setVisitedNodes(new Set(visitedNodes)); 56 | 57 | // Introduce a delay to visualize the traversal process 58 | await Sleep(speedRange); 59 | }; 60 | -------------------------------------------------------------------------------- /src/app/algorithm/treeTraversalTechnique/preOrderTraversal.ts: -------------------------------------------------------------------------------- 1 | import { Sleep } from '@/app/lib/sleepMethod'; 2 | import { ITreeNode } from '@/app/types/TreeTypeProps'; 3 | import React from 'react'; 4 | 5 | export const preOrderTraversal = async ( 6 | node: ITreeNode | null, 7 | visitedNodes: Set, 8 | setCurrentStep: React.Dispatch>, 9 | setVisitedNodes: React.Dispatch>>, 10 | steps: ITreeNode[], 11 | speedRange: number 12 | ) => { 13 | // handle the base case 14 | if (!node) return; 15 | 16 | // mark this node as visited 17 | if (node.id !== null) { 18 | visitedNodes.add(node.id); 19 | } 20 | 21 | // Mark the current node 22 | setCurrentStep(steps.indexOf(node)); 23 | 24 | // update state of visited 25 | setVisitedNodes(new Set(visitedNodes)); 26 | 27 | // wait until completed the current node 28 | await Sleep(speedRange); 29 | 30 | // Traverse left subtree 31 | if (node.left) { 32 | await preOrderTraversal(node.left, visitedNodes, setCurrentStep, setVisitedNodes, steps, speedRange); 33 | } 34 | 35 | // Backtrack to current node 36 | setCurrentStep(steps.indexOf(node)); 37 | await Sleep(speedRange); 38 | 39 | // Traverse right subtree 40 | if (node.right) { 41 | await preOrderTraversal(node.right, visitedNodes, setCurrentStep, setVisitedNodes, steps, speedRange); 42 | } 43 | 44 | // Backtrack to current node 45 | setCurrentStep(steps.indexOf(node)); 46 | await Sleep(speedRange); 47 | }; 48 | -------------------------------------------------------------------------------- /src/app/components/Tree/TreeComponent.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * A Root tree structure is defined here. This will return a svg after create a Tree structure. 3 | * @component - A React component 4 | */ 5 | 'use client'; 6 | 7 | import React, { useState } from 'react'; 8 | import TreeDFSTraversal from '@/app/utils/TreeDFSTraversal'; 9 | import TreeBFSTraversal from '@/app/utils/TreeBFSTraversal'; 10 | import { uid } from '@/app/lib/uidGenerator'; 11 | 12 | const TreeComponent = () => { 13 | // define a component local memory 14 | const [activeRootBtnType, setActiveRootBtnType] = useState('dfs'); 15 | const [childBtnActiveType, setChildBtnActiveType] = useState('pre-order'); 16 | const [randomKey, setRandomKey] = useState('1'); 17 | const [speedRange, setSpeedRange] = useState(200); 18 | 19 | /** 20 | * Performs an In-Order Depth First Search (DFS) traversal of the tree. 21 | * 22 | * This method sets the child button type to 'in-order', clears any timeouts, 23 | * and resets states. It then performs the in-order traversal and resets the states 24 | * after traversal is complete. 25 | * 26 | * @async 27 | * @function inOrderTechniqueBtnMethod 28 | * @returns {void} 29 | */ 30 | const inOrderTechniqueBtnMethod = async () => { 31 | // Set the button type to 'in-order' 32 | setChildBtnActiveType('in-order'); 33 | }; 34 | 35 | /** 36 | * Performs a Post-Order Depth First Search (DFS) traversal of the tree. 37 | * 38 | * This method sets the child button type to 'post-order', clears any timeouts, 39 | * and resets states. It performs the post-order traversal and resets the states 40 | * once traversal is complete. 41 | * 42 | * @async 43 | * @function postOrderTechniqueBtnMethod 44 | * @returns {void} 45 | */ 46 | const postOrderTechniqueBtnMethod = () => { 47 | // Set the button type to 'post-order' 48 | setChildBtnActiveType('post-order'); 49 | }; 50 | 51 | /** 52 | * Performs a pre-Order Depth First Search (DFS) traversal of the tree. 53 | * 54 | * This method sets the child button type to 'pre-order', clears any timeouts, 55 | * and resets states. It performs the post-order traversal and resets the states 56 | * once traversal is complete. 57 | * 58 | * @async 59 | * @function preOrderTechniqueBtnMethod 60 | * @returns {void} 61 | */ 62 | const preOrderTechniqueBtnMethod = () => { 63 | // Set the button type to 'pre-order' 64 | setChildBtnActiveType('pre-order'); 65 | }; 66 | 67 | /** submit method to perform current task from start */ 68 | const submitMethod = () => { 69 | setRandomKey(uid()); 70 | }; 71 | 72 | /** 73 | * onChange method of select 74 | * 75 | * @param {React.ChangeEvent} e 76 | */ 77 | const handleSelectChange = async (e: React.ChangeEvent) => { 78 | const value = e.target.value; 79 | setActiveRootBtnType(value); 80 | }; 81 | 82 | /** 83 | * input type range method 84 | * 85 | * @param {*} e 86 | */ 87 | const inputRangeMethod = (e: React.ChangeEvent) => { 88 | setSpeedRange(Number(e.target.value)); 89 | }; 90 | 91 | return ( 92 |
93 |
94 |
95 | {activeRootBtnType === 'dfs' ? ( 96 |
97 | 103 | 109 | 115 |
116 | ) : null} 117 |
118 |
119 |
120 |

Speed: {speedRange} (0 to 1500)

121 | 130 |
131 |
132 |

Select type

133 | 145 | 146 | 152 |
153 |
154 |
155 | 156 |
157 | {activeRootBtnType === 'dfs' ? ( 158 | 159 | ) : activeRootBtnType === 'bfs' ? ( 160 | 161 | ) : null} 162 |
163 |
164 | ); 165 | }; 166 | 167 | export default TreeComponent; 168 | -------------------------------------------------------------------------------- /src/app/components/home/HomeComponent.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable indent */ 2 | 'use client'; 3 | 4 | import { projectsData } from '@/app/data/dashboardSchemaData'; 5 | import { ProjectSchema } from '@/app/types/commonProps'; 6 | import Link from 'next/link'; 7 | import { ReactNode } from 'react'; 8 | 9 | const HomeComponent = (): ReactNode => { 10 | return ( 11 |
12 |
13 | {projectsData ? ( 14 |
15 | {projectsData.map((item: ProjectSchema) => { 16 | return ( 17 | 22 |
23 |
24 |

{item.name}

25 |
26 | {item.tags?.length 27 | ? item.tags.map((i) => ( 28 |

32 | {i.name} 33 |

34 | )) 35 | : null} 36 |
37 |
38 |
39 | 40 | ); 41 | })} 42 |
43 | ) : ( 44 |
45 |

Loading...

46 |
47 | )} 48 |
49 |
50 | ); 51 | }; 52 | 53 | export default HomeComponent; 54 | -------------------------------------------------------------------------------- /src/app/components/layouts/footer/FooterComponent.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import React from 'react'; 3 | 4 | const FooterComponent = () => ( 5 |
6 |
7 |
8 | 14 | Alamin 15 | 16 | 17 |
18 | 23 | alamin66.sit@gmail.com 24 | 25 | 26 | 27 | 28 | 35 | 36 | 37 |
38 |
39 |
40 | 41 |
42 |

43 | Designed and built by{' '} 44 | 50 | Alamin 51 | 52 |  with  53 | Love & Coffee 54 |

55 |
56 |
57 |
58 | ); 59 | 60 | export default FooterComponent; 61 | -------------------------------------------------------------------------------- /src/app/components/linked-list/LinkedListComponent.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { uid } from '@/app/lib/uidGenerator'; 4 | import React, { useState } from 'react'; 5 | import LinkedListBasics from './LinkedListBasics'; 6 | import ReverseLinkedList from './ReverseLinkedList'; 7 | import MergeTwoSortedList from './MergeTwoSortedList'; 8 | import DetectCycle from './DetectCycle'; 9 | 10 | const LinkedListComponent = () => { 11 | // define a component local memory 12 | const [activeRootBtnType, setActiveRootBtnType] = useState('merge-two-linked-list'); //reverse-linked-list 13 | const [randomKey, setRandomKey] = useState('1'); 14 | const [speedRange, setSpeedRange] = useState(200); 15 | 16 | /** submit method to perform current task from start */ 17 | const submitMethod = () => { 18 | setRandomKey(uid()); 19 | }; 20 | 21 | /** 22 | * onChange method of select 23 | * 24 | * @param {React.ChangeEvent} e 25 | */ 26 | const handleSelectChange = async (e: React.ChangeEvent) => { 27 | const value = e.target.value; 28 | setActiveRootBtnType(value); 29 | }; 30 | 31 | /** 32 | * input type range method 33 | * 34 | * @param {*} e 35 | */ 36 | const inputRangeMethod = (e: React.ChangeEvent) => { 37 | setSpeedRange(Number(e.target.value)); 38 | }; 39 | 40 | return ( 41 |
42 |
43 |
44 |
45 |

Speed: {speedRange} (0 to 1500)

46 | 55 |
56 |
57 |
58 |

Select type

59 | 80 |
81 | 87 |
88 |
89 |
90 | 91 |
92 | {activeRootBtnType === 'linked-list-crud' ? ( 93 | 94 | ) : activeRootBtnType === 'reverse-linked-list' ? ( 95 | 96 | ) : activeRootBtnType === 'merge-two-linked-list' ? ( 97 | 98 | ) : activeRootBtnType === 'cycle' ? ( 99 | 100 | ) : null} 101 |
102 |
103 | ); 104 | }; 105 | 106 | export default LinkedListComponent; 107 | -------------------------------------------------------------------------------- /src/app/components/pathFind/NoOfIslands.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { findNoOfIslands } from '@/app/algorithm/path-finding/noOfValidIslands'; 4 | import { UNIQUE_PATH_GRID_SIZE } from '@/app/constant'; 5 | import { noOfIslandsSortColorsData } from '@/app/data/mockData'; 6 | import { createGridWithUniquePath } from '@/app/data/PathFindingGridData'; 7 | import { clearAllTimeouts } from '@/app/lib/sleepMethod'; 8 | import { GridProps, PathFindingQueueProps, UniquePathPageProps } from '@/app/types/uniquePathProps'; 9 | import StatusColorsPlate from '@/app/utils/StatusColorsPlate'; 10 | import React, { useEffect, useState } from 'react'; 11 | import { toast } from 'react-toastify'; 12 | 13 | const NoOfIslands: React.FC = ({ useRandomKey, speedRange, gridSize }) => { 14 | // define component local state 15 | const [data, setData] = useState([]); 16 | const [, setQueue] = useState([]); 17 | const [countIslands, setCountIslands] = useState(0); 18 | 19 | useEffect(() => { 20 | let Time: number = 0; 21 | 22 | if (Object.keys(gridSize)?.length) { 23 | // create each new row, clear it's all previous states 24 | clearAllTimeouts(); 25 | 26 | const tempData = JSON.parse(JSON.stringify(createGridWithUniquePath(gridSize.rowSize, gridSize.colSize, 0.3))); 27 | 28 | setData([...tempData]); 29 | setQueue([]); 30 | setCountIslands(0); 31 | 32 | if (tempData?.length) { 33 | Time = window.setTimeout(() => { 34 | noOfIslandsMethod(tempData, []); 35 | }, 300); 36 | } 37 | } 38 | 39 | return () => { 40 | clearTimeout(Time); 41 | clearAllTimeouts(); 42 | }; 43 | // eslint-disable-next-line react-hooks/exhaustive-deps 44 | }, [gridSize, useRandomKey]); 45 | 46 | /** 47 | * Method to perform BFS on the grid to find all valid islands. 48 | * An island is defined as a connected group of cells with value `1`. 49 | * For each island found, the method marks it as visited and increments the island count. 50 | * 51 | * @async 52 | * @function noOfIslandsMethod 53 | * @param {GridProps[][]} data - The grid representing land (1) and water (0) cells. 54 | * @param {{ rowIdx: number; colIdx: number }[]} queue - The queue used for BFS traversal. 55 | * @returns {Promise} A Promise that resolves once all islands are found and counted. 56 | */ 57 | const noOfIslandsMethod = async (data: GridProps[][], queue: { rowIdx: number; colIdx: number }[]) => { 58 | try { 59 | const n = data.length; // Number of rows in the grid 60 | const m = data[0]?.length; // Number of columns in the grid 61 | 62 | // Clone data and queue to avoid mutating the original state 63 | const tempData = [...data]; 64 | const tempQueue = [...queue]; 65 | 66 | // Traverse the grid to find unvisited land cells (islands) 67 | for (let row = 0; row < n; row++) { 68 | for (let col = 0; col < m; col++) { 69 | // If the cell is land (1) and hasn't been visited yet, initiate BFS to explore the island 70 | if (tempData[row][col].data === 1 && !tempData[row][col].isVisit) { 71 | // Perform BFS to find and mark the entire island 72 | await findNoOfIslands(row, col, tempData, tempQueue, setData, setQueue, speedRange); 73 | // Show a success toast message indicating that a valid island was found 74 | toast.success('One valid island is found', { position: 'top-left' }); 75 | // Increment the island count 76 | setCountIslands((prev) => prev + 1); 77 | } 78 | } 79 | } 80 | } catch (error) { 81 | if (process.env.NODE_ENV === 'development') { 82 | // eslint-disable-next-line no-console 83 | console.log(error, 'from catch'); 84 | } 85 | } 86 | }; 87 | 88 | return ( 89 | <> 90 |
91 |
92 | 93 |
94 |

95 | No of islands : {countIslands} 96 |

97 |
98 | 99 |
100 | {data?.length ? ( 101 |
102 | {data.map((row, rowIndex) => ( 103 |
104 | {row.map((col, colIndex) => { 105 | let BG_COLOR = col.data === 0 ? 'bg-[#1ca3ec] text-white' : 'bg-[#E99F0C] text-black'; 106 | if (col.isInvalid) BG_COLOR = 'bg-red-600 text-white'; 107 | if (col.isCurrent) BG_COLOR = 'bg-blue-600 text-white'; 108 | if (col.isMarked) BG_COLOR = 'bg-pink-600 text-white'; 109 | if (col.isValidPath) BG_COLOR = 'bg-green-600 text-white'; 110 | if (col.islandColor?.length) BG_COLOR = col.islandColor; 111 | 112 | let borderStyles = `border-b-[0.5px] border-r-[0.5px] border-[#575C6B] text-xl`; 113 | 114 | if (rowIndex === 0) { 115 | borderStyles += ` border-t-[0.5px]`; 116 | } 117 | if (rowIndex === data?.length - 1) { 118 | borderStyles += ` border-b-[0.5px]`; 119 | } 120 | if (colIndex === 0) { 121 | borderStyles += ` border-l-[0.5px]`; 122 | } 123 | if (colIndex === data[0]?.length - 1) { 124 | borderStyles += ` border-r-[0.5px]`; 125 | } 126 | 127 | return ( 128 |
132 | {col.data} 133 |
134 | ); 135 | })} 136 |
137 | ))} 138 |
139 | ) : ( 140 |
141 |

Loading...

142 |
143 | )} 144 |
145 | 146 | ); 147 | }; 148 | 149 | export default NoOfIslands; 150 | -------------------------------------------------------------------------------- /src/app/components/pathFind/PathFind.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { uid } from '@/app/lib/uidGenerator'; 4 | import React, { useEffect, useState } from 'react'; 5 | import UniquePath from './UniquePath'; 6 | import { gridRowColSize } from '@/app/lib/helpers'; 7 | import { clearAllTimeouts } from '@/app/lib/sleepMethod'; 8 | import NoOfIslands from './NoOfIslands'; 9 | import ShortestPath from './ShortestPath'; 10 | 11 | const PathFind = () => { 12 | // define local state 13 | const [buttonType, setButtonType] = useState('unique-path'); //dijkstra 14 | const [randomKey, setRandomKey] = useState('1'); 15 | const [speedRange, setSpeedRange] = useState(100); 16 | const [gridSize, setGridSize] = useState<{ rowSize: number; colSize: number }>({ rowSize: 8, colSize: 10 }); 17 | const [submittedGridSize, setSubmittedGridSize] = useState<{ rowSize: number; colSize: number }>(gridSize); 18 | 19 | // clear times out before component unmount 20 | useEffect(() => { 21 | return () => { 22 | clearAllTimeouts(); 23 | }; 24 | }, []); 25 | 26 | /** updated current button with it's type */ 27 | const buttonMethod = () => { 28 | setRandomKey(uid()); 29 | setSubmittedGridSize(gridSize); // Update the submitted grid size to pass to the child component 30 | }; 31 | 32 | /** 33 | * onChange method of select 34 | * 35 | * @param {React.ChangeEvent} e 36 | */ 37 | const handleSelectChange = (e: React.ChangeEvent) => { 38 | setButtonType(e.target.value); 39 | }; 40 | 41 | /** 42 | * input type range method 43 | * 44 | * @param {*} e 45 | */ 46 | const inputRangeMethod = (e: React.ChangeEvent) => { 47 | setSpeedRange(Number(e.target.value)); 48 | }; 49 | 50 | /** 51 | *Get user selectable grid row size 52 | * 53 | * @param {React.ChangeEvent} e 54 | */ 55 | const handleSelectChangeForRow = (e: React.ChangeEvent) => { 56 | setGridSize((prv) => ({ ...prv, rowSize: Number(e.target.value) })); 57 | }; 58 | 59 | /** 60 | *Get user selectable grid row size 61 | * 62 | * @param {React.ChangeEvent} e 63 | */ 64 | const handleSelectChangeForCol = (e: React.ChangeEvent) => { 65 | setGridSize((prv) => ({ ...prv, colSize: Number(e.target.value) })); 66 | }; 67 | 68 | return ( 69 |
70 |
71 |
72 |
73 |
74 |

Speed: {speedRange} (0 to 1500)

75 | 84 |
85 |
86 | {buttonType !== 'shortest-path' ? ( 87 |
88 |
89 |

Row

90 | 103 |
104 |
105 |

Col

106 | 119 |
120 |
121 | ) : null} 122 |
123 |
124 |

Select type

125 | 140 | 141 | 147 |
148 |
149 |
150 |
151 | {buttonType === 'unique-path' ? ( 152 |
153 | 154 |
155 | ) : null} 156 | {buttonType === 'no-of-island' ? ( 157 |
158 | 159 |
160 | ) : buttonType === 'shortest-path' ? ( 161 | 162 | ) : null} 163 |
164 | ); 165 | }; 166 | 167 | export default PathFind; 168 | -------------------------------------------------------------------------------- /src/app/components/searching/SearchingComponent.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * A Root tree structure is defined here. This will return a svg after create a Tree structure. 3 | * @component - A React component 4 | */ 5 | 'use client'; 6 | 7 | import React, { useEffect, useState } from 'react'; 8 | import { uid } from '@/app/lib/uidGenerator'; 9 | import BinarySearchTreeComponent from './BinarySearchTreeComponent'; 10 | import { clearAllTimeouts } from '@/app/lib/sleepMethod'; 11 | import LinearSearchComponent from './LinearSearchComponent'; 12 | 13 | const SearchingComponent = () => { 14 | // define a component local memory 15 | const [activeRootBtnType, setActiveRootBtnType] = useState('bst'); 16 | const [randomKey, setRandomKey] = useState('1'); 17 | const [speedRange, setSpeedRange] = useState(200); 18 | 19 | // ensure clear all timeout after component un-mount 20 | useEffect(() => { 21 | return () => { 22 | clearAllTimeouts(); 23 | }; 24 | }, []); 25 | 26 | /** submit method to perform current task from start */ 27 | const submitMethod = () => { 28 | setRandomKey(uid()); 29 | }; 30 | 31 | /** 32 | * onChange method of select 33 | * 34 | * @param {React.ChangeEvent} e 35 | */ 36 | const handleSelectChange = async (e: React.ChangeEvent) => { 37 | const value = e.target.value; 38 | setActiveRootBtnType(value); 39 | }; 40 | 41 | /** 42 | * input type range method 43 | * 44 | * @param {*} e 45 | */ 46 | const inputRangeMethod = (e: React.ChangeEvent) => { 47 | setSpeedRange(Number(e.target.value)); 48 | }; 49 | 50 | return ( 51 |
52 |
53 |
54 |
55 |

Speed: {speedRange} (0 to 1500)

56 | 65 |
66 |
67 |

Select type

68 | 80 | 81 | 87 |
88 |
89 |
90 | 91 |
92 | {activeRootBtnType === 'bst' ? : null} 93 | {activeRootBtnType === 'linear-search' ? ( 94 | 95 | ) : null} 96 |
97 |
98 | ); 99 | }; 100 | 101 | export default SearchingComponent; 102 | -------------------------------------------------------------------------------- /src/app/components/sorting/BubbleSortComponent.tsx: -------------------------------------------------------------------------------- 1 | import { bubbleSortAlgo } from '@/app/algorithm/sorting/bubbleSort'; 2 | import { MERGE_SORT_SVG_HEIGHT, MERGE_SORT_SVG_WIDTH } from '@/app/constant'; 3 | import { bubbleSortColorsData } from '@/app/data/mockData'; 4 | import { sortingData } from '@/app/data/SortData'; 5 | import { clearAllTimeouts, Sleep } from '@/app/lib/sleepMethod'; 6 | import { SortingDataProps } from '@/app/types/sortingProps'; 7 | import StatusColorsPlate from '@/app/utils/StatusColorsPlate'; 8 | import React, { useEffect, useState } from 'react'; 9 | 10 | // Calculate the maximum value to normalize data 11 | const maxValue = Math.max(...sortingData.map((item) => Number(item.data))); 12 | 13 | // Calculate column width and spacing 14 | const columnWidth = MERGE_SORT_SVG_WIDTH / sortingData.length; 15 | const columnSpacing = 5; // Space between columns 16 | 17 | const BubbleSortComponent: React.FC<{ speedRange: number }> = ({ speedRange }) => { 18 | /** Define component state */ 19 | const [data, setData] = useState(JSON.parse(JSON.stringify(sortingData))); 20 | const [step, setStep] = useState(0); 21 | 22 | useEffect(() => { 23 | if (data.length) { 24 | bubbleSortMethod(); 25 | } 26 | // eslint-disable-next-line react-hooks/exhaustive-deps 27 | }, []); 28 | 29 | /** a method to mark state as a initial-state */ 30 | const resetDataState = async () => { 31 | // reset time-out 32 | clearAllTimeouts(); 33 | 34 | const tempData = data.map((item) => ({ 35 | ...item, 36 | isSorted: false, 37 | isSwapped: false, 38 | currentItem: false, 39 | isFinished: false, 40 | })); 41 | 42 | setData(tempData); 43 | }; 44 | 45 | const bubbleSortMethod = async () => { 46 | try { 47 | if (!data.length) { 48 | throw new Error('The array is undefined!'); 49 | } 50 | 51 | // Clear all state before starting 52 | await resetDataState(); 53 | 54 | // Wait for state update to complete 55 | await Sleep(100); 56 | 57 | // Call the bubble sort algorithm 58 | bubbleSortAlgo(data, setData, speedRange, setStep); 59 | } catch (error) { 60 | if (process.env.NODE_ENV === 'development') { 61 | // eslint-disable-next-line no-console 62 | console.error(error); 63 | } 64 | } 65 | }; 66 | 67 | return ( 68 |
69 |
70 | 71 |
72 |
73 | 74 | {data.map((item, index) => { 75 | const x = index * columnWidth; 76 | const columnHeight = (Number(item.data) / maxValue) * MERGE_SORT_SVG_HEIGHT + 15; 77 | 78 | let fillColor = 'black'; 79 | 80 | if (item.isSwapped) { 81 | fillColor = 'red'; 82 | } 83 | 84 | if (item.isSorted) { 85 | fillColor = 'green'; 86 | } 87 | 88 | return ( 89 | 90 | 97 | 98 | ); 99 | })} 100 | 101 |
102 |
103 | {data?.length && 104 | data.map((item) => { 105 | let fillColor = 'bg-white'; 106 | 107 | if (item.isSwapped) { 108 | fillColor = 'bg-red-600 text-white'; 109 | } 110 | 111 | if (item.isSorted) { 112 | fillColor = 'bg-green-600 text-white'; 113 | } 114 | return ( 115 |

116 | {item.data || ''} 117 |

118 | ); 119 | })} 120 |
121 |
122 |

Step: {step}

123 |
124 |
125 | ); 126 | }; 127 | 128 | export default BubbleSortComponent; 129 | -------------------------------------------------------------------------------- /src/app/components/sorting/HeapSortComponent.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { heapify, HeapSortApproach } from '@/app/algorithm/sorting/heapSort'; 3 | import { getRandomTreeData, NODE_POSITION } from '@/app/constant'; 4 | import { Tree } from '@/app/data-structure/Tree/TreeNode'; 5 | import { heapSortColorsData } from '@/app/data/mockData'; 6 | import { calculateLinePosition } from '@/app/lib/calculateSvgLinePosition'; 7 | import { HeapSortedItemProps } from '@/app/types/sortingProps'; 8 | import { ITreeNode } from '@/app/types/TreeTypeProps'; 9 | import StatusColorsPlate from '@/app/utils/StatusColorsPlate'; 10 | import React, { useEffect, useState } from 'react'; 11 | import { toast } from 'react-toastify'; 12 | 13 | const HeapSortComponent: React.FC<{ speedRange: number }> = ({ speedRange }) => { 14 | const [data, setData] = useState([]); 15 | const [sortedData, setSortedData] = useState([]); 16 | 17 | useEffect(() => { 18 | const newTree = new Tree(JSON.parse(JSON.stringify(getRandomTreeData(31)))); 19 | // created a valid tree 20 | newTree.insertIntoList(); 21 | if (newTree?.linearArr?.length) { 22 | setData(newTree.linearArr); 23 | } 24 | }, []); 25 | 26 | useEffect(() => { 27 | if (data?.length) { 28 | performHeapMethod(); 29 | } 30 | // eslint-disable-next-line react-hooks/exhaustive-deps 31 | }, [data.length]); 32 | 33 | const performHeapMethod = async () => { 34 | const tempData = [...data]; 35 | const n = tempData.length; 36 | 37 | // Index of last non-leaf node 38 | const startIdx = Math.floor(n / 2) - 1; 39 | 40 | // STEP: 1 -> Construct a heapify or max-heap tree 41 | toast.success('Heapify the tree'); 42 | 43 | // Perform reverse level order traversal 44 | // from last non-leaf node and heapify 45 | // each node 46 | for (let i = startIdx; i >= 0; i--) { 47 | await heapify(tempData, n, i, speedRange, setData); 48 | } 49 | 50 | // after completed heapify the root data, 51 | // perform a heap sort 52 | toast.success('Perform a heap sort'); 53 | // STEP: 2, Perform a heap sort 54 | HeapSortApproach(tempData, n, speedRange, setData, setSortedData); 55 | }; 56 | 57 | return ( 58 | <> 59 |
60 | 61 |
62 | 63 |
64 | {sortedData?.length ? ( 65 |
66 | {sortedData.map((item) => { 67 | return ( 68 |

72 | {item.data} 73 |

74 | ); 75 | })} 76 |
77 | ) : null} 78 |
79 |
80 | {data?.length ? ( 81 | 82 | {data.map((root) => { 83 | let fillColor = '#000'; // Default stroke color (text color and line color) 84 | let circleFillColor = '#fff'; // Default circle fill color 85 | let textColor = '#000'; 86 | 87 | // Define colors based on node states 88 | if (root.isCurrent) { 89 | fillColor = 'red'; 90 | circleFillColor = 'red'; 91 | textColor = '#fff'; 92 | } else if (root.isSwap) { 93 | textColor = '#fff'; 94 | circleFillColor = '#341f97'; 95 | } else if (root.isSorted) { 96 | fillColor = 'green'; 97 | circleFillColor = 'green'; 98 | textColor = 'white'; 99 | } 100 | 101 | return ( 102 | 103 | {root.parent && 104 | (() => { 105 | const linePos = calculateLinePosition( 106 | root.parent.cx!, 107 | root.parent.cy!, 108 | root.cx!, 109 | root.cy!, 110 | NODE_POSITION 111 | ); 112 | return ( 113 | <> 114 | 122 | 130 | 131 | 132 | ); 133 | })()} 134 | 142 | 143 | 144 | 152 | {root?.value || -1} 153 | 154 | 155 | ); 156 | })} 157 | 158 | ) : ( 159 |
160 |

Loading...

161 |
162 | )} 163 |
164 | 165 | ); 166 | }; 167 | 168 | export default HeapSortComponent; 169 | -------------------------------------------------------------------------------- /src/app/components/sorting/MergeSortComponent.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { mergeSortMethod } from '@/app/algorithm/sorting/mergeSort'; 4 | import { MERGE_SORT_SVG_HEIGHT, MERGE_SORT_SVG_WIDTH } from '@/app/constant'; 5 | import { mergeSortColorsData } from '@/app/data/mockData'; 6 | import { sortingData } from '@/app/data/SortData'; 7 | import { SortingDataProps } from '@/app/types/sortingProps'; 8 | import StatusColorsPlate from '@/app/utils/StatusColorsPlate'; 9 | import React, { useEffect, useState } from 'react'; 10 | 11 | // Calculate the maximum value to normalize data 12 | const maxValue = Math.max(...sortingData.map((item) => Number(item.data))); 13 | 14 | // Calculate column width and spacing 15 | const columnWidth = MERGE_SORT_SVG_WIDTH / sortingData.length; 16 | const columnSpacing = 5; // Space between columns 17 | 18 | const MergeSortComponent: React.FC<{ speedRange: number }> = ({ speedRange = 0 }) => { 19 | const [data, setData] = useState(JSON.parse(JSON.stringify(sortingData))); 20 | const [step, setStep] = useState(0); 21 | const [currentIndex, setCurrentIndex] = useState<{ 22 | leftIndex: number | null; 23 | rightIndex: number | null; 24 | }>({ 25 | leftIndex: -1, 26 | rightIndex: -1, 27 | }); // State for current index 28 | const [isSorted, setIsSorted] = useState(false); 29 | const [currentHalves, setCurrentHalves] = useState<{ 30 | leftHalf: number[]; 31 | rightHalf: number[]; 32 | }>({ 33 | leftHalf: [], 34 | rightHalf: [], 35 | }); 36 | const [completedItems, setCompletedItems] = useState([]); 37 | 38 | useEffect(() => { 39 | if (data.length) { 40 | mergeSortMethod( 41 | data, 42 | setStep, 43 | currentIndex, 44 | setCurrentIndex, 45 | setIsSorted, 46 | setData, 47 | speedRange, 48 | setCurrentHalves, 49 | setCompletedItems 50 | ); 51 | } 52 | // eslint-disable-next-line react-hooks/exhaustive-deps 53 | }, []); 54 | 55 | return ( 56 |
57 |
58 | 59 |
60 | 61 |
62 | 63 | {data.map((item, index) => { 64 | const x = index * columnWidth; 65 | const columnHeight = (Number(item.data) / maxValue) * MERGE_SORT_SVG_HEIGHT + 15; 66 | 67 | const isLeftHalf = currentHalves.leftHalf.includes(Number(item.id)); 68 | const isRightHalf = currentHalves.rightHalf.includes(Number(item.id)); 69 | const isCurrentLeft = index === currentIndex.leftIndex; 70 | const isCurrentRight = index === currentIndex.rightIndex; 71 | 72 | let isCompleted = false; 73 | 74 | if (isSorted) { 75 | isCompleted = completedItems.includes(index); 76 | } 77 | 78 | let fillColor = 'black'; // Default color 79 | 80 | if (isCompleted && isSorted) { 81 | fillColor = 'green'; // Color for completed sorting 82 | } else if (isCurrentLeft) { 83 | fillColor = 'red'; // Color for current left index 84 | } else if (isCurrentRight) { 85 | fillColor = 'blue'; // Color for current right index 86 | } else if (isLeftHalf) { 87 | fillColor = 'orange'; // Color for current left half 88 | } else if (isRightHalf) { 89 | fillColor = 'purple'; // Color for current right half 90 | } 91 | return ( 92 | 93 | 100 | 101 | ); 102 | })} 103 | 104 |
105 |
106 | {data?.length && 107 | data.map((item, index) => { 108 | const isLeftHalf = currentHalves.leftHalf.includes(Number(item.id)); 109 | const isRightHalf = currentHalves.rightHalf.includes(Number(item.id)); 110 | 111 | const isCurrentLeft = index === currentIndex.leftIndex; 112 | const isCurrentRight = index === currentIndex.rightIndex; 113 | 114 | let isCompleted = false; 115 | 116 | if (isSorted) { 117 | isCompleted = completedItems.includes(index); 118 | } 119 | 120 | return ( 121 |

137 | {item.data || ''} 138 |

139 | ); 140 | })} 141 |
142 |
143 |

Step: {step}

144 |
145 |
146 | ); 147 | }; 148 | 149 | export default MergeSortComponent; 150 | -------------------------------------------------------------------------------- /src/app/components/sorting/QuickSortComponent.tsx: -------------------------------------------------------------------------------- 1 | import { quickSortAlgo } from '@/app/algorithm/sorting/quickSort'; 2 | import { MERGE_SORT_SVG_HEIGHT, MERGE_SORT_SVG_WIDTH } from '@/app/constant'; 3 | import { sortingData } from '@/app/data//SortData'; 4 | import { quickSortColorsData } from '@/app/data/mockData'; 5 | import { clearAllTimeouts, Sleep } from '@/app/lib/sleepMethod'; 6 | import { SortingDataProps } from '@/app/types/sortingProps'; 7 | import StatusColorsPlate from '@/app/utils/StatusColorsPlate'; 8 | import React, { useEffect, useState } from 'react'; 9 | 10 | // Calculate the maximum value to normalize data 11 | const maxValue = Math.max(...sortingData.map((item) => Number(item.data))); 12 | 13 | // Calculate column width and spacing 14 | const columnWidth = MERGE_SORT_SVG_WIDTH / sortingData.length; 15 | const columnSpacing = 5; // Space between columns 16 | 17 | const QuickSortComponent: React.FC<{ speedRange: number }> = ({ speedRange }) => { 18 | /** Define component state */ 19 | const [data, setData] = useState(JSON.parse(JSON.stringify(sortingData))); 20 | 21 | const [step, setStep] = useState(0); 22 | 23 | useEffect(() => { 24 | if (data.length) { 25 | quickSortMethod(); 26 | } 27 | // eslint-disable-next-line react-hooks/exhaustive-deps 28 | }, []); 29 | 30 | /** a method to mark state as a initial-state */ 31 | const resetDataState = async () => { 32 | // reset time-out 33 | clearAllTimeouts(); 34 | 35 | const tempData = data.map((item) => ({ 36 | ...item, 37 | isSorted: false, 38 | currentItem: false, 39 | isSwapped: false, 40 | isFinished: false, 41 | isCurrentCompareAbleItem: false, 42 | isCandidate: false, 43 | isActive: false, 44 | xPosition: 0, 45 | isLeft: false, 46 | isRight: false, 47 | })); 48 | 49 | setData(tempData); 50 | }; 51 | 52 | /** 53 | * Method to perform quick sort visualization 54 | * 55 | * @async 56 | * @returns {*} 57 | */ 58 | const quickSortMethod = async () => { 59 | try { 60 | if (!data.length) { 61 | throw new Error('The array is undefined!'); 62 | } 63 | 64 | // Clear all state before starting 65 | await resetDataState(); 66 | 67 | // Wait for state update to complete 68 | await Sleep(100); 69 | 70 | // Call the quick sort algorithm 71 | await quickSortAlgo([...data], 0, data.length - 1, setStep, setData, speedRange); 72 | } catch (error) { 73 | if (process.env.NODE_ENV === 'development') { 74 | // eslint-disable-next-line no-console 75 | console.error(error); 76 | } 77 | } 78 | }; 79 | 80 | return ( 81 |
82 |
83 | 84 |
85 | 86 |
87 | 88 | {data.map((item, index) => { 89 | const x = index * columnWidth; 90 | const columnHeight = (Number(item.data) / maxValue) * MERGE_SORT_SVG_HEIGHT + 15; 91 | 92 | let fillColor = 'black'; 93 | if (item.currentItem) 94 | fillColor = '#FF4D4D'; // Red for the current item 95 | else if (item.isLeft) 96 | fillColor = '#6A0DAD'; // Purple for candidate items 97 | else if (item.isRight) 98 | fillColor = '#FF8C00'; // Orange for items being compared 99 | else if (item.isSorted) fillColor = '#28A745'; // Green for sorted items 100 | 101 | return ( 102 | 103 | 110 | 111 | ); 112 | })} 113 | 114 |
115 |
116 | {data?.length && 117 | data.map((item) => { 118 | let fillColor = 'bg-white'; 119 | if (item.currentItem) 120 | fillColor = 'bg-red-600 text-white'; // Red for the current item 121 | else if (item.isLeft) 122 | fillColor = 'bg-purple-600 text-white'; // Purple for candidate items 123 | else if (item.isRight) 124 | fillColor = 'bg-orange-600 text-white'; // Orange for items being compared 125 | else if (item.isSorted) fillColor = 'bg-green-600 text-white'; // Green for sorted items 126 | 127 | return ( 128 |

129 | {item.data || ''} 130 |

131 | ); 132 | })} 133 |
134 |
135 |

Step: {step}

136 |
137 |
138 | ); 139 | }; 140 | 141 | export default QuickSortComponent; 142 | -------------------------------------------------------------------------------- /src/app/components/sorting/SelectionSortComponent.tsx: -------------------------------------------------------------------------------- 1 | import { selectionSortAlgo } from '@/app/algorithm/sorting/selectionSort'; 2 | import { MERGE_SORT_SVG_HEIGHT, MERGE_SORT_SVG_WIDTH } from '@/app/constant'; 3 | import { selectionSortColorsData } from '@/app/data/mockData'; 4 | import { sortingData } from '@/app/data/SortData'; 5 | import { clearAllTimeouts, Sleep } from '@/app/lib/sleepMethod'; 6 | import { SortingDataProps } from '@/app/types/sortingProps'; 7 | import StatusColorsPlate from '@/app/utils/StatusColorsPlate'; 8 | import React, { useEffect, useState } from 'react'; 9 | 10 | // Calculate the maximum value to normalize data 11 | const maxValue = Math.max(...sortingData.map((item) => Number(item.data))); 12 | 13 | // Calculate column width and spacing 14 | const columnWidth = MERGE_SORT_SVG_WIDTH / sortingData.length; 15 | const columnSpacing = 5; // Space between columns 16 | 17 | const SelectionSortComponent: React.FC<{ speedRange: number }> = ({ speedRange }) => { 18 | /** Define component state */ 19 | const [data, setData] = useState(JSON.parse(JSON.stringify(sortingData))); 20 | 21 | const [step, setStep] = useState(0); 22 | 23 | useEffect(() => { 24 | if (data.length) { 25 | selectionSortMethod(); 26 | } 27 | // eslint-disable-next-line react-hooks/exhaustive-deps 28 | }, []); 29 | 30 | /** a method to mark state as a initial-state */ 31 | const resetDataState = async () => { 32 | // reset time-out 33 | clearAllTimeouts(); 34 | 35 | const tempData = data.map((item) => ({ 36 | ...item, 37 | isSorted: false, 38 | isSwapped: false, 39 | currentItem: false, 40 | isFinished: false, 41 | isCurrentCompareAbleItem: false, 42 | isCandidate: false, 43 | isActive: false, 44 | })); 45 | 46 | setData(tempData); 47 | }; 48 | 49 | const selectionSortMethod = async () => { 50 | try { 51 | if (!data.length) { 52 | throw new Error('The array is undefined!'); 53 | } 54 | 55 | // Clear all state before starting 56 | await resetDataState(); 57 | 58 | // Wait for state update to complete 59 | await Sleep(100); 60 | 61 | // Call the bubble sort algorithm 62 | selectionSortAlgo([...data], setData, speedRange, setStep); 63 | } catch (error) { 64 | if (process.env.NODE_ENV === 'development') { 65 | // eslint-disable-next-line no-console 66 | console.error(error); 67 | } 68 | } 69 | }; 70 | 71 | return ( 72 |
73 |
74 | 75 |
76 | 77 |
78 | 79 | {data.map((item, index) => { 80 | const x = index * columnWidth; 81 | const columnHeight = (Number(item.data) / maxValue) * MERGE_SORT_SVG_HEIGHT + 15; 82 | 83 | let fillColor = 'black'; 84 | 85 | if (item.currentItem) { 86 | fillColor = '#FF4D4D'; // Red 87 | } 88 | 89 | if (item.isCandidate) { 90 | fillColor = '#6A0DAD'; // Purple 91 | } 92 | 93 | if (item.isCurrentCompareAbleItem) { 94 | fillColor = '#FF8C00'; // Orange 95 | } 96 | 97 | if (item.isSorted) { 98 | fillColor = '#28A745'; // Green 99 | } 100 | 101 | return ( 102 | 103 | 110 | 111 | ); 112 | })} 113 | 114 |
115 |
116 | {data?.length && 117 | data.map((item) => { 118 | let fillColor = 'bg-white'; 119 | 120 | if (item.currentItem) { 121 | fillColor = 'bg-red-600 text-white'; // Red 122 | } 123 | 124 | if (item.isCandidate) { 125 | fillColor = 'bg-purple-600 text-white'; // Purple 126 | } 127 | 128 | if (item.isCurrentCompareAbleItem) { 129 | fillColor = 'bg-orange-600 text-white'; // Orange 130 | } 131 | 132 | if (item.isSorted) { 133 | fillColor = 'bg-green-600 text-white'; // Green 134 | } 135 | 136 | return ( 137 |

138 | {item.data || ''} 139 |

140 | ); 141 | })} 142 |
143 |
144 |

Step: {step}

145 |
146 |
147 | ); 148 | }; 149 | 150 | export default SelectionSortComponent; 151 | -------------------------------------------------------------------------------- /src/app/components/sorting/SortingComponent.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React, { useEffect, useState } from 'react'; 4 | import MergeSortComponent from './MergeSortComponent'; 5 | import { uid } from '@/app/lib/uidGenerator'; 6 | import BubbleSortComponent from './BubbleSortComponent'; 7 | import SelectionSortComponent from './SelectionSortComponent'; 8 | import QuickSortComponent from './QuickSortComponent'; 9 | import HeapSortComponent from './HeapSortComponent'; 10 | import { clearAllTimeouts } from '@/app/lib/sleepMethod'; 11 | 12 | const SortingComponent = () => { 13 | // define local state 14 | const [buttonType, setButtonType] = useState('merge-sort'); 15 | const [randomKey, setRandomKey] = useState(''); 16 | const [speedRange, setSpeedRange] = useState(200); 17 | 18 | // clear times out before component unmount 19 | useEffect(() => { 20 | return () => { 21 | clearAllTimeouts(); 22 | }; 23 | }, []); 24 | 25 | /** updated current button with it's type */ 26 | const buttonMethod = () => setRandomKey(uid()); 27 | 28 | /** 29 | * onChange method of select 30 | * 31 | * @param {React.ChangeEvent} e 32 | */ 33 | const handleSelectChange = (e: React.ChangeEvent) => { 34 | setButtonType(e.target.value); 35 | }; 36 | 37 | /** 38 | * input type range method 39 | * 40 | * @param {*} e 41 | */ 42 | const inputRangeMethod = (e: React.ChangeEvent) => { 43 | setSpeedRange(Number(e.target.value)); 44 | }; 45 | 46 | return ( 47 |
48 |
49 |
50 |
51 |

Speed: {speedRange} (0 to 1500)

52 | 61 |
62 |
63 | 85 | 86 | 92 |
93 |
94 |
95 | {buttonType === 'merge-sort' ? ( 96 |
97 | 98 |
99 | ) : null} 100 | {buttonType === 'bubble-sort' ? ( 101 |
102 | 103 |
104 | ) : null} 105 | {buttonType === 'selection-sort' ? ( 106 |
107 | 108 |
109 | ) : null} 110 | {buttonType === 'quick-sort' ? ( 111 |
112 | 113 |
114 | ) : null} 115 | {buttonType === 'heap-sort' ? ( 116 |
117 | 118 |
119 | ) : null} 120 |
121 | ); 122 | }; 123 | 124 | export default SortingComponent; 125 | -------------------------------------------------------------------------------- /src/app/components/sudoku-solver/SudoKuSolver.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React, { useEffect, useState } from 'react'; 4 | import SudoKuSolverComponent from './SudoKuSolverComponent'; 5 | import { uid } from '@/app/lib/uidGenerator'; 6 | import { clearAllTimeouts } from '@/app/lib/sleepMethod'; 7 | 8 | const SudoKuSolver = () => { 9 | /** Define component local memory state */ 10 | const [speedRange, setSpeedRange] = useState(200); 11 | const [randomKey, setRandomKey] = useState('1'); 12 | 13 | // Trigger for component mount 14 | useEffect(() => { 15 | // Trigger for component un-mount 16 | return () => clearAllTimeouts(); 17 | }, []); 18 | 19 | /** submit method to perform current task from start */ 20 | const submitMethod = () => { 21 | setRandomKey(uid()); 22 | }; 23 | 24 | /** 25 | * Handles the change event for an input range, updating the speed range state. 26 | * 27 | * @param {React.ChangeEvent} e - The input change event. 28 | */ 29 | const inputRangeMethod = (e: React.ChangeEvent) => { 30 | // Update the speed range state with the numeric value from the input 31 | setSpeedRange(Number(e.target.value)); 32 | }; 33 | 34 | return ( 35 |
36 |
37 |
38 |
39 |
40 |
41 |

Speed: {speedRange} (0 to 1500)

42 | 51 |
52 |
53 | 59 |
60 |
61 |
62 |
63 | {/* Render component */} 64 | 65 |
66 |
67 | ); 68 | }; 69 | 70 | export default SudoKuSolver; 71 | -------------------------------------------------------------------------------- /src/app/constant.ts: -------------------------------------------------------------------------------- 1 | import { ICell } from './types/NQueensProps'; 2 | 3 | /* custom tree node */ 4 | export const NODE_POSITION = 5; 5 | // node radius 6 | export const RADIUS: number = 8; 7 | // Space between children 8 | export const CHILD_SPACING: number = 45; 9 | // Height of the line connecting nodes 10 | export const LINE_HEIGHT: number = 45; 11 | // Offset to shift the left child line 12 | export const LEFT_LINE_OFFSET: number = 10; 13 | // Offset to shift the right child line 14 | export const RIGHT_LINE_OFFSET: number = 10; 15 | // Svg view box with 16 | export const SVG_VIEW_BOX_WIDTH = 240; 17 | // delay time of each DFS traversal 18 | export const DFS_DELAY = 600; 19 | // delay time of each BFS traversal 20 | export const BFS_DELAY = 600; 21 | 22 | /** 23 | * Get random data to create a tree 24 | * 25 | * @param {number} [size=31] 26 | * @returns {*} 27 | */ 28 | export const getRandomTreeData = (size: number = 31, range: number = 500) => 29 | Array.from({ length: size }).map(() => Math.floor(Math.random() * range + 1)); 30 | 31 | // fill the check board according to the grid size 32 | export const fillGridArray = (size: number, defaultValue: number = 0): ICell[][] => { 33 | let id = 1; 34 | return Array(size) 35 | .fill(0) 36 | .map(() => 37 | Array(size) 38 | .fill(0) 39 | .map(() => ({ id: id++, value: defaultValue })) 40 | ); 41 | }; 42 | 43 | export const GRID_SIZE = 4; 44 | 45 | /* merge sort board size and other content goes here */ 46 | export const MERGE_SORT_SVG_WIDTH = 2000; 47 | export const MERGE_SORT_SVG_HEIGHT = 400; 48 | // merge data sleep time 49 | export const MERGE_SLEEP_DELAY = 0; 50 | 51 | /** PATH FINDING CONSTANT THING DEFINE HERE */ 52 | // Directions for moving in the maze 53 | export const del_row = [+1, 0, 0, -1]; // Down, Left, Right, Up 54 | export const del_col = [0, -1, +1, 0]; 55 | // To identify a valid path 56 | export const directions = ['D', 'L', 'R', 'U']; // Direction string for consistency 57 | export const UNIQUE_PATH_SVG_ICON_SIZE = `w-[80%] min-[600px]:h-[20px] min-[600px]:w-[20px]`; 58 | export const UNIQUE_PATH_GRID_SIZE = `h-[50px] w-[50px]`; 59 | 60 | // Linked list component necessary constant thing 61 | export const LINKED_LIST_NODE_START_CX = 20; 62 | export const LINKED_LIST_NODE_START_CY = 20; 63 | -------------------------------------------------------------------------------- /src/app/data-structure/LinkedList/LinkedList.ts: -------------------------------------------------------------------------------- 1 | import { ITreeNode } from '@/app/types/TreeTypeProps'; 2 | import { TreeNode } from '../Tree/Node'; 3 | 4 | // // Define the Tree interface 5 | export interface ITree { 6 | head: ITreeNode | null; 7 | arr: (number | null)[]; 8 | } 9 | 10 | /** 11 | * Represents a linked list with optional cyclic references. 12 | * Implements the `ITree` interface. 13 | */ 14 | export class LinkedList implements ITree { 15 | /** The head node of the linked list. */ 16 | head: ITreeNode | null = null; 17 | /** An array representing the node values. */ 18 | arr: (number | null)[] = []; 19 | /** initialize start or root node cx value */ 20 | initialize_cx: number; 21 | 22 | /** 23 | * Creates an instance of the `LinkedList` class. 24 | * 25 | * @param {number | null[]} arr - An array of node values, where `null` represents no node. 26 | * @param {number | undefined} initialize_cx - the initial staring cx position of node. 27 | */ 28 | constructor(arr: (number | null)[], initialize_cx: number = 20, head: ITreeNode | null = null) { 29 | this.head = head; 30 | this.arr = arr; 31 | this.initialize_cx = initialize_cx; 32 | } 33 | 34 | /** 35 | * Creates a linked list from the provided array and sets up a cycle if specified. 36 | * The cycle is created by connecting the node at `cycle2Index` to the node at `cycle1Index`. 37 | * 38 | * @returns {void} 39 | */ 40 | createLinkedList(): void { 41 | if (this.arr.length === 0) return; 42 | 43 | // Insert the first node into the head 44 | const temp = new TreeNode(this.arr[0]); 45 | temp.cx = this.initialize_cx; 46 | temp.cy = 20; 47 | this.head = temp; 48 | 49 | // Create a pseudo copy of the head 50 | let current = this.head; 51 | 52 | for (let i = 1; i < this.arr.length; i++) { 53 | const newNode = new TreeNode(this.arr[i]); 54 | newNode.cx = this.initialize_cx + 25; 55 | newNode.cy = 20; 56 | 57 | current.next = newNode; 58 | current = newNode; 59 | 60 | // Update CX value for positioning 61 | this.initialize_cx += 25; 62 | } 63 | } 64 | 65 | /** 66 | * Inserts a new node with the specified value at the end of the linked list 67 | * and sets its position based on the provided x and y coordinates. 68 | * 69 | * @param {number} [x=20] - The x-coordinate for the new node's position. Defaults to 20. 70 | * @param {number} [y=20] - The y-coordinate for the new node's position. Defaults to 20. 71 | * @param {number} nodeValue - The value to be stored in the new node. 72 | * 73 | * @returns {void} - This method does not return a value. 74 | * 75 | * @example 76 | * const linkedList = new LinkedList(); 77 | * linkedList.insertIntoListWithGivenPositionXY(30, 40, 5); 78 | * // A new node with value 5 is added to the list at the position (30, 40). 79 | */ 80 | insertIntoListWithGivenPositionXY(x: number = 20, y: number = 20, nodeValue: number): void { 81 | // Create a new node 82 | const temp = new TreeNode(nodeValue); 83 | temp.cx = x; 84 | temp.cy = y; 85 | 86 | if (!this.head) { 87 | // If the list is empty, set the new node as the head 88 | this.head = temp; 89 | } else { 90 | // Traverse the list to find the last node 91 | let current = this.head; 92 | 93 | while (current.next) { 94 | current = current.next; 95 | } 96 | 97 | // Set the next pointer of the last node to the new node 98 | current.next = temp; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/app/data-structure/Tree/Node.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Initialized a tree-node with some predefined value 3 | * @return {treeNode} 4 | */ 5 | 6 | import { ITreeNode } from '@/app/types/TreeTypeProps'; 7 | 8 | /** 9 | * @param {value} this is current node data 10 | * @param {cx} current node x-axis position 11 | * @param {cy} current node y-axis position 12 | * @param {isVisited} the sign of node visited or not 13 | * @param {isCurrent} the sign of current node from given list of tree node 14 | * 15 | * @return {node} objects with completed initial node 16 | */ 17 | 18 | export class TreeNode implements ITreeNode { 19 | left: ITreeNode | null = null; 20 | right: ITreeNode | null = null; 21 | next: ITreeNode | null = null; 22 | parent: ITreeNode | null = null; 23 | value: number | null; 24 | id: number | null; 25 | cx: number | null; 26 | cy: number | null; 27 | isVisited: boolean; 28 | isCurrent: boolean; 29 | isSwap: boolean; 30 | isSorted: boolean; 31 | isTarget: boolean; 32 | isInvalid: boolean; 33 | isCycle: boolean; 34 | isInsertedPosition: boolean; 35 | destination: { x: number | null; y: number | null }; 36 | slowPointer: boolean; 37 | firstPointer: boolean; 38 | isCycleStartPoint: boolean; 39 | isCycleEndPoint: boolean; 40 | 41 | constructor( 42 | value: number | null = null, 43 | id: number | null = null, 44 | cx: number | null = null, 45 | cy: number | null = null 46 | ) { 47 | this.value = value; 48 | this.id = id || Math.floor(Math.random() * 9999); 49 | this.cx = cx || 0; 50 | this.cy = cy || 0; 51 | this.isVisited = false; 52 | this.isCurrent = false; 53 | this.isSwap = false; 54 | this.isSorted = false; 55 | this.isTarget = false; 56 | this.isInvalid = false; 57 | this.isCycle = false; 58 | this.isInsertedPosition = false; 59 | this.destination = { x: -1, y: -1 }; 60 | this.slowPointer = false; 61 | this.firstPointer = false; 62 | this.isCycleStartPoint = false; 63 | this.isCycleEndPoint = false; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/app/data-structure/Tree/TreeNode.ts: -------------------------------------------------------------------------------- 1 | import { SVG_VIEW_BOX_WIDTH } from '@/app/constant'; 2 | import { TreeNode } from './Node'; 3 | import { ITreeNode } from '@/app/types/TreeTypeProps'; 4 | 5 | // Adjust this to control the vertical spacing 6 | const LEVEL_HEIGHT = 30; 7 | 8 | // // Define the Tree interface 9 | export interface ITree { 10 | head: ITreeNode | null; 11 | arr: (number | null)[]; 12 | linearArr: ITreeNode[]; 13 | } 14 | 15 | /** 16 | * Represents a binary tree data structure. 17 | * Implements the ITree interface. 18 | * 19 | * @param {*} value 20 | * @return {LinkedList} 21 | */ 22 | 23 | export class Tree implements ITree { 24 | head: ITreeNode | null = null; 25 | arr: (number | null)[] = []; 26 | linearArr: ITreeNode[] = []; 27 | 28 | /** 29 | * Initializes a Tree instance with the provided array. 30 | * 31 | * @param {number | null[]} arr - An array representing the nodes of the tree in level order. 32 | */ 33 | constructor(arr: (number | null)[]) { 34 | this.head = null; 35 | this.arr = arr; 36 | } 37 | 38 | /** 39 | * Creates a balanced binary search tree from the current array of data. 40 | * 41 | * Sorts the array to ensure balance, then recursively builds the tree. 42 | * Calculates and sets positions for all nodes in the tree. 43 | * 44 | * @returns {void} 45 | */ 46 | createBalancedBST(): void { 47 | if (this.arr?.length === 0) return; 48 | 49 | // Sort the array before inserting into the tree to ensure balance 50 | const sortedArr = [...this.arr].sort((a, b) => Number(a) - Number(b)); 51 | 52 | if (!sortedArr?.length) return; 53 | 54 | // Recursively build a balanced BST 55 | this.head = this.buildBalancedBST(sortedArr, 0, sortedArr.length - 1); 56 | 57 | // Calculate positions for all nodes 58 | this.calculatePositions(this.head, SVG_VIEW_BOX_WIDTH / 2, LEVEL_HEIGHT, SVG_VIEW_BOX_WIDTH / 4); 59 | } 60 | 61 | /** 62 | * Recursively builds a balanced binary search tree from a sorted array. 63 | * 64 | * Finds the middle element as the root, and recursively builds left and right subtrees. 65 | * Sets the parent reference for each node. 66 | * 67 | * @param {number[] | null[]} arr - The sorted array of data. 68 | * @param {number} low - The lower index of the array segment. 69 | * @param {number} high - The higher index of the array segment. 70 | * @param {TreeNode | null} parent - The parent node of the current node. 71 | * @returns {TreeNode | null} - The root node of the built subtree. 72 | */ 73 | private buildBalancedBST( 74 | arr: (number | null)[], 75 | low: number, 76 | high: number, 77 | parent: TreeNode | null = null 78 | ): TreeNode | null { 79 | // Base case 80 | if (low > high) return null; 81 | 82 | // Find the middle element and make it the root 83 | const mid = Math.floor((low + high) / 2); 84 | const node = new TreeNode(arr[mid]); 85 | 86 | // Set parent reference 87 | node.parent = parent; 88 | 89 | // Recursively construct the left subtree and make it the left child of the root 90 | node.left = this.buildBalancedBST(arr, low, mid - 1, node); 91 | 92 | // Recursively construct the right subtree and make it the right child of the root 93 | node.right = this.buildBalancedBST(arr, mid + 1, high, node); 94 | 95 | return node; // Return the root node of this subtree 96 | } 97 | 98 | /** 99 | * Constructs a binary tree from the array. 100 | * - Creates the root node and adds it to a queue. 101 | * - Iterates through the array to build the tree level-wise. 102 | * - Limits the height of the tree to a maximum allowed level. 103 | * - Updates the `linearArr` with nodes in level order. 104 | * 105 | * @return {void} 106 | */ 107 | insertIntoList(): void { 108 | if (this.arr?.length === 0) return; 109 | 110 | // Initialize the root node 111 | this.head = new TreeNode(this.arr[0]); 112 | const queue: TreeNode[] = [this.head]; 113 | this.linearArr.push(this.head); 114 | 115 | let i = 1; // Index for the array 116 | const maxHeight = 3; // Maximum allowed height of the tree 117 | let currentLevel = 0; // Current level of the tree being processed 118 | 119 | while (i < this.arr.length && currentLevel <= maxHeight) { 120 | // Number of nodes at the current level 121 | const levelSize = queue.length; 122 | 123 | for (let j = 0; j < levelSize; j++) { 124 | // Get the current node from the queue 125 | const currentNode = queue.shift(); 126 | 127 | if (currentNode) { 128 | // Insert left child if available 129 | if (i < this.arr.length && this.arr[i] !== null) { 130 | const left = new TreeNode(this.arr[i++]); 131 | left.parent = currentNode; 132 | currentNode.left = left; 133 | // Insert into queue, and it will become the next level parent 134 | queue.push(currentNode.left); 135 | 136 | // Add current node to linear array 137 | this.linearArr.push(currentNode.left); 138 | } else { 139 | // Skip the current null item 140 | i++; 141 | } 142 | 143 | // Insert right child if available 144 | if (i < this.arr.length && this.arr[i] !== null) { 145 | const right = new TreeNode(this.arr[i++]); 146 | right.parent = currentNode; 147 | currentNode.right = right; 148 | // Insert into queue, and it will become the next level parent 149 | queue.push(currentNode.right); 150 | 151 | // Add current node to linear array 152 | this.linearArr.push(currentNode.right); 153 | } else { 154 | // Skip the current null item 155 | i++; 156 | } 157 | } 158 | } 159 | 160 | currentLevel++; // Move to the next level 161 | } 162 | 163 | // invoked the calculation method 164 | this.calculatePositions(this.head, SVG_VIEW_BOX_WIDTH / 2, LEVEL_HEIGHT, SVG_VIEW_BOX_WIDTH / 4); 165 | } 166 | 167 | /** 168 | * Recursively updates the position (cx, cy) of each node in the tree. 169 | * 170 | * @param {ITreeNode | null} node - The current node whose position is to be updated. 171 | * @param {number} x - The x-axis position for the current node. 172 | * @param {number} y - The y-axis position for the current node. 173 | * @param {number} offset - The distance from the x-axis for child nodes. 174 | * 175 | * @return {void} 176 | */ 177 | 178 | calculatePositions(node: ITreeNode | null, x: number, y: number, offset: number): void { 179 | if (!node) return; 180 | node.cx = x; 181 | node.cy = y; 182 | 183 | // Recursively update positions for left and right children 184 | if (node.left) { 185 | this.calculatePositions(node.left, x - offset, y + 30, offset / 2); // Adjust the y increment to control vertical spacing 186 | } 187 | if (node.right) { 188 | this.calculatePositions(node.right, x + offset, y + 30, offset / 2); 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/app/data-structure/minHeap/MinHeap.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A class representing a Min Heap data structure. 3 | * This implementation is used to efficiently retrieve the node 4 | * with the smallest distance. 5 | */ 6 | export class MinHeap { 7 | heap: { node: number; distance: number }[]; 8 | 9 | /** 10 | * Initializes an empty Min Heap. 11 | */ 12 | constructor() { 13 | this.heap = []; 14 | } 15 | 16 | /** 17 | * Inserts a new node with its associated distance into the heap. 18 | * This method maintains the heap property by bubbling up the new node. 19 | * 20 | * @param {number} node - The identifier of the node to insert. 21 | * @param {number} distance - The distance associated with the node. 22 | */ 23 | insert(node: number, distance: number) { 24 | this.heap.push({ node, distance }); 25 | this.bubbleUp(); 26 | } 27 | 28 | /** 29 | * Extracts the node with the smallest distance from the heap. 30 | * The root node is removed, and the last node is moved to the root 31 | * followed by bubbling down to maintain the heap property. 32 | * 33 | * @returns {{ node: number; distance: number } | undefined} - The node with the smallest distance or undefined if the heap is empty. 34 | */ 35 | extractMin() { 36 | if (this.heap.length === 1) return this.heap.pop(); 37 | const min = this.heap[0]; 38 | this.heap[0] = this.heap.pop()!; 39 | this.bubbleDown(); 40 | return min; 41 | } 42 | 43 | /** 44 | * Gets the parent index of a given node index. 45 | * 46 | * @param {number} index - The index of the current node. 47 | * @returns {number} - The index of the parent node. 48 | */ 49 | getParentIndex(index: number) { 50 | return Math.floor((index - 1) / 2); 51 | } 52 | 53 | /** 54 | * Swaps two elements in the heap. 55 | * 56 | * @param {number} index1 - The index of the first element. 57 | * @param {number} index2 - The index of the second element. 58 | */ 59 | swap(index1: number, index2: number) { 60 | [this.heap[index1], this.heap[index2]] = [this.heap[index2], this.heap[index1]]; 61 | } 62 | 63 | /** 64 | * Bubbles up the last element in the heap to maintain the heap property. 65 | */ 66 | bubbleUp() { 67 | let index = this.heap.length - 1; 68 | while (index > 0) { 69 | const parentIndex = this.getParentIndex(index); 70 | if (this.heap[index].distance >= this.heap[parentIndex].distance) break; 71 | 72 | this.swap(index, parentIndex); 73 | index = parentIndex; 74 | } 75 | } 76 | 77 | /** 78 | * Bubbles down the root element to maintain the heap property. 79 | * This method ensures that the smallest element moves to the root position. 80 | */ 81 | bubbleDown() { 82 | let index = 0; 83 | const length = this.heap.length; 84 | 85 | // eslint-disable-next-line no-constant-condition 86 | while (true) { 87 | const leftChild = 2 * index + 1; 88 | const rightChild = 2 * index + 2; 89 | let smallest = index; 90 | 91 | if (leftChild < length && this.heap[leftChild].distance < this.heap[smallest].distance) { 92 | smallest = leftChild; 93 | } 94 | 95 | if (rightChild < length && this.heap[rightChild].distance < this.heap[smallest].distance) { 96 | smallest = rightChild; 97 | } 98 | 99 | if (smallest === index) break; 100 | this.swap(index, smallest); 101 | index = smallest; 102 | } 103 | } 104 | 105 | /** 106 | * Checks if the heap is empty. 107 | * 108 | * @returns {boolean} - True if the heap is empty, false otherwise. 109 | */ 110 | isEmpty() { 111 | return this.heap.length === 0; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/app/data/PathFindingGridData.ts: -------------------------------------------------------------------------------- 1 | import { GridProps } from '../types/uniquePathProps'; 2 | 3 | /** 4 | * A dynamic approach to create a (n * m) valid grid 5 | * 6 | * @param {number} rows 7 | * @param {number} cols 8 | * @returns {GridProps[][]} 9 | */ 10 | export const createGridWithUniquePath = (rows: number, cols: number, threshold: number = 0.3): GridProps[][] => { 11 | const grid = Array.from({ length: rows }, (_, rowIdx) => 12 | Array.from({ length: cols }, (_, colIdx) => ({ 13 | id: rowIdx * cols + colIdx + 1, 14 | data: 1, // Initialize with default value (1 for walkable cells) 15 | isVisit: false, 16 | isCurrent: false, 17 | isActive: false, 18 | isAdjacent: false, 19 | isReachAble: false, 20 | isInvalid: false, 21 | isMarked: false, 22 | parent: { rowIdx: -1, colIdx: -1 }, 23 | isValidPath: false, 24 | islandColor: '', 25 | })) 26 | ); 27 | 28 | if (rows > 1 && cols > 1) { 29 | // Simple method to ensure a path from top-left to bottom-right 30 | for (let r = 0; r < rows; r++) { 31 | for (let c = 0; c < cols; c++) { 32 | if (r === rows - 1 || c === cols - 1) { 33 | grid[r][c].data = 1; // Ensure the last row and column are walkable 34 | } else { 35 | // 0.3 -> if we increase this, it will create more most obstacles or brick 36 | grid[r][c].data = Math.random() > threshold ? 1 : 0; // Random obstacles 37 | } 38 | } 39 | } 40 | grid[0][0].data = 1; // Ensure the start is walkable 41 | grid[rows - 1][cols - 1].data = 1; // Ensure the end is walkable 42 | } 43 | 44 | return grid; 45 | }; 46 | -------------------------------------------------------------------------------- /src/app/data/dashboardSchemaData.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * A dummy json data for home component. 3 | */ 4 | 5 | import { uid } from '../lib/uidGenerator'; 6 | import { ProjectSchema } from '../types/commonProps'; 7 | 8 | export const projectsData: ProjectSchema[] = [ 9 | { 10 | id: uid(), 11 | name: 'Sudoku Solver', 12 | navigate: '/sudoku-solver', 13 | tags: [ 14 | { 15 | id: uid(), 16 | name: 'DFS', 17 | }, 18 | ], 19 | }, 20 | { 21 | id: uid(), 22 | name: 'Tree', 23 | navigate: '/tree', 24 | tags: [ 25 | { 26 | id: uid(), 27 | name: 'DFS (in-order, pre-order, post-order)', 28 | }, 29 | { 30 | id: uid(), 31 | name: 'BFS', 32 | }, 33 | ], 34 | }, 35 | { 36 | id: uid(), 37 | name: 'N Queens', 38 | tags: [ 39 | { 40 | id: uid(), 41 | name: 'DFS', 42 | }, 43 | ], 44 | navigate: '/n-queens', 45 | }, 46 | { 47 | id: uid(), 48 | name: 'Sorting', 49 | tags: [ 50 | { 51 | id: uid(), 52 | name: 'Merge', 53 | }, 54 | { 55 | id: uid(), 56 | name: 'Quick', 57 | }, 58 | { 59 | id: uid(), 60 | name: 'Heap', 61 | }, 62 | { 63 | id: uid(), 64 | name: 'Bubble', 65 | }, 66 | { 67 | id: uid(), 68 | name: 'Selection', 69 | }, 70 | ], 71 | navigate: '/sorting', 72 | }, 73 | { 74 | id: uid(), 75 | name: 'Path Finding', 76 | tags: [ 77 | { 78 | id: uid(), 79 | name: 'Dijkstra', 80 | }, 81 | { 82 | id: uid(), 83 | name: 'Bellman Ford', 84 | }, 85 | { 86 | id: uid(), 87 | name: 'Floyd Warshall', 88 | }, 89 | { 90 | id: uid(), 91 | name: 'Rat in maze', 92 | }, 93 | { 94 | id: uid(), 95 | name: 'No of Island', 96 | }, 97 | ], 98 | navigate: '/path-finding', 99 | }, 100 | { 101 | id: uid(), 102 | name: 'Searching', 103 | tags: [ 104 | { 105 | id: uid(), 106 | name: 'Binary Search', 107 | }, 108 | ], 109 | navigate: '/searching', 110 | }, 111 | { 112 | id: uid(), 113 | name: 'Linked List', 114 | tags: [ 115 | { 116 | id: uid(), 117 | name: 'Reverse list', 118 | }, 119 | { 120 | id: uid(), 121 | name: 'Merge two list', 122 | }, 123 | { 124 | id: uid(), 125 | name: 'Basic (CRUD)', 126 | }, 127 | { 128 | id: uid(), 129 | name: 'Detect Cycle', 130 | }, 131 | ], 132 | navigate: '/linked-list', 133 | }, 134 | ]; 135 | -------------------------------------------------------------------------------- /src/app/data/linkedListData.ts: -------------------------------------------------------------------------------- 1 | export const CYCLE_NODE_DATA: { 2 | x: number; 3 | y: number; 4 | node: number; 5 | }[] = [ 6 | { x: 160, y: 20, node: 1 }, 7 | { x: 190, y: 35, node: 2 }, 8 | { x: 200, y: 65, node: 3 }, 9 | { x: 180, y: 90, node: 4 }, 10 | { x: 145, y: 100, node: 5 }, 11 | { x: 115, y: 85, node: 6 }, 12 | { x: 110, y: 50, node: 7 }, 13 | ]; 14 | -------------------------------------------------------------------------------- /src/app/data/sudokuData.ts: -------------------------------------------------------------------------------- 1 | import { SudoKuBoardProps } from '../types/sudokyProps'; 2 | 3 | // Object with default properties 4 | const objectProperty: Omit = { 5 | isValid: false, 6 | isActive: false, 7 | isCurrent: false, 8 | isTarget: false, 9 | isValidRowItem: false, 10 | isValidColItem: false, 11 | isValidSubGridItem: false, 12 | isInvalid: false, 13 | }; 14 | 15 | // Two-dimensional array for the Sudoku board 16 | export const SUDOKU_BOARD_DATA: SudoKuBoardProps[][] = [ 17 | [ 18 | { value: '9', id: '0-0', ...objectProperty }, 19 | { value: '5', id: '0-1', ...objectProperty }, 20 | { value: '7', id: '0-2', ...objectProperty }, 21 | { value: '#', id: '0-3', ...objectProperty }, 22 | { value: '1', id: '0-4', ...objectProperty }, 23 | { value: '3', id: '0-5', ...objectProperty }, 24 | { value: '#', id: '0-6', ...objectProperty }, 25 | { value: '8', id: '0-7', ...objectProperty }, 26 | { value: '4', id: '0-8', ...objectProperty }, 27 | ], 28 | [ 29 | { value: '4', id: '1-0', ...objectProperty }, 30 | { value: '8', id: '1-1', ...objectProperty }, 31 | { value: '3', id: '1-2', ...objectProperty }, 32 | { value: '#', id: '1-3', ...objectProperty }, 33 | { value: '5', id: '1-4', ...objectProperty }, 34 | { value: '7', id: '1-5', ...objectProperty }, 35 | { value: '1', id: '1-6', ...objectProperty }, 36 | { value: '#', id: '1-7', ...objectProperty }, 37 | { value: '6', id: '1-8', ...objectProperty }, 38 | ], 39 | [ 40 | { value: '#', id: '2-0', ...objectProperty }, 41 | { value: '1', id: '2-1', ...objectProperty }, 42 | { value: '2', id: '2-2', ...objectProperty }, 43 | { value: '#', id: '2-3', ...objectProperty }, 44 | { value: '4', id: '2-4', ...objectProperty }, 45 | { value: '9', id: '2-5', ...objectProperty }, 46 | { value: '5', id: '2-6', ...objectProperty }, 47 | { value: '3', id: '2-7', ...objectProperty }, 48 | { value: '7', id: '2-8', ...objectProperty }, 49 | ], 50 | [ 51 | { value: '1', id: '3-0', ...objectProperty }, 52 | { value: '7', id: '3-1', ...objectProperty }, 53 | { value: '#', id: '3-2', ...objectProperty }, 54 | { value: '3', id: '3-3', ...objectProperty }, 55 | { value: '#', id: '3-4', ...objectProperty }, 56 | { value: '4', id: '3-5', ...objectProperty }, 57 | { value: '9', id: '3-6', ...objectProperty }, 58 | { value: '#', id: '3-7', ...objectProperty }, 59 | { value: '2', id: '3-8', ...objectProperty }, 60 | ], 61 | [ 62 | { value: '5', id: '4-0', ...objectProperty }, 63 | { value: '#', id: '4-1', ...objectProperty }, 64 | { value: '4', id: '4-2', ...objectProperty }, 65 | { value: '9', id: '4-3', ...objectProperty }, 66 | { value: '7', id: '4-4', ...objectProperty }, 67 | { value: '#', id: '4-5', ...objectProperty }, 68 | { value: '3', id: '4-6', ...objectProperty }, 69 | { value: '6', id: '4-7', ...objectProperty }, 70 | { value: '#', id: '4-8', ...objectProperty }, 71 | ], 72 | [ 73 | { value: '3', id: '5-0', ...objectProperty }, 74 | { value: '#', id: '5-1', ...objectProperty }, 75 | { value: '9', id: '5-2', ...objectProperty }, 76 | { value: '5', id: '5-3', ...objectProperty }, 77 | { value: '#', id: '5-4', ...objectProperty }, 78 | { value: '8', id: '5-5', ...objectProperty }, 79 | { value: '7', id: '5-6', ...objectProperty }, 80 | { value: '#', id: '5-7', ...objectProperty }, 81 | { value: '1', id: '5-8', ...objectProperty }, 82 | ], 83 | [ 84 | { value: '8', id: '6-0', ...objectProperty }, 85 | { value: '4', id: '6-1', ...objectProperty }, 86 | { value: '5', id: '6-2', ...objectProperty }, 87 | { value: '7', id: '6-3', ...objectProperty }, 88 | { value: '9', id: '6-4', ...objectProperty }, 89 | { value: '#', id: '6-5', ...objectProperty }, 90 | { value: '6', id: '6-6', ...objectProperty }, 91 | { value: '1', id: '6-7', ...objectProperty }, 92 | { value: '3', id: '6-8', ...objectProperty }, 93 | ], 94 | [ 95 | { value: '#', id: '7-0', ...objectProperty }, 96 | { value: '9', id: '7-1', ...objectProperty }, 97 | { value: '1', id: '7-2', ...objectProperty }, 98 | { value: '#', id: '7-3', ...objectProperty }, 99 | { value: '3', id: '7-4', ...objectProperty }, 100 | { value: '6', id: '7-5', ...objectProperty }, 101 | { value: '#', id: '7-6', ...objectProperty }, 102 | { value: '7', id: '7-7', ...objectProperty }, 103 | { value: '5', id: '7-8', ...objectProperty }, 104 | ], 105 | [ 106 | { value: '7', id: '8-0', ...objectProperty }, 107 | { value: '#', id: '8-1', ...objectProperty }, 108 | { value: '6', id: '8-2', ...objectProperty }, 109 | { value: '1', id: '8-3', ...objectProperty }, 110 | { value: '8', id: '8-4', ...objectProperty }, 111 | { value: '5', id: '8-5', ...objectProperty }, 112 | { value: '4', id: '8-6', ...objectProperty }, 113 | { value: '#', id: '8-7', ...objectProperty }, 114 | { value: '9', id: '8-8', ...objectProperty }, 115 | ], 116 | ]; 117 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlaminPu1007/algorithm-visualizer/21845e972dd8e2378cbcd16accc5ae8cdd37acb2/src/app/favicon.ico -------------------------------------------------------------------------------- /src/app/globals.scss: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | body { 6 | background-color: #fff; 7 | } 8 | 9 | @layer utilities { 10 | .text-balance { 11 | text-wrap: balance; 12 | } 13 | } 14 | 15 | .navbar { 16 | @apply fixed list-none flex-col duration-200 ease-in max-[1023px]:left-0 max-[1023px]:top-0 max-[1023px]:h-[100vh] max-[1023px]:w-[350px] max-[1023px]:bg-white max-[1023px]:px-4 max-[1023px]:pt-[25px] lg:static lg:ml-auto lg:flex lg:flex-row lg:flex-wrap lg:items-center dark:max-[1023px]:bg-theme-dark-bg; 17 | } 18 | 19 | .nav-list-item-link { 20 | @apply relative my-2 inline-block whitespace-nowrap px-0 pb-2 text-lg font-light text-theme-primary duration-300 after:absolute after:bottom-0 after:left-0 after:h-[1px] after:w-0 after:bg-theme-secondary after:duration-200 hover:after:w-full lg:mx-[12px] lg:my-0 lg:pb-1 dark:text-theme-dark-primary dark:after:bg-theme-white; 21 | } 22 | 23 | .title-txt { 24 | @apply m-0 p-0 py-3 text-[1.55rem] font-bold uppercase tracking-[.02em] text-theme-secondary sm:text-3xl dark:text-white; 25 | } 26 | 27 | .root-btn { 28 | @apply rounded-sm border px-8 py-1 text-base transition-all duration-300 hover:bg-theme-btn-secondary hover:text-white; 29 | } 30 | 31 | .active-root-btn { 32 | @apply bg-theme-btn-secondary text-white; 33 | } 34 | 35 | .child-btn { 36 | @apply rounded-sm border px-3 py-1 text-sm text-black transition-all duration-300 hover:bg-blue-500 hover:text-white; 37 | } 38 | 39 | .active-child-btn { 40 | @apply bg-blue-500 text-white; 41 | } 42 | 43 | // after effect with animation 44 | .after-hover-animation { 45 | @apply after:absolute after:bottom-0 after:left-0 after:h-[1px] after:w-0 after:bg-theme-secondary after:duration-200 hover:after:w-[100%] dark:after:bg-theme-dark-secondary; 46 | } 47 | 48 | .footer-txt-gradient { 49 | background-image: linear-gradient(to left, #ec4899, #a855f7); 50 | background-clip: text; 51 | -webkit-background-clip: text; /* Safari and older versions of Chrome */ 52 | -moz-background-clip: text; /* Firefox (old versions) */ 53 | -ms-background-clip: text; /* Edge (old versions) */ 54 | -o-background-clip: text; /* Opera (old versions) */ 55 | color: transparent; 56 | -webkit-text-fill-color: transparent; /* Safari and older versions of Chrome */ 57 | -moz-text-fill-color: transparent; /* Firefox (old versions) */ 58 | -ms-text-fill-color: transparent; /* Edge (old versions) */ 59 | -o-text-fill-color: transparent; /* Opera (old versions) */ 60 | } 61 | 62 | // footer styles goes here 63 | .footer-nav-link { 64 | @apply relative inline-block px-1 pb-1 text-base text-theme-secondary duration-300 after:absolute after:bottom-0 after:left-0 after:h-[1px] after:w-0 after:bg-theme-secondary after:duration-300 hover:after:w-full lg:text-lg dark:text-theme-dark-secondary dark:after:bg-theme-white; 65 | } 66 | 67 | @layer utilities { 68 | input[type='number']::-webkit-outer-spin-button, 69 | input[type='number']::-webkit-inner-spin-button { 70 | @apply appearance-none; /* Hide number spinner for Webkit browsers */ 71 | } 72 | 73 | /* For Firefox */ 74 | input[type='number'] { 75 | -moz-appearance: textfield; /* Hide spinner for Firefox */ 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next'; 2 | import { Poppins } from 'next/font/google'; 3 | import './globals.scss'; 4 | import React from 'react'; 5 | import HeaderComponent from './components/layouts/header/HeaderComponent'; 6 | import FooterComponent from './components/layouts/footer/FooterComponent'; 7 | import Script from 'next/script'; 8 | import { ToastContainer } from 'react-toastify'; 9 | import 'react-toastify/dist/ReactToastify.css'; 10 | 11 | const poppins = Poppins({ 12 | subsets: ['latin'], 13 | weight: ['200', '100', '300', '400', '500', '600', '700', '800'], 14 | }); 15 | 16 | export const metadata: Metadata = { 17 | title: "Alamin's algorithm visualization.", 18 | description: 'A curated collection of algorithm and work by Alamin', 19 | }; 20 | 21 | export default function RootLayout({ 22 | children, 23 | }: Readonly<{ 24 | children: React.ReactNode; 25 | }>) { 26 | return ( 27 | 28 | 29 | 30 |
{children}
31 | 32 | 33 | 34 |