~/bend-docscommunity

cell.bend source

cell.bend on the hub · documented module

# Cell: one square of the board, and the two moves that act on it.# ================================================================## A cell carries three facts: whether it hides a mine, how many mines# touch it, and what the player has done to it. `near` is fixed when# the board is laid out. `mine` is fixed for the whole game. Only# `mark` moves, and it moves through a small state machine:##   Hidden  --flag-->  Flagged  --flag-->  Hidden#   Hidden  --open-->  Shown## A flag blocks an open, and a shown cell is final. LAWS.bend states# these as claims, and PROOF.bend proves them.import Basetype Mark is Data:  Hidden{}  Flagged{}  Shown{}type Cell is Data:  Cell{mine: Bool, near: U32, mark: Mark}def Mark.is_hidden(k: Mark) -> Bool:  match k:    case Hidden{}:      True{}    case Flagged{}:      False{}    case Shown{}:      False{}def Mark.is_flagged(k: Mark) -> Bool:  match k:    case Hidden{}:      False{}    case Flagged{}:      True{}    case Shown{}:      False{}def Mark.is_shown(k: Mark) -> Bool:  match k:    case Hidden{}:      False{}    case Flagged{}:      False{}    case Shown{}:      True{}# A flag on a mine stays a flag, so a won board keeps its flags.# Anything else on a mine comes up when the game is lost.def Mark.expose(k: Mark) -> Mark:  match k:    case Hidden{}:      Shown{}    case Flagged{}:      Flagged{}    case Shown{}:      Shown{}def Cell.is_mine(c: Cell) -> Bool:  match c:    case Cell{m, n, k}:      mdef Cell.near(c: Cell) -> U32:  match c:    case Cell{m, n, k}:      ndef Cell.mark(c: Cell) -> Mark:  match c:    case Cell{m, n, k}:      kdef Cell.is_hidden(c: Cell) -> Bool:  match c:    case Cell{m, n, k}:      Mark.is_hidden(k)def Cell.is_shown(c: Cell) -> Bool:  match c:    case Cell{m, n, k}:      Mark.is_shown(k)def Cell.is_flagged(c: Cell) -> Bool:  match c:    case Cell{m, n, k}:      Mark.is_flagged(k)# Right-click. It turns a flag on or off and leaves a shown cell alone.def Cell.flag(c: Cell) -> Cell:  match c:    case Cell{m, n, k}:      match k:        case Hidden{}:          Cell{m, n, Flagged{}}        case Flagged{}:          Cell{m, n, Hidden{}}        case Shown{}:          Cell{m, n, Shown{}}# Left-click. A flagged cell does not open; a shown cell does not change.def Cell.open(c: Cell) -> Cell:  match c:    case Cell{m, n, k}:      match k:        case Hidden{}:          Cell{m, n, Shown{}}        case Flagged{}:          Cell{m, n, Flagged{}}        case Shown{}:          Cell{m, n, Shown{}}# The end of a lost game: every mine that is not flagged comes up.def Cell.expose(c: Cell) -> Cell:  match c:    case Cell{m, n, k}:      match m:        case True{}:          Cell{True{}, n, Mark.expose(k)}        case False{}:          Cell{False{}, n, k}# A shown cell with no mine next to it. The flood spreads out of these.def Cell.is_open_blank(c: Cell) -> Bool:  match c:    case Cell{m, n, k}:      Bool.and(Mark.is_shown(k), U32.is_eq(n, 0))# Counters. Grid.sum adds these up over the whole board in parallel.def Cell.one_shown(c: Cell) -> U32:  Bool.to_u32(Cell.is_shown(c))def Cell.one_flag(c: Cell) -> U32:  Bool.to_u32(Cell.is_flagged(c))def Cell.one_mine(c: Cell) -> U32:  Bool.to_u32(Cell.is_mine(c))# A shown mine. One of these means the game is lost.def Cell.one_boom(c: Cell) -> U32:  match c:    case Cell{m, n, k}:      Bool.to_u32(Bool.and(m, Mark.is_shown(k)))