Files
connect_four_pico/CLAUDE.md
T
2026-03-27 15:37:18 +01:00

4.9 KiB

Connect Four Pico 2W

Embedded Connect Four game with AI, running on a Raspberry Pi Pico 2W with a PicoResTouch-LCD-2.8 touchscreen (2.8" TFT + resistive touch).

Build & Upload

# Build
pio run

# Upload to board
pio run --target upload

# Monitor serial output
pio device monitor

Requires PlatformIO CLI. The project uses the Arduino framework (earlephilhower core).

Project Structure

src/
  config.h        — Pin definitions, layout constants, colors, game defaults
  game.h / .cpp   — State enum, shared globals, board helpers, AI (minimax), game logic
  touch.h / .cpp  — XPT2046 raw reads, touch events, calibration
  storage.h / .cpp — EEPROM persistence (calibration, settings, game log)
  display.h / .cpp — All TFT drawing (board, menu, status, settings UI, game log UI)
  main.cpp         — setup(), loop(), state dispatch

Other files:

  • platformio.ini — Build configuration and tunable parameters
  • connect_four.js / connect_four.html — Browser edition (standalone, identical AI)
  • README.md — Technical and practical documentation
  • Background information.md — AI strategy explanation (accessible to all ages)

Key Technical Details

  • Hardware: Raspberry Pi Pico 2W (RP2350), PicoResTouch-LCD-2.8 (ST7789 TFT 320x240, XPT2046 resistive touch)
  • AI: Minimax with alpha-beta pruning, three-phase move strategy (instant win/block, blunder, deep search)
  • Display: Adafruit_ST7789 + Adafruit_GFX via SPI1, portrait mode (240x320), dark theme matching the JS canvas implementation
  • Touch: Raw XPT2046 SPI reads (shared SPI1 bus with display). Calibration on first boot, stored in EEPROM. Hold touch during boot to recalibrate.
  • Persistence: Settings and game log stored in EEPROM (flash-backed). Survives reboots.
  • Build flags: Tunable game parameters defined as -D flags in platformio.ini
  • Dependencies: Adafruit ST7735/ST7789 Library, Adafruit GFX Library, EEPROM + SPI (built-in)

Module Responsibilities

  • config.h: Constants only. No state, no functions. All pin defs, layout, colors, defaults.
  • game.h/cpp: Owns all shared globals (board, gameState, tft, etc.) as extern/definitions. Board helpers, scanBoard, evaluateBoard, minimax, computeAiMove.
  • touch.h/cpp: Owns touch calibration globals. readRawTouch, getTouchDown, colFromTouch, menuItemFromTouch, calibrateTouch.
  • storage.h/cpp: EEPROM layout defines. save/load for calibration, settings, game log. logGame, clearGameLog.
  • display.h/cpp: All drawing. drawCell, drawBoardFull, drawMenu, drawSettings, drawGameLogScreen, animateDrop. Settings/game log touch handlers.
  • main.cpp: setup, loop, state handlers (startGame, returnToMenu, startDemo, handleAiTurn, handleDemoStep, handleFlash).

Conventions

  • Naming: camelCase for all variables and functions
  • Game states: Use enum names (MENU, PLAYING, AI_TURN, FINISHED_WIN, FINISHED_DRAW, DEMO, SETTINGS, GAME_LOG), never magic numbers
  • Player colors: Use playerColor(player) helper, never inline color constants directly
  • Board reset: Use resetBoard(), never bare memset(board, 0, sizeof(board))
  • Column priority: Use the shared colOrder[] constant, never duplicate {3, 2, 4, 1, 5, 0, 6}
  • Duplicate logic: The win/draw/log check is handled by checkGameEnd() — do not duplicate this pattern
  • Colors: RGB565 constants prefixed with C_, derived from the JS canvas palette via the C565(r,g,b) macro

Display Layout (portrait 240x320)

  • Cell size: 32px, disc radius: 13px
  • Board origin: (8, 56), board size: 224x192
  • Column numbers at y=44, status text at y=254, sub-status at y=278
  • Board background with rounded corners, grid lines between cells, circular discs in cells

Demo Mode

Demo uses asymmetric ply depths (demoPly[0] and demoPly[1]) randomized at each demo game start via randomizeDemoPlies(). This ensures games produce winners rather than draws while still looking strategic.

Game Log

  • Stored as GameEntry structs (type, level, winner, moves), not as formatted strings
  • Persisted to EEPROM after each game via saveGameLog() / loadGameLog()
  • Viewable on-device via Settings > View Game Log (paginated, newest first)
  • Max entries configurable via MAX_GAME_LOG build flag
  • Player wins highlighted in red

Settings Menu

Accessible from the main menu (4th item). Allows adjusting:

  • AI Ply depth (1-10)
  • Blunder mode ON/OFF
  • Blunder chance (5-100%, step 5)
  • View Game Log (paginated, with clear option)
  • Recalibrate touch screen

Settings are persisted to EEPROM on exit.

EEPROM Layout

  • Offset 0: Touch calibration magic + data (9 bytes)
  • Offset 9: Settings magic + lookAhead, blunderEnabled, blunderChance, gameLogCount (5+1 bytes)
  • Offset 16+: Game log entries (46 bytes each)

Commit Style

Follow the existing pattern: [type] Description. where type is fix, update, add, or refactor.