Restructured project from nested workspace pattern to flat single-repo layout. This eliminates redundant nesting and consolidates all project files under version control. ## Migration Summary **Before:** ``` alex/ (workspace, not versioned) ├── chess-game/ (git repo) │ ├── js/, css/, tests/ │ └── index.html └── docs/ (planning, not versioned) ``` **After:** ``` alex/ (git repo, everything versioned) ├── js/, css/, tests/ ├── index.html ├── docs/ (project documentation) ├── planning/ (historical planning docs) ├── .gitea/ (CI/CD) └── CLAUDE.md (configuration) ``` ## Changes Made ### Structure Consolidation - Moved all chess-game/ contents to root level - Removed redundant chess-game/ subdirectory - Flattened directory structure (eliminated one nesting level) ### Documentation Organization - Moved chess-game/docs/ → docs/ (project documentation) - Moved alex/docs/ → planning/ (historical planning documents) - Added CLAUDE.md (workspace configuration) - Added IMPLEMENTATION_PROMPT.md (original project prompt) ### Version Control Improvements - All project files now under version control - Planning documents preserved in planning/ folder - Merged .gitignore files (workspace + project) - Added .claude/ agent configurations ### File Updates - Updated .gitignore to include both workspace and project excludes - Moved README.md to root level - All import paths remain functional (relative paths unchanged) ## Benefits ✅ **Simpler Structure** - One level of nesting removed ✅ **Complete Versioning** - All documentation now in git ✅ **Standard Layout** - Matches open-source project conventions ✅ **Easier Navigation** - Direct access to all project files ✅ **CI/CD Compatible** - All workflows still functional ## Technical Validation - ✅ Node.js environment verified - ✅ Dependencies installed successfully - ✅ Dev server starts and responds - ✅ All core files present and accessible - ✅ Git repository functional ## Files Preserved **Implementation Files:** - js/ (3,517 lines of code) - css/ (4 stylesheets) - tests/ (87 test cases) - index.html - package.json **CI/CD Pipeline:** - .gitea/workflows/ci.yml - .gitea/workflows/release.yml **Documentation:** - docs/ (12+ documentation files) - planning/ (historical planning materials) - README.md **Configuration:** - jest.config.js, babel.config.cjs, playwright.config.js - .gitignore (merged) - CLAUDE.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
627 lines
14 KiB
Markdown
627 lines
14 KiB
Markdown
# API Interfaces and Component Contracts
|
|
|
|
## Public API Interfaces
|
|
|
|
### 1. IChessBoard Interface
|
|
|
|
```javascript
|
|
interface IChessBoard {
|
|
// Properties
|
|
readonly squares: Square[];
|
|
readonly activePiece: ChessPiece | null;
|
|
|
|
// Square operations
|
|
getSquare(file: number, rank: number): Square;
|
|
getSquareByNotation(notation: string): Square;
|
|
setPiece(square: Square, piece: ChessPiece): void;
|
|
removePiece(square: Square): ChessPiece | null;
|
|
getPiece(square: Square): ChessPiece | null;
|
|
|
|
// Board queries
|
|
isSquareOccupied(square: Square): boolean;
|
|
isSquareEmpty(square: Square): boolean;
|
|
getSquareColor(square: Square): 'light' | 'dark';
|
|
findKing(color: 'white' | 'black'): Square | null;
|
|
getAllPieces(color?: 'white' | 'black'): ChessPiece[];
|
|
|
|
// Visual operations
|
|
highlightSquares(squares: Square[]): void;
|
|
clearHighlights(): void;
|
|
|
|
// State management
|
|
clone(): IChessBoard;
|
|
reset(): void;
|
|
toFEN(): string;
|
|
fromFEN(fen: string): void;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 2. IChessPiece Interface
|
|
|
|
```javascript
|
|
interface IChessPiece {
|
|
// Properties
|
|
readonly type: PieceType;
|
|
readonly color: 'white' | 'black';
|
|
position: Square | null;
|
|
hasMoved: boolean;
|
|
|
|
// Move generation
|
|
getPossibleMoves(board: IChessBoard): Square[];
|
|
getLegalMoves(board: IChessBoard, gameState: IGameState): Square[];
|
|
canMoveTo(square: Square, board: IChessBoard): boolean;
|
|
getAttackingSquares(board: IChessBoard): Square[];
|
|
|
|
// Piece information
|
|
getValue(): number;
|
|
getNotation(): string;
|
|
getImagePath(theme?: string): string;
|
|
|
|
// Utilities
|
|
clone(): IChessPiece;
|
|
equals(other: IChessPiece): boolean;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 3. IGameEngine Interface
|
|
|
|
```javascript
|
|
interface IGameEngine {
|
|
// Properties
|
|
readonly gameState: IGameState;
|
|
readonly currentPlayer: 'white' | 'black';
|
|
readonly moveHistory: IMove[];
|
|
readonly status: GameStatus;
|
|
|
|
// Game lifecycle
|
|
initializeGame(config?: GameConfig): void;
|
|
reset(): void;
|
|
|
|
// Move execution
|
|
executeMove(from: Square, to: Square, promotion?: PieceType): IMove | null;
|
|
undoMove(): IMove | null;
|
|
redoMove(): IMove | null;
|
|
|
|
// Game state queries
|
|
isCheck(color: 'white' | 'black'): boolean;
|
|
isCheckmate(color: 'white' | 'black'): boolean;
|
|
isStalemate(): boolean;
|
|
isDraw(): boolean;
|
|
isGameOver(): boolean;
|
|
getWinner(): 'white' | 'black' | 'draw' | null;
|
|
|
|
// Turn management
|
|
switchTurn(): void;
|
|
getCurrentPlayer(): 'white' | 'black';
|
|
|
|
// State management
|
|
getGameState(): IGameState;
|
|
loadGameState(state: IGameState): void;
|
|
saveGame(): string;
|
|
loadGame(saveData: string): void;
|
|
|
|
// Events
|
|
on(event: string, handler: Function): void;
|
|
off(event: string, handler: Function): void;
|
|
emit(event: string, data?: any): void;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 4. IMoveValidator Interface
|
|
|
|
```javascript
|
|
interface IMoveValidator {
|
|
// Primary validation
|
|
isMoveLegal(from: Square, to: Square, gameState: IGameState): boolean;
|
|
validateMove(move: IMove, gameState: IGameState): ValidationResult;
|
|
|
|
// Specific validations
|
|
isPseudoLegal(from: Square, to: Square, board: IChessBoard): boolean;
|
|
wouldExposeKing(move: IMove, gameState: IGameState): boolean;
|
|
validateCastling(king: Square, rook: Square, gameState: IGameState): boolean;
|
|
validateEnPassant(from: Square, to: Square, gameState: IGameState): boolean;
|
|
validatePromotion(move: IMove): boolean;
|
|
|
|
// Threat detection
|
|
isSquareAttacked(square: Square, byColor: 'white' | 'black', gameState: IGameState): boolean;
|
|
getAttackingPieces(square: Square, byColor: 'white' | 'black', gameState: IGameState): IChessPiece[];
|
|
isKingInCheck(color: 'white' | 'black', gameState: IGameState): boolean;
|
|
|
|
// Cache management
|
|
clearCache(): void;
|
|
}
|
|
|
|
interface ValidationResult {
|
|
valid: boolean;
|
|
reason?: string;
|
|
code?: string;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 5. IGameController Interface
|
|
|
|
```javascript
|
|
interface IGameController {
|
|
// Initialization
|
|
initialize(config: GameConfig): void;
|
|
startNewGame(config?: GameConfig): void;
|
|
|
|
// User interaction
|
|
handleSquareClick(square: Square): void;
|
|
handlePieceDrag(piece: IChessPiece, fromSquare: Square): void;
|
|
handlePieceDrop(toSquare: Square): void;
|
|
selectSquare(square: Square): void;
|
|
deselectSquare(): void;
|
|
|
|
// Game actions
|
|
makeMove(from: Square, to: Square, promotion?: PieceType): boolean;
|
|
offerDraw(): void;
|
|
acceptDraw(): void;
|
|
resign(color: 'white' | 'black'): void;
|
|
requestUndo(): void;
|
|
|
|
// Game management
|
|
pauseGame(): void;
|
|
resumeGame(): void;
|
|
saveGame(): string;
|
|
loadGame(saveData: string): void;
|
|
exportPGN(): string;
|
|
|
|
// Configuration
|
|
setGameMode(mode: 'pvp' | 'pva' | 'ava'): void;
|
|
setAIDifficulty(level: number): void;
|
|
updateSettings(settings: Partial<GameConfig>): void;
|
|
|
|
// Queries
|
|
getGameState(): IGameState;
|
|
getCurrentPlayer(): 'white' | 'black';
|
|
getGameStatus(): GameStatus;
|
|
getLegalMovesFor(square: Square): Square[];
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 6. IMoveGenerator Interface
|
|
|
|
```javascript
|
|
interface IMoveGenerator {
|
|
// Move generation
|
|
generateAllMoves(gameState: IGameState, color: 'white' | 'black'): IMove[];
|
|
generatePieceMoves(piece: IChessPiece, gameState: IGameState): IMove[];
|
|
generateCaptures(gameState: IGameState, color: 'white' | 'black'): IMove[];
|
|
generateQuietMoves(gameState: IGameState, color: 'white' | 'black'): IMove[];
|
|
|
|
// Special moves
|
|
generateCastlingMoves(color: 'white' | 'black', gameState: IGameState): IMove[];
|
|
generateEnPassantMoves(color: 'white' | 'black', gameState: IGameState): IMove[];
|
|
generatePromotionMoves(pawn: IChessPiece, gameState: IGameState): IMove[];
|
|
|
|
// Move ordering
|
|
orderMoves(moves: IMove[], gameState: IGameState): IMove[];
|
|
|
|
// Performance testing
|
|
perft(depth: number, gameState: IGameState): number;
|
|
|
|
// Cache
|
|
clearCache(): void;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 7. IGameHistory Interface
|
|
|
|
```javascript
|
|
interface IGameHistory {
|
|
// Properties
|
|
readonly moves: IMove[];
|
|
readonly currentIndex: number;
|
|
readonly canUndo: boolean;
|
|
readonly canRedo: boolean;
|
|
|
|
// History operations
|
|
addMove(move: IMove, position: string): void;
|
|
getMove(index: number): IMove | null;
|
|
getAllMoves(): IMove[];
|
|
clear(): void;
|
|
|
|
// Navigation
|
|
undo(): IMove | null;
|
|
redo(): IMove | null;
|
|
goToMove(index: number): IMove | null;
|
|
|
|
// Queries
|
|
getMoveCount(): number;
|
|
getLastMove(): IMove | null;
|
|
isThreefoldRepetition(): boolean;
|
|
getFiftyMoveCount(): number;
|
|
|
|
// Export
|
|
toPGN(metadata?: PGNMetadata): string;
|
|
toJSON(): string;
|
|
exportMoves(): string[];
|
|
|
|
// Import
|
|
fromPGN(pgn: string): void;
|
|
fromJSON(json: string): void;
|
|
importMoves(moves: string[]): void;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 8. IUIController Interface
|
|
|
|
```javascript
|
|
interface IUIController {
|
|
// Rendering
|
|
renderBoard(board: IChessBoard): void;
|
|
renderPiece(piece: IChessPiece, square: Square): void;
|
|
renderGameStatus(status: GameStatus): void;
|
|
updateCapturedPieces(pieces: { white: PieceType[], black: PieceType[] }): void;
|
|
|
|
// Animations
|
|
animateMove(from: Square, to: Square, duration?: number): Promise<void>;
|
|
animateCapture(square: Square): Promise<void>;
|
|
animatePromotion(square: Square, newPiece: PieceType): Promise<void>;
|
|
|
|
// Visual feedback
|
|
highlightSquare(square: Square, type: HighlightType): void;
|
|
clearHighlights(): void;
|
|
showLegalMoves(moves: Square[]): void;
|
|
hideLegalMoves(): void;
|
|
showCheck(color: 'white' | 'black'): void;
|
|
|
|
// Dialogs
|
|
showPromotionDialog(color: 'white' | 'black'): Promise<PieceType>;
|
|
showGameOverDialog(result: GameResult): void;
|
|
showSettingsDialog(): void;
|
|
|
|
// Interactions
|
|
enableDragAndDrop(): void;
|
|
disableDragAndDrop(): void;
|
|
enableClickToMove(): void;
|
|
disableClickToMove(): void;
|
|
|
|
// Sound
|
|
playSound(soundType: SoundType): void;
|
|
|
|
// Theme
|
|
setTheme(theme: string): void;
|
|
}
|
|
|
|
enum HighlightType {
|
|
SELECTED = 'selected',
|
|
LEGAL_MOVE = 'legal-move',
|
|
LAST_MOVE = 'last-move',
|
|
CHECK = 'check',
|
|
ATTACKED = 'attacked'
|
|
}
|
|
|
|
enum SoundType {
|
|
MOVE = 'move',
|
|
CAPTURE = 'capture',
|
|
CASTLE = 'castle',
|
|
CHECK = 'check',
|
|
CHECKMATE = 'checkmate',
|
|
DRAW = 'draw',
|
|
ILLEGAL = 'illegal'
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 9. IAIPlayer Interface
|
|
|
|
```javascript
|
|
interface IAIPlayer {
|
|
// Configuration
|
|
setDifficulty(level: number): void;
|
|
setThinkingTime(ms: number): void;
|
|
setSearchDepth(depth: number): void;
|
|
|
|
// Move calculation
|
|
calculateMove(gameState: IGameState): Promise<IMove>;
|
|
evaluatePosition(gameState: IGameState): number;
|
|
|
|
// Search
|
|
search(gameState: IGameState, depth: number): SearchResult;
|
|
minimax(depth: number, alpha: number, beta: number, gameState: IGameState): number;
|
|
|
|
// Opening book
|
|
hasOpeningMove(gameState: IGameState): boolean;
|
|
getOpeningMove(gameState: IGameState): IMove | null;
|
|
|
|
// Status
|
|
isThinking(): boolean;
|
|
cancelCalculation(): void;
|
|
|
|
// Events
|
|
on(event: 'move-ready' | 'thinking' | 'evaluation-update', handler: Function): void;
|
|
off(event: string, handler: Function): void;
|
|
}
|
|
|
|
interface SearchResult {
|
|
bestMove: IMove;
|
|
score: number;
|
|
depth: number;
|
|
nodesSearched: number;
|
|
timeElapsed: number;
|
|
principalVariation: IMove[];
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 10. IThemeManager Interface
|
|
|
|
```javascript
|
|
interface IThemeManager {
|
|
// Theme management
|
|
setTheme(themeName: string): void;
|
|
getTheme(): Theme;
|
|
getAvailableThemes(): string[];
|
|
|
|
// Custom themes
|
|
registerTheme(theme: Theme): void;
|
|
unregisterTheme(themeName: string): void;
|
|
|
|
// Import/Export
|
|
loadTheme(themeData: string): void;
|
|
exportTheme(themeName: string): string;
|
|
|
|
// Apply styles
|
|
applyColors(): void;
|
|
applyPieceSet(): void;
|
|
}
|
|
|
|
interface Theme {
|
|
name: string;
|
|
lightSquares: string;
|
|
darkSquares: string;
|
|
highlightColor: string;
|
|
legalMoveColor: string;
|
|
selectedColor: string;
|
|
checkColor: string;
|
|
pieceSet: string;
|
|
borderStyle?: string;
|
|
coordinatesColor?: string;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Event System API
|
|
|
|
### Event Emitter Base
|
|
|
|
```javascript
|
|
interface IEventEmitter {
|
|
on(event: string, handler: Function): void;
|
|
off(event: string, handler: Function): void;
|
|
once(event: string, handler: Function): void;
|
|
emit(event: string, data?: any): void;
|
|
removeAllListeners(event?: string): void;
|
|
}
|
|
```
|
|
|
|
### Game Events
|
|
|
|
```javascript
|
|
// Event payloads
|
|
interface MoveExecutedEvent {
|
|
move: IMove;
|
|
gameState: IGameState;
|
|
isCheck: boolean;
|
|
isCheckmate: boolean;
|
|
}
|
|
|
|
interface PieceSelectedEvent {
|
|
piece: IChessPiece;
|
|
square: Square;
|
|
legalMoves: Square[];
|
|
}
|
|
|
|
interface GameOverEvent {
|
|
status: GameStatus;
|
|
winner: 'white' | 'black' | 'draw' | null;
|
|
reason: string;
|
|
}
|
|
|
|
interface TurnChangedEvent {
|
|
player: 'white' | 'black';
|
|
moveNumber: number;
|
|
}
|
|
|
|
interface CheckDetectedEvent {
|
|
color: 'white' | 'black';
|
|
attackingPieces: IChessPiece[];
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Factory Interfaces
|
|
|
|
### Piece Factory
|
|
|
|
```javascript
|
|
interface IPieceFactory {
|
|
createPiece(type: PieceType, color: 'white' | 'black', position?: Square): IChessPiece;
|
|
createPawn(color: 'white' | 'black', position?: Square): IChessPiece;
|
|
createKnight(color: 'white' | 'black', position?: Square): IChessPiece;
|
|
createBishop(color: 'white' | 'black', position?: Square): IChessPiece;
|
|
createRook(color: 'white' | 'black', position?: Square): IChessPiece;
|
|
createQueen(color: 'white' | 'black', position?: Square): IChessPiece;
|
|
createKing(color: 'white' | 'black', position?: Square): IChessPiece;
|
|
}
|
|
```
|
|
|
|
### Game Factory
|
|
|
|
```javascript
|
|
interface IGameFactory {
|
|
createGame(config?: GameConfig): IGameEngine;
|
|
createGameFromFEN(fen: string, config?: GameConfig): IGameEngine;
|
|
createGameFromPGN(pgn: string, config?: GameConfig): IGameEngine;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Utility Interfaces
|
|
|
|
### Notation Converter
|
|
|
|
```javascript
|
|
interface INotationConverter {
|
|
moveToSAN(move: IMove, gameState: IGameState): string;
|
|
moveToLAN(move: IMove): string;
|
|
moveToUCI(move: IMove): string;
|
|
sanToMove(san: string, gameState: IGameState): IMove | null;
|
|
uciToMove(uci: string, gameState: IGameState): IMove | null;
|
|
}
|
|
```
|
|
|
|
### FEN Parser
|
|
|
|
```javascript
|
|
interface IFENParser {
|
|
parse(fen: string): IGameState;
|
|
generate(gameState: IGameState): string;
|
|
validate(fen: string): boolean;
|
|
}
|
|
```
|
|
|
|
### PGN Parser
|
|
|
|
```javascript
|
|
interface IPGNParser {
|
|
parse(pgn: string): PGNGame;
|
|
generate(game: IGameEngine): string;
|
|
validate(pgn: string): boolean;
|
|
}
|
|
|
|
interface PGNGame {
|
|
metadata: PGNMetadata;
|
|
moves: string[];
|
|
result: string;
|
|
}
|
|
|
|
interface PGNMetadata {
|
|
event?: string;
|
|
site?: string;
|
|
date?: string;
|
|
round?: string;
|
|
white?: string;
|
|
black?: string;
|
|
result?: string;
|
|
[key: string]: string | undefined;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Plugin Interface
|
|
|
|
```javascript
|
|
interface IChessPlugin {
|
|
name: string;
|
|
version: string;
|
|
|
|
// Lifecycle hooks
|
|
initialize(game: IGameEngine): void;
|
|
destroy(): void;
|
|
|
|
// Optional hooks
|
|
onMoveExecuted?(move: IMove, gameState: IGameState): void;
|
|
onGameStart?(config: GameConfig): void;
|
|
onGameEnd?(result: GameResult): void;
|
|
onTurnChange?(player: 'white' | 'black'): void;
|
|
|
|
// Custom functionality
|
|
getAPI?(): any;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Service Interfaces
|
|
|
|
### Storage Service
|
|
|
|
```javascript
|
|
interface IStorageService {
|
|
saveGame(key: string, game: IGameEngine): void;
|
|
loadGame(key: string): IGameEngine | null;
|
|
deleteGame(key: string): void;
|
|
listSavedGames(): string[];
|
|
|
|
saveSetting(key: string, value: any): void;
|
|
loadSetting(key: string): any;
|
|
|
|
clearAll(): void;
|
|
}
|
|
```
|
|
|
|
### Network Service (Future)
|
|
|
|
```javascript
|
|
interface INetworkService {
|
|
connect(gameId: string): Promise<void>;
|
|
disconnect(): void;
|
|
sendMove(move: IMove): void;
|
|
onMoveReceived(handler: (move: IMove) => void): void;
|
|
|
|
syncGameState(gameState: IGameState): void;
|
|
requestSync(): void;
|
|
|
|
chat(message: string): void;
|
|
onChatMessage(handler: (message: ChatMessage) => void): void;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Usage Example
|
|
|
|
```javascript
|
|
// Initialize game
|
|
const gameFactory = new GameFactory();
|
|
const game = gameFactory.createGame({
|
|
mode: 'pvp',
|
|
theme: 'classic',
|
|
soundEnabled: true
|
|
});
|
|
|
|
// Set up UI
|
|
const uiController = new UIController('#board-container');
|
|
uiController.renderBoard(game.getBoard());
|
|
|
|
// Handle moves
|
|
game.on('move-executed', (event: MoveExecutedEvent) => {
|
|
uiController.animateMove(event.move.from, event.move.to);
|
|
uiController.renderGameStatus(event.gameState.status);
|
|
});
|
|
|
|
// User interaction
|
|
uiController.on('square-clicked', (square: Square) => {
|
|
const legalMoves = game.getLegalMovesFor(square);
|
|
uiController.showLegalMoves(legalMoves);
|
|
});
|
|
|
|
// Execute move
|
|
game.executeMove(fromSquare, toSquare);
|
|
```
|
|
|
|
This API design ensures loose coupling, clear contracts, and easy testing while providing flexibility for future extensions.
|