# Developer Guide - HTML Chess Game ## Table of Contents 1. [Development Environment](#development-environment) 2. [Project Structure](#project-structure) 3. [Development Workflow](#development-workflow) 4. [Testing Strategy](#testing-strategy) 5. [Debugging Guide](#debugging-guide) 6. [Performance Optimization](#performance-optimization) 7. [Code Style Guide](#code-style-guide) 8. [Deployment](#deployment) 9. [Troubleshooting](#troubleshooting) --- ## Development Environment ### Prerequisites **Required:** - Modern web browser (Chrome 60+, Firefox 54+, Safari 10.1+, Edge 79+) - Text editor or IDE (VS Code recommended) - Git for version control **Optional:** - Node.js (for local server and testing) - Browser dev tools extensions - Code formatters (Prettier recommended) ### Initial Setup #### 1. Clone or Create Project ```bash # Create new project mkdir chess-game cd chess-game # Initialize git (optional) git init # Create project structure mkdir -p {css,js/{game,pieces,moves,ui,utils},assets/pieces,tests/{unit,integration},docs} ``` #### 2. Install Development Tools (Optional) ```bash # Initialize npm (for testing framework) npm init -y # Install dev dependencies (optional) npm install --save-dev \ live-server \ eslint \ prettier \ jest ``` #### 3. Set Up Live Server **Option 1: Using Python** ```bash python3 -m http.server 8000 ``` **Option 2: Using Node.js** ```bash npx http-server -p 8000 ``` **Option 3: Using VS Code Extension** - Install "Live Server" extension - Right-click `index.html` → "Open with Live Server" #### 4. Configure Editor **VS Code Settings (.vscode/settings.json):** ```json { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "javascript.preferences.quoteStyle": "single", "files.eol": "\n", "files.insertFinalNewline": true, "files.trimTrailingWhitespace": true } ``` **ESLint Config (.eslintrc.json):** ```json { "env": { "browser": true, "es2021": true }, "extends": "eslint:recommended", "parserOptions": { "ecmaVersion": 12, "sourceType": "module" }, "rules": { "indent": ["error", 4], "quotes": ["error", "single"], "semi": ["error", "always"] } } ``` **Prettier Config (.prettierrc):** ```json { "singleQuote": true, "tabWidth": 4, "useTabs": false, "semi": true, "trailingComma": "es5" } ``` --- ## Project Structure ### Directory Organization ``` chess-game/ ├── index.html # Main entry point ├── package.json # npm configuration (optional) ├── .gitignore # Git ignore rules ├── .eslintrc.json # ESLint configuration ├── .prettierrc # Prettier configuration │ ├── css/ # Stylesheets │ ├── board.css # Chess board styling │ ├── pieces.css # Piece styling │ └── ui.css # UI components │ ├── js/ # JavaScript modules │ ├── main.js # Application entry point │ │ │ ├── game/ # Game logic │ │ ├── ChessGame.js # Main game controller │ │ ├── Board.js # Board state management │ │ └── GameState.js # Game state and history │ │ │ ├── pieces/ # Piece implementations │ │ ├── Piece.js # Base piece class │ │ ├── Pawn.js # Pawn logic │ │ ├── Knight.js # Knight logic │ │ ├── Bishop.js # Bishop logic │ │ ├── Rook.js # Rook logic │ │ ├── Queen.js # Queen logic │ │ └── King.js # King logic │ │ │ ├── moves/ # Move validation │ │ ├── MoveValidator.js # Move validation │ │ ├── MoveGenerator.js # Legal move generation │ │ └── SpecialMoves.js # Special moves │ │ │ ├── ui/ # UI components │ │ ├── BoardRenderer.js # Board rendering │ │ ├── DragDropHandler.js # Drag-and-drop │ │ └── UIController.js # UI state management │ │ │ └── utils/ # Utilities │ ├── notation.js # Chess notation │ ├── storage.js # localStorage wrapper │ └── helpers.js # Helper functions │ ├── assets/ # Static assets │ └── pieces/ # Piece images (SVG) │ ├── white-king.svg │ ├── white-queen.svg │ └── ... │ ├── tests/ # Test files │ ├── unit/ # Unit tests │ │ ├── Board.test.js │ │ ├── pieces/ │ │ └── moves/ │ │ │ └── integration/ # Integration tests │ └── gameplay.test.js │ └── docs/ # Documentation ├── README.md ├── IMPLEMENTATION_GUIDE.md ├── API_REFERENCE.md └── ... ``` ### Module Dependencies ``` main.js ├── ChessGame.js │ ├── Board.js │ ├── GameState.js │ └── MoveValidator.js │ ├── Piece.js (and subclasses) │ └── SpecialMoves.js │ └── UIController.js ├── BoardRenderer.js └── DragDropHandler.js Utilities (used everywhere): ├── notation.js ├── storage.js └── helpers.js ``` --- ## Development Workflow ### 1. Feature Development Cycle ```bash # 1. Create feature branch (if using git) git checkout -b feature/castling-logic # 2. Write failing test first (TDD) # Edit tests/unit/moves/SpecialMoves.test.js # 3. Run tests npm test # 4. Implement feature # Edit js/moves/SpecialMoves.js # 5. Run tests until passing npm test # 6. Refactor if needed # Clean up code, improve performance # 7. Commit changes git add . git commit -m "feat: implement castling logic" # 8. Merge to main git checkout main git merge feature/castling-logic ``` ### 2. Daily Development Routine **Morning:** 1. Pull latest changes 2. Review open issues 3. Plan tasks for the day 4. Set up development environment **During Development:** 1. Write test first (TDD) 2. Implement minimal code to pass 3. Refactor for quality 4. Commit frequently 5. Run full test suite periodically **End of Day:** 1. Run full test suite 2. Commit all changes 3. Push to repository 4. Update task tracker 5. Document any blockers ### 3. Code Review Process **Before Requesting Review:** - [ ] All tests passing - [ ] Code formatted and linted - [ ] No console errors - [ ] Documentation updated - [ ] Self-review completed **Review Checklist:** - [ ] Code follows style guide - [ ] Tests are comprehensive - [ ] No performance regressions - [ ] Edge cases handled - [ ] Documentation accurate --- ## Testing Strategy ### Unit Testing **Framework:** Jest (or your choice) **Test Structure:** ```javascript // tests/unit/pieces/Rook.test.js import { Rook } from '../../../js/pieces/Rook.js'; import { Board } from '../../../js/game/Board.js'; describe('Rook', () => { let board; beforeEach(() => { board = new Board(); board.clear(); // Start with empty board }); describe('getValidMoves', () => { it('should move vertically', () => { const rook = new Rook('white', {row: 4, col: 4}); board.setPiece(4, 4, rook); const moves = rook.getValidMoves(board); const verticalMoves = moves.filter(m => m.col === 4); expect(verticalMoves.length).toBe(7); }); it('should be blocked by friendly pieces', () => { const rook = new Rook('white', {row: 4, col: 4}); const blockingPawn = new Pawn('white', {row: 4, col: 6}); board.setPiece(4, 4, rook); board.setPiece(4, 6, blockingPawn); const moves = rook.getValidMoves(board); const rightMoves = moves.filter(m => m.row === 4 && m.col > 4); expect(rightMoves.length).toBe(1); // Only to col 5 }); it('should capture enemy pieces', () => { const rook = new Rook('white', {row: 4, col: 4}); const enemyPawn = new Pawn('black', {row: 4, col: 6}); board.setPiece(4, 4, rook); board.setPiece(4, 6, enemyPawn); const moves = rook.getValidMoves(board); const canCaptureEnemy = moves.some(m => m.row === 4 && m.col === 6 ); expect(canCaptureEnemy).toBe(true); }); }); }); ``` **Run Tests:** ```bash # Run all tests npm test # Run specific file npm test -- Rook.test.js # Run with coverage npm test -- --coverage # Watch mode npm test -- --watch ``` ### Integration Testing **Test Complete Scenarios:** ```javascript // tests/integration/gameplay.test.js describe('Complete Game Scenarios', () => { it('should handle Scholar\'s Mate', () => { const game = new ChessGame(); // Move sequence expect(game.makeMove(6, 4, 4, 4).success).toBe(true); // e4 expect(game.makeMove(1, 4, 3, 4).success).toBe(true); // e5 expect(game.makeMove(7, 5, 4, 2).success).toBe(true); // Bc4 expect(game.makeMove(1, 1, 2, 2).success).toBe(true); // Nc6 expect(game.makeMove(7, 3, 3, 7).success).toBe(true); // Qh5 expect(game.makeMove(1, 6, 2, 5).success).toBe(true); // Nf6 expect(game.makeMove(3, 7, 1, 5).success).toBe(true); // Qxf7# // Verify checkmate expect(game.status).toBe('checkmate'); expect(game.winner).toBe('white'); }); it('should handle stalemate', () => { const game = new ChessGame(); // Set up stalemate position game.board.fromFEN('7k/5Q2/6K1/8/8/8/8/8 b - - 0 1'); expect(game.isStalemate('black')).toBe(true); expect(game.status).toBe('stalemate'); }); }); ``` ### Manual Testing Checklist **Before Each Release:** - [ ] All piece types move correctly - [ ] Special moves work (castling, en passant, promotion) - [ ] Check detection accurate - [ ] Checkmate detection accurate - [ ] Stalemate detection accurate - [ ] UI responsive and intuitive - [ ] Save/load functionality works - [ ] Undo/redo works correctly - [ ] No console errors - [ ] Performance acceptable - [ ] Works in all target browsers --- ## Debugging Guide ### Browser Developer Tools **Console Debugging:** ```javascript // Add debug logging console.log('Move validation:', { piece: piece.type, from: {row: fromRow, col: fromCol}, to: {row: toRow, col: toCol}, valid: result }); // Use debugger statement function makeMove(fromRow, fromCol, toRow, toCol) { debugger; // Execution will pause here const piece = this.board.getPiece(fromRow, fromCol); // ... } // Group related logs console.group('Move Validation'); console.log('Piece:', piece); console.log('Valid moves:', validMoves); console.log('Target:', {toRow, toCol}); console.groupEnd(); ``` **Breakpoints:** 1. Open DevTools (F12) 2. Go to Sources tab 3. Find your file 4. Click line number to set breakpoint 5. Refresh page to trigger **Watch Expressions:** - Add `this.board.grid` to watch - Add `this.gameState.moveHistory` to watch - Add `this.currentTurn` to watch ### Common Issues and Solutions #### Issue: Infinite Recursion in Check Detection **Problem:** ```javascript // Bad: Causes infinite loop function isMoveLegal(board, piece, toRow, toCol) { const validMoves = piece.getValidMoves(board); // Calls isMoveLegal again! // ... } ``` **Solution:** ```javascript // Good: Separate concerns function getValidMoves(board, piece) { // Get moves without check validation } function getLegalMoves(board, piece) { // Filter valid moves by check constraint return getValidMoves(board, piece) .filter(move => !leavesKingInCheck(board, piece, move)); } ``` #### Issue: Drag and Drop Not Working **Checklist:** - [ ] Element has `draggable="true"` - [ ] Event listeners attached to correct elements - [ ] `dataTransfer` used correctly - [ ] `preventDefault()` called in `dragover` **Debug:** ```javascript boardElement.addEventListener('dragstart', (e) => { console.log('Drag started:', e.target); console.log('Data:', e.dataTransfer.getData('text/plain')); }); boardElement.addEventListener('dragover', (e) => { console.log('Drag over:', e.target); e.preventDefault(); // Don't forget this! }); ``` #### Issue: Pieces Not Rendering **Checklist:** - [ ] CSS classes applied correctly - [ ] Grid layout configured - [ ] Z-index issues - [ ] Unicode symbols or images loading **Debug:** ```javascript // Verify DOM structure console.log('Board HTML:', boardElement.innerHTML); console.log('Squares:', boardElement.querySelectorAll('.square').length); console.log('Pieces:', boardElement.querySelectorAll('.piece').length); ``` ### Performance Profiling **Using Chrome DevTools:** 1. Open DevTools → Performance tab 2. Click Record 3. Perform action (e.g., make move) 4. Stop recording 5. Analyze timeline **Identify Bottlenecks:** - Excessive DOM manipulation - Slow move validation - Memory leaks - Unnecessary re-renders **Solution:** ```javascript // Before: Slow function updateBoard() { boardElement.innerHTML = ''; // Triggers reflow for (let row = 0; row < 8; row++) { for (let col = 0; col < 8; col++) { // Create and append elements } } } // After: Fast function updateBoard() { const fragment = document.createDocumentFragment(); for (let row = 0; row < 8; row++) { for (let col = 0; col < 8; col++) { // Create elements and append to fragment } } boardElement.innerHTML = ''; boardElement.appendChild(fragment); // Single reflow } ``` --- ## Performance Optimization ### Minimize DOM Manipulation **Use Document Fragments:** ```javascript const fragment = document.createDocumentFragment(); // Add all elements to fragment container.appendChild(fragment); // Single DOM update ``` **Batch Updates:** ```javascript // Bad: Multiple reflows element.style.width = '100px'; element.style.height = '100px'; element.style.backgroundColor = 'red'; // Good: Single reflow element.style.cssText = 'width: 100px; height: 100px; background-color: red;'; ``` ### Memoize Expensive Calculations ```javascript class Piece { constructor() { this._validMovesCache = null; this._cacheValidUntil = null; } getValidMoves(board) { const boardHash = board.getHash(); if (this._cacheValidUntil === boardHash) { return this._validMovesCache; } // Calculate moves this._validMovesCache = this.calculateValidMoves(board); this._cacheValidUntil = boardHash; return this._validMovesCache; } invalidateCache() { this._validMovesCache = null; this._cacheValidUntil = null; } } ``` ### Debounce UI Updates ```javascript function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // Usage const updateUI = debounce(() => { renderer.renderBoard(game.board, game.gameState); }, 100); ``` ### Optimize Event Handlers **Use Event Delegation:** ```javascript // Bad: Many listeners squares.forEach(square => { square.addEventListener('click', handleClick); }); // Good: Single listener boardElement.addEventListener('click', (e) => { const square = e.target.closest('.square'); if (square) { handleClick(square); } }); ``` --- ## Code Style Guide ### Naming Conventions **Variables:** ```javascript // camelCase for variables and functions const currentTurn = 'white'; const isKingInCheck = true; function makeMove(from, to) { } ``` **Classes:** ```javascript // PascalCase for classes class ChessGame { } class MoveValidator { } ``` **Constants:** ```javascript // UPPER_SNAKE_CASE for constants const MAX_MOVES = 500; const DEFAULT_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'; ``` **Private Members:** ```javascript // Prefix with underscore class Piece { constructor() { this._cachedMoves = null; } } ``` ### File Organization **One class per file:** ```javascript // Good: Rook.js export class Rook extends Piece { // ... } // Bad: pieces.js with all pieces export class Rook { } export class Bishop { } export class Knight { } ``` **Related functions can be grouped:** ```javascript // utils/helpers.js export function clamp(value, min, max) { } export function isInBounds(row, col) { } export function getOppositeColor(color) { } ``` ### Documentation **JSDoc Comments:** ```javascript /** * Validates if a move is legal according to chess rules * * @param {Board} board - The current board state * @param {Piece} piece - The piece to move * @param {number} toRow - Target row (0-7) * @param {number} toCol - Target column (0-7) * @param {GameState} gameState - Current game state * @returns {boolean} True if move is legal */ static isMoveLegal(board, piece, toRow, toCol, gameState) { // ... } ``` ### Error Handling **Use descriptive errors:** ```javascript // Good if (!piece) { throw new Error(`No piece found at position (${row}, ${col})`); } // Bad if (!piece) { throw new Error('Invalid'); } ``` **Return result objects:** ```javascript function makeMove(from, to) { if (!isValid) { return { success: false, error: 'Invalid move: piece cannot move there' }; } return { success: true, move: executedMove }; } ``` --- ## Deployment ### Pre-Deployment Checklist - [ ] All tests passing - [ ] No console errors - [ ] Code minified (optional) - [ ] Assets optimized - [ ] Browser compatibility tested - [ ] Performance acceptable - [ ] Documentation updated ### Build Process (Optional) If using build tools: ```bash # Install build tools npm install --save-dev webpack webpack-cli # Create webpack.config.js # Build for production npm run build ``` ### Static Hosting **GitHub Pages:** ```bash # Create gh-pages branch git checkout -b gh-pages # Push to GitHub git push origin gh-pages # Access at: https://username.github.io/chess-game ``` **Netlify:** 1. Connect GitHub repository 2. Set build command (if any) 3. Set publish directory 4. Deploy **Vercel:** ```bash npm install -g vercel vercel deploy ``` ### Performance Optimization for Production **Minify CSS/JS:** ```bash # CSS npx cssnano css/board.css > dist/board.min.css # JS npx terser js/main.js -o dist/main.min.js ``` **Optimize Images:** - Use SVG for piece images (scalable) - Compress PNG/JPG if used - Use appropriate formats **Enable Compression:** ``` # .htaccess for Apache AddOutputFilterByType DEFLATE text/html text/css application/javascript ``` --- ## Troubleshooting ### Common Errors **"Uncaught TypeError: Cannot read property 'grid' of undefined"** - Board not initialized - Check constructor calls - Verify import statements **"Maximum call stack size exceeded"** - Infinite recursion - Check move validation logic - Verify event listener cleanup **Drag and drop not working** - Check draggable attribute - Verify event listeners - Call preventDefault() in dragover ### Getting Help 1. Check documentation 2. Review API reference 3. Search existing issues 4. Ask specific questions with code samples --- **Next:** See [HANDOFF_CHECKLIST.md](HANDOFF_CHECKLIST.md) for implementation timeline