chess/docs/architecture/data-models.md
Christoph Wagner 5ad0700b41 refactor: Consolidate repository structure - flatten from workspace pattern
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>
2025-11-23 10:05:26 +01:00

11 KiB
Raw Permalink Blame History

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.