From daf09a1413e2f4ddab3394fb087bafc228d57145 Mon Sep 17 00:00:00 2001
From: Daniel <you@example.com>
Date: Wed, 18 Sep 2024 22:02:48 +0200
Subject: [PATCH] implemented MergeSort

---
 Dockerfile                |   3 +-
 docker-compose.yml        |   5 +-
 src/MergeSort.js          | 122 ++++++++++++++++++++++++++++++++++++++
 src/SortingVisualizer.css |  27 +++++++--
 src/SortingVisualizer.jsx |  45 +++++++++++---
 5 files changed, 187 insertions(+), 15 deletions(-)
 create mode 100644 src/MergeSort.js

diff --git a/Dockerfile b/Dockerfile
index c97b2e1..2e7e291 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -18,6 +18,7 @@ COPY vite.config.js .
 
 # port 5173
 EXPOSE 5173
+EXPOSE 9229
 
 #Start
-CMD ["npm", "run", "dev", "--", "--host"]
+CMD ["npm", "run", "dev", "--", "--host", "$DEBUG_FLAG"]
diff --git a/docker-compose.yml b/docker-compose.yml
index ba7c89f..fe4480d 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -4,13 +4,16 @@ services:
     container_name: Sorting-Visualizer 
     ports:
       - 127.0.0.1:5173:5173
+      - 127.0.0.1:9229:9229
+
     volumes:
       - ./src/:/app/sorting-visualizer/src/
       - ./package-lock.json:/app/sorting-visualizer/package-lock.json
       - ./package.json:/app/sorting-visualizer/package.json
     networks:
       - my-network
-
+    environment:
+      DEBUG_FLAG: "--inspect=0.0.0.0:9229"
 networks:
   my-network:
     driver: bridge
