librarygames/shut-the-box/ShutTheBox.xtl
Shut the box's rules, a library: shut-the-box.xtl (scripted), play.xtl (at the terminal) and the web page all use these. Tiles 1 to 9 start open. Each turn roll two dice (one die once the open tiles add up to 6 or less) and shut open tiles adding up to the roll. When no set of open tiles makes the roll, the game is over and the open tiles are the score; shut them all to win.
The state is the open tiles as a 0/1 vector of 9.
ˡn̲ew : (Any a, Num b) => a -> b
A new box: all nine tiles open (1).
ˡn̲ew ← { x → 9 r̲eshape 1 }
ˡs̲core : Int -> Int
The open tiles' sum: the tiles times the 0/1 vector, an inner product.
ˡs̲core ← { s → s '+ '× i̲nner r̲ange 9 }
ˡs̲ubsets : Unit -> Int
Every set of tiles at once: the 512 subsets of 1 to 9 as the columns of a 9 by 512 matrix of bits (the binary digits of 0 to 511), and all their sums by one inner product.
ˡs̲ubsets ← { @ → 2 2 2 2 2 2 2 2 2 e̲ncode o̲ffsets 512 }
ˡs̲ums : Unit -> Int
Every subset's sum: the tiles' numbers against the 512 subsets, one inner product.
ˡs̲ums ← { @ → (r̲ange 9) '+ '× i̲nner ˡs̲ubsets @ }
ˡr̲oll : Int -> Int
The roll: two dice, or one when the open tiles add up to 6 or less.
ˡr̲oll ← { s → r̲oll! (1 + 6 < ˡs̲core s) r̲eshape 6 }
ˡm̲oves : Int -> Int -> Int
The moves for roll r: the subsets that use only open tiles (every bit at most the tile's 0 or 1) and add up to r, one per row.
ˡm̲oves ← { s r → M ← ˡs̲ubsets @ fits ← '∧ r̲/ M ≤ s 'l̲eft t̲able o̲ffsets 512 o̲\ (w̲here fits ∧ r = ˡs̲ums @) s̲elect₂ M }
ˡs̲hut : (Num a, Truthy a, Truthy b) => a -> b -> a
Shut the tiles of a move (a 0/1 vector of 9).
ˡs̲hut ← { s m → s × n̲ot m }
ˡs̲tatus : Num a => Int -> Int -> a
0 playing, 1 the box shut, 2 stuck (the score stands).
ˡs̲tatus ← { s r → f̲irst (((0 = ˡs̲core s) c̲at 0 = t̲ally s ˡm̲oves r) r̲eplicate 1 2) c̲at 0 }
ˡv̲iew : Int -> Char
The tiles as the box shows them: open ones by number, shut ones as ., spaced (lib/Board).
ˡv̲iew ← { s → r̲avel ᵇs̲paced (1 9 r̲eshape 1 + s × r̲ange 9) s̲elect ".123456789" }
ˡt̲iles : Truthy a => a -> Char
A move as its tiles, "1 2 4".
ˡt̲iles ← { m → f̲ormat w̲here m }