Retrochallenge 2016/10:
Ironic Computer Space Simulator (ICSS)

Episode 9: Scores, Just in Time

The end is nigh! — Not of the world, hopefully, but of October — and that is, of Retrochallenge. So it's only appropriate that we should catch the first glimpses of the finishing line. In order to get there, we have to figure out first, how to output figures onto the scope.

Score display in ICSS, version 0.4 (screenshot of emulation).

Score display in ICSS, version 0.4 (screenshot of emulation).

So we're going to implement the scores. On the level of just keeping scores this is a task rathe mundane: Just add two variables, one for the score of the player (rocket) and another one for the saucers, clear them at the start of a game and advance them on each hit.

As it comes to displaying the scores, things are a bit different: The PDP-1 doesn't feature any support for character output onto the scope by default (while there is, in fact, an optional symbol generator, Type 33, at just US$ 4,000 in 1963 — just two brand-new cars!). We'll have to do this on our own, programwise, — and this is a time consuming task! Thus, we're chosing to implement an outline compiler to produce procedural object code for drawing any of the characters as fast as possible, so that we may go flicker-free. We're going to do a simple JIT compiler to be run at the start of the program, just as Dan Edwards did it for the outlines of Spacewar!'s spaceships around the turn of the year 1961/62.

(Note: If we were targeting the CHM machine only, we could dispense with the effort, since this one has, in fact, a high-speed symbol generator. But we want to keep this program as general as possible and, by the way, our humble emulator lacks a symbol generator, as well.)

Score and time display in Computer Space

Score and time display in Computer Space.
(Image: hardcoregaming101.net.)

First, we need some characters to draw, and we will need the numbers 0 to 9 and the characters A to F, since Computer Space features a unique one-digit hex display for the scores. While the arcade machine renders its numerals in a 7-segement display style, we can't do this, if we want to stick with the spirit of the period. 7-segment displays where widely unknown and LEDs weren't commonly available at all before 1968. This was the era of Nixie tubes and their beautiful glowing numbers — and we really need something more appropriate to match the PDP-1 and the appearance of its scope.

We go with what seems to be the standard definition, which may be found in a subroutine published by DEC in 1961. (See PDP-1_Subroutines_1961.pdf at bistavers.org [at the end of document], also, as of 1964 for the symbol generator, CHM, Catalog No. 102636251.)

(Note: Our PDP-1 emulator renders these definitions, as well, in JavaScript, for the purpose of its splash screen. If you press the tiny black button at the bottom right of the emulator's scope, just where the outlet for the cable of the light pen would be on the real machine, you'll get a service screen including the entire character dump.)

And this is what these characters look like, as far as required by our program:

PDP-1 character definitions for the Type 30 display

PDP-1 character definitions for the Type 30 display.

The characters are defined for a 7 rows × 5 dots grid of arbitrary scale. We're not going to render the dots at uniform distances for both vertical and horizontal dimensions, as shown here, but compressed, in an aspect ratio favoring the vertical extent.

