├── .circleci └── config.yml ├── .gitignore ├── .prettierrc ├── .stylelintrc.json ├── README.md ├── images ├── App.png ├── BubbleSort.gif ├── CountingSort.gif └── bucketsort.gif ├── jsdoc.conf.json ├── package-lock.json ├── package.json ├── public ├── Thumbnail.png ├── barChart.png ├── index.html ├── manifest.json └── robots.txt └── src ├── __tests__ └── visualizer │ └── algorithm │ └── sortingalgorithms │ ├── bubbleSort.test.js │ ├── bucketSort.test.js │ ├── countingSort.test.js │ ├── heapSort.test.js │ ├── insertionSort.test.js │ ├── mergeSort.test.js │ ├── quickSort.test.js │ ├── radixSort.test.js │ ├── selectionSort.test.js │ └── shellSort.test.js ├── _testutil ├── ArraysBucketUtil.js ├── ArraysRadixUtil.js ├── ArraysUtil.js └── TestUtil.js ├── app ├── App.css └── App.js ├── component ├── IsVisibleYDirection │ └── IsVisibleYDirection.js ├── header │ ├── SectionHeader.js │ └── styles.css ├── logo │ ├── logo.js │ └── styles.css └── navigationMenu │ ├── NavigationMenu.js │ └── styles.css ├── contactus ├── ContactUs.js ├── body │ ├── Form.js │ ├── Notification.js │ └── styles.css ├── contactusheader │ ├── ContactUsHeader.js │ └── styles.css ├── footer │ ├── Footer.js │ └── styles.css └── styles.css ├── home ├── Home.js ├── homedescription │ ├── HomeDescription.js │ └── styles.css └── styles.css ├── howitworks ├── HowItWorks.js ├── StepsData.js ├── step │ ├── Step.js │ └── styles.css └── styles.css ├── index.css ├── index.js ├── reportWebVitals.js ├── setupTests.js ├── team ├── Team.js ├── TeamData.js ├── image │ ├── ashley.png │ ├── how-it-works-image.jpg │ ├── keanecjy.png │ ├── keanecjy_smaller.png │ ├── sean.jpg │ └── team-image.jpg ├── profile │ ├── Profile.js │ └── styles.css └── styles.css └── visualizer ├── algorithm ├── sortingalgorithms │ ├── allSorts.js │ ├── bubbleSort.js │ ├── bucketSort.js │ ├── countingSort.js │ ├── heapSort.js │ ├── insertionSort.js │ ├── mergeSort.js │ ├── quickSort.js │ ├── radixSort.js │ ├── selectionSort.js │ ├── shellSort.js │ └── swap.js └── stepbysteptemplate │ ├── allSortsStepByStep.js │ ├── bucketSortStepByStep.js │ ├── countingSortStepByStep.js │ ├── genericSwapStepByStep.js │ ├── heapSortStepByStep.js │ ├── mergeSortStepByStep.js │ ├── quickSortStepByStep.js │ ├── radixSortStepByStep.js │ └── selectionSortStepByStep.js ├── codeinformation ├── CodeInformation.js ├── codeexplaination │ ├── CodeExplanation.js │ ├── PerformanceSection.js │ └── styles.css ├── codetemplate │ ├── CodeTemplate.js │ ├── Selector.js │ └── styles.css ├── explanations │ ├── Explanations.js │ ├── bubbleSortEx.js │ ├── bucketSortEx.js │ ├── countingSortEx.js │ ├── heapSortEx.js │ ├── insertionSortEx.js │ ├── mergeSortEx.js │ ├── quickSortEx.js │ ├── radixSortEx.js │ ├── selectionSortEx.js │ └── shellSortEx.js ├── styles.css └── templates │ ├── Templates.js │ ├── bubbleSortTemplate.js │ ├── bucketSortTemplate.js │ ├── countingSortTemplate.js │ ├── heapSortTemplate.js │ ├── insertionSortTemplate.js │ ├── mergeSortTemplate.js │ ├── quickSortTemplate.js │ ├── radixSortTemplate.js │ ├── selectionSortTemplate.js │ └── shellSortTemplate.js └── sortingvisualizer ├── Visualizer.js ├── component ├── animationprogressbar │ └── AnimationProgressBar.js ├── animationscreen │ ├── AnimationScreen.js │ ├── AnimationScreenUtil.js │ ├── BucketSortScreen.js │ ├── CountingSortScreen.js │ ├── GenericSortScreen.js │ ├── MergeSortScreen.js │ ├── RadixSortScreen.js │ └── styles.css ├── block │ ├── AnimatedBlock.js │ ├── BucketSortBlock.js │ ├── CountBlock.js │ ├── CountingSortBlock.js │ ├── HighlightUtil.js │ ├── HighlightedOval.js │ ├── MergeSortBlock.js │ ├── Oval.js │ └── styles.css ├── button │ ├── ButtonBox.js │ ├── forwardbackbutton │ │ ├── BackButton.js │ │ ├── ForwardButton.js │ │ └── styles.css │ ├── newdatabutton │ │ ├── NewDataButton.js │ │ └── styles.css │ ├── styles.css │ └── threestatebutton │ │ ├── PlayPauseReplayButton.js │ │ ├── ThreeStateButton.js │ │ └── styles.css ├── legend │ ├── Legend.js │ ├── LegendHeader.js │ ├── LegendInformation.js │ └── styles.css ├── multipleblocks │ ├── HorizontalArray.js │ ├── StackOfAnimatedBoxes.js │ ├── StackOfBoxes.js │ └── styles.css ├── selectors │ ├── algorithmselector │ │ ├── AlgorithmSelector.js │ │ └── styles.css │ └── sliderselector │ │ ├── SelectorProps.js │ │ ├── SliderSelector.js │ │ └── styles.css └── stepbystep │ ├── StepByStep.js │ ├── StepByStepUtil.js │ └── styles.css ├── styles.css └── util ├── ArrayUtil.js ├── BucketSortUtil.js ├── CountingSortUtil.js ├── GeneralUtil.js ├── MathUtil.js ├── MergeSortUtil.js ├── QuickSortUtil.js ├── RadixSortUtil.js └── SwappingAlgoUtil.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | jobs: 3 | build: 4 | docker: 5 | - image: circleci/node:current 6 | steps: 7 | - checkout 8 | - restore_cache: # special step to restore the dependency cache 9 | key: dependency-cache-{{ checksum "package.json" }} 10 | - run: 11 | name: Setup Dependencies 12 | command: npm install 13 | - run: 14 | name: Setup Code Climate test-reporter 15 | command: | 16 | curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter 17 | chmod +x ./cc-test-reporter 18 | - save_cache: # special step to save the dependency cache 19 | key: dependency-cache-{{ checksum "package.json" }} 20 | paths: 21 | - ./node_modules 22 | - run: # run tests 23 | name: Run Test and Coverage 24 | command: | 25 | ./cc-test-reporter before-build 26 | npm test -- --coverage 27 | ./cc-test-reporter after-build -r, --id 825b263ca0cc3bd8e15a5587453c8482b670d092ff0ba4162a97c1940f9186a3 -------------------------------------------------------------------------------- /.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 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | *.log 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | .eslintcache 25 | /out 26 | /docs 27 | /.idea 28 | sort-algo.iml 29 | /.gradle -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": true, 3 | "printWidth": 100, 4 | "singleQuote": true, 5 | "tabWidth": 2, 6 | "trailingComma": "es5", 7 | "endOfLine": "auto" 8 | } 9 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard" 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CircleCI](https://circleci.com/gh/December-software-project/sort-algo/tree/main.svg?style=shield)](https://circleci.com/gh/December-software-project/sort-algo/tree/main) 2 | [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) 3 | [![Netlify Status](https://api.netlify.com/api/v1/badges/2364c0d1-0366-4601-8ce0-1ac2084a5020/deploy-status)](https://app.netlify.com/sites/algosort/deploys) 4 | [![Maintainability Status](https://api.codeclimate.com/v1/badges/b7464f445c1a7f5de797/maintainability)](https://codeclimate.com/github/December-software-project/sort-algo/maintainability) 5 | 6 | # Sort-Algo 7 | 8 | Welcome to Sort-Algo, a sorting visualiser app which helps you to learn and understand sorting algorithms through 9 | interacting animations as well as explanations.
10 |
11 | We built this app as we feel there is a lack of visual representation when students learn sorting algorithms. 12 | Hence, we would like to provide future students who are learning these sorting algorithms a platform to visualize such 13 | algorithms with step by step explanations. We hope that you enjoy learning and playing around with this visualization 14 | tool. Check out our app [here!](https://algosort.netlify.app/) 15 | 16 | ## Features preview 17 | 18 |

Bubble Sort preview

19 | 20 | 21 | 22 |
23 | 24 |

Counting Sort preview

25 | 26 | 27 | 28 |
29 | 30 |

Bucket Sort preview

31 | 32 | 33 | 34 |
35 | 36 |
37 | 38 | ### Choose the algorithm you want 39 | 40 | There are a wide range of algorithms, each with their complexity evaluations and code in `Java` 41 | , `JavaScript`, `Python` and `C/C++`. 42 | 43 | Available algorithms: 44 | 45 | * Bubble Sort 46 | * Insertion Sort 47 | * Selection Sort 48 | * Merge Sort 49 | * Quick Sort 50 | * Heap Sort 51 | * Shell Sort 52 | * Counting Sort 53 | * Radix Sort 54 | * Bucket Sort 55 | 56 | ### Adjust the speed of the visualizer and array size 57 | 58 | There are sliders to adjust the size and speed of the visualizer. The speed ranges from 1-10 and size ranges from 5-25 59 | or 1-10 depending on the algorithm selected. 60 | 61 | ### Start the animation 62 | 63 | There is a play button which starts the animation. Additionally, at any point in time, you can also pause the animation. Once 64 | the animation is completed, the play button will be replaced with a replay button. 65 | 66 | ### Step tracing 67 | 68 | There is a step tracing feature provided whereby pressing the arrow buttons will allow you to execute the animation step 69 | by step to fully understand how the algorithm works through visual animation and a description of what is happening at 70 | each step. 71 | 72 | ## Project structure 73 | 74 | The current project structure and its important directories are shown below: 75 | 76 | ``` 77 | SortAlgo 78 | └─public/ 79 | └─src/ 80 | └─__test__/ 81 | └─app/ 82 | └─component/ 83 | └─contactus/ 84 | └─home/ 85 | └─howitworks/ 86 | └─team/ 87 | └─visualizer/ 88 | └─index 89 | ``` 90 | 91 | ## Collaboration 92 | 93 | If you like this project, and wish to contribute more to it, do contact us through the form in the 94 | `Contact Us` section from the [website](https://algosort.netlify.app/). 95 | -------------------------------------------------------------------------------- /images/App.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/images/App.png -------------------------------------------------------------------------------- /images/BubbleSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/images/BubbleSort.gif -------------------------------------------------------------------------------- /images/CountingSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/images/CountingSort.gif -------------------------------------------------------------------------------- /images/bucketsort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/images/bucketsort.gif -------------------------------------------------------------------------------- /jsdoc.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": true, 4 | "dictionaries": ["jsdoc", "closure"] 5 | }, 6 | "source": { 7 | "include": ["src"], 8 | "includePattern": ".+\\.js(doc|x)?$", 9 | "excludePattern": "(^|\\/|\\\\)_" 10 | }, 11 | "plugins": ["plugins/markdown", "better-docs/component", "better-docs/category"], 12 | "opts": { 13 | "destination": "docs", 14 | "recurse": true, 15 | "readme": "README.md", 16 | "template": "node_modules/better-docs" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "temp", 3 | "description": "Sorting visualizer web application created for students to learn and understand sorting algorithms better!", 4 | "version": "0.1.0", 5 | "dependencies": { 6 | "@ant-design/icons": "^4.3.0", 7 | "@material-ui/core": "^4.11.2", 8 | "@material-ui/lab": "^4.0.0-alpha.57", 9 | "@testing-library/jest-dom": "^5.11.6", 10 | "@testing-library/react": "^11.2.2", 11 | "@testing-library/user-event": "^12.5.0", 12 | "ace-builds": "^1.4.12", 13 | "antd": "^4.9.2", 14 | "better-docs": "^2.3.2", 15 | "emailjs-com": "^2.6.4", 16 | "formik": "^2.2.6", 17 | "intersection-observer": "^0.11.0", 18 | "lodash": "^4.17.20", 19 | "react": "^17.0.1", 20 | "react-ace": "^9.2.1", 21 | "react-dom": "^17.0.1", 22 | "react-hexagon": "^1.1.3", 23 | "react-icons": "^4.1.0", 24 | "react-is-visible": "^1.1.1", 25 | "react-particles-js": "^3.4.1", 26 | "react-scripts": "4.0.1", 27 | "react-spring": "^8.0.27", 28 | "react-svg-path": "^1.4.3", 29 | "react-tsparticles": "^1.18.11", 30 | "web-vitals": "^0.2.4", 31 | "yup": "^0.32.8" 32 | }, 33 | "scripts": { 34 | "start": "react-scripts start", 35 | "build": "react-scripts build", 36 | "test": "react-scripts test --coverage --watchAll=false", 37 | "eject": "react-scripts eject", 38 | "pretty": "prettier --write \"./**/*.{js,jsx,json,css}\"", 39 | "docs": "jsdoc -c jsdoc.conf.json", 40 | "css": "npx stylelint \"src/**/*.css\"" 41 | }, 42 | "repository": { 43 | "type": "git", 44 | "url": "https://github.com/December-software-project/sort-algo" 45 | }, 46 | "keywords": [ 47 | "Sorting", 48 | "Visualizer", 49 | "algorithms", 50 | "sort", 51 | "Data structures" 52 | ], 53 | "contributors": [ 54 | "Keane Chan Jun Yu", 55 | "Sean Lum Jian Yang", 56 | "Ashley Lau Jun Hao" 57 | ], 58 | "eslintConfig": { 59 | "extends": [ 60 | "react-app", 61 | "react-app/jest" 62 | ] 63 | }, 64 | "browserslist": { 65 | "production": [ 66 | ">0.2%", 67 | "not dead", 68 | "not op_mini all" 69 | ], 70 | "development": [ 71 | "last 1 chrome version", 72 | "last 1 firefox version", 73 | "last 1 safari version" 74 | ] 75 | }, 76 | "devDependencies": { 77 | "@material-ui/icons": "^4.11.2", 78 | "jsdoc": "^3.6.6", 79 | "prettier": "^2.2.1", 80 | "stylelint": "^13.8.0", 81 | "stylelint-config-standard": "^20.0.0" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /public/Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/public/Thumbnail.png -------------------------------------------------------------------------------- /public/barChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/public/barChart.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 23 | 24 | 33 | 34 | 38 | SortAlgo 39 | 40 | 41 | 42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "SortAlgo", 3 | "name": "SortAlgo sorting visualizer Web Application", 4 | "icons": [ 5 | { 6 | "src": "barChart.png", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/__tests__/visualizer/algorithm/sortingalgorithms/bubbleSort.test.js: -------------------------------------------------------------------------------- 1 | import bubbleSort from '../../../../visualizer/algorithm/sortingalgorithms/bubbleSort'; 2 | import { assertSortSuccess } from '../../../../_testutil/TestUtil'; 3 | import { 4 | ANIMATION_ARRAY_ALREADY_SORTED, 5 | ARRAY_DUPLICATES, 6 | ARRAY_EXPECTED_RANDOM_MIXED, 7 | ARRAY_EXPECTED_RANDOM_NEGATIVE, 8 | ARRAY_EXPECTED_RANDOM_POSITIVE, 9 | ARRAY_EXPECTED_STRICTLY_DESCENDING, 10 | ARRAY_RANDOM_MIXED, 11 | ARRAY_RANDOM_NEGATIVE, 12 | ARRAY_RANDOM_POSITIVE, 13 | ARRAY_STRICTLY_ASCENDING, 14 | ARRAY_STRICTLY_DESCENDING, 15 | } from '../../../../_testutil/ArraysUtil'; 16 | 17 | test('Already Sorted with duplicates', () => { 18 | assertBubbleSortSuccess(ARRAY_DUPLICATES, ARRAY_DUPLICATES, ANIMATION_ARRAY_ALREADY_SORTED); 19 | }); 20 | 21 | test('Already Sorted ascending', () => { 22 | assertBubbleSortSuccess( 23 | ARRAY_STRICTLY_ASCENDING, 24 | ARRAY_STRICTLY_ASCENDING, 25 | ANIMATION_ARRAY_ALREADY_SORTED 26 | ); 27 | }); 28 | 29 | test('Descending array', () => { 30 | const expected = [ 31 | [1, 0, false], 32 | [1, 0, true], 33 | [2, 1, false], 34 | [2, 1, true], 35 | [3, 2, false], 36 | [3, 2, true], 37 | [1, 0, false], 38 | [1, 0, true], 39 | [2, 1, false], 40 | [2, 1, true], 41 | [1, 0, false], 42 | [1, 0, true], 43 | ]; 44 | 45 | assertBubbleSortSuccess(ARRAY_STRICTLY_DESCENDING, ARRAY_EXPECTED_STRICTLY_DESCENDING, expected); 46 | }); 47 | 48 | test('Random array positive numbers', () => { 49 | const expected = [ 50 | [1, 0, false], 51 | [2, 1, false], 52 | [2, 1, true], 53 | [3, 2, false], 54 | [3, 2, true], 55 | [1, 0, false], 56 | [2, 1, false], 57 | ]; 58 | 59 | assertBubbleSortSuccess(ARRAY_RANDOM_POSITIVE, ARRAY_EXPECTED_RANDOM_POSITIVE, expected); 60 | }); 61 | 62 | test('Random array negative numbers', () => { 63 | const expected = [ 64 | [1, 0, false], 65 | [1, 0, true], 66 | [2, 1, false], 67 | [2, 1, true], 68 | [3, 2, false], 69 | [3, 2, true], 70 | [1, 0, false], 71 | [2, 1, false], 72 | [2, 1, true], 73 | [1, 0, false], 74 | ]; 75 | 76 | assertBubbleSortSuccess(ARRAY_RANDOM_NEGATIVE, ARRAY_EXPECTED_RANDOM_NEGATIVE, expected); 77 | }); 78 | 79 | test('Random array negative and positive numbers', () => { 80 | const expected = [ 81 | [1, 0, false], 82 | [2, 1, false], 83 | [2, 1, true], 84 | [3, 2, false], 85 | [3, 2, true], 86 | [1, 0, false], 87 | [2, 1, false], 88 | [2, 1, true], 89 | [1, 0, false], 90 | [1, 0, true], 91 | ]; 92 | 93 | assertBubbleSortSuccess(ARRAY_RANDOM_MIXED, ARRAY_EXPECTED_RANDOM_MIXED, expected); 94 | }); 95 | 96 | const assertBubbleSortSuccess = (initialArray, sortedArray, expected) => 97 | assertSortSuccess(initialArray, sortedArray, expected, bubbleSort); 98 | -------------------------------------------------------------------------------- /src/__tests__/visualizer/algorithm/sortingalgorithms/countingSort.test.js: -------------------------------------------------------------------------------- 1 | import countingSort from '../../../../visualizer/algorithm/sortingalgorithms/countingSort'; 2 | import { assertSortSuccess } from '../../../../_testutil/TestUtil'; 3 | import { 4 | ARRAY_DUPLICATES, 5 | ARRAY_EXPECTED_RANDOM_POSITIVE, 6 | ARRAY_EXPECTED_STRICTLY_DESCENDING, 7 | ARRAY_RANDOM_POSITIVE, 8 | ARRAY_STRICTLY_ASCENDING, 9 | ARRAY_STRICTLY_DESCENDING, 10 | } from '../../../../_testutil/ArraysUtil'; 11 | 12 | test('Already Sorted with duplicates', () => { 13 | assertCountSortSuccess(ARRAY_DUPLICATES, ARRAY_DUPLICATES); 14 | }); 15 | 16 | test('Already Sorted ascending', () => { 17 | assertCountSortSuccess(ARRAY_STRICTLY_ASCENDING, ARRAY_STRICTLY_ASCENDING); 18 | }); 19 | 20 | test('Descending array', () => { 21 | assertCountSortSuccess(ARRAY_STRICTLY_DESCENDING, ARRAY_EXPECTED_STRICTLY_DESCENDING); 22 | }); 23 | 24 | test('Random array positive numbers', () => { 25 | assertCountSortSuccess(ARRAY_RANDOM_POSITIVE, ARRAY_EXPECTED_RANDOM_POSITIVE); 26 | }); 27 | 28 | const assertCountSortSuccess = (initialArray, sortedArray) => { 29 | const appendedArray = generateAppendedArray(sortedArray); 30 | const expected = initialArray.concat(appendedArray); 31 | assertSortSuccess(initialArray, initialArray, expected, countingSort); 32 | }; 33 | 34 | const generateAppendedArray = (arr) => { 35 | let id = -1; 36 | return arr.map((obj) => ({ 37 | id: (id += 1), 38 | height: obj.height, 39 | isShown: true, 40 | })); 41 | }; 42 | -------------------------------------------------------------------------------- /src/__tests__/visualizer/algorithm/sortingalgorithms/insertionSort.test.js: -------------------------------------------------------------------------------- 1 | import insertionSort from '../../../../visualizer/algorithm/sortingalgorithms/insertionSort'; 2 | import { assertSortSuccess } from '../../../../_testutil/TestUtil'; 3 | import { 4 | ANIMATION_ARRAY_ALREADY_SORTED, 5 | ARRAY_DUPLICATES, 6 | ARRAY_EXPECTED_RANDOM_MIXED, 7 | ARRAY_EXPECTED_RANDOM_NEGATIVE, 8 | ARRAY_EXPECTED_RANDOM_POSITIVE, 9 | ARRAY_EXPECTED_STRICTLY_DESCENDING, 10 | ARRAY_RANDOM_MIXED, 11 | ARRAY_RANDOM_NEGATIVE, 12 | ARRAY_RANDOM_POSITIVE, 13 | ARRAY_STRICTLY_ASCENDING, 14 | ARRAY_STRICTLY_DESCENDING, 15 | } from '../../../../_testutil/ArraysUtil'; 16 | 17 | test('Already Sorted with duplicates', () => { 18 | assertInsertionSortSuccess(ARRAY_DUPLICATES, ARRAY_DUPLICATES, ANIMATION_ARRAY_ALREADY_SORTED); 19 | }); 20 | 21 | test('Already Sorted ascending', () => { 22 | assertInsertionSortSuccess( 23 | ARRAY_STRICTLY_ASCENDING, 24 | ARRAY_STRICTLY_ASCENDING, 25 | ANIMATION_ARRAY_ALREADY_SORTED 26 | ); 27 | }); 28 | 29 | test('Descending array', () => { 30 | const expected = [ 31 | [1, 0, false], 32 | [1, 0, true], 33 | [2, 1, false], 34 | [2, 1, true], 35 | [1, 0, false], 36 | [1, 0, true], 37 | [3, 2, false], 38 | [3, 2, true], 39 | [2, 1, false], 40 | [2, 1, true], 41 | [1, 0, false], 42 | [1, 0, true], 43 | ]; 44 | 45 | assertInsertionSortSuccess( 46 | ARRAY_STRICTLY_DESCENDING, 47 | ARRAY_EXPECTED_STRICTLY_DESCENDING, 48 | expected 49 | ); 50 | }); 51 | 52 | test('Random array positive numbers', () => { 53 | const expected = [ 54 | [1, 0, false], 55 | [2, 1, false], 56 | [2, 1, true], 57 | [3, 2, false], 58 | [3, 2, true], 59 | ]; 60 | 61 | assertInsertionSortSuccess(ARRAY_RANDOM_POSITIVE, ARRAY_EXPECTED_RANDOM_POSITIVE, expected); 62 | }); 63 | 64 | test('Random array negative numbers', () => { 65 | const expected = [ 66 | [1, 0, false], 67 | [1, 0, true], 68 | [2, 1, false], 69 | [2, 1, true], 70 | [3, 2, false], 71 | [3, 2, true], 72 | [2, 1, false], 73 | [2, 1, true], 74 | ]; 75 | 76 | assertInsertionSortSuccess(ARRAY_RANDOM_NEGATIVE, ARRAY_EXPECTED_RANDOM_NEGATIVE, expected); 77 | }); 78 | 79 | test('Random array negative and positive numbers', () => { 80 | const expected = [ 81 | [1, 0, false], 82 | [2, 1, false], 83 | [2, 1, true], 84 | [3, 2, false], 85 | [3, 2, true], 86 | [2, 1, false], 87 | [2, 1, true], 88 | [1, 0, false], 89 | [1, 0, true], 90 | ]; 91 | 92 | assertInsertionSortSuccess(ARRAY_RANDOM_MIXED, ARRAY_EXPECTED_RANDOM_MIXED, expected); 93 | }); 94 | 95 | const assertInsertionSortSuccess = (initialArray, sortedArray, expected) => 96 | assertSortSuccess(initialArray, sortedArray, expected, insertionSort); 97 | -------------------------------------------------------------------------------- /src/__tests__/visualizer/algorithm/sortingalgorithms/mergeSort.test.js: -------------------------------------------------------------------------------- 1 | import mergeSort from '../../../../visualizer/algorithm/sortingalgorithms/mergeSort'; 2 | import { assertSortSuccess } from '../../../../_testutil/TestUtil'; 3 | import { 4 | ARRAY_DUPLICATES, 5 | ARRAY_EXPECTED_RANDOM_MIXED, 6 | ARRAY_EXPECTED_RANDOM_NEGATIVE, 7 | ARRAY_EXPECTED_RANDOM_POSITIVE, 8 | ARRAY_EXPECTED_STRICTLY_DESCENDING, 9 | ARRAY_RANDOM_MIXED, 10 | ARRAY_RANDOM_NEGATIVE, 11 | ARRAY_RANDOM_POSITIVE, 12 | ARRAY_STRICTLY_ASCENDING, 13 | ARRAY_STRICTLY_DESCENDING, 14 | } from '../../../../_testutil/ArraysUtil'; 15 | 16 | const expectedForSortedAtStart = [ 17 | [-1, -1, true, -1, false, [0, 1]], 18 | [0, -1, false, 0, false], 19 | [-1, 1, false, 1, true], 20 | [-1, -1, true, -1, false, [2, 3]], 21 | [2, -1, false, 2, false], 22 | [-1, 3, false, 3, true], 23 | [-1, -1, true, -1, false, [0, 1, 2, 3]], 24 | [0, -1, false, 0, false], 25 | [1, -1, false, 1, false], 26 | [-1, 2, false, 2, false], 27 | [-1, 3, false, 3, true], 28 | ]; 29 | 30 | test('Already Sorted with duplicates', () => { 31 | assertMergeSortSuccess(ARRAY_DUPLICATES, ARRAY_DUPLICATES, expectedForSortedAtStart); 32 | }); 33 | 34 | test('Already Sorted ascending', () => { 35 | assertMergeSortSuccess( 36 | ARRAY_STRICTLY_ASCENDING, 37 | ARRAY_STRICTLY_ASCENDING, 38 | expectedForSortedAtStart 39 | ); 40 | }); 41 | 42 | test('Descending array', () => { 43 | const expected = [ 44 | [-1, -1, true, -1, false, [0, 1]], 45 | [-1, 1, false, 0, false], 46 | [0, -1, false, 1, true], 47 | [-1, -1, true, -1, false, [2, 3]], 48 | [-1, 3, false, 2, false], 49 | [2, -1, false, 3, true], 50 | [-1, -1, true, -1, false, [0, 1, 2, 3]], 51 | [-1, 2, false, 0, false], 52 | [-1, 3, false, 1, false], 53 | [0, -1, false, 2, false], 54 | [1, -1, false, 3, true], 55 | ]; 56 | 57 | assertMergeSortSuccess(ARRAY_STRICTLY_DESCENDING, ARRAY_EXPECTED_STRICTLY_DESCENDING, expected); 58 | }); 59 | 60 | test('Random array positive numbers', () => { 61 | const expected = [ 62 | [-1, -1, true, -1, false, [0, 1]], 63 | [0, -1, false, 0, false], 64 | [-1, 1, false, 1, true], 65 | [-1, -1, true, -1, false, [2, 3]], 66 | [2, -1, false, 2, false], 67 | [-1, 3, false, 3, true], 68 | [-1, -1, true, -1, false, [0, 1, 2, 3]], 69 | [0, -1, false, 0, false], 70 | [-1, 2, false, 1, false], 71 | [-1, 3, false, 2, false], 72 | [1, -1, false, 3, true], 73 | ]; 74 | 75 | assertMergeSortSuccess(ARRAY_RANDOM_POSITIVE, ARRAY_EXPECTED_RANDOM_POSITIVE, expected); 76 | }); 77 | 78 | test('Random array negative numbers', () => { 79 | const expected = [ 80 | [-1, -1, true, -1, false, [0, 1]], 81 | [-1, 1, false, 0, false], 82 | [0, -1, false, 1, true], 83 | [-1, -1, true, -1, false, [2, 3]], 84 | [-1, 3, false, 2, false], 85 | [2, -1, false, 3, true], 86 | [-1, -1, true, -1, false, [0, 1, 2, 3]], 87 | [0, -1, false, 0, false], 88 | [-1, 2, false, 1, false], 89 | [-1, 3, false, 2, false], 90 | [1, -1, false, 3, true], 91 | ]; 92 | 93 | assertMergeSortSuccess(ARRAY_RANDOM_NEGATIVE, ARRAY_EXPECTED_RANDOM_NEGATIVE, expected); 94 | }); 95 | 96 | test('Random array negative and positive numbers', () => { 97 | const expected = [ 98 | [-1, -1, true, -1, false, [0, 1]], 99 | [0, -1, false, 0, false], 100 | [-1, 1, false, 1, true], 101 | [-1, -1, true, -1, false, [2, 3]], 102 | [-1, 3, false, 2, false], 103 | [2, -1, false, 3, true], 104 | [-1, -1, true, -1, false, [0, 1, 2, 3]], 105 | [-1, 2, false, 0, false], 106 | [0, -1, false, 1, false], 107 | [-1, 3, false, 2, false], 108 | [1, -1, false, 3, true], 109 | ]; 110 | 111 | assertMergeSortSuccess(ARRAY_RANDOM_MIXED, ARRAY_EXPECTED_RANDOM_MIXED, expected); 112 | }); 113 | 114 | const assertMergeSortSuccess = (initialArray, sortedArray, expected) => 115 | assertSortSuccess(initialArray, sortedArray, expected, mergeSort); 116 | -------------------------------------------------------------------------------- /src/__tests__/visualizer/algorithm/sortingalgorithms/quickSort.test.js: -------------------------------------------------------------------------------- 1 | import quickSort from '../../../../visualizer/algorithm/sortingalgorithms/quickSort'; 2 | import { assertSortSuccess } from '../../../../_testutil/TestUtil'; 3 | import { 4 | ARRAY_DUPLICATES, 5 | ARRAY_EXPECTED_RANDOM_MIXED, 6 | ARRAY_EXPECTED_RANDOM_NEGATIVE, 7 | ARRAY_EXPECTED_RANDOM_POSITIVE, 8 | ARRAY_EXPECTED_STRICTLY_DESCENDING, 9 | ARRAY_RANDOM_MIXED, 10 | ARRAY_RANDOM_NEGATIVE, 11 | ARRAY_RANDOM_POSITIVE, 12 | ARRAY_STRICTLY_ASCENDING, 13 | ARRAY_STRICTLY_DESCENDING, 14 | } from '../../../../_testutil/ArraysUtil'; 15 | 16 | test('Already Sorted with duplicates', () => { 17 | const expected = [ 18 | [0, 0, false, 3, 'jToPivot', -1], 19 | [1, 1, false, 3, 'jToPivot', -1], 20 | [2, 2, false, 3, 'jToPivot', -1], 21 | [0, 3, true, 3, 'swapPivot', -1], 22 | [1, 1, false, 3, 'jToPivot', 0], 23 | [2, 2, false, 3, 'jToPivot', 0], 24 | [1, 3, true, 3, 'swapPivot', 0], 25 | [2, 2, false, 3, 'jToPivot', 1], 26 | [2, 3, true, 3, 'swapPivot', 1], 27 | ]; 28 | 29 | assertQuickSortSuccess(ARRAY_DUPLICATES, ARRAY_DUPLICATES, expected); 30 | }); 31 | 32 | test('Already Sorted ascending', () => { 33 | const expected = [ 34 | [0, 0, false, 3, 'incI', -1], 35 | [1, 1, false, 3, 'incI', 0], 36 | [2, 2, false, 3, 'incI', 1], 37 | [3, 3, true, 3, 'swapPivot', 2], 38 | [0, 0, false, 2, 'incI', -1], 39 | [1, 1, false, 2, 'incI', 0], 40 | [2, 2, true, 2, 'swapPivot', 1], 41 | [0, 0, false, 1, 'incI', -1], 42 | [1, 1, true, 1, 'swapPivot', 0], 43 | ]; 44 | 45 | assertQuickSortSuccess(ARRAY_STRICTLY_ASCENDING, ARRAY_STRICTLY_ASCENDING, expected); 46 | }); 47 | 48 | test('Descending array', () => { 49 | const expected = [ 50 | [0, 0, false, 3, 'jToPivot', -1], 51 | [1, 1, false, 3, 'jToPivot', -1], 52 | [2, 2, false, 3, 'jToPivot', -1], 53 | [0, 3, true, 3, 'swapPivot', -1], 54 | [1, 1, false, 3, 'incI', 0], 55 | [2, 2, false, 3, 'incI', 1], 56 | [3, 3, true, 3, 'swapPivot', 2], 57 | [1, 1, false, 2, 'jToPivot', 0], 58 | [1, 2, true, 2, 'swapPivot', 0], 59 | ]; 60 | 61 | assertQuickSortSuccess(ARRAY_STRICTLY_DESCENDING, ARRAY_EXPECTED_STRICTLY_DESCENDING, expected); 62 | }); 63 | 64 | test('Random array positive numbers', () => { 65 | const expected = [ 66 | [0, 0, false, 3, 'incI', -1], 67 | [1, 1, false, 3, 'jToPivot', 0], 68 | [2, 2, false, 3, 'incI', 0], 69 | [1, 2, true, 3, 'iToJ', 1], 70 | [2, 3, true, 3, 'swapPivot', 1], 71 | [0, 0, false, 1, 'incI', -1], 72 | [1, 1, true, 1, 'swapPivot', 0], 73 | ]; 74 | 75 | assertQuickSortSuccess(ARRAY_RANDOM_POSITIVE, ARRAY_EXPECTED_RANDOM_POSITIVE, expected); 76 | }); 77 | 78 | test('Random array negative numbers', () => { 79 | const expected = [ 80 | [0, 0, false, 3, 'jToPivot', -1], 81 | [1, 1, false, 3, 'incI', -1], 82 | [0, 1, true, 3, 'iToJ', 0], 83 | [2, 2, false, 3, 'jToPivot', 0], 84 | [1, 3, true, 3, 'swapPivot', 0], 85 | [2, 2, false, 3, 'incI', 1], 86 | [3, 3, true, 3, 'swapPivot', 2], 87 | ]; 88 | 89 | assertQuickSortSuccess(ARRAY_RANDOM_NEGATIVE, ARRAY_EXPECTED_RANDOM_NEGATIVE, expected); 90 | }); 91 | 92 | test('Random array negative and positive numbers', () => { 93 | const expected = [ 94 | [0, 0, false, 3, 'jToPivot', -1], 95 | [1, 1, false, 3, 'jToPivot', -1], 96 | [2, 2, false, 3, 'jToPivot', -1], 97 | [0, 3, true, 3, 'swapPivot', -1], 98 | [1, 1, false, 3, 'jToPivot', 0], 99 | [2, 2, false, 3, 'jToPivot', 0], 100 | [1, 3, true, 3, 'swapPivot', 0], 101 | [2, 2, false, 3, 'incI', 1], 102 | [3, 3, true, 3, 'swapPivot', 2], 103 | ]; 104 | 105 | assertQuickSortSuccess(ARRAY_RANDOM_MIXED, ARRAY_EXPECTED_RANDOM_MIXED, expected); 106 | }); 107 | 108 | const assertQuickSortSuccess = (initialArray, sortedArray, expected) => 109 | assertSortSuccess(initialArray, sortedArray, expected, quickSort); 110 | -------------------------------------------------------------------------------- /src/__tests__/visualizer/algorithm/sortingalgorithms/selectionSort.test.js: -------------------------------------------------------------------------------- 1 | import selectionSort from '../../../../visualizer/algorithm/sortingalgorithms/selectionSort'; 2 | import { assertSortSuccess } from '../../../../_testutil/TestUtil'; 3 | import { 4 | ARRAY_DUPLICATES, 5 | ARRAY_EXPECTED_RANDOM_MIXED, 6 | ARRAY_EXPECTED_RANDOM_NEGATIVE, 7 | ARRAY_EXPECTED_RANDOM_POSITIVE, 8 | ARRAY_EXPECTED_STRICTLY_DESCENDING, 9 | ARRAY_RANDOM_MIXED, 10 | ARRAY_RANDOM_NEGATIVE, 11 | ARRAY_RANDOM_POSITIVE, 12 | ARRAY_STRICTLY_ASCENDING, 13 | ARRAY_STRICTLY_DESCENDING, 14 | } from '../../../../_testutil/ArraysUtil'; 15 | 16 | test('Already Sorted with duplicates', () => { 17 | const expected = [ 18 | [0, 1, false], 19 | [0, 2, false], 20 | [0, 3, false], 21 | [1, 2, false], 22 | [1, 3, false], 23 | [2, 3, false], 24 | ]; 25 | 26 | assertSelectionSortSuccess(ARRAY_DUPLICATES, ARRAY_DUPLICATES, expected); 27 | }); 28 | 29 | test('Already Sorted ascending', () => { 30 | const expected = [ 31 | [0, 1, false], 32 | [0, 2, false], 33 | [0, 3, false], 34 | [1, 2, false], 35 | [1, 3, false], 36 | [2, 3, false], 37 | ]; 38 | 39 | assertSelectionSortSuccess(ARRAY_STRICTLY_ASCENDING, ARRAY_STRICTLY_ASCENDING, expected); 40 | }); 41 | 42 | test('Descending array', () => { 43 | const expected = [ 44 | [0, 1, false], 45 | [1, 2, false], 46 | [2, 3, false], 47 | [3, 0, true], 48 | [1, 2, false], 49 | [2, 3, false], 50 | [2, 1, true], 51 | [2, 3, false], 52 | ]; 53 | 54 | assertSelectionSortSuccess( 55 | ARRAY_STRICTLY_DESCENDING, 56 | ARRAY_EXPECTED_STRICTLY_DESCENDING, 57 | expected 58 | ); 59 | }); 60 | 61 | test('Random array positive numbers', () => { 62 | const expected = [ 63 | [0, 1, false], 64 | [0, 2, false], 65 | [0, 3, false], 66 | [1, 2, false], 67 | [2, 3, false], 68 | [2, 1, true], 69 | [2, 3, false], 70 | [3, 2, true], 71 | ]; 72 | 73 | assertSelectionSortSuccess(ARRAY_RANDOM_POSITIVE, ARRAY_EXPECTED_RANDOM_POSITIVE, expected); 74 | }); 75 | 76 | test('Random array negative numbers', () => { 77 | const expected = [ 78 | [0, 1, false], 79 | [1, 2, false], 80 | [1, 3, false], 81 | [1, 0, true], 82 | [1, 2, false], 83 | [2, 3, false], 84 | [3, 1, true], 85 | [2, 3, false], 86 | ]; 87 | 88 | assertSelectionSortSuccess(ARRAY_RANDOM_NEGATIVE, ARRAY_EXPECTED_RANDOM_NEGATIVE, expected); 89 | }); 90 | 91 | test('Random array negative and positive numbers', () => { 92 | const expected = [ 93 | [0, 1, false], 94 | [0, 2, false], 95 | [0, 3, false], 96 | [3, 0, true], 97 | [1, 2, false], 98 | [2, 3, false], 99 | [3, 1, true], 100 | [2, 3, false], 101 | ]; 102 | 103 | assertSelectionSortSuccess(ARRAY_RANDOM_MIXED, ARRAY_EXPECTED_RANDOM_MIXED, expected); 104 | }); 105 | 106 | const assertSelectionSortSuccess = (initialArray, sortedArray, expected) => 107 | assertSortSuccess(initialArray, sortedArray, expected, selectionSort); 108 | -------------------------------------------------------------------------------- /src/__tests__/visualizer/algorithm/sortingalgorithms/shellSort.test.js: -------------------------------------------------------------------------------- 1 | import shellSort from '../../../../visualizer/algorithm/sortingalgorithms/shellSort'; 2 | import { assertSortSuccess } from '../../../../_testutil/TestUtil'; 3 | import { 4 | ARRAY_DUPLICATES, 5 | ARRAY_EXPECTED_RANDOM_MIXED, 6 | ARRAY_EXPECTED_RANDOM_NEGATIVE, 7 | ARRAY_EXPECTED_RANDOM_POSITIVE, 8 | ARRAY_EXPECTED_STRICTLY_DESCENDING, 9 | ARRAY_RANDOM_MIXED, 10 | ARRAY_RANDOM_NEGATIVE, 11 | ARRAY_RANDOM_POSITIVE, 12 | ARRAY_STRICTLY_ASCENDING, 13 | ARRAY_STRICTLY_DESCENDING, 14 | } from '../../../../_testutil/ArraysUtil'; 15 | 16 | test('Already Sorted with duplicates', () => { 17 | const expected = [ 18 | [0, 2, false], 19 | [1, 3, false], 20 | [0, 1, false], 21 | [1, 2, false], 22 | [2, 3, false], 23 | ]; 24 | 25 | assertShellSortSuccess(ARRAY_DUPLICATES, ARRAY_DUPLICATES, expected); 26 | }); 27 | 28 | test('Already Sorted ascending', () => { 29 | const expected = [ 30 | [0, 2, false], 31 | [1, 3, false], 32 | [0, 1, false], 33 | [1, 2, false], 34 | [2, 3, false], 35 | ]; 36 | 37 | assertShellSortSuccess(ARRAY_STRICTLY_ASCENDING, ARRAY_STRICTLY_ASCENDING, expected); 38 | }); 39 | 40 | test('Descending array', () => { 41 | const expected = [ 42 | [0, 2, false], 43 | [0, 2, true], 44 | [1, 3, false], 45 | [1, 3, true], 46 | [0, 1, false], 47 | [0, 1, true], 48 | [1, 2, false], 49 | [2, 3, false], 50 | [2, 3, true], 51 | [1, 2, false], 52 | ]; 53 | 54 | assertShellSortSuccess(ARRAY_STRICTLY_DESCENDING, ARRAY_EXPECTED_STRICTLY_DESCENDING, expected); 55 | }); 56 | 57 | test('Random array positive numbers', () => { 58 | const expected = [ 59 | [0, 2, false], 60 | [1, 3, false], 61 | [1, 3, true], 62 | [0, 1, false], 63 | [1, 2, false], 64 | [1, 2, true], 65 | [0, 1, false], 66 | [2, 3, false], 67 | ]; 68 | 69 | assertShellSortSuccess(ARRAY_RANDOM_POSITIVE, ARRAY_EXPECTED_RANDOM_POSITIVE, expected); 70 | }); 71 | 72 | test('Random array negative numbers', () => { 73 | const expected = [ 74 | [0, 2, false], 75 | [0, 2, true], 76 | [1, 3, false], 77 | [0, 1, false], 78 | [0, 1, true], 79 | [1, 2, false], 80 | [2, 3, false], 81 | [2, 3, true], 82 | [1, 2, false], 83 | [1, 2, true], 84 | [0, 1, false], 85 | ]; 86 | 87 | assertShellSortSuccess(ARRAY_RANDOM_NEGATIVE, ARRAY_EXPECTED_RANDOM_NEGATIVE, expected); 88 | }); 89 | 90 | test('Random array negative and positive numbers', () => { 91 | const expected = [ 92 | [0, 2, false], 93 | [1, 3, false], 94 | [1, 3, true], 95 | [0, 1, false], 96 | [0, 1, true], 97 | [1, 2, false], 98 | [2, 3, false], 99 | ]; 100 | 101 | assertShellSortSuccess(ARRAY_RANDOM_MIXED, ARRAY_EXPECTED_RANDOM_MIXED, expected); 102 | }); 103 | 104 | const assertShellSortSuccess = (initialArray, sortedArray, expected) => 105 | assertSortSuccess(initialArray, sortedArray, expected, shellSort); 106 | -------------------------------------------------------------------------------- /src/_testutil/ArraysBucketUtil.js: -------------------------------------------------------------------------------- 1 | export const ARRAY_DUPLICATES = [ 2 | { id: 1, height: 0.9 }, 3 | { id: 2, height: 0.9 }, 4 | { id: 3, height: 0.9 }, 5 | { id: 4, height: 0.9 }, 6 | ]; 7 | 8 | export const ARRAY_ASCENDING_IN_BUCKET = [ 9 | { id: 1, height: 0.111 }, 10 | { id: 2, height: 0.123 }, 11 | { id: 3, height: 0.133 }, 12 | { id: 4, height: 0.145 }, 13 | ]; 14 | 15 | export const ARRAY_DIFFERENT_BUCKETS = [ 16 | { id: 1, height: 0.89 }, 17 | { id: 2, height: 0.334 }, 18 | { id: 3, height: 0.417 }, 19 | { id: 4, height: 0.12 }, 20 | ]; 21 | 22 | export const ARRAY_MIXED_BUCKETS = [ 23 | { id: 1, height: 0.787 }, 24 | { id: 2, height: 0.7 }, 25 | { id: 3, height: 0.678 }, 26 | { id: 4, height: 0.654 }, 27 | ]; 28 | -------------------------------------------------------------------------------- /src/_testutil/ArraysRadixUtil.js: -------------------------------------------------------------------------------- 1 | export const ARRAY_TWO_DIGITS = [ 2 | { id: 1, height: 32 }, 3 | { id: 2, height: 44 }, 4 | { id: 3, height: 41 }, 5 | { id: 4, height: 32 }, 6 | ]; 7 | 8 | export const ARRAY_THREE_DIGITS = [ 9 | { id: 1, height: 324 }, 10 | { id: 2, height: 441 }, 11 | { id: 3, height: 412 }, 12 | { id: 4, height: 323 }, 13 | ]; 14 | 15 | export const ARRAY_MIXED = [ 16 | { id: 1, height: 909 }, 17 | { id: 2, height: 9 }, 18 | { id: 3, height: 44 }, 19 | { id: 4, height: 4 }, 20 | ]; 21 | -------------------------------------------------------------------------------- /src/_testutil/ArraysUtil.js: -------------------------------------------------------------------------------- 1 | export const ARRAY_DUPLICATES = [ 2 | { id: 1, height: 3 }, 3 | { id: 2, height: 3 }, 4 | { id: 3, height: 3 }, 5 | { id: 4, height: 3 }, 6 | ]; 7 | 8 | export const ARRAY_STRICTLY_ASCENDING = [ 9 | { id: 1, height: 1 }, 10 | { id: 2, height: 2 }, 11 | { id: 3, height: 3 }, 12 | { id: 4, height: 4 }, 13 | ]; 14 | 15 | export const ARRAY_STRICTLY_DESCENDING = [ 16 | { id: 1, height: 4 }, 17 | { id: 2, height: 3 }, 18 | { id: 3, height: 2 }, 19 | { id: 4, height: 1 }, 20 | ]; 21 | 22 | export const ARRAY_EXPECTED_STRICTLY_DESCENDING = [ 23 | { id: 4, height: 1 }, 24 | { id: 3, height: 2 }, 25 | { id: 2, height: 3 }, 26 | { id: 1, height: 4 }, 27 | ]; 28 | 29 | export const ARRAY_RANDOM_POSITIVE = [ 30 | { id: 1, height: 1 }, 31 | { id: 2, height: 5 }, 32 | { id: 3, height: 2 }, 33 | { id: 4, height: 3 }, 34 | ]; 35 | 36 | export const ARRAY_EXPECTED_RANDOM_POSITIVE = [ 37 | { id: 1, height: 1 }, 38 | { id: 3, height: 2 }, 39 | { id: 4, height: 3 }, 40 | { id: 2, height: 5 }, 41 | ]; 42 | 43 | export const ARRAY_RANDOM_NEGATIVE = [ 44 | { id: 1, height: -1 }, 45 | { id: 2, height: -5 }, 46 | { id: 3, height: -2 }, 47 | { id: 4, height: -3 }, 48 | ]; 49 | 50 | export const ARRAY_EXPECTED_RANDOM_NEGATIVE = [ 51 | { id: 2, height: -5 }, 52 | { id: 4, height: -3 }, 53 | { id: 3, height: -2 }, 54 | { id: 1, height: -1 }, 55 | ]; 56 | 57 | export const ARRAY_RANDOM_MIXED = [ 58 | { id: 1, height: -1 }, 59 | { id: 2, height: 5 }, 60 | { id: 3, height: 2 }, 61 | { id: 4, height: -3 }, 62 | ]; 63 | 64 | export const ARRAY_EXPECTED_RANDOM_MIXED = [ 65 | { id: 4, height: -3 }, 66 | { id: 1, height: -1 }, 67 | { id: 3, height: 2 }, 68 | { id: 2, height: 5 }, 69 | ]; 70 | 71 | export const ANIMATION_ARRAY_ALREADY_SORTED = [ 72 | [1, 0, false], 73 | [2, 1, false], 74 | [3, 2, false], 75 | ]; 76 | -------------------------------------------------------------------------------- /src/_testutil/TestUtil.js: -------------------------------------------------------------------------------- 1 | const assertEqual = (actual, expected) => { 2 | expect(actual).toStrictEqual(expected); 3 | }; 4 | 5 | export const assertSortSuccess = (initialArray, sortedArray, expectedArray, sortingAlgorithm) => { 6 | const animationArr = sortingAlgorithm(initialArray); 7 | assertEqual(initialArray, sortedArray); 8 | assertEqual(animationArr, expectedArray); 9 | }; 10 | -------------------------------------------------------------------------------- /src/app/App.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | scroll-behavior: smooth; 5 | scroll-padding-top: 59px; 6 | } 7 | 8 | .app { 9 | display: flex; 10 | } 11 | 12 | .app-container { 13 | position: absolute; 14 | display: flex; 15 | flex-direction: column; 16 | } 17 | -------------------------------------------------------------------------------- /src/app/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './App.css'; 3 | 4 | import HowItWorks from '../howitworks/HowItWorks'; 5 | import ContactUs from '../contactus/ContactUs'; 6 | import Home from '../home/Home'; 7 | import Team from '../team/Team'; 8 | import Visualizer from '../visualizer/sortingvisualizer/Visualizer'; 9 | import NavigationMenu from '../component/navigationMenu/NavigationMenu'; 10 | 11 | /** 12 | * Main controller of the App. Contains a navigation menu and its corresponding sections. 13 | * 14 | * @component 15 | * @category Main App 16 | */ 17 | function App() { 18 | return ( 19 |
20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 | ); 30 | } 31 | 32 | export default App; 33 | -------------------------------------------------------------------------------- /src/component/IsVisibleYDirection/IsVisibleYDirection.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import IsVisible from 'react-is-visible'; 3 | 4 | /** 5 | * A wrapper component which helps to animate the component upwards. 6 | * 7 | * @component 8 | * @param {any} props Attribute to be passed into this component. 9 | */ 10 | const IsVisibleYDirection = (props) => { 11 | const transitionStyling = (isVisible) => ({ 12 | transform: isVisible ? `translateY(0px)` : props.yValue, 13 | transition: `all 1.0s ease-in-out`, 14 | }); 15 | 16 | return ( 17 | 18 | {(isVisible) => ( 19 |
20 | {props.children} 21 |
22 | )} 23 |
24 | ); 25 | }; 26 | 27 | export default IsVisibleYDirection; 28 | -------------------------------------------------------------------------------- /src/component/header/SectionHeader.js: -------------------------------------------------------------------------------- 1 | import React, { useRef } from 'react'; 2 | import './styles.css'; 3 | import 'intersection-observer'; 4 | import IsVisible from 'react-is-visible'; 5 | 6 | /** 7 | * General component header that animates to the center upon entering user's view port. 8 | * 9 | * @component 10 | * @param {string} sectionHeader Name of the section header. 11 | * @param {string} translateX Extra translation in x direction for the line underneath the header. 12 | * @returns {JSX.Element} Header for each category. 13 | */ 14 | const SectionHeader = ({ sectionHeader, translateX }) => { 15 | /** 16 | * Animates the header to the center. 17 | * 18 | * @param isVisible boolean value denoting whether the component is visible in user's view port. 19 | * @returns {{transform: string, transition: string}} Inline-styling for animation. 20 | */ 21 | const HeaderStyling = (isVisible) => ({ 22 | transform: isVisible ? `translateX(0px)` : `translateX(750px)`, 23 | transition: `all 1.5s ease-in-out`, 24 | }); 25 | const HeaderLineStyling = (isVisible) => ({ 26 | transform: isVisible ? translateX : `translateX(-750px)`, 27 | transition: `all 1.5s ease-in-out`, 28 | }); 29 | 30 | const nodeRef = useRef(); 31 | 32 | return ( 33 | 34 | {(isVisible) => ( 35 |
36 | {sectionHeader} 37 |
38 |
39 | )} 40 | 41 | ); 42 | }; 43 | 44 | export default SectionHeader; 45 | -------------------------------------------------------------------------------- /src/component/header/styles.css: -------------------------------------------------------------------------------- 1 | .section-header-line { 2 | background-color: #a5aefc; 3 | height: 2px; 4 | width: 70%; 5 | } 6 | 7 | .section-header > span { 8 | align-items: center; 9 | color: #5467ff; 10 | display: flex; 11 | font-family: 'Open Sans', serif; 12 | font-size: 34px; 13 | font-weight: 600; 14 | justify-content: center; 15 | } 16 | -------------------------------------------------------------------------------- /src/component/logo/logo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | 4 | /** 5 | * Sort-Algo logo used in Navigation Menu. 6 | * 7 | * @component 8 | * @category Navigation Menu 9 | */ 10 | const Logo = () => { 11 | return ( 12 | 13 |
14 |
15 |
16 | 17 | ); 18 | }; 19 | 20 | export default Logo; 21 | -------------------------------------------------------------------------------- /src/component/logo/styles.css: -------------------------------------------------------------------------------- 1 | .logo { 2 | align-items: flex-end; 3 | display: flex; 4 | height: 40px; 5 | justify-content: space-between; 6 | margin-right: 6px; 7 | transition: 0.6s; 8 | width: 36px; 9 | } 10 | 11 | .logo-block-one { 12 | background: #fff; 13 | height: 20px; 14 | transition: 0.6s; 15 | width: 10px; 16 | } 17 | 18 | .logo-block-one.sticky { 19 | background: #9aa6f8; 20 | } 21 | 22 | .logo-block-two { 23 | background: #fff; 24 | height: 30px; 25 | transition: 0.6s; 26 | width: 10px; 27 | } 28 | 29 | .logo-block-two.sticky { 30 | background: #7485fa; 31 | } 32 | 33 | .logo-block-three { 34 | background: #fff; 35 | height: 40px; 36 | transition: 0.6s; 37 | width: 10px; 38 | } 39 | 40 | .logo-block-three.sticky { 41 | background: #5f6fff; 42 | } 43 | -------------------------------------------------------------------------------- /src/component/navigationMenu/NavigationMenu.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | 4 | import Logo from '../logo/logo'; 5 | 6 | /** 7 | * Navigation Menu of the app. 8 | * 9 | * @component 10 | * @category App header 11 | */ 12 | const NavigationMenu = () => { 13 | return ( 14 | 39 | ); 40 | }; 41 | 42 | export default NavigationMenu; 43 | -------------------------------------------------------------------------------- /src/component/navigationMenu/styles.css: -------------------------------------------------------------------------------- 1 | .nav-bar { 2 | align-items: center; 3 | background: transparent; 4 | display: flex; 5 | height: 75px; 6 | overflow: hidden; 7 | padding-top: 20px; 8 | position: fixed; 9 | top: 0; 10 | transition: 0.6s; 11 | width: 100%; 12 | z-index: 50; 13 | } 14 | 15 | .nav-bar.sticky { 16 | background: #fff; 17 | box-shadow: -1px -2px 17px 1px rgba(232, 238, 255, 1); 18 | height: 60px; 19 | padding: 0; 20 | } 21 | 22 | .nav-bar ul { 23 | display: flex; 24 | flex-wrap: wrap; 25 | justify-content: center; 26 | margin-bottom: 0; 27 | width: 60%; 28 | } 29 | 30 | .nav-bar a { 31 | color: white; 32 | font-size: 18px; 33 | font-weight: 500; 34 | position: relative; 35 | text-align: justify; 36 | text-decoration: none; 37 | } 38 | 39 | .nav-logo a { 40 | font-size: 24px; 41 | font-weight: 700; 42 | } 43 | 44 | .nav-bar.sticky a { 45 | color: #454545; 46 | } 47 | 48 | .nav-menu li { 49 | display: inline-block; 50 | margin: 0 1rem; 51 | padding-inline: 0.5em; 52 | } 53 | 54 | .nav-menu a.active { 55 | border-bottom: 1.5px solid #fff; 56 | color: #fff; 57 | } 58 | 59 | .nav-menu a:hover { 60 | color: #b6b8ff; 61 | border-color: #e7e7fc; 62 | } 63 | 64 | .nav-logo { 65 | align-items: center; 66 | color: #5467ff; 67 | display: flex; 68 | justify-content: center; 69 | width: 40%; 70 | } 71 | 72 | .nav-logo a:hover { 73 | color: #fff; 74 | } 75 | 76 | /* Behaviour of the navigation menu after scrolling. */ 77 | 78 | .nav-bar.sticky .nav-logo a { 79 | color: #5467ff; 80 | } 81 | 82 | .nav-bar.sticky .nav-menu a:hover { 83 | color: #5467ff; 84 | } 85 | 86 | .nav-bar.sticky .nav-menu a.active { 87 | border-bottom: 1.5px solid #a5aefc; 88 | color: #5467ff; 89 | } 90 | 91 | @media screen and (max-width: 500px) { 92 | .nav-menu { 93 | display: none; 94 | height: 0; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/contactus/ContactUs.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Form from './body/Form'; 3 | import Footer from './footer/Footer'; 4 | import './styles.css'; 5 | import ContactUsHeader from './contactusheader/ContactUsHeader'; 6 | 7 | /** 8 | * Contact Us Section of the app. 9 | * 10 | * @component 11 | * @category App Body 12 | */ 13 | const ContactUs = () => { 14 | return ( 15 |
16 | 17 |
18 |
19 |
20 | ); 21 | }; 22 | 23 | export default ContactUs; 24 | -------------------------------------------------------------------------------- /src/contactus/body/Notification.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Snackbar, makeStyles } from '@material-ui/core'; 3 | import { Alert } from '@material-ui/lab'; 4 | import IconButton from '@material-ui/core/IconButton'; 5 | import CloseIcon from '@material-ui/icons/Close'; 6 | 7 | /** 8 | * A pop-up notification on the bottom left-hand corner to indicate that message is being sent. 9 | * 10 | * @component 11 | * @category Contact Us 12 | * @param isShowMessage boolean value of whether to show the message notification. 13 | * @param setIsShowMessage A setter which changes the state of isShowMessage. 14 | * @returns {JSX.Element} A notification which appears at the bottom left-hand corner. 15 | */ 16 | const Notification = ({ isShowMessage, setIsShowMessage }) => { 17 | const styles = makeStyles((theme) => ({ 18 | root: { 19 | backgroundColor: '#313131', 20 | color: 'white', 21 | }, 22 | })); 23 | 24 | const useStyles = styles(); 25 | 26 | /** 27 | * Handle the close event of the notification. Blocks all other method of closing except when 28 | * clicking the cross button. 29 | */ 30 | const handleClose = (event, reason) => { 31 | // to prevent users from clicking elsewhere to close the notification 32 | if (reason === 'clickaway') return; 33 | setIsShowMessage(false); 34 | }; 35 | 36 | return ( 37 | 43 | setIsShowMessage(false)} 53 | > 54 | 55 | 56 | } 57 | > 58 | Message sent. 59 | 60 | 61 | ); 62 | }; 63 | 64 | export default Notification; 65 | -------------------------------------------------------------------------------- /src/contactus/contactusheader/ContactUsHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Header from '../../component/header/SectionHeader'; 3 | import './styles.css'; 4 | 5 | /** 6 | * Header for contact us. 7 | * 8 | * @component 9 | * @category Contact Us 10 | */ 11 | const ContactUsHeader = () => { 12 | const ContactUsText = () => ( 13 | 14 | Do contact us if there is any error or improvement or wish to collaborate on this project 15 | 16 | ); 17 | 18 | return ( 19 |
20 |
21 | 22 |
23 | ); 24 | }; 25 | 26 | export default ContactUsHeader; 27 | -------------------------------------------------------------------------------- /src/contactus/contactusheader/styles.css: -------------------------------------------------------------------------------- 1 | .contact-us-header-box > span { 2 | color: #8789b5; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 15px; 5 | transform: translateY(30px); 6 | } 7 | 8 | .contact-us-header-box { 9 | align-items: center; 10 | display: flex; 11 | flex-direction: column; 12 | height: 20vh; 13 | } 14 | -------------------------------------------------------------------------------- /src/contactus/footer/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | 4 | import { MdCopyright } from 'react-icons/md'; 5 | 6 | /** 7 | * Footer at the end of page. 8 | * 9 | * @component 10 | * @category Contact Us 11 | */ 12 | const Footer = () => { 13 | return ( 14 |
15 |
16 |
17 |
About Us
18 | Home 19 | How It Works 20 | Visualizer 21 | Team 22 | Contact Us 23 |
24 | Copyright 2020 SortAlgo. 25 |
26 |
27 |
28 | ); 29 | }; 30 | 31 | export default Footer; 32 | -------------------------------------------------------------------------------- /src/contactus/footer/styles.css: -------------------------------------------------------------------------------- 1 | .footer-container { 2 | background: #5467ff; 3 | bottom: 0; 4 | display: flex; 5 | height: 400px; 6 | position: absolute; 7 | width: 100%; 8 | } 9 | 10 | .triangle { 11 | border-left: 1300px solid transparent; 12 | border-top: 100px solid #fff; 13 | position: absolute; 14 | right: 0; 15 | top: 0; 16 | } 17 | 18 | .links-container { 19 | display: flex; 20 | flex-direction: column; 21 | padding-left: 100px; 22 | padding-top: 40px; 23 | } 24 | 25 | .footer-title { 26 | color: #fff; 27 | font-size: 21px; 28 | font-weight: 500; 29 | line-height: 50px; 30 | } 31 | 32 | .copy-right { 33 | align-items: center; 34 | bottom: 70px; 35 | color: #fff; 36 | font-family: serif; 37 | font-size: 22px; 38 | position: absolute; 39 | } 40 | 41 | .footer-container a { 42 | color: #fff; 43 | font-size: 18px; 44 | line-height: 30px; 45 | scroll-behavior: unset; 46 | } 47 | 48 | .footer-container a:hover { 49 | color: #e5e5e5; 50 | } 51 | -------------------------------------------------------------------------------- /src/contactus/styles.css: -------------------------------------------------------------------------------- 1 | .contact-us { 2 | background: white; 3 | display: flex; 4 | flex-direction: column; 5 | height: 150vh; 6 | } 7 | -------------------------------------------------------------------------------- /src/home/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | 4 | import Particles from 'react-tsparticles'; 5 | import HomeDescription from './homedescription/HomeDescription'; 6 | 7 | /** 8 | * Home Section of the app. 9 | * 10 | * @component 11 | * @category App Body 12 | */ 13 | const Home = () => { 14 | return ( 15 |
16 | 17 | 84 |
85 | ); 86 | }; 87 | 88 | export default Home; 89 | -------------------------------------------------------------------------------- /src/home/homedescription/HomeDescription.js: -------------------------------------------------------------------------------- 1 | import React, { useRef } from 'react'; 2 | import './styles.css'; 3 | import 'intersection-observer'; 4 | import IsVisible from 'react-is-visible'; 5 | 6 | /** 7 | * Home description in Home Section. 8 | * 9 | * @component 10 | * @category Home 11 | */ 12 | const HomeDescription = () => { 13 | const titleStyling = (isVisible) => ({ 14 | transform: isVisible ? `translateX(0px)` : `translateX(750px)`, 15 | transition: `all 1.5s ease-in-out`, 16 | }); 17 | const descriptionStyling = (isVisible) => ({ 18 | transform: isVisible ? `translate(0px)` : `translateX(-750px)`, 19 | transition: `all 1.5s ease-in-out`, 20 | }); 21 | 22 | const nodeRef = useRef(); 23 | 24 | return ( 25 | 26 | {(isVisible) => ( 27 |
28 |
29 | Sorting algorithms made easy 30 |
31 |
32 | Visualize the step by step process of popular sorting algorithms! 33 |
34 |
35 | )} 36 |
37 | ); 38 | }; 39 | 40 | export default HomeDescription; 41 | -------------------------------------------------------------------------------- /src/home/homedescription/styles.css: -------------------------------------------------------------------------------- 1 | .content { 2 | align-items: center; 3 | display: flex; 4 | flex-direction: column; 5 | height: 100vh; 6 | justify-content: center; 7 | position: absolute; 8 | width: 100%; 9 | } 10 | 11 | .title { 12 | color: white; 13 | display: flex; 14 | font-family: serif; 15 | font-size: 30px; 16 | font-weight: 600; 17 | justify-content: center; 18 | } 19 | 20 | .description { 21 | color: white; 22 | font-size: 25px; 23 | justify-content: center; 24 | margin-top: 50px; 25 | } 26 | -------------------------------------------------------------------------------- /src/home/styles.css: -------------------------------------------------------------------------------- 1 | .home { 2 | display: flex; 3 | min-height: 105vh; 4 | overflow: hidden; 5 | padding-bottom: 5vh; 6 | } 7 | 8 | .wrapper { 9 | height: 100%; 10 | width: 100%; 11 | } 12 | -------------------------------------------------------------------------------- /src/howitworks/HowItWorks.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import './styles.css'; 4 | 5 | import HowItWorksHeader from '../component/header/SectionHeader'; 6 | import HowItWorksImage from '../team/image/how-it-works-image.jpg'; 7 | import Step from './step/Step'; 8 | import { StepsData } from './StepsData'; 9 | 10 | /** 11 | * How It Works Section of the app. 12 | * 13 | * @component 14 | * @category App Body 15 | */ 16 | const HowItWorks = () => { 17 | return ( 18 |
19 | 20 |
21 | 22 |
23 | {/*Steps 1 and 3*/} 24 | {StepsData.map((data, index) => 25 | index % 2 === 0 ? ( 26 | 27 | ) : null 28 | )} 29 |
30 |
31 | {/*Steps 2 and 4*/} 32 | {StepsData.map((data, index) => 33 | index % 2 === 1 ? ( 34 | 35 | ) : null 36 | )} 37 |
38 |
39 |
40 | ); 41 | }; 42 | 43 | export default HowItWorks; 44 | -------------------------------------------------------------------------------- /src/howitworks/StepsData.js: -------------------------------------------------------------------------------- 1 | import { AiFillSetting, AiOutlineSelect } from 'react-icons/ai'; 2 | import { GoPlay } from 'react-icons/go'; 3 | import { MdReplay } from 'react-icons/md'; 4 | import React from 'react'; 5 | 6 | /** 7 | * Array containing the details of each particular step. 8 | */ 9 | export const StepsData = [ 10 | { 11 | icon: , 12 | title: '1. Select the Algorithm', 13 | description: 'Visualize the algorithm of your choice.', 14 | }, 15 | { 16 | icon: , 17 | title: '2. Select Settings', 18 | description: 'Adjust the speed of the visualizer and array size.', 19 | }, 20 | { 21 | icon: , 22 | title: '3. Start Sorting', 23 | description: 'Press the play button to start the step by step sorting process.', 24 | }, 25 | { 26 | icon: , 27 | title: '4. Fast-forward, Backtrack, and Replay', 28 | description: 29 | 'Replay the entire sorting process or walk through ' + 30 | 'the algorithm one step at a time with these functions.', 31 | }, 32 | ]; 33 | -------------------------------------------------------------------------------- /src/howitworks/step/Step.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | import IsVisibleYDirection from '../../component/IsVisibleYDirection/IsVisibleYDirection'; 4 | 5 | /** 6 | * General instruction step in How It Works Section. 7 | * 8 | * @component 9 | * @param {icon} icon Icon of the step. 10 | * @param {string} title Title of the step. 11 | * @param {string} description Description of the step. 12 | * @returns {JSX.Element} A complete step component. 13 | */ 14 | const Step = ({ icon, title, description }) => { 15 | return ( 16 | 17 |
{icon}
18 |

{title}

19 |

{description}

20 |
21 | ); 22 | }; 23 | 24 | export default Step; 25 | -------------------------------------------------------------------------------- /src/howitworks/step/styles.css: -------------------------------------------------------------------------------- 1 | .step-container { 2 | background: #fff; 3 | display: flex; 4 | flex-direction: column; 5 | padding: 0 0 20px; 6 | width: 200px; 7 | } 8 | 9 | .step-picture { 10 | align-items: center; 11 | display: flex; 12 | height: 70px; 13 | justify-content: center; 14 | width: 70px; 15 | } 16 | 17 | .step-title { 18 | color: #595da5; 19 | font-family: 'Open Sans', sans-serif; 20 | font-size: 18px; 21 | font-weight: 600; 22 | margin-bottom: 0.5em; 23 | margin-top: 0.5em; 24 | } 25 | 26 | .step-description { 27 | color: #8789b5; 28 | font-family: 'Open Sans', sans-serif; 29 | line-height: 18px; 30 | } 31 | -------------------------------------------------------------------------------- /src/howitworks/styles.css: -------------------------------------------------------------------------------- 1 | .how-it-works { 2 | align-items: center; 3 | display: flex; 4 | flex-direction: column; 5 | min-height: 95vh; 6 | } 7 | 8 | .how-it-works-container { 9 | display: flex; 10 | justify-content: space-evenly; 11 | padding: 40px 0 0; 12 | width: 90%; 13 | } 14 | 15 | .how-it-works-picture { 16 | height: 90%; 17 | width: 45%; 18 | } 19 | 20 | .steps { 21 | flex-direction: column; 22 | justify-content: space-around; 23 | margin-top: 75px; 24 | width: 200px; 25 | } 26 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | body { 7 | font-family: 'Open Sans', sans-serif; 8 | -webkit-font-smoothing: antialiased; 9 | margin: 0; 10 | -moz-osx-font-smoothing: grayscale; 11 | overflow-x: hidden; 12 | } 13 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './app/App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | /** 8 | * Listener to show current navigation window/menu. 9 | */ 10 | window.addEventListener('scroll', (event) => { 11 | let navigationLinks = document.querySelectorAll('nav ul li a'); 12 | let fromTop = window.scrollY + 60 + window.innerHeight * 0.05; 13 | let navigationMenu = document.querySelector('nav'); 14 | let menuHeaders = document.querySelectorAll('nav div a div'); 15 | 16 | // Header transits to the next state when scrollY > 0 (upon scrolling from the top) 17 | navigationMenu.classList.toggle('sticky', window.scrollY > 0); 18 | menuHeaders.forEach((link) => { 19 | link.classList.toggle('sticky', window.scrollY > 0); 20 | }); 21 | 22 | navigationLinks.forEach((link) => { 23 | let section = document.querySelector(link.hash); 24 | 25 | if (section.offsetTop <= fromTop && section.offsetTop + section.offsetHeight > fromTop) { 26 | link.classList.add('active'); 27 | } else { 28 | link.classList.remove('active'); 29 | } 30 | }); 31 | }); 32 | 33 | ReactDOM.render( 34 | 35 | 36 | , 37 | document.getElementById('root') 38 | ); 39 | 40 | // If you want to start measuring performance in your app, pass a function 41 | // to log results (for example: reportWebVitals(console.log)) 42 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 43 | reportWebVitals(); 44 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = (onPerfEntry) => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/team/Team.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | import { TeamData, TeamDescription } from './TeamData'; 4 | import TeamImage from './image/team-image.jpg'; 5 | import TeamHeader from '../component/header/SectionHeader'; 6 | import Profile from './profile/Profile'; 7 | 8 | /** 9 | * Team Section of the app. 10 | * 11 | * @component 12 | * @category App Body 13 | */ 14 | const Team = () => { 15 | return ( 16 |
17 | 18 |
19 | 20 |
21 |

Meet our team

22 |

{TeamDescription}

23 | {TeamData.map((data, index) => ( 24 | 32 | ))} 33 |
34 |
35 |
36 | ); 37 | }; 38 | 39 | export default Team; 40 | -------------------------------------------------------------------------------- /src/team/TeamData.js: -------------------------------------------------------------------------------- 1 | import Ashley from './image/ashley.png'; 2 | import Keane from './image/keanecjy_smaller.png'; 3 | import Sean from './image/sean.jpg'; 4 | 5 | const TeamMemberDescription = 'Sophomore at National University of Singapore'; 6 | 7 | export const TeamData = [ 8 | { 9 | img: Sean, 10 | name: 'Lum Jian Yang Sean', 11 | description: TeamMemberDescription, 12 | linkedInUrl: 'https://www.linkedin.com/in/jyjy98/', 13 | gitHubUrl: 'https://github.com/seanjyjy', 14 | }, 15 | { 16 | img: Keane, 17 | name: 'Keane Chan Jun Yu', 18 | description: TeamMemberDescription, 19 | linkedInUrl: 'https://www.linkedin.com/in/keanecjy/', 20 | gitHubUrl: 'https://github.com/keanecjy', 21 | }, 22 | { 23 | img: Ashley, 24 | name: 'Lau Jun Hao Ashley', 25 | description: TeamMemberDescription, 26 | linkedInUrl: 'https://www.linkedin.com/in/ashley-lau-625237163/', 27 | gitHubUrl: 'https://github.com/Ashley-Lau', 28 | }, 29 | ]; 30 | export const TeamDescription = 31 | 'We are a group of highly motivated students from National ' + 32 | 'University of Singapore that are invested in the field of software engineering and algorithms.' + 33 | ' Feel free to contact us to collaborate on interesting software engineering projects.'; 34 | -------------------------------------------------------------------------------- /src/team/image/ashley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/src/team/image/ashley.png -------------------------------------------------------------------------------- /src/team/image/how-it-works-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/src/team/image/how-it-works-image.jpg -------------------------------------------------------------------------------- /src/team/image/keanecjy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/src/team/image/keanecjy.png -------------------------------------------------------------------------------- /src/team/image/keanecjy_smaller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/src/team/image/keanecjy_smaller.png -------------------------------------------------------------------------------- /src/team/image/sean.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/src/team/image/sean.jpg -------------------------------------------------------------------------------- /src/team/image/team-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/December-software-project/sort-algo/d37d1510ee223db3a107f18470230bf777360a18/src/team/image/team-image.jpg -------------------------------------------------------------------------------- /src/team/profile/Profile.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | import IsVisibleYDirection from '../../component/IsVisibleYDirection/IsVisibleYDirection'; 4 | import { FaGithub, FaLinkedin } from 'react-icons/fa'; 5 | 6 | const Profile = ({ img, name, description, linkedInLink, gitHubLink }) => { 7 | return ( 8 | 9 | 10 |
11 |

{name}

12 |

{description}

13 | 14 | 15 | 16 | 23 | 24 | 25 |
26 |
27 | ); 28 | }; 29 | 30 | export default Profile; 31 | -------------------------------------------------------------------------------- /src/team/profile/styles.css: -------------------------------------------------------------------------------- 1 | .profile-container { 2 | background: #fff; 3 | display: flex; 4 | flex-direction: row; 5 | padding: 0 0 20px; 6 | width: 350px; 7 | } 8 | 9 | .profile-description-container { 10 | flex-direction: column; 11 | line-height: 0; 12 | padding-left: 20px; 13 | padding-top: 9px; 14 | } 15 | 16 | .picture { 17 | border-color: #d7dbff; 18 | border-radius: 10px; 19 | border-style: solid; 20 | border-width: 0.1px; 21 | height: 70px; 22 | image-rendering: -moz-crisp-edges; /* Firefox */ 23 | image-rendering: -o-crisp-edges; /* Opera */ 24 | image-rendering: -webkit-optimize-contrast; /* This helps to make the image clearer even though it is being underlined */ 25 | -ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */ 26 | width: 70px; 27 | } 28 | 29 | .profile-title { 30 | color: #595da5; 31 | font-family: 'Open Sans', sans-serif; 32 | font-size: 18px; 33 | font-weight: 600; 34 | } 35 | 36 | .profile-description { 37 | color: #8789b5; 38 | font-family: 'Open Sans', sans-serif; 39 | line-height: 18px; 40 | } 41 | 42 | .github-logo { 43 | margin-left: 10px; 44 | } 45 | -------------------------------------------------------------------------------- /src/team/styles.css: -------------------------------------------------------------------------------- 1 | .team { 2 | align-items: center; 3 | display: flex; 4 | flex-direction: column; 5 | min-height: 100vh; 6 | } 7 | 8 | .team-container { 9 | display: flex; 10 | flex-direction: row; 11 | justify-content: space-around; 12 | margin-top: 3%; 13 | width: 90%; 14 | } 15 | 16 | .team-picture { 17 | height: 85%; 18 | margin-top: 2%; 19 | width: 45%; 20 | } 21 | 22 | .team-profile { 23 | flex-direction: column; 24 | justify-content: space-between; 25 | width: 35%; 26 | } 27 | 28 | .team-title { 29 | color: #595da5; 30 | font-family: 'Open Sans', sans-serif; 31 | font-size: 20px; 32 | font-weight: 600; 33 | } 34 | 35 | .team-description { 36 | color: #8789b5; 37 | font-family: 'Open Sans', sans-serif; 38 | font-size: 16px; 39 | line-height: 18px; 40 | padding-bottom: 15px; 41 | } 42 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/allSorts.js: -------------------------------------------------------------------------------- 1 | import insertionSort from './insertionSort'; 2 | import quickSort from './quickSort'; 3 | import bubbleSort from './bubbleSort'; 4 | import radixSort from './radixSort'; 5 | import bucketSort from './bucketSort'; 6 | import countingSort from './countingSort'; 7 | import mergeSort from './mergeSort'; 8 | import selectionSort from './selectionSort'; 9 | import shellSort from './shellSort'; 10 | import heapSort from './heapSort'; 11 | 12 | /** 13 | * An Object component that is used to access the sorting method. 14 | * 15 | * @namespace SortingAlgorithms 16 | * @type {Object} 17 | */ 18 | const SortingAlgorithms = { 19 | 'Insertion Sort': insertionSort, 20 | 'Bubble Sort': bubbleSort, 21 | 'Quick Sort': quickSort, 22 | 'Radix Sort': radixSort, 23 | 'Bucket Sort': bucketSort, 24 | 'Counting Sort': countingSort, 25 | 'Selection Sort': selectionSort, 26 | 'Merge Sort': mergeSort, 27 | 'Shell Sort': shellSort, 28 | 'Heap Sort': heapSort, 29 | }; 30 | 31 | export default SortingAlgorithms; 32 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/bubbleSort.js: -------------------------------------------------------------------------------- 1 | import { swap } from './swap'; 2 | 3 | /** 4 | * Sorts the array using Bubble Sort and stores each sorting step into the animation array. 5 | * 6 | * @memberOf SortingAlgorithms 7 | * @param {Object[]} arr The array to be sorted. 8 | * @returns {any[]} Animation array which contains the animation instruction for each step. 9 | */ 10 | const bubbleSort = (arr) => { 11 | let receivedArr = arr; 12 | let animationArr = []; 13 | for (let i = receivedArr.length - 1; i >= 0; i--) { 14 | let flag = true; 15 | for (let j = 0; j < i; j++) { 16 | animationArr.push([j + 1, j, false]); 17 | if (receivedArr[j].height > receivedArr[j + 1].height) { 18 | swap(j, j + 1, receivedArr); 19 | animationArr.push([j + 1, j, true]); 20 | flag = false; 21 | } 22 | } 23 | if (flag) { 24 | break; 25 | } 26 | } 27 | return animationArr; 28 | }; 29 | 30 | export default bubbleSort; 31 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/bucketSort.js: -------------------------------------------------------------------------------- 1 | import insertionSort from './insertionSort'; 2 | 3 | /** 4 | * Sorts the array using Bucket Sort and stores each sorting step into the animation array. 5 | * 6 | * @memberOf SortingAlgorithms 7 | * @param {Object[]} arr The array to be sorted. 8 | * @returns {any[]} Animation array which contains the animation instruction for each step. 9 | */ 10 | const bucketSort = (arr) => { 11 | const totalSlots = 10; 12 | let buckets = [...Array(totalSlots)].map(() => []); 13 | let animationArr = []; 14 | let id = 0; 15 | for (const item of arr) { 16 | const location = Math.floor(totalSlots * item.height); 17 | animationArr.push({ 18 | id: id, 19 | height: item.height, 20 | isShown: true, 21 | location: location, 22 | isDistributing: true, 23 | }); 24 | id++; 25 | buckets[location].push(item); 26 | } 27 | 28 | // Sort all arrays in buckets 29 | for (let i = 0; i < totalSlots; i++) { 30 | // Signify start of sort 31 | animationArr.push({ 32 | isSort: true, 33 | location: i, 34 | }); 35 | 36 | // Execute insertion sort animations 37 | let insertionSortAnimation = insertionSort(buckets[i]).map((arr) => [...arr, i]); 38 | animationArr = animationArr.concat(insertionSortAnimation); 39 | 40 | // Signify end of sort 41 | animationArr.push({ 42 | isSort: false, 43 | location: i, 44 | }); 45 | } 46 | 47 | // Restore element back into array 48 | id = 0; 49 | let location = 0; 50 | for (const array of buckets) { 51 | for (const item of array) { 52 | animationArr.push({ 53 | id: id, 54 | height: item.height, 55 | isShown: true, 56 | location: location, 57 | isDistributing: false, 58 | isSwap: false, 59 | }); 60 | id++; 61 | } 62 | location++; 63 | } 64 | return animationArr; 65 | }; 66 | 67 | export default bucketSort; 68 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/countingSort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sorts the array using Counting Sort and stores each sorting step into the animation array. 3 | * 4 | * @memberOf SortingAlgorithms 5 | * @param {Object[]} arr The array to be sorted. 6 | * @returns {any[]} Animation array which contains the animation instruction for each step. 7 | */ 8 | const countingSort = (arr) => { 9 | let receivedArr = arr; 10 | let countArr = [...Array(10)].map(() => 0); 11 | for (let i = 0; i < receivedArr.length; i++) { 12 | countArr[receivedArr[i].height]++; 13 | } 14 | let id = 0; 15 | for (let i = 0; i < countArr.length; i++) { 16 | while (countArr[i] !== 0) { 17 | receivedArr.push({ 18 | id: id, 19 | height: i, 20 | isShown: true, 21 | }); 22 | id++; 23 | countArr[i]--; 24 | } 25 | } 26 | return receivedArr; 27 | }; 28 | 29 | export default countingSort; 30 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/heapSort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sorts the array using Heap Sort and stores each sorting step into the animation array. 3 | * 4 | * @memberOf SortingAlgorithms 5 | * @see {@link https://www.w3resource.com/javascript-exercises/searching-and-sorting-algorithm/searching-and-sorting-algorithm-exercise-3.php} 6 | * @param {Object[]} arr The array to be sorted. 7 | * @returns {any[]} Animation array which contains the animation instruction for each step. 8 | */ 9 | import { swap } from './swap'; 10 | 11 | // Keeps track of how many items are not sorted 12 | let array_length; 13 | 14 | // Keeps track of the animation 15 | let animationArr = []; 16 | 17 | // Bubbling the element up to its correct position (heapify) 18 | const heap_root = (arr, i) => { 19 | let left = 2 * i + 1; 20 | let right = 2 * i + 2; 21 | let max = i; 22 | 23 | if (left < array_length && arr[left].height > arr[max].height) { 24 | max = left; 25 | } 26 | 27 | if (right < array_length && arr[right].height > arr[max].height) { 28 | max = right; 29 | } 30 | 31 | animationArr.push([i, max, false, false]); 32 | 33 | if (max !== i) { 34 | animationArr.push([i, max, true, false]); 35 | 36 | swap(i, max, arr); 37 | heap_root(arr, max); 38 | } 39 | }; 40 | 41 | const heapSort = (arr) => { 42 | let receivedArr = arr; 43 | array_length = receivedArr.length; 44 | animationArr = []; 45 | 46 | // Creating the maximum heap 47 | for (let i = Math.floor(array_length / 2); i >= 0; i -= 1) { 48 | heap_root(receivedArr, i); 49 | } 50 | 51 | // Sorting the array by extracting the the element and placing at the end of the array 52 | for (let i = arr.length - 1; i > 0; i--) { 53 | animationArr.push([i, 0, true, true]); 54 | swap(0, i, receivedArr); 55 | array_length--; 56 | 57 | heap_root(receivedArr, 0); 58 | } 59 | 60 | return animationArr; 61 | }; 62 | 63 | export default heapSort; 64 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/insertionSort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sorts the array using Insertion Sort and stores each sorting step into the animation array. 3 | * 4 | * @memberOf SortingAlgorithms 5 | * @param {Object[]} arr The array to be sorted. 6 | * @returns {any[]} Animation array which contains the animation instruction for each step. 7 | */ 8 | const insertionSort = (arr) => { 9 | let receivedArr = arr; 10 | let animationArr = []; 11 | let length = receivedArr.length; 12 | for (let i = 1; i < length; i++) { 13 | let key = receivedArr[i]; 14 | let j = i - 1; 15 | animationArr.push([i, i - 1, false]); 16 | while (j >= 0 && receivedArr[j].height > key.height) { 17 | receivedArr[j + 1] = receivedArr[j]; 18 | animationArr.push([j + 1, j, true]); 19 | j--; 20 | if (j >= 0 && receivedArr[j].height > key.height) { 21 | animationArr.push([j + 1, j, false]); 22 | } 23 | } 24 | receivedArr[j + 1] = key; 25 | } 26 | return animationArr; 27 | }; 28 | 29 | export default insertionSort; 30 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/mergeSort.js: -------------------------------------------------------------------------------- 1 | const merge = (receivedArr, start, mid, end, animationArr) => { 2 | const n1 = mid - start + 1; 3 | const n2 = end - mid; 4 | let leftArray = []; 5 | let rightArray = []; 6 | let allIndexInSwap = []; 7 | for (let i = 0; i < n1; i++) { 8 | leftArray.push(receivedArr[start + i]); 9 | allIndexInSwap.push(start + i); 10 | } 11 | for (let j = 0; j < n2; j++) { 12 | rightArray.push(receivedArr[mid + 1 + j]); 13 | allIndexInSwap.push(mid + 1 + j); 14 | } 15 | animationArr.push([-1, -1, true, -1, false, allIndexInSwap]); 16 | let i = 0, 17 | j = 0, 18 | k = start; 19 | while (i < n1 && j < n2) { 20 | if (leftArray[i].height <= rightArray[j].height) { 21 | animationArr.push([start + i, -1, false, k, false]); 22 | receivedArr[k++] = leftArray[i++]; 23 | } else { 24 | animationArr.push([-1, mid + 1 + j, false, k, false]); 25 | receivedArr[k++] = rightArray[j++]; 26 | } 27 | } 28 | 29 | while (i < n1) { 30 | if (i + 1 === n1) { 31 | animationArr.push([start + i, -1, false, k, true]); 32 | } else { 33 | animationArr.push([start + i, -1, false, k, false]); 34 | } 35 | receivedArr[k++] = leftArray[i++]; 36 | } 37 | 38 | while (j < n2) { 39 | if (j + 1 === n2) { 40 | animationArr.push([-1, mid + 1 + j, false, k, true]); 41 | } else { 42 | animationArr.push([-1, mid + 1 + j, false, k, false]); 43 | } 44 | receivedArr[k++] = rightArray[j++]; 45 | } 46 | }; 47 | 48 | const mergeSortHelper = (receivedArr, animationArr, start, end) => { 49 | if (start < end) { 50 | const mid = Math.floor((start + end) / 2); 51 | mergeSortHelper(receivedArr, animationArr, start, mid); 52 | mergeSortHelper(receivedArr, animationArr, mid + 1, end); 53 | merge(receivedArr, start, mid, end, animationArr); 54 | } 55 | }; 56 | 57 | /** 58 | * Sorts the array using Merge Sort and stores each sorting step into the animation array. 59 | * 60 | * @memberOf SortingAlgorithms 61 | * @see {@link https://www.geeksforgeeks.org/merge-sort/} 62 | * @param {Object[]} arr The array to be sorted. 63 | * @returns {any[]} Animation array which contains the animation instruction for each step. 64 | */ 65 | const mergeSort = (arr) => { 66 | let receivedArr = arr; 67 | let animationArr = []; 68 | mergeSortHelper(receivedArr, animationArr, 0, arr.length - 1); 69 | return animationArr; 70 | }; 71 | 72 | export default mergeSort; 73 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/quickSort.js: -------------------------------------------------------------------------------- 1 | import { swap } from './swap'; 2 | 3 | const partition = (arr, low, high, animationArr) => { 4 | let pivot = arr[high].height; 5 | let i = low - 1; 6 | for (let j = low; j < high; j++) { 7 | if (arr[j].height < pivot) { 8 | // first boolean is to represent a swap 9 | animationArr.push([j, j, false, high, 'incI', i]); 10 | i++; 11 | if (i !== j) { 12 | animationArr.push([i, j, true, high, 'iToJ', i]); 13 | swap(i, j, arr); 14 | } 15 | } else { 16 | animationArr.push([j, j, false, high, 'jToPivot', i]); 17 | } 18 | } 19 | animationArr.push([i + 1, high, true, high, 'swapPivot', i]); 20 | swap(i + 1, high, arr); 21 | return i + 1; 22 | }; 23 | 24 | const quickSortHelper = (arr, low, high, animationArr) => { 25 | if (low < high) { 26 | let pi = partition(arr, low, high, animationArr); 27 | quickSortHelper(arr, low, pi - 1, animationArr); 28 | quickSortHelper(arr, pi + 1, high, animationArr); 29 | } 30 | }; 31 | 32 | /** 33 | * Sorts the array using Quick Sort and stores each sorting step into the animation array. 34 | * 35 | * @memberOf SortingAlgorithms 36 | * @see {@link https://www.geeksforgeeks.org/quick-sort/} 37 | * @param {Object[]} arr The array to be sorted. 38 | * @returns {any[]} Animation array which contains the animation instruction for each step. 39 | */ 40 | const quickSort = (arr) => { 41 | let animationArr = []; 42 | quickSortHelper(arr, 0, arr.length - 1, animationArr); 43 | return animationArr; 44 | }; 45 | 46 | export default quickSort; 47 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/radixSort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sorts the array using Radix Sort and stores each sorting step into the animation array. 3 | * 4 | * @memberOf SortingAlgorithms 5 | * @see {@link https://www.tutorialspoint.com/radix-sort-in-javascript} 6 | * @param {Object[]} arr The array to be sorted. 7 | * @returns {any[]} Animation array which contains the animation instruction for each step. 8 | */ 9 | const radixSort = (arr) => { 10 | let inputArr = arr; 11 | let animationArr = []; 12 | const maxNum = Math.max(...inputArr.map((x) => x.height)) * 10; 13 | let divisor = 10; 14 | while (divisor < maxNum) { 15 | let id = 0; 16 | let buckets = [...Array(10)].map(() => []); 17 | 18 | for (const item of inputArr) { 19 | const height = item.height; 20 | const location = Math.floor((height % divisor) / (divisor / 10)); 21 | buckets[location].push(item); 22 | animationArr.push({ 23 | id: id, 24 | height: item.height, 25 | isShown: true, 26 | location: location, 27 | isDistributing: true, 28 | }); 29 | id++; 30 | } 31 | inputArr = [].concat.apply([], buckets); 32 | id = 0; 33 | let location = 0; 34 | for (const array of buckets) { 35 | for (const item of array) { 36 | animationArr.push({ 37 | id: id, 38 | height: item.height, 39 | isShown: true, 40 | location: location, 41 | isDistributing: false, 42 | }); 43 | id++; 44 | } 45 | location++; 46 | } 47 | divisor *= 10; 48 | } 49 | return animationArr; 50 | }; 51 | 52 | export default radixSort; 53 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/selectionSort.js: -------------------------------------------------------------------------------- 1 | import { swap } from './swap'; 2 | 3 | /** 4 | * Sorts the array using Selection Sort and stores each sorting step into the animation array. 5 | * 6 | * @memberOf SortingAlgorithms 7 | * @param {Object[]} arr The array to be sorted. 8 | * @returns {any[]} Animation array which contains the animation instruction for each step. 9 | */ 10 | const selectionSort = (arr) => { 11 | let receivedArr = arr; 12 | let animationArr = []; 13 | for (let i = 0; i < receivedArr.length - 1; i++) { 14 | let smallestIdx = i; 15 | for (let j = i + 1; j < receivedArr.length; j++) { 16 | animationArr.push([smallestIdx, j, false]); 17 | if (receivedArr[j].height < receivedArr[smallestIdx].height) { 18 | smallestIdx = j; 19 | } 20 | } 21 | if (i !== smallestIdx) { 22 | swap(smallestIdx, i, receivedArr); 23 | animationArr.push([smallestIdx, i, true]); 24 | } 25 | } 26 | return animationArr; 27 | }; 28 | 29 | export default selectionSort; 30 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/shellSort.js: -------------------------------------------------------------------------------- 1 | import { swap } from './swap'; 2 | 3 | /** 4 | * Sorts the array using Shell Sort and stores each sorting step into the animation array. 5 | * 6 | * @memberOf SortingAlgorithms 7 | * @see {@link https://levelup.gitconnected.com/shell-sort-in-javascript-c8a487041cdb} 8 | * @param {Object[]} arr The array to be sorted. 9 | * @returns {any[]} Animation array which contains the animation instruction for each step. 10 | */ 11 | const shellSort = (arr) => { 12 | let n = arr.length; 13 | let receivedArr = arr; 14 | let animationArr = []; 15 | 16 | for (let gap = Math.floor(n / 2); gap > 0; gap = Math.floor(gap / 2)) { 17 | for (let i = gap; i < n; i += 1) { 18 | let temp = receivedArr[i].height; 19 | 20 | let j; 21 | for (j = i; j >= gap; j -= gap) { 22 | animationArr.push([j - gap, j, false]); 23 | if (receivedArr[j - gap].height > temp) { 24 | animationArr.push([j - gap, j, true]); 25 | swap(j - gap, j, receivedArr); 26 | continue; 27 | } 28 | break; 29 | } 30 | } 31 | } 32 | 33 | return animationArr; 34 | }; 35 | 36 | export default shellSort; 37 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/sortingalgorithms/swap.js: -------------------------------------------------------------------------------- 1 | export const swap = (i, j, arr) => { 2 | let temp = arr[i]; 3 | arr[i] = arr[j]; 4 | arr[j] = temp; 5 | }; 6 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/stepbysteptemplate/allSortsStepByStep.js: -------------------------------------------------------------------------------- 1 | import { genericSwapStepByStep } from './genericSwapStepByStep'; 2 | import { selectionSortStepByStep } from './selectionSortStepByStep'; 3 | import { mergeSortStepByStep } from './mergeSortStepByStep'; 4 | import { quickSortStepByStep } from './quickSortStepByStep'; 5 | import { countingSortStepByStep } from './countingSortStepByStep'; 6 | import { radixSortStepByStep } from './radixSortStepByStep'; 7 | import { bucketSortStepByStep } from './bucketSortStepByStep'; 8 | import { heapSortStepByStep } from './heapSortStepByStep'; 9 | 10 | /** 11 | * An Object component that is used to access the sorting method step by step template. 12 | * 13 | * @namespace StepByStepTemplate 14 | * @type {Object} 15 | */ 16 | const SortingAlgorithmsStepByStep = { 17 | 'Insertion Sort': genericSwapStepByStep, 18 | 'Bubble Sort': genericSwapStepByStep, 19 | 'Selection Sort': selectionSortStepByStep, 20 | 'Merge Sort': mergeSortStepByStep, 21 | 'Quick Sort': quickSortStepByStep, 22 | 'Counting Sort': countingSortStepByStep, 23 | 'Shell Sort': genericSwapStepByStep, 24 | 'Radix Sort': radixSortStepByStep, 25 | 'Bucket Sort': bucketSortStepByStep, 26 | 'Heap Sort': heapSortStepByStep, 27 | }; 28 | 29 | export default SortingAlgorithmsStepByStep; 30 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/stepbysteptemplate/bucketSortStepByStep.js: -------------------------------------------------------------------------------- 1 | import { radixSortStepByStep } from './radixSortStepByStep'; 2 | import { genericSwapStepByStep } from './genericSwapStepByStep'; 3 | 4 | /** 5 | * Generates the step by step template for Bucket Sort. 6 | * 7 | * @method 8 | * @memberOf StepByStepTemplate 9 | * @param {any[]} animationArr An array that contains all the animation steps. 10 | * @param {number} idx Index of the current animation step. 11 | * @param {Object[]} stackArr An array representing the buckets. 12 | * @returns {string} The information regarding the current step of the animation. 13 | */ 14 | export const bucketSortStepByStep = (animationArr, idx, stackArr) => { 15 | const currentAnimation = animationArr[idx - 1]; 16 | 17 | // Insertion sort taking place in bucket 18 | if (currentAnimation.length === 4) { 19 | const location = currentAnimation[3]; 20 | return genericSwapStepByStep(animationArr, idx, stackArr[location].array); 21 | } 22 | 23 | if (currentAnimation.isSort === undefined) { 24 | return radixSortStepByStep(animationArr, idx); 25 | } 26 | 27 | // Signal start of sorting bucket 28 | if (currentAnimation.isSort) { 29 | return `Currently sorting bucket ${currentAnimation.location}`; 30 | } else { 31 | return `Bucket ${currentAnimation.location} has been sorted!`; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/stepbysteptemplate/countingSortStepByStep.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates the step by step template for Counting Sort. 3 | * 4 | * @method 5 | * @memberOf StepByStepTemplate 6 | * @param {any[]} animationArr An array that contains all the animation steps. 7 | * @param {number} idx Index of the current animation step. 8 | * @param {Object[]} referenceArray An array containing the data which is being sorted. 9 | * @returns {string} The information regarding the current step of the animation. 10 | */ 11 | export const countingSortStepByStep = (animationArr, idx, referenceArray) => { 12 | const height = animationArr[idx - 1].height; 13 | 14 | if (idx > referenceArray.length) { 15 | return `Restore element ${height} and decrease count of ${height} by 1`; 16 | } else { 17 | return `Increase count of ${animationArr[idx - 1].height} by 1`; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/stepbysteptemplate/genericSwapStepByStep.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates the step by step template for Insertion, Bubble, Selection, Shell Sort. 3 | * 4 | * @method 5 | * @memberOf StepByStepTemplate 6 | * @param {any[]} animationArr An array that contains all the animation steps. 7 | * @param {number} idx Index of the current animation step. 8 | * @param {Object[]} referenceArray An array containing the data which is being sorted. 9 | * @returns {string} The information regarding the current step of the animation. 10 | */ 11 | export const genericSwapStepByStep = (animationArr, idx, referenceArray) => { 12 | if (idx === animationArr.length) { 13 | return 'Array is sorted'; 14 | } 15 | let animationArrSwapIdx = animationArr[idx - 1]; 16 | let firstIdx = animationArrSwapIdx[0]; 17 | let secondIdx = animationArrSwapIdx[1]; 18 | let isSwap = animationArrSwapIdx[2]; 19 | let firstIdxVal = referenceArray[firstIdx].height; 20 | let secondIdxVal = referenceArray[secondIdx].height; 21 | let isBigger = secondIdxVal > firstIdxVal; 22 | 23 | if (isSwap) { 24 | return `Since swap is true, swap ${secondIdxVal} and ${firstIdxVal}`; 25 | } 26 | 27 | // Comparisons message 28 | let message = `Check if ${secondIdxVal} > ${firstIdxVal} :\n`; 29 | 30 | if (isBigger) { 31 | message += `Since ${secondIdxVal} > ${firstIdxVal}, swap is set to true`; 32 | } else { 33 | message += `Since ${secondIdxVal} <= ${firstIdxVal}, swap is set to false and iteration continues`; 34 | } 35 | return message; 36 | }; 37 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/stepbysteptemplate/heapSortStepByStep.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates the step by step template for Heap Sort. 3 | * 4 | * @method 5 | * @memberOf StepByStepTemplate 6 | * @param {any[]} animationArr An array that contains all the animation steps. 7 | * @param {number} idx Index of the current animation step. 8 | * @param {Object[]} referenceArray An array containing the data which is being sorted. 9 | * @returns {string} The information regarding the current step of the animation. 10 | */ 11 | export const heapSortStepByStep = (animationArr, idx, referenceArray) => { 12 | if (idx === animationArr.length) { 13 | return 'Array is sorted'; 14 | } 15 | let animationArrSwapIdx = animationArr[idx - 1]; 16 | let firstIdx = animationArrSwapIdx[0]; 17 | let secondIdx = animationArrSwapIdx[1]; 18 | let isSwap = animationArrSwapIdx[2]; 19 | let heapStep = animationArrSwapIdx[3]; 20 | let firstIdxVal = referenceArray[firstIdx].height; 21 | let secondIdxVal = referenceArray[secondIdx].height; 22 | let isBigger = secondIdxVal > firstIdxVal; 23 | 24 | if (heapStep) { 25 | return `Swap the largest item in the heap, ${firstIdxVal}, with the 26 | leaf node with the largest index, ${secondIdxVal}`; 27 | } 28 | 29 | if (isSwap) { 30 | return `Since swap is true, swap ${secondIdxVal} and ${firstIdxVal}`; 31 | } 32 | 33 | // Comparisons message 34 | let message = `Check if ${firstIdxVal} is larger than its child nodes:\n`; 35 | 36 | if (isBigger) { 37 | message += `Since ${secondIdxVal} > ${firstIdxVal}, swap is set to true`; 38 | } else { 39 | message += `Since ${firstIdxVal} is larger than its child nodes, swap is set 40 | to false and iteration continues`; 41 | } 42 | return message; 43 | }; 44 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/stepbysteptemplate/mergeSortStepByStep.js: -------------------------------------------------------------------------------- 1 | import { findIndexToUseInMergeSort } from '../../sortingvisualizer/util/MergeSortUtil'; 2 | import { arrayCopy } from '../../sortingvisualizer/util/ArrayUtil'; 3 | 4 | /** 5 | * Generates the step by step template for Merge Sort. 6 | * 7 | * @method 8 | * @memberOf StepByStepTemplate 9 | * @param {any[]} animationArr An array that contains all the animation steps. 10 | * @param {number} idx Index of the current animation step. 11 | * @param {Object[]} referenceArray An array containing the data which is being sorted. 12 | * @returns {string} The information regarding the current step of the animation. 13 | */ 14 | export const mergeSortStepByStep = (animationArr, idx, referenceArray) => { 15 | if (idx === animationArr.length) { 16 | return 'Array is sorted'; 17 | } else if (referenceArray[0].isShift !== undefined) { 18 | let animationArrSwapIdx = animationArr[idx - 1]; 19 | let isShift = animationArrSwapIdx[2]; 20 | let newTempArr = arrayCopy(referenceArray); 21 | let iIdx = animationArrSwapIdx[0]; 22 | let jIdx = animationArrSwapIdx[1]; 23 | let idxToUse = findIndexToUseInMergeSort(newTempArr, iIdx, jIdx); 24 | if (isShift) { 25 | // explaining the moving downwards and comparison 26 | // this is slightly inefficient but since we are dealing with small data, it should be fine 27 | let message = 'Currently in merge process: '; 28 | for (let values of referenceArray) { 29 | if (values.isShift) { 30 | message += values.height + ', '; 31 | } 32 | } 33 | return message.slice(0, -1); 34 | } 35 | // shifting back up to correct position 36 | let min = referenceArray[idxToUse].height; 37 | let message = `Since the minimum is ${min}, we move ${min} up\nCurrently left in the merge process: `; 38 | for (let values of referenceArray) { 39 | if (values.isShift) { 40 | message += values.height + ', '; 41 | } 42 | } 43 | message = message.slice(0, -1); 44 | return message; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/stepbysteptemplate/quickSortStepByStep.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates the step by step template for Quick Sort. 3 | * 4 | * @method 5 | * @memberOf StepByStepTemplate 6 | * @param {any[]} animationArr An array that contains all the animation steps. 7 | * @param {number} idx Index of the current animation step. 8 | * @param {Object[]} referenceArray An array containing the data which is being sorted. 9 | * @returns {string} The information regarding the current step of the animation. 10 | */ 11 | export const quickSortStepByStep = (animationArr, idx, referenceArray) => { 12 | if (idx === animationArr.length) { 13 | return 'Array is sorted'; 14 | } 15 | 16 | let animationArrSwapIdx = animationArr[idx - 1]; 17 | let firstIdx = animationArrSwapIdx[0]; 18 | let secondIdx = animationArrSwapIdx[1]; 19 | let isSwap = animationArrSwapIdx[2]; 20 | let firstIdxVal = referenceArray[firstIdx].height; 21 | let secondIdxVal = referenceArray[secondIdx].height; 22 | let pivotIdx = animationArrSwapIdx[3]; 23 | let pivotIdxVal = referenceArray[pivotIdx].height; 24 | let command = animationArrSwapIdx[4]; 25 | let indexOfSmallerElement = animationArrSwapIdx[5]; 26 | 27 | // when a swap occurs, it is either swapping two element while iterating, else, it is swapping 28 | // the pivot to its position 29 | let incJ = ` Now we increment the loop variable from ${secondIdx} to ${secondIdx + 1}.`; 30 | let incI = `we increment the index of the smaller element from ${indexOfSmallerElement} to ${ 31 | indexOfSmallerElement + 1 32 | }.`; 33 | if (isSwap) { 34 | if (command === 'iToJ') { 35 | return ( 36 | `Since swap is true, we swap index of the smaller element, ${indexOfSmallerElement} with` + 37 | ` value ${firstIdxVal}, with loop variable index ${secondIdx}, ` + 38 | `with value ${secondIdxVal}.` + 39 | incJ 40 | ); 41 | } 42 | return ( 43 | `Since we finish one iteration, we swap the pivot to next of index of smallest` + 44 | `element ${firstIdx}` 45 | ); 46 | } 47 | // Comparison to determine if to increment both loop variable or just one 48 | let comparisonStatement; 49 | let swapStatement; 50 | if (command === 'incI') { 51 | comparisonStatement = `Since ${secondIdxVal} < pivot value ${pivotIdxVal}, `; 52 | // if both index are the same, no need to set swap to true 53 | if (secondIdx !== indexOfSmallerElement + 1) { 54 | swapStatement = ` Since index of smaller element ${ 55 | indexOfSmallerElement + 1 56 | } not equal to index of loop variable ${secondIdx}, Swap is set to true.`; 57 | } else { 58 | swapStatement = ` Since index of smaller element ${ 59 | indexOfSmallerElement + 1 60 | } equal to index of loop variable ${secondIdx}, Swap is set to false.`; 61 | swapStatement += incJ; 62 | } 63 | return comparisonStatement + incI + swapStatement; 64 | } 65 | 66 | comparisonStatement = `Since ${secondIdxVal} >= pivot value ${pivotIdxVal}, `; 67 | swapStatement = `Swap is set to false`; 68 | return comparisonStatement + swapStatement + incJ; 69 | }; 70 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/stepbysteptemplate/radixSortStepByStep.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates the step by step template Radix Sort. 3 | * 4 | * @method 5 | * @memberOf StepByStepTemplate 6 | * @param {any[]} animationArr An array that contains all the animation steps. 7 | * @param {number} idx Index of the current animation step. 8 | * @returns {string} The information regarding the current step of the animation. 9 | */ 10 | export const radixSortStepByStep = (animationArr, idx) => { 11 | const currentAnimation = animationArr[idx - 1]; 12 | const height = currentAnimation.height; 13 | const location = currentAnimation.location; 14 | 15 | if (currentAnimation.isDistributing) { 16 | return `Put element ${height} at the end of bucket ${location}`; 17 | } else { 18 | return `Restore the first element (${height}) in bucket ${location} back to array`; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /src/visualizer/algorithm/stepbysteptemplate/selectionSortStepByStep.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates the step by step template for Selection Sort. 3 | * 4 | * @method 5 | * @memberOf StepByStepTemplate 6 | * @param {any[]} animationArr An array that contains all the animation steps. 7 | * @param {number} idx Index of the current animation step. 8 | * @param {Object[]} referenceArray An array containing the data which is being sorted. 9 | * @returns {string} The information regarding the current step of the animation. 10 | */ 11 | export const selectionSortStepByStep = (animationArr, idx, referenceArray) => { 12 | if (idx === animationArr.length) { 13 | return 'Array is sorted'; 14 | } 15 | let animationArrSwapIdx = animationArr[idx - 1]; 16 | let firstIdx = animationArrSwapIdx[0]; 17 | let secondIdx = animationArrSwapIdx[1]; 18 | let isSwap = animationArrSwapIdx[2]; 19 | let firstIdxVal = referenceArray[firstIdx].height; 20 | let secondIdxVal = referenceArray[secondIdx].height; 21 | let isSmaller = secondIdxVal < firstIdxVal; 22 | 23 | if (isSwap) { 24 | if (firstIdxVal === secondIdxVal) { 25 | return `Since the smallest value is still ${firstIdxVal}. There is no change in position`; 26 | } 27 | return `The smallest value so far is ${secondIdxVal}. We swap it to index ${secondIdx}`; 28 | } 29 | 30 | // Comparisons 31 | let message = `Check if ${secondIdxVal} is smaller than the smallest value so far: ${firstIdxVal}\n`; 32 | if (isSmaller) { 33 | message += `Since ${secondIdxVal} is smaller than ${firstIdxVal}, smallest value is set to ${secondIdxVal}`; 34 | } else { 35 | message += `Since ${secondIdxVal} is not smaller than ${firstIdxVal}, no change to smallest value`; 36 | } 37 | return message; 38 | }; 39 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/CodeInformation.js: -------------------------------------------------------------------------------- 1 | import CodeExplanation from './codeexplaination/CodeExplanation'; 2 | import CodeTemplate from './codetemplate/CodeTemplate'; 3 | import React from 'react'; 4 | import './styles.css'; 5 | 6 | /** 7 | * Code information component which provides information on the current sorting algorithm. 8 | * 9 | * @component 10 | * @category App Body 11 | * @param {string} visualizerAlgorithm Current sorting algorithm selected. 12 | * @returns {JSX.Element} Code information component which provides information on the current sorting algorithm. 13 | */ 14 | const CodeInformation = ({ visualizerAlgorithm }) => ( 15 |
16 | 17 | 18 |
19 | ); 20 | 21 | export default CodeInformation; 22 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/codeexplaination/CodeExplanation.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import './styles.css'; 3 | import explanations from '../explanations/Explanations'; 4 | import PerformanceSection from './PerformanceSection'; 5 | 6 | /** 7 | * CodeExplanation component which encapsulates the details for how the sorting algorithm works, 8 | * and the performance of the algorithm. 9 | * 10 | * @component 11 | * @category CodeExplanation 12 | * @param {string} algo Current algorithm selected. 13 | * @returns {JSX.Element} Code explanation component. 14 | */ 15 | const CodeExplanation = ({ algo }) => { 16 | // Sort details of the algorithm. 17 | const [sortDetails, setSortDetails] = useState(() => explanations[algo]); 18 | 19 | useEffect(() => { 20 | setSortDetails(explanations[algo]); 21 | }, [algo]); 22 | 23 | /** 24 | * First header component for the explanation section. 25 | * 26 | * @returns {JSX.Element} First header component for the explanation section. 27 | */ 28 | const HeaderOne = () =>
How {sortDetails.name} Sort works
; 29 | 30 | /** 31 | * Explanation component detailing how the code works. 32 | * 33 | * @returns {JSX.Element} Explanation component detailing how the code works. 34 | */ 35 | const Explanation = () =>

{sortDetails.description}

; 36 | 37 | /** 38 | * Second header component for the performance section. 39 | * 40 | * @returns {JSX.Element} Second header component for the performance section. 41 | */ 42 | const HeaderTwo = () =>
Performance
; 43 | 44 | /** 45 | * Link component which provides a link to an external website for more information about the 46 | * sorting algorithm used. 47 | * 48 | * @returns {JSX.Element} Link component. 49 | */ 50 | const Link = () => ( 51 | 52 | Click for more info 53 | 54 | ); 55 | 56 | return ( 57 |
58 | 59 | 60 | 61 | 62 | 63 |
64 | ); 65 | }; 66 | 67 | export default CodeExplanation; 68 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/codeexplaination/PerformanceSection.js: -------------------------------------------------------------------------------- 1 | import { FaCheckCircle, FaTimesCircle } from 'react-icons/fa'; 2 | import React from 'react'; 3 | import './styles.css'; 4 | 5 | /** 6 | * Performance section detailing the performance of the current sorting algorithm. 7 | * 8 | * @component 9 | * @category CodeExplanation 10 | * @returns {JSX.Element} Performance section component. 11 | */ 12 | const PerformanceSection = ({ sortDetails }) => { 13 | /** 14 | * Complexities terminologies used. 15 | * 16 | * @returns {JSX.Element} List of complexities component. 17 | */ 18 | const ListOfComplexities = () => ( 19 |
20 |

Worst time complexity

21 |

Average time complexity

22 |

Best time complexity

23 |

Worst space complexity

24 |
25 | ); 26 | 27 | /** 28 | * Complexities of the sorting algorithm. 29 | * 30 | * @returns {JSX.Element} Complexity component describing the complexities of the sorting 31 | * algorithm. 32 | */ 33 | const Complexity = () => ( 34 |
35 |

O({sortDetails.worstTime})

36 |

θ({sortDetails.averageTime})

37 |

Ω({sortDetails.bestTime})

38 |

O({sortDetails.worstSpace})

39 |
40 | ); 41 | 42 | /** 43 | * General type with icon template, used for detailing whether the sorting algorithm used is 44 | * stable and in-place. 45 | * 46 | * @param {string} type Input type. 47 | * @param {boolean} isTick detailing whether the type is true or false. 48 | * @returns {JSX.Element} Type with icon component. 49 | */ 50 | const TypeWithIcon = ({ type, isTick }) => { 51 | /** 52 | * Icon type which describes whether the boolean is true or false. Returns the Tick symbol 53 | * if boolean is true, otherwise it returns the Cross symbol. 54 | * 55 | * @returns {JSX.Element} IconType. 56 | */ 57 | const IconType = () => { 58 | return isTick ? ( 59 | 60 | ) : ( 61 | 62 | ); 63 | }; 64 | 65 | return ( 66 |
67 |

{type}

68 | 69 |
70 | ); 71 | }; 72 | 73 | return ( 74 |
75 |

76 | {`Assuming N is the size of array, ` + sortDetails.additionalDesc} 77 |

78 |
79 | 80 | 81 |
82 |
83 | 84 | 85 |
86 |
87 | ); 88 | }; 89 | 90 | export default PerformanceSection; 91 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/codeexplaination/styles.css: -------------------------------------------------------------------------------- 1 | .main { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | 6 | .main header { 7 | color: #32325d; 8 | font-family: 'Open Sans Semibold', sans-serif; 9 | font-size: 18px; 10 | margin-bottom: 10px; 11 | } 12 | 13 | .main p { 14 | color: #8789b5; 15 | font-size: 16px; 16 | margin-bottom: 1.5em; 17 | } 18 | 19 | .explanation-para { 20 | font-family: 'Open Sans', sans-serif; 21 | font-size: 16px; 22 | } 23 | 24 | .performance { 25 | font-family: 'Open Sans Semibold', sans-serif; 26 | } 27 | 28 | .performance p { 29 | font-size: 15px; 30 | margin-bottom: 0.5em; 31 | } 32 | 33 | .row-container-one { 34 | display: flex; 35 | flex-direction: row; 36 | justify-content: space-between; 37 | margin-bottom: 1.5em; 38 | } 39 | 40 | .text { 41 | align-items: center; 42 | display: grid; 43 | } 44 | 45 | .complexity { 46 | align-items: center; 47 | display: grid; 48 | } 49 | 50 | .complexity p { 51 | background-color: #5467ff; 52 | border: 5px solid #5467ff; 53 | border-radius: 20px; 54 | color: #f2f2f2; 55 | font-family: 'Open Sans Semibold', sans-serif; 56 | letter-spacing: 1.3px; 57 | text-align: center; 58 | } 59 | 60 | .row-container-two { 61 | display: grid; 62 | grid-template-columns: repeat(2, 1fr); 63 | justify-items: center; 64 | margin-top: 1%; 65 | } 66 | 67 | .row-container-two div { 68 | min-width: 100px; 69 | text-align: center; 70 | } 71 | 72 | .link, 73 | .link:focus { 74 | color: steelblue; 75 | font-size: 15px; 76 | margin-top: 6%; 77 | text-decoration: underline; 78 | width: fit-content; 79 | } 80 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/codetemplate/CodeTemplate.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import templates from '../templates/Templates'; 3 | import Selector from './Selector'; 4 | import './styles.css'; 5 | import AceEditor from 'react-ace'; 6 | import 'ace-builds/webpack-resolver'; 7 | import 'ace-builds/src-noconflict/mode-java'; 8 | import 'ace-builds/src-noconflict/mode-python'; 9 | import 'ace-builds/src-noconflict/mode-c_cpp'; 10 | import 'ace-builds/src-noconflict/mode-javascript'; 11 | import 'ace-builds/src-noconflict/theme-textmate'; 12 | 13 | /** 14 | * Code template which encapsulates the details for the programming language selectors and code 15 | * editor. 16 | * 17 | * @component 18 | * @category CodeTemplate 19 | * @param {string} algo Current algorithm selected. 20 | * @returns {JSX.Element} Code template component. 21 | */ 22 | const CodeTemplate = ({ algo }) => { 23 | // Code templates used of this algorithm 24 | const [template, setTemplate] = useState(() => templates[algo]); 25 | 26 | // Current programming language selected 27 | const [selected, setSelected] = useState('Java'); 28 | 29 | useEffect(() => { 30 | setTemplate(templates[algo]); 31 | }, [algo]); 32 | 33 | /** 34 | * Gets the current mode corresponding to the programming language selected. 35 | * 36 | * @returns {string} Current mode. 37 | */ 38 | const getMode = () => (selected === 'C/C++' ? 'c_cpp' : selected.toLowerCase()); 39 | 40 | return ( 41 |
42 | 43 | 53 |
54 | ); 55 | }; 56 | 57 | export default CodeTemplate; 58 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/codetemplate/Selector.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | 4 | /** 5 | * Selector component which allows the users to select the code corresponding to the programming 6 | * language. 7 | * 8 | * @component 9 | * @category CodeTemplate 10 | * @returns {JSX.Element} Selector component. 11 | */ 12 | const Selector = ({ selected, setSelected }) => { 13 | /** 14 | * Select button for users to choose the programming language. 15 | * 16 | * @param language Programming language. 17 | * @returns {JSX.Element} Select button. 18 | */ 19 | const Select = ({ language }) => ( 20 |

setSelected(language)} 26 | > 27 | {language} 28 |

29 | ); 30 | 31 | return ( 32 |
33 | 35 | 37 |
38 | ); 39 | }; 40 | 41 | export default Selector; 42 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/codetemplate/styles.css: -------------------------------------------------------------------------------- 1 | .code-template { 2 | align-items: center; 3 | height: 100%; 4 | margin-left: 4%; 5 | padding: 0 8% 0; 6 | width: 90%; 7 | } 8 | 9 | .editor { 10 | background-color: #f1f5fd; 11 | border: 1px solid #5e9bd1; 12 | border-top: 3px solid #f1f5fd; 13 | box-shadow: 0 5px 10px 1px rgba(0, 0, 0, 0.2); 14 | width: 100% !important; 15 | } 16 | 17 | .selector { 18 | align-items: center; 19 | display: grid; 20 | grid-template-columns: repeat(4, 1fr); 21 | } 22 | 23 | .select { 24 | border-top-left-radius: 20px; 25 | border-top-right-radius: 20px; 26 | color: white; 27 | font-family: 'Open Sans Semibold', sans-serif; 28 | font-size: 16px; 29 | height: 35px; 30 | line-height: 35px; 31 | margin-bottom: 0; 32 | text-align: center; 33 | } 34 | 35 | .select:hover { 36 | cursor: pointer; 37 | } 38 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/explanations/Explanations.js: -------------------------------------------------------------------------------- 1 | import BubbleSort from './bubbleSortEx'; 2 | import InsertionSort from './insertionSortEx'; 3 | import QuickSort from './quickSortEx'; 4 | import RadixSort from './radixSortEx'; 5 | import BucketSort from './bucketSortEx'; 6 | import CountingSort from './countingSortEx'; 7 | import SelectionSort from './selectionSortEx'; 8 | import MergeSort from './mergeSortEx'; 9 | import ShellSort from './shellSortEx'; 10 | import HeapSort from './heapSortEx'; 11 | 12 | /** 13 | * Contains all the explanations for the sorting algorithms. 14 | * 15 | * @namespace Explanations 16 | * @type {Object} 17 | */ 18 | const explanations = { 19 | 'Bubble Sort': BubbleSort, 20 | 'Insertion Sort': InsertionSort, 21 | 'Quick Sort': QuickSort, 22 | 'Radix Sort': RadixSort, 23 | 'Bucket Sort': BucketSort, 24 | 'Counting Sort': CountingSort, 25 | 'Selection Sort': SelectionSort, 26 | 'Merge Sort': MergeSort, 27 | 'Shell Sort': ShellSort, 28 | 'Heap Sort': HeapSort, 29 | }; 30 | 31 | export default explanations; 32 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/explanations/bubbleSortEx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bubble sort algorithm details. 3 | * 4 | * @memberOf Explanations 5 | * @see {@link https://www.geeksforgeeks.org/bubble-sort/|Geeks for Geeks} 6 | * @const { 7 | * {bestTime: string, 8 | * worstSpace: string, 9 | * additionalDesc: string, 10 | * averageTime: JSX.Element, 11 | * stable: boolean, 12 | * name: string, 13 | * worstTime: JSX.Element, 14 | * link: string, 15 | * description: string, 16 | * inPlace: boolean} 17 | * } 18 | */ 19 | const BubbleSort = { 20 | name: 'Bubble', 21 | description: 22 | 'Bubble Sort is the simplest sorting algorithm that works by ' + 23 | 'repeatedly swapping adjacent elements if they are in the wrong order. ' + 24 | 'This procedure is repeated until no swaps are required, indicating ' + 25 | 'that the list has been sorted.', 26 | additionalDesc: '', 27 | worstTime: ( 28 | 29 | N2 30 | 31 | ), 32 | averageTime: ( 33 | 34 | N2 35 | 36 | ), 37 | bestTime: 'N', 38 | worstSpace: '1', 39 | stable: true, 40 | inPlace: true, 41 | link: 'https://www.geeksforgeeks.org/bubble-sort/', 42 | }; 43 | 44 | export default BubbleSort; 45 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/explanations/bucketSortEx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bucket sort algorithm details. 3 | * Explanation adapted from CLRS Introduction to Algorithms textbook. 4 | * 5 | * @memberOf Explanations 6 | * @const { 7 | * {bestTime: string, 8 | * worstSpace: string, 9 | * additionalDesc: string, 10 | * averageTime: string, 11 | * stable: boolean, 12 | * name: string, 13 | * worstTime: JSX.Element, 14 | * link: string, 15 | * description: string, 16 | * inPlace: boolean} 17 | * } 18 | */ 19 | const BucketSort = { 20 | name: 'Bucket', 21 | description: 22 | 'Bucket sort assumes that the input is drawn from a uniform distribution of [0, 1). ' + 23 | 'The interval [0, 1) is divided into n equal-sized sub-intervals (buckets). Then, the input ' + 24 | 'array is distributed into these buckets. To produce ' + 25 | 'the output, we simply sort the numbers in each bucket and then go through the buckets in ' + 26 | 'order to list the elements.', 27 | additionalDesc: '', 28 | worstTime: ( 29 | 30 | N2 31 | 32 | ), 33 | averageTime: 'N', 34 | bestTime: 'N', 35 | worstSpace: 'N', 36 | stable: true, 37 | inPlace: false, 38 | link: 'https://www.geeksforgeeks.org/bucket-sort-2/', 39 | }; 40 | 41 | export default BucketSort; 42 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/explanations/countingSortEx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Counting sort algorithm details. 3 | * 4 | * @memberOf Explanations 5 | * @see {@link https://www.geeksforgeeks.org/counting-sort/|Geeks for Geeks} 6 | * @const { 7 | * {bestTime: string, 8 | * worstSpace: string, 9 | * additionalDesc: string, 10 | * averageTime: string, 11 | * stable: boolean, 12 | * name: string, 13 | * worstTime: string, 14 | * link: string, 15 | * description: string, 16 | * inPlace: boolean} 17 | * } 18 | */ 19 | const CountingSort = { 20 | name: 'Counting', 21 | description: 22 | 'Counting sort is a sorting technique based on keys between a specific range. It works by ' + 23 | 'counting the number of objects having distinct key values (kind of hashing), and using ' + 24 | 'arithmetic on those counts to determine the positions of each key value in the output ' + 25 | 'sequence.', 26 | additionalDesc: 'k is the range of the key values,', 27 | worstTime: 'N + k', 28 | averageTime: 'N + k', 29 | bestTime: 'N + k', 30 | worstSpace: 'N + k', 31 | stable: true, 32 | inPlace: false, 33 | link: 'https://www.geeksforgeeks.org/counting-sort/', 34 | }; 35 | 36 | export default CountingSort; 37 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/explanations/heapSortEx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Heap sort algorithm details. 3 | * 4 | * @memberOf Explanations 5 | * @see {@link https://www.geeksforgeeks.org/heap-sort/|Geeks for Geeks} 6 | * @const { 7 | * {bestTime: string, 8 | * worstSpace: string, 9 | * additionalDesc: string, 10 | * averageTime: string, 11 | * stable: boolean, 12 | * name: string, 13 | * worstTime: string, 14 | * link: string, 15 | * description: string, 16 | * inPlace: boolean} 17 | * } 18 | */ 19 | const HeapSort = { 20 | name: 'Heap', 21 | description: 22 | 'Heap Sort is a comparison based sorting technique based on Binary Heap data structure.' + 23 | ' It is similar to selection sort where we first find the maximum element and place the' + 24 | ' maximum element at the end. We repeat the same process for the remaining elements.', 25 | additionalDesc: '', 26 | worstTime: 'NlogN', 27 | averageTime: 'NlogN', 28 | bestTime: 'NlogN', 29 | worstSpace: '1', 30 | stable: false, 31 | inPlace: true, 32 | link: 'https://www.geeksforgeeks.org/heap-sort/', 33 | }; 34 | 35 | export default HeapSort; 36 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/explanations/insertionSortEx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Insertion sort algorithm details. 3 | * 4 | * @memberOf Explanations 5 | * @see {@link https://www.geeksforgeeks.org/insertion-sort/|Geeks for Geeks} 6 | * @const { 7 | * {bestTime: string, 8 | * worstSpace: string, 9 | * additionalDesc: string, 10 | * averageTime: JSX.Element, 11 | * stable: boolean, 12 | * name: string, 13 | * worstTime: JSX.Element, 14 | * link: string, 15 | * description: string, 16 | * inPlace: boolean} 17 | * } 18 | */ 19 | const InsertionSort = { 20 | name: 'Insertion', 21 | description: 22 | 'Insertion Sort is a simple sorting algorithm that builds the final ' + 23 | 'sorted list one item at a time. The list is virtually split ' + 24 | 'into a sorted and an unsorted part. Values from the unsorted part are ' + 25 | 'picked and placed at the correct position in the sorted part.', 26 | additionalDesc: '', 27 | worstTime: ( 28 | 29 | N2 30 | 31 | ), 32 | averageTime: ( 33 | 34 | N2 35 | 36 | ), 37 | bestTime: 'N', 38 | worstSpace: '1', 39 | stable: true, 40 | inPlace: true, 41 | link: 'https://www.geeksforgeeks.org/insertion-sort/', 42 | }; 43 | 44 | export default InsertionSort; 45 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/explanations/mergeSortEx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Merge sort algorithm details. 3 | * 4 | * @memberOf Explanations 5 | * @see {@link https://www.geeksforgeeks.org/merge-sort/|Geeks for Geeks} 6 | * @const { 7 | * {bestTime: string, 8 | * worstSpace: string, 9 | * additionalDesc: string, 10 | * averageTime: string, 11 | * stable: boolean, 12 | * name: string, 13 | * worstTime: string, 14 | * link: string, 15 | * description: string, 16 | * inPlace: boolean} 17 | * } 18 | */ 19 | const MergeSort = { 20 | name: 'Merge', 21 | description: 22 | 'Merge Sort is a Divide and Conquer algorithm. It divides the input array into two halves, ' + 23 | 'calls itself for the two halves, and then merges the two sorted halves. The merge() function ' + 24 | 'is used for merging two halves. The merge(arr, l, m, r) is a key process that assumes that ' + 25 | 'arr[l..m] and arr[m+1..r] are sorted and merges the two sorted subarrays into one', 26 | additionalDesc: '', 27 | worstTime: 'NlogN', 28 | averageTime: 'NlogN', 29 | bestTime: 'NlogN', 30 | worstSpace: 'N', 31 | stable: true, 32 | inPlace: false, 33 | link: 'https://www.geeksforgeeks.org/merge-sort/', 34 | }; 35 | 36 | export default MergeSort; 37 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/explanations/quickSortEx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Quick sort algorithm details. 3 | * 4 | * @memberOf Explanations 5 | * @see {@link https://www.geeksforgeeks.org/quick-sort/|Geeks for Geeks} 6 | * @const { 7 | * {bestTime: string, 8 | * worstSpace: string, 9 | * additionalDesc: string, 10 | * averageTime: string, 11 | * stable: boolean, 12 | * name: string, 13 | * worstTime: JSX.Element, 14 | * link: string, 15 | * description: string, 16 | * inPlace: boolean} 17 | * } 18 | */ 19 | const QuickSort = { 20 | name: 'Quick', 21 | description: 22 | 'Quick Sort is a Divide and Conquer algorithm. It picks an element as pivot and partitions ' + 23 | 'the given array around the picked pivot. There are many different versions of Quick Sort that ' + 24 | 'pick pivot in different ways.', 25 | additionalDesc: '', 26 | worstTime: ( 27 | 28 | N2 29 | 30 | ), 31 | averageTime: 'NlogN', 32 | bestTime: 'N', 33 | worstSpace: 'N', 34 | stable: false, 35 | inPlace: true, 36 | link: 'https://www.geeksforgeeks.org/quick-sort/', 37 | }; 38 | 39 | export default QuickSort; 40 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/explanations/radixSortEx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Radix sort algorithm details. 3 | * 4 | * @memberOf Explanations 5 | * @see {@link https://www.programiz.com/dsa/radix-sort|Programiz} 6 | * @const { 7 | * {bestTime: string, 8 | * worstSpace: string, 9 | * additionalDesc: string, 10 | * averageTime: string, 11 | * stable: boolean, 12 | * name: string, 13 | * worstTime: string, 14 | * link: string, 15 | * description: string, 16 | * inPlace: boolean} 17 | * } 18 | */ 19 | const RadixSort = { 20 | name: 'Radix', 21 | description: 22 | 'Radix sort works by sorting each digit from least significant digit to most significant ' + 23 | "digit. So in base 10 (the decimal system), radix sort would sort by the digits in the 1's " + 24 | 'place, then the 10’s place, and so on. To do this, radix sort uses counting sort as a ' + 25 | 'subroutine to sort the digits in each place value.', 26 | additionalDesc: 27 | 'd is the number of digits in the input numbers, b is the base for representing numbers,', 28 | worstTime: 'd(n + b)', 29 | averageTime: 'd(n + b)', 30 | bestTime: 'd(n + b)', 31 | worstSpace: 'n + b', 32 | stable: true, 33 | inPlace: false, 34 | link: 'https://www.programiz.com/dsa/radix-sort', 35 | }; 36 | 37 | export default RadixSort; 38 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/explanations/selectionSortEx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Selection sort algorithm details. 3 | * 4 | * @memberOf Explanations 5 | * @see {@link https://www.geeksforgeeks.org/selection-sort/|Geeks for Geeks} 6 | * @const { 7 | * {bestTime: JSX.Element, 8 | * worstSpace: string, 9 | * additionalDesc: string, 10 | * averageTime: JSX.Element, 11 | * stable: boolean, 12 | * name: string, 13 | * worstTime: JSX.Element, 14 | * link: string, 15 | * description: string, 16 | * inPlace: boolean} 17 | * } 18 | */ 19 | const SelectionSort = { 20 | name: 'Selection', 21 | description: 22 | 'Selection Sort algorithm sorts an array by repeatedly finding the minimum element ' + 23 | '(considering ascending order) from unsorted part and putting it at the beginning. The ' + 24 | 'algorithm maintains two subarrays, a subarray which is sorted and the remaining array which' + 25 | ' is unsorted', 26 | additionalDesc: '', 27 | worstTime: ( 28 | 29 | N2 30 | 31 | ), 32 | averageTime: ( 33 | 34 | N2 35 | 36 | ), 37 | bestTime: ( 38 | 39 | N2 40 | 41 | ), 42 | worstSpace: '1', 43 | stable: false, 44 | inPlace: true, 45 | link: 'https://www.geeksforgeeks.org/selection-sort/', 46 | }; 47 | 48 | export default SelectionSort; 49 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/explanations/shellSortEx.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Shell sort algorithm details. 3 | * 4 | * @memberOf Explanations 5 | * @see {@link https://www.geeksforgeeks.org/shellsort/|Geeks for Geeks} 6 | * @const { 7 | * {bestTime: string, 8 | * worstSpace: string, 9 | * additionalDesc: string, 10 | * averageTime: string, 11 | * stable: boolean, 12 | * name: string, 13 | * worstTime: JSX.Element, 14 | * link: string, 15 | * description: string, 16 | * inPlace: boolean} 17 | * } 18 | */ 19 | const ShellSort = { 20 | name: 'Shell', 21 | description: 22 | 'Shell Sort is mainly a variation of Insertion Sort. The idea of Shell Sort is to allow exchange ' + 23 | 'of items far apart from each other, then progressively reducing the gap between elements ' + 24 | 'to be compared. In the last iteration of Shell Sort where gap equals 1, regular Insertion Sort ' + 25 | 'is performed on the resultant array.', 26 | additionalDesc: '', 27 | worstTime: ( 28 | 29 | N2 30 | 31 | ), 32 | averageTime: 'NlogN', 33 | bestTime: 'NlogN', 34 | worstSpace: '1', 35 | stable: false, 36 | inPlace: true, 37 | link: 'https://www.geeksforgeeks.org/shellsort/', 38 | }; 39 | 40 | export default ShellSort; 41 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/styles.css: -------------------------------------------------------------------------------- 1 | .code { 2 | align-content: center; 3 | display: grid; 4 | gap: 20px; 5 | grid-template-columns: 1fr 2.5fr; 6 | justify-items: start; 7 | margin-left: 4%; 8 | margin-top: 4%; 9 | padding: 0 20px 40px; 10 | transform: translateX(3vw); 11 | } 12 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/templates/Templates.js: -------------------------------------------------------------------------------- 1 | import BubbleSort from './bubbleSortTemplate'; 2 | import InsertionSort from './insertionSortTemplate'; 3 | import QuickSort from './quickSortTemplate'; 4 | import RadixSort from './radixSortTemplate'; 5 | import BucketSort from './bucketSortTemplate'; 6 | import CountingSort from './countingSortTemplate'; 7 | import SelectionSort from './selectionSortTemplate'; 8 | import MergeSort from './mergeSortTemplate'; 9 | import ShellSort from './shellSortTemplate'; 10 | import HeapSort from './heapSortTemplate'; 11 | 12 | /** 13 | * Contains all the code templates for the sorting algorithms. 14 | * 15 | * @namespace Code templates 16 | * @type {Object} 17 | */ 18 | const templates = { 19 | 'Bubble Sort': BubbleSort, 20 | 'Insertion Sort': InsertionSort, 21 | 'Quick Sort': QuickSort, 22 | 'Radix Sort': RadixSort, 23 | 'Bucket Sort': BucketSort, 24 | 'Counting Sort': CountingSort, 25 | 'Selection Sort': SelectionSort, 26 | 'Merge Sort': MergeSort, 27 | 'Shell Sort': ShellSort, 28 | 'Heap Sort': HeapSort, 29 | }; 30 | 31 | export default templates; 32 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/templates/bubbleSortTemplate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bubble sort algorithm details. 3 | * 4 | * @memberOf Code templates 5 | * @const {{Java: string, 'C/C++': string, JavaScript: string, Python: string}} 6 | */ 7 | const BubbleSort = { 8 | Java: 9 | 'void swap(int[] arr, int i, int j) {\n' + 10 | ' int temp = arr[i];\n' + 11 | ' arr[i] = arr[j];\n' + 12 | ' arr[j] = temp;\n' + 13 | '}\n' + 14 | '\n' + 15 | 'void bubbleSort(int[] arr) {\n' + 16 | ' \n' + 17 | ' // Loop in the range of unsorted elements\n' + 18 | ' for (int i = arr.length - 1; i >= 0; i--) {\n' + 19 | ' boolean swapped = true;\n' + 20 | ' \n' + 21 | ' // Bubble largest element to the end\n' + 22 | ' for (int j = 0; j < i; j++) {\n' + 23 | ' if (arr[j] > arr[j + 1]) {\n' + 24 | ' swap(arr, j, j + 1);\n' + 25 | ' swapped = false;\n' + 26 | ' }\n' + 27 | ' }\n' + 28 | ' \n' + 29 | ' // Array is already sorted as there are no swaps in this iteration\n' + 30 | ' if (swapped) {\n' + 31 | ' break;\n' + 32 | ' }\n' + 33 | ' }\n' + 34 | '}\n', 35 | JavaScript: 36 | 'function bubbleSort(arr) {\n\n' + 37 | ' // Loop in the range of unsorted elements\n' + 38 | ' for (let i = arr.length - 1; i >= 0; i--) {\n' + 39 | ' let swapped = true;\n\n' + 40 | ' // Bubble largest element to the end\n' + 41 | ' for (let j = 0; j < i; j++) {\n' + 42 | ' if (arr[j] > arr[j + 1]) {\n' + 43 | ' [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];\n' + 44 | ' swapped = false;\n' + 45 | ' }\n' + 46 | ' }\n\n' + 47 | ' // Array is already sorted as there are no swaps in this iteration\n' + 48 | ' if (swapped) {\n' + 49 | ' break;\n' + 50 | ' }\n' + 51 | ' }\n' + 52 | '}\n', 53 | Python: 54 | 'def bubble_sort(arr):\n' + 55 | '\n' + 56 | ' # Loop in the range of unsorted elements\n' + 57 | ' for i in range(len(arr) - 1, 0, -1):\n' + 58 | ' swapped = True\n' + 59 | '\n' + 60 | ' # Bubble largest element to the end\n' + 61 | ' for j in range(i):\n' + 62 | ' if arr[j] > arr[j + 1]:\n' + 63 | ' arr[j], arr[j + 1] = arr[j + 1], arr[j]\n' + 64 | ' swapped = False\n' + 65 | '\n' + 66 | ' # Array is already sorted as there are no swaps in this iteration\n' + 67 | ' if swapped:\n' + 68 | ' break\n', 69 | 'C/C++': 70 | 'void swap(int *a, int *b)\n' + 71 | '{\n' + 72 | ' int temp = *a;\n' + 73 | ' *a = *b;\n' + 74 | ' *b = temp;\n' + 75 | '}\n' + 76 | '\n' + 77 | 'void bubbleSort(int arr[], int len)\n' + 78 | '{\n' + 79 | ' int i, j;\n' + 80 | ' bool swapped;\n' + 81 | '\n' + 82 | ' // Loop in the range of unsorted elements\n' + 83 | ' for (i = len - 1; i >= 0; --i)\n' + 84 | ' {\n' + 85 | ' swapped = true;\n' + 86 | '\n' + 87 | ' // Bubble largest element to the end\n' + 88 | ' for (j = 0; j < i; ++j)\n' + 89 | ' {\n' + 90 | ' if (arr[j] > arr[j + 1])\n' + 91 | ' {\n' + 92 | ' swap(&arr[j], &arr[j + 1]);\n' + 93 | ' swapped = false;\n' + 94 | ' }\n' + 95 | ' }\n' + 96 | '\n' + 97 | ' // Array is already sorted as there are no swaps in this iteration\n' + 98 | ' if (swapped)\n' + 99 | ' {\n' + 100 | ' break;\n' + 101 | ' }\n' + 102 | ' }\n' + 103 | '}\n', 104 | }; 105 | 106 | export default BubbleSort; 107 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/templates/insertionSortTemplate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Insertion sort algorithm details. 3 | * 4 | * @see {@link https://www.geeksforgeeks.org/insertion-sort/|Geeks for Geeks} 5 | * @memberOf Code templates 6 | * @const {{Java: string, 'C/C++': string, JavaScript: string, Python: string}} 7 | */ 8 | const InsertionSort = { 9 | Java: 10 | 'void insertionSort(int[] arr) {\n' + 11 | '\n' + 12 | ' // Elements from 0 to i - 1 are sorted\n' + 13 | ' for (int i = 1; i < arr.length; i++) {\n' + 14 | '\n' + 15 | ' int key = arr[i];\n' + 16 | ' int j = i - 1;\n' + 17 | '\n' + 18 | ' // Locate position of key to insert in the sorted region\n' + 19 | ' while (j >= 0 && arr[j] > key) {\n' + 20 | ' arr[j + 1] = arr[j];\n' + 21 | ' j -= 1;\n' + 22 | ' }\n' + 23 | ' arr[j + 1] = key;\n' + 24 | ' }\n' + 25 | '}\n', 26 | JavaScript: 27 | 'function insertionSort(arr) {\n' + 28 | '\n' + 29 | ' // Elements from 0 to i - 1 are sorted\n' + 30 | ' for (let i = 1; i < arr.length; i++) {\n' + 31 | ' \n' + 32 | ' const key = arr[i];\n' + 33 | ' let j = i - 1;\n' + 34 | '\n' + 35 | ' // Locate position of key to insert in the sorted region\n' + 36 | ' while (j >= 0 && arr[j] > key) {\n' + 37 | ' arr[j + 1] = arr[j];\n' + 38 | ' j -= 1;\n' + 39 | ' }\n' + 40 | ' arr[j + 1] = key;\n' + 41 | ' }\n' + 42 | '}\n', 43 | Python: 44 | 'def insertion_sort(arr):\n' + 45 | '\n' + 46 | ' # Elements from 0 to i - 1 are sorted\n' + 47 | ' for i in range(1, len(arr)):\n' + 48 | '\n' + 49 | ' key = arr[i]\n' + 50 | ' j = i - 1\n' + 51 | '\n' + 52 | ' # Locate position of key to insert in the sorted region\n' + 53 | ' while j >= 0 and arr[j] > key:\n' + 54 | ' arr[j + 1] = arr[j]\n' + 55 | ' j -= 1\n' + 56 | ' arr[j + 1] = key\n', 57 | 'C/C++': 58 | 'void insertionSort(int arr[], int len)\n' + 59 | '{\n' + 60 | ' // Elements from 0 to i - 1 are sorted\n' + 61 | ' for (int i = 1; i < len; i++)\n' + 62 | ' {\n' + 63 | '\n' + 64 | ' int key = arr[i];\n' + 65 | ' int j = i - 1;\n' + 66 | '\n' + 67 | ' // Locate position of key to insert in the sorted region\n' + 68 | ' while (j >= 0 && arr[j] > key)\n' + 69 | ' {\n' + 70 | ' arr[j + 1] = arr[j];\n' + 71 | ' j -= 1;\n' + 72 | ' }\n' + 73 | ' arr[j + 1] = key;\n' + 74 | ' }\n' + 75 | '}\n', 76 | }; 77 | 78 | export default InsertionSort; 79 | -------------------------------------------------------------------------------- /src/visualizer/codeinformation/templates/selectionSortTemplate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Selection sort algorithm details. 3 | * 4 | * @see {@link https://www.geeksforgeeks.org/selection-sort/|Geeks for Geeks} 5 | * @see {@link https://stackabuse.com/selection-sort-in-javascript/|StackAbuse} 6 | * @see {@link https://stackabuse.com/selection-sort-in-python/|StackAbuse} 7 | * @memberOf Code templates 8 | * @const {{Java: string, 'C/C++': string, JavaScript: string, Python: string}} 9 | */ 10 | const SelectionSort = { 11 | Java: 12 | 'void sort(int[] arr) {\n' + 13 | ' int n = arr.length;\n' + 14 | ' // One by one move boundary of unsorted subarray \n' + 15 | ' for (int i = 0; i < n - 1; i++) {\n' + 16 | ' // Find the minimum element in unsorted array \n' + 17 | ' int minIdx = i;\n' + 18 | ' for (int j = i + 1; j < n; j++) {\n' + 19 | ' if (arr[j] < arr[min_idx]) {\n' + 20 | ' minIdx = j;\n' + 21 | ' }\n' + 22 | ' }\n' + 23 | ' // Swap the found minimum element with the first element \n' + 24 | ' int temp = arr[minIdx];\n' + 25 | ' arr[minIdx] = arr[i];\n' + 26 | ' arr[i] = temp;\n' + 27 | ' }\n' + 28 | '} \n', 29 | JavaScript: 30 | 'function selectionSort(inputArr) {\n' + 31 | ' let n = inputArr.length;\n' + 32 | ' for (let i = 0; i < n - 1; i++) {\n' + 33 | ' // Finding the smallest number in the subarray\n' + 34 | ' let min = i;\n' + 35 | ' for (let j = i + 1; j < n; j++) {\n' + 36 | ' if (inputArr[j] < inputArr[min]) {\n' + 37 | ' min = j;\n' + 38 | ' }\n' + 39 | ' }\n' + 40 | ' if (min != i) {\n' + 41 | ' // Swapping the elements\n' + 42 | ' let tmp = inputArr[i];\n' + 43 | ' inputArr[i] = inputArr[min];\n' + 44 | ' inputArr[min] = tmp;\n' + 45 | ' }\n' + 46 | ' }\n' + 47 | ' return inputArr;\n' + 48 | '}\n', 49 | Python: 50 | 'def selection_sort(L):\n' + 51 | ' # i indicates how many items were sorted\n' + 52 | ' for i in range(len(L) - 1):\n' + 53 | ' # To find the minimum value of the unsorted segment\n' + 54 | ' # We first assume that the first element is the lowest\n' + 55 | ' min_index = i\n' + 56 | ' # We then use j to loop through the remaining elements\n' + 57 | ' for j in range(i + 1, len(L) - 1):\n' + 58 | ' # Update the min_index if the element at j is lower than it\n' + 59 | ' if L[j] < L[min_index]:\n' + 60 | ' min_index = j\n' + 61 | ' # After finding the lowest item of the unsorted regions,\n' + 62 | ' # swap with the first unsorted item\n' + 63 | ' L[i], L[min_index] = L[min_index], L[i]\n', 64 | 'C/C++': 65 | 'void selectionSort(int arr[], int n)\n' + 66 | '{\n' + 67 | ' int i, j, minIdx;\n' + 68 | ' // One by one move boundary of unsorted subarray \n' + 69 | ' for (i = 0; i < n - 1; i++)\n' + 70 | ' {\n' + 71 | ' // Find the minimum element in unsorted array \n' + 72 | ' minIdx = i;\n' + 73 | ' for (j = i + 1; j < n; j++) \n' + 74 | ' {\n' + 75 | ' if (arr[j] < arr[min_idx]) \n' + 76 | ' {\n' + 77 | ' minIdx = j;\n' + 78 | ' }\n' + 79 | ' }\n' + 80 | ' // Swap the found minimum element with the first element \n' + 81 | ' swap(&arr[minIdx], &arr[i]);\n' + 82 | ' }\n' + 83 | '} \n', 84 | }; 85 | 86 | export default SelectionSort; 87 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/animationprogressbar/AnimationProgressBar.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import 'antd/dist/antd.css'; 3 | import { Progress } from 'antd'; 4 | import { VisualizerStateContext } from '../../Visualizer'; 5 | 6 | /** 7 | * Progress bar for the animation completion. 8 | * 9 | * @component 10 | * @category Visualizer 11 | */ 12 | const AnimationProgressBar = () => { 13 | const { animationPercentage } = useContext(VisualizerStateContext); 14 | return ( 15 |
16 | 24 |
25 | ); 26 | }; 27 | 28 | export default AnimationProgressBar; 29 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/animationscreen/AnimationScreen.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from 'react'; 2 | import { useTransition } from 'react-spring'; 3 | import './styles.css'; 4 | import { VisualizerStateContext } from '../../Visualizer'; 5 | import { isBucketSort, isCountingSort, isMergeSort, isRadixSort } from '../../util/GeneralUtil'; 6 | import CountingSortScreen from './CountingSortScreen'; 7 | import RadixSortScreen from './RadixSortScreen'; 8 | import BucketSortScreen from './BucketSortScreen'; 9 | import MergeSortScreen from './MergeSortScreen'; 10 | import GenericSortScreen from './GenericSortScreen'; 11 | import { arrayCopy } from '../../util/ArrayUtil'; 12 | 13 | /** 14 | * The screen which shows the animation for the sorting visualizer. 15 | * 16 | * @component 17 | * @category Visualizer 18 | * @returns {JSX.Element} Animation sort screen component. 19 | */ 20 | const AnimationScreen = () => { 21 | const { 22 | isPlay, 23 | isReplay, 24 | arrayData, 25 | animationArr, 26 | idx, 27 | referenceArray, 28 | speed, 29 | setIdx, 30 | setReferenceArray, 31 | executeForwardAnimation, 32 | resetDataWhenAnimationFinish, 33 | dataSize, 34 | visualizerAlgorithm, 35 | isReset, 36 | setIsReset, 37 | } = useContext(VisualizerStateContext); 38 | const animationSpeedArray = [1000, 800, 600, 500, 400, 320, 260, 200, 160, 120]; 39 | let xDirection = 0; 40 | 41 | useEffect(() => { 42 | /** 43 | * This is for replay, or any changes to arrayData 44 | */ 45 | if (isReset) { 46 | setReferenceArray(arrayCopy(arrayData)); 47 | setIdx(0); 48 | setIsReset(false); 49 | } 50 | }, [arrayData, isReplay]); 51 | 52 | /** 53 | * This is the loop animation and ending of animation screen. 54 | * If block is to do the loop animation. 55 | * Else Block is to change the state into replay. 56 | */ 57 | useEffect(() => { 58 | if (!isReplay && isPlay && idx < animationArr.length) { 59 | setTimeout(() => { 60 | executeForwardAnimation(); 61 | }, animationSpeedArray[speed - 1]); 62 | } else if (!isReplay && isPlay) { 63 | resetDataWhenAnimationFinish(referenceArray); 64 | } 65 | }, [isPlay, idx]); 66 | 67 | const transitions = useTransition( 68 | referenceArray.map((data) => { 69 | if (isMergeSort(visualizerAlgorithm)) { 70 | return { ...data, x: parseInt(data.xDirection) }; 71 | } 72 | return { ...data, x: (xDirection += 10) - 10 }; 73 | }), 74 | (d) => d.id, 75 | { 76 | from: { height: 0, opacity: 1 }, 77 | leave: { height: 0, opacity: 1 }, 78 | enter: ({ x, height }) => ({ x, height, opacity: 1 }), 79 | update: ({ x, height }) => ({ x, height }), 80 | } 81 | ); 82 | 83 | const dataItem = { 84 | transitions: transitions, 85 | dataSize: dataSize, 86 | }; 87 | 88 | if (isCountingSort(visualizerAlgorithm)) { 89 | return ; 90 | } else if (isRadixSort(visualizerAlgorithm)) { 91 | return ; 92 | } else if (isBucketSort(visualizerAlgorithm)) { 93 | return ; 94 | } else if (isMergeSort(visualizerAlgorithm)) { 95 | return ; 96 | } else { 97 | return ; 98 | } 99 | }; 100 | 101 | export default AnimationScreen; 102 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/animationscreen/AnimationScreenUtil.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates a translation in the x direction to shift the animation screen when the data size 3 | * is more than 12. 4 | * 5 | * @method 6 | * @category VisualizerUtil 7 | * @param {number} dataSize Data size. 8 | * @returns {number} Translation in the x direction when the data size is more than 12. 9 | */ 10 | export const translateXOfVisualizer = (dataSize) => { 11 | if (dataSize > 12) { 12 | let singleBlockWidth = 200 / dataSize; 13 | return (dataSize - 12) * singleBlockWidth; 14 | } 15 | return 0; 16 | }; 17 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/animationscreen/BucketSortScreen.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { VisualizerStateContext } from '../../Visualizer'; 3 | import StackOfAnimatedBoxes from '../multipleblocks/StackOfAnimatedBoxes'; 4 | import './styles.css'; 5 | import HorizontalArray from '../multipleblocks/HorizontalArray'; 6 | import Oval from '../block/Oval'; 7 | 8 | /** 9 | * Bucket sort screen which encapsulates the fields and components of the animation. 10 | * 11 | * @component 12 | * @category AnimationScreen 13 | * @returns {JSX.Element} Bucket sort screen component. 14 | */ 15 | const BucketSortScreen = () => { 16 | const { referenceArray, stackArr } = useContext(VisualizerStateContext); 17 | 18 | return ( 19 |
20 | 21 |
22 | {stackArr.map((stack) => ( 23 | 28 | ))} 29 |
30 |
31 | ); 32 | }; 33 | 34 | export default BucketSortScreen; 35 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/animationscreen/CountingSortScreen.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import CountingSortBlock from '../block/CountingSortBlock'; 3 | import './styles.css'; 4 | import { VisualizerStateContext } from '../../Visualizer'; 5 | import HorizontalArray from '../multipleblocks/HorizontalArray'; 6 | import CountBlock from '../block/CountBlock'; 7 | 8 | /** 9 | * Counting sort screen which encapsulates the fields and components of the animation. 10 | * 11 | * @component 12 | * @category AnimationScreen 13 | * @returns {JSX.Element} Counting sort screen component. 14 | */ 15 | const CountingSortScreen = () => { 16 | const { referenceArray, countArr } = useContext(VisualizerStateContext); 17 | 18 | return ( 19 |
20 | 21 |
22 | 23 |
24 |
25 | ); 26 | }; 27 | 28 | export default CountingSortScreen; 29 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/animationscreen/GenericSortScreen.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AnimatedBlock from '../block/AnimatedBlock'; 3 | import './styles.css'; 4 | import { translateXOfVisualizer } from './AnimationScreenUtil'; 5 | 6 | /** 7 | * Animation screen which shows the Insertion, Bubble, Selection, Shell Sort algorithm. 8 | * 9 | * @component 10 | * @category AnimationScreen 11 | * @param {Object[]} transitions An array which contains the animated blocks. 12 | * @param {number} dataSize The number of blocks. 13 | * @returns {JSX.Element} Generic sort screen component. 14 | */ 15 | const GenericSortScreen = ({ transitions, dataSize }) => { 16 | return ( 17 |
23 | {transitions.map(({ item, props: { x, ...rest } }, index) => { 24 | return ( 25 | 34 | ); 35 | })} 36 |
37 | ); 38 | }; 39 | 40 | export default GenericSortScreen; 41 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/animationscreen/MergeSortScreen.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import MergeSortBlock from '../block/MergeSortBlock'; 3 | import './styles.css'; 4 | import { translateXOfVisualizer } from './AnimationScreenUtil'; 5 | 6 | /** 7 | * Animation screen which shows the Merge Sort algorithm. 8 | * 9 | * @component 10 | * @category AnimationScreen 11 | * @param {Object[]} transitions An array which contains the animated blocks. 12 | * @param {number} dataSize The number of blocks. 13 | * @returns {JSX.Element} Merge sort screen component. 14 | */ 15 | const MergeSortScreen = ({ transitions, dataSize }) => { 16 | return ( 17 |
18 |
24 | {transitions.map(({ item, props: { x, ...rest } }, index) => { 25 | return ( 26 | 37 | ); 38 | })} 39 |
40 |
41 |
42 | ); 43 | }; 44 | 45 | export default MergeSortScreen; 46 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/animationscreen/RadixSortScreen.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { VisualizerStateContext } from '../../Visualizer'; 3 | import './styles.css'; 4 | import '../multipleblocks/styles.css'; 5 | import HorizontalArray from '../multipleblocks/HorizontalArray'; 6 | import HighlightedOval from '../block/HighlightedOval'; 7 | import StackOfBoxes from '../multipleblocks/StackOfBoxes'; 8 | 9 | /** 10 | * Radix sort screen which encapsulates the fields and components of the animation. 11 | * 12 | * @component 13 | * @category AnimationScreen 14 | * @returns {JSX.Element} Radix sort screen component. 15 | */ 16 | const RadixSortScreen = () => { 17 | const { referenceArray, stackArr } = useContext(VisualizerStateContext); 18 | 19 | return ( 20 |
21 | 22 |
23 | {stackArr.map((stack) => ( 24 | 25 | ))} 26 |
27 |
28 | ); 29 | }; 30 | 31 | export default RadixSortScreen; 32 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/animationscreen/styles.css: -------------------------------------------------------------------------------- 1 | .list { 2 | align-items: flex-end; 3 | box-sizing: border-box; 4 | display: flex; 5 | flex-direction: row; 6 | min-height: 100px; 7 | } 8 | 9 | .container-one { 10 | display: flex; 11 | flex-direction: column; 12 | padding-top: 25px; 13 | } 14 | 15 | .spaced-out-container { 16 | display: flex; 17 | flex-direction: column; 18 | justify-content: space-between; 19 | min-height: 370px; 20 | padding-top: 25px; 21 | } 22 | 23 | .stack-arr { 24 | display: flex; 25 | flex-direction: row; 26 | justify-content: center; 27 | } 28 | 29 | .empty-space-for-merge-sort { 30 | box-sizing: border-box; 31 | height: 150px; 32 | } 33 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/block/AnimatedBlock.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | import { animated } from 'react-spring'; 4 | 5 | /** 6 | * A block which animates to show the sorting animation. 7 | * 8 | * @component 9 | * @category Block 10 | * @param {Object} item The information of the block. 11 | * @param {number} x The displacement of the block in the X-Direction. 12 | * @param {Object} rest All other information of the props. 13 | * @param {number} length The number of blocks. 14 | * @param {number} index Index of the block. 15 | * @param {boolean} isSwap A boolean value denoting whether this block is in a swap animation. 16 | * @param {number} width Width of the block. 17 | * @returns {JSX.Element} An animated block which translate in the X-Direction. 18 | */ 19 | const AnimatedBlock = ({ item, props: { x, ...rest }, length, index, isSwap, width }) => { 20 | return ( 21 | `translate3d(${x}px,0,0)`), 29 | backgroundImage: isSwap 30 | ? `linear-gradient(45deg, #13B1B7, #11C2C9)` 31 | : `linear-gradient(45deg, #287ED0, #5466FF)`, 32 | }} 33 | > 34 | {item.height} 35 | 36 | ); 37 | }; 38 | 39 | export default AnimatedBlock; 40 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/block/BucketSortBlock.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { animated } from 'react-spring'; 3 | import { spreadNumber } from './HighlightUtil'; 4 | import './styles.css'; 5 | 6 | /** 7 | * A bucket sort block which animates to show the sorting animation. 8 | * 9 | * @component 10 | * @category Block 11 | * @param {Object} item The information of the block. 12 | * @param {Object} x The displacement of the block. 13 | * @param {Object} rest All other information of the props. 14 | * @returns {JSX.Element} An animated block which translates in the y direction. 15 | */ 16 | const BucketSortBlock = ({ item, props: { y, ...rest } }) => { 17 | return ( 18 | `translate3d(0,${y}px,0)`), 27 | }} 28 | > 29 |
{spreadNumber(item.height)}
30 |
31 | ); 32 | }; 33 | 34 | export default BucketSortBlock; 35 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/block/CountBlock.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import './styles.css'; 3 | import { VisualizerStateContext } from '../../Visualizer'; 4 | 5 | /** 6 | * A count block used to collect items from the reference array. 7 | * 8 | * @component 9 | * @category Block 10 | * @returns {JSX.Element} Count block component. 11 | */ 12 | const CountBlock = ({ item }) => { 13 | const { dataSize } = useContext(VisualizerStateContext); 14 | 15 | /** 16 | * Color array used to represent the intensity of the highlight for each block. 17 | * 18 | * @const {string[]} 19 | */ 20 | const colorArr = [ 21 | '#B8B8B8', 22 | '#b4d3de', 23 | '#7AC1DB', 24 | '#74a2d6', 25 | '#7B9AD6', 26 | '#6A8FDB', 27 | '#5480D9', 28 | '#3B6DD2', 29 | '#3b5cd2', 30 | '#274ac8', 31 | '#1e41c8', 32 | '#183cc6', 33 | '#092ec8', 34 | '#091cc8', 35 | '#0600c3', 36 | '#0600a0', 37 | '#030062', 38 | '#030030', 39 | '#030016', 40 | '#000000', 41 | '#000000', 42 | '#000000', 43 | '#000000', 44 | '#000000', 45 | '#000000', 46 | ]; 47 | 48 | return ( 49 |
50 |
58 | {item.height} 59 |
60 | {item.count} 61 |
62 | ); 63 | }; 64 | 65 | export default CountBlock; 66 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/block/CountingSortBlock.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import './styles.css'; 3 | import { VisualizerStateContext } from '../../Visualizer'; 4 | 5 | /** 6 | * A counting sort block which represents a data item in the array. 7 | * 8 | * @component 9 | * @category Block 10 | * @param item Data item from the reference array. 11 | * @returns {JSX.Element} 12 | */ 13 | const CountingSortBlock = ({ item }) => { 14 | const { dataSize } = useContext(VisualizerStateContext); 15 | 16 | return ( 17 |
26 | {item.height} 27 |
28 | ); 29 | }; 30 | 31 | export default CountingSortBlock; 32 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/block/HighlightUtil.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | /** 4 | * Retrieves the current digit to highlight. 5 | * 6 | * @category HighlightUtil 7 | * @param {number} idx Index of the current animation. 8 | * @param {number} dataSize Size of data array. 9 | * @returns {number} Digit to highlight. 10 | */ 11 | const getDigitToHighlight = (idx, dataSize) => { 12 | if (idx < 2 * dataSize) { 13 | return 1; 14 | } else if (idx < 4 * dataSize) { 15 | return 2; 16 | } else if (idx < 6 * dataSize) { 17 | return 3; 18 | } else { 19 | // No highlight case 20 | return -1; 21 | } 22 | }; 23 | 24 | /** 25 | * Highlights a digit in the value based on the current stage of the animation. 26 | * 27 | * @method 28 | * @category HighlightUtil 29 | * @param {number} value Value of element. 30 | * @param {number} idx Current index of the animation. 31 | * @param {number} dataSize Size of data selected. 32 | * @returns {JSX.Element[]} Array of digits. 33 | */ 34 | export const highlightDigit = (value, idx, dataSize) => { 35 | const currentHighlighted = getDigitToHighlight(idx, dataSize); 36 | let current = 0; 37 | let index = 1; 38 | let numberMapping = []; 39 | while (value > 0) { 40 | current = value % 10; 41 | numberMapping.push([current, currentHighlighted === index]); 42 | index++; 43 | value = Math.floor(value / 10); 44 | } 45 | return numberMapping.map((x) => ( 46 | {x[0]} 47 | )); 48 | }; 49 | 50 | /** 51 | * Spreads the number into spans of digits. 52 | * 53 | * @method 54 | * @category HighlightUtil 55 | * @param {number} value Number to spread. 56 | * @returns {JSX.Element[]} Array of digits. 57 | */ 58 | export const spreadNumber = (value) => { 59 | let stringArray = Array.from(value.toString()); 60 | return stringArray.map((x) => {x}); 61 | }; 62 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/block/HighlightedOval.js: -------------------------------------------------------------------------------- 1 | import { highlightDigit } from './HighlightUtil'; 2 | import React, { useContext } from 'react'; 3 | import { VisualizerStateContext } from '../../Visualizer'; 4 | import './styles.css'; 5 | 6 | /** 7 | * Single oval to represent an item in the reference array. 8 | * 9 | * @component 10 | * @category Block 11 | * @param {Object} item Element in the reference array. 12 | * @param {boolean} display States if the oval should be highlighted. 13 | * @param {number} marginTop Margin 14 | * @returns {JSX.Element} Single oval containing the item. 15 | */ 16 | const HighlightedOval = ({ item, display, marginTop }) => { 17 | const { idx, dataSize } = useContext(VisualizerStateContext); 18 | 19 | return ( 20 |
27 |
{highlightDigit(item.height, idx, dataSize)}
28 |
29 | ); 30 | }; 31 | 32 | export default HighlightedOval; 33 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/block/MergeSortBlock.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | import { animated } from 'react-spring'; 4 | 5 | /** 6 | * A block which animates to show the Merge Sort algorithm. 7 | * 8 | * @component 9 | * @category Block 10 | * @param {Object} item The information of the block. 11 | * @param {number} x The displacement of the block in the X-Direction. 12 | * @param {Object} rest All other information of the props. 13 | * @param {number} length The number of blocks. 14 | * @param {number} index Index of the block. 15 | * @param {boolean} isSwap A boolean value denoting whether this block is in a shift animation. 16 | * @param {number} width Width of the block. 17 | * @returns {JSX.Element} An animated block which translate in either the X or Y-Direction. 18 | */ 19 | const MergeSortBlock = ({ item, props: { x, ...rest }, length, index, isShift, width }) => { 20 | return ( 21 | `translate3d(${x}px, 150px,0)`) 30 | : x.interpolate((x) => `translate3d(${x}px,0,0)`), 31 | backgroundImage: isShift 32 | ? `linear-gradient(45deg, #13B1B7, #11C2C9)` 33 | : `linear-gradient(45deg, #287ED0, #5466FF)`, 34 | pos: item.pos, 35 | prevPos: item.prevPos, 36 | }} 37 | > 38 | {item.height} 39 | 40 | ); 41 | }; 42 | 43 | export default MergeSortBlock; 44 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/block/Oval.js: -------------------------------------------------------------------------------- 1 | import { spreadNumber } from './HighlightUtil'; 2 | import React from 'react'; 3 | import './styles.css'; 4 | 5 | /** 6 | * Single oval to represent an item in the reference array. 7 | * 8 | * @component 9 | * @category Block 10 | * @param {Object} item Element in the reference array. 11 | * @returns {JSX.Element} Single oval containing the item. 12 | */ 13 | const Oval = ({ item }) => ( 14 |
20 |
{spreadNumber(item.height)}
21 |
22 | ); 23 | 24 | export default Oval; 25 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/block/styles.css: -------------------------------------------------------------------------------- 1 | /* For all blocks */ 2 | .animated-block { 3 | align-items: flex-end; 4 | align-self: flex-end; 5 | border-radius: 5px; 6 | box-shadow: 0 5px 13px 1px rgba(0, 0, 0, 0.2); 7 | display: flex; 8 | justify-content: center; 9 | position: relative; 10 | } 11 | 12 | .animated-block > span { 13 | color: whitesmoke; 14 | } 15 | 16 | /* Counting sort */ 17 | .fixed-array-container { 18 | align-items: center; 19 | align-self: flex-end; 20 | display: flex; 21 | flex-direction: column; 22 | } 23 | 24 | .count { 25 | font-family: 'Open Sans Semibold', sans-serif; 26 | font-size: 16px; 27 | margin-top: 5px; 28 | } 29 | 30 | /* Bucket and radix sort */ 31 | .oval { 32 | align-items: center; 33 | background: linear-gradient(45deg, #287ed0, #5466ff); 34 | border-radius: 50%; 35 | box-shadow: 0 5px 13px 1px rgba(0, 0, 0, 0.2); 36 | color: #d7d7d7; 37 | display: flex; 38 | font-size: 16px; 39 | height: 40px; 40 | justify-content: center; 41 | padding: 5px; 42 | position: relative; 43 | width: 50px; 44 | } 45 | 46 | .decimal > span:nth-child(3) { 47 | color: white; 48 | font-weight: bold; 49 | } 50 | 51 | .reversed-number { 52 | align-items: center; 53 | display: flex; 54 | flex-direction: row-reverse; 55 | justify-content: center; 56 | } 57 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/button/ButtonBox.js: -------------------------------------------------------------------------------- 1 | import BackButton from './forwardbackbutton/BackButton'; 2 | import ThreeStateButton from './threestatebutton/ThreeStateButton'; 3 | import NewDataButton from './newdatabutton/NewDataButton'; 4 | import ForwardButton from './forwardbackbutton/ForwardButton'; 5 | import React from 'react'; 6 | import './styles.css'; 7 | 8 | /** 9 | * A component which holds forward and backward button, as well as the play, pause and replay button. 10 | * 11 | * @component 12 | * @category Visualizer 13 | */ 14 | const ButtonBox = () => ( 15 |
16 | 17 |
18 | 19 | 20 |
21 | 22 |
23 | ); 24 | 25 | export default ButtonBox; 26 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/button/forwardbackbutton/BackButton.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { AiOutlineLeft } from 'react-icons/ai'; 3 | import { IconContext } from 'react-icons'; 4 | import { VisualizerStateContext } from '../../../Visualizer'; 5 | import './styles.css'; 6 | import { resetArray } from '../../../util/ArrayUtil'; 7 | 8 | /** 9 | * A button which executes one step in reverse for the sorting animation. 10 | * 11 | * @component 12 | * @category Button 13 | */ 14 | const BackButton = () => { 15 | const { 16 | isPlay, 17 | animationPercentage, 18 | executeBackwardAnimation, 19 | idx, 20 | arrayData, 21 | setArrayData, 22 | setIsReset, 23 | visualizerAlgorithm, 24 | } = useContext(VisualizerStateContext); 25 | 26 | const isEmpty = animationPercentage === 0; 27 | 28 | /** 29 | * Event handler to trigger the backward animation. 30 | */ 31 | const handleBackButtonClick = () => { 32 | executeBackwardAnimation(); 33 | // this is to check if we are at the start animation, to reset the color of the block 34 | if (idx - 1 <= 0) { 35 | setArrayData(resetArray(visualizerAlgorithm, arrayData)); 36 | setIsReset(true); 37 | } 38 | }; 39 | 40 | return ( 41 | 58 | ); 59 | }; 60 | 61 | export default BackButton; 62 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/button/forwardbackbutton/ForwardButton.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { IconContext } from 'react-icons'; 3 | import { AiOutlineRight } from 'react-icons/ai'; 4 | import './styles.css'; 5 | import { VisualizerStateContext } from '../../../Visualizer'; 6 | 7 | /** 8 | * A button which executes one step forward for the sorting animation. 9 | * 10 | * @component 11 | * @category Button 12 | */ 13 | const ForwardButton = () => { 14 | const { isPlay, animationPercentage, executeForwardAnimation, idx, animationArr } = useContext( 15 | VisualizerStateContext 16 | ); 17 | 18 | const isFull = animationPercentage === 100; 19 | 20 | /** 21 | * Event handler to trigger the forward animation. 22 | */ 23 | const handleForwardButtonClick = () => { 24 | if (idx < animationArr.length) { 25 | executeForwardAnimation(); 26 | } 27 | }; 28 | 29 | return ( 30 | 47 | ); 48 | }; 49 | 50 | export default ForwardButton; 51 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/button/forwardbackbutton/styles.css: -------------------------------------------------------------------------------- 1 | .forward-back-button { 2 | height: 30px; 3 | vertical-align: middle; 4 | width: 30px; 5 | } 6 | 7 | .forward-back-button-holder { 8 | background-color: white; 9 | border: none; 10 | outline: none; 11 | } 12 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/button/newdatabutton/NewDataButton.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import './styles.css'; 3 | import { VisualizerStateContext } from '../../../Visualizer'; 4 | import { buckets } from '../../../util/CountingSortUtil'; 5 | import { stack } from '../../../util/RadixSortUtil'; 6 | import { arrayCopy, generateArray } from '../../../util/ArrayUtil'; 7 | 8 | /** 9 | * A button to generate new data for the "blocks" for the sorting animation. 10 | * 11 | * @component 12 | * @category Button 13 | */ 14 | const NewDataButton = () => { 15 | const { 16 | isPlay, 17 | dataSize, 18 | setArrayData, 19 | setIsInMidstOfSort, 20 | setIsReplay, 21 | setAnimationPercentage, 22 | visualizerAlgorithm, 23 | setCountArr, 24 | setStackArr, 25 | setIsReset, 26 | setHistoryArr, 27 | } = useContext(VisualizerStateContext); 28 | 29 | /** 30 | * Event handler to generate new data set for the sorting animation. 31 | */ 32 | const handleNewDataButtonClick = () => { 33 | if (!isPlay) { 34 | setArrayData(generateArray(dataSize, visualizerAlgorithm)); 35 | setIsInMidstOfSort(false); 36 | setAnimationPercentage(0); 37 | setIsReplay(false); 38 | setCountArr(arrayCopy(buckets)); 39 | setStackArr(arrayCopy(stack)); 40 | setHistoryArr([]); 41 | setIsReset(true); 42 | } 43 | }; 44 | 45 | return ( 46 |
47 | handleNewDataButtonClick()}>New Data 48 |
49 | ); 50 | }; 51 | 52 | export default NewDataButton; 53 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/button/newdatabutton/styles.css: -------------------------------------------------------------------------------- 1 | .new-data-box { 2 | transform: translateY(20px); 3 | -moz-user-select: none; /* Firefox */ 4 | -ms-user-select: none; /* IE10+ */ 5 | -webkit-user-select: none; /* Chrome/Safari */ 6 | user-select: none; 7 | } 8 | 9 | .new-data-box > span { 10 | color: #8789b5; 11 | font-family: 'Open Sans', serif; 12 | font-size: 14px; 13 | } 14 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/button/styles.css: -------------------------------------------------------------------------------- 1 | .button-box { 2 | display: flex; 3 | flex: 3; 4 | justify-content: center; 5 | } 6 | 7 | .play-reset-button-box { 8 | align-items: center; 9 | display: flex; 10 | flex-direction: column; 11 | } 12 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/button/threestatebutton/PlayPauseReplayButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { IconContext } from 'react-icons'; 3 | import { AiFillCaretRight, AiOutlinePause, AiOutlineReload } from 'react-icons/ai'; 4 | import './styles.css'; 5 | 6 | /** 7 | * Depending on the {@code type}, it will show the relevant button state. 8 | * 9 | * @component 10 | * @category Button 11 | * @param {string} type The state of the button to be shown: 'play', 'pause', 'replay'. 12 | */ 13 | const PlayPauseReplayButton = ({ type }) => { 14 | return ( 15 | 21 | {type === 'play' ? ( 22 | 23 | ) : type === 'pause' ? ( 24 | 25 | ) : ( 26 | 27 | )} 28 | 29 | ); 30 | }; 31 | 32 | export default PlayPauseReplayButton; 33 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/button/threestatebutton/ThreeStateButton.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { VisualizerStateContext } from '../../../Visualizer'; 3 | import PlayPauseReplayButton from './PlayPauseReplayButton'; 4 | import './styles.css'; 5 | 6 | /** 7 | * A component which holds the 3 states, Play, Pause, Replay. 8 | * 9 | * @component 10 | * @category Button 11 | */ 12 | const ThreeStateButton = () => { 13 | const { 14 | isPlay, 15 | isReplay, 16 | setIsReplay, 17 | setIsPlay, 18 | setIsInMidstOfSort, 19 | setAnimationPercentage, 20 | setIsReset, 21 | } = useContext(VisualizerStateContext); 22 | 23 | /** 24 | * Event handler that trigger play, pause, replay functionality. 25 | */ 26 | const handleThreeStateButtonClick = () => { 27 | if (isReplay) { 28 | setIsReplay(false); 29 | setAnimationPercentage(0); 30 | setIsReset(true); 31 | setTimeout(() => setIsPlay(true), 300); 32 | } else { 33 | setIsPlay(!isPlay); 34 | } 35 | setIsInMidstOfSort(true); 36 | }; 37 | 38 | return ( 39 | 48 | ); 49 | }; 50 | 51 | export default ThreeStateButton; 52 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/button/threestatebutton/styles.css: -------------------------------------------------------------------------------- 1 | .three-state-button { 2 | color: white; 3 | height: 40px; 4 | vertical-align: middle; 5 | width: 40px; 6 | } 7 | 8 | .three-state-button-holder { 9 | background-image: linear-gradient(90deg, #287ed0, #5466ff); 10 | border: none; 11 | border-radius: 100%; 12 | box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.2); 13 | cursor: pointer; 14 | height: 70px; 15 | outline: none; 16 | transform: translateY(10px); 17 | width: 70px; 18 | } 19 | 20 | .three-state-button-holder:hover { 21 | box-shadow: 1px 6px 6px rgba(190, 196, 255, 0.6); 22 | } 23 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/legend/Legend.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import LegendInformation from './LegendInformation'; 3 | import LegendHeader from './LegendHeader'; 4 | import './styles.css'; 5 | import { VisualizerStateContext } from '../../Visualizer'; 6 | import { hasLegend, isMergeSort, isSelectionSort } from '../../util/GeneralUtil'; 7 | 8 | /** 9 | * A legend which display information about the current sorting animation. 10 | * 11 | * @component 12 | * @category Visualizer 13 | */ 14 | const Legend = () => { 15 | const { visualizerAlgorithm } = useContext(VisualizerStateContext); 16 | 17 | const legendInformation = [ 18 | { 19 | color: 'linear-gradient(45deg, #13B1B7, #11C2C9)', 20 | description: isMergeSort(visualizerAlgorithm) 21 | ? 'Currently involved in the merge process' 22 | : isSelectionSort(visualizerAlgorithm) 23 | ? 'Currently involved in selection process' 24 | : 'Currently involved in the swap process', 25 | }, 26 | { 27 | color: 'linear-gradient(45deg, #287ED0, #5466FF)', 28 | description: isMergeSort(visualizerAlgorithm) 29 | ? 'Not involved in the merge process' 30 | : isSelectionSort(visualizerAlgorithm) 31 | ? 'Not involved in the selection process' 32 | : 'Not involved in the swap process', 33 | }, 34 | ]; 35 | 36 | return ( 37 |
38 | {hasLegend(visualizerAlgorithm) && ( 39 |
40 |
41 | 42 |
43 |
44 | {legendInformation.map(({ color, description }, index) => ( 45 | 46 | ))} 47 |
48 |
49 | )} 50 |
51 | ); 52 | }; 53 | 54 | export default Legend; 55 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/legend/LegendHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | 4 | /** 5 | * Header for the Legend. 6 | * 7 | * @component 8 | * @category Legend 9 | */ 10 | const LegendHeader = () => { 11 | return ( 12 | <> 13 |
14 | Legend 15 |
16 |
17 | 18 | ); 19 | }; 20 | 21 | export default LegendHeader; 22 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/legend/LegendInformation.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | 4 | /** 5 | * The information which is displayed in the legend component. 6 | * 7 | * @component 8 | * @category Legend 9 | */ 10 | const LegendInformation = ({ color, description }) => { 11 | return ( 12 |
13 |
14 |
15 |
16 |
17 | {description} 18 |
19 |
20 | ); 21 | }; 22 | 23 | export default LegendInformation; 24 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/legend/styles.css: -------------------------------------------------------------------------------- 1 | .legend-box { 2 | display: flex; 3 | flex: 4; 4 | height: 100%; 5 | justify-content: flex-start; 6 | } 7 | 8 | .legend-header-box { 9 | display: flex; 10 | flex-direction: column; 11 | height: 30%; 12 | justify-content: center; 13 | } 14 | 15 | .legend-information-box { 16 | display: flex; 17 | flex-direction: column; 18 | white-space: nowrap; 19 | } 20 | 21 | .legend-header > span { 22 | color: #8789b5; 23 | font-family: 'Open Sans', serif; 24 | font-size: 16px; 25 | } 26 | 27 | .legend-header-line { 28 | background-color: #d5d9fc; 29 | height: 1px; 30 | transform: translateY(5px); 31 | width: 55px; 32 | } 33 | 34 | .legend-information { 35 | display: flex; 36 | flex: 1; 37 | padding-top: 5px; 38 | } 39 | 40 | .legend-information-box-holder { 41 | align-items: flex-start; 42 | display: flex; 43 | justify-content: flex-start; 44 | } 45 | 46 | .legend-information-box-box { 47 | height: 20px; 48 | width: 20px; 49 | } 50 | 51 | .legend-information-description-holder { 52 | display: flex; 53 | flex: 6; 54 | transform: translateX(10px); 55 | } 56 | 57 | .legend-information-description-text { 58 | color: #8789b5; 59 | font-family: 'Open Sans', serif; 60 | font-size: 13px; 61 | } 62 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/multipleblocks/HorizontalArray.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './styles.css'; 3 | 4 | /** 5 | * Horizontal array representation of the entire array. 6 | * 7 | * @component 8 | * @category MultipleBlocks 9 | * @param referenceArray Current state of the data array. 10 | * @param BlockType Used to represent each item in the data array. 11 | * @returns {JSX.Element} Horizontal array component. 12 | */ 13 | const HorizontalArray = ({ referenceArray, BlockType }) => { 14 | return ( 15 |
16 | {referenceArray.map((x) => ( 17 | 18 | ))} 19 |
20 | ); 21 | }; 22 | 23 | export default HorizontalArray; 24 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/multipleblocks/StackOfAnimatedBoxes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTransition } from 'react-spring'; 3 | import BucketSortBlock from '../block/BucketSortBlock'; 4 | import './styles.css'; 5 | 6 | /** 7 | * Animated stack of boxes used for bucket sort. 8 | * 9 | * @component 10 | * @category MultipleBlocks 11 | * @param {any[]} individualStack Individual bucket in the stack. 12 | * @param {number} value Index of the stack. 13 | * @returns {JSX.Element} Stack of boxes component. 14 | */ 15 | const StackOfAnimatedBoxes = ({ individualStack, value }) => { 16 | let yDirection = 0; 17 | 18 | // Transition for the single stack 19 | const transition = useTransition( 20 | individualStack.map((data) => { 21 | return { ...data, y: (yDirection -= 10) + 10 }; 22 | }), 23 | (d) => d.id, 24 | { 25 | from: { height: 0, opacity: 1 }, 26 | leave: { height: 0, opacity: 1 }, 27 | enter: ({ y, height }) => ({ y, height, opacity: 1 }), 28 | update: ({ y, height }) => ({ y, height }), 29 | } 30 | ); 31 | 32 | return ( 33 |
34 |
35 | {transition.map(({ item, props: { y, ...rest } }) => ( 36 | 37 | ))} 38 |
39 |
{value}
40 |
41 | ); 42 | }; 43 | 44 | export default StackOfAnimatedBoxes; 45 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/multipleblocks/StackOfBoxes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import HighlightedOval from '../block/HighlightedOval'; 3 | 4 | /** 5 | * Stack of boxes of an item in the bucket for radix sort. 6 | * 7 | * @component 8 | * @category MultipleBlocks 9 | * @param {Object} individualStack A single stack in the buckets. 10 | * @returns {JSX.Element} Stack of boxes component. 11 | */ 12 | const StackOfBoxes = ({ individualStack }) => ( 13 |
14 |
15 | {individualStack.array.map((x) => ( 16 | 17 | ))} 18 |
19 |
{individualStack.value}
20 |
21 | ); 22 | 23 | export default StackOfBoxes; 24 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/multipleblocks/styles.css: -------------------------------------------------------------------------------- 1 | .horiz-arr { 2 | align-self: center; 3 | display: grid; 4 | gap: 10px; 5 | grid-auto-flow: column; 6 | justify-content: center; 7 | } 8 | 9 | .stack { 10 | align-items: center; 11 | display: flex; 12 | flex-direction: column; 13 | justify-content: flex-end; 14 | margin-left: 10px; 15 | } 16 | 17 | .stack-boxes { 18 | display: flex; 19 | flex-direction: column-reverse; 20 | } 21 | 22 | .number-with-line { 23 | border-top: 1px solid black; 24 | font-family: 'Open Sans Semibold', sans-serif; 25 | font-size: 15px; 26 | margin-top: 10px; 27 | text-align: center; 28 | width: 60px; 29 | } 30 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/selectors/algorithmselector/AlgorithmSelector.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import { Dropdown, Menu } from 'antd'; 3 | import { DownOutlined } from '@ant-design/icons'; 4 | import { VisualizerStateContext } from '../../../Visualizer'; 5 | import 'antd/dist/antd.css'; 6 | import { isRadixOrBucket } from '../../../util/GeneralUtil'; 7 | import { buckets } from '../../../util/CountingSortUtil'; 8 | import './styles.css'; 9 | import { stack } from '../../../util/RadixSortUtil'; 10 | import { arrayCopy, generateArray } from '../../../util/ArrayUtil'; 11 | 12 | /** 13 | * A drop down menu which allows users to pick their algorithm for the visualizer. 14 | * 15 | * @component 16 | * @category Visualizer 17 | */ 18 | const AlgorithmChooser = () => { 19 | const { 20 | dataSize, 21 | setDataSize, 22 | isPlay, 23 | isInMidstOfSort, 24 | setIsReplay, 25 | setIsInMidstOfSort, 26 | setVisualizerAlgorithm, 27 | setArrayData, 28 | setAnimationPercentage, 29 | setIsReset, 30 | setCountArr, 31 | setStackArr, 32 | setHistoryArr, 33 | } = useContext(VisualizerStateContext); 34 | 35 | const [algorithm, setAlgorithm] = useState('Bubble Sort'); 36 | 37 | /** 38 | * List of available Algorithms available in Sort-Algo. 39 | */ 40 | const listOfAlgorithm = [ 41 | { algorithmName: 'Bubble Sort', key: '0' }, 42 | { algorithmName: 'Insertion Sort', key: '1' }, 43 | { algorithmName: 'Selection Sort', key: '2' }, 44 | { algorithmName: 'Merge Sort', key: '3' }, 45 | { algorithmName: 'Quick Sort', key: '4' }, 46 | { algorithmName: 'Heap Sort', key: '5' }, 47 | { algorithmName: 'Shell Sort', key: '6' }, 48 | { algorithmName: 'Counting Sort', key: '7' }, 49 | { algorithmName: 'Radix Sort', key: '8' }, 50 | { algorithmName: 'Bucket Sort', key: '9' }, 51 | ]; 52 | 53 | /** 54 | * Retrieves the algorithm name being chosen and set the system's algorithm to the selected algorithm. 55 | * 56 | * @param algorithmName Algorithm which is chosen via the drop down menu. 57 | */ 58 | const handleMenuClick = (algorithmName) => { 59 | setAlgorithm(algorithmName); 60 | setVisualizerAlgorithm(algorithmName); 61 | if (algorithm !== algorithmName) { 62 | if (isInMidstOfSort) { 63 | setIsInMidstOfSort(false); 64 | } 65 | if (dataSize > 10 && isRadixOrBucket(algorithmName)) { 66 | setArrayData(generateArray(10, algorithmName)); 67 | setDataSize(10); 68 | } else { 69 | setArrayData(generateArray(dataSize, algorithmName)); 70 | } 71 | setIsReplay(false); 72 | setIsReset(true); 73 | setCountArr(arrayCopy(buckets)); 74 | setStackArr(arrayCopy(stack)); 75 | setHistoryArr([]); 76 | setAnimationPercentage(0); 77 | } 78 | }; 79 | 80 | /** 81 | * A drop down list which displays a list of algorithms available in Sort-Algo. 82 | * 83 | * @type {JSX.Element} 84 | */ 85 | const menu = ( 86 | 87 | {listOfAlgorithm.map(({ algorithmName, key }) => { 88 | return ( 89 | handleMenuClick(algorithmName)} 92 | style={{ color: '#8789B5' }} 93 | > 94 | {algorithmName} 95 | 96 | ); 97 | })} 98 | 99 | ); 100 | 101 | return ( 102 | 119 | ); 120 | }; 121 | 122 | export default AlgorithmChooser; 123 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/selectors/algorithmselector/styles.css: -------------------------------------------------------------------------------- 1 | #algorithm-selector-drop-down-arrow { 2 | align-items: center; 3 | color: #8789b5; 4 | display: flex; 5 | font-size: 17px; 6 | justify-content: flex-end; 7 | width: 120px; 8 | } 9 | 10 | .algorithm-selector-holder { 11 | display: flex; 12 | transform: translate(-15px, 10px); 13 | width: 120px; 14 | } 15 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/selectors/sliderselector/SelectorProps.js: -------------------------------------------------------------------------------- 1 | export const SpeedSelectorProps = { 2 | min: 1, 3 | max: 10, 4 | name: 'Speed', 5 | }; 6 | 7 | export const DataSizeSelectorProps = { 8 | min: 5, 9 | max: 25, 10 | name: 'Size', 11 | }; 12 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/selectors/sliderselector/SliderSelector.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import { Slider } from 'antd'; 3 | import 'antd/dist/antd.css'; 4 | import './styles.css'; 5 | import { VisualizerStateContext } from '../../../Visualizer'; 6 | import { isRadixOrBucket } from '../../../util/GeneralUtil'; 7 | 8 | /** 9 | * A generic component for the slider. 10 | * 11 | * @component 12 | * @category Visualizer 13 | * @param {function} setData A method to change the data upon sliding. 14 | * @param {number} min The minimum value for the slider. 15 | * @param {number} max The maximum value for the slider. 16 | * @param {string} name The name to be displayed for the slider. 17 | * @returns {JSX.Element} A slider component that is bounded by {@code min} and {@code max}. 18 | */ 19 | const SliderSelector = ({ setData, min, max, name }) => { 20 | const { isPlay, visualizerAlgorithm } = useContext(VisualizerStateContext); 21 | 22 | const maxSize = isRadixOrBucket(visualizerAlgorithm) ? 10 : max; 23 | 24 | const [sliderData, setSliderData] = useState(() => Math.floor((min + maxSize) / 2)); 25 | 26 | return ( 27 |
28 | 29 | {name}: {sliderData} 30 | 31 | setSliderData(val)} 36 | onAfterChange={() => setData(sliderData)} 37 | disabled={isPlay} 38 | /> 39 |
40 | ); 41 | }; 42 | 43 | export default SliderSelector; 44 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/selectors/sliderselector/styles.css: -------------------------------------------------------------------------------- 1 | .selector-holder { 2 | width: 300px; 3 | } 4 | 5 | .selector-holder > span { 6 | color: #8789b5; 7 | font-family: 'Open Sans', serif; 8 | font-size: 16px; 9 | } 10 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/stepbystep/StepByStep.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import './styles.css'; 3 | import { VisualizerStateContext } from '../../Visualizer'; 4 | import { getStepByStepText } from './StepByStepUtil'; 5 | 6 | /** 7 | * A component which display each steps of the sorting algorithm. 8 | * 9 | * @component 10 | * @category Visualizer 11 | */ 12 | const StepByStep = () => { 13 | const { 14 | animationArr, 15 | idx, 16 | referenceArray, 17 | visualizerAlgorithm, 18 | animationPercentage, 19 | stackArr, 20 | } = useContext(VisualizerStateContext); 21 | 22 | return ( 23 |
24 |

25 | {animationPercentage > 0 && 26 | getStepByStepText(visualizerAlgorithm, animationArr, idx, referenceArray, stackArr)} 27 |

28 |
29 | ); 30 | }; 31 | 32 | export default StepByStep; 33 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/stepbystep/StepByStepUtil.js: -------------------------------------------------------------------------------- 1 | import SortingAlgorithmsStepByStep from '../../../algorithm/stepbysteptemplate/allSortsStepByStep'; 2 | import { isBucketSort } from '../../util/GeneralUtil'; 3 | 4 | /** 5 | * Gets the step by step text to display to the user. 6 | * 7 | * @method 8 | * @category StepTracingUtil 9 | * @param {string} visualizerAlgorithm The current algorithm of the visualizer. 10 | * @param {any[]} animationArr Animation array. 11 | * @param {number} idx Index of animation. 12 | * @param {Object[]} referenceArray Reference array of blocks displayed. 13 | * @param {Object[]} stackArr Stack array, present only in bucket and radix sort. 14 | * @returns {string} Step by step text generated. 15 | */ 16 | export const getStepByStepText = ( 17 | visualizerAlgorithm, 18 | animationArr, 19 | idx, 20 | referenceArray, 21 | stackArr 22 | ) => { 23 | const sortAlgoStepByStep = SortingAlgorithmsStepByStep[visualizerAlgorithm]; 24 | if (isBucketSort(visualizerAlgorithm)) { 25 | return sortAlgoStepByStep(animationArr, idx, stackArr); 26 | } 27 | return sortAlgoStepByStep(animationArr, idx, referenceArray); 28 | }; 29 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/component/stepbystep/styles.css: -------------------------------------------------------------------------------- 1 | .step-by-step-holder { 2 | background-color: #fafbff; 3 | border: 1px solid rgba(166, 175, 251, 1); 4 | border-radius: 5px; 5 | height: 90px; 6 | padding: 0 5px; 7 | transform: translate(-7px, 30px); 8 | width: 410px; 9 | } 10 | 11 | .step-by-step-holder > p { 12 | color: #8789b5; 13 | font-family: 'Open Sans', serif; 14 | font-weight: 500; 15 | text-align: center; 16 | white-space: pre-line; 17 | } 18 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/styles.css: -------------------------------------------------------------------------------- 1 | .visualizer-box { 2 | align-items: flex-end; 3 | display: flex; 4 | flex: 1; 5 | justify-content: center; 6 | width: 100%; 7 | } 8 | 9 | .controller-box { 10 | align-items: center; 11 | display: flex; 12 | flex: 2; 13 | flex-direction: row; 14 | flex-grow: 0; 15 | justify-content: center; 16 | min-height: 275px; 17 | width: 100%; 18 | } 19 | 20 | .visualizer-header-box { 21 | align-items: center; 22 | display: flex; 23 | flex: 1; 24 | flex-direction: column; 25 | margin-bottom: 1px; 26 | width: 100%; 27 | } 28 | 29 | .visualizer { 30 | align-items: center; 31 | display: flex; 32 | flex-direction: column; 33 | flex-grow: 0; 34 | justify-content: center; 35 | min-height: 700px; 36 | width: 100%; 37 | } 38 | 39 | .speed-selector-box { 40 | align-items: flex-end; 41 | display: flex; 42 | flex: 4; 43 | flex-direction: column; 44 | } 45 | 46 | #visualizer { 47 | min-width: 100%; 48 | padding-bottom: 3%; 49 | width: 0; 50 | } 51 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/util/ArrayUtil.js: -------------------------------------------------------------------------------- 1 | import { generateValue } from './MathUtil'; 2 | import { generateMergeSortArray } from './MergeSortUtil'; 3 | import { generateCountSortArray } from './CountingSortUtil'; 4 | import { generateRadixSortArray } from './RadixSortUtil'; 5 | import { generateBucketSortArray } from './BucketSortUtil'; 6 | import SortingAlgorithms from '../../algorithm/sortingalgorithms/allSorts'; 7 | import { isCountingSort, isMergeSort, isRadixOrBucket } from './GeneralUtil'; 8 | 9 | /** 10 | * Resets the given array. 11 | * 12 | * @method 13 | * @category ArrayUtil 14 | * @param {string} visualizerAlgorithm Algorithm used. 15 | * @param {Object[]} arr Array to be reset. 16 | * @returns {Object[]} Array that has been reset. 17 | */ 18 | export const resetArray = (visualizerAlgorithm, arr) => { 19 | if (isRadixOrBucket(visualizerAlgorithm)) { 20 | return arrayCopy(arr); 21 | } 22 | 23 | return arrayCopy(arr).map((x) => { 24 | let tempArrElement = x; 25 | if (isCountingSort(visualizerAlgorithm)) { 26 | tempArrElement.isShown = true; 27 | } else if (isMergeSort(visualizerAlgorithm)) { 28 | tempArrElement.isShift = false; 29 | } else { 30 | tempArrElement.isSwap = false; 31 | } 32 | return tempArrElement; 33 | }); 34 | }; 35 | 36 | /** 37 | * Creates a deep copy of the array. 38 | * 39 | * @method 40 | * @category ArrayUtil 41 | * @param {Object[]} arr Array to be copied. 42 | * @returns {Object[]} Deep copy of the input array. 43 | */ 44 | export const arrayCopy = (arr) => { 45 | return JSON.parse(JSON.stringify(arr)); 46 | }; 47 | 48 | /** 49 | * Retrieves the animation array based on the given array and algorithm selected. 50 | * 51 | * @method 52 | * @category ArrayUtil 53 | * @param {string} visualizerAlgorithm The current algorithm of the visualizer. 54 | * @param {Object[]} arrayData Given array. 55 | * @returns {any[]} An array that contains all the animation steps. 56 | */ 57 | export const getAnimationArr = (visualizerAlgorithm, arrayData) => { 58 | const sortAlgo = SortingAlgorithms[visualizerAlgorithm]; 59 | return sortAlgo(arrayCopy(arrayData)); 60 | }; 61 | 62 | /** 63 | * Object used to map the names of each algorithm to its generated array. 64 | * 65 | * @method 66 | * @category ArrayUtil 67 | * @const {Object} 68 | */ 69 | const arrayGenerator = { 70 | 'Insertion Sort': (size) => generateDefaultArray(size), 71 | 'Bubble Sort': (size) => generateDefaultArray(size), 72 | 'Quick Sort': (size) => generateDefaultArray(size), 73 | 'Shell Sort': (size) => generateDefaultArray(size), 74 | 'Heap Sort': (size) => generateDefaultArray(size), 75 | 'Selection Sort': (size) => generateDefaultArray(size), 76 | 'Merge Sort': (size) => generateMergeSortArray(size), 77 | 'Counting Sort': (size) => generateCountSortArray(size), 78 | 'Radix Sort': (size) => generateRadixSortArray(size), 79 | 'Bucket Sort': (size) => generateBucketSortArray(size), 80 | }; 81 | 82 | /** 83 | * Generates a random array based on the size chosen and the algorithm selected. 84 | * 85 | * @method 86 | * @category ArrayUtil 87 | * @param {number} size Size of array selected by user. 88 | * @param {string} visualizerAlgorithm The current algorithm of the visualizer. 89 | * @returns {Object[]} Random array generated. 90 | */ 91 | export const generateArray = (size, visualizerAlgorithm) => { 92 | return arrayGenerator[visualizerAlgorithm](size); 93 | }; 94 | 95 | /** 96 | * Generates the default array. Used by all sorting algorithms involving swaps only. 97 | * 98 | * @category ArrayUtil 99 | * @param {number} size Size of array selected by user. 100 | * @returns {Object[]} Random array generated. 101 | */ 102 | const generateDefaultArray = (size) => { 103 | let array = []; 104 | for (let i = 0; i < size; i++) { 105 | array.push({ 106 | id: i, 107 | height: generateValue(5, 20), 108 | isSwap: false, 109 | }); 110 | } 111 | return array; 112 | }; 113 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/util/BucketSortUtil.js: -------------------------------------------------------------------------------- 1 | import { executeRadixSort } from './RadixSortUtil'; 2 | import { executeSwap } from './SwappingAlgoUtil'; 3 | import { resetArray } from './ArrayUtil'; 4 | 5 | /** 6 | * Generates a random decimal. 7 | * 8 | * @category BucketSortUtil 9 | * @returns {number} Random decimal generated. 10 | */ 11 | const generateDecimal = () => { 12 | return +Math.random().toFixed(3); 13 | }; 14 | 15 | /** 16 | * Inner sorting algorithm used for bucket sort. 17 | * 18 | * @category BucketSortUtil 19 | * @type {string} 20 | */ 21 | const innerSortUsed = 'Insertion Sort'; 22 | 23 | /** 24 | * Executes one step of the bucket sort algorithm. 25 | * 26 | * @method 27 | * @category BucketSortUtil 28 | * @param {any} currentAnimation Current animation object. 29 | * @param {Object[]} referenceArray Current state of the data array in the sorting execution. 30 | * @param {Object[]} stackArr Current state of the stack array in the sorting execution. 31 | * @param {boolean} isForward Boolean value which states if this is a forward or backward animation. 32 | * @returns {Object[]} The next state of the reference array after this sorting step. 33 | */ 34 | export const executeBucketSort = (currentAnimation, referenceArray, stackArr, isForward) => { 35 | if (currentAnimation.length === 4) { 36 | executeInnerBucketSort(currentAnimation, stackArr); 37 | } else if (currentAnimation.isSort === undefined) { 38 | executeRadixSort(currentAnimation, referenceArray, stackArr, isForward); 39 | } else { 40 | executeResetBucket(currentAnimation, stackArr); 41 | } 42 | return referenceArray; 43 | }; 44 | 45 | /** 46 | * Executes one step of insertion sort on one single bucket. 47 | * 48 | * @category BucketSortUtil 49 | * @param {any[]} currentAnimation Current animation object. 50 | * @param {Object[]} stackArr Current stack array. 51 | */ 52 | const executeInnerBucketSort = (currentAnimation, stackArr) => { 53 | const firstIdx = currentAnimation[0]; 54 | const secondIdx = currentAnimation[1]; 55 | const isSwapOccurring = currentAnimation[2]; 56 | const location = currentAnimation[3]; 57 | stackArr[location].array = executeSwap( 58 | firstIdx, 59 | secondIdx, 60 | stackArr[location].array, 61 | isSwapOccurring, 62 | innerSortUsed 63 | ); 64 | }; 65 | 66 | /** 67 | * Resets the inner bucket to the default state. This removes any leftover highlight from the 68 | * elements. 69 | * 70 | * @category BucketSortUtil 71 | * @param {Object} currentAnimation Current animation object. 72 | * @param {Object[]} stackArr Current stack array. 73 | */ 74 | const executeResetBucket = (currentAnimation, stackArr) => { 75 | const location = currentAnimation.location; 76 | stackArr[location].array = resetArray(innerSortUsed, stackArr[location].array); 77 | }; 78 | 79 | /** 80 | * Generates the random array for bucket sort. 81 | * 82 | * @method 83 | * @category BucketSortUtil 84 | * @param {number} size Size of array generated. 85 | * @returns {Object[]} Random array for bucket sort. 86 | */ 87 | export const generateBucketSortArray = (size) => { 88 | let array = []; 89 | for (let i = 0; i < size; i++) { 90 | array.push({ 91 | id: i, 92 | height: generateDecimal(), 93 | isShown: true, 94 | }); 95 | } 96 | return array; 97 | }; 98 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/util/CountingSortUtil.js: -------------------------------------------------------------------------------- 1 | import { generateValue } from './MathUtil'; 2 | 3 | /** 4 | * Buckets used for counting sort animation. 5 | * 6 | * @category CountingSortUtil 7 | * @const {Object[]} 8 | */ 9 | export const buckets = [ 10 | { height: 1, count: 0 }, 11 | { height: 2, count: 0 }, 12 | { height: 3, count: 0 }, 13 | { height: 4, count: 0 }, 14 | { height: 5, count: 0 }, 15 | { height: 6, count: 0 }, 16 | { height: 7, count: 0 }, 17 | { height: 8, count: 0 }, 18 | { height: 9, count: 0 }, 19 | ]; 20 | 21 | /** 22 | * Generates the random array for counting sort. 23 | * 24 | * @method 25 | * @category CountingSortUtil 26 | * @param {number} size Size of array generated. 27 | * @returns {Object[]} Random array for counting sort. 28 | */ 29 | export const generateCountSortArray = (size) => { 30 | let array = []; 31 | for (let i = 0; i < size; i++) { 32 | array.push({ 33 | id: i, 34 | height: generateValue(1, 9), 35 | isShown: true, 36 | }); 37 | } 38 | return array; 39 | }; 40 | 41 | // Function to execute the counting sort animation 42 | 43 | /** 44 | * Executes one step of the counting sort algorithm. 45 | * 46 | * @method 47 | * @category CountingSortUtil 48 | * @param {Object} currentAnimation Current animation object. 49 | * @param {Object[]} referenceArray Current state of the data array in the sorting execution. 50 | * @param {number} animationPx Current animation percentage. 51 | * @param {Object[]} countArr Count bucket array used for counting sort. 52 | * @param {boolean} isForward Boolean value which states if this is a forward or backward animation. 53 | * @returns {Object[]} The next state of the reference array after this sorting step. 54 | */ 55 | export const executeCountSort = ( 56 | currentAnimation, 57 | referenceArray, 58 | animationPx, 59 | countArr, 60 | isForward 61 | ) => { 62 | const index = currentAnimation.id; 63 | const height = currentAnimation.height; 64 | const isCountAnimation = (isForward && animationPx <= 50) || (!isForward && animationPx >= 50); 65 | if (isCountAnimation) { 66 | referenceArray[index].isShown = false; 67 | countArr[height - 1].count += 1; 68 | } else { 69 | referenceArray[index] = currentAnimation; 70 | referenceArray[index].isShown = true; 71 | countArr[height - 1].count -= 1; 72 | } 73 | return referenceArray; 74 | }; 75 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/util/GeneralUtil.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns true if the algorithm input is counting sort. 3 | * 4 | * @method 5 | * @category GeneralUtil 6 | * @param {string} visualizerAlgorithm Input algorithm. 7 | * @returns {boolean} True if the algorithm is counting sort. 8 | */ 9 | export const isCountingSort = (visualizerAlgorithm) => visualizerAlgorithm === 'Counting Sort'; 10 | 11 | /** 12 | * Returns true if the algorithm input is radix sort. 13 | * 14 | * @method 15 | * @category GeneralUtil 16 | * @param {string} visualizerAlgorithm Input algorithm. 17 | * @returns {boolean} True if the algorithm is radix sort. 18 | */ 19 | export const isRadixSort = (visualizerAlgorithm) => visualizerAlgorithm === 'Radix Sort'; 20 | 21 | /** 22 | * Returns true if the algorithm input is bucket sort. 23 | * 24 | * @method 25 | * @category GeneralUtil 26 | * @param {string} visualizerAlgorithm Input algorithm. 27 | * @returns {boolean} True if the algorithm is bucket sort. 28 | */ 29 | export const isBucketSort = (visualizerAlgorithm) => visualizerAlgorithm === 'Bucket Sort'; 30 | 31 | /** 32 | * Returns true if the algorithm input is radix or bucket sort. 33 | * 34 | * @method 35 | * @category GeneralUtil 36 | * @param {string} visualizerAlgorithm Input algorithm. 37 | * @returns {boolean} True if the algorithm is radix or bucket sort. 38 | */ 39 | export const isRadixOrBucket = (visualizerAlgorithm) => 40 | isRadixSort(visualizerAlgorithm) || isBucketSort(visualizerAlgorithm); 41 | 42 | /** 43 | * Returns true if the algorithm input is merge sort. 44 | * 45 | * @method 46 | * @category GeneralUtil 47 | * @param {string} visualizerAlgorithm Input algorithm. 48 | * @returns {boolean} True if the algorithm is merge sort. 49 | */ 50 | export const isMergeSort = (visualizerAlgorithm) => visualizerAlgorithm === 'Merge Sort'; 51 | 52 | /** 53 | * Returns true if the algorithm input is selection sort. 54 | * 55 | * @method 56 | * @category GeneralUtil 57 | * @param {string} visualizerAlgorithm Input algorithm. 58 | * @returns {boolean} True if the algorithm is selection sort. 59 | */ 60 | export const isSelectionSort = (visualizerAlgorithm) => visualizerAlgorithm === 'Selection Sort'; 61 | 62 | /** 63 | * Returns true if the algorithm input is quick sort. 64 | * 65 | * @method 66 | * @category GeneralUtil 67 | * @param {string} visualizerAlgorithm Input algorithm. 68 | * @returns {boolean} True if the algorithm is quick sort. 69 | */ 70 | export const isQuickSort = (visualizerAlgorithm) => visualizerAlgorithm === 'Quick Sort'; 71 | 72 | /** 73 | * Returns true if the algorithm input is any sort aside from bucket, radix and counting sort. 74 | * 75 | * @method 76 | * @category GeneralUtil 77 | * @param {string} visualizerAlgorithm Input algorithm. 78 | * @returns {boolean} True if the algorithm is any sort aside from bucket, radix and counting sort. 79 | */ 80 | export const hasLegend = (visualizerAlgorithm) => 81 | visualizerAlgorithm === 'Bubble Sort' || 82 | visualizerAlgorithm === 'Insertion Sort' || 83 | visualizerAlgorithm === 'Selection Sort' || 84 | visualizerAlgorithm === 'Quick Sort' || 85 | visualizerAlgorithm === 'Heap Sort' || 86 | visualizerAlgorithm === 'Merge Sort' || 87 | visualizerAlgorithm === 'Shell Sort'; 88 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/util/MathUtil.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates a random number within [min, max]. 3 | * 4 | * @method 5 | * @category MathUtil 6 | * @param {number} min Min number selected. 7 | * @param {number} max Max number selected. 8 | * @returns {number} Random number generated. 9 | */ 10 | export const generateValue = (min, max) => { 11 | return Math.floor(Math.random() * (max - min + 1) + min); 12 | }; 13 | 14 | /** 15 | * Rounds the number to 2 decimal places, if necessary. 16 | * 17 | * @method 18 | * @category MathUtil 19 | * @see {@link https://stackoverflow.com/questions/11832914/round-to-at-most-2-decimal-places-only-if-necessary|Stack Overflow} 20 | * @param {number} num Input number. 21 | * @returns {number} Rounded number with maximum 2 decimal places. 22 | */ 23 | export const roundToTwoDp = (num) => { 24 | return +(Math.round(num + 'e+2') + 'e-2'); 25 | }; 26 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/util/QuickSortUtil.js: -------------------------------------------------------------------------------- 1 | import { executeSwap } from './SwappingAlgoUtil'; 2 | 3 | /** 4 | * A sorting execution for Quick Sort. 5 | * 6 | * @method 7 | * @category QuickSortUtil 8 | * @param {any[]} currentAnimation The current animation to be executed. 9 | * @param {Object[]} referenceArray The array holding data for the "blocks". 10 | * @param {string} visualizerAlgorithm The current algorithm of the visualizer. 11 | * @param {function} setReferenceArray A set state method for reference array. 12 | * @returns {Object[]} The resultant array upon the swap animation. 13 | */ 14 | export const executeQuickSort = ( 15 | currentAnimation, 16 | referenceArray, 17 | visualizerAlgorithm, 18 | setReferenceArray 19 | ) => { 20 | let firstIdx = currentAnimation[1]; 21 | let secondIdx = currentAnimation[0]; 22 | let pivotIdx = currentAnimation[3]; 23 | let isSwapOccurring = currentAnimation[2]; 24 | let arrToUse = executeSwapWithPivot( 25 | firstIdx, 26 | secondIdx, 27 | pivotIdx, 28 | referenceArray, 29 | isSwapOccurring, 30 | visualizerAlgorithm 31 | ); 32 | setReferenceArray(arrToUse); 33 | return arrToUse; 34 | }; 35 | 36 | /** 37 | * A sorting execution for Quick Sort 38 | * 39 | * @method 40 | * @category QuickSortUtil 41 | * @param {number} firstIdx The first index to be swapped 42 | * @param {number} secondIdx The second index to be swapped 43 | * @param {number} pivotIdx The pivot index that is being compared to 44 | * @param {Object[]} arr The array which the index at {@code firstIdx} and {@code secondIdx} is swapped 45 | * @param {boolean} isSwapOccurring A boolean value denoting whether a swap will occur 46 | * @param {string} visualizerAlgorithm The current algorithm of the visualizer 47 | * @returns {Object[]} A new Object array which has been been swap and highlighted or just highlighted 48 | */ 49 | export const executeSwapWithPivot = ( 50 | firstIdx, 51 | secondIdx, 52 | pivotIdx, 53 | arr, 54 | isSwapOccurring, 55 | visualizerAlgorithm 56 | ) => { 57 | let newTempArr = executeSwap(firstIdx, secondIdx, arr, isSwapOccurring, visualizerAlgorithm); 58 | newTempArr[pivotIdx].isSwap = true; 59 | return newTempArr; 60 | }; 61 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/util/RadixSortUtil.js: -------------------------------------------------------------------------------- 1 | import { generateValue } from './MathUtil'; 2 | 3 | /** 4 | * Fixed stack array created for radix and bucket sort usage. 5 | * 6 | * @category RadixSortUtil 7 | * @const {Object[]} 8 | */ 9 | export const stack = [ 10 | { value: 0, array: [] }, 11 | { value: 1, array: [] }, 12 | { value: 2, array: [] }, 13 | { value: 3, array: [] }, 14 | { value: 4, array: [] }, 15 | { value: 5, array: [] }, 16 | { value: 6, array: [] }, 17 | { value: 7, array: [] }, 18 | { value: 8, array: [] }, 19 | { value: 9, array: [] }, 20 | ]; 21 | 22 | /** 23 | * Generates a random value for generation of array in radix sort. 24 | * 25 | * @method 26 | * @category RadixSortUtil 27 | * @returns {number} Random number generated. 28 | */ 29 | export const generateRandomValue = () => { 30 | const randomVal = Math.random(); 31 | if (randomVal < 0.1) { 32 | return generateValue(1, 9); 33 | } else if (randomVal < 0.2) { 34 | return generateValue(10, 99); 35 | } else if (randomVal <= 1) { 36 | return generateValue(100, 999); 37 | } 38 | }; 39 | 40 | /** 41 | * Generates the random array for radix sort. 42 | * 43 | * @method 44 | * @category RadixSortUtil 45 | * @param {number} size Size of array generated. 46 | * @returns {Object[]} Random array for radix sort. 47 | */ 48 | export const generateRadixSortArray = (size) => { 49 | let array = []; 50 | for (let i = 0; i < size; i++) { 51 | array.push({ 52 | id: i, 53 | height: generateRandomValue(), 54 | isShown: true, 55 | }); 56 | } 57 | return array; 58 | }; 59 | 60 | /** 61 | * Executes one step of the radix sort algorithm. 62 | * 63 | * @method 64 | * @category RadixSortUtil 65 | * @param {Object} currentAnimation Current animation object. 66 | * @param {Object[]} referenceArray Current state of the data array in the sorting execution. 67 | * @param {Object[]} stackArr Current state of the stack array in the sorting execution. 68 | * @param {boolean} isForward Boolean value which states if this is a forward or backward animation. 69 | * @returns {Object[]} The next state of the reference array after this sorting step. 70 | */ 71 | export const executeRadixSort = (currentAnimation, referenceArray, stackArr, isForward) => { 72 | const index = currentAnimation.id; 73 | const isDistributing = currentAnimation.isDistributing; 74 | const isDistributingAnimation = !(isForward ^ isDistributing); 75 | 76 | if (isDistributingAnimation) { 77 | referenceArray[index].isShown = false; 78 | const location = currentAnimation.location; 79 | if (isForward) { 80 | stackArr[location].array.push(currentAnimation); 81 | } else { 82 | stackArr[location].array.unshift(currentAnimation); 83 | } 84 | } else { 85 | // Putting back into array 86 | const location = currentAnimation.location; 87 | referenceArray[index] = currentAnimation; 88 | referenceArray[index].isShown = true; 89 | if (isForward) { 90 | stackArr[location].array.shift(); 91 | } else { 92 | stackArr[location].array.pop(); 93 | } 94 | } 95 | return referenceArray; 96 | }; 97 | -------------------------------------------------------------------------------- /src/visualizer/sortingvisualizer/util/SwappingAlgoUtil.js: -------------------------------------------------------------------------------- 1 | // For swapping algorithms 2 | import { swap } from '../../algorithm/sortingalgorithms/swap'; 3 | import { resetArray } from './ArrayUtil'; 4 | 5 | /** 6 | * Sets the state of the "block" or "oval" to be highlighted. 7 | * 8 | * @method 9 | * @category SwappingUtil 10 | * @param {number} firstIdx The first block" or "oval" to be highlighted. 11 | * @param {number} secondIdx The second block" or "oval" to be highlighted. 12 | * @param {Object[]} arr The array which the index at {@code firstIdx} and {@code secondIdx} is highlighted 13 | */ 14 | export const highlight = (firstIdx, secondIdx, arr) => { 15 | arr[firstIdx].isSwap = true; 16 | arr[secondIdx].isSwap = true; 17 | }; 18 | 19 | /** 20 | * Swaps the position of the two object in the array. 21 | * 22 | * @method 23 | * @category SwappingUtil 24 | * @param {number} firstIdx The first index to be swapped in the array. 25 | * @param {number} secondIdx The second index to be swapped in the array. 26 | * @param {Object[]} arr The array which the index at {@code firstIdx} and {@code secondIdx} is swapped and highlighted or just highlighted. 27 | * @param {boolean} isSwapOccurring A boolean value denoting whether a swap will occur. 28 | * @param {string} visualizerAlgorithm The current algorithm of the visualizer. 29 | * @returns {Object[]} A new Object array which has been been swap and highlighted or just highlighted. 30 | */ 31 | export const executeSwap = (firstIdx, secondIdx, arr, isSwapOccurring, visualizerAlgorithm) => { 32 | let newTempArr = resetArray(visualizerAlgorithm, arr); 33 | highlight(firstIdx, secondIdx, newTempArr); 34 | if (!isSwapOccurring) { 35 | return newTempArr; 36 | } 37 | swap(firstIdx, secondIdx, newTempArr); 38 | return newTempArr; 39 | }; 40 | 41 | /** 42 | * A generic sorting execution for Insertion, Bubble, Selection, Shell Sort 43 | * 44 | * @method 45 | * @category SwappingUtil 46 | * @param {any[]} currentAnimation The current animation to be executed. 47 | * @param {Object[]} referenceArray The array holding data for the "blocks" 48 | * @param {string} visualizerAlgorithm The current algorithm of the visualizer 49 | * @param {function} setReferenceArray A set state method for reference array. 50 | * @returns {Object[]} The resultant array upon the swap animation 51 | */ 52 | export const executeGenericSort = ( 53 | currentAnimation, 54 | referenceArray, 55 | visualizerAlgorithm, 56 | setReferenceArray 57 | ) => { 58 | let firstIdx = currentAnimation[0]; 59 | let secondIdx = currentAnimation[1]; 60 | let isSwapOccurring = currentAnimation[2]; 61 | let arrToUse = executeSwap( 62 | firstIdx, 63 | secondIdx, 64 | referenceArray, 65 | isSwapOccurring, 66 | visualizerAlgorithm 67 | ); 68 | setReferenceArray(arrToUse); 69 | return arrToUse; 70 | }; 71 | --------------------------------------------------------------------------------