Skip to content

M8: Flock Splits — first open-ended mini-game #88

Description

@season179

Work mode: AFK — carry through to merge + deploy per acceptance criteria.

The first real-mechanic experiment (not a quiz wrapper): a corral in Woolly
Meadows where the child partitions 10 fluffballs between two pens any way
they like. Every non-empty split is accepted; the delight is discovering
distinct decompositions (6 + 4 = 10), not being judged. Session-local
only: no save changes, no journal, no variant reward, no question banks, no
generic activity framework, no new art assets.

Design context: meadow-isle.md §2 (ten-pen fences, number bonds) and the
reserved mini-game pocket concept. This module is deliberately not an
answer_form precedent — the first-class activity-form question in
meadow-isle.md stays open.

Touch set (exact)

  • shared/telemetry.ts — add minigame_session_ended event spec (below).
  • game/assets/shared/telemetry.ts — synced copy via npm run sync.
  • game/assets/src/world/flock-splits.ts — NEW pure rule module (no cc
    imports): split canonicalization, move/submit rules, session state,
    entry-critter placement.
  • game/assets/src/world/FlockSplitsScreen.ts — NEW screen (cocos).
  • game/assets/src/world/arc.ts — extend ArcCritter.kind union with
    "minigame" (one line; nothing else changes).
  • game/assets/src/world/WorldScreen.ts — route bump/interact on
    kind === "minigame" critters to actions.onMinigame(critter); combine
    flockSplitsCrittersFor(regionId) into the existing critter render pass.
  • game/assets/src/GameApp.ts — Screen union + startMinigame /
    endMinigame (ShopScreen pattern); emit telemetry once on teardown.
  • game/tests/flock-splits.test.ts — NEW pure tests.
  • docs/preview-smoke-check.md — add the mini-game smoke steps.
  • New-file .metas generated by the Cocos build, committed (existing
    pattern).

shared/question-v2.ts, question banks, save-v2, persistence, worker
source: untouched.

Data / control flow

  1. flockSplitsCrittersFor("meadow/woolly") returns one entry critter
    (kind: "minigame", speciesId woolly/fluffball, walkable tile pinned
    by test — suggested x=8, y=6 in the north pen interior).
  2. WorldScreen bump/interact → WorldActions.onMinigame
    GameApp.startMinigame() mounts FlockSplitsScreen.
  3. Screen holds session state from the pure module:
    { staging: 10, pens: [0, 0], found: string[], rounds: 1, dupes: 0 }.
    All mutations go through the pure functions; the screen only renders.
  4. Exit button or completion → GameApp.endMinigame(result) → emit
    minigame_session_ended once → destroy screen, world resumes in place.

UI states

  • Playing: staging area with 10 fluffball placeholder nodes; two pen
    zones. Tap a pen to arm it (highlighted); tap a sheep in staging to send
    it to the armed pen; tap a sheep in a pen to return it to staging. Each
    pen shows a live count numeral + ten-frame (paintCellGrid, existing
    FigureView painter). A bilingual confirm button ("好了!/Done") submits.
  • Split feedback (submit):
    • staging not empty → gentle nudge ("还有羊在外面"), no state change;
    • a pen is empty → gentle nudge ("两个围栏都要有羊哦");
    • duplicate (canonical key already found, e.g. 4+6 after 6+4) → gentle
      "这种分法找过了", dupes++, sheep stay put;
    • accepted → the equation card shows (6 + 4 = 10), sheep settle,
      found records the key, next round resets pens to staging.
  • Complete (3 distinct): the session's equation cards shown together,
    celebratory bilingual line, Replay (resets found, rounds++) and
    Exit buttons.
  • No timer anywhere; failure states are impossible by construction.

Pure module API (contract for tests)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions