Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions SortVision/src/algorithms/bubbleSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ export const bubbleSort: SortingAlgorithm = async (
setCurrentBar,
shouldStopRef,
sortPausedRef,
audio
audio,
delayRef
) => {
const delayRefs: SortStepDelayRefs = { shouldStopRef, sortPausedRef };
const delayRefs: SortStepDelayRefs = {
shouldStopRef,
sortPausedRef,
delayRef,
};
let swaps = 0;
let comparisons = 0;
const arr = [...array];
Expand Down
9 changes: 7 additions & 2 deletions SortVision/src/algorithms/bucketSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,14 @@ export const bucketSort: SortingAlgorithm = async (
setCurrentBar,
shouldStopRef,
sortPausedRef,
audio
audio,
delayRef
) => {
const delayRefs: SortStepDelayRefs = { shouldStopRef, sortPausedRef };
const delayRefs: SortStepDelayRefs = {
shouldStopRef,
sortPausedRef,
delayRef,
};
const metrics: SortStepMetrics = { swaps: 0, comparisons: 0 };

if (array.length === 0) {
Expand Down
9 changes: 7 additions & 2 deletions SortVision/src/algorithms/heapSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,14 @@ export const heapSort: SortingAlgorithm = async (
setCurrentBar,
shouldStopRef,
sortPausedRef,
audio
audio,
delayRef
) => {
const delayRefs: SortStepDelayRefs = { shouldStopRef, sortPausedRef };
const delayRefs: SortStepDelayRefs = {
shouldStopRef,
sortPausedRef,
delayRef,
};
const metrics: SortStepMetrics = { swaps: 0, comparisons: 0 };
const arr = [...array];
const n = arr.length;
Expand Down
9 changes: 7 additions & 2 deletions SortVision/src/algorithms/insertionSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ export const insertionSort: SortingAlgorithm = async (
setCurrentBar,
shouldStopRef,
sortPausedRef,
audio
audio,
delayRef
) => {
const delayRefs: SortStepDelayRefs = { shouldStopRef, sortPausedRef };
const delayRefs: SortStepDelayRefs = {
shouldStopRef,
sortPausedRef,
delayRef,
};
let swaps = 0;
let comparisons = 0;
const arr = [...array];
Expand Down
9 changes: 7 additions & 2 deletions SortVision/src/algorithms/mergeSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,14 @@ export const mergeSort: SortingAlgorithm = async (
setCurrentBar,
shouldStopRef,
sortPausedRef,
audio
audio,
delayRef
) => {
const delayRefs: SortStepDelayRefs = { shouldStopRef, sortPausedRef };
const delayRefs: SortStepDelayRefs = {
shouldStopRef,
sortPausedRef,
delayRef,
};
const metrics: SortStepMetrics = { swaps: 0, comparisons: 0 };
const arr = [...array];

Expand Down
9 changes: 7 additions & 2 deletions SortVision/src/algorithms/quickSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,14 @@ export const quickSort: SortingAlgorithm = async (
setCurrentBar,
shouldStopRef,
sortPausedRef,
audio
audio,
delayRef
) => {
const delayRefs: SortStepDelayRefs = { shouldStopRef, sortPausedRef };
const delayRefs: SortStepDelayRefs = {
shouldStopRef,
sortPausedRef,
delayRef,
};
const metrics: SortStepMetrics = { swaps: 0, comparisons: 0 };
const arr = [...array];

Expand Down
9 changes: 7 additions & 2 deletions SortVision/src/algorithms/radixSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,14 @@ export const radixSort: SortingAlgorithm = async (
setCurrentBar,
shouldStopRef,
sortPausedRef,
audio
audio,
delayRef
) => {
const delayRefs: SortStepDelayRefs = { shouldStopRef, sortPausedRef };
const delayRefs: SortStepDelayRefs = {
shouldStopRef,
sortPausedRef,
delayRef,
};
const metrics: SortStepMetrics = { swaps: 0, comparisons: 0 };

if (array.length === 0) {
Expand Down
9 changes: 7 additions & 2 deletions SortVision/src/algorithms/selectionSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ export const selectionSort: SortingAlgorithm = async (
setCurrentBar,
shouldStopRef,
sortPausedRef,
audio
audio,
delayRef
) => {
const delayRefs: SortStepDelayRefs = { shouldStopRef, sortPausedRef };
const delayRefs: SortStepDelayRefs = {
shouldStopRef,
sortPausedRef,
delayRef,
};
let swaps = 0;
let comparisons = 0;
const arr = [...array];
Expand Down
27 changes: 27 additions & 0 deletions SortVision/src/algorithms/sleep.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { delayStep } from '@/algorithms/sleep';
import type { SortStepDelayRefs } from '@/algorithms/types';

const createDelayRefs = (delay: number): SortStepDelayRefs => ({
shouldStopRef: { current: false },
sortPausedRef: { current: false },
delayRef: { current: delay },
});

describe('delayStep', () => {
afterEach(() => {
vi.useRealTimers();
});

it('uses updated delayRef values while waiting', async () => {
vi.useFakeTimers();
const refs = createDelayRefs(1000);
const wait = delayStep(1000, refs);

await vi.advanceTimersByTimeAsync(40);
refs.delayRef!.current = 10;
await vi.advanceTimersByTimeAsync(32);

await expect(wait).resolves.toBeUndefined();
});
});
8 changes: 5 additions & 3 deletions SortVision/src/algorithms/sleep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const POLL_MS = 32;
* Honors {@link SortStepDelayRefs.shouldStopRef} (abort) and {@link SortStepDelayRefs.sortPausedRef} (pause).
*/
export function delayStep(ms: number, refs: SortStepDelayRefs): Promise<void> {
const deadline = performance.now() + ms;
const start = performance.now();
return new Promise(resolve => {
const step = () => {
if (refs.shouldStopRef.current) {
Expand All @@ -19,11 +19,13 @@ export function delayStep(ms: number, refs: SortStepDelayRefs): Promise<void> {
return;
}
const now = performance.now();
if (now >= deadline) {
const currentDelay = refs.delayRef?.current ?? ms;
const elapsed = now - start;
if (elapsed >= currentDelay) {
resolve();
return;
}
setTimeout(step, Math.min(POLL_MS, deadline - now));
setTimeout(step, Math.min(POLL_MS, currentDelay - elapsed));
};
step();
});
Expand Down
5 changes: 4 additions & 1 deletion SortVision/src/algorithms/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ export type ShouldStopRef = MutableRefObject<boolean>;

/** When true, {@link delayStep} blocks until cleared (pause without aborting). */
export type SortPausedRef = MutableRefObject<boolean>;
export type SortDelayRef = MutableRefObject<number>;

export type SortStepDelayRefs = {
shouldStopRef: ShouldStopRef;
sortPausedRef: SortPausedRef;
delayRef?: SortDelayRef;
};

/**
Expand All @@ -50,5 +52,6 @@ export type SortingAlgorithm = (
setCurrentBar: Dispatch<SetStateAction<CurrentBarState>>,
shouldStopRef: ShouldStopRef,
sortPausedRef: SortPausedRef,
audio: SortingAlgorithmAudio
audio: SortingAlgorithmAudio,
delayRef?: SortDelayRef
) => Promise<SortStepMetrics>;
32 changes: 22 additions & 10 deletions SortVision/src/components/panels/ConfigPanel/ConfigPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { ArrayVisualization } from '../../sortingVisualizer/components/ArrayVisualization';
import StepExplanationPanel from '../../sortingVisualizer/components/StepExplanationPanel';
import {
AlgorithmSelector,
ComplexityInfo,
Expand Down Expand Up @@ -73,16 +74,27 @@ const ConfigPanel = ({

{/* Add the array visualization */}
{array && (
<ArrayVisualization
algorithm={algorithm}
array={array}
currentBar={currentBar}
isSorting={isSorting}
isPaused={isPaused}
currentTestingAlgo={currentTestingAlgo}
isStopped={isStopped}
height="h-100"
/>
<div className="grid grid-cols-1 xl:grid-cols-[minmax(0,1fr)_18rem] gap-4 items-stretch">
<ArrayVisualization
algorithm={algorithm}
array={array}
currentBar={currentBar}
isSorting={isSorting}
isPaused={isPaused}
currentTestingAlgo={currentTestingAlgo}
isStopped={isStopped}
height="h-100"
/>
<StepExplanationPanel
algorithm={algorithm}
array={array}
currentBar={currentBar}
isSorting={isSorting}
isPaused={isPaused}
currentTestingAlgo={currentTestingAlgo}
isStopped={isStopped}
/>
</div>
)}
</div>
);
Expand Down
16 changes: 5 additions & 11 deletions SortVision/src/components/panels/config/SpeedControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ import {
normalizedSpeedRatio,
} from './visualizerControlConstants';

const SpeedControl = ({
speed,
setSpeed,
isSorting,
audio,
}: SpeedControlProps) => {
const SpeedControl = ({ speed, setSpeed, audio }: SpeedControlProps) => {
const { t } = useLanguage();

return (
Expand Down Expand Up @@ -102,7 +97,6 @@ const SpeedControl = ({
max={SPEED_MS_MAX}
step={SPEED_MS_SLIDER_STEP}
onValueChange={value => setSpeed(value[0]!)}
disabled={isSorting}
className="relative z-10"
name="animation speed"
aria-label="Animation Speed Slider"
Expand Down Expand Up @@ -154,13 +148,13 @@ const SpeedControl = ({
<button
type="button"
onClick={() => {
if (!isSorting && speed < SPEED_MS_MAX) {
if (speed < SPEED_MS_MAX) {
const newSpeed = Math.min(SPEED_MS_MAX, speed * 2);
setSpeed(newSpeed);
audio.playAccessSound();
}
}}
disabled={isSorting || speed >= SPEED_MS_MAX}
disabled={speed >= SPEED_MS_MAX}
className="group/btn relative size-8 rounded-md bg-slate-800 border border-slate-700 hover:bg-slate-700 transition-all duration-300 overflow-hidden"
aria-label="Double animation delay"
>
Expand All @@ -173,13 +167,13 @@ const SpeedControl = ({
<button
type="button"
onClick={() => {
if (!isSorting && speed > SPEED_MS_MIN) {
if (speed > SPEED_MS_MIN) {
const newSpeed = Math.max(SPEED_MS_MIN, speed / 2);
setSpeed(newSpeed);
audio.playAccessSound();
}
}}
disabled={isSorting || speed <= SPEED_MS_MIN}
disabled={speed <= SPEED_MS_MIN}
className="group/btn relative size-8 rounded-md bg-slate-800 border border-slate-700 hover:bg-slate-700 transition-all duration-300 overflow-hidden"
aria-label="Halve animation delay"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const runAlgorithm = async ({
inputArray,
setArray,
speed,
speedRef,
setCurrentBar,
shouldStopRef,
sortPausedRef,
Expand All @@ -37,6 +38,7 @@ const runAlgorithm = async ({
inputArray: number[];
setArray: Dispatch<SetStateAction<number[]>>;
speed: number;
speedRef: MutableRefObject<number>;
setCurrentBar: Dispatch<SetStateAction<CurrentBarState>>;
shouldStopRef: MutableRefObject<boolean>;
sortPausedRef: MutableRefObject<boolean>;
Expand All @@ -54,7 +56,8 @@ const runAlgorithm = async ({
setCurrentBar,
shouldStopRef,
sortPausedRef,
audio
audio,
speedRef
);
};

Expand Down Expand Up @@ -89,6 +92,7 @@ const useSortingControls = () => {
array: number[],
setArray: Dispatch<SetStateAction<number[]>>,
speed: number,
speedRef: MutableRefObject<number>,
setCurrentBar: Dispatch<SetStateAction<CurrentBarState>>,
shouldStopRef: MutableRefObject<boolean>,
sortPausedRef: MutableRefObject<boolean>,
Expand Down Expand Up @@ -130,6 +134,7 @@ const useSortingControls = () => {
inputArray: array,
setArray,
speed,
speedRef,
setCurrentBar,
shouldStopRef,
sortPausedRef,
Expand Down Expand Up @@ -170,6 +175,7 @@ const useSortingControls = () => {
array: number[],
setArray: Dispatch<SetStateAction<number[]>>,
speed: number,
speedRef: MutableRefObject<number>,
setCurrentBar: Dispatch<SetStateAction<CurrentBarState>>,
shouldStopRef: MutableRefObject<boolean>,
userCancelRequestedRef: MutableRefObject<boolean>,
Expand Down Expand Up @@ -209,6 +215,7 @@ const useSortingControls = () => {
inputArray: [...originalArray],
setArray,
speed,
speedRef,
setCurrentBar,
shouldStopRef,
sortPausedRef,
Expand Down
Loading
Loading