librarygames/robot-chase/RobotChase.xtl
Robot chase's rules, a library: robot-chase.xtl (scripted), play.xtl (at the terminal) and the web page all use these. A 16 by 16 board, you and 12 robots. Every turn you step (or wait, or teleport), then every robot steps one square toward you, all at once. Robots that land on the same square crash and leave a wreck; a robot that walks into a wreck is destroyed. Clear the board to win; meet a robot or a wreck and you lose. Ported from the COR24 BASIC robot-chase.bas.
The game is one flat vector of numbers (so a page can hand it back in): player row and column (0 to 15), teleports left, turn, the last event, the status (0 playing, 1 won, 2 lost), then the robots' rows, their columns, which are alive (12 each), and the wrecks (256 cells).
Reading the state
ˡr̲obots : a -> a
The robots as a 2 by 12 matrix: row 1 their rows, row 2 their columns.
ˡr̲obots ← { s → (2 c̲at ˡn) r̲eshape (2 × ˡn) t̲ake ˡhead d̲rop s }
ˡa̲live : a -> a
Which robots still run (1) or are wrecked (0).
ˡa̲live ← { s → ˡn t̲ake (ˡhead + 2 × ˡn) d̲rop s }
ˡw̲recks : a -> a
The wreck piles on the 16 by 16 field (1 a pile).
ˡw̲recks ← { s → 16 16 r̲eshape -256 t̲ake s }
ˡc̲ell : Num a => a -> a
A square's number, 1 to 256, from row and column (or many, as a 2-row matrix).
ˡc̲ell ← { rc → 16 ᵇc̲ell rc }
ˡo̲nSquares : (Num a, Truthy a) => Int -> a -> a
How much of w lands on each of the 256 squares, when item i of w is on square k[i]: a 256 by 12 table of square against robot, times w (an inner product). With w the live robots, the robots per square.
ˡo̲nSquares ← { k w → ((r̲ange 256) '= t̲able k) '+ '× i̲nner w }
A new game
ˡn̲ew : Any a => a -> Int
13 different squares at random (the order of 256 random keys), as a 2 by 13 matrix of rows and columns: you on the first, a robot on each of the others.
ˡn̲ew ← { x → rc ← 16 ᵇr̲c (ˡn + 1) t̲ake g̲rade r̲oll! 256 r̲eshape 1000000 (1 s̲elect₂ rc) c̲at 3 0 0 0 c̲at (r̲avel 1 d̲rop₂ rc) c̲at (ˡn r̲eshape 1) c̲at 256 r̲eshape 0 }
The robots' turn
ˡc̲hase : Int -> Int
Every live robot steps toward you at once: the sign of the difference (a fork, d [> - <] 0), a 2 by 12 matrix of -1, 0 and 1, added to their positions. Then: a robot on your square catches you; robots on a wreck die; robots sharing a square (more than one live robot there) crash and leave a wreck.
ˡc̲hase ← { s → a ← ˡa̲live s w ← r̲avel ˡw̲recks s d ← ((ˡp̲os s) 'l̲eft t̲able r̲ange ˡn) − ˡr̲obots s R ← (ˡr̲obots s) + ((2 c̲at ˡn) r̲eshape a) × d [> − <] 0 k ← ˡc̲ell R caught ← '∨ r̲/ a × k = ˡc̲ell ˡp̲os s a1 ← a × n̲ot k s̲elect w crash ← a1 × 1 < k s̲elect k ˡo̲nSquares a1 a2 ← a1 × n̲ot crash w2 ← 1 × w ∨ 0 < k ˡo̲nSquares crash caught = 1 ? (4 t̲ake s) c̲at 8 2 c̲at (r̲avel R) c̲at a c̲at w (4 t̲ake s) c̲at (ˡe̲vent s) c̲at (0 = '+ r̲/ a2) c̲at (r̲avel R) c̲at a2 c̲at w2 }
Your turn
ˡk̲eys : Num a => Unit -> a
The numeric keypad: 7 8 9 up, 4 5 6 (5 waits), 1 2 3 down; the step for each key as a column of a 2 by 9 table (rows, columns).
ˡk̲eys ← { @ → 2 9 r̲eshape 1 1 1 0 0 0 -1 -1 -1 -1 0 1 -1 0 1 -1 0 1 }
ˡo̲n : Int -> Int -> Int
What is on square q: 2 a wreck, 1 a live robot, 0 nothing.
ˡo̲n ← { s q → k ← ˡc̲ell q w ← k s̲elect r̲avel ˡw̲recks s r ← '∨ r̲/ (ˡa̲live s) × k = ˡc̲ell ˡr̲obots s (2 × w) m̲ax r }
ˡm̲oved : Num a => a -> a -> a
The state after your move: h is where you are (row, column), the teleports left, the event and the status; the turn counts up.
ˡm̲oved ← { s h → (3 t̲ake h) c̲at (1 + ˡt̲urn s) c̲at (-2 t̲ake h) c̲at ˡhead d̲rop s }
ˡm̲ove : Int -> Int -> Int
A turn: key 1 to 9 steps (5 waits), 0 teleports, 99 resigns; then, unless the game ended, the robots chase. The event says what happened: 0 nothing, 1 blocked by the wall, 2 stepped onto a wreck, 3 walked into a robot, 4 no teleports left, 5 teleported, 6 teleported into a wreck, 7 teleported into a robot, 8 caught, 9 resigned.
ˡm̲ove ← { s c → c = 99 ? s ˡm̲oved (ˡp̲os s) c̲at (ˡt̲ele s) c̲at 9 2 c = 0 ? ˡc̲hase ˡt̲eleport s q ← (ˡp̲os s) + c s̲elect₂ ˡk̲eys @ wall ← '∨ r̲/ (q < 0) ∨ q > 15 wall = 1 ? ˡc̲hase s ˡm̲oved (ˡp̲os s) c̲at (ˡt̲ele s) c̲at 1 0 there ← s ˡo̲n q there = 2 ? s ˡm̲oved q c̲at (ˡt̲ele s) c̲at 2 2 there = 1 ? s ˡm̲oved q c̲at (ˡt̲ele s) c̲at 3 2 ˡc̲hase s ˡm̲oved q c̲at (ˡt̲ele s) c̲at 0 0 }
ˡt̲eleport : Int -> Int
Teleport: the player to a random square, then the robots chase.
ˡt̲eleport ← { s → t ← ˡt̲ele s t ≤ 0 ? s ˡm̲oved (ˡp̲os s) c̲at 0 c̲at 4 0 q ← 16 ᵇr̲c r̲oll! 256 there ← s ˡo̲n q there = 2 ? s ˡm̲oved q c̲at (t − 1) c̲at 6 2 there = 1 ? s ˡm̲oved q c̲at (t − 1) c̲at 7 2 s ˡm̲oved q c̲at (t − 1) c̲at 5 0 }
ˡm̲essage : Int -> Char
What the last event was, as the BASIC said it.
ˡm̲essage ← { s → e ← ˡe̲vent s d̲isclose (1 + e) s̲elect "" "BLOCKED BY WALL." "YOU STEPPED ONTO WRECKAGE." "YOU WALKED INTO A ROBOT." "NO TELEPORTS LEFT." "*BEEP* TELEPORTED." "TELEPORTED INTO WRECKAGE!" "TELEPORTED INTO A ROBOT!" "A ROBOT CAUGHT YOU!" "*** COMMAND RESIGNED ***" }
What you see
ˡc̲odes : Int -> Int
Every square's code at once, from three 0/1 boards: 1 empty, 2 a robot, 3 a wreck, 4 you, 5 where something got you.
ˡc̲odes ← { s → code ← 1 + (0 < (ˡc̲ell ˡr̲obots s) ˡo̲nSquares ˡa̲live s) + 2 × r̲avel ˡw̲recks s kp ← ˡc̲ell ˡp̲os s me ← (r̲ange 256) = kp 16 16 r̲eshape (code × n̲ot me) + me × 4 + 1 < kp s̲elect code }
ˡv̲iew : Int -> Char
The board as text: . empty, R robot, * wreck, P you (X where something got you), spaced, with the BASIC's labels.
ˡv̲iew ← { s → lab ← 16 3 r̲eshape " 0 1 2 3 4 5 6 7 8 9 A B C D E F " top ← 1 35 r̲eshape " 0 1 2 3 4 5 6 7 8 9 A B C D E F " top c̲at lab c̲at₂ ᵇs̲paced (ˡc̲odes s) s̲elect ".R*PX" }
ˡp̲icture : Int -> Char
The board as a picture X_eTaL draws (SVG text): the same characters, one per square of a 16 by 16 grid; []S_HOW shows it.
ˡp̲icture ← { s → ⎕G̲RID (ˡc̲odes s) s̲elect ".R*PX" }
ˡl̲rs : Int -> Int
The long-range scan: the board in 4 by 4 regions, as a 4 by 4 by 4 by 4 array (region row, row, region column, column) summed over the rows and columns inside each region: robots, wrecks, and where you are.
ˡl̲rs ← { s → robots ← (ˡc̲ell ˡr̲obots s) ˡo̲nSquares ˡa̲live s me ← (r̲ange 256) = ˡc̲ell ˡp̲os s (ʰr̲egions robots) c̲at₂ (ʰr̲egions r̲avel ˡw̲recks s) c̲at₂ ʰr̲egions me }