trigo / trigo-web /app /src /stores /gameStore.ts
k-l-lambda's picture
updated
502af73
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);
}
}
}
});