soma.cell

Rock-paper-scissors — round judging and best-of-N scoring judge(a, b) returns "p1", "p2", or "tie" from the two throws

play_match scores a list of round pairs and reports the winner. Pure and deterministic. Run: soma run rock_paper_scissors.cell --signal demo Test: soma test rock_paper_scissors.cell

A Soma program from the games part of the verified corpus: 72 lines, cells RockPaperScissors, RpsTests. It passes soma check with soma 3.2.4.

How it is built

The cell RockPaperScissors declares 4 signals in its face: judge(a: String, b: String) -> String, beats(a: String, b: String) -> Bool, play_match(rounds: List) -> Map and demo() -> Map. Handlers: beats (line 20), judge (line 29), play_match (line 36) and demo (line 48).

The file also holds 1 test cell (RpsTests) with 6 assertions, run by soma test.

Generated from soma describe on this file.

The source

soma.toml

[package]
name = "games-corpus"
version = "0.1.0"
description = "Training corpus: games & simulations"

# The turn/phase machine is intentionally cyclic (a game loops through
# phases each round) with a `* -> over` escape, so we verify only that no
# reachable state deadlocks — liveness to a terminal is not the contract here.
[verify]
deadlock_free = true

rock_paper_scissors.cell

// ============================================================================
// Rock-paper-scissors — round judging and best-of-N scoring
// ============================================================================
//
// judge(a, b) returns "p1", "p2", or "tie" from the two throws. play_match
// scores a list of round pairs and reports the winner. Pure and deterministic.
//
// Run:  soma run rock_paper_scissors.cell --signal demo
// Test: soma test rock_paper_scissors.cell

cell RockPaperScissors {
    face {
        signal judge(a: String, b: String) -> String
        signal beats(a: String, b: String) -> Bool
        signal play_match(rounds: List) -> Map
        signal demo() -> Map
    }

    // Does throw a beat throw b?
    on beats(a: String, b: String) {
        return match a {
            "rock"     -> b == "scissors"
            "paper"    -> b == "rock"
            "scissors" -> b == "paper"
            _          -> false
        }
    }

    on judge(a: String, b: String) {
        if a == b { return "tie" }
        if beats(a, b) { return "p1" }
        return "p2"
    }

    // rounds is a list of {p1, p2} maps; tally wins and name the victor.
    on play_match(rounds: List) {
        let s1 = 0
        let s2 = 0
        for r in rounds {
            let w = judge(r.p1, r.p2)
            if w == "p1" { s1 = s1 + 1 }
            if w == "p2" { s2 = s2 + 1 }
        }
        let winner = if s1 > s2 { "p1" } else if s2 > s1 { "p2" } else { "tie" }
        return map("p1", s1, "p2", s2, "winner", winner)
    }

    on demo() {
        return play_match([
            map("p1", "rock",     "p2", "scissors"),
            map("p1", "paper",    "p2", "scissors"),
            map("p1", "scissors", "p2", "rock")
        ])
    }
}

cell test RpsTests {
    rules {
        assert judge("rock", "scissors") == "p1"
        assert judge("rock", "paper") == "p2"
        assert judge("paper", "paper") == "tie"
        assert beats("scissors", "paper") == true
        assert beats("scissors", "rock") == false
        // best-of-3: p1 takes round 1, loses 2 & 3 → p2 wins the match
        assert play_match([
            map("p1", "rock",     "p2", "scissors"),
            map("p1", "rock",     "p2", "paper"),
            map("p1", "scissors", "p2", "rock")
        ]).winner == "p2"
    }
}

What the toolchain says

Run on a fresh copy of the program at build time; the outputs are pasted unedited.

$ soma check rock_paper_scissors.cell
✓ All checks passed.
$ soma test rock_paper_scissors.cell
test RpsTests ...
  ✓ assert judge("rock", "scissors") == "p1"
  ✓ assert judge("rock", "paper") == "p2"
  ✓ assert judge("paper", "paper") == "tie"
  ✓ assert beats("scissors", "paper") == true
  ✓ assert beats("scissors", "rock") == false
  ✓ assert play_match([ map("p1", "rock", "p2", "scissors"), map("p1", "rock", "p2", "paper"), map("p1", "scissors", "p2", "rock") ]).winner == "p2"

6 tests: 6 passed, 0 failed
$ soma verify rock_paper_scissors.cell
Verifying rock_paper_scissors.cell...
No state machine in this program: nothing to prove beyond `soma check` (invariants and lifecycles are what verify proves).
VERIFY OK (vacuous — no state machine)

Builtins used

map

Source file: /corpus/games/rock_paper_scissors.cell · examples/corpus/games/rock_paper_scissors.cell