Android target, suspending agents, and observable table snapshots

Build:
- :engine now uses com.android.kotlin.multiplatform.library (AGP 9.2.1), the
  modern KMP Android integration, rather than plain androidTarget(). Produces
  engine.aar alongside the JVM target; compileAndroidMain verified.
- Version catalog added; SDK levels match the other JSJ apps (compileSdk 37,
  minSdk 26).

Engine:
- PlayerAgent.act() and Table.playHand() are now suspend, so a human player can
  wait for input without blocking a thread. Bots are unaffected; the simulator
  wraps in runBlocking.
- TableSnapshot/SeatSnapshot published after the deal, before and after every
  action, and at the finish. Immutable, aliasing no live Seat state, giving
  animation, hand history, saving, and replay one boundary to work against.
- Snapshots carry the whole truth; maskedFor(viewer) is an explicit step that
  hides hole cards the viewer is not entitled to. Showdown reveals contenders;
  folded hands never are.
- Terminal snapshots report the contested pot rather than 0. settle() zeroes
  contributions when awarding, so the naive value was empty at exactly the
  moment the UI needs to show what was won. Caught by a new test.
- HumanAgent suspends on a CompletableDeferred and clears its pending state in a
  finally block, so cancelling an abandoned hand releases the wait instead of
  stranding it. Re-usable afterwards; a stale submit returns false.

Tests: 37 -> 45. Chips still conserved, skill gradient still monotonic.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jay
2026-07-25 10:55:28 -04:00
parent 96af198097
commit 7f82251d86
11 changed files with 459 additions and 27 deletions
+14 -3
View File
@@ -1,15 +1,26 @@
plugins {
kotlin("multiplatform")
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.android.kotlin.multiplatform.library)
}
kotlin {
// JVM target drives tests and the headless simulator today.
// androidTarget() / iosArm64() slot in here later without touching commonMain.
// JVM target drives tests and the headless tuning simulator.
jvm()
// The modern KMP Android integration. `androidTarget()` is the older path.
androidLibrary {
namespace = "com.jsjdesigns.poker.engine"
compileSdk = 37
minSdk = 26
}
sourceSets {
commonMain.dependencies {
implementation(libs.kotlinx.coroutines.core)
}
commonTest.dependencies {
implementation(kotlin("test"))
implementation(libs.kotlinx.coroutines.test)
}
}
}