Skip to content

feat: Kids Math Duel — 2-player head-to-head voice math game for families - #375

Merged
uzair401 merged 4 commits into
openhome-dev:devfrom
hassan1731996:feature/kids-math-duel
Sep 18, 2026
Merged

uzair401 merged 4 commits into
openhome-dev:devfrom
hassan1731996:feature/kids-math-duel

Conversation

@hassan1731996

@hassan1731996 hassan1731996 commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • First ability in the catalog targeting kids and families — a completely absent user segment across all 120+ abilities
  • Head-to-head 2-player voice math game: 10 questions alternating (5 each), 8-second soft countdown, steal mechanic on wrong answers or timeouts
  • Pure Python math generation — no LLM per question, zero latency between rounds

What makes it different

vibe-trivia spelling-bee-coach Kids Math Duel
Players 1 1 2 (head-to-head)
Question source LLM Static word list Pure Python
Steal mechanic No No Yes
Countdown timer No No Yes — 8s soft
Target audience General General Kids & families

Implementation notes

Timer (epoch counter): session_tasks.create() launches the countdown in parallel while user_response() waits for input. An epoch counter (_timer_epoch) prevents a previous question's countdown from firing into the next question when the user answers quickly.

Steal mechanic: Wrong answer or timeout → opponent is asked the same question, without revealing the answer first. The answer is only spoken if the steal also fails.

Difficulty tiers:

  • Easy: + and −, numbers 1–20
  • Medium: +, −, ×, times-tables range (1–12)
  • Hard: +, −, ×, ÷ (division always whole-number), up to 50×12

Patterns followed:

  • get_single_key unwrap: .get("value", raw) ✅
  • Storage upsert: create_key + success check → update_key ✅
  • LLM guards: all text_to_text_response() calls wrapped in (... or "") ✅
  • resume_normal_flow() in finally block ✅
  • No asyncio, no print(), no hardcoded keys ✅

Test plan

  • Trigger with "math duel" → name collection → difficulty selection flows correctly
  • 10 questions alternate between players (P1 Q1, P2 Q2, ...)
  • Correct answer: score updates, streak increments, opponent streak resets
  • Wrong answer: steal offered to opponent WITHOUT revealing the answer first; answer revealed only if steal also fails
  • Timer fires after 8s: "Time's up! [Opponent] — steal it!" speaks; game moves to steal without hanging
  • Fast answer (< 8s): countdown from Q1 does NOT fire during Q2
  • Play-again loop: new difficulty can be chosen each round
  • Exit words ("stop", "quit") exit cleanly at any prompt
  • validate_ability.py ✅ flake8 ✅

Head-to-head voice math game targeting families and kids, a user segment
entirely absent from the catalog. Ten questions alternating between two
players, 8-second soft countdown timer, and a steal mechanic that keeps
both players engaged even when it's not their turn.

Key design decisions:
- Pure Python math generation (random.randint) — no LLM per question,
  instant and deterministic
- Soft timer via session_tasks.create() parallel countdown so user_response()
  is never blocked; epoch counter prevents countdown bleed across questions
- Steal mechanic does NOT reveal the answer before the steal attempt;
  answer is only spoken if the steal also fails
- LLM used only for post-game debrief (2-sentence fun summary)
- Per-player leaderboard (best score, best streak, games played) persisted
  via create_key/update_key upsert pattern
- validate_ability.py clean, flake8 clean
@hassan1731996
hassan1731996 requested a review from a team as a code owner September 13, 2026 09:30
@github-actions

Copy link
Copy Markdown
Contributor

✅ Community PR Path Check — Passed

All changed files are inside the community/ folder. Looks good!

@github-actions

Copy link
Copy Markdown
Contributor

🔀 Branch Merge Check

PR direction: feature/kids-math-duel → dev

✅ Passed — feature/kids-math-duel → dev is a valid merge direction

@github-actions github-actions Bot added the community-ability Community-contributed ability label Sep 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Lint Results

🔧 Formatting fixes available

This PR is from a fork, so fixes could not be pushed automatically. Download the python-lint-results artifact from the workflow run for the patch file, then run:

git apply autofix.patch

✅ __init__.py — Empty as expected

Files linted: community/kids-math-duel/main.py

✅ Flake8 — Passed

✅ All checks passed!

@github-actions

Copy link
Copy Markdown
Contributor

✅ Ability Validation Passed

📋 Validating: community/kids-math-duel
  ✅ All checks passed!

hassan1731996 and others added 2 commits September 13, 2026 14:38
- _is_exit() was only checked at setup (name/difficulty), never during an
  actual answer turn - saying "stop" mid-game fell through to the LLM
  fallback in _check_answer() and just scored as wrong.
- _ask_with_timer() awaited user_response() alone, with the countdown
  firing "Time's up!" in parallel but never unblocking that await - a
  silent player left the whole ability hanging with no recovery.

Race the listen against the timer instead of awaiting the listen alone;
whichever finishes first wins and the other is cancelled. An exit word on
either the main answer or a steal sets _exit_requested, which now breaks
_run_game's loop and skips the result announcement and leaderboard save
in _run(), matching how the existing setup-time exits already behave.
@uzair401

Copy link
Copy Markdown
Contributor

Pushed a fix for the two issues from review:

  • Exit words ("stop", etc.) weren't checked during actual gameplay, only at setup — saying "stop" mid-game just scored as a wrong answer. Now checked on both the main answer and the steal attempt, and quitting mid-game skips the result announcement and leaderboard save.
  • The countdown timer didn't cancel the concurrent listen, so a silent player could hang the ability forever. _ask_with_timer now races the listen against the timer and proceeds with whichever finishes first.

Tested locally against the patched file (silent-past-timer, answer-in-time, exit-mid-question, full-loop-quit) — all resolve correctly.

@uzair401
uzair401 merged commit 765accd into openhome-dev:dev Sep 18, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-ability Community-contributed ability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants