-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
345 additions
and
90 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { Stage } from "@pixi/react"; | ||
import { Graphics as GraphicComponent } from "@pixi/react"; | ||
import { Color, Graphics } from "pixi.js"; | ||
import { useCallback, useContext } from "react"; | ||
import ThemeContext from "../../context/ThemeContext"; | ||
|
||
const sortingColor = { | ||
dark: { | ||
bgColor: new Color("black"), | ||
barColor: new Color("green"), | ||
selectedColor: new Color("white") | ||
}, | ||
light: { | ||
bgColor: new Color("white"), | ||
barColor: new Color("black"), | ||
selectedColor: new Color("grey") | ||
} | ||
} | ||
|
||
const SortVisualizer: React.FC<{ | ||
values: number[], | ||
currentPosition: number, | ||
width: number, | ||
height: number, | ||
base_offset?: number, | ||
gap?: number | ||
}> = ({ gap, values, width, height, currentPosition, base_offset }) => { | ||
const {theme} = useContext(ThemeContext); | ||
const currColors = theme === "dark" ? sortingColor.dark : sortingColor.light; | ||
const m = base_offset ? base_offset : 100; | ||
const draw = useCallback((g: Graphics) => { | ||
g.clear(); | ||
g.beginFill(currColors.bgColor); | ||
g.drawRect(0, 0, width, height); | ||
// render each of the values in the item | ||
let max_val = values[0]; | ||
let min_val = values[0]; | ||
for (const v of values) { | ||
max_val = Math.max(v, max_val); | ||
min_val = Math.min(v, min_val); | ||
} | ||
const w = width / values.length; | ||
|
||
const gapWrapper = gap ? gap : 0.5 * w; | ||
for (let i = 0; i < values.length; ++i) { | ||
const perc = Math.round( (values[i] - min_val) / (max_val - min_val) * (height - m)) + m; | ||
g.beginFill(currColors.barColor); | ||
if (currentPosition === i) { | ||
g.beginFill(currColors.selectedColor); | ||
} | ||
g.drawRect(i*w, height - perc, w - gapWrapper, perc); | ||
} | ||
}, [currColors.bgColor, currColors.barColor, currColors.selectedColor, width, height, values, gap, m, currentPosition]); | ||
return <Stage width={width} height={height}> | ||
<GraphicComponent draw={draw} /> | ||
</Stage> | ||
} | ||
|
||
export default SortVisualizer; |
11 changes: 11 additions & 0 deletions
11
gabau.github.io/src/components/layouts/CenteredDivLayout.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
|
||
|
||
export default function CenteredDivLayout({ children }: { | ||
children: JSX.Element | string | ||
}) { | ||
return <div className="flex flex-col items-center justify-center"> | ||
<div className="flex flex-row items-center justify-center"> | ||
{children} | ||
</div> | ||
</div> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
import { useEffect, useState } from "react"; | ||
import SortVisualizer from "../../components/games/SortVisualizer"; | ||
import CenteredDivLayout from "../../components/layouts/CenteredDivLayout"; | ||
|
||
// stores the states for partition sort | ||
class PartitionSortState { | ||
partitions: { start: number; end: number }[]; | ||
currPos: number; | ||
frontPointer: number; | ||
start: number; | ||
end: number; | ||
constructor() { | ||
this.partitions = []; | ||
this.currPos = 0; | ||
this.frontPointer = 0; | ||
this.start = 0; | ||
this.end = 0; | ||
} | ||
|
||
swap(values: number[], i: number, j: number) { | ||
if (i >= values.length || j >= values.length) return; | ||
const tmp = values[i]; | ||
values[i] = values[j]; | ||
values[j] = tmp; | ||
} | ||
|
||
getNextStep(values: number[]) { | ||
if ( | ||
this.currPos >= this.end || | ||
this.frontPointer >= this.end || | ||
this.start >= this.end | ||
) { | ||
// push the current partitions onto the stack | ||
if (this.start < this.end) { | ||
if (this.frontPointer !== this.end) { | ||
this.partitions.push({ | ||
start: this.start, | ||
end: this.frontPointer, | ||
}); | ||
} | ||
if (this.start !== this.frontPointer + 1) { | ||
this.partitions.push({ | ||
start: this.frontPointer + 1, | ||
end: this.end, | ||
}); | ||
} | ||
} | ||
|
||
// console.log(values); | ||
// return "finished" | ||
// reset the position to the partitions | ||
// Finshed sorting | ||
if (this.partitions.length === 0) { | ||
return "finished"; | ||
} | ||
this.currPos = this.partitions[0].start + 1; | ||
this.frontPointer = this.partitions[0].start; | ||
this.end = this.partitions[0].end; | ||
this.start = this.frontPointer; | ||
this.partitions = this.partitions.slice(1); | ||
} | ||
|
||
// if (values[this.frontPointer] > values[this.frontPointer + 1]) { | ||
// this.swap(values, this.frontPointer, this.frontPointer + 1); | ||
// this.frontPointer += 1; | ||
// this.currPos = Math.max(this.frontPointer + 1, this.currPos); | ||
// return values; | ||
// } | ||
if (values[this.currPos] <= values[this.frontPointer]) { | ||
this.swap(values, this.currPos, this.frontPointer + 1); | ||
this.swap(values, this.frontPointer, this.frontPointer + 1); | ||
this.frontPointer += 1; | ||
} | ||
this.currPos += 1; | ||
return values; | ||
} | ||
} | ||
|
||
export default function SortVisPage() { | ||
const [values, setValues] = useState<number[]>([4, 0]); | ||
const [partSort] = useState(new PartitionSortState()); | ||
const [startAnim, setStartAnim] = useState(false); | ||
const [currPosition, setCurrPosition] = useState(0); | ||
const [arraySize, setArraySize] = useState(40); | ||
const [animating, setAnimating] = useState(false); | ||
const [intervalTime, setIntervalTime] = useState(10); | ||
const [currTimeout, setCurrTimeout] = useState<number | null>(null); | ||
useEffect(() => { | ||
setValues(Array.from({ length: 40 }, () => Math.floor(Math.random() * 40))); | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (!startAnim) return; | ||
partSort.start = 0; | ||
partSort.end = values.length; | ||
partSort.frontPointer = 0; | ||
partSort.currPos = 1; | ||
const f = () => { | ||
if (!animating) return; | ||
const r = partSort.getNextStep(values); | ||
if (r === "finished") { | ||
setAnimating(false); | ||
return; | ||
} | ||
setCurrPosition(partSort.currPos); | ||
setCurrTimeout(setTimeout(f, intervalTime)); | ||
}; | ||
const t = setTimeout(f, intervalTime); | ||
return () => clearTimeout(t); | ||
}, [partSort, startAnim, values, animating, intervalTime]); | ||
|
||
return ( | ||
<CenteredDivLayout> | ||
<div className="flex flex-row bg-slate-500 dark:bg-slate-800"> | ||
<div className="flex flex-col items-center w-full h-full flex-auto m-8 space-y-2"> | ||
<div className="flex flex-row flex-wrap"> | ||
<button | ||
onClick={() => { | ||
if (animating) return; | ||
setAnimating(true); | ||
setStartAnim(true); | ||
setTimeout(() => setStartAnim(false), 1000); | ||
}} | ||
className="bg-gray-200 hover:bg-gray-400 dark:hover:bg-gray-900 focus:outline-none focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-700 dark:focus:ring-gray-700 dark:border-gray-700" | ||
> | ||
Start Animation | ||
</button> | ||
<button | ||
className="bg-gray-200 hover:bg-gray-400 dark:hover:bg-gray-900 focus:outline-none focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-700 dark:focus:ring-gray-700 dark:border-gray-700" | ||
onClick={() => { | ||
setValues( | ||
Array.from({ length: arraySize }, () => | ||
Math.floor(Math.random() * arraySize) | ||
) | ||
); | ||
}} | ||
> | ||
Randomise array | ||
</button> | ||
<button | ||
className="text-red-800 dark:text-red-300 bg-gray-200 hover:bg-gray-400 dark:hover:bg-gray-900 focus:outline-none focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-700 dark:focus:ring-gray-700 dark:border-gray-700" | ||
onClick={() => { | ||
if (currTimeout !== null) { | ||
clearTimeout(currTimeout); | ||
} | ||
setAnimating(false); | ||
}} | ||
> | ||
Stop Sorting | ||
</button> | ||
</div> | ||
<label>Set the number of values to sort</label> | ||
<input | ||
type="number" | ||
max="1000" | ||
value={arraySize} | ||
onChange={(e) => setArraySize(e.target.value as unknown as number)} | ||
className="rounded-lg bg-slate-200 dark:bg-slate-600 p-3 shadow my-5" | ||
/> | ||
<input | ||
type="range" | ||
max="1000" | ||
value={arraySize} | ||
onChange={(e) => setArraySize(e.target.value as unknown as number)} | ||
className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700" | ||
/> | ||
|
||
<label>Set the time in miliseconds </label> | ||
<input | ||
type="number" | ||
max="1000" | ||
value={intervalTime} | ||
onChange={(e) => setIntervalTime(e.target.value as unknown as number)} | ||
className="rounded-lg bg-slate-200 dark:bg-slate-600 p-3 shadow my-5" | ||
/> | ||
<input | ||
type="range" | ||
max="1000" | ||
value={intervalTime} | ||
onChange={(e) => setIntervalTime(e.target.value as unknown as number)} | ||
className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700" | ||
/> | ||
</div> | ||
<SortVisualizer | ||
values={values} | ||
currentPosition={currPosition} | ||
width={800} | ||
height={800} | ||
/> | ||
</div> | ||
</CenteredDivLayout> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.