diff --git a/src/apps/sorting-visualizer/__tests__/hooks/use-algo.hook.spec.ts b/src/apps/sorting-visualizer/__tests__/hooks/use-algo.hook.spec.ts index e886fbf..a5ecfdf 100644 --- a/src/apps/sorting-visualizer/__tests__/hooks/use-algo.hook.spec.ts +++ b/src/apps/sorting-visualizer/__tests__/hooks/use-algo.hook.spec.ts @@ -1,5 +1,5 @@ import { - playSimulation, + simulator, setHighlightInterval, setSwapInterval, } from '@sortViz/store/global.state'; @@ -14,7 +14,7 @@ describe('useAlgo hook', () => { beforeAll(() => { setSwapInterval(0); setHighlightInterval(0); - playSimulation(); + simulator.start(); }); it('should sort initial array', async () => { diff --git a/src/apps/sorting-visualizer/__tests__/sorting-algorithms/all-sort.spec.ts b/src/apps/sorting-visualizer/__tests__/sorting-algorithms/all-sort.spec.ts index e279996..51c50cd 100644 --- a/src/apps/sorting-visualizer/__tests__/sorting-algorithms/all-sort.spec.ts +++ b/src/apps/sorting-visualizer/__tests__/sorting-algorithms/all-sort.spec.ts @@ -1,5 +1,5 @@ import { - playSimulation, + simulator, setHighlightInterval, setSwapInterval, } from '@sortViz/store/global.state'; @@ -12,7 +12,7 @@ describe('bubble sort', () => { beforeAll(() => { setSwapInterval(0); setHighlightInterval(0); - playSimulation(); + simulator.start(); }); it('should sort initial array', async () => { diff --git a/src/apps/sorting-visualizer/helpers/algorithm-helpers.ts b/src/apps/sorting-visualizer/helpers/algorithm-helpers.ts index cd7fe2d..6269627 100644 --- a/src/apps/sorting-visualizer/helpers/algorithm-helpers.ts +++ b/src/apps/sorting-visualizer/helpers/algorithm-helpers.ts @@ -1,6 +1,6 @@ import { highlightInterval, - resolveWhenPlaying, + simulator, swapInterval, } from '@sortViz/store/global.state'; @@ -12,7 +12,7 @@ export async function* swap( i: number, j: number ): SortAsyncGenerator { - await resolveWhenPlaying; + await simulator.isPlayingPromise; const temp = array[i]; array[i] = array[j]; @@ -21,18 +21,18 @@ export async function* swap( yield { type: 'swap', positions: [i, j] }; await delay(swapInterval); - await resolveWhenPlaying; + await simulator.isPlayingPromise; } export async function* highlight(...positions: number[]): SortAsyncGenerator { yield { type: 'highlight', positions: [-1, -1] }; await delay(highlightInterval); - await resolveWhenPlaying; + await simulator.isPlayingPromise; yield { type: 'highlight', positions }; await delay(highlightInterval); - await resolveWhenPlaying; + await simulator.isPlayingPromise; } export async function* showPivot(position: number): SortAsyncGenerator { @@ -44,7 +44,7 @@ export async function* sort(position: number): SortAsyncGenerator { } export async function* move(...positions: number[]): SortAsyncGenerator { - await resolveWhenPlaying; + await simulator.isPlayingPromise; yield { type: 'move', positions }; await delay(swapInterval); } diff --git a/src/apps/sorting-visualizer/hooks/use-algo.hook.tsx b/src/apps/sorting-visualizer/hooks/use-algo.hook.tsx index 4aa1a72..ab5aab9 100644 --- a/src/apps/sorting-visualizer/hooks/use-algo.hook.tsx +++ b/src/apps/sorting-visualizer/hooks/use-algo.hook.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from 'react'; import { SortAsyncGenerator } from '@sortViz/models/types'; -import { resolveWhenPlaying } from '@sortViz/store/global.state'; +import { simulator } from '@sortViz/store/global.state'; function useAlgo( array: number[], @@ -19,7 +19,7 @@ function useAlgo( const compareCount = useRef(0); const fn = async () => { - await resolveWhenPlaying; + await simulator.isPlayingPromise; for await (const data of it.current) { setSwaps([-1, -1]); diff --git a/src/apps/sorting-visualizer/store/global.state.ts b/src/apps/sorting-visualizer/store/global.state.ts index c3deb7e..de5d69c 100644 --- a/src/apps/sorting-visualizer/store/global.state.ts +++ b/src/apps/sorting-visualizer/store/global.state.ts @@ -1,33 +1,9 @@ -let resolver: () => void; -export let resolveWhenPlaying: Promise; -export let isPlaying = false; +import { Simulator } from '@/lib/helpers/simulator'; + export const maxInterval = 2000; export let highlightInterval = 250; export let swapInterval = 1000; - -export const playSimulation = () => { - if (isPlaying) { - return; - } - - isPlaying = true; - resolver(); -}; - -export const setResolver = () => { - resolveWhenPlaying = new Promise((resolve) => { - resolver = resolve; - }); -}; - -export const pauseSimulation = () => { - if (!isPlaying) { - return; - } - - isPlaying = false; - setResolver(); -}; +export const simulator = new Simulator(); export const setSwapInterval = (interval: number) => { swapInterval = interval; @@ -36,5 +12,3 @@ export const setSwapInterval = (interval: number) => { export const setHighlightInterval = (interval: number) => { highlightInterval = interval; }; - -setResolver(); diff --git a/src/apps/sorting-visualizer/store/sorting-visualizer.slice.ts b/src/apps/sorting-visualizer/store/sorting-visualizer.slice.ts index b512a6a..ea57128 100644 --- a/src/apps/sorting-visualizer/store/sorting-visualizer.slice.ts +++ b/src/apps/sorting-visualizer/store/sorting-visualizer.slice.ts @@ -1,8 +1,7 @@ import { initialArray, selectedAlgosStatus } from '@sortViz/config'; import { maxInterval, - pauseSimulation, - playSimulation, + simulator, setHighlightInterval, setSwapInterval, } from './global.state'; @@ -42,7 +41,7 @@ export const sortingVisualizerSlice = createSlice({ setIsPlaying: (state, action: PayloadAction) => { state.isPlaying = action.payload; - action.payload ? playSimulation() : pauseSimulation(); + action.payload ? simulator.start() : simulator.pause(); if (!state.isPlaying && state.timeIntervalId) { clearInterval(state.timeIntervalId); @@ -60,7 +59,7 @@ export const sortingVisualizerSlice = createSlice({ setReset: (state) => { state.reset = !state.reset; - pauseSimulation(); + simulator.pause(); state.time = 0; }, diff --git a/src/lib/helpers/simulator.ts b/src/lib/helpers/simulator.ts new file mode 100644 index 0000000..cf94f7a --- /dev/null +++ b/src/lib/helpers/simulator.ts @@ -0,0 +1,41 @@ +export class Simulator { + public isPlaying = false; + public isPlayingPromise: Promise; + private isPlayingResolver!: () => void; + private onPlay: (() => void) | undefined; + private onStop: (() => void) | undefined; + + constructor(onPlay?: () => void, onStop?: () => void) { + this.onPlay = onPlay; + this.onStop = onStop; + this.isPlayingPromise = new Promise((r) => { + this.isPlayingResolver = r; + }); + } + + start() { + if (this.isPlaying) { + return; + } + + this.isPlaying = true; + this.isPlayingResolver(); + this.onPlay?.(); + } + + pause() { + if (!this.isPlaying) { + return; + } + + this.isPlaying = false; + this.isPlayingPromise = new Promise((r) => { + this.isPlayingResolver = r; + }); + this.onStop?.(); + } + + getStatus() { + return this.isPlayingPromise; + } +}