You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a synchronized two-player Mancala (Kalah) game across the paired ESP32-2432S028 CYDs, where each player sows stones from their own board and the two screens stay in lockstep over ESP-NOW.
Locking in Kalah rules explicitly (the common Western variant) to avoid ambiguity: 6 pits per player, 2 stores, sow skips the opponent's store only, captures enabled. This is distinct from Oware and other variants.
Rules (Kalah)
Each player owns 6 pits and 1 store (Kalah), starting with 4 stones per pit.
On a turn, the current player picks up all stones from one of their own non-empty pits.
Sow one stone into each following pit counter-clockwise, including the player's own store, skipping the opponent's store.
Free turn: if the last stone lands in the player's own store, the same player moves again (turn does not rotate).
Capture: if the last stone lands in one of the player's own previously-empty pits, capture that stone plus all stones in the directly opposite opponent pit, moving them to the player's store.
Endgame: when either player's 6 pits are all empty, the opponent sweeps all stones remaining on their own side into their store. Most stones in store wins; equal counts is a draw.
Two-screen layout — selectable display mode
This is the core UX question the implementation must settle. Two modes, selectable at game start:
Mode 1 — Split view (6 pits per screen)
Each CYD shows only that player's 6 pits + both stores.
The opponent's 6 pits are shown as a compact read-only strip (or omitted entirely).
Control passes between the two players: only the player whose turn it is can interact with their screen; the opponent's screen is read-only during that turn.
When the turn ends, the active screen dims/hides the touch targets and the other screen becomes active.
This matches the physical experience of sitting opposite each other with a shared board between you.
Mode 2 — Full mirrored view (12 pits per screen)
Each CYD renders the full 14-slot board (both players' pits + both stores).
The current player's pits are touchable; the opponent's pits and both stores are read-only/greyed.
This mirrors a single physical Mancala board laid between two players, keeps stone movement legible, and avoids confusion about where sown stones land.
Both screens are active simultaneously; the turn indicator is the only thing that changes.
Selector
At game start, the host chooses Split (6) or Mirrored (12) from the Home screen.
Both devices receive the mode and render accordingly.
Mode 1 is recommended default for competitive play (less visual clutter, explicit turn handoff); Mode 2 is better for teaching/casual play.
Turn ownership and input
Only the current player (matching turnBoardId) can act; tapping an empty pit, an opponent pit, or a store does nothing.
After a legal sow, the resulting board is broadcast to the peer, which validates the transition locally before adopting (no trust). The defending device can re-derive sowing, captures, and free-turn rotation from the state delta to confirm legality.
Packet decision to make: reuse the existing PuzzleState/FullState packet shape or define a dedicated MancalaState packet (14 pit counts + turn + phase + game id/revision). A dedicated packet is cleaner given the different board shape; flag the protocol-version bump either way.
Synchronization
Mancala is fully deterministic with no hidden state, so it is a straightforward FullState-driven game.
Reuse the Mastermind foundation: active-game epoch isolation, authenticated sender identity, ACK/retry, replay rejection, and full-state reconciliation.
Free-turn edge case: when the last stone lands in the current player's store, turnBoardId must not rotate. Both UIs must reflect "same player goes again" without the other player being able to act out of turn — this is the trickiest sync case and needs an explicit host test.
Navigation
Both boards provide an EXIT control during play, free-turn continuation, and results.
Either player may return both devices to the shared Home selector.
Same idempotent EXIT semantics as Mastermind and Planet Slide: EXIT dominates concurrent input, retries after packet/ACK loss, converges terminal state, and cannot be undone by stale packets.
Acceptance criteria
Sowing distributes stones counter-clockwise and skips only the opponent's store.
Free-turn rotation (last stone in own store) is deterministic and correctly suppresses turn change.
Capture math (last stone in own empty pit captures opposite pit) is correct and re-derivable by the peer.
Endgame detection and the opponent's remaining-stone sweep produce the correct final score, including draws.
Only the current player can act; opponent/empty/store taps are inert.
State stays synchronized across both screens through captures, free turns, and endgame.
Both display modes work: Split (6) and Mirrored (12), selectable at start.
In Split mode, control cleanly passes between screens on turn change; the non-active screen shows read-only state.
EXIT works from either board in every phase and converges both to Home.
Pure rules pass strict host compilation with -std=c++17 -Wall -Wextra -Werror (sowing, capture, free-turn, endgame, EXIT).
Both CYDs flashed and physically verified through a full game including captures, at least one free turn, and the endgame sweep, in both display modes.
Feature
Add a synchronized two-player Mancala (Kalah) game across the paired ESP32-2432S028 CYDs, where each player sows stones from their own board and the two screens stay in lockstep over ESP-NOW.
Locking in Kalah rules explicitly (the common Western variant) to avoid ambiguity: 6 pits per player, 2 stores, sow skips the opponent's store only, captures enabled. This is distinct from Oware and other variants.
Rules (Kalah)
Two-screen layout — selectable display mode
This is the core UX question the implementation must settle. Two modes, selectable at game start:
Mode 1 — Split view (6 pits per screen)
Mode 2 — Full mirrored view (12 pits per screen)
Selector
Turn ownership and input
turnBoardId) can act; tapping an empty pit, an opponent pit, or a store does nothing.PuzzleState/FullStatepacket shape or define a dedicatedMancalaStatepacket (14 pit counts + turn + phase + game id/revision). A dedicated packet is cleaner given the different board shape; flag the protocol-version bump either way.Synchronization
FullState-driven game.turnBoardIdmust not rotate. Both UIs must reflect "same player goes again" without the other player being able to act out of turn — this is the trickiest sync case and needs an explicit host test.Navigation
EXITcontrol during play, free-turn continuation, and results.Acceptance criteria
-std=c++17 -Wall -Wextra -Werror(sowing, capture, free-turn, endgame, EXIT).