librarygames/minesweeper/Mines.xtl

Minesweeper's rules, a library: minesweeper.xtl (scripted), play.xtl (at the terminal) and the web page all use these. A 9 by 9 field hides 10 mines; open a square to see how many mines touch it, flag the ones you think are mines, and open every safe square to win.

The state is one vector: the status (0 playing, 1 won, 2 lost), then the mines, the opened squares and the flags, three 9 by 9 0/1 boards.

source · imports b: lib/Board.xtl

ˡn : Int

value · line 13

The field's width and height.

ˡn ← 9

ˡm̲ines : a -> a

function · line 16

Where the mines are, n by n (1 a mine).

ˡm̲ines ← { s → (ˡn c̲at ˡn) r̲eshape 81 t̲ake 1 d̲rop s }

ˡo̲pen : a -> a

function · line 19

Which squares are open, n by n.

ˡo̲pen ← { s → (ˡn c̲at ˡn) r̲eshape 81 t̲ake 82 d̲rop s }

ˡf̲lags : a -> a

function · line 22

Which squares are flagged, n by n.

ˡf̲lags ← { s → (ˡn c̲at ˡn) r̲eshape -81 t̲ake s }

ˡs̲tatus : a -> a

function · line 25

0 playing, 1 won, 2 lost.

ˡs̲tatus ← { s → f̲irst s }

ˡs̲tate : a -> a -> a

function · line 28

The state again from a status and the three boards.

ˡs̲tate ← { st m → st c̲at r̲avel m }

ˡn̲ew : (Any a, Num b, Truthy b) => a -> b

function · line 32

A new field: 10 mines on the first 10 squares of a random order.

ˡn̲ew ← { x →
  m ← (r̲ange 81) m̲ember? 10 t̲ake g̲rade r̲oll! 81 r̲eshape 1000000
  0 c̲at m c̲at 162 r̲eshape 0
}

ˡa̲round : Num a => a -> a

function · line 41

The eight neighbors of every square at once, as Life counts them (lib/Board: the board in a border of zeros rotated by every offset and summed, less itself).

ˡa̲round ← { b → ᵇa̲round b }

ˡc̲ounts : Num a => a -> a

function · line 44

How many mines touch each square.

ˡc̲ounts ← { s → ˡa̲round ˡm̲ines s }

ˡw̲ith : a -> a -> a

function · line 48

The state again from a status and the three boards' parts.

ˡw̲ith ← { s so → (f̲irst so) c̲at (r̲avel ˡm̲ines s) c̲at 1 d̲rop so }

ˡr̲eveal : (Num a, Truthy a) => a -> Int -> a

function · line 56

Opening square rc (row, column from 1): a mine loses; otherwise the opened region grows by flood fill: every opened square with no mine around it opens its neighbors, again and again until nothing changes. Squares next to a mine have a count, so the fill never reaches a mine. Opened squares lose their flags.

ˡr̲eveal ← { s rc →
  k ← ˡn ᵇc̲ell rc − 1
  1 = k s̲elect r̲avel ˡm̲ines s ? s ˡw̲ith 2 c̲at (r̲avel (ˡo̲pen s) ∨ ˡm̲ines s) c̲at r̲avel ˡf̲lags s
  start ← (ˡo̲pen s) ∨ (ˡn c̲at ˡn) r̲eshape k = r̲ange 81
  o ← s ˡg̲row start
  won ← 0 = '+ r̲/ r̲avel (n̲ot o) ∧ n̲ot ˡm̲ines s
  s ˡw̲ith won c̲at (r̲avel o) c̲at r̲avel (ˡf̲lags s) ∧ n̲ot o
}

ˡg̲row : (Num a, Truthy a) => a -> a -> a

function · line 66

The opened region grown by flood fill: every opened square with no mine around it opens its neighbors, until nothing changes.

ˡg̲row ← { s o →
  zero ← o ∧ 0 = ˡc̲ounts s
  more ← (o ∨ 0 < ˡa̲round zero) ∧ n̲ot ˡm̲ines s
  more m̲atch o ? o
  s ˡg̲row more
}

ˡf̲lag : (Num a, Truthy a) => a -> Int -> a

function · line 74

Flag (or unflag) square rc, if it is not open.

ˡf̲lag ← { s rc →
  k ← ˡn ᵇc̲ell rc − 1
  1 = k s̲elect r̲avel ˡo̲pen s ? s
  f ← (r̲avel ˡf̲lags s) ≠ k = r̲ange 81
  s ˡw̲ith (ˡs̲tatus s) c̲at (r̲avel ˡo̲pen s) c̲at f
}
Used in: ᵘt̲urn

ˡc̲odes : (Num a, Truthy a) => a -> a

function · line 86

The field as text: # unopened, F flagged, . an opened square with no mine around, 1 to 8 its count, * a mine (shown once the game is lost); row and column numbers around it, spaced (lib/Board). Every square's code at once.

ˡc̲odes ← { s →
  o ← ˡo̲pen s
  shown ← o ∧ n̲ot ˡm̲ines s
  boom ← o ∧ ˡm̲ines s
  1 + ((n̲ot o) ∧ ˡf̲lags s) + (2 × boom) + shown × 3 + ˡc̲ounts s
}

ˡv̲iew : Int -> Char

function · line 94

The field as text: # unopened, F flagged, * a mine (when lost), . an opened square with no mine around, else its count.

ˡv̲iew ← { s →
  lab ← (ˡn c̲at 2) r̲eshape "1 2 3 4 5 6 7 8 9 "
  (1 20 r̲eshape "  1 2 3 4 5 6 7 8 9 ") c̲at lab c̲at₂ ᵇs̲paced (ˡc̲odes s) s̲elect "#F*.12345678"
}

ˡp̲icture : Int -> Char

function · line 100

The field as a picture X_eTaL draws: the same characters in a grid.

ˡp̲icture ← { s → ⎕G̲RID (ˡc̲odes s) s̲elect "#F*.12345678" }
Used in: pic, ᵘt̲urn