Skip to content

rummy: gin and 10-card deals; basic becomes 7-card - #1613

Merged
aaylward merged 7 commits into
mainfrom
claude/rummy-game-backend-ui-fvxk0l
Sep 29, 2026
Merged

aaylward merged 7 commits into
mainfrom
claude/rummy-game-backend-ui-fvxk0l

Conversation

@aaylward

@aaylward aaylward commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #1610.

The dealer can now deal 7-card (formerly basic), 10-card, or heads-up gin. The options depend on the seat count: 2 seats get all three, 3 seats get 7-card and 10-card, and 4 seats get 7-card only. In every variant the ace runs high or low but never wraps around.

  • Best-meld search (arrange.h): finds each hand's least-deadwood melds, with lay-offs. It is checked against a brute force and against a corpus generated by an independent Python oracle (testdata/arrange_corpus.json). The UI replays the same corpus.
  • GinState:
    • The upcard round.
    • A knock at 10 deadwood or less.
    • Gin and undercut scoring.
    • A drawn deal once the stock is down to 2.
    • Its own v1 JSON serialization, which refuses rows that couldn't be played.
  • Table: TableState holds Deal = variant<GameState, GinState>. The hub goes through the deal* helpers.
  • Wire:
    • New pass and knock moves.
    • New canDrawDiscard field on the view.
    • A new upcard stage.
    • lastDeal.gin carries the arranged hands, the lay-offs and the ending.
  • Stats: gin deals are recorded as gin; 7-card and 10-card stay rummy. otel_contract now also pins recordedName's words against the stats and deja readers.
  • Storage: 7-card tables are still stored as basic; every other variant is stored under its wire word.
  • Docs: CLAUDE.md and WORKING_AGREEMENT.md now say never to schedule check-ins on a PR. This rides here at the owner's request.

Rollout: deploy muchq.github.io#390 first; it works against the current hub. A hub rolled back past this PR still reads 7-card tables but drops tables with 10-card or gin deals.

Verified locally: the rummy lib, games_hub (including the PG suites against Postgres), otel_contract, stats and deja are green. A gin deal was played end to end in a browser against #390.

Review: my own four-lens panel and Cursor's review ran. Their findings are fixed in this PR's later commits. Known gaps left as-is:

  • Lay-offs and the draw ending are covered in the lib but not on the wire.
  • When two arrangements tie on deadwood, the engine, not the player, picks which melds the knocker shows.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
1d4-web 36333e3 Commit Preview URL

Branch Preview URL
Sep 29 2026, 01:07 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
iili 36333e3 Commit Preview URL

Branch Preview URL
Sep 29 2026, 01:08 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
ast-lol 36333e3 Commit Preview URL

Branch Preview URL
Sep 29 2026, 01:08 PM

@github-actions github-actions Bot added the service:unknown Impacted services could not be computed label Sep 29, 2026
@cursor

cursor Bot commented Sep 29, 2026

Copy link
Copy Markdown

Review panel + Bugbot (53cc0ab0)

Four lenses + Bugbot. Bugbot found no bugs. Gin rules / variant dispatch / store-basic↔wire-7-card / arrange corpus look sound on the happy path. Author panel fold-ins and known deferrals (lay-offs lib-covered with empty wire goldens; engine-picked tie arrangements) accepted. build-and-test / sanitize still running at post time.

Verdict: LGTM with fold-ins. Sharpest gap is gin serde lagging GameState’s hostile-row bar; rest is docs/pins.

