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>
601 lines
14 KiB
Markdown
601 lines
14 KiB
Markdown
# Implementation Guide - Chess Game
|
|
|
|
## Overview
|
|
Step-by-step guide for implementing the HTML chess game with single-player functionality.
|
|
|
|
## Phase 1: Foundation (Day 1)
|
|
|
|
### Step 1.1: Create Project Structure
|
|
```bash
|
|
mkdir chess-game
|
|
cd chess-game
|
|
mkdir -p css js/{models,controllers,views,engine,utils} assets/{pieces,sounds} tests
|
|
touch index.html css/{main,board,pieces,game-controls,animations}.css
|
|
```
|
|
|
|
### Step 1.2: Implement Constants.js
|
|
**File**: `js/utils/Constants.js`
|
|
|
|
**Key Elements**:
|
|
- Board dimensions (8x8)
|
|
- Piece types and colors
|
|
- Initial piece positions
|
|
- Game status constants
|
|
|
|
**Test Criteria**:
|
|
- All constants are immutable (use `Object.freeze()`)
|
|
- Initial positions are valid board coordinates
|
|
- No duplicate piece positions
|
|
|
|
### Step 1.3: Implement Helpers.js
|
|
**File**: `js/utils/Helpers.js`
|
|
|
|
**Key Functions**:
|
|
```javascript
|
|
// Position validation
|
|
isValidPosition(row, col)
|
|
|
|
// Position comparison
|
|
positionsEqual(pos1, pos2)
|
|
|
|
// Coordinate conversion
|
|
algebraicToPosition('e4') // → {row: 4, col: 4}
|
|
positionToAlgebraic({row: 4, col: 4}) // → 'e4'
|
|
|
|
// Array utilities
|
|
deepClone(obj)
|
|
```
|
|
|
|
**Test Criteria**:
|
|
- Boundary testing (row/col 0-7)
|
|
- Invalid input handling
|
|
- Correct algebraic notation conversion
|
|
|
|
### Step 1.4: Implement EventBus.js
|
|
**File**: `js/utils/EventBus.js`
|
|
|
|
**Key Features**:
|
|
- Subscribe to events
|
|
- Publish events
|
|
- Unsubscribe from events
|
|
|
|
**Events to Support**:
|
|
- `piece:selected`
|
|
- `piece:moved`
|
|
- `piece:captured`
|
|
- `game:check`
|
|
- `game:checkmate`
|
|
- `game:over`
|
|
- `turn:changed`
|
|
|
|
## Phase 2: Data Models (Days 2-3)
|
|
|
|
### Step 2.1: Implement Board.js
|
|
**File**: `js/models/Board.js`
|
|
|
|
**Key Methods**:
|
|
```javascript
|
|
constructor() // Initialize 8x8 grid
|
|
getPieceAt(position) // Get piece at position
|
|
setPieceAt(position, piece) // Place piece
|
|
removePieceAt(position) // Remove piece
|
|
movePiece(from, to) // Move piece (update positions)
|
|
getAllPieces() // Get all pieces on board
|
|
getPiecesByColor(color) // Get pieces of one color
|
|
clone() // Deep copy board state
|
|
reset() // Reset to initial state
|
|
```
|
|
|
|
**Data Structure**:
|
|
```javascript
|
|
// Use 2D array
|
|
this._squares = Array(8).fill(null).map(() => Array(8).fill(null));
|
|
|
|
// Or use Map for sparse storage
|
|
this._pieces = new Map(); // key: 'row-col', value: Piece
|
|
```
|
|
|
|
**Test Criteria**:
|
|
- Initial setup has 32 pieces
|
|
- Can get/set pieces correctly
|
|
- Clone creates independent copy
|
|
- Moving piece updates both positions
|
|
|
|
### Step 2.2: Implement Piece.js (Base Class)
|
|
**File**: `js/models/Piece.js`
|
|
|
|
**Properties**:
|
|
```javascript
|
|
constructor(color, position, type) {
|
|
this.color = color; // 'white' or 'black'
|
|
this.position = position; // {row, col}
|
|
this.type = type; // 'pawn', 'rook', etc.
|
|
this.hasMoved = false; // For castling/pawn moves
|
|
}
|
|
```
|
|
|
|
**Methods**:
|
|
```javascript
|
|
move(newPosition) // Update position
|
|
getValidMoves(board) // Abstract - override in subclasses
|
|
canMoveTo(position, board) // Check if specific move is valid
|
|
clone() // Create copy
|
|
```
|
|
|
|
### Step 2.3: Implement Individual Pieces
|
|
**Files**: `js/models/pieces/*.js`
|
|
|
|
#### Implementation Order:
|
|
1. **Rook.js** (simplest - straight lines)
|
|
2. **Bishop.js** (diagonal lines)
|
|
3. **Queen.js** (combines rook + bishop)
|
|
4. **Knight.js** (L-shapes, no blocking)
|
|
5. **King.js** (one square, castling)
|
|
6. **Pawn.js** (most complex - promotion, en passant)
|
|
|
|
#### Example: Pawn.js Template
|
|
```javascript
|
|
import Piece from '../Piece.js';
|
|
|
|
class Pawn extends Piece {
|
|
constructor(color, position) {
|
|
super(color, position, 'pawn');
|
|
}
|
|
|
|
getValidMoves(board) {
|
|
const moves = [];
|
|
const direction = this.color === 'white' ? -1 : 1;
|
|
const startRow = this.color === 'white' ? 6 : 1;
|
|
|
|
// One square forward
|
|
// Two squares forward (if on start row)
|
|
// Diagonal captures
|
|
// En passant (if applicable)
|
|
|
|
return moves;
|
|
}
|
|
}
|
|
|
|
export default Pawn;
|
|
```
|
|
|
|
**Test Each Piece**:
|
|
- Starting position moves
|
|
- Capture moves
|
|
- Blocked moves
|
|
- Edge of board
|
|
- Special moves (castling, en passant, promotion)
|
|
|
|
### Step 2.4: Implement GameState.js
|
|
**File**: `js/models/GameState.js`
|
|
|
|
**Properties**:
|
|
```javascript
|
|
constructor() {
|
|
this.currentPlayer = 'white';
|
|
this.moveHistory = [];
|
|
this.capturedPieces = [];
|
|
this.isCheck = false;
|
|
this.isCheckmate = false;
|
|
this.isStalemate = false;
|
|
this.enPassantTarget = null; // For en passant validation
|
|
}
|
|
```
|
|
|
|
**Methods**:
|
|
```javascript
|
|
switchTurn()
|
|
addMove(move) // {piece, from, to, captured}
|
|
getLastMove()
|
|
isGameOver()
|
|
reset()
|
|
```
|
|
|
|
## Phase 3: Game Engine (Days 4-5)
|
|
|
|
### Step 3.1: Implement MoveValidator.js
|
|
**File**: `js/engine/MoveValidator.js`
|
|
|
|
**Key Methods**:
|
|
```javascript
|
|
isValidMove(piece, from, to, board)
|
|
// 1. Check if move is in piece's valid moves
|
|
// 2. Check if move doesn't expose king to check
|
|
// 3. Return true/false
|
|
|
|
wouldExposeKing(piece, from, to, board)
|
|
// Simulate move and check if king is in check
|
|
|
|
isPiecePinned(piece, board)
|
|
// Check if piece is pinned to king
|
|
```
|
|
|
|
### Step 3.2: Implement MoveGenerator.js
|
|
**File**: `js/engine/MoveGenerator.js`
|
|
|
|
**Key Methods**:
|
|
```javascript
|
|
getAllValidMoves(color, board)
|
|
// Get all legal moves for a color
|
|
// Used for: check detection, AI, stalemate
|
|
|
|
hasValidMoves(color, board)
|
|
// Quick check if player can move
|
|
```
|
|
|
|
### Step 3.3: Implement CheckDetector.js
|
|
**File**: `js/engine/CheckDetector.js`
|
|
|
|
**Key Methods**:
|
|
```javascript
|
|
isKingInCheck(color, board)
|
|
// Check if king is under attack
|
|
|
|
isCheckmate(color, board)
|
|
// Check if in check AND no valid moves
|
|
|
|
isStalemate(color, board)
|
|
// Check if NOT in check AND no valid moves
|
|
|
|
getAttackingPieces(color, board)
|
|
// Get pieces attacking the king
|
|
```
|
|
|
|
### Step 3.4: Implement RuleEngine.js
|
|
**File**: `js/engine/RuleEngine.js`
|
|
|
|
**Special Rules**:
|
|
```javascript
|
|
canCastle(king, rook, board)
|
|
// Kingside or queenside castling
|
|
|
|
isEnPassantValid(pawn, target, board, gameState)
|
|
// Check en passant conditions
|
|
|
|
handlePawnPromotion(pawn, choice = 'queen')
|
|
// Promote pawn to chosen piece
|
|
```
|
|
|
|
## Phase 4: Views (Days 6-7)
|
|
|
|
### Step 4.1: Implement BoardView.js
|
|
**File**: `js/views/BoardView.js`
|
|
|
|
**Key Methods**:
|
|
```javascript
|
|
render(board)
|
|
// Create 64 squares with alternating colors
|
|
// Add coordinate labels (a-h, 1-8)
|
|
|
|
highlightSquare(position, className)
|
|
// Highlight selected piece or valid moves
|
|
|
|
clearHighlights()
|
|
|
|
getSquareElement(position)
|
|
// Get DOM element for position
|
|
```
|
|
|
|
**HTML Structure**:
|
|
```html
|
|
<div class="board">
|
|
<div class="square light" data-row="0" data-col="0"></div>
|
|
<!-- ... 64 squares -->
|
|
</div>
|
|
```
|
|
|
|
### Step 4.2: Implement PieceView.js
|
|
**File**: `js/views/PieceView.js`
|
|
|
|
**Key Methods**:
|
|
```javascript
|
|
renderPiece(piece, square)
|
|
// Create piece element and add to square
|
|
// Use Unicode symbols or images
|
|
|
|
removePiece(position)
|
|
|
|
movePiece(from, to, animate = true)
|
|
// Animate piece movement
|
|
|
|
enableDragDrop(pieceElement, callbacks)
|
|
// Setup drag and drop handlers
|
|
```
|
|
|
|
**Piece Representation**:
|
|
```javascript
|
|
const PIECE_SYMBOLS = {
|
|
'white-king': '♔',
|
|
'white-queen': '♕',
|
|
'white-rook': '♖',
|
|
// ... or use images
|
|
};
|
|
```
|
|
|
|
### Step 4.3: Implement UIManager.js
|
|
**File**: `js/views/UIManager.js`
|
|
|
|
**UI Elements**:
|
|
```javascript
|
|
showMessage(text, type = 'info')
|
|
// Display status message
|
|
|
|
showCheckIndicator(color)
|
|
|
|
showPromotionDialog(callback)
|
|
// Show piece selection for pawn promotion
|
|
|
|
updateTurnIndicator(color)
|
|
|
|
updateCapturedPieces(pieces)
|
|
|
|
enableControls() / disableControls()
|
|
```
|
|
|
|
## Phase 5: Controllers (Days 8-9)
|
|
|
|
### Step 5.1: Implement MoveController.js
|
|
**File**: `js/controllers/MoveController.js`
|
|
|
|
**Workflow**:
|
|
```javascript
|
|
handleMoveAttempt(piece, from, to) {
|
|
// 1. Validate move
|
|
if (!this.validator.isValidMove(piece, from, to, board)) {
|
|
return { success: false, reason: 'Invalid move' };
|
|
}
|
|
|
|
// 2. Execute move
|
|
const capturedPiece = this.executeMove(piece, from, to);
|
|
|
|
// 3. Check for special rules
|
|
if (piece.type === 'pawn' && this._isPromotionRow(to)) {
|
|
this._handlePromotion(piece);
|
|
}
|
|
|
|
// 4. Update game state
|
|
this.gameState.addMove({piece, from, to, captured: capturedPiece});
|
|
|
|
// 5. Check for check/checkmate
|
|
this._checkGameStatus();
|
|
|
|
// 6. Switch turn
|
|
this.gameState.switchTurn();
|
|
|
|
return { success: true, captured: capturedPiece };
|
|
}
|
|
```
|
|
|
|
### Step 5.2: Implement GameController.js
|
|
**File**: `js/controllers/GameController.js`
|
|
|
|
**Main Loop**:
|
|
```javascript
|
|
class GameController {
|
|
constructor(board, gameState, moveController, uiManager) {
|
|
// Initialize dependencies
|
|
this._setupEventListeners();
|
|
}
|
|
|
|
startNewGame() {
|
|
// Reset board and state
|
|
// Render initial position
|
|
// Start player's turn
|
|
}
|
|
|
|
_setupEventListeners() {
|
|
// Listen for square clicks
|
|
// Handle piece selection
|
|
// Handle move attempts
|
|
}
|
|
|
|
_handleSquareClick(row, col) {
|
|
if (!this.selectedPiece) {
|
|
// Try to select piece
|
|
this._selectPiece(row, col);
|
|
} else {
|
|
// Try to move selected piece
|
|
this._attemptMove(row, col);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Step 5.3: Implement AIController.js
|
|
**File**: `js/controllers/AIController.js`
|
|
|
|
**AI Strategy** (Start Simple):
|
|
```javascript
|
|
// Level 1: Random valid move
|
|
getRandomMove(color, board) {
|
|
const validMoves = this.moveGen.getAllValidMoves(color, board);
|
|
return validMoves[Math.floor(Math.random() * validMoves.length)];
|
|
}
|
|
|
|
// Level 2: Material evaluation
|
|
getBestMove(color, board, depth = 2) {
|
|
// Minimax algorithm
|
|
// Evaluate position based on piece values
|
|
// Return best move
|
|
}
|
|
```
|
|
|
|
**Piece Values**:
|
|
- Pawn: 1
|
|
- Knight: 3
|
|
- Bishop: 3
|
|
- Rook: 5
|
|
- Queen: 9
|
|
- King: ∞
|
|
|
|
## Phase 6: Integration (Day 10)
|
|
|
|
### Step 6.1: Create main.js
|
|
**File**: `js/main.js`
|
|
|
|
```javascript
|
|
import Board from './models/Board.js';
|
|
import GameState from './models/GameState.js';
|
|
import GameController from './controllers/GameController.js';
|
|
// ... import all dependencies
|
|
|
|
// Wait for DOM
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// Initialize models
|
|
const board = new Board();
|
|
const gameState = new GameState();
|
|
|
|
// Initialize views
|
|
const boardView = new BoardView(document.querySelector('.board'));
|
|
const uiManager = new UIManager();
|
|
|
|
// Initialize controllers
|
|
const moveController = new MoveController(/* dependencies */);
|
|
const gameController = new GameController(/* dependencies */);
|
|
|
|
// Start game
|
|
gameController.startNewGame();
|
|
});
|
|
```
|
|
|
|
### Step 6.2: Create index.html
|
|
**File**: `index.html`
|
|
|
|
```html
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Chess Game</title>
|
|
<link rel="stylesheet" href="css/main.css">
|
|
<link rel="stylesheet" href="css/board.css">
|
|
<link rel="stylesheet" href="css/pieces.css">
|
|
<link rel="stylesheet" href="css/game-controls.css">
|
|
<link rel="stylesheet" href="css/animations.css">
|
|
</head>
|
|
<body>
|
|
<main class="game-container">
|
|
<section class="game-info">
|
|
<h1>Chess Game</h1>
|
|
<div class="turn-indicator">White's Turn</div>
|
|
<div class="status-message"></div>
|
|
</section>
|
|
|
|
<section class="board-container">
|
|
<div class="board"></div>
|
|
</section>
|
|
|
|
<aside class="game-controls">
|
|
<button id="new-game">New Game</button>
|
|
<button id="undo">Undo</button>
|
|
<div class="captured-pieces">
|
|
<div class="captured-white"></div>
|
|
<div class="captured-black"></div>
|
|
</div>
|
|
</aside>
|
|
</main>
|
|
|
|
<script type="module" src="js/main.js"></script>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
## Critical Implementation Notes
|
|
|
|
### Common Pitfalls
|
|
|
|
1. **Check Validation Loop**
|
|
- Don't call `isKingInCheck()` inside `getValidMoves()`
|
|
- Use two-pass validation: piece moves → filter exposing king
|
|
|
|
2. **Deep Cloning**
|
|
- Board cloning must deep clone all pieces
|
|
- Use JSON or manual clone, not shallow copy
|
|
|
|
3. **Event Listeners**
|
|
- Remove old listeners before adding new ones
|
|
- Use event delegation for dynamically created elements
|
|
|
|
4. **State Management**
|
|
- Keep single source of truth (GameState)
|
|
- Don't duplicate state in multiple places
|
|
|
|
5. **Performance**
|
|
- Cache valid moves when position hasn't changed
|
|
- Use early returns in validation
|
|
- Avoid re-rendering entire board on each move
|
|
|
|
### Testing Strategy
|
|
|
|
1. **Unit Tests First**
|
|
- Test each piece movement in isolation
|
|
- Test board operations
|
|
- Test validation logic
|
|
|
|
2. **Integration Tests**
|
|
- Test complete move flow
|
|
- Test check/checkmate scenarios
|
|
- Test special moves (castling, en passant)
|
|
|
|
3. **Manual Testing Scenarios**
|
|
- Scholar's mate (4-move checkmate)
|
|
- Fool's mate (2-move checkmate)
|
|
- Castling (both sides)
|
|
- Pawn promotion
|
|
- Stalemate positions
|
|
|
|
## Dependencies Between Components
|
|
|
|
```
|
|
Phase 1 (Utils) → Phase 2 (Models) → Phase 3 (Engine) → Phase 4 (Views) → Phase 5 (Controllers) → Phase 6 (Integration)
|
|
```
|
|
|
|
**Parallel Development**:
|
|
- Views can be developed alongside Engine
|
|
- AI can be developed after basic game works
|
|
- Tests can be written alongside implementation
|
|
|
|
## Success Criteria
|
|
|
|
### Minimum Viable Product (MVP)
|
|
- [ ] All pieces move according to chess rules
|
|
- [ ] Can detect check
|
|
- [ ] Can detect checkmate
|
|
- [ ] Player vs player works
|
|
- [ ] Can start new game
|
|
|
|
### Full Feature Set
|
|
- [ ] Player vs computer AI
|
|
- [ ] Pawn promotion
|
|
- [ ] Castling (both sides)
|
|
- [ ] En passant
|
|
- [ ] Stalemate detection
|
|
- [ ] Move history
|
|
- [ ] Undo move
|
|
- [ ] Highlight valid moves
|
|
- [ ] Capture display
|
|
- [ ] Animated moves
|
|
|
|
## Estimated Timeline
|
|
|
|
- **Phase 1**: 4 hours
|
|
- **Phase 2**: 8 hours
|
|
- **Phase 3**: 8 hours
|
|
- **Phase 4**: 6 hours
|
|
- **Phase 5**: 8 hours
|
|
- **Phase 6**: 4 hours
|
|
- **Testing & Polish**: 8 hours
|
|
|
|
**Total**: ~45 hours (1-2 weeks for one developer)
|
|
|
|
## Next Steps
|
|
|
|
1. Review this guide with the team
|
|
2. Set up development environment
|
|
3. Start with Phase 1 (Foundation)
|
|
4. Implement in order, testing as you go
|
|
5. Use the code templates as starting points
|
|
6. Reference coding standards for style
|
|
7. Coordinate via memory for swarm work
|