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>
11 KiB
11 KiB
Data Models and Structures
Core Data Structures
1. Square
Represents a single square on the chess board.
class Square {
file: number; // 0-7 (a-h)
rank: number; // 0-7 (1-8)
color: 'light' | 'dark';
piece: ChessPiece | null;
// Helper methods
toAlgebraic(): string; // "e4"
fromAlgebraic(notation: string): Square;
equals(other: Square): boolean;
clone(): Square;
}
// Examples
{ file: 4, rank: 3, color: 'light', piece: null } // e4
{ file: 0, rank: 0, color: 'dark', piece: WhiteRook } // a1
Algebraic Notation Mapping:
- Files: a=0, b=1, c=2, d=3, e=4, f=5, g=6, h=7
- Ranks: 1=0, 2=1, 3=2, 4=3, 5=4, 6=5, 7=6, 8=7
2. BoardState
Represents the complete chess board configuration.
class BoardState {
// Array representation (primary)
squares: Square[64];
// Alternative: 2D array
// grid: Square[8][8];
// Bitboard representation (optional, for performance)
bitboards: {
white: {
pawns: BigInt,
knights: BigInt,
bishops: BigInt,
rooks: BigInt,
queens: BigInt,
king: BigInt,
all: BigInt
},
black: { /* same structure */ },
occupied: BigInt,
empty: BigInt
};
// Helper methods
getSquare(file: number, rank: number): Square;
getSquareByIndex(index: number): Square;
getPieceAt(square: Square): ChessPiece | null;
setPieceAt(square: Square, piece: ChessPiece): void;
removePieceAt(square: Square): void;
clone(): BoardState;
toFEN(): string;
fromFEN(fen: string): BoardState;
}
Index Calculation:
// Square to index: rank * 8 + file
// Index to square: { file: index % 8, rank: Math.floor(index / 8) }
Starting Position FEN:
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
3. PieceType Enumeration
const PieceType = {
PAWN: 'pawn',
KNIGHT: 'knight',
BISHOP: 'bishop',
ROOK: 'rook',
QUEEN: 'queen',
KING: 'king'
};
const PieceValue = {
pawn: 1,
knight: 3,
bishop: 3,
rook: 5,
queen: 9,
king: Infinity
};
const PieceNotation = {
pawn: '', // No letter for pawns
knight: 'N',
bishop: 'B',
rook: 'R',
queen: 'Q',
king: 'K'
};
4. Move
Represents a single chess move with all metadata.
class Move {
from: Square;
to: Square;
piece: PieceType;
color: 'white' | 'black';
captured: PieceType | null;
promotion: PieceType | null;
// Special move flags
isCastling: boolean;
isEnPassant: boolean;
isCheck: boolean;
isCheckmate: boolean;
// Metadata
notation: string; // "Nf3", "exd5", "O-O"
algebraicNotation: string; // "e2e4"
timestamp: number;
moveNumber: number;
// Methods
toSAN(): string; // Standard Algebraic Notation
toLAN(): string; // Long Algebraic Notation
toUCI(): string; // Universal Chess Interface
equals(other: Move): boolean;
clone(): Move;
}
Notation Examples:
- SAN: "Nf3", "e4", "O-O", "Qxe5+", "e8=Q#"
- LAN: "Ng1-f3", "e2-e4", "Qd1xe5+"
- UCI: "e2e4", "e7e5", "e1g1" (castling), "e7e8q" (promotion)
5. GameState
Complete game state snapshot for state management.
class GameState {
board: BoardState;
currentPlayer: 'white' | 'black';
moveNumber: number;
halfMoveClock: number; // For 50-move rule
// Special move tracking
enPassantSquare: Square | null;
castlingRights: {
whiteKingSide: boolean,
whiteQueenSide: boolean,
blackKingSide: boolean,
blackQueenSide: boolean
};
// Game status
status: GameStatus;
lastMove: Move | null;
// Captured pieces
capturedPieces: {
white: PieceType[],
black: PieceType[]
};
// Methods
toFEN(): string;
fromFEN(fen: string): GameState;
clone(): GameState;
hash(): string; // For position repetition
equals(other: GameState): boolean;
}
FEN Format:
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
│ │ │ │ │ │
│ │ │ │ │ └─ Full move number
│ │ │ │ └─── Halfmove clock
│ │ │ └───── En passant square
│ │ └────────── Castling rights
│ └──────────── Active player
└──────────────────────────────────────────────────────── Board position
6. GameStatus Enumeration
const GameStatus = {
ACTIVE: 'active',
CHECK: 'check',
CHECKMATE: 'checkmate',
STALEMATE: 'stalemate',
DRAW_50_MOVE: 'draw-50-move',
DRAW_REPETITION: 'draw-repetition',
DRAW_INSUFFICIENT: 'draw-insufficient-material',
DRAW_AGREEMENT: 'draw-agreement',
RESIGNATION: 'resignation'
};
7. GameConfiguration
Settings and options for game initialization.
class GameConfig {
mode: 'pvp' | 'pva' | 'ava';
timeControl: TimeControl | null;
playerWhite: Player;
playerBlack: Player;
aiDifficulty: number; // 1-10 for AI opponent
theme: string;
soundEnabled: boolean;
animationSpeed: number; // ms for animations
autoSave: boolean;
legalMovesHighlight: boolean;
dragAndDrop: boolean;
}
class TimeControl {
type: 'none' | 'classical' | 'rapid' | 'blitz' | 'bullet';
initialTime: number; // seconds
increment: number; // seconds per move
whiteTime: number;
blackTime: number;
}
class Player {
name: string;
type: 'human' | 'ai';
color: 'white' | 'black';
elo: number | null;
}
8. MoveHistory
Structure for tracking complete game history.
class MoveHistory {
moves: Move[];
positions: string[]; // FEN strings for repetition detection
currentIndex: number;
startingPosition: string; // Initial FEN
// PGN metadata
metadata: {
event: string,
site: string,
date: string,
round: string,
white: string,
black: string,
result: string
};
// Methods
addMove(move: Move, position: string): void;
getMove(index: number): Move;
getAllMoves(): Move[];
undo(): Move | null;
redo(): Move | null;
canUndo(): boolean;
canRedo(): boolean;
clear(): void;
toPGN(): string;
fromPGN(pgn: string): MoveHistory;
toJSON(): string;
fromJSON(json: string): MoveHistory;
}
PGN Format Example:
[Event "Casual Game"]
[Site "Chess App"]
[Date "2025.11.22"]
[Round "1"]
[White "Player 1"]
[Black "Player 2"]
[Result "1-0"]
1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 1-0
9. Event System
Event definitions for component communication.
class GameEvent {
type: EventType;
payload: any;
timestamp: number;
source: string;
}
const EventType = {
// Board events
SQUARE_CLICKED: 'square-clicked',
PIECE_SELECTED: 'piece-selected',
PIECE_MOVED: 'piece-moved',
PIECE_CAPTURED: 'piece-captured',
PIECE_PROMOTED: 'piece-promoted',
// Game events
GAME_STARTED: 'game-started',
GAME_OVER: 'game-over',
TURN_CHANGED: 'turn-changed',
CHECK_DETECTED: 'check-detected',
MOVE_EXECUTED: 'move-executed',
MOVE_UNDONE: 'move-undone',
MOVE_REDONE: 'move-redone',
// UI events
THEME_CHANGED: 'theme-changed',
SETTINGS_UPDATED: 'settings-updated',
// AI events
AI_THINKING: 'ai-thinking',
AI_MOVE_READY: 'ai-move-ready',
// Error events
INVALID_MOVE: 'invalid-move',
VALIDATION_FAILED: 'validation-failed'
};
10. Bitboard Representation (Advanced)
For performance-critical operations and AI.
class Bitboard {
value: BigInt; // 64-bit integer representing board
// Bitwise operations
setBit(square: Square): void;
clearBit(square: Square): void;
toggleBit(square: Square): void;
testBit(square: Square): boolean;
popCount(): number; // Count set bits
// Board operations
and(other: Bitboard): Bitboard;
or(other: Bitboard): Bitboard;
xor(other: Bitboard): Bitboard;
not(): Bitboard;
shift(direction: number): Bitboard;
// Move generation helpers
northOne(): Bitboard;
southOne(): Bitboard;
eastOne(): Bitboard;
westOne(): Bitboard;
getSetSquares(): Square[];
}
Bitboard Example:
Bit 0 = a1, Bit 1 = b1, ..., Bit 7 = h1
Bit 8 = a2, Bit 9 = b2, ..., Bit 63 = h8
White pawns starting position:
0x000000000000FF00 (bits 8-15 set)
Black pawns starting position:
0x00FF000000000000 (bits 48-55 set)
Data Flow Diagrams
Move Execution Flow
User Input
↓
UI captures click/drag
↓
GameController validates selection
↓
MoveValidator checks legality
↓
GameEngine executes move
↓
BoardState updated
↓
GameHistory records move
↓
UI renders new state
↓
Turn switches
State Update Flow
Move → GameState (immutable) → New GameState
↓ ↓
└─────── History records both ──────┘
Serialization Formats
JSON Save Format
{
"version": "1.0.0",
"timestamp": 1700000000000,
"gameState": {
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
"moveHistory": [
{"from": "e2", "to": "e4", "notation": "e4"},
{"from": "e7", "to": "e5", "notation": "e5"}
],
"capturedPieces": {"white": [], "black": []},
"timeControl": {
"whiteTime": 600,
"blackTime": 595
}
},
"config": {
"mode": "pvp",
"theme": "classic"
}
}
Local Storage Keys
const StorageKeys = {
CURRENT_GAME: 'chess-current-game',
SAVED_GAMES: 'chess-saved-games',
SETTINGS: 'chess-settings',
THEME: 'chess-theme',
GAME_HISTORY: 'chess-game-history'
};
Performance Considerations
Memory Optimization
- Board Representation: Array[64] uses ~2KB per position
- Move History: Average game ~80 moves = ~40KB
- Bitboards: Enable compact representation (8 bytes per piece type)
Caching Strategy
class CacheManager {
moveValidationCache: Map<string, boolean>;
moveGenerationCache: Map<string, Move[]>;
evaluationCache: Map<string, number>;
maxSize: number = 10000;
set(key: string, value: any): void;
get(key: string): any | null;
clear(): void;
prune(): void; // Remove old entries
}
Position Hashing
// Zobrist hashing for position identification
class ZobristHash {
pieceKeys: BigInt[64][12]; // Square × PieceType
castlingKeys: BigInt[4];
enPassantKeys: BigInt[8];
sideToMoveKey: BigInt;
hash(gameState: GameState): BigInt;
updateHash(hash: BigInt, move: Move): BigInt;
}
This data model design ensures efficient state management, easy serialization, and optimal performance for both UI rendering and AI computation.