mirror of
https://github.com/tiennm99/gsd-framework.git
synced 2026-08-08 02:24:38 +00:00
feat(04-01): add GameState enum and StateChangeEvent type
- Add GameState enum with 4 string values (IDLE, SELECTING, MATCHING, GAME_OVER) - Add StateChangeEvent interface with from/to properties - Add game:stateChange event to GameEvents interface - Add tests for GameState enum values and types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
// src/__tests__/Game.integration.test.ts - Integration tests for Game state management
|
||||
import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
import { Game } from '../game/Game';
|
||||
import { GameState } from '../state/GameStateManager';
|
||||
|
||||
describe('Game Integration - State Management', () => {
|
||||
let game: Game | null = null;
|
||||
|
||||
beforeEach(() => {
|
||||
// Set up DOM environment
|
||||
document.body.innerHTML = `
|
||||
<canvas id="game"></canvas>
|
||||
<div id="score-display">Score: 0</div>
|
||||
<div id="game-over-overlay" class="hidden"></div>
|
||||
`;
|
||||
|
||||
// Mock canvas context
|
||||
const canvas = document.getElementById('game') as HTMLCanvasElement;
|
||||
const mockContext = {
|
||||
scale: vi.fn(),
|
||||
fillStyle: '',
|
||||
fillRect: vi.fn(),
|
||||
clearRect: vi.fn(),
|
||||
};
|
||||
vi.spyOn(canvas, 'getContext').mockReturnValue(mockContext as any);
|
||||
|
||||
// Create game instance
|
||||
game = new Game();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up DOM after each test
|
||||
if (game) {
|
||||
game.stop();
|
||||
game = null;
|
||||
}
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
describe('Plan 04-01: State Machine', () => {
|
||||
test('should initialize in IDLE state', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should transition to SELECTING when first tile selected', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should transition to MATCHING when match processing', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should block input during MATCHING state', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Plan 04-02: Win/Lose Detection', () => {
|
||||
test('should detect win condition when all tiles cleared', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should detect no-moves condition when no valid pairs', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should show game over overlay on win', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should show game over overlay on no-moves', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should transition to GAME_OVER state on game end', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Plan 04-03: Restart Functionality', () => {
|
||||
test('should reset grid when restart called', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should reset score to 0 when restart called', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should reset state to IDLE when restart called', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should hide game over overlay when restart called', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should preserve previous score when restart called', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should show previous score display after restart', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
// src/__tests__/GameStateManager.test.ts - Unit tests for GameStateManager class
|
||||
import { describe, test, expect, beforeEach, vi } from 'vitest';
|
||||
import { GameStateManager } from '../state/GameStateManager';
|
||||
import { TypedEventEmitter } from '../game/EventEmitter';
|
||||
|
||||
// Mock TypedEventEmitter for testing
|
||||
vi.mock('../game/EventEmitter', () => ({
|
||||
TypedEventEmitter: class MockTypedEventEmitter {
|
||||
on = vi.fn();
|
||||
emit = vi.fn();
|
||||
off = vi.fn();
|
||||
},
|
||||
}));
|
||||
|
||||
describe('GameStateManager', () => {
|
||||
let mockEventEmitter: TypedEventEmitter<any>;
|
||||
let stateManager: GameStateManager;
|
||||
|
||||
beforeEach(() => {
|
||||
// Create fresh mock event emitter for each test
|
||||
mockEventEmitter = new TypedEventEmitter() as any;
|
||||
stateManager = new GameStateManager(mockEventEmitter);
|
||||
});
|
||||
|
||||
describe('initialization', () => {
|
||||
test('should initialize in IDLE state', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('state transitions', () => {
|
||||
test('should validate state transitions correctly', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should emit state change events on valid transition', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false for invalid transitions', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tile selection by state', () => {
|
||||
test('should allow tile selection in IDLE state', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should block tile selection in MATCHING state', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should block tile selection in GAME_OVER state', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('game reset', () => {
|
||||
test('should reset from GAME_OVER to IDLE', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
// src/__tests__/NoMovesDetector.test.ts - Unit tests for NoMovesDetector class
|
||||
import { describe, test, expect, beforeEach } from 'vitest';
|
||||
import { NoMovesDetector } from '../detection/NoMovesDetector';
|
||||
import type { Tile } from '../types';
|
||||
import { CONFIG } from '../config';
|
||||
|
||||
describe('NoMovesDetector', () => {
|
||||
// Helper function placeholders (will be implemented in TDD)
|
||||
function createMockGrid(rows: number, cols: number): Tile[][] {
|
||||
// TODO: Implement mock grid creation
|
||||
return [];
|
||||
}
|
||||
|
||||
function createMockTile(id: string, type: number, row: number, col: number, cleared: boolean = false): Tile {
|
||||
// TODO: Implement mock tile creation
|
||||
return {
|
||||
id,
|
||||
type,
|
||||
position: { row, col },
|
||||
cleared,
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset state before each test
|
||||
});
|
||||
|
||||
describe('basic detection', () => {
|
||||
test('should return true when valid pair exists', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false when no valid pairs exist', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('algorithm optimization', () => {
|
||||
test('should use type-optimized algorithm', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should skip cleared tiles when checking', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('edge cases', () => {
|
||||
test('should handle empty board', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('path detection', () => {
|
||||
test('should detect valid pair with direct path', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should detect valid pair with 1-turn path', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test('should detect valid pair with 2-turn path', () => {
|
||||
// TODO: Implement test
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
+166
-128
@@ -1,128 +1,166 @@
|
||||
// Tests for src/types/index.ts
|
||||
// Test 1: TilePosition type has row and col as numbers
|
||||
// Test 2: Tile interface has id, type, position, cleared
|
||||
// Test 3: GameEvents type defines event names and payloads
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import type { TilePosition, Tile, GameEvents } from '../types';
|
||||
|
||||
describe('Type Definitions', () => {
|
||||
describe('TilePosition', () => {
|
||||
it('should accept object with row and col as numbers', () => {
|
||||
const position: TilePosition = { row: 5, col: 10 };
|
||||
expect(position.row).toBe(5);
|
||||
expect(position.col).toBe(10);
|
||||
});
|
||||
|
||||
it('should allow row and col to be 0', () => {
|
||||
const position: TilePosition = { row: 0, col: 0 };
|
||||
expect(position.row).toBe(0);
|
||||
expect(position.col).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tile', () => {
|
||||
it('should have id as string', () => {
|
||||
const tile: Tile = {
|
||||
id: 'tile-0-0',
|
||||
type: 0,
|
||||
position: { row: 0, col: 0 },
|
||||
cleared: false,
|
||||
};
|
||||
expect(typeof tile.id).toBe('string');
|
||||
});
|
||||
|
||||
it('should have type as number (0-15 for emoji index)', () => {
|
||||
const tile: Tile = {
|
||||
id: 'tile-5-5',
|
||||
type: 7,
|
||||
position: { row: 5, col: 5 },
|
||||
cleared: false,
|
||||
};
|
||||
expect(typeof tile.type).toBe('number');
|
||||
expect(tile.type).toBeGreaterThanOrEqual(0);
|
||||
expect(tile.type).toBeLessThanOrEqual(15);
|
||||
});
|
||||
|
||||
it('should have position as TilePosition', () => {
|
||||
const tile: Tile = {
|
||||
id: 'tile-1-2',
|
||||
type: 3,
|
||||
position: { row: 1, col: 2 },
|
||||
cleared: false,
|
||||
};
|
||||
expect(tile.position).toHaveProperty('row');
|
||||
expect(tile.position).toHaveProperty('col');
|
||||
});
|
||||
|
||||
it('should have cleared as boolean', () => {
|
||||
const tile: Tile = {
|
||||
id: 'tile-2-3',
|
||||
type: 5,
|
||||
position: { row: 2, col: 3 },
|
||||
cleared: true,
|
||||
};
|
||||
expect(typeof tile.cleared).toBe('boolean');
|
||||
expect(tile.cleared).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GameEvents', () => {
|
||||
it('should define game:start event with void payload', () => {
|
||||
// Type check - if this compiles, the type is correct
|
||||
type StartPayload = GameEvents['game:start'];
|
||||
const payload: StartPayload = undefined;
|
||||
expect(payload).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should define game:tick event with deltaTime', () => {
|
||||
type TickPayload = GameEvents['game:tick'];
|
||||
const payload: TickPayload = { deltaTime: 16.67 };
|
||||
expect(payload.deltaTime).toBe(16.67);
|
||||
});
|
||||
|
||||
it('should define tile:selected event with tile, row, col', () => {
|
||||
type SelectedPayload = GameEvents['tile:selected'];
|
||||
const tile: Tile = {
|
||||
id: 'test',
|
||||
type: 0,
|
||||
position: { row: 0, col: 0 },
|
||||
cleared: false,
|
||||
};
|
||||
const payload: SelectedPayload = { tile, row: 0, col: 0 };
|
||||
expect(payload.tile).toBe(tile);
|
||||
expect(payload.row).toBe(0);
|
||||
expect(payload.col).toBe(0);
|
||||
});
|
||||
|
||||
it('should define tile:cleared event with tile', () => {
|
||||
type ClearedPayload = GameEvents['tile:cleared'];
|
||||
const tile: Tile = {
|
||||
id: 'test',
|
||||
type: 1,
|
||||
position: { row: 1, col: 1 },
|
||||
cleared: true,
|
||||
};
|
||||
const payload: ClearedPayload = { tile };
|
||||
expect(payload.tile).toBe(tile);
|
||||
});
|
||||
|
||||
it('should define game:score event with points', () => {
|
||||
type ScorePayload = GameEvents['game:score'];
|
||||
const payload: ScorePayload = { points: 100 };
|
||||
expect(payload.points).toBe(100);
|
||||
});
|
||||
|
||||
it('should define game:over event with won boolean', () => {
|
||||
type OverPayload = GameEvents['game:over'];
|
||||
const payload: OverPayload = { won: true };
|
||||
expect(payload.won).toBe(true);
|
||||
});
|
||||
|
||||
it('should define error event with Error', () => {
|
||||
type ErrorPayload = GameEvents['error'];
|
||||
const payload: ErrorPayload = new Error('Test error');
|
||||
expect(payload).toBeInstanceOf(Error);
|
||||
});
|
||||
});
|
||||
});
|
||||
// Tests for src/types/index.ts
|
||||
// Test 1: TilePosition type has row and col as numbers
|
||||
// Test 2: Tile interface has id, type, position, cleared
|
||||
// Test 3: GameEvents type defines event names and payloads
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import type { TilePosition, Tile, GameEvents, StateChangeEvent } from '../types';
|
||||
import { GameState } from '../types';
|
||||
|
||||
describe('Type Definitions', () => {
|
||||
describe('TilePosition', () => {
|
||||
it('should accept object with row and col as numbers', () => {
|
||||
const position: TilePosition = { row: 5, col: 10 };
|
||||
expect(position.row).toBe(5);
|
||||
expect(position.col).toBe(10);
|
||||
});
|
||||
|
||||
it('should allow row and col to be 0', () => {
|
||||
const position: TilePosition = { row: 0, col: 0 };
|
||||
expect(position.row).toBe(0);
|
||||
expect(position.col).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tile', () => {
|
||||
it('should have id as string', () => {
|
||||
const tile: Tile = {
|
||||
id: 'tile-0-0',
|
||||
type: 0,
|
||||
position: { row: 0, col: 0 },
|
||||
cleared: false,
|
||||
};
|
||||
expect(typeof tile.id).toBe('string');
|
||||
});
|
||||
|
||||
it('should have type as number (0-15 for emoji index)', () => {
|
||||
const tile: Tile = {
|
||||
id: 'tile-5-5',
|
||||
type: 7,
|
||||
position: { row: 5, col: 5 },
|
||||
cleared: false,
|
||||
};
|
||||
expect(typeof tile.type).toBe('number');
|
||||
expect(tile.type).toBeGreaterThanOrEqual(0);
|
||||
expect(tile.type).toBeLessThanOrEqual(15);
|
||||
});
|
||||
|
||||
it('should have position as TilePosition', () => {
|
||||
const tile: Tile = {
|
||||
id: 'tile-1-2',
|
||||
type: 3,
|
||||
position: { row: 1, col: 2 },
|
||||
cleared: false,
|
||||
};
|
||||
expect(tile.position).toHaveProperty('row');
|
||||
expect(tile.position).toHaveProperty('col');
|
||||
});
|
||||
|
||||
it('should have cleared as boolean', () => {
|
||||
const tile: Tile = {
|
||||
id: 'tile-2-3',
|
||||
type: 5,
|
||||
position: { row: 2, col: 3 },
|
||||
cleared: true,
|
||||
};
|
||||
expect(typeof tile.cleared).toBe('boolean');
|
||||
expect(tile.cleared).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GameEvents', () => {
|
||||
it('should define game:start event with void payload', () => {
|
||||
// Type check - if this compiles, the type is correct
|
||||
type StartPayload = GameEvents['game:start'];
|
||||
const payload: StartPayload = undefined;
|
||||
expect(payload).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should define game:tick event with deltaTime', () => {
|
||||
type TickPayload = GameEvents['game:tick'];
|
||||
const payload: TickPayload = { deltaTime: 16.67 };
|
||||
expect(payload.deltaTime).toBe(16.67);
|
||||
});
|
||||
|
||||
it('should define tile:selected event with tile, row, col', () => {
|
||||
type SelectedPayload = GameEvents['tile:selected'];
|
||||
const tile: Tile = {
|
||||
id: 'test',
|
||||
type: 0,
|
||||
position: { row: 0, col: 0 },
|
||||
cleared: false,
|
||||
};
|
||||
const payload: SelectedPayload = { tile, row: 0, col: 0 };
|
||||
expect(payload.tile).toBe(tile);
|
||||
expect(payload.row).toBe(0);
|
||||
expect(payload.col).toBe(0);
|
||||
});
|
||||
|
||||
it('should define tile:cleared event with tile', () => {
|
||||
type ClearedPayload = GameEvents['tile:cleared'];
|
||||
const tile: Tile = {
|
||||
id: 'test',
|
||||
type: 1,
|
||||
position: { row: 1, col: 1 },
|
||||
cleared: true,
|
||||
};
|
||||
const payload: ClearedPayload = { tile };
|
||||
expect(payload.tile).toBe(tile);
|
||||
});
|
||||
|
||||
it('should define game:score event with points', () => {
|
||||
type ScorePayload = GameEvents['game:score'];
|
||||
const payload: ScorePayload = { points: 100 };
|
||||
expect(payload.points).toBe(100);
|
||||
});
|
||||
|
||||
it('should define game:over event with won boolean', () => {
|
||||
type OverPayload = GameEvents['game:over'];
|
||||
const payload: OverPayload = { won: true };
|
||||
expect(payload.won).toBe(true);
|
||||
});
|
||||
|
||||
it('should define error event with Error', () => {
|
||||
type ErrorPayload = GameEvents['error'];
|
||||
const payload: ErrorPayload = new Error('Test error');
|
||||
expect(payload).toBeInstanceOf(Error);
|
||||
});
|
||||
|
||||
it('should define game:stateChange event with StateChangeEvent', () => {
|
||||
type StateChangePayload = GameEvents['game:stateChange'];
|
||||
const payload: StateChangePayload = {
|
||||
from: GameState.IDLE,
|
||||
to: GameState.SELECTING
|
||||
};
|
||||
expect(payload.from).toBe(GameState.IDLE);
|
||||
expect(payload.to).toBe(GameState.SELECTING);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GameState', () => {
|
||||
it('should have 4 string values', () => {
|
||||
expect(GameState.IDLE).toBe('IDLE');
|
||||
expect(GameState.SELECTING).toBe('SELECTING');
|
||||
expect(GameState.MATCHING).toBe('MATCHING');
|
||||
expect(GameState.GAME_OVER).toBe('GAME_OVER');
|
||||
});
|
||||
|
||||
it('should have string enum values for debugging', () => {
|
||||
expect(typeof GameState.IDLE).toBe('string');
|
||||
expect(typeof GameState.SELECTING).toBe('string');
|
||||
expect(typeof GameState.MATCHING).toBe('string');
|
||||
expect(typeof GameState.GAME_OVER).toBe('string');
|
||||
});
|
||||
});
|
||||
|
||||
describe('StateChangeEvent', () => {
|
||||
it('should have from and to properties of type GameState', () => {
|
||||
const event: StateChangeEvent = {
|
||||
from: GameState.IDLE,
|
||||
to: GameState.SELECTING
|
||||
};
|
||||
expect(event.from).toBe(GameState.IDLE);
|
||||
expect(event.to).toBe(GameState.SELECTING);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// src/detection/NoMovesDetector.ts - Stub implementation for TDD
|
||||
// This will be implemented in Plan 04-02
|
||||
|
||||
import type { Tile } from '../types';
|
||||
import { CONFIG } from '../config';
|
||||
|
||||
export class NoMovesDetector {
|
||||
static hasValidMoves(grid: Tile[][]): boolean {
|
||||
// TODO: Implement no-moves detection algorithm
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// src/state/GameStateManager.ts - Stub implementation for TDD
|
||||
// This will be implemented in Plan 04-01
|
||||
|
||||
import { TypedEventEmitter } from '../game/EventEmitter';
|
||||
|
||||
export enum GameState {
|
||||
IDLE = 'IDLE',
|
||||
SELECTING = 'SELECTING',
|
||||
MATCHING = 'MATCHING',
|
||||
GAME_OVER = 'GAME_OVER',
|
||||
}
|
||||
|
||||
export class GameStateManager {
|
||||
private currentState: GameState = GameState.IDLE;
|
||||
|
||||
constructor(private events: TypedEventEmitter<any>) {}
|
||||
|
||||
getCurrentState(): GameState {
|
||||
return this.currentState;
|
||||
}
|
||||
|
||||
canSelectTile(): boolean {
|
||||
return this.currentState === GameState.IDLE || this.currentState === GameState.SELECTING;
|
||||
}
|
||||
|
||||
transitionTo(newState: GameState): boolean {
|
||||
// TODO: Implement state transition validation
|
||||
this.currentState = newState;
|
||||
return true;
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.currentState = GameState.IDLE;
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,32 @@ export interface MatchResult {
|
||||
turns?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a game state in the state machine
|
||||
* String enum for better debugging and logging
|
||||
*/
|
||||
export enum GameState {
|
||||
/** Waiting for player input */
|
||||
IDLE = 'IDLE',
|
||||
/** One tile selected, waiting for second tile */
|
||||
SELECTING = 'SELECTING',
|
||||
/** Processing match, input blocked */
|
||||
MATCHING = 'MATCHING',
|
||||
/** Game ended (win or no moves) */
|
||||
GAME_OVER = 'GAME_OVER',
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a state transition event
|
||||
* Emitted when game state changes
|
||||
*/
|
||||
export interface StateChangeEvent {
|
||||
/** Previous state */
|
||||
from: GameState;
|
||||
/** New state */
|
||||
to: GameState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps event names to their payload types
|
||||
* Used for type-safe event emission and handling
|
||||
@@ -58,6 +84,7 @@ export interface MatchResult {
|
||||
export interface GameEvents {
|
||||
'game:start': void;
|
||||
'game:tick': { deltaTime: number };
|
||||
'game:stateChange': StateChangeEvent;
|
||||
'tilesSelected': { tile1: Tile; tile2: Tile };
|
||||
'tile:selected': { tile: Tile; row: number; col: number };
|
||||
'tile:cleared': { tile: Tile };
|
||||
|
||||
Reference in New Issue
Block a user