Skip to content

Add showdown status and card-reveal action to parsed hands#105

Merged
ggratte merged 3 commits intoItalyToast:masterfrom
ggratte:add-showdown-status
Apr 20, 2026
Merged

Add showdown status and card-reveal action to parsed hands#105
ggratte merged 3 commits intoItalyToast:masterfrom
ggratte:add-showdown-status

Conversation

@ggratte
Copy link
Copy Markdown
Collaborator

@ggratte ggratte commented Apr 18, 2026

Summary

Surfaces two new properties on every parsed hand, derived once in a post-parse pass so no site parser needs to change:

  • HandHistory.WentToShowdown (bool) — true iff the hand reached showdown with at least two players still live.
  • Player.RevealAction (enum: NotShown / MuckedAtShowdown / ShownAtShowdown / ShownVoluntarily) — what the rest of the table saw this player do with their hole cards.

Why

Until now, Player.HoleCards was a single nullable slot that parsers overwrote regardless of how the cards became known — dealt to hero, shown voluntarily, forced at showdown, or leaked via mucked [cards] in summary. Consumers couldn't distinguish a hero's dealt cards from a villain's showdown reveal, and had no convenience flag for WTSD.

The three facts are kept on orthogonal axes by design:

Question Answered by
Does the parser have the cards? Player.HoleCards != null
Is this player the hero? HandHistory.Hero
What did the table see? Player.RevealAction (new)

So a hero who reaches showdown and turns over cleanly gets RevealAction.ShownAtShowdown (table-visibility) without losing the fact that HoleCards was set from the "Dealt to" line (parser-knowledge).

Reveal values may be partial in Omaha / hi-lo split games (a player shows only some of 4/5/6 hole cards). This is documented on the enum; callers detect it by comparing HoleCards.Count against the expected count for GameDescription.GameType.

Implementation

  • HandHistories.Objects/Cards/RevealAction.cs — new enum with XML docs.
  • HandHistories.Objects/Players/Player.cs — new RevealAction property (defaults to NotShown).
  • HandHistories.Objects/Hand/HandHistory.cs — new WentToShowdown property (defaults to false).
  • HandHistories.Parser/Analyzers/ShowdownAnalyzer.cs — single linear walk of HandActions to populate both.
  • HandHistories.Parser/Parsers/FastParser/Base/HandHistoryParserFastImpl.cs — invokes the analyzer right after FinalizeHandHistory in ParseFullHandHistory, so every site parser inherits the behaviour.

Test-infra fixes bundled in (required to run the suite on macOS)

These are small but worth flagging so reviewers know why they're in this PR:

  • Retargeted both unit-test projects from netcoreapp3.1 to net8.0. .NET Core 3.1 is EOL (Dec 2022) with no native arm64 build, so the previous target couldn't run on Apple Silicon without x64 + Rosetta 2. Production libraries stay on netstandard2.0 / netstandard2.1 — downstream consumers unaffected. Rationale is inlined in both csproj files.
  • Fixed a hard-coded \ path separator in SampleHandHistoryRepositoryFileBasedImpl.GetSampleHandHistoryFolder with Path.Combine. The old code returned null on unix filesystems, cascading into ~700 NullReferenceExceptions in tests that split the result.

After these fixes the suite goes from unrunnable on macOS → 994 passing / 27 failing. The remaining 27 failures are pre-existing cross-platform issues (Windows-1252 sample-file encoding read as UTF-8, and \r\n-only line splits on LF checkouts) and are unrelated to this change.

Test plan

  • New ShowdownAnalyzerTests (5 tests) covers every enum value, the WentToShowdown flag, and the mucked-but-leaked-in-summary case — all pass.
  • Full suite runs on macOS (net8.0): 994 passing / 27 pre-existing failures unrelated to this PR.
  • CI / Windows run to confirm no regressions on the maintainer's primary platform.

🤖 Generated with Claude Code

ggratte and others added 3 commits April 18, 2026 07:06
What
----
Two new properties, populated once per hand in a post-parse pass:

- HandHistory.WentToShowdown (bool) — true iff the hand reached the
  showdown phase with at least two players still live.
- Player.RevealAction (enum: NotShown / MuckedAtShowdown / ShownAtShowdown
  / ShownVoluntarily) — what the rest of the table saw this player do
  with their hole cards.

Derivation lives in HandHistories.Parser.Analyzers.ShowdownAnalyzer and
is invoked from HandHistoryParserFastImpl.ParseFullHandHistory right
after FinalizeHandHistory, so every site parser gets it for free.

Why
---
Until now, Player.HoleCards was a single nullable slot that parsers
overwrote regardless of how cards became known (dealt to hero, shown
voluntarily, forced at showdown, or leaked via "mucked [cards]" in
summary). Downstream consumers couldn't tell a hero's dealt cards from
a villain's showdown reveal, and had no convenience flag for WTSD.

The three facts are intentionally kept on orthogonal axes:
  * Does the parser have the cards? → Player.HoleCards != null
  * Is this player the hero?        → HandHistory.Hero
  * What did the table see?         → Player.RevealAction
This way a hero who reaches showdown and turns over cleanly gets
RevealAction.ShownAtShowdown (table-visibility) without losing the fact
that HoleCards was set from the "Dealt to" line (parser-knowledge).

Reveal values may be partial in Omaha/hi-lo (e.g. a player shows only
some of 4/5/6 hole cards); this is documented on the enum and callers
can detect it by comparing HoleCards.Count against the expected count
for GameDescription.GameType.

Tests
-----
Five new unit tests in ShowdownAnalyzerTests cover each enum value, the
WentToShowdown flag, and the mucked-but-leaked-in-summary case.

Cross-platform test-infra fixes (required to run the suite on macOS)
--------------------------------------------------------------------
- Retargeted both unit-test projects from netcoreapp3.1 to net8.0.
  .NET Core 3.1 is EOL (Dec 2022) and has no native arm64 build, so the
  previous target couldn't run on Apple Silicon without installing the
  x64 runtime under Rosetta 2. Production libraries remain on
  netstandard2.0 / netstandard2.1, so downstream consumers are
  unaffected. The rationale is inlined in both csproj files.
- Replaced a hard-coded backslash path separator in
  SampleHandHistoryRepositoryFileBasedImpl with Path.Combine. The old
  code returned null on unix filesystems, causing ~700 cascading
  NullReferenceException failures in tests that split the result.

After these fixes the suite goes from unrunnable → 994 passing / 27
failing on macOS. The remaining 27 failures are pre-existing
cross-platform issues (Windows-1252 sample-file encoding read as UTF-8,
and "\r\n"-only line splits on LF checkouts) and are unrelated to this
change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ggratte ggratte merged commit be01b59 into ItalyToast:master Apr 20, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant