~/bend-docscommunity

main.bend source

main.bend on the hub · documented module

# main.bend: Minesweeper in a window.# ===================================## Build and run it:##   bend main.bend -o minesweeper#   ./minesweeper## Left-click opens a square. Right-click flags one. Middle-click, or a# left-click on a number that already has all its flags, opens every# square around it at once. `r` deals a new board.## The status line is the window title, because the playfield fills the# window: a 16x16 board of 32x32 tiles is exactly 512x512 pixels, and# an Image is a quadtree over a square.import Baseimport ./game.bend as GM# The seed comes from /dev/urandom, so each run lays a different board.# If that file is not there, the game falls back to a fixed board.def Main.mix(bs: List<&2, U32>, acc: U32) -> U32:  match bs:    case Nil{}:      acc    case Con{b, rest}:      Main.mix(rest, (acc * 256 + b : U32))def Main.seed.take(r: Result<&1, &1, U32 & String, List<&2, U32>>) -> U32:  match r:    case Fail{e}:      20260917    case Done{bs}:      Main.mix(bs, 0)def Main.seed.close(  pair: File & Result<&1, &1, U32 & String, List<&2, U32>>) -> IO(U32):  (fh, r) = pair  do IO<U32>:    File.close(fh)    return Main.seed.take(r)def Main.seed.open(r: Result<&1, &1, U32 & String, File>) -> IO(U32):  match r:    case Fail{e}:      IO.pure(U32, 20260917)    case Done{fh}:      IO.bind(File & Result<&1, &1, U32 & String, List<&2, U32>>, U32,        File.read_bytes(fh, 4), Main.seed.close)def Main.seed() -> IO(U32):  IO.bind(Result<&1, &1, U32 & String, File>, U32,    File.open("/dev/urandom", "r"), Main.seed.open)# One frame: drop the image the window handed back, fold this frame's# events into the state, refresh the title, and hand the loop on.# `rest` is a closure, not a name, because two functions may not call# each other in Bend.def Main.turn.go(  pair: GM.Game & Bool,  w: Window,  rest: Window -> Bool -> GM.Game -> IO(Unit)) -> IO(Unit):  (ng, al) = pair  +g2 = ng  do IO<Unit>:    w2 : Window <- Window.set_title(w, GM.Game.title(g2))    rest(w2, al, g2)def Main.turn(  shown: Window & Image & List<Event>,  g: GM.Game,  rest: Window -> Bool -> GM.Game -> IO(Unit)) -> IO(Unit):  (w, img, evs) = shown  do IO<Unit>:    IO.pure(Unit, Image.drop(img))    Main.turn.go(GM.Game.feed(evs, True{}, g), w, rest)def Main.loop(fuel: Nat, alive: Bool, w: Window, g: GM.Game) -> IO(Unit):  match fuel alive:    case 0n a:      Window.close(w)    case Succ{f} False{}:      Window.close(w)    case Succ{f} True{}:      +gg = GM.Game.tock(g)      do IO<Unit>:        shown : Window & Image & List<Event> <- Window.frame(w, GM.Game.image(gg))        Main.turn(shown, gg, w2 => al => ng => Main.loop(f, al, w2, ng))def main() -> IO(Unit):  do IO<Unit>:    sd : U32 <- Main.seed()    +g : GM.Game = GM.Game.new(4n, 40, sd, 5n)    +px : U32 = GM.Game.size(g)    w : Window <- IO.try(Window, Window.open(GM.Game.title(g), px, px))    Main.loop(U32.to_nat(4294967295), True{}, w, g)