Skip to content

ferrohd/bowling-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bowling-rs

docs.rs Crates.io License: GPL-3.0-or-later Crates.io Total Downloads GitHub Repo stars

A bowling game engine in Rust. It handles scoring, frame tracking, multiplayer turn rotation, and split detection for ten-pin, candlepin, and duckpin bowling.

The interesting bit is that the game is modelled as a typestate machine. Rolling on a finished game or building a game with no players are compile errors, not runtime ones. Frames work the same way internally: each delivery consumes the current frame state and produces the next one, so invalid transitions can't happen.

Usage

use bowling_rs::prelude::*;

let alice = Player::new("Alice").unwrap();
let bob = Player::new("Bob").unwrap();
let game = GameBuilder::<TenPin>::new(alice)
    .add_player(bob)
    .build();

let mut progress = Progress::AwaitingRoll(game);

loop {
    match progress {
        Progress::AwaitingRoll(g) => {
            progress = g.roll_count(10).unwrap();
        }
        Progress::Complete(g) => {
            for (i, board) in g.scoreboards().iter().enumerate() {
                println!("{}: {}", g.player(i).name(), board.total);
            }
            break;
        }
    }
}

roll_count(n) picks n pins for you. If you need to control which specific pins get knocked down, or record a foul, use roll() with a Roll directly:

// specific pins
let delivery = Roll::clean(PinSet::of([0, 1, 2]));
let progress = game.roll(delivery).unwrap();

// foul: pins physically fell, but score is zero
let foul = Roll::foul(PinSet::of([0, 1, 2]));

Turn rotation between players is handled automatically. After each player finishes a frame, the next one bowls the same frame, and so on.

Supported rulesets

Ten-pin Candlepin Duckpin
Balls per frame 2 3 3
Deadwood Cleared Remains Cleared
3-ball clearance n/a Spare (bonus) AllDown (no bonus)
Split detection Yes No No

All three use 10 pins, 10 frames, and the usual bonus scoring (strike = next 2 balls, spare = next 1 ball). The Ruleset trait is open, so you can implement your own variant if you need different pin counts, frame counts, deadwood rules, etc.

Pins

Pins are tracked with PinSet, a u16 bitset. Set operations like difference, union, intersection, and complement are all there, and most are const:

let rack = PinSet::full::<10>();
let knocked = PinSet::of([0, 5]);
let standing = rack - knocked;
assert_eq!(standing.count(), 8);

Scoring

game.scoreboard(i) computes per-frame scoring. Frames waiting on future bonus rolls show as Pending rather than giving you a wrong number. Once enough rolls exist they resolve with base, bonus, and cumulative totals:

Frame |   1 |   2 |   3 |   4 |   5 |   6 |   7 |   8 |   9 |  10 |
Base  |  10 |  10 |  10 |  10 |  10 |  10 |  10 |  10 |  10 |  30 |
Bonus |  20 |  20 |  20 |  20 |  20 |  20 |  20 |  20 |  10 |   0 |
Cum.  |  30 |  60 |  90 | 120 | 150 | 180 | 210 | 240 | 270 | 300 |
Total: 300

Split detection

For ten-pin, TEN_PIN_GEOMETRY models the physical pin layout as an adjacency graph. A split is when the head pin is down and the remaining pins form disconnected groups:

let standing = PinSet::of([6, 9]); // 7-10 split
assert!(TEN_PIN_GEOMETRY.is_split(standing));

Detection uses BFS over the PinSet bitset, so there's no allocation involved.

Examples

cargo run --bin perfect_game   # 12 strikes, 300 points
cargo run --bin multiplayer    # two-player game with scoreboards
cargo run --bin splits         # split detection on various pin leaves
cargo run --bin rulesets        # same rolls under ten-pin, candlepin, duckpin

Tests

cargo test

This runs unit tests, property tests (proptest), and compile-fail tests (trybuild). The compile-fail tests check that rolling on a completed game and building with no players are type errors.

License

Licensed under the GNU General Public License v3.0 or later.

For commercial licensing options (use without GPL obligations), contact the project maintainer.

About

A typestate-driven bowling game engine in Rust.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages