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>
20 KiB
Chess Rules Reference
Table of Contents
- Game Objective
- Board Setup
- Piece Movement
- Special Moves
- Check and Checkmate
- Draw Conditions
- Chess Notation
- Rule Edge Cases
Game Objective
Chess is a two-player strategy game where the objective is to checkmate the opponent's king.
- Checkmate: The king is under attack (in check) and cannot escape
- Win Conditions: Checkmate or opponent resignation
- Draw Conditions: Stalemate, insufficient material, threefold repetition, fifty-move rule, or agreement
Board Setup
Board Orientation
- 8x8 grid with alternating light and dark squares
- Bottom-right square from each player's perspective is a light square
- Ranks (rows) numbered 1-8, files (columns) labeled a-h
- White pieces start on ranks 1-2, black on ranks 7-8
Initial Position
a b c d e f g h
8 ♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜ 8
7 ♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟ 7
6 · · · · · · · · 6
5 · · · · · · · · 5
4 · · · · · · · · 4
3 · · · · · · · · 3
2 ♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙ 2
1 ♖ ♘ ♗ ♕ ♔ ♗ ♘ ♖ 1
a b c d e f g h
FEN Notation: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
Piece Placement
White (bottom):
- a1, h1: Rooks (♖)
- b1, g1: Knights (♘)
- c1, f1: Bishops (♗)
- d1: Queen (♕)
- e1: King (♔)
- a2-h2: Pawns (♙)
Black (top):
- a8, h8: Rooks (♜)
- b8, g8: Knights (♞)
- c8, f8: Bishops (♝)
- d8: Queen (♛)
- e8: King (♚)
- a7-h7: Pawns (♟)
Mnemonic: "Queen on her own color" (white queen on light square, black queen on dark square)
Piece Movement
Pawn (♙ ♟)
Basic Movement:
- Moves forward one square
- From starting position, can move forward two squares
- Captures diagonally forward one square
- Cannot move backward
Special Rules:
- Can only capture diagonally (not straight ahead)
- Blocked if square directly ahead is occupied
- See En Passant and Promotion
Diagram:
· · · · · · · ·
· · ♟ · ♟ · · · ← Can capture here
· · · ♙ · · · · ← Pawn position
· · · ↑ · · · · ← Can move here
· · · ↑ · · · · ← Can move here (if first move)
Implementation Note:
- White pawns move up (decreasing row), black pawns move down (increasing row)
- Starting rank: white on row 6, black on row 1
- Promotion rank: white on row 0, black on row 7
Knight (♘ ♞)
Movement Pattern:
- L-shaped: 2 squares in one direction, 1 square perpendicular
- Can jump over other pieces
- 8 possible moves maximum (if not blocked)
Movement Offsets:
(-2, -1) (-2, +1)
↖ ↗
(-1,-2) ♘ (-1,+2)
↙ ↘
(+1,-2) (+1,+2)
↖ ↗
(+2, -1) (+2, +1)
Diagram:
· · X · X · · ·
· X · · · X · ·
· · · ♘ · · · ·
· X · · · X · ·
· · X · X · · ·
Implementation:
const knightMoves = [
[-2, -1], [-2, 1], [-1, -2], [-1, 2],
[1, -2], [1, 2], [2, -1], [2, 1]
];
Bishop (♗ ♝)
Movement Pattern:
- Any number of squares diagonally
- Cannot jump over pieces
- Stays on same color squares entire game
Diagram:
X · · · · · · ·
· X · · · · · X
· · X · · · X ·
· · · ♗ · X · ·
· · · · X · · ·
· · · X · · · ·
Implementation:
const bishopDirections = [
[-1, -1], // up-left
[-1, +1], // up-right
[+1, -1], // down-left
[+1, +1] // down-right
];
Rook (♖ ♜)
Movement Pattern:
- Any number of squares horizontally or vertically
- Cannot jump over pieces
- Involved in castling (see Castling)
Diagram:
· · · X · · · ·
· · · X · · · ·
· · · X · · · ·
X X X ♖ X X X X
· · · X · · · ·
· · · X · · · ·
Implementation:
const rookDirections = [
[-1, 0], // up
[+1, 0], // down
[0, -1], // left
[0, +1] // right
];
Queen (♕ ♛)
Movement Pattern:
- Combines rook and bishop movement
- Any number of squares in any direction
- Cannot jump over pieces
- Most powerful piece
Diagram:
X · · X · · · X
· X · X · · X ·
· · X X · X · ·
X X X ♕ X X X X
· · X X · X · ·
· X · X · · X ·
Implementation:
const queenDirections = [
[-1, -1], [-1, 0], [-1, +1],
[0, -1], [0, +1],
[+1, -1], [+1, 0], [+1, +1]
];
King (♔ ♚)
Movement Pattern:
- One square in any direction
- Cannot move into check
- Involved in castling (see Castling)
Diagram:
· · · · · · · ·
· · X X X · · ·
· · X ♔ X · · ·
· · X X X · · ·
Implementation:
const kingMoves = [
[-1, -1], [-1, 0], [-1, +1],
[0, -1], [0, +1],
[+1, -1], [+1, 0], [+1, +1]
];
Critical Rules:
- Cannot move into check (square attacked by opponent)
- Cannot castle out of, through, or into check
- Most important piece (game ends if checkmated)
Special Moves
Castling
Purpose: Protect king and activate rook
Types:
- Kingside Castling (O-O): King moves two squares toward h-file rook
- Queenside Castling (O-O-O): King moves two squares toward a-file rook
Conditions (ALL must be met):
- Neither king nor rook has moved previously
- No pieces between king and rook
- King is not in check
- King does not pass through check
- King does not end up in check
Kingside Castling (White):
Before: · · · · ♔ · · ♖
After: · · · · · ♖ ♔ ·
e1 → g1, h1 → f1
Queenside Castling (White):
Before: ♖ · · · ♔ · · ·
After: · · ♔ ♖ · · · ·
e1 → c1, a1 → d1
Implementation Logic:
function canCastle(king, rook, board) {
// 1. Check if pieces have moved
if (king.hasMoved || rook.hasMoved) return false;
// 2. Check if path is clear
const [minCol, maxCol] = [
Math.min(king.col, rook.col),
Math.max(king.col, rook.col)
];
for (let col = minCol + 1; col < maxCol; col++) {
if (board.getPiece(king.row, col)) return false;
}
// 3. Check if king is in check
if (isKingInCheck(board, king.color)) return false;
// 4. Check if king passes through check
const direction = rook.col > king.col ? 1 : -1;
for (let i = 1; i <= 2; i++) {
const testCol = king.col + (direction * i);
if (isSquareUnderAttack(board, king.row, testCol, opponentColor)) {
return false;
}
}
return true;
}
En Passant
Purpose: Prevent pawns from avoiding capture by double-stepping
Condition:
- Opponent pawn moves two squares from starting position
- Lands beside your pawn (same rank)
- You can capture it as if it moved only one square
- Must be done immediately (next move only)
Diagram:
Before: After capture:
· · · · · · · · · · · · · · · ·
♟ · ♟ · · · · · · · ♟ · · · · ·
· ♙ · · · · · · · · ♙ · · · · · ← White pawn captures
♙ · · · · · · · · · · · · · · ·
FEN Notation:
- En passant target square recorded in FEN
- Example:
...w KQkq e6...(e6 is en passant target)
Implementation:
function canEnPassant(pawn, targetCol, gameState) {
// Must be on correct rank
const correctRank = pawn.color === 'white' ? 3 : 4;
if (pawn.row !== correctRank) return false;
// Check last move
const lastMove = gameState.getLastMove();
if (!lastMove || lastMove.piece.type !== 'pawn') return false;
// Must have moved two squares
const moveDistance = Math.abs(lastMove.to.row - lastMove.from.row);
if (moveDistance !== 2) return false;
// Must be adjacent
return Math.abs(pawn.col - targetCol) === 1 &&
lastMove.to.col === targetCol &&
lastMove.to.row === pawn.row;
}
function executeEnPassant(board, pawn, targetRow, targetCol) {
// Remove captured pawn
const capturedPawn = board.getPiece(pawn.row, targetCol);
board.setPiece(pawn.row, targetCol, null);
// Move attacking pawn
board.movePiece(pawn.row, pawn.col, targetRow, targetCol);
return capturedPawn;
}
Pawn Promotion
Condition: Pawn reaches the opposite end of the board (rank 8 for white, rank 1 for black)
Options: Can promote to:
- Queen (most common)
- Rook
- Bishop
- Knight
- Cannot promote to King or Pawn
Notation:
e8=Q- Pawn to e8, promotes to queenaxb8=N+- Pawn captures on b8, promotes to knight with check
Diagram:
♟ · · · · · · · ← Black pawn about to promote
· · · · · · · ·
...
♙ · · · · · · · ← White pawn about to promote
Implementation:
function canPromote(pawn) {
const promotionRank = pawn.color === 'white' ? 0 : 7;
return pawn.row === promotionRank;
}
function promote(board, pawn, pieceType) {
// pieceType: 'queen', 'rook', 'bishop', 'knight'
const PieceClass = getPieceClass(pieceType);
const newPiece = new PieceClass(pawn.color, pawn.position);
board.setPiece(pawn.row, pawn.col, newPiece);
return newPiece;
}
UI Consideration: Show dialog for player to choose promotion piece
Check and Checkmate
Check
Definition: King is under direct attack by opponent piece
Rules:
- Player in check must get out of check
- Cannot make any move that leaves king in check
- Must respond with one of three options:
- Move king to safe square
- Block the attack
- Capture the attacking piece
Notation: Add + to move notation (e.g., Qh5+)
Implementation:
function isKingInCheck(board, color) {
// Find king position
const kingPos = findKing(board, color);
if (!kingPos) return false; // Should never happen
// Check if any opponent piece attacks king square
for (let row = 0; row < 8; row++) {
for (let col = 0; col < 8; col++) {
const piece = board.getPiece(row, col);
if (piece && piece.color !== color) {
const moves = piece.getValidMoves(board);
if (moves.some(m => m.row === kingPos.row && m.col === kingPos.col)) {
return true;
}
}
}
}
return false;
}
Checkmate
Definition: King is in check and cannot escape
Conditions:
- King is in check
- King cannot move to safe square
- No piece can block the attack
- Attacking piece cannot be captured
Notation: Add # to move notation (e.g., Qf7#)
Result: Game ends, attacking player wins
Famous Checkmate Patterns:
Scholar's Mate (4 moves):
1. e4 e5
2. Bc4 Nc6
3. Qh5 Nf6??
4. Qxf7# (checkmate)
Back Rank Mate:
a b c d e f g h
8 · · · · · ♜ ♚ · 8 ← King trapped by own pawns
7 · · · · · ♟ ♟ ♟ 7
Implementation:
function isCheckmate(board, color) {
// Must be in check
if (!isKingInCheck(board, color)) {
return false;
}
// Check if any legal move exists
for (let row = 0; row < 8; row++) {
for (let col = 0; col < 8; col++) {
const piece = board.getPiece(row, col);
if (piece && piece.color === color) {
const moves = piece.getValidMoves(board);
for (const move of moves) {
// Simulate move
const testBoard = board.clone();
testBoard.movePiece(row, col, move.row, move.col);
// If king no longer in check, not checkmate
if (!isKingInCheck(testBoard, color)) {
return false;
}
}
}
}
}
// No legal moves available
return true;
}
Draw Conditions
Stalemate
Definition: Player has no legal moves but is NOT in check
Result: Game is a draw
Diagram:
a b c d e f g h
8 · · · · · · ♔ · 8
7 · · · · · ♕ · · 7
6 · · · · · · · ♚ 6 ← Black king, not in check
Black to move has no legal moves → Stalemate
Implementation:
function isStalemate(board, color) {
// Must NOT be in check
if (isKingInCheck(board, color)) {
return false;
}
// But has no legal moves
return !hasAnyLegalMove(board, color);
}
Insufficient Material
Definition: Neither player has enough pieces to force checkmate
Automatic Draw Conditions:
- King vs King
- King + Bishop vs King
- King + Knight vs King
- King + Bishop vs King + Bishop (same color squares)
Not Automatic Draw (checkmate still possible):
- King + Rook vs King
- King + Queen vs King
- King + Pawn vs King
- King + 2 Knights vs King (very rare, but possible)
Implementation:
function isInsufficientMaterial(board) {
const pieces = getAllPieces(board);
// King vs King
if (pieces.length === 2) return true;
// King + Minor piece vs King
if (pieces.length === 3) {
return pieces.some(p => p.type === 'bishop' || p.type === 'knight');
}
// King + Bishop vs King + Bishop (same color)
if (pieces.length === 4) {
const bishops = pieces.filter(p => p.type === 'bishop');
if (bishops.length === 2) {
return (bishops[0].position.row + bishops[0].position.col) % 2 ===
(bishops[1].position.row + bishops[1].position.col) % 2;
}
}
return false;
}
Threefold Repetition
Definition: Same position occurs three times (not necessarily consecutive)
Criteria for "same position":
- Same pieces on same squares
- Same player to move
- Same castling rights
- Same en passant availability
Claim: Player can claim draw when position repeats third time
Implementation:
function isThreefoldRepetition(gameState) {
const currentFEN = gameState.toFEN();
const fenHistory = gameState.moveHistory.map(m => m.fen);
let count = 0;
for (const fen of fenHistory) {
if (fen === currentFEN) {
count++;
if (count >= 3) return true;
}
}
return false;
}
Fifty-Move Rule
Definition: 50 consecutive moves by each player with no pawn move or capture
Counter: Reset to 0 when:
- Any pawn moves
- Any piece is captured
Claim: Player can claim draw after 50 moves
Implementation:
function isFiftyMoveRule(gameState) {
return gameState.halfMoveClock >= 100; // 50 moves per player
}
Draw by Agreement
Process:
- Player offers draw
- Opponent can accept or decline
- If accepted, game ends in draw
Notation: ½-½ in PGN
Chess Notation
Algebraic Notation (Standard)
Format: [Piece][From Square][Capture][To Square][Promotion][Check/Checkmate]
Pieces:
- K = King
- Q = Queen
- R = Rook
- B = Bishop
- N = Knight
- (no letter) = Pawn
Examples:
e4- Pawn to e4Nf3- Knight to f3Bxc6- Bishop captures on c6Qh5+- Queen to h5, checke8=Q#- Pawn to e8, promotes to queen, checkmateO-O- Kingside castlingO-O-O- Queenside castlingNbd7- Knight from b-file to d7 (disambiguation)
Disambiguation: When two pieces of same type can move to same square:
- Add file letter:
Nbd7(knight from b-file) - Add rank number:
R1e2(rook from rank 1) - Add both if needed:
Qh4e1
FEN (Forsyth-Edwards Notation)
Purpose: Represent board position in single string
Format: [Position] [Turn] [Castling] [En Passant] [Halfmove] [Fullmove]
Example:
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
Components:
-
Position (ranks 8-1, separated by
/):- Lowercase = black pieces
- Uppercase = white pieces
- Numbers = empty squares
/= next rank
-
Turn:
w= white to moveb= black to move
-
Castling Rights:
K= white kingsideQ= white queensidek= black kingsideq= black queenside-= no castling available
-
En Passant:
- Target square (e.g.,
e3) -if not available
- Target square (e.g.,
-
Halfmove Clock:
- Moves since last capture/pawn move
-
Fullmove Number:
- Increments after black's move
Implementation:
function toFEN(board, gameState, currentTurn) {
let fen = '';
// Position
for (let row = 0; row < 8; row++) {
let emptyCount = 0;
for (let col = 0; col < 8; col++) {
const piece = board.getPiece(row, col);
if (piece) {
if (emptyCount > 0) {
fen += emptyCount;
emptyCount = 0;
}
fen += piece.toFENChar();
} else {
emptyCount++;
}
}
if (emptyCount > 0) fen += emptyCount;
if (row < 7) fen += '/';
}
// Turn
fen += ` ${currentTurn[0]}`;
// Castling
fen += ` ${gameState.castlingRights || '-'}`;
// En passant
fen += ` ${gameState.enPassantTarget || '-'}`;
// Clocks
fen += ` ${gameState.halfMoveClock} ${gameState.fullMoveNumber}`;
return fen;
}
PGN (Portable Game Notation)
Purpose: Record complete game with metadata
Format:
[Event "Casual Game"]
[Site "Online"]
[Date "2025.01.22"]
[Round "1"]
[White "Player 1"]
[Black "Player 2"]
[Result "1-0"]
1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7
6. Re1 b5 7. Bb3 d6 8. c3 O-O 9. h3 Nb8 1-0
Results:
1-0- White wins0-1- Black wins1/2-1/2- Draw*- Game in progress
Rule Edge Cases
Illegal Positions
Positions that cannot occur:
- Both kings in check simultaneously
- Pawn on rank 1 or 8 (must have promoted)
- More than 8 pawns of one color
- More than 16 pieces of one color total
- Castling when king/rook has moved
Ambiguous Captures
When multiple pieces can capture same square:
Raxe1 // Rook from a-file captures
R1xe1 // Rook from rank 1 captures
Qh4e1 // Queen from h4 captures (needs both)
Pawn Captures and Files
Pawn captures include file letter:
exd5 // Pawn from e-file captures on d5
e4 // Pawn moves to e4 (no capture)
Check and Illegal Moves
Invalid moves:
- Moving into check
- Not responding to check
- Exposing own king to check
All must be prevented in implementation!
Implementation Checklist
Use this checklist to validate your chess implementation:
Basic Movement
- All pieces move according to rules
- Pieces cannot move through others (except knight)
- Pieces cannot capture own color
- Pawns move forward only
- Pawns capture diagonally
Special Moves
- Pawn double-move from start
- En passant capture
- En passant expires after one turn
- Castling kingside
- Castling queenside
- Castling prevented by moved pieces
- Cannot castle through check
- Cannot castle in/out of check
- Pawn promotion
- Pawn promotion piece selection
Check/Checkmate
- Detect when king is in check
- Prevent moves that leave king in check
- Force response to check
- Detect checkmate
- Detect stalemate
Draw Conditions
- Insufficient material
- Threefold repetition
- Fifty-move rule
- Draw by agreement
Notation
- FEN export
- FEN import
- PGN export
- Algebraic notation for moves
- Move disambiguation
For implementation details, see IMPLEMENTATION_GUIDE.md
For API reference, see API_REFERENCE.md