From d2443a5e1877dc4abc2d0c12e0b927af99b6a02a Mon Sep 17 00:00:00 2001 From: DarkKnight4212 Date: Mon, 9 Oct 2023 14:23:03 +0530 Subject: [PATCH 1/2] Sorting visualizer done --- SortingVisualizer/Tushar2930/README.md | 4 + SortingVisualizer/Tushar2930/index.html | 86 ++++++++ SortingVisualizer/Tushar2930/src/main.js | 169 +++++++++++++++ SortingVisualizer/Tushar2930/src/sort.js | 248 +++++++++++++++++++++++ SortingVisualizer/Tushar2930/styles.css | 79 ++++++++ 5 files changed, 586 insertions(+) create mode 100644 SortingVisualizer/Tushar2930/README.md create mode 100644 SortingVisualizer/Tushar2930/index.html create mode 100644 SortingVisualizer/Tushar2930/src/main.js create mode 100644 SortingVisualizer/Tushar2930/src/sort.js create mode 100644 SortingVisualizer/Tushar2930/styles.css diff --git a/SortingVisualizer/Tushar2930/README.md b/SortingVisualizer/Tushar2930/README.md new file mode 100644 index 000000000..d590c79af --- /dev/null +++ b/SortingVisualizer/Tushar2930/README.md @@ -0,0 +1,4 @@ +# Sorting Visualizer + +This is a project that visualizes the sorting of a given array with multiple algorithm options. +I started this project because I was always fascinated that the concept of organization could be so easily captured within algorithms, as well as the fact that some core mathematical principles can make some incredibly-fast algorithms. diff --git a/SortingVisualizer/Tushar2930/index.html b/SortingVisualizer/Tushar2930/index.html new file mode 100644 index 000000000..871c232dd --- /dev/null +++ b/SortingVisualizer/Tushar2930/index.html @@ -0,0 +1,86 @@ + + + + + Sorting Visualizer + + + + + + + + + + + +
+

Sorting Algorithm Visualizer!

+
+ +
+
+

Current Array Size:

+ +
+ +
+

+ Current Delay (lower is faster): ms +

