Skip to content
cuihairuPublic

Repository files navigation

English | 中文

Sandtable logo

Sandtable

Docs Deploy Docs CI License

Sandtable is a configuration-driven simulation and experimentation framework for game systems.

Sandtable is a configuration-driven simulation and experimentation framework for game systems. It is used to simulate players, combat, the economy, and progression over long time horizons, and to support game-balance work through experiments and metric analysis.

Positioning (read this first)

  • Relative comparison, not absolute prediction. Player behavior probabilities are set by hand, so the absolute numbers produced by the simulation are not to be trusted on their own. Sandtable's value lies in comparison: the difference between parameter A and parameter B when both run the same experiment (e.g. ΔD7 Power, ΔWinRate), together with confidence intervals.
  • Modeling assumptions: at the MVP stage, players are mutually independent, only PvE content exists, and economy metrics are aggregates of resource income and spending across all players. This is the largest modeling assumption, and it drives the "parallelize by player" architecture. Introducing markets, PvP, or guilds would change the architecture and is out of MVP scope.
  • Forms: CLI (MVP) / Web (Rust→WASM + React) / Desktop (Tauri 2); all three forms share the same Rust kernel; local-first, no server. Result data goes through Arrow / Parquet, with DuckDB (native and DuckDB-Wasm) as the analysis layer.

Current status

The planned slices through Phase 8 are implemented (crates: sandtable-core + sandtable-cli; all three forms — CLI, Web (Rust→WASM + React) and a Linux-first Desktop shell (Tauri 2) — link the same kernel, which has zero platform dependencies and continuously passes the wasm32-unknown-unknown compile gate):

  • Keyed RNG: derived directly from (seed, actor_id, day, event_index, purpose); combat uses explicit sequence keys so that A/B arms share keys and remain comparable (CRN)
  • A YAML-configured RPG loop: behavior → resolved combat → rewards → progression → stagnation → churn, advancing as day-granularity discrete events
  • Experiment statistics: the replicate is the statistical unit; t-distribution CI₉₅, paired differences + effect size d, and CI verdicts under the PASS/BORDERLINE/FAIL convention
  • Experiment layer: grid / random / Latin-hypercube sweeps, OAT sensitivity, interpolated single-axis recommendations, and optimization (evolutionary and Pareto multi-objective) backed by a random-forest surrogate model
  • Online metric aggregation: retention / win rate / inflation / sink_ratio / power percentile snapshots, sliced by cohort; pulls-to-hit for pity-driven gacha
  • Random-function extension: weighted tables (compile-time CDF), shuffling and weighted sampling without replacement, pity state machines, Box–Muller normals, and a chi-square disttest for distribution checks
  • Reporting and exchange: single-file HTML reports, .sandtable project archives, a two-way CSV parameter table, and Arrow / Parquet behind a feature flag
  • Testing: closed-form cross-checks, byte-for-byte determinism under the same seed, golden snapshots, and equivalence tests locking CLI ↔ Web (WASM) ↔ Desktop to one kernel
  • Python bindings: a pyo3 + maturin extension module (sandtable-sim wheel; load / run / sweep / recommend / params, plus the stage-3 day-level read-only hook run_with_day_hook), with parity tests locking Python ↔ CLI to one kernel — crate README
cargo install --path crates/sandtable-cli
sandtable simulate --players 10000 --days 30 --out out/     # single run
sandtable compare --attack-a 100 --attack-b 105 --replicates 12 --out out/  # A/B comparison
sandtable validate --days 30                                # validate parameters

A single run of 10k players × 30 days takes about 0.5 s (release build). The full plan lives in the documentation site (sources under docs/); for the roadmap see 18 · Roadmap.

Documentation structure

The original plan was a single monolithic document (archived at docs/计划-原始.md), later split into 20 chapters, with five more chapters added for the Pokémon case study, the Web form, the genre matrix, the random-function extension and the formula-curve reference. The mapping from chapters to the original plan:

Chapter Contents Original plan
01 Positioning Core problem, modeling assumptions, relative-comparison stance §1
02 Scope What is included, what is excluded, license §2
03 Core concepts The seven concepts, the Model/World split §3
04 Simulation kernel World composition, execution loop, parallelism model §4
05 Time model Layered nesting: discrete events + in-combat ticks §4.1, §21
06 Deterministic RNG Keyed randomness, parallel determinism rules §5
07 Configuration and formula engine Parameter registry, config_hash, expression compilation §6
08 Tech stack Selection table and dependency decision records §7, §8
09 Data output JSON/CSV first; Parquet behind a feature flag §9
10 CLI Subcommands and output conventions §10
11 Experiment pipeline Full workflow and replicates §11
12 Parameter sweep Grid / Random / Monte Carlo §12
13 KPIs and metrics Metric formulas, online aggregation, CI-based verdicts §13
14 Sensitivity analysis OAT elasticities (selected method) §14
15 Balance recommendation Interpolated intervals, confidence definitions §15
16 MVP Minimal RPG loop, A/B comparison, acceptance criteria §16, §17, §26
17 Project structure Crate split and naming checks §18
18 Roadmap Vertical slices + verification nodes §19
19 Testing strategy Layered: closed-form checks, snapshots, statistical regression §20
20 Design principles and vision Principles, product forms, vision §22–§25
21 Real-configuration validation Pokémon (Gen 1 Kanto) case study and the friction list —
22 Web Browser form, scale boundaries, query and export —
23 Genre × simulation functions Six genre families vs. generic blocks / genre-specific gaps —
24 Random functions Weighted tables, pity, normals, chi-square and staging —
25 Common functions and curves Built-in function reference and evaluator-generated curve library —

License

Apache-2.0.