[package]
name = "pkcore"
description = "Prototype core poker library."
version = "0.2.0"
rust-version = "1.94.1"
edition = "2024"
authors = ["electronicpanopticon <gaoler@electronicpanopticon.com>"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/ImperialBower/pkcore.git"
homepage = "https://github.com/ImperialBower/pkcore"
keywords = ["poker", "holdem", "omaha", "equity", "cards"]
categories = ["games", "algorithms", "simulation"]
exclude = [".github/workflows/*", "data/*", "docs/*", "benches/*", "examples/*", "generated/hups.db", "generated/old/*", "generated/kuhn-repl-history", "proto/*", "scripts/*", ".gitignore", "Cargo.lock", ".claude", "CLAUDE.md", "DIARY.md", "marathon_failure.yaml"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

# docs.rs builds with all features so gated items (pokerbench, bot-training,
# debug-json, generators) render with their "available on feature X" banners.
[package.metadata.docs.rs]
all-features = true

[features]
## Default features enable the full EPIC-26 stack (player-stats and the
## optional persistence layer) plus bot-profiles and hand-histories so that
## examples (e.g. interactive_play, player_stats_session) work with a plain
## `cargo run --example`.  Downstream consumers who don't need persistence
## can opt out with `default-features = false` and re-enable just what they
## want.
default = [
    "bot-profiles",
    "hand-histories",
    "player-stats",
    "player-stats-persistence",
    "equity",
    "store",
    "terminal",
]
## Enables the on-disk storage layer: SQLite-backed HUP results (the `Sqlable`
## trait, `HUPResult`'s DB query/insert methods, `Connect`) and the
## zstd-compressed binary card map (`FiveBCM`/`SevenFiveBCM`, `bc_rank_hashmap`,
## and `SortedHeadsUp::wins`). Pulls in `rusqlite` (bundled SQLite) and `zstd`.
## Non-wasm only — those dependencies are target-gated, so the store code is
## always inert on wasm regardless of this flag. On by default; turn it off with
## `default-features = false` for a storage-free (pure) build. The pure `HUPResult`
## data type and its CSV/`Display` helpers remain available without the feature.
store = ["dep:rusqlite", "dep:zstd"]
## Enables the interactive terminal layer: `Terminal::pause` (raw-mode key
## reads) and ANSI colour output in `casino::table` and `analysis::nubibus`.
## Pulls in `termion` (unix only). With the feature off, colour output falls
## back to the existing no-op shims and `pause` is unavailable — giving a
## delivery-agnostic (headless) build. On by default.
terminal = ["dep:termion"]
## When enabled, `SolverResult::save` and `SolverResult::load` use human-readable
## JSON instead of the default compact binary (postcard) format. Useful for
## inspecting solver output during development. The explicit `save_json` /
## `load_json` and `save_binary` / `load_binary` methods are always available
## regardless of this flag.
debug-json = []
## Enables the multi-way equity engine in `analysis::equity` (exact enumeration
## plus seeded Monte Carlo, parallelized with rayon). Pure compute — adds no new
## dependencies (`rayon` and `rand` are already required). Off by default so
## library builds stay lean; enable it for the `pkodds` equity service.
equity = []
## Enables YAML serialization/deserialization for `BotProfile` and related
## types in the `bot` module. Adds a `serde_yaml_bw` dependency.
bot-profiles = ["dep:serde_yaml_bw"]
## Enables YAML serialization/deserialization for `HandHistory` and related
## types in the `hand_history` module. Adds a `serde_yaml_bw` dependency.
hand-histories = ["dep:serde_yaml_bw"]
## Enables the per-player aggregator in `analysis::player_stats`
## (`PlayerStats`, `StatsRegistry`, `Confidence`, derived ratios). EPIC-26.
player-stats = []
## Enables on-disk persistence for `StatsRegistry` via `PlayerStatsStore` and
## `YamlPlayerStatsStore` (one YAML file per player Uuid). Off by default; opt
## in for multi-session experiments. EPIC-26 Phase 4.
player-stats-persistence = ["player-stats", "dep:serde_yaml_bw"]
## Enables `ExploitConfig` YAML serialisation and the `ExploitTrainer`
## gradient-free optimisation loop (EPIC-28).  Requires player-stats and
## bot-profiles; adds no external optimiser dependency.
bot-training = ["player-stats", "bot-profiles", "dep:serde_yaml_bw"]
## Enables the `pokerbench` module: PokerBench (HuggingFace `RZ412/Pokerbench`
## scenario model, CSV/JSON loaders, canonical seating, and solver-label scoring.
## Analysis-only and additive (EPIC-43 Phase 1). Pure parsing — `csv`, `serde`,
## and `serde_json` are already required, so it adds no new dependencies.
pokerbench = []
## Enables historical offline generator inputs (e.g. `UNIQUE_HANDS`, the distinct
## 5-card hand enumeration read from a self-generated file). These have no runtime
## callers and require self-generated data; kept out of the default published API.
generators = []

[dependencies]
bint = "0.1.15"
cardpack = "0.6.9"
bitvec = { version = "1.1", features = ["alloc",  "atomic", "std", "serde", "testing" ] }
csv = "1.4"
indexmap = { version = "2.12", features = ["rayon"] }
itertools = "0.14"
log = "0.4"
percent-encoding = "2.3"
pkstate = "0.1.2"
rand = "0.9"
random_name_generator = "0.3.6" 
rayon = "1.11.0"
regex = { version = "1.12", features = [] }
postcard = { version = "1", features = ["alloc", "use-std"] }
serde_yaml_bw = { version = "2.5", optional = true }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
strum = { version = "0.28", features = ["derive"] }
strum_macros = "0.28"
thousands = "0.2.0"
uuid = { version = "1.22", features = ["serde", "v4"] }
wincounter = "0.1.5"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
rusqlite = { version = "0.34", optional = true, features = ["bundled"] } # 0.35 breaks HUPResult https://github.com/rusqlite/rusqlite/releases#reactions--reaction_button_component-a0702b
zstd = { version = "0.13", optional = true }

[target.'cfg(unix)'.dependencies]
termion = { version = "4.0", optional = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom_v2 = { package = "getrandom", version = "0.2", features = ["js"] }
getrandom_v3 = { package = "getrandom", version = "0.3", features = ["wasm_js"] }
uuid = { version = "1.22", features = ["serde", "v4", "js"] }

[[example]]
name = "calc"
required-features = ["equity"]

# Storage-backed tools: SQLite HUP store + zstd binary card map (audit II.11 /
# P7). Without `store`, `rusqlite`/`Sqlable`/`HUPResult` DB methods / BCM
# generation are absent, so these must not build under `--no-default-features`.
[[example]]
name = "audit"
required-features = ["store"]

[[example]]
name = "export_hups_bin"
required-features = ["store"]

[[example]]
name = "generate_bcm"
required-features = ["store"]

[[example]]
name = "hup_dump"
required-features = ["store"]

[[example]]
name = "insert_distinct"
required-features = ["store"]

[[example]]
name = "preflop"
required-features = ["store"]

# Uses `Terminal::pause` (raw-mode key reads), which is gated behind `terminal`.
[[example]]
name = "pluripop"
required-features = ["terminal"]

[[example]]
name = "equity"
required-features = ["equity"]

[[example]]
name = "bcrepl"
required-features = ["equity"]

[[example]]
name = "bot_selfplay"
required-features = ["bot-profiles", "hand-histories"]

[[example]]
name = "interactive_play"
required-features = ["bot-profiles", "hand-histories"]

[[example]]
name = "interactive_play_flhe"
required-features = ["bot-profiles"]

[[example]]
name = "interactive_play_plo"
required-features = ["bot-profiles"]

[[example]]
name = "interactive_play_razz"
required-features = ["bot-profiles"]

[[example]]
name = "interactive_play_stud_hi"
required-features = ["bot-profiles"]

[[example]]
name = "replay_play"
required-features = ["hand-histories", "bot-profiles"]

[[example]]
name = "yaml_audit"
required-features = ["hand-histories", "bot-profiles"]

[[example]]
name = "player_stats_review"
required-features = ["bot-profiles", "hand-histories", "player-stats"]

[[example]]
name = "player_stats_session"
required-features = ["bot-profiles", "hand-histories", "player-stats-persistence"]

[[example]]
name = "exploitative_play"
required-features = ["bot-profiles", "player-stats"]

[[example]]
name = "train_exploit_config"
required-features = ["bot-training"]

[[test]]
name = "replay_consistency"
required-features = ["hand-histories", "bot-profiles"]

[[test]]
name = "bot_marathon"
required-features = ["hand-histories", "bot-profiles"]

[[test]]
name = "pkarena0_session"
required-features = ["hand-histories", "bot-profiles"]

[[test]]
name = "hand_history_legacy_yaml"
required-features = ["hand-histories"]

[[test]]
name = "player_stats_consistency"
required-features = ["bot-profiles", "hand-histories", "player-stats"]

[[test]]
name = "player_stats_persistence"
required-features = ["bot-profiles", "hand-histories", "player-stats-persistence"]

[[test]]
name = "exploitative_play_smoke"
required-features = ["bot-profiles", "player-stats"]

[[test]]
name = "training_integration"
required-features = ["bot-training"]

[dev-dependencies]
clap = { version = "4.6", features = ["derive", "unicode"] }
clap-repl = "0.3.2"
criterion = "0.5"
elr_primes = "0.1.2"
env_logger = "0.11.9"
reedline = "0.38"
serde_yaml_bw = "2.5"

rstest = "0.26.1"
serde_test = "1.0.177"
testing_logger = "0.1.1"
#ratatui = { version = "0.30", features = ["all-widgets"] }
test-log = "0.2.19"

[[bench]]
name = "preflop_odds"
harness = false
required-features = ["equity"]
