Phase 2 + 3: full chess rules + UX polish for RP2040 (with self-tests)#11
Open
semichcsc-byte wants to merge 3 commits into
Open
Phase 2 + 3: full chess rules + UX polish for RP2040 (with self-tests)#11semichcsc-byte wants to merge 3 commits into
semichcsc-byte wants to merge 3 commits into
Conversation
1) stockfish_settings.h: medium() depth 6 -> 10
Bug: serial said 'Medium (Depth 10)' but the struct sent depth=6,
making Easy and Medium identical. Aligns with the documented intent.
2) chess_bot.cpp::parseStockfishResponse: split HTTP headers from body
before scanning for JSON. Cloudflare's response includes JSON-shaped
headers (Nel:, Report-To:) that come before the real body, so the
previous indexOf("{") grabbed the wrong object. Symptom: 'API request
was not successful' on a successful response. Fix: locate the body
after the first blank line (\\r\\n\\r\\n) and parse from there.
3) chess_bot.cpp::makeBotMove: validate the API's move locally before
mutating board state. Protects against malformed JSON, partial reads,
side-of-turn mismatches and any future API quirk. On rejection the
board returns to the player's turn instead of corrupting state.
Also reset isWhiteTurn on parse/response failure paths so the user
isn't stuck.
4) OpenChess.ino MODE_GAME_3: replace blind 3s loop with a wait-until-
piece-lifted gate. Old behaviour spammed the serial at ~3 lines/sec
forever while a piece sat on the placeholder square (4,3) since
handleGameSelection re-triggered the same branch every cycle. Now we
wait for the sensor to clear before re-arming the menu.
5) chess_engine.h: introduce MAX_MOVES_PER_PIECE constant (=28) and use
it everywhere. Was inconsistent: chess_moves used moves[28], chess_bot
used moves[27]. Eliminates the off-by-one buffer-overflow risk for
queens reaching 27 candidates.
All five are RP2040-friendly and apply equally to other WiFiNINA boards
(Nano 33 IoT, MKR WiFi 1010). Verified by recompiling and reflashing
the official OpenChess.ino on an Arduino Nano RP2040 Connect; bot mode
still connects, parses Stockfish replies and plays correctly.
This is a substantial gameplay upgrade for the official Concept-Bytes firmware path on the Arduino Nano RP2040 Connect. All changes verified by 10/10 self-tests run at every boot, plus an on-device smoke test. == Phase 2: chess rules == * Check detection: new ChessEngine::isInCheck and isSquareAttacked. * Legal-move filtering: getLegalMoves wraps getPossibleMoves and removes any move that would leave the player's king in check (so pinned pieces, illegal king walks, etc. are no longer offered). * Checkmate / Stalemate detection via getGameResult, with on-board game-over animations (white wins: full-board white; black wins: red pulse; draw: fireworks). * Castling: kingside and queenside, full FIDE rules (king and rook on home squares, path clear, king not in check, king does not pass through attacked square). Castling rights are tracked in the new GameState struct and updated automatically by applyMove (also cleared if the rook is captured on its starting square). * En passant: tracked via GameState::enPassantRow/Col, set on a 2-square pawn advance and cleared otherwise. The capturing pawn's destination is shown pink on the LED hint, and applyMove removes the captured pawn from its actual square (one rank back from EP target). * 50-move rule via halfMoveClock, reset on pawn move or capture. * Insufficient material draw: K vs K, and K + single minor piece (B or N) vs K. * Promotion choice: when a pawn reaches the back rank in Human-vs- Human mode, four selector LEDs light up on the player's back rank (a/b/c/d files = Q/R/B/N). Place any piece on one to choose. Bot mode still auto-promotes to queen since the Stockfish API string isn't parsed for the optional 5th promotion char yet. == Phase 3: UX polish == * Sensor debounce: a reading must repeat for SENSOR_DEBOUNCE_SCANS=3 consecutive scans before flipping the public sensor state. Eliminates the 'piece flicker' false-positives we saw in serial when sliding pieces across squares during board setup. * AP shutdown after non-bot mode: WiFi.end() is called when entering Chess Moves / Sensor Test, dropping the OpenChessBoard AP that was drawing ~100 mA and creating an unused WiFi network. Bot mode is untouched (it tears down + reopens internally per PR Concept-Bytes#9). * Self-tests: ChessEngine::runSelfTests runs at boot before WiFi setup and prints PASS/FAIL for 10 deterministic positions (initial moves, Fool's Mate, pinned rook, both castlings, castle-in-check forbidden, en-passant, K-vs-K, kingside castle layout). On any failure the board flashes red 5x so the user knows the firmware is broken before they start a game. == Engine API == * New: GameState struct, getLegalMoves, isLegalMove, isInCheck, isSquareAttacked, hasAnyLegalMove, getGameResult, applyMove, isCastlingMove, isEnPassantMove, runSelfTests. * getPieceColor moved to public. * All callers in chess_moves.cpp and chess_bot.cpp now go through the new API; board mutation lives in ChessEngine::applyMove so castling/EP/state updates can never be forgotten. == Verification == Sketch uses 150679 bytes (0%) of program storage space. Global variables use 44640 bytes (16%) of dynamic memory. 10/10 self-tests passed. Tested on Arduino Nano RP2040 Connect with WiFiNINA firmware 3.0.1. Boot clean, mode selection works, chess_moves Human-vs-Human plays through opening + showcheck + castling correctly, chess_bot Human-vs- AI still connects via PR Concept-Bytes#9 and applies validated moves. Builds on PR Concept-Bytes#9 (WiFi AP->STA) and PR Concept-Bytes#10 (5 quality fixes).
Adds OPENCHESS_FW_VERSION '1.0.0-rp2040' macro and prints it (plus the fork name) in the startup banner. Tagged v1.0.0-rp2040 to match.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Substantial gameplay upgrade for the official Concept-Bytes firmware on Arduino Nano RP2040 Connect: full chess rules (check, checkmate, castling, en-passant, draws, promotion choice), sensor debounce, AP shutdown, and a 10-test on-boot validation suite. +1107 / -282 lines, 9 files, 10/10 self-tests passing.
Builds on top of:
This PR depends on those landing first (or being squashed in together).
What changes for the user
OpenChessBoardstays up foreverEngine architecture
New
ChessEngineAPI, withboard[]mutation centralised inapplyMoveso castling / EP / state updates can never be missed:getPossibleMovesis kept as the pseudo-legal generator (no own-check filter); it's still used internally byisSquareAttackedandgetLegalMoves.Self-tests (run at every boot)
These caught one real bug during development (a wrong test position that turned out to be a wrong test position rather than an engine bug — but the same pattern would catch a real regression).
Sensor debounce
Each
readSensors()call updates a per-square "stable count". A reading must repeat for 3 consecutive scans before the public state flips. Tunable viaSENSOR_DEBOUNCE_SCANSin board_driver.h.This was visible in serial as flicker (
qappearing/disappearing on d8 between scans during board setup) — gone now.AP shutdown
When entering Chess Moves or Sensor Test,
WiFi.end()is called to release the radio. TheOpenChessBoardAP was drawing ~100 mA continuously and creating a persistent WiFi network nobody uses once a mode is selected. Bot mode is untouched because PR #9 already does the AP teardown internally.Promotion choice (Human vs Human)
When a pawn reaches the back rank, four selector LEDs light up on the player's own back rank with distinct colours:
Place any piece on one to choose. The selector then waits for you to lift the piece off the menu before re-arming the move detector.
Bot mode still auto-promotes to queen — the Stockfish API string
e7e8qincludes the promotion piece in its 5th character, but the existingparseMoveonly grabs the first 4 chars. That's a small follow-up, easy to bolt on but kept out of scope here to keep PR size manageable.Verification
Tested on Arduino Nano RP2040 Connect with WiFiNINA firmware 3.0.1:
applyMoveTrade-offs
GameStateinstances and debounce buffers