+ +
+
+ +
+ + +
+ +
+ + +
+ +
+ + Your browser does not support the canvas element :,( + +
+ + + + + diff --git a/SortingVisualizer/Tushar2930/src/main.js b/SortingVisualizer/Tushar2930/src/main.js new file mode 100644 index 000000000..5f1257be7 --- /dev/null +++ b/SortingVisualizer/Tushar2930/src/main.js @@ -0,0 +1,169 @@ + +function clearCanvas() { + ctx.beginPath(); + ctx.fillStyle = BACKGROUND_COLOR; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.closePath(); +} + +function resetArray() { + array = []; +} + +async function sleep() { + return new Promise((temp) => { + setTimeout(() => temp(2), SPEED); // timeout this function for duration SPEED + }); +} + +function swap(i, j) { + let temp = array[i]; + array[i] = array[j]; + array[j] = temp; +} + +/** + * + * @param {index in array to draw} index + * @param {The value of the index in array} value + * @param {The new color to draw the index} color + */ +function drawBar(index, value, color = DEFAULT_COLOR) { + ctx.beginPath(); + // clear the previous bar + ctx.fillStyle = BACKGROUND_COLOR; + ctx.fillRect( + Math.ceil((WIDTH / ARR_SIZE) * index), + 0, + Math.floor(WIDTH / ARR_SIZE), + HEIGHT + ); + + ctx.fillStyle = color; + ctx.fillRect( + Math.ceil((WIDTH / ARR_SIZE) * index), + HEIGHT, + Math.floor(WIDTH / ARR_SIZE), + Math.floor(-HEIGHT * (value / MAX_ARR_VAL)) + ); + + ctx.closePath(); +} + +function drawArray() { + clearCanvas(); + + for (let i = 0; i < array.length; i++) { + let val = array[i]; + drawBar(i, val, DEFAULT_COLOR); + } +} + +function randomizeArray() { + if (running) { + running = false; + } + clearCanvas(); + resetArray(); + + for (let i = 0; i < ARR_SIZE; i++) { + array.push(Math.floor(Math.random() * MAX_ARR_VAL)); + } + + drawArray(); +} + +function runSort() { + + if (!running) { + running = true; + + let sortingAlgorithm; + const algoName = sortingAlgo.value; + switch (algoName) { + case "bubble": + sortingAlgorithm = bubbleSort; + break; + case "selection": + sortingAlgorithm = selectionSort; + break; + case "insertion": + sortingAlgorithm = insertionSort; + break; + case "merge": + sortingAlgorithm = mergeSort; + break; + case "quick": // TODO + sortingAlgorithm = quickSort; + break; + case "heap": + sortingAlgorithm = heapSort; + break; + default: + console.log("Invalid input"); + } + + sortingAlgorithm(array).then((sorted) => { + if (running) { + array = sorted; + drawArray(); + running = false; + } + }); + + } else { + console.log("Cannot restart: sorting is actively running!"); + } +} + +function speedInput() { + SPEED = speedSlider.value; + speedOutput.innerHTML = SPEED; +} +function sizeInput() { + ARR_SIZE = sizeSlider.value; + sizeOutput.innerHTML = ARR_SIZE; +} + +var canvas = document.getElementById("myCanvas"); +var ctx = canvas.getContext("2d"); +const WIDTH = canvas.width, + HEIGHT = canvas.height; + +// button, slider setup +randomizeBtn = document.getElementById("randomizeBtn"); +sortingBtn = document.getElementById("sortButton"); + +// array size +var sizeSlider = document.getElementById("sizeSlider"); +var sizeOutput = document.getElementById("sizeValue"); +var ARR_SIZE; +// getting latency +var speedSlider = document.getElementById("speedSlider"); +var speedOutput = document.getElementById("speedValue"); // get the output from the slider span +var SPEED; +// getting sorting algorithm +var sortingAlgo = document.getElementById("sortingFunction"); + +// everytime we mess with slider, it updates values inside +speedSlider.oninput = speedInput; +sizeSlider.oninput = () => { + sizeInput(); + + randomizeArray(); +}; + + +// initializing stuff I use everywhere +let array = []; +const MAX_ARR_VAL = 100; +let running = false; + +// COLORS +const DEFAULT_COLOR = "black"; +const BACKGROUND_COLOR = "white"; + +// first call +speedInput(); +sizeInput(); +randomizeArray(); // randomize and draw the array diff --git a/SortingVisualizer/Tushar2930/src/sort.js b/SortingVisualizer/Tushar2930/src/sort.js new file mode 100644 index 000000000..f513360a7 --- /dev/null +++ b/SortingVisualizer/Tushar2930/src/sort.js @@ -0,0 +1,248 @@ +const isSorted = (array) => { + for (let i = 1; i < array.length; i++) { + if (array[i - 1] > array[i]) { + return false; + } + } + return true; +}; + +const isMaxHeap = (array) => { + for (let i = 1; i < array.length; i++) { + if (array[Math.floor((i - 1) / 2)] < array[i]) { + return false; + } + } + return true; +}; + +async function bubbleSort(arr) { + let compare = true; + while (compare === true && running) { + compare = false; + for (let i = 0; i < arr.length - 1 && running; i++) { + // swap + if (arr[i] > arr[i + 1]) { + compare = true; + // swap + swap(i, i + 1); + drawBar(i, array[i], "red"); + drawBar(i + 1, array[i + 1], "red"); + await sleep(); + } + drawArray(); + } + } + + return arr; +} + +async function selectionSort(arr) { + // algorithm works by selecting the minimum element in i...n and swapping + for (let i = 0; i < arr.length && running; i++) { + let minDex = i; + for (let j = i + 1; j < arr.length && running; j++) { + drawArray(); + drawBar(minDex, array[minDex], "red"); + if (arr[minDex] > arr[j]) { + // update smallest element + minDex = j; + + drawBar(minDex, array[minDex], "red"); + // await sleep(); + } + await sleep(); + } + + // swap i with minDex + drawArray(); + drawBar(i, array[i], "red"); + drawBar(minDex, array[minDex], "red"); + swap(i, minDex); + await sleep(); + drawArray(); + } + + return arr; +} + +async function insertionSort(arr) { + for (let i = 1; i < arr.length && running; i++) { + // start at first index + let j = i; + while (running && + j > 0 && arr[j - 1] > arr[j] + ) { + drawArray(); + drawBar(j - 1, arr[j - 1], "red"); + drawBar(j, arr[j], "red"); + swap(j - 1, j); + await sleep(); + + j--; + } + } + + return arr; +} + +/** + * + * @param {Array to construct heap from, then sort} arr + */ +async function heapSort(arr) { + const getLeftIndex = (index) => { + return index * 2 + 1 < arr.length ? index * 2 + 1 : -1; + }; + + const getRightIndex = (index) => { + return index * 2 + 2 < arr.length ? index * 2 + 2 : -1; + }; + + const getParentIndex = (index) => { + return index != 0 ? Math.floor((index - 1) / 2) : -1; + }; + + // construct maxheap: swim up for each index + for (let index = 1; index < arr.length && running; index++) { + let parentIndex = getParentIndex(index); + // swim up until we find place in Max-Heap + while (running && + parentIndex != -1 && arr[parentIndex] < arr[index] + ) { + // do the swap and update the value + // console.log(parentIndex, index); + + drawArray(); + drawBar(index, arr[index], "red"); + drawBar(parentIndex, arr[parentIndex], "red"); + + swap(parentIndex, index); + await sleep(); + drawArray(); + + // info for next iteration + index = parentIndex; + parentIndex = getParentIndex(index); + } + } + + // removeMax and re-establish heap + for (let i = arr.length - 1; running && i > 0; i--) { + // swap maxNode with end of the heap + drawArray(); + drawBar(0, arr[0], "red"); + drawBar(i, arr[i], "red"); + + swap(0, i); + await sleep(); + drawArray(); + + // utility functions to get left and right children + const getLeftChild = (index) => { + return index * 2 + 1 < i ? arr[index * 2 + 1] : -1; + }; + const getRightChild = (index) => { + return index * 2 + 2 < i ? arr[index * 2 + 2] : -1; + }; + + // sink down the node until in the correct position + let index = 0; + while (running && + getLeftIndex(index) < i && // heap has at least 1 child node (left firs always) + (arr[index] < getLeftChild(index, i) || + arr[index] < getRightChild(index, i)) + ) { + // swap index with larger of two children + let newIndex = + getLeftChild(index, i) > getRightChild(index, i) + ? getLeftIndex(index) + : getRightIndex(index); + + drawArray(); + drawBar(index, arr[index], "red"); + drawBar(newIndex, arr[newIndex], "red"); + + swap(index, newIndex); + await sleep(); + drawArray(); + + index = newIndex; + } + } + + return arr; +} + +async function mergeSort(arr) { + array = arr; + drawArray(arr); + let sorted_arr = await recursiveMergeSort(arr, 0); + return sorted_arr; +} + +/** + * + * @param {* Our array to sort *} arr + * @param {* Our shift from the original array (helps with sorting later on)} shift + * @returns + */ +async function recursiveMergeSort(arr, shift) { + if (arr.length <= 1) { + return arr; + } + + const half = Math.ceil(arr.length / 2); + let [left, right] = await Promise.all([ + recursiveMergeSort(arr.slice(0, half), 0), + recursiveMergeSort(arr.slice(half), half), + ]); + + let [leftIndex, rightIndex] = [0, 0]; + + // ALGO: construct new array from min btwn left and right at each index + for (let i = 0; i < arr.length && running; i++) { + // update the recursive array representation, and get the index we'll swap + if (leftIndex == left.length || right[rightIndex] < left[leftIndex]) { + // index will be left + rightIndex of overall array + arr[i] = right[rightIndex]; + rightIndex++; + } else if ( + rightIndex == right.length || + left[leftIndex] <= right[rightIndex] + ) { + arr[i] = left[leftIndex]; + leftIndex++; + } + + // internal array indices + const shiftI = shift + i; + + // we have to directly overwrite the array in order for it to show + await sleep(); + array[shiftI] = arr[i]; + drawBar(shiftI, arr[i], "red"); + await sleep(); + drawArray(); + } + + return arr; +} + +function test() { + rand_arr = []; + let s = 10; + let maxVal = 100; + // build random array + for (let i = 0; i < s; i++) { + rand_arr.push(Math.floor(Math.random() * maxVal)); + } + + // test sorting algo + mergeSort(rand_arr).then((result) => { + console.log(result); + console.log(isSorted(result)); + }); +} + +// test(); diff --git a/SortingVisualizer/Tushar2930/styles.css b/SortingVisualizer/Tushar2930/styles.css new file mode 100644 index 000000000..390c5c6ff --- /dev/null +++ b/SortingVisualizer/Tushar2930/styles.css @@ -0,0 +1,79 @@ +html, body { + margin: 5px; + padding-bottom: 2em; + background: #7cc6fe; + font-family: sans-serif; +} + +.intro { + text-align: center; + margin-left: 10vw; + margin-right: 10vw; + padding-top: 5vh; +} +.intro h1 { + font-size: 2.75em; + color: azure; +} +.intro h3 { + color: azure; +} + +.slider-container { + display: flex; + flex-wrap: wrap; + justify-content: center; +} +.slider { + text-align: center; + padding-right: 2em; + padding-left: 2em; +} +.slider h3 { + color: azure; +} + + +.algo-selection-container { + padding: 10px; + display: flex; + flex-wrap: wrap; + justify-content: center; +} + +.algo-selection-container label { + font-size: large; + color: azure; +} + +.button { + background-color: #4CAF50; + border: none; + color: white; + padding: 15px 32px; + text-align: center; + + display: inline-block; + + font-size: 16px; + margin: 1em; + transition: all 200ms ease; +} +.button:hover { + transform: scale(1.15); + background: #e2bd45; + border-color: rgb(252, 0, 0); + border-width: 0.1rem; +} +.sorting-button-container { + padding: 10px; + display: flex; + align-items: center; + justify-content: center; +} + + + +.canvas-container { + text-align: center; +} \ No newline at end of file From b279010e6339afaff9f094e14924be565733db5c Mon Sep 17 00:00:00 2001 From: Tushar2930 <110845672+Tushar2930@users.noreply.github.com> Date: Mon, 9 Oct 2023 18:00:40 +0530 Subject: [PATCH 2/2] Screenshots uploaded --- SortingVisualizer/Tushar2930/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SortingVisualizer/Tushar2930/README.md b/SortingVisualizer/Tushar2930/README.md index d590c79af..0e15addc1 100644 --- a/SortingVisualizer/Tushar2930/README.md +++ b/SortingVisualizer/Tushar2930/README.md @@ -2,3 +2,5 @@ This is a project that visualizes the sorting of a given array with multiple algorithm options. I started this project because I was always fascinated that the concept of organization could be so easily captured within algorithms, as well as the fact that some core mathematical principles can make some incredibly-fast algorithms. +![111](https://github.com/Tushar2930/javascript-mini-projects/assets/110845672/23f8cda7-aa40-4d07-9ed9-7fbd553181ab) +![222](https://github.com/Tushar2930/javascript-mini-projects/assets/110845672/d93fe7cb-83f6-4ea9-bd8c-3e7d69e6a307)