Files
holdem_poker/tools/generate_card_assets.sh
thejayman77 950c7ceb57 Playable Android table
The game runs on device: verified on a Pixel 10 Pro emulator (Android 17) by
installing, tapping through a hand, and confirming it advanced pre-flop to flop
with correct pot, folds, and re-offered action.

App:
- :app module on AGP 9.2.1. Note AGP 9 has built-in Kotlin support, so applying
  org.jetbrains.kotlin.android conflicts with it ("extension with name 'kotlin'
  already registered"); only android.application + kotlin.compose are applied,
  matching recipeze.
- PokerViewModel runs a continuous cash game and publishes to Compose.
- Compose table: opponents, board, pot, hero, action bar with a raise slider.

Frames are queued, not conflated. An all-in runout emits flop, turn and river
microseconds apart; pushing those into a StateFlow would collapse them and the
board would jump from empty to complete. The engine's suspending observer sends
into a Channel, a consumer paces each frame, and only then is StateFlow updated
— so backpressure paces the engine rather than the UI dropping frames. Three
tests cover this, including a characterisation test showing a conflating
StateFlow does lose the intermediate frames.

Assets:
- tools/generate_card_assets.sh rasterises the SVGs into four density buckets
  using sips, which renders SVG directly — no librsvg or ImageMagick.
- Resource names are prefixed card_ because Android resource names may not start
  with a digit (10_of_clubs would be rejected).
- CardArt.kt maps deck index to drawable via static R references, so R8 resource
  shrinking cannot strip the artwork the way getIdentifier lookups would risk.

Layout fixes found by actually looking at the running app: five opponents did
not fit a fixed-width scrolling row (Enzo was off-screen), the header collided
with the status bar clock, and the board floated against a large dead space.

Tests: 52 -> 55, green on jvmTest and testAndroidHostTest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 17:23:34 -04:00

42 lines
1.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Rasterises the card SVGs into Android density buckets.
#
# The SVGs in assets/cards/ stay the source of truth; this regenerates the
# drawables at any size. Uses macOS `sips`, which renders SVG directly — no
# librsvg or ImageMagick needed.
#
# Note the `card_` prefix: Android resource names may not start with a digit, so
# `10_of_clubs.svg` must become `card_10_of_clubs.png`.
#
# Usage: tools/generate_card_assets.sh
set -euo pipefail
SRC="$(cd "$(dirname "$0")/.." && pwd)/assets/cards"
RES="$(cd "$(dirname "$0")/.." && pwd)/app/src/main/res"
# Card art is 2:3. Widths are chosen so xxhdpi lands at a crisp 240x360.
declare -a BUCKETS=(
"mdpi:80:120"
"hdpi:120:180"
"xhdpi:160:240"
"xxhdpi:240:360"
)
count=0
for bucket in "${BUCKETS[@]}"; do
IFS=':' read -r density width height <<< "$bucket"
out="$RES/drawable-$density"
mkdir -p "$out"
for svg in "$SRC"/*.svg; do
base="$(basename "$svg" .svg)"
# playing_cards_deck is the 52-card contact sheet, not a usable game asset.
[ "$base" = "playing_cards_deck" ] && continue
sips -s format png -z "$height" "$width" "$svg" --out "$out/card_$base.png" >/dev/null 2>&1
count=$((count + 1))
done
echo " $density (${width}x${height}): $(ls "$out" | wc -l | tr -d ' ') files"
done
echo "generated $count PNGs"
du -sh "$RES" | awk '{print " total: " $1}'