sourcegames/trek/StarTrek.xtl
1⍝# Star Trek's rules, a library: trek.xtl (scripted), play.xtl (at the
2⍝# terminal) and the web page all use these. The classic Star Trek game
3⍝# as the COR24 BASIC demo plays it: an 8 by 8 galaxy of quadrants, each
4⍝# an 8 by 8 grid of sectors; find and destroy every Klingon before the
5⍝# stardate runs out, with warp and impulse drive, phasers, photon
6⍝# torpedoes and shields.
7⍝#
8⍝# The game is one vector: 1 energy, 2 torpedoes, 3 shields, 4 stardate,
9⍝# 5 deadline, 6 and 7 the quadrant (row, column, 0 to 7), 8 and 9 the
10⍝# sector, 10 the status (0 playing, 1 won, 2 out of time, 3 ship lost,
11⍝# 4 resigned); then the galaxy as three planes of 64 (Klingons, bases,
12⍝# stars per quadrant) and the current quadrant's 64 sectors (0 empty,
13⍝# 1 the Enterprise, 2 a star, 3 a base, 4 and more a Klingon: its hit
14⍝# points plus 4).
15
16ᵇ⁼u̲se< "Board"
17ˢ⁼u̲se< "State"
18ˣ⁼u̲se< "Text"
19
20⍝## Reading the state
21⍝ Where each thing is in the state vector, by name.
22⍝ :: Int
23⍝# Where the energy is, in the state.
24ˡenergy ← 1
25⍝ :: Int
26⍝# Where the torpedoes left are, in the state.
27ˡtorpedoes ← 2
28⍝ :: Int
29⍝# Where the shields are, in the state.
30ˡshieldsAt ← 3
31⍝ :: Int
32⍝# Where the stardate is, in the state.
33ˡstardate ← 4
34⍝ :: Int
35⍝# Where the quadrant's row is, in the state.
36ˡquadRow ← 6
37⍝ :: Int
38⍝# Where the quadrant's column is, in the state.
39ˡquadCol ← 7
40⍝ :: Int
41⍝# Where the sector's row is, in the state.
42ˡsectRow ← 8
43⍝ :: Int
44⍝# Where the sector's column is, in the state.
45ˡsectCol ← 9
46⍝ :: Int
47⍝# Where the status is, in the state.
48ˡstatus ← 10
49
50⍝ :: a -> a
51⍝# The energy left.
52ˡe̲nergy ← { s → 1 s̲elect s }
53⍝ :: a -> a
54⍝# Torpedoes left.
55ˡt̲orps ← { s → 2 s̲elect s }
56⍝ :: a -> a
57⍝# The shields' energy.
58ˡs̲hields ← { s → 3 s̲elect s }
59⍝ :: a -> a
60⍝# The stardate.
61ˡd̲ate ← { s → 4 s̲elect s }
62⍝ :: a -> a
63⍝# The quadrant: row and column, 0 to 7.
64ˡq̲uad ← { s → 6 7 s̲elect s }
65⍝ :: a -> a
66⍝# The sector within the quadrant: row and column, 0 to 7.
67ˡs̲ector ← { s → 8 9 s̲elect s }
68⍝ :: a -> a
69⍝# 0 playing, 1 won, 2 time ran out, 3 the Enterprise lost, 4 resigned.
70ˡs̲tatus ← { s → 10 s̲elect s }
71⍝ :: a -> Int -> a
72⍝# Plane p of the galaxy (1 Klingons, 2 bases, 3 stars), an 8 by 8 matrix.
73ˡg̲alaxy ← { s p → 8 8 r̲eshape 64 t̲ake (10 + 64 × p − 1) d̲rop s }
74⍝ :: a -> a
75⍝# The quadrant shown: 8 by 8 sectors (0 empty, then the Enterprise, a star, a base, a Klingon's hit points).
76ˡg̲rid ← { s → 8 8 r̲eshape -64 t̲ake s }
77⍝ :: Num a => a -> a
78⍝# Klingons in the galaxy and in this quadrant.
79ˡk̲lingons ← { s → '+ r̲/ r̲avel s ˡg̲alaxy 1 }
80⍝ :: (Num a, Num b, Truthy b) => a -> b
81⍝# How many Klingons are in this quadrant.
82ˡh̲ere ← { s → '+ r̲/ r̲avel 4 ≤ ˡg̲rid s }
83
84⍝ :: Int -> Int -> Int
85⍝## Changing it
86⍝# Several items changed at once (lib/State): iv is index, value, ...
87ˡu̲pdate ← { s iv → s ˢu̲pdate iv }
88⍝ :: Int -> Int -> Int
89⍝# The items from position p on replaced by v (pv is p then v; lib/State).
90ˡp̲ut ← { s pv → s ˢp̲ut pv }
91⍝ :: Int -> Int -> Int
92⍝# The state with a new quadrant grid.
93ˡw̲ithGrid ← { s g → s ˡp̲ut ((t̲ally s) − 63) c̲at r̲avel g }
94⍝ :: Int -> Int -> Int
95⍝# The state with plane p of the galaxy replaced (pg is p then its 64 numbers).
96ˡw̲ithPlane ← { s pg → s ˡp̲ut (11 + 64 × (f̲irst pg) − 1) c̲at 1 d̲rop pg }
97⍝ :: Num a => a -> a
98⍝# The quadrant's square in a galaxy plane, 1 to 64.
99ˡh̲ome ← { s → 1 + (8 × 6 s̲elect s) + 7 s̲elect s }
100
101⍝ :: Int -> Char
102⍝## Where things are, said as the BASIC said it
103⍝# A row and column (0 to 7) as "C-5".
104ˡa̲t ← { rc → ((1 + f̲irst rc) s̲elect "ABCDEFGH") c̲at "-" c̲at f̲ormat 1 + 2 s̲elect rc }
105
106⍝ :: Num a => Unit -> a
107⍝# The eight courses of the compass, 1 north, clockwise: the step in rows
108⍝# and columns for each, as a 2 by 8 table.
109ˡc̲ourses ← { @ → 2 8 r̲eshape -1 -1 0 1 1 1 0 -1 0 1 1 1 0 -1 -1 -1 }
110
111⍝ :: Any a => a -> Int
112⍝## A new game and a new quadrant
113⍝# Every quadrant at once: Klingons in about 15 of each 100 (1 to 3 of
114⍝# them), a base in 2 of 10, 1 to 5 stars. A galaxy without Klingons is
115⍝# rolled again.
116ˡn̲ew ← { x →
117 kl ← (85 < r̲oll! 64 r̲eshape 100) × r̲oll! 64 r̲eshape 3
118 0 = '+ r̲/ kl ? ˡn̲ew x
119 bases ← 2 ≥ r̲oll! 64 r̲eshape 10
120 stars ← r̲oll! 64 r̲eshape 5
121 q ← (r̲oll! 8 8) − 1
122 ˡe̲nter (3000 10 0 2300 2330 c̲at q c̲at 0 0 0) c̲at kl c̲at bases c̲at stars c̲at 64 r̲eshape 0
123}
124⍝ :: Int -> Int
125⍝# Entering a quadrant: the Enterprise, its Klingons (5 hit points
126⍝# each), base and stars on different sectors at random, all placed at
127⍝# once: the codes in a row, put into the sectors of a random order (the
128⍝# order's own order is its inverse).
129ˡe̲nter ← { s →
130 c ← ˡh̲ome s
131 n ← c s̲elect r̲avel s ˡg̲alaxy 1
132 b ← c s̲elect r̲avel s ˡg̲alaxy 2
133 i ← c s̲elect r̲avel s ˡg̲alaxy 3
134 order ← g̲rade r̲oll! 64 r̲eshape 1000000
135 codes ← 1 c̲at (n r̲eshape 9) c̲at (b r̲eshape 3) c̲at (i r̲eshape 2) c̲at (63 − n + b + i) r̲eshape 0
136 e ← (f̲irst order) − 1
137 t ← (s ˡu̲pdate ˡsectRow c̲at (e d̲iv 8) c̲at ˡsectCol c̲at e m̲od 8) ˡw̲ithGrid (g̲rade order) s̲elect codes
138 0 = n ? t
139 said ← p̲rint! ""
140 said ← p̲rint! "*** RED ALERT *** RED ALERT *** RED ALERT ***"
141 said ← p̲rint! @ f̲ormat< "*** {n} KLINGON(S) IN QUADRANT {l:a_t l:q_uad s} ***"
142 said ← p̲rint! "*** RED ALERT *** RED ALERT *** RED ALERT ***"
143 t
144}
145
146⍝ :: Int -> Int
147⍝## Scans
148⍝# The short-range scan: the sector grid as characters, every sector at
149⍝# once (a Klingon's code, 4 or more, is cut to 4 and read as K), spaced
150⍝# by lib/Board.
151ˡs̲rs ← { s →
152 said ← p̲rint! ""
153 said ← p̲rint! @ f̲ormat< "QUADRANT {l:a_t l:q_uad s} SECTOR {l:a_t l:s_ector s}"
154 said ← p̲rint! " 1 2 3 4 5 6 7 8"
155 shown ← p̲rint! (8 2 r̲eshape "A B C D E F G H ") c̲at₂ ᵇs̲paced (1 + 4 m̲in ˡg̲rid s) s̲elect ".E*BK"
156 said ← p̲rint! @ f̲ormat< "STARDATE {l:d_ate s} ENERGY {l:e_nergy s} SHIELDS {l:s_hields s} TORP {l:t_orps s}"
157 said ← p̲rint! @ f̲ormat< "QUADRANT {l:a_t l:q_uad s} KLINGONS LEFT {l:k_lingons s}"
158 s
159}
160⍝ :: Int -> Int
161⍝# The long-range scan: the 5 by 5 quadrants around this one, each as its
162⍝# Klingons, bases and stars in three digits, "***" off the galaxy. The
163⍝# window's rows and columns are a table; the three planes' values for
164⍝# the 25 quadrants are one selection from a 3 by 64 matrix, and every
165⍝# cell's four characters are picked at once from " *0123456789".
166ˡl̲rs ← { s →
167 said ← p̲rint! ""
168 said ← p̲rint! @ f̲ormat< "LONG RANGE SCAN AT QUADRANT {l:a_t l:q_uad s}"
169 said ← p̲rint! "LEGEND: K B S K=KLINGONS B=BASES S=STARS ***=VOID"
170 r ← (f̲irst ˡq̲uad s) + -2 -1 0 1 2
171 c ← (2 s̲elect ˡq̲uad s) + -2 -1 0 1 2
172 in ← r̲avel ((r ≥ 0) ∧ r ≤ 7) '∧ t̲able (c ≥ 0) ∧ c ≤ 7
173 cell ← r̲avel 1 + (8 × 0 m̲ax 7 m̲in r) '+ t̲able 0 m̲ax 7 m̲in c
174 planes ← cell s̲elect₂ 3 64 r̲eshape 192 t̲ake 10 d̲rop s
175 digits ← ((3 + planes) × 3 25 r̲eshape in) + 2 × 3 25 r̲eshape n̲ot in
176 shown ← p̲rint! (5 20 r̲eshape r̲avel₂ (25 r̲eshape 1) c̲at digits) s̲elect " *0123456789"
177 s
178}
179
180⍝## Small helpers
181
182⍝ :: (Any a, Any b) => a -> b -> a
183⍝# Say t and give s back.
184ˡs̲ay ← { s t →
185 said ← p̲rint! t
186 s
187}
188⍝ :: Any a => a -> a
189⍝# Refuse a command for want of energy.
190ˡi̲nsufficient ← { s → s ˡs̲ay "INSUFFICIENT ENERGY" }
191⍝ :: Num a => a -> a
192⍝# A sector's number, 1 to 64, from its row and column.
193ˡc̲ell ← { rc → 8 ᵇc̲ell rc }
194⍝ :: Int -> Int -> Int
195⍝# The Enterprise moved to sector rc: its old sector emptied, the new one
196⍝# marked, both in one expression over the 64 sectors.
197ˡm̲oveTo ← { s rc →
198 g ← r̲avel ˡg̲rid s
199 all ← r̲ange 64
200 g ← g × all ≠ ˡc̲ell ˡs̲ector s
201 g ← (g × all ≠ ˡc̲ell rc) + all = ˡc̲ell rc
202 (s ˡu̲pdate ˡsectRow c̲at (f̲irst rc) c̲at ˡsectCol c̲at 2 s̲elect rc) ˡw̲ithGrid g
203}
204⍝ :: Int -> Int -> Int
205⍝# A path from the Enterprise along course c for k steps: a 2 by k matrix
206⍝# of rows and columns, every step at once; and which steps are inside
207⍝# the quadrant, and their sectors (clamped, for looking them up).
208ˡp̲ath ← { s ck →
209 d ← (f̲irst ck) s̲elect₂ ˡc̲ourses @
210 k ← r̲ange 2 s̲elect ck
211 ((ˡs̲ector s) 'l̲eft t̲able k) + d '× t̲able k
212}
213⍝ :: (Num a, Truthy b) => a -> b
214⍝# Whether every point of P (rows and columns) lies inside a quadrant.
215ˡi̲nside ← { P → '∧ r̲/ (P ≥ 0) ∧ P ≤ 7 }
216⍝ :: Num a => a -> a
217⍝# The sectors (1 to 64) of the points P, clamped to the quadrant.
218ˡc̲ells ← { P → 1 + (8 × 0 m̲ax 7 m̲in 1 s̲elect P) + 0 m̲ax 7 m̲in 2 s̲elect P }
219⍝ :: Num a => Int -> a
220⍝# Print each sector of a flat list of rows and columns, " C-5".
221ˡt̲rack ← { v →
222 0 = t̲ally v ? 0
223 said ← p̲rint! @ f̲ormat< " {l:a_t 2 t_ake v}"
224 1 + ˡt̲rack 2 d̲rop v
225}
226
227⍝ :: Int -> Int
228⍝## The Klingons fire back
229⍝# 30 to 60 units: the shields take them first, the rest comes off the
230⍝# energy.
231ˡf̲ire ← { s →
232 0 = ˡh̲ere s ? s
233 u ← 29 + r̲oll! 31
234 h ← ˡs̲hields s
235 e ← (ˡe̲nergy s) − 0 m̲ax u − h
236 h ← 0 m̲ax h − u
237 said ← p̲rint! @ f̲ormat< "HIT - SHIELDS {h} ENERGY {e}"
238 s ˡu̲pdate ˡenergy c̲at e c̲at ˡshieldsAt c̲at h
239}
240
241⍝ :: Int -> Int -> Int
242⍝## Moving
243⍝# Warp: course c, factor p (1 to 8) quadrants; 8 energy and one stardate
244⍝# a factor; clamped at the galaxy's edge; a new quadrant, then a scan.
245ˡw̲arp ← { s cp →
246 c ← f̲irst cp
247 p ← 2 s̲elect cp
248 (c < 1) ∨ (c > 8) ∨ (p < 1) ∨ p > 8 ? s
249 (ˡe̲nergy s) < 8 × p ? ˡi̲nsufficient s
250 q ← (ˡq̲uad s) + p × c s̲elect₂ ˡc̲ourses @
251 said ← (q < 0) ∨ q > 7
252 told ← ˡc̲lamped '+ r̲/ said
253 q ← 0 m̲ax 7 m̲in q
254 ˡs̲rs ˡe̲nter s ˡu̲pdate ˡenergy c̲at ((ˡe̲nergy s) − 8 × p) c̲at ˡstardate c̲at ((ˡd̲ate s) + p) c̲at ˡquadRow c̲at (f̲irst q) c̲at ˡquadCol c̲at 2 s̲elect q
255}
256⍝ :: Num a => Int -> a
257⍝# Say n times that a move was clamped at the galaxy's edge.
258ˡc̲lamped ← { n → ˣl̲ines n r̲eshape e̲nclose "OUT OF GALAXY - CLAMPED" }
259⍝ :: Int -> Int -> Int
260⍝# Impulse: course c, p (1 to 8) sectors, a unit of energy each. The
261⍝# whole path at once; the first step that leaves the quadrant or meets
262⍝# something decides: through to the end, into the next quadrant, or
263⍝# halted just before the obstacle.
264ˡi̲mpulse ← { s cp →
265 c ← f̲irst cp
266 p ← 2 s̲elect cp
267 (c < 1) ∨ (c > 8) ∨ (p < 1) ∨ p > 8 ? s
268 (ˡe̲nergy s) < p ? ˡi̲nsufficient s
269 t ← s ˡu̲pdate ˡenergy c̲at (ˡe̲nergy s) − p
270 P ← s ˡp̲ath c c̲at p
271 in ← ˡi̲nside P
272 busy ← in ∧ 0 ≠ (ˡc̲ells P) s̲elect r̲avel ˡg̲rid s
273 j ← f̲irst (w̲here (n̲ot in) ∨ busy) c̲at p + 1
274 j > p ? ˡs̲rs t ˡm̲oveTo p s̲elect₂ P
275 0 = j s̲elect in ? ˡs̲rs t ˡc̲ross c
276 ˡs̲rs t ˡh̲alt j s̲elect₂ (ˡs̲ector s) c̲at₂ P
277}
278⍝ :: Int -> Int -> Int
279⍝# Leave the quadrant along course c: into the neighbor, clamped at the galaxy's edge.
280ˡc̲ross ← { s c →
281 q ← 0 m̲ax 7 m̲in (ˡq̲uad s) + c s̲elect₂ ˡc̲ourses @
282 ˡe̲nter s ˡu̲pdate ˡquadRow c̲at (f̲irst q) c̲at ˡquadCol c̲at 2 s̲elect q
283}
284⍝ :: Int -> Int -> Int
285⍝# Stop at sector rc in front of an obstacle.
286ˡh̲alt ← { s rc →
287 said ← p̲rint! @ f̲ormat< "OBSTRUCTED - HALTED AT SECTOR {l:a_t rc}"
288 s ˡm̲oveTo rc
289}
290
291⍝ :: Int -> Int -> Int
292⍝## Fighting
293⍝# Phasers: p energy split over the Klingons here; every Klingon is hit
294⍝# at once (its code less the share); those below 4 are destroyed. One
295⍝# line per Klingon, in sector order; then they fire back.
296ˡp̲hasers ← { s p →
297 n ← ˡh̲ere s
298 0 = n ? s ˡs̲ay "NO KLINGONS HERE"
299 p ≤ 0 ? s
300 p > ˡe̲nergy s ? ˡi̲nsufficient s
301 g ← r̲avel ˡg̲rid s
302 hit ← g ≥ 4
303 v ← g − hit × p d̲iv n
304 dead ← hit ∧ v < 4
305 said ← ˡh̲its r̲avel₂ (2 c̲at '+ r̲/ hit) r̲eshape ((w̲here hit) c̲at hit r̲eplicate v)
306 kl ← (r̲avel s ˡg̲alaxy 1) − ('+ r̲/ dead) × (r̲ange 64) = ˡh̲ome s
307 ˡf̲ire ((s ˡu̲pdate ˡenergy c̲at (ˡe̲nergy s) − p) ˡw̲ithGrid v × n̲ot dead) ˡw̲ithPlane 1 c̲at kl
308}
309⍝ :: Num a => Int -> a
310⍝# The phaser report from pairs of a sector and what is left of its
311⍝# Klingon.
312ˡh̲its ← { v →
313 0 = t̲ally v ? 0
314 k ← (f̲irst v) − 1
315 rc ← (k d̲iv 8) c̲at k m̲od 8
316 hp ← (2 s̲elect v) − 4
317 said ← p̲rint! @ f̲ormat< "KLINGON AT {l:a_t rc}{l:p_hp hp}"
318 1 + ˡh̲its 2 d̲rop v
319}
320⍝ :: Int -> Char
321⍝# What a hit leaves of a Klingon: destroyed, or its hit points left.
322ˡp̲hp ← { hp →
323 hp < 0 ? " DESTROYED"
324 @ f̲ormat< " HIT - HP LEFT {hp}"
325}
326⍝ :: Int -> Int -> Int
327⍝# A photon torpedo along course c: the whole track at once, to the first
328⍝# thing it meets or the quadrant's edge; a Klingon or a base there is
329⍝# destroyed, a star absorbs it. Then the Klingons fire back.
330ˡt̲orpedo ← { s c →
331 0 ≥ ˡt̲orps s ? s ˡs̲ay "NO TORPEDOES REMAINING"
332 (c < 1) ∨ c > 8 ? s
333 said ← p̲rint! "TORPEDO TRACK:"
334 t ← s ˡu̲pdate ˡtorpedoes c̲at (ˡt̲orps s) − 1
335 P ← s ˡp̲ath c c̲at 7
336 in ← ˡi̲nside P
337 what ← in × (ˡc̲ells P) s̲elect r̲avel ˡg̲rid s
338 j ← f̲irst (w̲here (n̲ot in) ∨ what ≠ 0) c̲at 8
339 hits ← j s̲elect in c̲at 0
340 shown ← ˡt̲rack r̲avel₂ ((j − 1) + hits) t̲ake₂ P
341 0 = hits ? ˡf̲ire t ˡs̲ay "TORPEDO MISSED - LEFT QUADRANT"
342 ˡf̲ire t ˡs̲trike (j s̲elect what) c̲at j s̲elect₂ P
343}
344⍝ :: Int -> Int -> Int
345⍝# What a torpedo did on sector rc (the thing's code first).
346ˡs̲trike ← { s wrc →
347 w ← f̲irst wrc
348 rc ← 1 d̲rop wrc
349 at ← ˡa̲t rc
350 k ← ˡc̲ell rc
351 w = 2 ? s ˡs̲ay @ f̲ormat< "TORPEDO ABSORBED BY STAR AT {at}"
352 g ← (r̲avel ˡg̲rid s) × k ≠ r̲ange 64
353 w = 3 ? (s ˡw̲ithGrid g) ˡw̲ithPlane 2 c̲at (r̲avel s ˡg̲alaxy 2) × (ˡh̲ome s) ≠ r̲ange 64
354 said ← p̲rint! @ f̲ormat< "*** KLINGON DESTROYED AT {at} ***"
355 (s ˡw̲ithGrid g) ˡw̲ithPlane 1 c̲at (r̲avel s ˡg̲alaxy 1) − (ˡh̲ome s) = r̲ange 64
356}
357⍝ :: Int -> Int -> Int
358⍝# Shields: p energy into the shields (negative drains them back).
359ˡs̲hieldsTo ← { s p →
360 0 > (ˡe̲nergy s) − p ? ˡi̲nsufficient s
361 s ˡu̲pdate ˡenergy c̲at ((ˡe̲nergy s) − p) c̲at ˡshieldsAt c̲at (ˡs̲hields s) + p
362}
363
364⍝## Reports
365
366⍝ :: Int -> Int
367⍝# The status report: the stardate, energy, shields, torpedoes and
368⍝# Klingons left, the quadrant and the sector.
369ˡr̲eport ← { s →
370 said ← p̲rint! ""
371 said ← p̲rint! @ f̲ormat< "STARDATE {l:d_ate s} / {5 s_elect s}"
372 said ← p̲rint! @ f̲ormat< "ENERGY {l:e_nergy s}"
373 said ← p̲rint! @ f̲ormat< "SHIELDS {l:s_hields s}"
374 said ← p̲rint! @ f̲ormat< "TORP {l:t_orps s}"
375 said ← p̲rint! @ f̲ormat< "KLINGONS {l:k_lingons s}"
376 said ← p̲rint! @ f̲ormat< "QUADRANT {l:a_t l:q_uad s}"
377 said ← p̲rint! @ f̲ormat< "SECTOR {l:a_t l:s_ector s}"
378 s
379}
380⍝ :: Any a => a -> a
381⍝# Print the commands.
382ˡh̲elp ← { s →
383 said ← p̲rint! ""
384 shown ← ˡl̲ines (
385 "1 SRS SHORT RANGE SCAN"
386 "2 LRS LONG RANGE SCAN"
387 "3 WAR WARP DRIVE"
388 "4 IMP IMPULSE DRIVE"
389 "5 PHA PHASERS"
390 "6 TOR TORPEDOES"
391 "7 SHE SHIELD CONTROL"
392 "8 STA STATUS"
393 "9 HEL THIS HELP"
394 "0 QUI RESIGN"
395 ""
396 "COURSE COMPASS (FOR WARP/IMPULSE/TORPEDO):"
397 " 8 1 2 1=N 2=NE 3=E 4=SE"
398 " 7 + 3 5=S 6=SW 7=W 8=NW"
399 " 6 5 4"
400 "COORDS: ROWS A-H DOWN, COLS 1-8 ACROSS (E.G. C-5)")
401 s
402}
403⍝ :: Num a => Box Char -> a
404⍝# Print each string of a list of strings (lib/Text).
405ˡl̲ines ← { v → ˣl̲ines v }
406
407⍝ :: Int -> Int -> Int
408⍝## The game's course
409⍝# A command and its arguments: 1 SRS, 2 LRS, 3 warp (course, factor),
410⍝# 4 impulse (course, sectors), 5 phasers (energy), 6 torpedo (course),
411⍝# 7 shields (energy), 8 status, 9 help, 0 resign; then the verdict.
412ˡc̲ommand ← { s v →
413 ˡj̲udge s ˡd̲o v
414}
415⍝ :: Int -> Int -> Int
416⍝# Carry out command v (its number, then its arguments).
417ˡd̲o ← { s v →
418 c ← f̲irst v
419 a ← 1 d̲rop v
420 c = 1 ? ˡs̲rs s
421 c = 2 ? ˡl̲rs s
422 c = 3 ? s ˡw̲arp a
423 c = 4 ? s ˡi̲mpulse a
424 c = 5 ? s ˡp̲hasers f̲irst a
425 c = 6 ? s ˡt̲orpedo f̲irst a
426 c = 7 ? s ˡs̲hieldsTo f̲irst a
427 c = 8 ? ˡr̲eport s
428 c = 9 ? ˡh̲elp s
429 c = 0 ? s ˡu̲pdate ˡstatus c̲at 4
430 s ˡs̲ay "?WHAT"
431}
432⍝ :: Int -> Int
433⍝# The status: out of time first, then the ship lost, then the mission
434⍝# complete (as the BASIC checks them); a resignation stands.
435ˡj̲udge ← { s →
436 4 = ˡs̲tatus s ? s
437 over ← ((ˡd̲ate s) > 5 s̲elect s) c̲at (0 ≥ ˡe̲nergy s) c̲at 0 = ˡk̲lingons s
438 s ˡu̲pdate ˡstatus c̲at f̲irst (over r̲eplicate 2 3 1) c̲at 0
439}
440⍝ :: Int -> Char
441⍝# The game's ending, printed, and the Klingons left.
442ˡe̲nd ← { s →
443 st ← ˡs̲tatus s
444 said ← p̲rint! ""
445 st = 1 ? ˡm̲ission s
446 said ← p̲rint! d̲isclose (st − 1) s̲elect "*** STARDATE EXPIRED ***" "*** ENTERPRISE LOST ***" "*** COMMAND RESIGNED ***"
447 @ f̲ormat< "KLINGONS REMAINING {l:k_lingons s}"
448}
449⍝ :: Int -> Char
450⍝# The mission complete: the stardate and the energy left.
451ˡm̲ission ← { s →
452 said ← p̲rint! "*** MISSION COMPLETE ***"
453 said ← p̲rint! @ f̲ormat< "STARDATE {l:d_ate s}"
454 @ f̲ormat< "ENERGY {l:e_nergy s}"
455}
f̲ormat< expands to
("*** " c̲at (f̲ormat (n)) c̲at " KLINGON(S) IN QUADRANT " c̲at (f̲ormat (ˡa̲t ˡq̲uad s)) c̲at " ***")
f̲ormat< expands to
("QUADRANT " c̲at (f̲ormat (ˡa̲t ˡq̲uad s)) c̲at " SECTOR " c̲at (f̲ormat (ˡa̲t ˡs̲ector s)))
f̲ormat< expands to
("STARDATE " c̲at (f̲ormat (ˡd̲ate s)) c̲at " ENERGY " c̲at (f̲ormat (ˡe̲nergy s)) c̲at " SHIELDS " c̲at (f̲ormat (ˡs̲hields s)) c̲at " TORP " c̲at (f̲ormat (ˡt̲orps s)))
f̲ormat< expands to
("QUADRANT " c̲at (f̲ormat (ˡa̲t ˡq̲uad s)) c̲at " KLINGONS LEFT " c̲at (f̲ormat (ˡk̲lingons s)))
f̲ormat< expands to
("KLINGONS " c̲at (f̲ormat (ˡk̲lingons s)))
f̲ormat< expands to
"KLINGONS REMAINING " c̲at (f̲ormat (ˡk̲lingons s))