Skip to content

Cyrus-Krispin/gambitron

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

82 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ† Gambitron

Gambitron Demo

Play vs Gambitron

Chess AI Β· Minimax & Ξ±Ξ² pruning Β· WebSocket Β· Game history

React TypeScript Python FastAPI


Architecture Overview

flowchart TB
    subgraph Frontend["Frontend (Vercel)"]
        Landing["Landing /"]
        Play["Play /play/:id"]
        History["History /history"]
        Replay["Replay /history/:gameId"]
    end

    subgraph Transport["Transport"]
        WS["WebSocket wss://"]
        REST["REST https://"]
    end

    subgraph Backend["Backend (EC2 / FastAPI)"]
        subgraph WSModule["WebSocket /ws"]
            Handlers["handlers: start_game β†’ player_move β†’ AI β†’ ai_move"]
            ConnMgr["connection_manager: game_id β†’ subscriptions"]
            Timers["timers: 100ms tick β†’ time_update β†’ timeout"]
        end
        subgraph RESTModule["REST"]
            Health["GET /health"]
            Games["GET /games, /games/:id"]
            Moves["GET /games/:id/moves"]
            Legacy["POST / (legacy FEN→AI)"]
        end
        Engine["chess_engine: get_best_move, minimax, Ξ±Ξ²"]
    end

    subgraph DB["Database (PostgreSQL)"]
        Games["games: id, created_at, ended_at, result, pgn"]
    end

    Landing --> Transport
    Play --> Transport
    History --> REST
    Replay --> REST
    Transport --> Backend
    Backend --> DB
Loading

1.0 β†’ 1.1 Architecture Migration

1.0 Architecture (Legacy)

flowchart LR
    subgraph Client["React Frontend (Vercel)"]
        FE["localStorage, Client timers, No history"]
    end

    subgraph AWS["AWS"]
        APIGW["API Gateway REST"]
        Lambda["AWS Lambda 30s timeout"]
    end

    Client -->|"POST ?value=FEN"| APIGW
    APIGW --> Lambda
    Lambda -->|"{updated_fen, result}"| Client
Loading
  • ❌ 30s API Gateway timeout
  • ❌ No game history / replay
  • ❌ Stateless: every move = new HTTP request
  • ❌ Client-owned timers (could desync)
  • ❌ No reconnection / session recovery

1.1 Architecture (Current)

flowchart TB
    subgraph Client["React Frontend (Vercel)"]
        C["Game history, Replay, Reconnect, White or Black"]
    end

    subgraph Backend["EC2 + FastAPI"]
        B["WebSocket /ws, REST /games, Backend timers, No timeout"]
    end

    subgraph DB["PostgreSQL"]
        D["games + pgn"]
    end

    Client <-->|"WebSocket: start_game, player_move, ai_move, time_update"| Backend
    Client -->|"GET /games, /games/:id/moves"| Backend
    Backend --> DB
Loading
  • βœ… No timeout (persistent connection)
  • βœ… Game history + replay (PGN)
  • βœ… Server-owned timers (authoritative)
  • βœ… Reconnect + subscribe for session recovery
  • βœ… Play as White or Black (request_ai_move for Black)
  • βœ… Capture display, material diff
  • βœ… Admin panel (REST fallback)

Migration Summary

Aspect 1.0 1.1
Transport REST POST per move WebSocket (bidirectional)
Backend AWS Lambda EC2 + FastAPI
Timeout 30s (API Gateway) None (persistent)
Game state Client only (localStorage) Server + DB
Timers Client (setInterval) Server (100ms tick, broadcast)
History None GET /games, replay from PGN
Reconnect N/A subscribe + game_state
Color choice White only White or Black

Data Flow Diagrams

WebSocket Message Flow

sequenceDiagram
    participant C as Client
    participant S as Server

    C->>S: start_game {timeControlMs, playerColor}
    S->>S: INSERT games, register_game (timers)
    S->>C: game_started {gameId, fen}

    opt Player is Black
        C->>S: request_ai_move {gameId, fen}
        S->>S: AI β†’ append_move
        S->>C: ai_move {updatedFen, san}
    end

    C->>S: player_move {gameId, fen, san, from, to}
    S->>S: append_move (player)
    S->>S: AI (thread pool)
    S->>S: append_move (AI)
    S->>C: ai_move {updatedFen}

    loop Every 100ms
        S->>C: time_update {playerTimeMs, aiTimeMs}
    end

    opt On timeout/checkmate
        S->>S: finalize_game_to_pgn, UPDATE games
        S->>C: game_ended
    end
Loading

Backend Component Diagram

