Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: CI

on:
pull_request:
push:
branches:
- main

jobs:
rust:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt

- name: Check formatting
run: cargo fmt --check

- name: Lint
run: cargo clippy --all-targets -- -D warnings

- name: Test
run: cargo test --all-targets

- name: Doctest
run: cargo test --doc

- name: Build docs
run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps

- name: Verify package
run: cargo package
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ version = "0.1.0"
edition = "2021"
license = "MIT"
description = "Stateful baseball game replay engine for scoring event streams"
repository = "https://github.com/Jud/diamond-replay"
homepage = "https://github.com/Jud/diamond-replay"
documentation = "https://docs.rs/diamond-replay"
readme = "README.md"
keywords = ["baseball", "replay", "statistics", "gamechanger", "tui"]
categories = ["command-line-utilities", "parser-implementations"]

[dependencies]
crossterm = { version = "0.29.0", features = ["event-stream"] }
Expand Down
22 changes: 15 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,32 @@ Four TUI views: Box Score, Batting, Pitching, Little League. Press `?` on any st

`--little-league` adds per-team youth stats: run sourcing, pace, baserunning chaos, free bases.

`--no-steal-home` replays the game with steal-of-home attempts blocked. Runners stay at 3B but auto-score on any subsequent ball in play that doesn't end the inning, plus walks, WP, and PB.
`--no-steal-home` replays the game with chaos scoring from 3B blocked. Runners stay at 3B but auto-score on any subsequent ball in play that doesn't end the inning, plus forced advances such as walks and HBP.

## Library

```rust
let result = diamond_replay::replay_from_json(&event_json)?;
use diamond_replay::{replay_from_json, replay_from_json_with_options, ReplayOptions};

let result = replay_from_json(&event_json)?;
let simulated = replay_from_json_with_options(
&event_json,
ReplayOptions::no_steal_home(),
)?;

for (id, player) in &result.player_stats {
let b = &player.batting;
println!("{id}: {}/{} | {:.3} wOBA", b.hits, b.ab, b.woba.unwrap_or(0.0));
}
```

The supported library surface is exposed from the crate root: replay functions, `ReplayOptions`, `RuleSet`, `RawApiEvent`, `ReplayError`, `GameResult`, and the result stat structs.

## Stats

### Batting

PA, AB, H, TB, XBH, AVG, OBP, SLG, OPS, ISO, BABIP, wOBA, K%, BB%, BB/K, GB%, FB%, LD%, HR/FB, RBI, R, SB, CS, SB%, GIDP, QAB%, Competitive AB%, P/PA, Hard Hit%.
PA, AB, H, TB, XBH, AVG, OBP, SLG, OPS, ISO, BABIP, wOBA, K%, BB%, BB/K, GB%, FB%, LD%, HR/FB, RBI, R, SB, CS, SB%, GIDP, CI, QAB%, Competitive AB%, P/PA, Hard Hit%.

### Pitching

Expand Down Expand Up @@ -76,18 +84,18 @@ See `testdata/` for 14 complete game files from real 10U and 13U games.
cargo test
```

68 tests: 39 unit (stat computation, stat help coverage), 29 integration (full-game linescores, LL balance invariants, undo/redo, simulation).
100 tests: 64 unit (stat computation, stat help coverage, rule compiler, stream traversal, shadow state, lineup mutation handling), 34 integration/artifact tests (full-game linescores, accounting gates, LL balance invariants, undo/redo, simulation), and 2 doctests.

## Architecture

~5,500 lines of Rust. Dependencies: `serde`, `serde_json`, `thiserror`, `ratatui`, `crossterm`.
~6,200 lines of Rust, plus fixture-backed integration tests. Dependencies: `serde`, `serde_json`, `thiserror`, `ratatui`, `crossterm`.

```
src/
lib.rs public API
lib.rs public API and stable type re-exports
event.rs JSON parsing, typed event enums
undo.rs stack-based undo/redo resolution
filter.rs EventFilter trait, simulation filters
rules/ rule-set event stream compilers
state.rs GameState, BaseState, PAContext
replay.rs state machine, event loop, LL stats
compute.rs pure stat formulas
Expand Down
9 changes: 6 additions & 3 deletions docs/LEGACY_STATS.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ pub struct RawStats {
| `strikes_looking` | `pitch` result = `strike_looking` |
| `fouls` | `pitch` result = `foul` |
| `bip` | `pitch` result = `ball_in_play` |
| `hbp` | `pitch` result = `hit_by_pitch`, or `end_at_bat` reason = `hit_by_pitch` or `catcher_interference` |
| `hbp` | `pitch` result = `hit_by_pitch`, or `end_at_bat` reason = `hit_by_pitch` |
| `ci` | `end_at_bat` reason = `catcher_interference` |
| `k` | Strike count reaches 3 (via strikes), or dropped third strike |
| `k_looking` | K where last strike was `strike_looking` |
| `k_swinging` | K where last strike was `strike_swinging` |
Expand Down Expand Up @@ -115,6 +116,7 @@ pub struct BattingStats {
pub k_swinging: i32, // strikeouts swinging
pub bb: i32, // walks
pub hbp: i32, // hit by pitch
pub ci: i32, // catcher interference
pub singles: i32, // singles
pub doubles: i32, // doubles
pub triples: i32, // triples
Expand All @@ -130,12 +132,13 @@ pub struct BattingStats {

| Field | Recorded by | Trigger |
|-------|------------|---------|
| `pa` | `record_k`, `record_bb`, `record_hbp`, `record_bip`, `record_dropped_k` | Every completed PA |
| `pa` | `record_k`, `record_bb`, `record_hbp`, `record_ci`, `record_bip`, `record_dropped_k` | Every completed PA |
| `k` | `record_k`, `record_dropped_k` | Strikeout (3 strikes or dropped third) |
| `k_looking` | `record_k`, `record_dropped_k` | K where `looking=true` (last strike was called) |
| `k_swinging` | `record_k`, `record_dropped_k` | K where `looking=false` |
| `bb` | `record_bb` | Ball 4 |
| `hbp` | `record_hbp` | Hit by pitch or catcher interference |
| `hbp` | `record_hbp` | Hit by pitch |
| `ci` | `record_ci` | Catcher interference |
| `singles` | `record_bip` | `PlayResult::Single` |
| `doubles` | `record_bip` | `PlayResult::Double` |
| `triples` | `record_bip` | `PlayResult::Triple` |
Expand Down
Loading
Loading