// ============================================================================ // Pig — the press-your-luck dice game, scored from a roll log // ============================================================================ // // In Pig a player rolls a d6 repeatedly, banking the running total — but a 1 // busts the turn and scores 0. turn_score() folds a list of rolls into the // banked points. play() runs the "hold at 20" strategy over a deterministic // roll stream and reports the turn outcomes. // // Run: soma run pig_dice.cell --signal demo // Test: soma test pig_dice.cell cell PigDice { face { signal turn_score(rolls: List) -> Int signal hold_at(rolls: List, target: Int) -> Map signal demo() -> Map } // Sum the rolls; a single 1 anywhere busts the whole turn to 0. on turn_score(rolls: List) { if any(rolls, r => r == 1) { return 0 } return sum(rolls) } // Stop as soon as the running total reaches `target` (or a 1 busts). on hold_at(rolls: List, target: Int) { let total = 0 let busted = false let used = 0 for r in rolls { if total < target && busted == false { used = used + 1 if r == 1 { total = 0 busted = true } else { total = total + r } } } return map("score", total, "rolls_used", used, "busted", busted) } on demo() { // rolls 5,4,6,3 → 18, then 5 → 23 ≥ 20, hold return hold_at([5, 4, 6, 3, 5, 2], 20) } } cell test PigTests { rules { // clean run, no 1 assert turn_score([3, 4, 5]) == 12 // a 1 busts the turn to 0 assert turn_score([6, 6, 1, 6]) == 0 assert turn_score([]) == 0 // hold-at-20: 5+4+6+3+5 = 23, stops after 5 rolls assert hold_at([5, 4, 6, 3, 5, 2], 20).score == 23 assert hold_at([5, 4, 6, 3, 5, 2], 20).rolls_used == 5 // busting before target assert hold_at([5, 1, 6, 6], 20).busted == true assert hold_at([5, 1, 6, 6], 20).score == 0 } }