#poker #cfr #poker-cards #regret-minimization

bin+lib little-sorry

Library to help with coding regret minimization

9 releases (4 stable)

Uses new Rust 2024

2.1.0 Apr 14, 2026
2.0.0 Feb 19, 2026
1.1.0 Mar 28, 2025
0.5.0 Nov 30, 2024
0.1.0 Nov 27, 2019

#91 in Games

Download history 26/week @ 2026-01-25 10/week @ 2026-02-01 25/week @ 2026-02-08 48/week @ 2026-02-15 317/week @ 2026-02-22 86/week @ 2026-03-01 65/week @ 2026-03-08 55/week @ 2026-03-15 56/week @ 2026-03-22 65/week @ 2026-03-29 59/week @ 2026-04-05 40/week @ 2026-04-12 61/week @ 2026-04-19 138/week @ 2026-04-26 256/week @ 2026-05-03 123/week @ 2026-05-10

591 downloads per month
Used in rs_poker

Apache-2.0

54KB
1K SLoC

Little Sorry

A Rust library for regret minimization algorithms (Counterfactual Regret Minimization) used to find Nash equilibrium strategies in imperfect-information games.

Features

  • 6 CFR variants via the RegretMinimizer trait:
    • CFR+ — regret clipping at zero
    • Discounted CFR (DCFR) — time-based discounting with configurable parameters
    • DCFR+ — combines DCFR discounting with CFR+ clipping
    • Linear CFR — linear time-weighted regrets
    • Predictive CFR+ (PCFR+) — uses future regret predictions
    • Predictive DCFR+ (PDCFR+) — combines DCFR+ discounting with predictive updates
  • Zero-allocation hot path — no heap allocations during update_regret
  • Minimal dependencies (rand only)
  • Rock-Paper-Scissors example game (feature-gated behind rps)

Getting Started

Add this to your Cargo.toml:

[dependencies]
little-sorry = "2.1.0"

Quick Example

use little_sorry::{CfrPlusRegretMatcher, RegretMinimizer};

let mut matcher = CfrPlusRegretMatcher::new(3);

// Run many iterations of regret updates
for _ in 0..1000 {
    let rewards = &[1.0, -0.5, 0.2];
    matcher.update_regret(rewards);
}

// Get the Nash equilibrium approximation
let strategy = matcher.best_weight();

All variants implement the RegretMinimizer trait, so you can swap algorithms generically:

use little_sorry::{DiscountedRegretMatcher, RegretMinimizer};

fn train<M: RegretMinimizer>(matcher: &mut M, iterations: usize) {
    for _ in 0..iterations {
        let rewards = &[1.0, -0.5, 0.2];
        matcher.update_regret(rewards);
    }
}

Building and Testing

This project uses mise to manage tooling and tasks.

# Run all checks (formatting, linting, tests, TOML validation)
mise check

# Run tests
mise run check:test:nextest

# Run benchmarks
cargo bench --features rps

# Run the RPS example
cargo run --release --features rps --bin run_rps

License

Licensed under the Apache License, Version 2.0.

Dependencies

~390KB