flowchart TB
    Main["main.py (FastAPI)"]

    subgraph Endpoints["Endpoints"]
        WS["/ws endpoint"]
        REST["REST routes"]
        Timer["_timer_loop"]
    end

    subgraph WSFlow["WebSocket Flow"]
        HM["handle_message"]
        Handlers["handlers: start_game, player_move, promotion_move, request_ai_move, subscribe"]
        Engine["chess_engine"]
    end

    subgraph RESTFlow["REST Flow"]
        GamesDB["games_db"]
        MovesDB["moves_db"]
    end

    subgraph TimerFlow["Timer Flow"]
        Tick["timers.tick_all"]
        Broadcast["broadcast_to_game"]
        ConnMgr["connection_manager: subscribe, broadcast, on_disconnect"]
    end

    Main --> WS
    Main --> REST
    Main --> Timer
    WS --> HM
    HM --> Handlers
    Handlers --> Engine
    REST --> GamesDB
    REST --> MovesDB
    Timer --> Tick
    Tick --> Broadcast
    Broadcast --> ConnMgr
Loading

Frontend Structure

frontend/src/
β”œβ”€β”€ App.tsx                 # Routes: /, /play/:id, /history, /history/:id, /about, /admin
β”œβ”€β”€ hooks/
β”‚   └── useGame.ts         # WebSocket client, game state, timers, move handling
β”œβ”€β”€ lib/
β”‚   └── websocket.ts       # createReconnectingSocket, sendMessage, types
β”œβ”€β”€ pages/
β”‚   β”œβ”€β”€ Landing.tsx        # Time control + color pick β†’ /play/new?minutes=&color=
β”‚   β”œβ”€β”€ Play.tsx           # ChessBoard, TimerCard, CaptureDisplay, Dialogs
β”‚   β”œβ”€β”€ History.tsx        # GET /games β†’ list β†’ link to /history/:id
β”‚   β”œβ”€β”€ Replay.tsx         # GET /games/:id/moves β†’ step-through replay
β”‚   β”œβ”€β”€ About.tsx          # Architecture, tech stack
β”‚   └── Game.tsx           # Admin: FEN loader, REST fallback
└── components/
    β”œβ”€β”€ ChessBoard.tsx     # 8Γ—8 grid, piece rendering, click-to-move
    β”œβ”€β”€ ChessPiece.tsx     # Piece SVG, drag state
    β”œβ”€β”€ TimerCard.tsx      # MM:SS countdown, active state
    β”œβ”€β”€ CaptureDisplay.tsx  # Captured pieces, material diff
    β”œβ”€β”€ Dialogs.tsx        # Promotion, endgame, error
    └── Layout.tsx         # Header nav (History, About)

Backend Structure

backend/
β”œβ”€β”€ main.py                # FastAPI, CORS, /ws, REST, startup/shutdown
β”œβ”€β”€ chess_engine.py        # get_best_move(fen), minimax, evaluate
β”œβ”€β”€ config.py              # ALLOWED_ORIGINS, DATABASE_URL, PGN_STORAGE_DIR
β”œβ”€β”€ db/
β”‚   β”œβ”€β”€ connection.py      # asyncpg pool, create_pool, close_pool
β”‚   β”œβ”€β”€ games.py           # create_game, get_game, list_games, update_game_ended
β”‚   └── moves.py           # append_move, get_moves_by_game, finalize_game_to_pgn
β”œβ”€β”€ websocket/
β”‚   β”œβ”€β”€ handlers.py        # handle_start_game, player_move, promotion_move,
β”‚   β”‚                     # request_ai_move, subscribe, handle_message
β”‚   β”œβ”€β”€ connection_manager.py  # subscribe, unsubscribe, broadcast_to_game
β”‚   └── timers.py          # register_game, tick_all, apply_elapsed, timeout
└── migrations/
    └── schema.sql         # games table

AI Engine (chess_engine.py)

flowchart TB
    Start["get_best_move(fen)"]
    Board["chess.Board(fen)"]
    Check{"is_game_over? no legal moves?"}
    Return1["return / 400"]
    Minimax["minimax depth=3, Ξ±Ξ² pruning"]
    Eval["evaluate_board_state"]
    Return2["return {updated_fen, result, san, from_square, to_square, captured}"]

    Start --> Board
    Board --> Check
    Check -->|yes| Return1
    Check -->|no| Minimax
    Minimax --> Eval
    Eval --> Return2

    subgraph EvalDetails["Evaluation"]
        M["material P=100 N=320 B=330 R=500 Q=900 K=20000"]
        PST["piece-square tables"]
        CC["center control"]
        PA["pawn advancement"]
        BP["bishop pair"]
        RM["rook mobility"]
        KS["king safety"]
    end
Loading

Quick Start

# Frontend
cd frontend && npm install && npm run dev

# Backend
cd backend && python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
fastapi dev main.py

Env: VITE_backend, VITE_WS_URL (frontend); DATABASE_URL, ALLOWED_ORIGINS (backend).


License

MIT

About

πŸ€– AI Chess Bot | ⚑ AWS Lambda | 🧠 Minimax Algorithm | βš›οΈ React | πŸ† Real-time Gameplay

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors