Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

STRIKE ZONE!

Ten-pin bowling for Roblox — the frame-scored sports genre rebuilt as pure property-tested scoring laws: exact strike/spare lookahead, a 300-perfect-game invariant, tenth-frame bonus-roll rules, and standing- pin legality, over real physics lanes with two-sweep launch meters.

Core loop

  1. Every player gets their own lane with 10 physics pins.
  2. Click BOWL → the POWER meter sweeps; click to lock it. The ANGLE sweep follows; click again to launch. Server converts fractions into ball velocity and lets physics do the rest.
  3. Pins count as fallen when they tip past 60° or drift off their spot; legality law clamps knockdowns to pins actually standing.
  4. Classic ten-frame rules: strikes/spares chain bonuses, the tenth grants extra rolls on strike or spare, and the game ends exactly when the tenth completes. Chase the perfect 300.

Property-test contracts

  • Frame law: open frames sum; SPARE = 10 + EXACTLY the next one roll; STRIKE = 10 + EXACTLY the next two — shared bonus rolls between consecutive strikes count once for each role, never double-counted.
  • Unscoreable law: a strike with fewer than two future rolls adds NOTHING yet (0), then scores once the rolls arrive.
  • Perfect-game law: twelve strikes = EXACTLY 300; eleven strikes + a nine = 299 (270 through frame nine + 29 in the tenth).
  • Tenth-frame law: open tenth ends after two rolls; a spare grants exactly one bonus (5/5/7 → 17); a strike grants exactly two (10/3/4 → 17); a second tenth strike RESETS the rack for legality purposes.
  • Legality law: pinsStandingForNextRoll tracks frames, spares, and tenth resets exactly ({6}→4, {6,4}→10, {10}→10).
  • End law: not over at 9 strikes, not over when the tenth starts, over precisely on completion; position() tracks frame/roll exactly.
  • Corpus: the canonical Wikipedia example scores its published 133; all gutters score 0 and end the game.

Implementation catches

Two genuine engine bugs caught by the corpus: strike bonuses read the strike itself plus ONE future roll instead of the actual next two (off-by-one on flat[start]), and the tenth-frame sum used table.unpack inside a compound assignment — which silently takes only the FIRST value. Three spec expectations also had hand-arithmetic errors where bonus rolls legitimately re-score as the following frame's own content (e.g. {10,7,2} totals 28, not 19). Plus the recurring pre-declaration nil-global (isFallen) and a duplicated meter state machine in the HUD.

Layout

src/shared/     Config + BowlingMath (frame/perfect/tenth/legality/end laws)
src/server/     Remotes + BowlingService (private lanes, physics pins,
                tip-or-drift fallen detection, settle windows)
src/client/     Network + two-sweep power/angle meter + roll history
tests/          lune headless specs (17) incl. published-score corpus

Commands

lune run tests/run_tests.luau      # unit tests
lune run tests/syntax_check.luau   # compile-check all sources
rojo build -o strike-zone.rbxlx    # validate project mapping
rojo serve                         # live-sync into Studio

CI runs tests, syntax checks, and a Rojo build on every push.

Known gaps (v0.1)

  • No gutter walls — balls that drift far enough fall to the floor
  • No spin/hook mechanic
  • No Studio playtest yet (human dependency)

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages