Files
2026-03-27 15:37:18 +01:00

106 lines
4.9 KiB
Markdown

# 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
```bash
# 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`.