Survivors (verified):

  1. Correctness / resource — deserializeGinState accepts playing rows with no legal move, and unbounded hands. game_state_serde rejects stuck playing rows ("a playing row with no move to make"). Gin has no twin: a restored phase=playing / stage=stock|draw with empty stock wedges (canDrawStock/canDrawDiscard false; pass refused). Separately, readCards allows up to 52; arrange assumes uint32_t bitmasks (1 << hand.size() UB at ≥32) and runs under hub mu_ on knock / leave / abandoned deadwood. Cap hands at gin’s 10/11 and add the stuck-row guard; pin both in RejectsWhatTheEngineCouldNotPlay.

  2. Docs — cards/rummy/README.md misstates storage. Still says game_state_serde is what the hub stores a table in. Hub stores table_serde v2 (nested deal; 7-card as "basic"; gin via gin_serde). Fold the README to match.

  3. Tests — gin deal → event word "gin" unpinned. recordedName(Gin)=="gin" is unit-pinned; otel scrapes it. FinishedOf / EveryEventsLineIsTextWithNothingToEscape only finish SevenCard → "rummy" (allow-list still omits "gin"). Hub e2e comment still says deals are “recorded as rummy whatever the deal's variant.” Add a gin FinishedOf (and escape-loop) case; fix the comment.

  4. Tests (soft) — wire never pins lastDeal.gin.ending: "draw". Engine has the stock-floor draw; smithy documents it; wire goldens only gin / undercut. Author’s empty-laidOff gap stays intentional.

  5. Altitude (soft) — basicDeal() naming residue. Storage basic means SevenCard only; basicDeal() returns GameState* for both 7- and 10-card. Prefer rummyDeal() / gameDeal(). Process tip (WORKING_AGREEMENT / CLAUDE.md) is fine folded — name it in the PR body.

Line comments below. Panel complete.

Comment thread domains/games/libs/cards/rummy/README.md Outdated
Comment thread domains/games/libs/cards/rummy/gin_serde.cc Outdated
@cursor

cursor Bot commented Sep 29, 2026

Copy link
Copy Markdown

Recheck at a73993ac

Ace high/low / no-wrap pins across 7-card, 10-card, and gin look good (including gin lay-offs that refuse the corner).

Still open from the prior review:

  1. gin serde stuck-row guard + hand-size cap (arrange under hub lock)
  2. cards/rummy/README.md storage paragraph (table_serde, not game_state_serde)
  3. gin → event word "gin" (FinishedOf / escape allow-list / hub e2e comment)
  4. soft: wire ending:"draw"; basicDeal() rename; name the docs tip in the PR body

CI was green on 53cc0ab0; this tip’s run in progress.

Copy link
Copy Markdown
Collaborator Author

The remaining summary items, in 36333e3:

  1. Done. AGinDealPlayedOutIsCompletedAsGin pins the event word gin, and the escape loop now covers gin. A mutant that records gin as rummy is killed. I also fixed the hub e2e comment.
  2. Not done. The draw ending (draw) is pinned in the engine (GinStock.ADiscardLeavingTwoInTheStockDrawsTheDeal), but not on the wire. With the unshuffled test deck, getting there takes about 28 scripted turns. The hub maps endings through the same switch that the gin and undercut wire goldens already exercise.
  3. Done. basicDeal() is renamed to rummyDeal().

The docs commit (no scheduled check-ins on PRs, in CLAUDE.md and WORKING_AGREEMENT.md) is part of this PR at the owner's request.


Generated by Claude Code

@cursor

cursor Bot commented Sep 29, 2026

Copy link
Copy Markdown

Recheck at 36333e32

Closed:

  1. Gin serde — hands capped at 11; stuck playing rows refused (!canDrawStock && !canDrawDiscard / empty hand at play); four cases in RejectsWhatTheEngineCouldNotPlay.
  2. README — table_serde + nested engine schemas + basic for 7-card.
  3. Gin event word — AGinDealPlayedOutIsCompletedAsGin; escape allow-list includes "gin"; hub e2e comment fixed.
  4. Soft ending:"draw" wire — accepted as won’t-fix (engine pin; long scripted path; same hub switch as gin/undercut goldens).
  5. basicDeal() → rummyDeal(); docs tip named in the PR body.

LGTM.

@github-actions github-actions Bot added service:deja Changes the deja image service:games_hub Changes the games_hub image service:stats Changes the stats image and removed service:unknown Impacted services could not be computed labels Sep 29, 2026
@aaylward
aaylward merged commit 8313929 into main Sep 29, 2026
24 checks passed
@aaylward
aaylward deleted the claude/rummy-game-backend-ui-fvxk0l branch September 29, 2026 14:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

service:deja Changes the deja image service:games_hub Changes the games_hub image service:stats Changes the stats image

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rummy: Gin variant

2 participants