Spaces:
Running
Running
| import { defineStore } from "pinia"; | |
| import { TrigoGameFrontend } from "../utils/TrigoGameFrontend"; | |
| import type { | |
| Stone, | |
| BoardShape, | |
| Player, | |
| Move, | |
| Position, | |
| GameConfig, | |
| TerritoryResult | |
| } from "../../../inc/trigo"; | |
| /** | |
| * Game Store State | |
| * | |
| * Refactored to use TrigoGameFrontend as the single source of truth | |
| */ | |
| export interface GameState { | |
| game: TrigoGameFrontend; | |
| config: GameConfig; | |
| } | |
| /** | |
| * Pinia store for game state management | |
| * | |
| * Now delegates all game logic to TrigoGameFrontend | |
| */ | |
| export const useGameStore = defineStore("game", { | |
| state: (): GameState => ({ | |
| game: new TrigoGameFrontend({ x: 5, y: 5, z: 5 }), | |
| config: { | |
| boardShape: { x: 5, y: 5, z: 5 }, | |
| allowUndo: true | |
| } | |
| }), | |
| getters: { | |
| // Board state | |
| board: (state): Stone[][][] => state.game.getBoard(), | |
| boardShape: (state): BoardShape => state.game.getShape(), | |
| // Current player | |
| currentPlayer: (state): Player => state.game.getCurrentPlayerString(), | |
| currentPlayerColor: (state): Player => state.game.getCurrentPlayerString(), | |
| opponentPlayer: (state): Player => state.game.getOpponentPlayer(), | |
| // Move history | |
| moveHistory: (state): Move[] => state.game.getMoveHistory(), | |
| moveCount: (state): number => state.game.getMoveCount(), | |
| currentMoveIndex: (state): number => state.game.getCurrentMoveIndex(), | |
| currentMoves: (state): Move[] => { | |
| const history = state.game.getMoveHistory(); | |
| const currentIndex = state.game.getCurrentMoveIndex(); | |
| return history.slice(0, currentIndex); | |
| }, | |
| // Game status | |
| gameStatus: (state) => state.game.getStatus(), | |
| gameResult: (state) => state.game.getResult(), | |
| isGameActive: (state): boolean => state.game.isGameActive(), | |
| // Captured stones | |
| capturedStones: (state): { black: number; white: number } => { | |
| const counts = state.game.getCapturedCounts(); | |
| return { | |
| black: counts.white, // Black captured white stones | |
| white: counts.black // White captured black stones | |
| }; | |
| }, | |
| // Pass tracking | |
| passCount: (state): number => state.game.getConsecutivePassCount(), | |
| // Undo/Redo capabilities | |
| canUndo: (state): boolean => { | |
| return state.config.allowUndo && state.game.canUndo(); | |
| }, | |
| canRedo: (state): boolean => { | |
| return state.config.allowUndo && state.game.canRedo(); | |
| }, | |
| // Position checks | |
| isValidPosition: | |
| (state) => | |
| (x: number, y: number, z: number): boolean => { | |
| return state.game.isValidPosition(x, y, z); | |
| }, | |
| isEmpty: | |
| (state) => | |
| (x: number, y: number, z: number): boolean => { | |
| return state.game.isEmpty(x, y, z); | |
| }, | |
| getStone: | |
| (state) => | |
| (x: number, y: number, z: number): Stone => { | |
| return state.game.getStoneAt(x, y, z) as Stone; | |
| } | |
| }, | |
| actions: { | |
| /** | |
| * Initialize a new game | |
| */ | |
| initializeGame(boardShape: BoardShape = { x: 5, y: 5, z: 5 }): void { | |
| this.game = new TrigoGameFrontend(boardShape); | |
| this.config.boardShape = boardShape; | |
| this.saveToSessionStorage(); | |
| }, | |
| /** | |
| * Start the game | |
| */ | |
| startGame(): void { | |
| this.game.startGame(); | |
| this.saveToSessionStorage(); | |
| }, | |
| /** | |
| * Make a move | |
| */ | |
| makeMove( | |
| x: number, | |
| y: number, | |
| z: number | |
| ): { success: boolean; capturedPositions?: Position[] } { | |
| // Check if game is active | |
| if (!this.game.isGameActive()) { | |
| console.warn("Game is not active"); | |
| return { success: false }; | |
| } | |
| // Attempt to make the move | |
| const success = this.game.makeMove(x, y, z); | |
| if (success) { | |
| // Get captured positions from last step | |
| const lastStep = this.game.getLastStep(); | |
| const capturedPositions = lastStep?.capturedPositions; | |
| // Save to storage | |
| this.saveToSessionStorage(); | |
| return { success: true, capturedPositions }; | |
| } | |
| return { success: false }; | |
| }, | |
| /** | |
| * Pass turn | |
| */ | |
| pass(): boolean { | |
| if (!this.game.isGameActive()) { | |
| return false; | |
| } | |
| const success = this.game.pass(); | |
| if (success) { | |
| this.saveToSessionStorage(); | |
| } | |
| return success; | |
| }, | |
| /** | |
| * Resign/surrender | |
| */ | |
| resign(): boolean { | |
| if (!this.game.isGameActive()) { | |
| return false; | |
| } | |
| const success = this.game.surrender(); | |
| if (success) { | |
| this.saveToSessionStorage(); | |
| } | |
| return success; | |
| }, | |
| /** | |
| * Undo last move | |
| */ | |
| undoMove(): boolean { | |
| if (!this.canUndo) { | |
| return false; | |
| } | |
| const success = this.game.undoMove(); | |
| if (success) { | |
| this.saveToSessionStorage(); | |
| } | |
| return success; | |
| }, | |
| /** | |
| * Redo next move | |
| */ | |
| redoMove(): boolean { | |
| if (!this.canRedo) { | |
| return false; | |
| } | |
| const success = this.game.redoMove(); | |
| if (success) { | |
| this.saveToSessionStorage(); | |
| } | |
| return success; | |
| }, | |
| /** | |
| * Jump to specific move in history | |
| */ | |
| jumpToMove(index: number): boolean { | |
| const success = this.game.jumpToMove(index); | |
| if (success) { | |
| this.saveToSessionStorage(); | |
| } | |
| return success; | |
| }, | |
| /** | |
| * Reset game to initial state | |
| */ | |
| resetGame(): void { | |
| this.game.reset(); | |
| this.saveToSessionStorage(); | |
| }, | |
| /** | |
| * Change board shape (only when game is idle) | |
| */ | |
| setBoardShape(shape: BoardShape): boolean { | |
| if (this.game.getStatus() !== "idle") { | |
| console.warn("Cannot change board shape while game is active"); | |
| return false; | |
| } | |
| this.initializeGame(shape); | |
| return true; | |
| }, | |
| /** | |
| * Calculate territory | |
| */ | |
| computeTerritory(): TerritoryResult { | |
| return this.game.computeTerritory(); | |
| }, | |
| /** | |
| * Get neighboring positions (6 directions in 3D) | |
| */ | |
| getNeighbors(x: number, y: number, z: number): Array<{ x: number; y: number; z: number }> { | |
| const neighbors = [ | |
| { x: x + 1, y, z }, | |
| { x: x - 1, y, z }, | |
| { x, y: y + 1, z }, | |
| { x, y: y - 1, z }, | |
| { x, y, z: z + 1 }, | |
| { x, y, z: z - 1 } | |
| ]; | |
| return neighbors.filter((pos) => this.isValidPosition(pos.x, pos.y, pos.z)); | |
| }, | |
| /** | |
| * Save game state to session storage | |
| */ | |
| saveToSessionStorage(): void { | |
| try { | |
| this.game.saveToSessionStorage("trigoGameState"); | |
| } catch (error) { | |
| console.error("Failed to save game state:", error); | |
| } | |
| }, | |
| /** | |
| * Load game state from session storage | |
| */ | |
| loadFromSessionStorage(): boolean { | |
| try { | |
| const success = this.game.loadFromSessionStorage("trigoGameState"); | |
| if (success) { | |
| console.log("Game state restored from session storage"); | |
| } | |
| return success; | |
| } catch (error) { | |
| console.error("Failed to load game state:", error); | |
| return false; | |
| } | |
| }, | |
| /** | |
| * Clear saved game state | |
| */ | |
| clearSessionStorage(): void { | |
| try { | |
| this.game.clearSessionStorage("trigoGameState"); | |
| } catch (error) { | |
| console.error("Failed to clear session storage:", error); | |
| } | |
| } | |
| } | |
| }); | |