diff --git a/src/MergeSort.js b/src/MergeSort.js
new file mode 100644
index 0000000..2c935a1
--- /dev/null
+++ b/src/MergeSort.js
@@ -0,0 +1,122 @@
+async function MergeSort(EingangsArray, startIdx, endIdx, arrayCopy, updateBars, setColor, sortSpeed) {
+    if (startIdx >= endIdx) return;
+
+    // Split array
+    const cuttingEdge = Math.floor((startIdx + endIdx) / 2);
+
+    // Recursively sort both halves
+    await MergeSort(EingangsArray, startIdx, cuttingEdge, arrayCopy, updateBars, setColor, sortSpeed);
+    await MergeSort(EingangsArray, cuttingEdge + 1, endIdx, arrayCopy, updateBars, setColor, sortSpeed);
+
+    // Merge halves back togeteher
+    await merge(EingangsArray, startIdx, cuttingEdge, endIdx, arrayCopy, updateBars, setColor, sortSpeed);
+}
+
+async function merge(EingangsArray, startIdx, middleIdx, endIdx, arrayCopy, updateBars, setColor, sortSpeed) {
+    let i = startIdx;
+    let j = middleIdx + 1;
+    let k = startIdx;
+    const bars = document.querySelectorAll('.bar'); // get all bars
+    const sortSpeedSwitch = Number(sortSpeed);
+
+
+    // index exist?
+    const isValidIndex = (index) => index >= 0 && index < bars.length;
+
+    // Merge halves back togeteher
+    while (i <= middleIdx && j <= endIdx) {
+        if (isValidIndex(i) && isValidIndex(j)) {
+            // Change color of compared bars
+            bars[i].style.backgroundColor = 'red';
+            bars[j].style.backgroundColor = 'red';
+        }
+
+        switch (sortSpeedSwitch) {
+            case 0:
+                break; // No delay
+            case 40:
+                await new Promise(resolve => setTimeout(resolve, 90));
+                break;
+            case 100:
+                await new Promise(resolve => setTimeout(resolve, 200));
+                break;
+        }
+        if (EingangsArray[i] <= EingangsArray[j]) {
+            arrayCopy[k] = EingangsArray[i];
+            i++;
+        } else {
+            arrayCopy[k] = EingangsArray[j];
+            j++;
+        }
+
+        // Update Array
+        await updateArrayState(EingangsArray, arrayCopy, startIdx, endIdx, updateBars, sortSpeed);
+        if (isValidIndex(i - 1)) bars[i - 1].style.backgroundColor = ''; // default colr
+        if (isValidIndex(j - 1)) bars[j - 1].style.backgroundColor = '';
+
+        k++;
+    }
+
+    // Copy  from the LEFT half
+    while (i <= middleIdx) {
+        switch (sortSpeedSwitch) {
+            case 0:
+                break; // No delay
+            case 40:
+                await new Promise(resolve => setTimeout(resolve, 90));
+                break;
+            case 100:
+                await new Promise(resolve => setTimeout(resolve, 200));
+                break;
+        }
+
+        arrayCopy[k] = EingangsArray[i];
+        await updateArrayState(EingangsArray, arrayCopy, startIdx, endIdx, updateBars, sortSpeed);
+        if (isValidIndex(i)) bars[i].style.backgroundColor = '';
+
+        i++;
+        k++;
+    }
+
+    // Copy  from the RIGHT half
+    while (j <= endIdx) {
+        switch (sortSpeedSwitch) {
+            case 0:
+                break; // No delay
+            case 40:
+                await new Promise(resolve => setTimeout(resolve, 90));
+                break;
+            case 100:
+                await new Promise(resolve => setTimeout(resolve, 200));
+                break;
+        }
+
+        arrayCopy[k] = EingangsArray[j];
+        await updateArrayState(EingangsArray, arrayCopy, startIdx, endIdx, updateBars, sortSpeed);
+        if (isValidIndex(j)) bars[j].style.backgroundColor = '';
+
+        j++;
+        k++;
+    }
+
+    // Copy merged values back
+    for (let i = startIdx; i <= endIdx; i++) {
+        EingangsArray[i] = arrayCopy[i];
+    }
+
+    // adding to class 'finished'
+    if (endIdx - startIdx + 1 === EingangsArray.length) {
+        setColor(0);
+    }
+}
+
+async function updateArrayState(EingangsArray, arrayCopy, startIdx, endIdx, updateBars, sortSpeed) {
+    updateBars([...arrayCopy]);
+    await new Promise(resolve => setTimeout(resolve, sortSpeed));
+}
+
+export default async function startMergeSort(EingangsArray, updateBars, setFinish, sortSpeed) {
+    const arrayCopy = [...EingangsArray];
+
+    await MergeSort(EingangsArray, 0, EingangsArray.length - 1, arrayCopy, updateBars, setFinish, sortSpeed);
+}
diff --git a/src/SortingVisualizer.css b/src/SortingVisualizer.css
index 991362a..91b9266 100644
--- a/src/SortingVisualizer.css
+++ b/src/SortingVisualizer.css
@@ -15,6 +15,9 @@ body {
     height: 100px;
     flex: 1 1 20px;
     min-width: 2px;
+    margin: 0px;
+    transform-origin: bottom;
+
 }
 
 .sorted {
@@ -75,13 +78,20 @@ button:active {
 }
 
 .DivArray {
-    transform: scaleY(-1);
     display: flex;
+    position: absolute;
+    position: fixed;
     flex-wrap: nowrap;
     justify-content: center;
     gap: 2px;
     width: 90%;
-    margin-top: 5px;
+    margin-top: 60px;
+    align-items: flex-end;
+    overflow: hidden;
+    height: 400px;
+/
+
+
 }
 
 #dropdown-menu {
@@ -91,7 +101,6 @@ button:active {
     margin-top: 3px;
 }
 
-
 #dropdown-item {
     color: white;
     font-size: 16px;
@@ -115,7 +124,6 @@ button:active {
     height: 100%;
     display: flex;
     place-items: center;
-    margin-inline: 10px;
     justify-content: center;
     width: 195px;
     transition: none;
@@ -135,6 +143,17 @@ button:active {
     color: white;
 }
 
+.Divider {
+    background: gray;
+    height: 70%;
+    margin-left: 8px;
+    margin-right: 3px;
+    width: 2px;
+}
+
+#dividerLeft {
+    margin-right: 8px;
+}
 
 @keyframes ScaleAnimation {
     0% {
diff --git a/src/SortingVisualizer.jsx b/src/SortingVisualizer.jsx
index 4521e25..6fe070a 100644
--- a/src/SortingVisualizer.jsx
+++ b/src/SortingVisualizer.jsx
@@ -1,6 +1,7 @@
 import {useState, useEffect} from 'react';
 import './SortingVisualizer.css'
 import BubbleSort from "./BubbleSort";
+import startMergeSort from "./MergeSort.js";
 import RangeSlider from 'react-bootstrap-range-slider';
 import 'react-bootstrap-range-slider/dist/react-bootstrap-range-slider.css';
 import {Dropdown} from 'react-bootstrap';
@@ -13,9 +14,10 @@ function SortingVisualizer() {
     const [BarNumber, setBarNumber] = useState(() => monitorSize > 100 ? 100 : monitorSize); // max of 100 bars
     const [bars, setbars] = useState(() => generateArray(BarNumber));
     const [sorting, setSorting] = useState(false);
-    const [alreadySorted, setAlreadySorted] = useState();
+    const [alreadySorted, setColor] = useState();
     const [isSorted, setIsSorted] = useState(false);
     const [sortSpeed, setSortSpeed] = useState('40');
+    const [Algo, setAlgo] = useState('BubbleSort');
 
     const SliderWithInputFormControl = () => {
         const [sliderValue_intern, setSliderValue_intern] = useState(BarNumber);
@@ -41,18 +43,22 @@ function SortingVisualizer() {
     }
 
     function generateArray(numberBars) {
-        return Array.from({length: numberBars}, () => getRandomArbitrary(50, 300));
+        return Array.from({length: numberBars}, () => getRandomArbitrary(20, 400));
     }
 
     async function handleSorting() {
         if (sorting) return;
         setSorting(true);
-        await BubbleSort(bars, setbars, setAlreadySorted, sortSpeed);
+        if (Algo == 'BubbleSort') {
+            await BubbleSort(bars, setbars, setColor, sortSpeed);
+        } else if (Algo == 'MergeSort') {
+            await startMergeSort(bars, setbars, setColor, sortSpeed);
+        }
         setSorting(false);
     }
 
     function resetBars() {
-        setAlreadySorted(1000);
+        setColor(1000);
         setbars(generateArray(BarNumber));
         let ColoredBars = document.getElementsByClassName('sorted');
         document.getElementById('startButton').innerText = 'Sort!';
@@ -73,7 +79,7 @@ function SortingVisualizer() {
 
     function handleButton() {
         if (!sorting && !isSorted) {
-            setAlreadySorted(1000);
+            setColor(1000);
             handleSorting();
         } else if (isSorted) {
             resetBars();
@@ -106,14 +112,15 @@ function SortingVisualizer() {
                            value={BarNumber} style={{
                         width: '42px',
                         fontfamily: 'Arial sans-serif',
-                        fontSize:'16px',
-                        margin: '10px',
+                        fontSize: '16px',
+                        marginLeft: '10px',
+                        marginRight: '5px',
                         borderRadius: '5px',
                         border: 'none',
                         textAlign: 'center'
                     }}/>
-                    <div style={{background: 'gray', height: '70%', marginLeft: '10px', width: '2px'}}></div>
-                    <Dropdown id="dropdown">
+                    <div id="dividerLeft" className="Divider"></div>
+                    <Dropdown id="dropdown" className="dropdown-wide">
                         <Dropdown.Toggle
                             id="dropdown"
                             disabled={sorting}
@@ -138,6 +145,26 @@ function SortingVisualizer() {
                             </Dropdown.Item>
                         </Dropdown.Menu>
                     </Dropdown>
+                    <div className="Divider"></div>
+                    <Dropdown id="dropdown">
+                        <Dropdown.Toggle
+                            id="dropdown"
+                            disabled={sorting}
+                        >
+                            Algorithm: {
+                            [Algo]
+                        }
+                        </Dropdown.Toggle>
+                        <Dropdown.Menu id="dropdown-menu">
+                            <Dropdown.Item id="dropdown-item" onClick={() => setAlgo('BubbleSort')}>
+                                BubbleSort
+                            </Dropdown.Item>
+                            <Dropdown.Item id="dropdown-item" onClick={() => setAlgo('MergeSort')}>
+                                MergeSort
+                            </Dropdown.Item>
+                        </Dropdown.Menu>
+                    </Dropdown>
+
                     <button id='startButton' className="Button" disabled={sorting}
                             style={{background: `${sorting ? 'red' : ''}`}} onClick={() => {
                         handleButton()
-- 
GitLab