While the authentic character data is organized columnwise, we prefer to have it in rows (we'll see late, why). Therefor, we generate our own, two 18-bit words for each character, lining up 5 bits for each rows, starting at the left and chaining rows in top-down order. For this, we write a little script to generate the data words in the browser (why not?), to be seen here, ICSS Character Data Generator.

With this in place, we have ultimately arrived at the end of any further procrastination and have to address the outline compiler.

We're going to scan the code words (character data) left to right, keep track of the x-index of the bit currently scanned and of the x-coordinate of the last display command compiled, add any offsets where needed, and compile appropriate display commands. As we're moving along the x-axis, we're going mostly just by modifying the x-location in the accumulator by additions and subtractions. Just at the end of a row, we have to swap the y-coordinate in and out to advance this one. We optimize our compiler a little bit, by advancing bidirectional, but just for the first bit scanned in a row, since we do not have any look-ahead to do much more. And of course, we have to keep track of our bit position in the data, in order to advance to the second code word at the right time.

And this is how we do it:

Now we may run the outline compiler for each of the characters and store the respective start addresses in a table. (The compiled object code will go after the code of the program and the space reserved for its variables.) Also, we produce a little calling routine, to be called by the "jda" instruction, passing the digit (character index) in AC, which selects the respective routine from the table and calls it. This is also, where our compiled outline routine returns to.

The real beauty in this is that, while we would have to frequently store states and intermediate results for an interpreter with just two CPU registers to go with, the compiler and the object code compiled by it can go nicely along by just dealing with the accumulator. (IO is used for the code word only in the compiler, and for the y-component in the object code.) As a result, the compiled code is running as fast as the display allows (10 CPU cyles delay between display commands).

Our little optimization strategy is working great for vertical lines, like the vertical stroke in a "1", but does little for other figures, like a "3", because of the lack of any look-ahead for further directional optimization. Here's a small example of the code produced by the compiler:

/* ICSS character outline compiler *
/compiled code for characters '1' and '3'

/unit offset y
02564     010000     010000       / cgy           (16 screen locations)

/unit offsets x  (2..4 generated by program)
02565     006000     006000       / cgx x 1       (12 screen locations)
02566     014000     014000       /     x 2
02567     022000     022000       /     x 3
02570     030000     030000       /     x 4


/        '  *  '
/        ' **  '
/        '  *  '
/        '  *  '
/        '  *  '
/        '  *  '
/        '  *  '

/generated outline code for character '1'

/addr     instr      disass         symbolic        notes

03421     222750     lio 2750     / lio cy          start y in io
03422     202747     lac 2747     / lac cx          start x in ac
03423     402566     add 2566     / add 2566
03424     724107     iot 4107     / dpy-i 4100      display a dot
03425     673777     rcr 777      / rcr 9s          swap
03426     673777     rcr 777      / rcr 9s
03427     422564     sub 2564     / sub cgy         next row, inc. y
03430     673777     rcr 777      / rcr 9s
03431     673777     rcr 777      / rcr 9s
03432     422565     sub 2565     / sub cgx         - 1 unit
03433     730000     ioh          / ioh             wait for display
03434     724107     iot 4107     / dpy-i 4100      display a dot
03435     402565     add 2565     / add cgx         + 1 unit
03436     730000     ioh          / ioh
03437     724107     iot 4107     / dpy-i 4100      display a dot
03440     673777     rcr 777      / rcr 9s          swap
03441     673777     rcr 777      / rcr 9s
03442     422564     sub 2564     / sub cgy         next row
03443     673777     rcr 777      / rcr 9s          swap
03444     673777     rcr 777      / rcr 9s
03445     730000     ioh          / ioh
03446     724107     iot 4107     / dpy-i 4100      display a dot
03447     673777     rcr 777      / rcr 9s          swap
03450     673777     rcr 777      / rcr 9s
03451     422564     sub 2564     / sub cgy         next row
03452     673777     rcr 777      / rcr 9s
03453     673777     rcr 777      / rcr 9s
03454     730000     ioh          / ioh
03455     724107     iot 4107     / dpy-i 4100      display a dot
03456     673777     rcr 777      / rcr 9s          swap
03457     673777     rcr 777      / rcr 9s
03460     422564     sub 2564     / sub cgy         next row
03461     673777     rcr 777      / rcr 9s          swap
03462     673777     rcr 777      / rcr 9s
03463     730000     ioh          / ioh
03464     724107     iot 4107     / dpy-i 4100      display a dot
03465     673777     rcr 777      / rcr 9s          swap
03466     673777     rcr 777      / rcr 9s
03467     422564     sub 2564     / sub cgy         next row
03470     673777     rcr 777      / rcr 9s          swap
03471     673777     rcr 777      / rcr 9s
03472     730000     ioh          / ioh
03473     724107     iot 4107     / dpy-i 4100      display a dot
03474     673777     rcr 777      / rcr 9s          swap
03475     673777     rcr 777      / rcr 9s
03476     422564     sub 2564     / sub cgy         next row
03477     673777     rcr 777      / rcr 9s          swap
03500     673777     rcr 777      / rcr 9s          swap
03501     730000     ioh          / ioh
03502     724107     iot 4107     / dpy-i 4100      display a dot
03503     730000     ioh          / ioh
03504     602757     jmp 2757     / jmp cdx         exit


/        ' *** '
/        '*   *'
/        '    *'
/        '  ** '
/        '    *'
/        '*   *'
/        ' *** '

/generated outline code for character '3'

/addr     instr      disass         symbolic        notes

03621     222750     lio 2750     / lio cy          start y in io
03622     202747     lac 2747     / lac cx          start x in ac
03623     402565     add 2565     / add cgx         + 1 unit
03624     724107     iot 4107     / dpy-i 4100      display a dot
03625     402565     add 2565     / add cgx         + 1 unit
03626     730000     ioh          / ioh             wait for display
03627     724107     iot 4107     / dpy-i 4100      display next dot
03630     402565     add 2565     / add cgx         + 1 unit
03631     730000     ioh          / ioh
03632     724107     iot 4107     / dpy-i 4100
03633     673777     rcr 777      / rcr 9s          swap
03634     673777     rcr 777      / rcr 9s
03635     422564     sub 2564     / sub cgy         next row
03636     673777     rcr 777      / rcr 9s          swap
03637     673777     rcr 777      / rcr 9s
03640     422567     sub 2567     / sub cgx + 2     - 3 units
03641     730000     ioh          / ioh
03642     724107     iot 4107     / dpy-i 4100
03643     402570     add 2570     / add cgx + 3     + 4 units
03644     730000     ioh          / ioh
03645     724107     iot 4107     / dpy-i 4100
03646     673777     rcr 777      / rcr 9s          swap
03647     673777     rcr 777      / rcr 9s
03650     422564     sub 2564     / sub cgy         next row
03651     673777     rcr 777      / rcr 9s          swap
03652     673777     rcr 777      / rcr 9s
03653     730000     ioh          / ioh
03654     724107     iot 4107     / dpy-i 4100
03655     673777     rcr 777      / rcr 9s          swap
03656     673777     rcr 777      / rcr 9s
03657     422564     sub 2564     / sub cgy
03660     673777     rcr 777      / rcr 9s          swap
03661     673777     rcr 777      / rcr 9s
03662     422566     sub 2566     / sub cgx + 1     - 2 units
03663     730000     ioh          / ioh
03664     724107     iot 4107     / dpy-i 4100
03665     402565     add 2565     / add cgx         + 1 unit
03666     730000     ioh          / ioh
03667     724107     iot 4107     / dpy-i 4100
03670     673777     rcr 777      / rcr 9s          swap
03671     673777     rcr 777      / rcr 9s
03672     422564     sub 2564     / sub cgy         next row
03673     673777     rcr 777      / rcr 9s          swap
03674     673777     rcr 777      / rcr 9s
03675     402565     add 2565     / add cgx         + 1 unit
03676     730000     ioh          / ioh
03677     724107     iot 4107     / dpy-i 4100
03700     673777     rcr 777      / rcr 9s          swap
03701     673777     rcr 777      / rcr 9s
03702     422564     sub 2564     / sub cgy         next row
03703     673777     rcr 777      / rcr 9s          swap
03704     673777     rcr 777      / rcr 9s
03705     422570     sub 2570     / sub cgx + 3     - 4 units
03706     730000     ioh          / ioh
03707     724107     iot 4107     / dpy-i 4100
03710     402570     add 2570     / add cgx + 3     + 4 units
03711     730000     ioh          / ioh
03712     724107     iot 4107     / dpy-i 4100
03713     673777     rcr 777      / rcr 9s          swap
03714     673777     rcr 777      / rcr 9s
03715     422564     sub 2564     / sub cgy         next row
03716     673777     rcr 777      / rcr 9s          swap
03717     673777     rcr 777      / rcr 9s
03720     422567     sub 2567     / sub cgx + 2     - 3 units
03721     730000     ioh          / ioh
03722     724107     iot 4107     / dpy-i 4100
03723     402565     add 2565     / add cgx         + 1 unit
03724     730000     ioh          / ioh
03725     724107     iot 4107     / dpy-i 4100
03726     402565     add 2565     / add cgx         + 1 unit
03727     730000     ioh          / ioh
03730     724107     iot 4107     / dpy-i 4100
03731     730000     ioh          / ioh
03732     602757     jmp 2757     / jmp cdx         exit

With this installed, our program is still running fast, maybe just a tick too fast, even with some throttle left. Quite promising and pleasing, as well.

Implementation — As in Real Life
Fear and Loathing (and Despair) at Las Emulatores

As mentioned earlier, the in-browser emulator lacks any debugging facilities. There isn't even a way to log to any console from inside a program. For the purpose of testing a JIT compiler, not the best of preconditions. And the devil never sleeps…

As could be expected, I'm seeing nothing on the screen on the first run. There isn't even an illfated jump causing an infinite loop (which would be eventually detected by the emulator). — Hum.

We detect an error and finally see some outline, but it is skewed and distorted. — Hum?!

Staring at the code reveals little of errors, so we actually need some way to inspect the results of our attempts of compiling procedural outline code. — We produce a test version of the emulator by inserting a few lines to export a memory dump on a key press. Also, there's a rudementary disassembler (see the edited output above), we have produced once to peek into some ancient object tapes (of course, related to Spacewar!). So, dump the memory, copy'n'paste it into a source file and run the disassembly.

Lets stare at the code again. — Hum… — Not much to see there, all looks fine. We insert test statements, change parameters, reassemble the code, run it, dump the memory, copy'n'paste, disassemble, stare — rinse & repeat.

This uses actually more than an hour without results. First, we even get some entirely senseless dissassembly, until we detect that our code dump somehow forgot to add zeros in front of any numbers (since it's all octal). Nevertheless, when we eventually see the compiled code as-is, there's nothing to see, as far as it were for any errors.

Eventually, we tinker with the character dimensions, and there's some irritation. The horizontal offsets just don't match. We have them in a static table, 4 numbers in octal, multiples of the base unit. Should be easy, but it isn't. We use a calculator to add them correctly. We wrap our head around octal numbers, but it still doesn't work out. — At last, we implement the multiples of the grid unit to be generated by the program … and it finally works.

I still don't know, where this error in the offset values may have been and how it may have occured, since accumulating numbers should be easy, shouldn't it? Even by the use of a calculator and repetitively hitting the sum key. — So the code devil had another sleepless hour …

Friendly Outlook

In order to not to close in thus a gloomy temper, we really have to announce that we're seeing the finishing line! We reorganized a few snippets by relocating the motion tables to the front of the code and tinkered a bit with the AI (essentially by changing from noise in the aiming epsilon to noise in the assumed targed position, as already announced last episode). And the AI may be even a bit too good by now. We'll see.

All that's left to do, besides adjusting a few parameters, is to implement an attract mode and time keeping for the count-up on the duration of the game. And, we'll have to adjust the pace and find out, how much time we're actually spending in the major routines in order to pace the game and its frame rate properly. (And here, life will be actually easier with the emulator, as we'll simply let it dump the numbers of cycles spent between visiting any of two memory locations.)

And this is what our game looks like after affixing an emulated note to the emulated scope as a legend to the displayed numerals produced by the program emulated in the virtual PDP-1, simulating an ancient, while younger, coin-op. machine, which the real PDP-1 and Spacewar! had once inspired:

ICSS, version 0.4 (screenshot of emulation).

Ironic Computer Space Simulator for the PDP-1, version 0.4 (screenshot of the emulator).

Experience the code live:   www.masswerk.at/icss/.

And here are the respective labels (at the side of the screen) at/on/in the original Computer Space machine:

Computer Space: screen with labels.

Computer Space: Labels at the side of the monitor bezel.
(Image: oobject.com; edited, N.L.)

Still To Do

And here's our growing code, so far:

ironic computer space  0.4  nl 2016-10-28

	mul=mus			/instruction code for multiplication
	div=dis			/instruction code for division
	ioh=iot i		/wait for completion pulse (CRT display)
	szm=sza sma-szf		/skip on ac zero or minus
	spq=szm i		/skip on ac plus and not zero

define initialize A,B
	law B
	dap A
	term

define index A,B,C
	idx A
	sas B
	jmp C
	term

define swap
	rcl 9s
	rcl 9s
	term

define load A,B
	lio (B
	dio A
	term

define setup A,B
	law i B
	dac A
	term

define count A,B
	isp A
	jmp B
	term

/macros specific to the program

define scale A,B,C
	lac A
	sar B
	dac C
	term

define random
	lac ran
	rar 1s
	xor (355671
	add (355671
	dac ran
	term


/ Computer Space
/ Original arcade game by Nolan Bushnell and Ted Dabney,
/ Syzygy Engineering / Nutting Associates, 1971.
/ 'A simulated space battle that pits
/  computer-guided saucers against
/  a rocket ship that you control.'

/ sense switch options
/ SSW 1 ... parallax effect
/           off - stars roll continuously to the left.
/           on  - background stars move raltively to rocket ship.
/ SSW 2 ... parallax effect strength (together with SSW 1)
/           off - subtle effect.
/           on  - stronger effect.
/ SSW 3 ... torpedoes, single shots (like spacewar!)
/           off - 'continuous fire' action.
/           on  - trigger blocks and waits for new press.
/ SSW 4 ... torpedoes, steering
/           off - steering applies only, while the ship is turning.
/           on  - torpedoes eventually follow the turn of the ship.
/ SSW 5 ... saucer motion
/           off - diagonals are horizontally stretched.
/                 (conforms more to the overall impression of CS)
/           on  - geometrical diagonals.
/ SSW 6 ... saucer piloting, which saucer is shooting?
/           off - always the same one (as in original CS).
/           on  - random select.


3/	jmp sbf			/ ignore seq. break
	jmp a0			/ start addr, use control boxes
	jmp a1			/ alt. start addr, use testword controls


/game parameters

raa,  6,	1200		/ rocket angular acceleration
rvl,  7,	sar 8s		/ scaling rocket velocity
ras, 10,	law i 6		/ rocket acceleration sensitivity (skip)
rad, 11,	law i 4		/ rocket acceleration damping (averaging)
trv, 12,	sar 7s		/ scaling torpedo velocity
tlf, 13,	law i 250	/ torpedo life
rsd, 14,	60		/ rocket reset delay (frames)
etl, 15,	law i 240	/ enemy torpedo life
etd, 16,	law i 30	/ enemy torpedo cooling (frames)
etf, 17,	law i 100	/ enemy first torpedo cooling (after score)
ela, 20, 	sal 6s		/ scaling enemey torp look-ahead
ete, 21,	14000		/ epsilon for enemy aiming
etn, 22,	sal 3s		/ scaling noise for enemy torpedo aim
ran, 23,	0		/ random number


/saucer movement table (dy, dx)
/ diagonals proper
ut1,	 600		   0
	-600		   0
	   0		 600
	   0		-600
	 400		 400
	-400		 400
	 400		-400
	-400		-400

/ horizontally streched diagonals, default (dy, dx)
ut0,	 600		   0
	-600		   0
	   0		 600
	   0		-600
	 400		 600
	-400		 600
	 400		-600
	-400		-600

/saucer torpedo movement table (dy, dx)
emt,	 2400		    0
	-2400		    0
	    0		 2400
	    0		-2400
	 1600		 1600
	-1600		 1600
	 1600		-1600
	-1600		-1600


/routine to flush sequence breaks, if they occur.

sbf,	tyi
	lio 2
	lac 0
	lsm
	jmp i 1


/sine-cosine subroutine - Adams associates
/calling sequence= number in AC, jda sin or jdacos.
/argument is between +/- +2 pi, with binary point to right of bit 3.
/answer has binary point to right of bit 0.  Time = 2.35-? ms.
/changed for auto-multiply , ddp 1/19/63

cos,	0
	dap csx
	lac (62210
	add cos
	dac sin
	jmp .+4

sin,	0
	dap csx
	lac sin
	spa
si1,	add (311040
	sub (62210
	sma
	jmp si2
	add (62210

si3,	ral 2s
	mul (242763
	dac sin
	mul sin
	dac cos
	mul (756103
	add (121312
	mul cos
	add (532511
	mul cos
	add (144417
	mul sin
	scl 3s
	dac cos
	xor sin
	sma
	jmp csx-1
	lac (377777
	lio sin
	spi
	cma
	jmp csx

	lac cos
csx,	jmp .

si2,	cma
	add (62210
	sma
	jmp si3
	add (62210
	spa
	jmp .+3
	sub (62210
	jmp si3

	sub (62210
	jmp si1


/subroutines for background display

nos=77 	/number of stars

/table of stars coors (nos words, 9 bits x and 9 bits y)
bst,	. nos/

/setup (nos random coors starting at bst)

bsi,	dap bsx				/ deposit return address
	init bsc, bst			/ deposit first addr of bst in bsc
bsl,	random				/ get a new random number
bsc,	dac .				/ store it in current loc of st
	index bsc, (dac bst+nos, bsl	/ increment bsl, repeat at bgl for nos times
bsx,	jmp .				/ return


/display background stars (displays every 2nd frame only)

bg,	dap bgx				/ deposit return address
	lac \frc			/ check frame conter
	and (1
	sza				/ skip every second frame
	jmp bgi				/ jump to star display
	szs i 10			/ sense switch 1 for parallax effect
	jmp bgd
	lac \rdx
	szs i 20			/ sense switch 2 for stronger effect
	jmp . 3
	sar 1s
	add \rdx
	sar 3s
	cma
	add bgh
	dac bgh
	lac \rdy
	szs i 20
	jmp . 3
	sar 1s
	add \rdy
	sar 3s
	cma
	add bgv
	dac bgv
	jmp bgx				/ return
bgd,	lac \frc			/ advance x offset slowly
	and (177
	sza
	jmp bgx
	law i 400
	add bgh
	dac bgh
	jmp bgx				/ return
bgi,	init bgl, bst			/ init bgl to first addr of stars table
bgl,	lac .				/ get coors of next star (x/y)
	cli				/ clear io
	scr 9s				/ shift low 9 bits in high 9 bits of io (x)
	sal 9s				/ move remaining 9 bits in ac in high part (y)
	add bgv				/ add vertical offset
	swap				/ swap contents of ac and io
	add bgh				/ add horizontal offset
	dpy-i				/ display a dot at coors in ac (x) and io (y)
	index bgl, (lac bst+nos, bgl	/ repeat the loop at bgl nos times
bgx,	jmp .				/ return

bgh,	0
bgv,	0


/here from start

a0,	law rcb			/configure to read control boxes (sa 4)
	dap rcw
	jmp a2

a1,	law rtw			/configure to read testword (sa 5)
	dap rcw

/start a new run

a2,	jsp ci
	jsp bsi			/ initial setup of bg-stars
	dzm bgh			/ reset offsets of stars to zero
	dzm bgv

/rocket setup

ar,	lac (240000
	dac \rth		/ rotational angle
	lac (-200000
	dac \rpx		/ pos x
	cma
	dac \rpy		/ pos y
	law 300
	dac \rdx
	law i 500
	dac \rdy
	dzm \rac		/ acceleration skip counter
	dzm \rxc		/ reset center offset
	dzm \ryc
	law 1
	dac \rks		/status
	dzm \sc1		/score
	dzm \trs		/torpedo status counter
	dzm \cwo		/old control word

/saucer setup

au,	lac (200000
	dac \upy		/ pos x
	lac (140000
	dac \upx		/ pos y
	dzm \udc		/ animation skip counter
	law 1
	dac \udd		/ animation direction
	dzm \umo		/ direction code
	law 600
	dac \udy		/ delta y
	dzm \udx		/ delta x
	law i 100
	dac \ufc		/ duration of movement
	law 1
	dac \uft		/ speed of center animation (1,3)
	law 1
	dac \ufs		/ state counter
	dzm \sc2
	dzm \ets		/ torpedo state
	jsp etr			/ get torpedo cooling (\etc)

/main loop

fr0,	load \ict, -2040 	/ initial instruction budget (delay)
	idx \frc		/ increment frame counter
	clf 1			/ flag 1 indicates active player's ship
	clf 2
	clf 3

	jsp bg			/ display background
	jsp rkt			/ rocket routine
	jsp ufo
	lac \trs
	sza
	jsp trp			/ torpedo routine
	lac \ets
	sza
	jsp etm			/ enemy torpedo routine
	jsp df			/ check collisions

	lac \cw
	dac \cwo

	jsp scd			/display scores


	count \ict, .		/ use up rest of time of main loop
	jmp fr0			/ next frame


/score display

scd,	dap scx
	lac (330000
	dac cx
	lac (144000
	dac cy
	lac \sc1
	and (17
	jda cdp
	lac (30000
	dac cy
	lac \sc2
	and (17
	jda cdp
	lac (-64000
	dac cy
	cla
	jda cdp
	lac (260000
	dac cx
	cla
	jda cdp
scx,	jmp .

/collision / hit detection

df,	clf 5
	dap dfx
	lac \ufs		/check saucer state
	spq			/skip on positive
	jmp dfx
	lac \rks		/check rocket state
	spq
	jmp dfx

	lac \rpx		/get rotational center of rocket
	sub \rxc
	dac \px
	lac \rpy
	add \ryc
	dac \py

	law \px			/set up rocket for comparison
	dap mx1
	law \py
	dap my1

	lac (21000		/set up collision radii (x 34, y 24) in screen locs
	dac \dxe
	sar 1s
	dac \de2
	lac (14000
	dac \dye

	law \upx		/first saucer
	dap mx2
	law \upy
	dap my2
	jsp dmf			/compare them
	sza			/hit?
	jmp dxr			/yes

	lac \upy		/second saucer
	sub (400000		/vertical offset
	dac \vpy
	law \vpy
	dap my2
	jsp dmf			/compare them
	sza			/hit?
	jmp dxr			/yes

dft,	lac \trs		/torpedo active?
	sma
	jmp dfe
	lac (12200		/setup hit box (x 21, y 10)
	dac \dxe
	sar 1s
	dac \de2
	lac (5000
	dac \dfy
	law \tpx		/set up torp as first object
	dap mx1
	law \tpy
	dap my1
	jsp dmf			/compare
	sza
	jmp dxu			/hit, respawn

	law \upy
	dap my2
	jsp dmf			/compare them
	sza			/hit?
	jmp dxu

dfe,	lac \ets		/enemy torpedo active?
	sza i
	jmp dfx
	lac (11000
	dac \dxe
	dac \dye
	law 6400
	dac \de2
	law \px
	dap mx1
	law \py
	dap my1
	law \epx
	dap mx2
	law \epy
	dap my2
	jsp dmf
	sza i
	jmp dfx
	dzm \ets		/reset enemy torpedo
	xct etf			/get initial topredo cooling
	dac \etc		/and store it
	lac
	stf 5

dxr,	law i 100		/set rocket state to collision
	sub rsd			/additional delay before reset
	dac \rks
	dzm \rdx
	dzm \rdy
	dzm \trs
	lac \rth
	dac \th0
	dzm \thc
	law i 10
	dac \thd
	idx \sc2
	szf i 5
	jsp urs			/respawn saucers
	jmp dfx

dxu,	dzm \trs		/set up saucer explosion, reset torpedoes
	dzm \ets
	lac i my2		/set up pos y
	dac \upy
	idx \sc1
	law i 30 30
	dac \ufs

dfx,	jmp .			/return


/subroutine to compare object positions (from spacewar, mod n.l.)
dmf,	dap dmx
mx1,	lac .			/calc if collision
mx2,	sub .			/delta x
	spa			/take abs val
	cma
	dac \t1
	sub \dxe		/ < epsilon x ?
	sma
	jmp dm0			/no
my1,	lac .
my2,	sub .
	spa
	cma
	sub \dye		/ < epsilon y ?
	sma
	jmp dm0			/no
	add \t1
	sub \de2		/ < epsilon 2 ?
	sma
	jmp dm0
	law 1			/return 1 (in ac) for hit
	jmp dmx
dm0,	cla			/return 0 for miss
dmx,	jmp .


/saucers

ufo,	dap ufx
	lac \ufs
	spq
	jmp uxe
	clf 6

	lac \upx		/update position
	add \udx
	dac \upx
	dac \px
	lac \upy
	add \udy
	dac \upy
	dac \py
	jsp sd			/display first saucer
	lac \py
	sub (400000		/half-screen vertical offset
	dac \py
	jsp sd			/display second saucer

	isp \ufc		/increment leg counter
	jmp uf1			/continue
	lac \umo		/new direction
	spa
	jmp uza			/we're in a 3-steps stop (\umo: -3..-1)
	sar 3s			/ 010 set for single step stop
	sza
	jmp uz1
	random
	sma
	jmp uf2			/set up new leg

	dzm \udx		/stop
	dzm \udy
	lac ran			/what kind of stop will it be?
	ral 3s
	spa
	jmp uz0			/three-steps stop
	law 10			/single-step stop, keep center animation
	dac \umo
	jmp uzb			/get delay and continue
uz0,	law i 3			/first period of three-steps stop
	dac \umo		/reuse \umo as step counter (negative)
	law 3
	dac \uft		/set animation to slow (3)
uzb,	jsp utd			/get duration
	sar 1s
	dac \ufc
	jmp eta			/continue for torpedo setup

uza,	cma			/3-steps stop, dispatch on -\umo (-3..-1)
	add (. 3
	dap . 2
	idx \umo
	jmp .
	jmp uz1
	jmp uz2
uz3,	dzm \udd		/3 - stop animation
	jmp . 2
uz2,	jsp ucd			/2 - still stopped, new animation direction
	jsp utd
	sar 1s
	dac \ufc
	jmp eta
uz1,	stf 6			/1 - start over, but keep animation
	random
	jmp . 2

uf2,	clf 6			/set up for a new leg (flag 6: keep anim. dir.)
	and (7
	dac \umo		/new motion code (0..7)
	sal 1s			/read corresponding dx/dy form movement table
	szs i 50		/sense switch 5 to select table (ut1 or ut0)
	jmp . 3
	add (ut1		/setup reference location for dy in \t1
	jmp . 2
	add (ut0		/select other table
	dac \t1
	lac i \t1		/load dy indirectly from addr. in \t1
	dac \udy
	idx \t1			/increment addr. in \t1
	lac i \t1		/load dx indirectly from addr. in \t1
	dac \udx
	szf 6 i			/skip next on flag 6
	jsp ucd			/set new direction for animation
	jsp utd			/get delay
	dac \ufc

uf1,	lac \frc		/increment center animation
	and \uft
	sza
	jmp eta
	lac \udc		/udc = 0..5
	sub \udd
	dac \udc
	sma
	jmp . 4
	law 5
	dac \udc
	jmp eta
	sad (6
	dzm \udc
	jmp eta

ufi,	lac \ict		/update instruction count
	add (1200
	dac \ict

ufx, jmp .


ucd,	dap ucx			/subroutine to set center animation
	lio ran
	ril 1s
	law 1
	spi
	cma
	dac \udd
	lac ran			/animation speed, favor faster
	rar 9s
	and (3
	sza
	jmp . 3
	law 1
	jmp . 2
	law 3
	dac \uft
ucx,	jmp .

utd,	dap utx			/subroutine to get random delay (leg length)
	random
	sar 9s
	sar 3s
	sub (270
utx,	jmp .

urs,	dap urx			/subroutine to respawn the saucers
	lac ran			/random offset x to player's rocket
	rar 9s
	sar 2s
	dac \upx
	sar 1s
	add \upx
	add (400000
	add \rpx
	dac \upx
	random			/random pos y
	dac \upy
	jsp ucd			/set up center animation
	dac \udd
	law i 40		/set up delay before next leg
	dac \ufc
	law i 1			/stopped (end of 3-steps stop)
	dac \umo
	jsp etr			/reset torpedo, get cooling
	law 1			/set state to active
	dac \ufs
urx,	jmp .


/saucer explosion (similar to spacewar)
/ jump here from inside ufo

uxe,	law uxs			/set up instr at uxs to be xct-ed in ux1
	dap ux1
	lac \ufs
	add (30			/done with explosion, 030 frames setup delay
	sma
	jmp ux3
	sal 1s
	dac \uxc		/repeat for 030 particles
	add (50			/first and last frames small explosion
	spa
	jmp ux0
	sub (30
	sma
	idx ux1			/increment addr in ux1 for bigger explosion
ux0,	random			/start of loop, get random number
	and (6s			/constrain to lowest 6 bits (as no of shifts)
	ior (scl		/assemble a shift instruction for these
	dac ux2			/insert it at ux2
	random			/new random number
	cli
	scr 9s			/split it into lower parts of ac and io
	sir 9s
ux1,	xct .			/apply scaling (size)
ux2,	opr			/apply shift for random spread
	add \upy		/add center pos x/y
	swap
	add \upx
	dpy -i 100		/display a  dot
	isp \uxc		/redo \uxc times
	jmp ux0
ux3,	isp \ufs		/increment status counter
	jmp ufi
	jsp urs			/last iteration, respawn saucers
	jmp ufi

uxs,	scl 1s			/scaling for small explosion
	scl 2s			/ and bigger one, to be xct-ed at ux1


/saucer torpedo ai (setup)
/ here from inside ufo

eta,	lac \ets		/torpedo already active?
	spa
	jmp ufi
	szf i 1			/rocket active?
	jmp ufi
	lac \ufs		/saucers active?
	spq
	jmp ufi
	isp \etc		/count up cooling
	jmp ufi
	dzm \etc

	lac \upx		/position of tubes
	add (10400
	dac \epx
	lac \upy
	sub (3400
	dac \epy

	random			/get random offset for targeting
	cli
	scr 9s			/split it into lower parts of ac and io
	sir 9s
	xct etn			/scale it
	dac \exn		/store noise x
	swap			/same for y
	xct etn
	dac \eyn


	szs i 60		/sense switch 6 to select saucers at random
	jmp et1			/ original shoots always from same saucer
	random
	sma			/which saucer
	jmp et1
	lac \epy
	add (400000
	dac \epy
et1,
/	random
/	sar 9s
/	add ete
/	spa
/	cma
	lac ete
	dac \eps

	lac \rdx
	xct ela			/look-ahead
	add \rpx
	sub \rxc
	add \exn
	sub \epx
	dac \dx			/delta x
	spa
	cma
	dac \adx		/abs delta x

	lac \rdy		/same for y
	xct ela
	add \rpy
	add \ryc
	add \eyn
	sub \epy
	dac \dy
	spa
	cma
	dac \ady
	sub \eps
	spa
	jmp eah
	lac \adx
	sub \eps
	spa
	jmp eav

	lac \adx
	sub \ady
	spa
	cma
	sub eps
	sma
	jmp ufi
ead,
	law 4
	lio \dy
	spi
	law 5
	lio \dx
	spi
	add (2
	jmp et3
eah,
	law 2
	lio \dx
	spi
	law 3
	jmp et3
eav,
	cla
	lio \dy
	spi
	law 1
et3,
	sal 1s			/read corresponding dx/dy form movement table
	add (emt		/setup reference location for dy in \t1
	dac \t1
	lac i \t1		/load dy indirectly from addr. in \t1
	dac \edy
	idx \t1			/increment addr. in \t1
	lac i \t1		/load dx indirectly from addr. in \t1
	dac \edx
	xct etl
	dac \ets

eti,	/lac \ict		/update instruction count
	/add (40
	/dac \ict
	jmp ufi			/return to ufo


/saucer torpedo movement routine

etm,	dap etx
	isp \ets		/count up life
	jmp . 2
	jmp etr 1		/expired
	lac \epy
	add \edy
	dac \epy
	swap
	lac \epx
	add \edx
	dac \epx
	dpy -i 100
etx,	jmp .			/return
etr,	dap etx			/reset
	dzm \ets
	xct etd
	dac \etc
	jmp etx


/player rocket routine

rkt,	dap rkx
	lac \rks		/check for collision state
	szm			/ < 0 ?
	jmp rka			/no
	isp \rks		/manage rocket hit state
	jmp rke
	idx \rks
	lac \th0
	dac \rth
	jmp rcw
rke,	add rsd
	sma
	jmp rkx

rt1,	lac \thc		/animate collision, spin clockwise progressively
	dac \thn
	lio raa			/angular acceleration
rt2,	sil 1s
	isp \thn		/shift left \thd times
	jmp rt2
	isp \thd
	jmp rt3
	law i 20		/add another shift every 20 frames
	dac \thd
	lac \thc
	sub (1
	dac \thc
rt3,	swap
	cma cli -opr		/make it a clockwise spin, clear io
	add \rth		/update rotational angle
	jmp rkr

rka,	stf 1			/start active rocket
rcw,	jsp .			/read control word (ccw, cw, trust, fire)
	dio \cw			/merge (or) spacewar player inputs
	cla
	rcr 4s
	ior \cw
	dac \cw

	lio \cw			/parse and process rotation
	lac \rth		/load angle
	spi			/sign cleared in io?
	add raa			/no, add angular acceleration
	ril 1s			/next bit
	spi
	sub raa
rkr,	sma			/normalize 0 >= angle >= 2Pi (0311040)
	sub (311040
	spa
	add (311040
	dac \rth		/update angle

	ril 1s			/parse thrust input
	spi
	stf 2			/set flag 2 for thrust
	ril 1s
	spi i			/check next bit for fire
	jmp . 7
	szs i 30		/sense switch 3 for single shot
	jmp . 4
	lio \cwo
	ril 3s
	spi i			/block if already set in old control word
	stf 3			/set flag 3 for torp

	jda sin			/get sin, store it in \sn
	dac \sn
	lac \rth
	jda cos			/get cos, store it in \cs
	dac \cs

	szf i 2			/flag 5 set? update dx / dy
	jmp rk0
	lac \frc		/load frame counter
	isp \rac		/sensitivity, frame skip
	jmp rk1
	xct ras			/reset counter
	dac \rac
	lac \sn			/dx
	cma
	xct rvl			/apply scaling for acceleration
	swap			/swap result into io
	xct rad			/damping, get loop count
	dac \rdc
rx0,	swap			/get intermediate value from io
	add \rdx		/average with old dx
	sar 1s
	swap			/swap into io
	isp \rdc		/increment loop
	jmp rx0
	dio \rdx		/store updated dx
	lac \cs			/same for dy
	xct rvl
	swap
	xct rad
	dac \rdc
ry0,	swap
	add \rdy
	sar 1s
	swap
	isp \rdc
	jmp ry0
	dio \rdy
	jmp rk1

rk0,	dzm \rac

rk1,	scale \sn, 4s, \sn1	/get position of rocket tip
	sar 2s			/offset x = (sin >> 4) - (sin >> 8)
	cma
	add \sn1
	dac \sn1
	scale \cs, 4s, \cn1	/offset y = (cos >> 4) - (cos >> 8)
	sar 2s
	cma
	add \cn1
	dac \cn1
	lac \rpx		/update pos x (add dx)
	add \rdx
	dac \rpx
	sub \sn1		/subtract offset for tip, store it in \px
	dac \px
	lac \rpy		/same for y
	add \rdy
	dac \rpy
	add \cn1
	dac \py

	scale \sn1, 1s, \rxc	/store half-offset for hit detection
	scale \cn1, 1s, \ryc

	scale \sn, 6s, \sn8	/scaled sine, 8 steps
	sar 1s
	dac \sn4		/4 steps
	sar 1s
	dac \sn2		/2 steps
	sar 1s
	dac \sn1		/1 step
	dac \sm1
	add \sn2
	dac \sn3		/3 steps
	dac \sm3
	add \sn2
	dac \sn5		/5 steps
	add \sn1
	dac \sn6		/6 steps
	dac \sm6

	scale \cs, 6s, \cn8	/scaled cosine, 8 steps
	sar 1s
	dac \cn4		/4 steps
	sar 1s
	dac \cn2		/2 steps
	sar 1s
	dac \cn1		/1 step
	dac \cm1
	add \cn2
	dac \cn3		/3 steps
	dac \cm3
	add \cn2
	dac \cn5		/5 steps
	add \cn1
	dac \cn6		/6 steps
	dac \cm6

	jsp rod			/display it

	szf i 3			/fire torpedo?
	jmp rkq			/no
	szf i 1			/are we active?
	jmp rkq			/no
	lac \trs
	sza			/torpedo already active?
	jmp rkq			/yes
	lac \ufs
	spq			/saucers active?
	jmp rkq			/no
	xct tlf			/set up torpedo
	dac \trs
	lac \rpx		/copy position
	dac \tpx
	lac \rpy
	dac \tpy
	lac \sn			/dx
	cma
	xct trv			/apply scaling for velocity
	dac \tdx
	lac \cs			/dy
	xct trv
	dac \tdy

rkq,	szf i 2			/advance random on thrust
	jmp rki			/ to prevent patterned behavior of saucers
	random

rki,	lac \ict		/update instruction count
	add (600
	dac \ict

rkx,	jmp .


/torpedo (rocket)

trp,	dap trx
	isp \trs		/count up status counter (zero = inactive)
	jmp . 2
trx,	jmp .
	szf i 1
	jmp tr1
	lac \frc		/frame skip
	and (3
	sza
	jmp tr1
	szs 40			/sense switch 4 for high agility
	jmp tr2
	lac \cw			/check control input for rotation (ccw, cw)
	and (600000
	sza i			/steering?
	jmp tr1			/no
tr2,	lac \cs			/update with steering
	xct trv			/scale cos of rocket
	add \tdy		/average 3 times with current dy
	sar 1s
	add \tdy
	sar 1s
	add \tdy
	sar 1s
	dac \tdy		/store updated dy
	add \tpy		/update pos y
	dac \tpy
	swap
	lac \sn			/same for sine, dx and pos x
	cma
	xct trv
	add \tdx
	sar 1s
	add \tdx
	sar 1s
	add \tdx
	sar 1s
	dac \tdx
	add \tpx
	dac \tpx
	dpy -i			/display adot and jump to return
	jmp trx
tr1,	lac \tpy		/no steering, simple update
	add \tdy
	dac \tpy
	swap
	lac \tpx
	add \tdx
	dac \tpx
	dpy -i
	jmp trx

/control word get routines

/read control boxes
rcb,	dap rcx
	cli
	iot 11
rcx,	jmp .

/read testword
rtw,	dap rtx
	lat
	swap
rtx,	jmp .


/rocket display
/ step rearwards -  x add \sn1, y sub \cn1
/ step outwards  -  x add \cm1, y add \sm1
/ step inwards   -  x sub \cm1, y sub \sm1

define disp
	dpy-i 100		/display a dot at brightness level +1
	term

rod, 	dap rox
	stf 6			/set flag 6
	lac \px
	lio \py
	disp

rop,	swap			/y +4, x +6
	sub \cn4
	add \sm6
	swap
	add \sn4
	add \cm6
	disp

	swap			/y +5, x +3
	sub \cn5
	add \sm3
	swap
	add \sn5
	add \cm3
	disp

	swap			/y +6, x +1
	sub \cn6
	add \sm1
	swap
	add \sn6
	add \cm1
	disp

	swap			/y +6, x -1
	sub \cn6
	sub \sm1
	swap
	add \sn6
	sub \cm1
	disp

	swap			/y +8, x +6
	sub \cn8
	add \sm6
	swap
	add \sn8
	add \cm6
	disp

	swap			/y 3, x -10
	sub \cn3
	sub \sm3
	sub \sm6
	sub \sm1
	swap
	add \sn3
	sub \cm3
	sub \cm6
	sub \cm1
	disp

	swap			/y +7, x +6
	sub \cn8
	add \cn1
	add \sm6
	swap
	add \sn8
	sub \sn1
	add \cm6
	disp

	szf i 6			/flag 6 set? (skip on not zero)
	jmp rot
	clf 6			/clear flag 6
	lac \cm1		/invert unit vector components
	cma
	dac \cm1
	lac \sm1
	cma
	dac \sm1
	lac \cm3
	cma
	dac \cm3
	lac \sm3
	cma
	dac \sm3
	lac \cm6
	cma
	dac \cm6
	lac \sm6
	cma
	dac \sm6
	lac \px			/load first pos
	lio \py
	jmp rop			/second pass for other side

rot,	szf i 2			/no, flag 2 set?
rox,	jmp .			/no, return
	swap			/draw exhaust flame
	sub \sm6		/x -11
	sub \sm6
	add \sm1
	swap
	sub \cm6
	sub \cm6
	add \cm1
	dac \px			/store position
	dio \py
	lac \frc		/load frame counter
	and (4
	sza			/is it zero? (state switch)
	jmp ro2
ro1,	lac \py			/state 1, display at y-1
	add \cn1
	swap
	lac \px
	sub \sn1
	disp
	jmp rox
ro2,	lac \py			/state 2, display at y+5
	sub \cn5
	swap
	lac \px
	add \sn5
	disp
	jmp rox			/jump to return


/saucer display

define sdisp B			/display a dot (opt. brightness parameter)
	dpy -4000 B		/ request completion pulse
	term

sd,	dap sdx
	clf 5
	clf 6
	law i 4
	dac \sdc

sdl,	law 5000		/y +/- 10, x +/- 4
	szf 6
	cma
	add \py
	swap
	law 2000
	szf 5
	cma
	add \px
	disp

	law 3400		/y +/- 7, x +/- 7
	szf 6
	cma
	add \py
	swap
	law 3400
	szf 5
	cma
	add \px
	disp

	law 3400		/y +/- 7, x x+/- 15
	szf 6
	cma
	add \py
	swap
	law 7400
	szf 5
	cma
	add \px
	disp

	lac \sdc		/dispatch on \sdc (-4..-1) for passes (set flags)
	cma
	add (sdd
	dap sdd
	idx \sdc		/increment counter and jump
sdd,	jmp .
	jmp sd1
	jmp sd2
	jmp sd3
	stf 6			/2nd pass
	jmp sdl
sd3,	stf 5			/3rd pass
	jmp sdl
sd2,	clf 6			/4th pass
	jmp sdl
sd1,	lio \py			/done, display outer dots
	lac (12400		/y 0, x + 21 (right side)
	add \px
	sdisp 100
	lac (-12400		/y 0, x - 21 (left side)
	add \px
	ioh
	sdisp 100

	add (1000
	swap

	lac \udc		/draw first group of dots at the left
	sal 1s			/ dispatch on \udc x 3 (udc = 0..5) for clipping
	add \udc
	add (sd4 1
	dap \sd4
	swap
	lio \py
sd4, 	jmp .
	add (1000		/0
	nop
	nop
	add (1000		/1
	ioh
	sdisp
	add (1000		/2
	ioh
	sdisp
	add (1000		/3
	ioh
	sdisp
	add (1000		/4
	ioh
	sdisp

	add (3000		/5, display 4 dots
	ioh
	sdisp
	add (1000
	ioh
	sdisp
	add (1000
	ioh
	sdisp
	add (1000
	ioh
	sdisp

	add (3000		/display 4 dots
	sdisp
	add (1000
	ioh
	sdisp
	add (1000
	ioh
	sdisp
	add (1000
	ioh
	sdisp


	add (3000		/draw group of remaining dots at the right
	swap
	lac \udc		/dispatch on \udc x 3 (udc = 0..5) for clipping
	add (sd5 1
	dap sd5
	swap
	lio \py
sd5,	jmp .
	jmp sd0
	jmp sd0
	jmp sd9
	jmp sd8
	jmp sd7
	jmp sd6
sd6,	ioh			/4 dots
	sdisp
	add (1000
sd7,	ioh			/3 dots
	sdisp
	add (1000
sd8,	ioh			/2 dots
	sdisp
	add (1000
sd9,	ioh			/last dot
	sdisp
sd0,	ioh			/fetch and clear last completion pulse

sdx,	jmp .			/return


/character outline compiler

/character outlines
/ 7 rows at 5 dots, left to right, top down,
/ 2 words per character, aligned left.
cot,
	350614	306134	/0
	106041	020410	/1
	350411	442076	/2
	350411	406134	/3
	451227	610204	/4
	770207	406134	/5
	350607	506134	/6
	760421	041020	/7
	350613	506134	/8
	350613	604230	/9
	105214	376142	/A
	750617	506174	/B
	350604	102134	/C
	750614	306174	/D
	770207	502076	/E
	770207	502040	/F

coa,	. 21/			/space for addresses of character object code

cgy,	10000			/unit for character grid y
cgx,	 6000			/unit for character grid x
	. 3/			/reserve space for x-unit offsets 2..4


/setup and compile digits 0-9, chars A-F
ci,	dap cix
	lac cgx			/set up grid units (1..4)
	add cgx
	dac cgx 1
	add cgx
	dac cgx 2
	add cgx
	dac cgx 3
ci2,	dzm \t1			/compile outlines
	law ctb
	dap ci4
	law coa
	dap ci5
	cla
ci3,	dac . 4			/fix up character index
ci4,	law .			/start address of compiled code (fixed up)
ci5,	dac .			/store start address (fixed up)
	jda cc
	0			/character index (fixed up)
	dap ci4
	idx ci5
	idx \t1
	sas (21
	jmp ci3
cix,	jmp .

/character outline compiler
/ call  law addr, jda cc, char-index (see cot)
/ returns next address in ac, compiled code will exit at cdx

define comp A			/push instr. A to object code
	lac A
	dac i cc
	idx cc
	term

define cadd A			/add instr. A to ac and push to object code
	add A
	dac i cc
	idx cc
	term

cc,	0
	dap ccx
	lac i ccx		/get char-index
	sal 1s
	add (cot
	dac \cwd		/addr. of first code word
	idx ccx			/fix up return address
	stf 6			/flag 6 for first dot
	law i 22
	dac \cbi		/bit counter
	lio i \cwd		/get first code word to parse
	comp (lio cy		/- reset y
	dzm \cyi
	comp (lac cx		/- reset x
	dzm \cxp		/current x
ccr,	dzm \cxi		/new row
	spi i			/is there a dot?
	jmp ccs			/no
	lac \cxi		/get offset to last x
	sub \cxp
	sza i
	jmp ccd
	spa
	jmp ccm
	cadd (add cgx-1
	jmp cca
ccm,	cma
	cadd (sub cgx-1
cca,	lac \cxi
	dac \cxp
ccd,	szf 6
	jmp cd1
	comp (ioh		/- wait for display
cd1,	comp (dpy -4000 100	/- display a dot
	clf 6
ccs,	ril 1s			/advance to next bit
	isp \cbi
	jmp cci
	law i 22		/fetch next code word
	dac \cbi
	idx \cwd
	lio i \cwd
cci,	idx \cxi
	sas (5			/end of a row?
	jmp ccr 1		/no
	idx \cyi		/next row
	sad (7			/was it the last one?
	jmp ccz			/trail and exit
	comp (rcr 9s		/- swap
	comp (rcr 9s
	comp (sub cgy		/- increment pos y
	comp (rcr 9s		/- swap
	comp (rcr 9s
	jmp ccr
ccz,	szf 6
	jmp cz1
	comp (ioh
cz1,	comp (jmp cdx
ccx,	jmp .			/return

cx,	0
cy,	0

/display a character
/ call  law char-index, jda cd (coors in cx, cy)
cdp,	0
	dap cdx
	law coa
	add cdp
	dap . 1
	jmp i .
cdx,	jmp .

	constants
	variables

ctb,				/start address for code of outline compiler

	start 4

(~ 1.68 K 18-bit words, 03300 locations incl. variables, + JIT compiled code from 03300 – 05676, ~ 1.25 K, 02476 locations.)

 

That's all for this post.

 

Next:   Episode 10: AI and the Problem of Missing Accurately

Previous:   Episode 8: The Saucers Strike Back

Back to the index.

— This series is part of Retrochallenge 2016/10. —