├── .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 | [](https://circleci.com/gh/December-software-project/sort-algo/tree/main)
2 | [](https://github.com/prettier/prettier)
3 | [](https://app.netlify.com/sites/algosort/deploys)
4 | [](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 |
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 |
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 |
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 = () => ;
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 |
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 |
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 |
34 |
35 |
36 |
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 |
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 |
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 |
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 |
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 |
--------------------------------------------------------------------------------