Spaces:
Sleeping
Sleeping
| import { create } from 'zustand'; | |
| import type { | |
| GridState, | |
| SearchResult, | |
| PlanResult, | |
| ComparisonResult, | |
| Algorithm, | |
| SearchStep, | |
| GridConfig, | |
| } from '../types'; | |
| import { generateGrid, createPlan, compareAlgorithms, findPath } from '../api/client'; | |
| interface GridStore { | |
| // Grid state | |
| grid: GridState | null; | |
| initialState: string; | |
| traffic: string; | |
| // Search state | |
| searchResult: SearchResult | null; | |
| planResult: PlanResult | null; | |
| comparisonResults: ComparisonResult[] | null; | |
| // Visualization state | |
| currentStep: number; | |
| steps: SearchStep[]; | |
| isPlaying: boolean; | |
| playbackSpeed: number; // ms per step | |
| // UI state | |
| selectedAlgorithm: Algorithm; | |
| isLoading: boolean; | |
| error: string | null; | |
| // Actions | |
| setGrid: (grid: GridState, initialState: string, traffic: string) => void; | |
| generateNewGrid: (config?: GridConfig) => Promise<void>; | |
| runSearch: (start: { x: number; y: number }, goal: { x: number; y: number }) => Promise<void>; | |
| runPlan: (visualize?: boolean) => Promise<void>; | |
| runComparison: () => Promise<void>; | |
| setAlgorithm: (algorithm: Algorithm) => void; | |
| setCurrentStep: (step: number) => void; | |
| play: () => void; | |
| pause: () => void; | |
| setSpeed: (speed: number) => void; | |
| reset: () => void; | |
| nextStep: () => void; | |
| prevStep: () => void; | |
| } | |
| export const useGridStore = create<GridStore>((set, get) => ({ | |
| // Initial state | |
| grid: null, | |
| initialState: '', | |
| traffic: '', | |
| searchResult: null, | |
| planResult: null, | |
| comparisonResults: null, | |
| currentStep: 0, | |
| steps: [], | |
| isPlaying: false, | |
| playbackSpeed: 100, | |
| selectedAlgorithm: 'BF', | |
| isLoading: false, | |
| error: null, | |
| // Actions | |
| setGrid: (grid, initialState, traffic) => { | |
| set({ | |
| grid, | |
| initialState, | |
| traffic, | |
| searchResult: null, | |
| planResult: null, | |
| comparisonResults: null, | |
| currentStep: 0, | |
| steps: [], | |
| isPlaying: false, | |
| error: null, | |
| }); | |
| }, | |
| generateNewGrid: async (config = {}) => { | |
| set({ isLoading: true, error: null }); | |
| try { | |
| const result = await generateGrid(config); | |
| set({ | |
| grid: result.parsed, | |
| initialState: result.initialState, | |
| traffic: result.traffic, | |
| searchResult: null, | |
| planResult: null, | |
| comparisonResults: null, | |
| currentStep: 0, | |
| steps: [], | |
| isPlaying: false, | |
| isLoading: false, | |
| }); | |
| } catch (error) { | |
| set({ | |
| error: error instanceof Error ? error.message : 'Failed to generate grid', | |
| isLoading: false, | |
| }); | |
| } | |
| }, | |
| runSearch: async (start, goal) => { | |
| const { grid, selectedAlgorithm } = get(); | |
| if (!grid) return; | |
| set({ isLoading: true, error: null }); | |
| try { | |
| const result = await findPath( | |
| grid.width, | |
| grid.height, | |
| start, | |
| goal, | |
| grid.segments, | |
| grid.tunnels, | |
| selectedAlgorithm | |
| ); | |
| set({ | |
| searchResult: result, | |
| steps: result.steps || [], | |
| currentStep: 0, | |
| isPlaying: false, | |
| isLoading: false, | |
| }); | |
| } catch (error) { | |
| set({ | |
| error: error instanceof Error ? error.message : 'Search failed', | |
| isLoading: false, | |
| }); | |
| } | |
| }, | |
| runPlan: async (visualize = false) => { | |
| const { initialState, traffic, selectedAlgorithm } = get(); | |
| if (!initialState) return; | |
| set({ isLoading: true, error: null }); | |
| try { | |
| const result = await createPlan(initialState, traffic, selectedAlgorithm, visualize); | |
| set({ | |
| planResult: result, | |
| isLoading: false, | |
| }); | |
| } catch (error) { | |
| set({ | |
| error: error instanceof Error ? error.message : 'Planning failed', | |
| isLoading: false, | |
| }); | |
| } | |
| }, | |
| runComparison: async () => { | |
| const { initialState, traffic } = get(); | |
| if (!initialState) return; | |
| set({ isLoading: true, error: null }); | |
| try { | |
| const result = await compareAlgorithms(initialState, traffic); | |
| set({ | |
| comparisonResults: result.comparisons, | |
| isLoading: false, | |
| }); | |
| } catch (error) { | |
| set({ | |
| error: error instanceof Error ? error.message : 'Comparison failed', | |
| isLoading: false, | |
| }); | |
| } | |
| }, | |
| setAlgorithm: (algorithm) => { | |
| set({ selectedAlgorithm: algorithm }); | |
| }, | |
| setCurrentStep: (step) => { | |
| const { steps } = get(); | |
| set({ currentStep: Math.max(0, Math.min(step, steps.length - 1)) }); | |
| }, | |
| play: () => { | |
| set({ isPlaying: true }); | |
| }, | |
| pause: () => { | |
| set({ isPlaying: false }); | |
| }, | |
| setSpeed: (speed) => { | |
| set({ playbackSpeed: speed }); | |
| }, | |
| reset: () => { | |
| set({ | |
| currentStep: 0, | |
| isPlaying: false, | |
| }); | |
| }, | |
| nextStep: () => { | |
| const { currentStep, steps } = get(); | |
| if (currentStep < steps.length - 1) { | |
| set({ currentStep: currentStep + 1 }); | |
| } else { | |
| set({ isPlaying: false }); | |
| } | |
| }, | |
| prevStep: () => { | |
| const { currentStep } = get(); | |
| if (currentStep > 0) { | |
| set({ currentStep: currentStep - 1 }); | |
| } | |
| }, | |
| })); | |