Inside Spacewar!
Part 4: The Outline Compiler
(Introduction · The Code · Compiling the Outlines · Movement Semantics · Outline Pragmatics · Constraints · The Object Code)
In this part of our software archeological journey through the internals of Spacewar!, the earliest known digital video game, we're going to peek inside one of the most opaque parts of Spacewar!, Dan Edwards' famous outline compiler for drawing the spaceships.
BTW: ▶ You can play here the original code of Spacewar! running in an emulation.
There is some history behind this piece of code: Once there would have been an outline interpreter by Steve Russell which would be stepping over the defining outline data held in a separate table per spaceship. But with the introduction of the code for calculating gravity — also by Dan Edwards and all-important to the gameplay — the game was driven beyond flicker-free display performance. Enter the outline compiler, maintaining both the required speed and the configureable outlines:
The ship outlines were represented as a series of direction codes starting from the nose of the ship; when the ship was vertical and tail-down, each code pointed to one of the five possible adjacent dots could be displayed next. To display the ship at an angle, Russell calculated the appropriate sine and cosine and added them to the original direction code constants, in effect rotating the entire grid. With this method, the ship's angle had to be calculated only once in each display frame. The outline codes were kept in a table so that different shapes could be tried out at will, but this meant the table had to be searched every frame to generate the outline. As the game developed, this arrangement proved to be a sticking point which we shall see, was neatly solved by Dan Edwards.
(…)
The addition of gravity pushed Spacewar! over the edge of flicker-free display. To get back under the limit, Dan Edwards devised an elegant fiddle to speed up the outline display routine.
In Russell's original program, the outline tables were examined and interpreted in every display frame, an essentially redundant operation. Edwards replaced this procedure with an outline "compiler," which examined the tables at the start of a game and compiled a short program to generate the outline for each ship. This dramatically reduced calculation time, restoring the steady display and making room for the last of the original bells and whistles. (J. M. Graetz, "The Origin of Spacewar", Creative Computing, August 1981)
So, instead of iterating over the data twice per frame (once for each ship) and having to do all this parsing of the data and branching to various parts of the code based on the encoded commands, the outline data would be parsed once for all at the start of the game. The outline compiler would step over the various data points and would assemble the required code in a single stream of commands, to be injected into the PDP-1's memory just after the end of the data of the collidible objects table. Thus, there are now two sides to the code, which is effectively separating into two distinctive tasks, what would have been done at once by the interpreter before: On the one hand, there's the branching required to follow an outline as encoded in the outline table, which is done at compile time. On the other hand, there is the actual drawing in a 2D context, done by calling the resulting object code. For this, the main program would have to supply the current x and y coordinates telling the compiled code were to draw the outline. And it will have to tell the compiled routine, at wich angle to draw a ship. (There will be probably some trigonometry involved in order to map a given rotation angle to a Cartesian coordinate system.)
We've already seen in Part 3, how the outline compiler would have been initially called at the start of the program. Let's see, what's actually happening, when "jda oc
" is executed …
The Code
Credits: Spacewar! was conceived in 1961 by Martin Graetz, Stephen Russell, and Wayne Wiitanen. It was first realized on the PDP-1 in 1962 by Stephen Russell, Peter Samson, Dan Edwards, and Martin Graetz, together with Alan Kotok, Steve Piner, and Robert A Saunders. Spacewar! is in the public domain, but this credit paragraph must accompany all distributed versions of the program.
/outline compiler /ac=where to compile to, call jda oc /ot=address of outline table define plinst A lac A dac i oc idx oc terminate define comtab A, B plinst A jsp ocs lac B jmp oce terminate ocs, dap ocz /puts in swap dio i oc idx oc dio i oc idx oc ocz, jmp . oc, 0 /outline compiler proper dap ocx lac i ocx dap ocg plinst (stf 5 dap ocm idx ocx ock, plinst (lac \sx1 plinst (lio \sy1 clf 6 ocj, setup \occ,6 ocg, lio . /outline table och, cla rcl 3s dio \oci lio (rcl 9s dispatch opr jmp oc1 oco, jmp oc2 ocq, jmp oc3 ocp, jmp oc4 ocr, jmp oc5 jmp oc6 plinst (szf 5 /7 code add (4 dap ocn plinst ocn plinst (dac \sx1 plinst (dio \sy1 plinst (jmp sq6 plinst (clf 5 plinst (lac \scm plinst (cma plinst (dac \scm plinst (lac \ssm plinst (cma plinst (dac \ssm plinst (lac \csm plinst (lio \ssd plinst (dac \ssd plinst (dio \csm plinst (lac \ssc plinst (lio \csn plinst (dac \csn plinst (dio \ssc plinst ocm ocx, jmp . ocm, jmp . ocn, jmp . oc1, plinst (add \ssn jsp ocs lac (sub \scn oce, dac i oc idx oc jsp ocs plinst (ioh lac (dpy-4000 ocd, dac i oc idx oc lio \oci count \occ, och idx ocg jmp ocj oc2, comtab (add \scm, (add \ssm oc3, comtab (add \ssc, (sub \csm oc4, comtab (sub \scm, (sub \ssm oc5, comtab (add \csn, (sub \ssd oc6, szf 6 jmp oc9 stf 6 plinst (dac \ssa lac (dio \ssi jmp ocd oc9, clf 6 plinst (lac \ssa lac (lio \ssi jmp ocd
And this is the data defining the outlines of the spaceships:
/ outlines of spaceships ot1, 111131 111111 111111 111163 311111 146111 111114 700000 . 5/ ot2, 013113 113111 116313 131111 161151 111633 365114 700000 . 5/
(For the basics of PDP-1 instructions and Macro assembler code, please refer to Part 1. We'll repeat the semantics of the instructions as we're encountering them.)
Where to start with this piece of code? Following best practice, we'll start at the beginning, right where the compiler is called by the main code:
Compiling the Outlines
As we might remember from Part 3, the outline compiler is called by the following instructions, here for spaceship 1:
law nnn / start of outline program
dac not
/ ...
jda oc / compile outline
ot1
This is loading the address of the location right after the data of the objects table into the accumulator, stores this for later use as the start address of the compiled code in the location labeled not
, and calls the outline compiler by the instruction "jda oc
", followed by the address of the outline data for the first spaceship in the next location.
As we already know (from previous parts), instruction jda
deposits the contents of the accumulator in the location provided in the address part, puts the value of the program counter plus 1 into the accumulator (to be used as the return address) and jumps to the next location after the provided address. By this, we've successfully passed the start address for the code (in oc
) as well as the address of the data (in the accumulator), and make a jump to oc+1
.
Note: It might be fair to note here that this technique of passing multiple parameters is already to be found in the multiply and divide routines by BBN (Bolt, Beranek and Newman) and might have been adopted from there.
oc, 0 /outline compiler proper dap ocx // store address of pointer to the data in ocx lac i ocx // load first data word dap ocg // store it in address part of ocg plinst (stf 5 // compile "stf 5" (set flag 5) dap ocm // put the current object code address in ocm idx ocx // index ocx, now the actual return address
(As usual, comments starting with double slashes are mine and not in the original code.)
With location oc
serving as the pointer for the generated object code, we enter at the next instruction, where we store the location of the data table in the address part of ocx
. (This is using the naming convention generally indicating a return address. We'll see soon, why this would be so.) Then, we load the contents of the address to which the value in ocx
is pointing to, the very first location of the data table, into the accumulator. This first data word is then stored in ocg
, serving as the store for the current data word.
The macro plinst
(push last instruction ?) injects the provided constant expression in the current (or currently last) location of the object code as designated by oc
and increments oc
to point to the next location. As a side effect, the current value of oc
is also left in the accumulator. This is now stored in the address part of location ocm
(which is already containing a jmp
in the instruction part) for later use. We may note that this is the location of the next instruction after the very first "stf 5
" (set flag 5) at the start of the compiled code.
Finally, the contents of ocx
is incremented by 1, now pointing to the actual return address after the pointer to the outline data.
Let's have a closer look at macro plinst
, which is performing most of the actual assembly:
define plinst A lac A dac i oc idx oc terminate
This macro is taking a single argument (A
), a constant expression which is loaded into the accumulator by the first lac
. This value is then deposited in the location to which oc
is currently pointing to. Finally, the instruction "idx oc
" increments the contents of oc
, leaving the incremented value in the accumulator as a side effect.
The following instructions are finializing the setup steps:
ock, plinst (lac \sx1 // compile "lac \sx1" (load x into AC) plinst (lio \sy1 // compile "lio \sy1" (load y into IO) clf 6 // clear flag 6 ocj, setup \occ,6 // initialize \occ with -6
The first two pseudo instruction insert the macor plinst
to compile the instructions "lac \sx1
" and "lio \sy1
", effecting in the object code to load the x-position and the y-position of the current object (the spaceship) into the accumulator and the IO register respectively. Then "clf 6
" clears program flag 6 and the macro setup
(which we've already seen in Part 3) sets the variable \occ
to the value -6
to be used as a count-up.
By now, the compiled code is:
stf 5 lac \sx1 lio \sy1
As we may remember from Part 3, the variables \sx1
and \sy1
are containing the x and y coordinates of the current spaceship in the format used by the dpy
instruction (with the most significant 10 bits indicating the position and the lower 8 bits ignored). Thus, in the compiled code, AC and IO are now pointing to the very first display location as stored in \sx1
and \sy1
.
ocg, lio . /outline table // load current data word into IO och, cla // clear AC rcl 3s // rotate first three bits (first nibble) of IO into AC dio \oci // store rest in \oci lio (rcl 9s // load constant "rcl 9s" into IO dispatch // like FORTRAN computed GO TO on contents of AC opr // case 0: nop, fall through jmp oc1 // case 1 oco, jmp oc2 // case 2 ocq, jmp oc3 // case 3 ocp, jmp oc4 // case 4 ocr, jmp oc5 // case 5 jmp oc6 // case 6 ... // case 7
With this initial setup done, we're heading straight to the actual parsing. At ocg
the lio
instruction loads the contents of the current data word (this being the very first location, inserted previously by a dap
instruction) into the IO register. The next instruction "rcl 3s
" (rotate combined registers left) rotates the highest three bits (or nibble, or the first octal digit) into the accumulator, with the remainder stored in the variable \oci
for later use. As we can already see, the commands creating the outlines are encoded in three bits or a single octal digit. Since there are 6 of them in an 18-bit word, we also can now understand, why the counter occ
would have been initialized for a countup from -6
. The next pseudo instruction inserts the production of the macro dispatch
, which is quite the equivalent of a FORTRAN computed GO TO statement (or, as we would call this in assembler, is setting up a jump by a dispatch table):
define dispatch add (. 3 // add current address + 3 (first after macro) to AC dap . 1 // deposit in next address jmp . // and jump there term
The macro effects in an indexed jump to any of the 7 locations following immediately after its insertion.
(In case you would wonder, this macro is defined at the top of the source of part 1, in the section containing the macros specific to Spacewar!. This placement and the fact that it is used only here once, suggests that this might have been a piece of code used more commonly by the original outline interpreter.)
The first instruction of the dispatch table, executed in case that the accumulator would contain 0
, is a simple opr
, synonymous to nop
(no operation). This will simply fall through to the next case.
The next jmp
instructions cover the cases for the acumulator containing any value in the range 1..6
, and with 7
, we would continue with the code following to these jump vectors.
Let's see, what's happening, in case we would take the jump to oc1
for a nibble of value 1
in our data word:
oc1, plinst (add \ssn // compile "add \ssn" jsp ocs // copy IO to the next 2 addresses at oc (swap) lac (sub \scn // load "sub \scn" into AC oce, dac i oc // display action: deposit AC at current code location idx oc // increment oc jsp ocs // copy IO to the next 2 addresses at oc (swap) plinst (ioh // compile "ioh" (wait for completion pulse) lac (dpy-4000 // load "dpy-400" into AC ocd, dac i oc // deposit at current code location idx oc // increment oc lio \oci // advance to next nibble or word: load \oci in IO count \occ, och // increment \occ (up from -6), while negative, // jump to och (get next nibble and execute switch) idx ocg // increment ocg (next data word) jmp ocj // start over with the new data word
After compiling "add \ssn
" by inserting macro plinst
(we'll explore the semantics of these variables soon), the jump to the subroutine ocs
effects in the compiliation of twice the contents of IO:
ocs, dap ocz /puts in swap // deposit return address in ocz dio i oc // deposit IO in address in oc idx oc // increment oc dio i oc // deposit IO in address in oc idx oc // increment oc ocz, jmp . // return
Since the IO register was set up to contain the value of the constant expression "rcl 9s
", this will insert the equivalent of the macro swap
, we've seen already in Part 2: Two consecutive instructions to rotate AC and IO as a combined register by 9 bits, resulting in an exchange of the contents of the two registers. As we may remember, this was used to set up AC for the x-coordinate of a dpy
instruction, then swap the registers, compose the y-coordinate in the accumulator, and swap the registers back, now with the y-coordinate in IO and the x-coordinate in AC.
This is exactly what is compiled here: AC was set up in the compiled code to contain the current x-coordinate as in \sx1
. This is now swapped and the accumulator is now containing the current y-position. The expression "sub \scn
" is now compiled and this is followed by another call of ocs
, inserting another swap.
The pseudo instruction "plinst (ioh
" compiles a ioh
instruction, resulting in the CPU to wait for the completion pulse sent by the CRT display. (For details, please refer to Part 2.) Then the constant expression for the actual display command "dpy-4000
" is loaded into AC. At ocd
this is put at the current end of the object code stack and the pointer oc
is incremented once again.
By now, this inserted the following code production in the object code at oc
, updating both the x and y coordinates, waiting for the display to be ready, and finally issuing a new display command:
add \ssn rcl 9s rcl 9s sub \scn rcl 9s rcl 9s ioh dpy-4000
With the actual compilation done, we're left with advancing to the next nibble of the outline data (last few lines repeated from above):
lio \oci // advance to next nibble or word: load \oci in IO count \occ, och // increment \occ (up from -6), while negative, // jump to och (get next nibble and execute switch) idx ocg // increment ocg (next data word) jmp ocj // start over with the new data word
This loads the rest of the rotated data word as stored previously in \oci
into IO, just as befor at label ocg
. The pseudo instruction "count \occ, och
" performs the count-up on the 6 nibbles of the data word. (We've seen the macro count
already in Part 3.) If \occ
would be still negative after the increment, we would jump to label och
, rotating the next nibble into AC. If the result would be positive, indicating we would have parsed all 6 nibbles already, we fall through to the next instruction, incrementing the address stored in ocg
to advance to the next data word. This is then parsed by the jump to ocj
, resetting the counter \occ
, and starting over with the new data word.
Having investigated a full loop for parsing and compiling an outline code of 1
, let's see whats happening with some other codes:
oc2, comtab (add \scm, (add \ssm oc3, comtab (add \ssc, (sub \csm oc4, comtab (sub \scm, (sub \ssm oc5, comtab (add \csn, (sub \ssd
The jump vectors for the codes 2..5
will take us to the labels with the respective numbers at their end. Each of them inserts the macro comtab
with two constant expressions as the arguments, each representing an instruction to be compiled. This is, what comtab
(command tablutor ?) looks like:
define comtab A, B plinst A // compile A in oc jsp ocs // compile swap lac B // put B into AC jmp oce // display and advance terminate
This is compiling the first parameter into the current location of the object code, adds a swap to it (there's still "rcl 9s
" in IO) and puts the value of the second parameter into the accumulator. Then it jumps to the label oce
, we've seen before: This will compile the contents of AC, add another swap to the compiled code, as well as the ioh
and dpy-4000
instructions, and execute the next iteration over the parse/compile loop.
Thus, macro comtab
produces a compiled object code quite like the one we've seen before, with the notable difference of the instructions for updating the x and y coordinates by the expressions in A
and B
respectively:
A // first parameter (update x) rcl 9s rcl 9s B // second parameter (update y) rcl 9s rcl 9s ioh dpy-4000
Note: An attentive reader might have noticed that this is the same production as the one of the code entered at oc1
, even using the same instructions at label oce
and beyond, but with parameters. Why isn't the code at oc1
just "comtab (add \ssn, (sub \scn
"? We don't know, but it's quite as if the code at oc1
would be exemplifying the workings of the macro comtab
which would be hidden in some indirectness else.
Movement Semantics
In order to understand the semantics of these code productions inserted by the outline codes 0...5
, we'll have to peek ahead into some code of the main program, we haven't explored yet. By now, we only know that the outline commands will cause the following movements:
outline advance by x, y: 0: fall through to 1 1: +\ssn -\scn 2: +\scm +\ssm 3: +\ssc -\csm 4: -\scm -\ssm 5: +\csn -\ssd
Inside the code managing the spaceships, we'll find the following setup of these variables just before the call of the compiled outline code (at sp5
), with \sn
being the sine of the rotation angle in mth
and \cs
containing the cosine:
scale \sn, 9s, \ssn // store scaled sine in \ssn scale \cs, 9s, \scn // store scaled cosine in \scn lac \ssn dac \ssm // \ssm = \ssn add \scn dac \ssc // \ssc = \ssn + \scn dac \ssd // \ssd = \ssn + \scn lac \ssn sub \scn dac \csn // \csn = \ssn - \scn cma // complement AC dac \csm // \csm = -\csn lac \scn dac \scm // \scm = \scn cla cli-opr // clear AC and IO dpy-4000 // display a dot in center, request completion pulse sp5, jmp . // jump to compiled outline code sq6, ioh // wait for last completion pulse
The two insertions of the macro scale
are scaling the current sine and cosine to a value that would produce an advance by a single display location for a value of 1
. (By altering the scaling factor as in 9s
, we could enlarge the outline by multiplying the steps by powers of 2. This is also the trick applied by Barry Silverman, Brian Silverman, and Vadim Gerasimov in their version of the code of Spacewar! 3.1, modified to display the ships at double size for the benefit of modern displays, by changing this value to 8s
.) Since the format of the positional values for the dpy
instruction automatically allows for a fractional part of 8 binary digits, any values between 0
and 1
will be handled gracefully, with just the discrete integer parts used as the actual display location.
As we can see, rather than just supplying the turning angle (theta) of the ship, the required trigonometry is done in the main program. This is part of Steve Russell's "basic trick" of calculating the sine and cosine only once per frame and reusing them (resulting in something alike turning the entire universe), here by setting up a matrix of derivative values for the use of the compiled outline routines, which will have to deal with these positional offsets only. This is, what this matrix looks like, when the code produced by the outline compiler is called at label sq5
:
\ssn = sin (scaled) \scn = cos (scaled) \ssm = \ssn \ssc = \ssn + \scn \ssd = \ssn + \scn \csn = \ssn - \scn \csm = -(\ssn - \scn) \scm = \scn
Before we investigating these values, we may note the actual calling sequence of the compiled outline code: Since the compiled code is starting with a ioh
, we would need to call a dpy-4000
instruction before (in order to provide the completion pulse by the display) or the code would be waiting for ever. This is provided by the combined cla
(clear AC) and cli
(clear IO) as in "cla cli-opr
" and the following dpy-4000
display command. As this is resetting AC and IO to point to the origin at the center of the screen, there will be always a spot at the very center of the scope, even, if the "heavy star" would be disabled by activating sense switch 6. Likewise, the code produced by the compiler loop is ending in a dpy-4000
instruction, so there's a ioh
to wait for and clear this final completion pulse at label sq6
.
Back to the semantics of the outline code, we'll see that just some values are actually used to move the outline in the resulting code. This would translate to the following values and respective movements:
Movements by x, y: code / theta (deg) 90 45 30 0 0: => 1 1: +sin -cos 1 -0 0.7 -0.7 0.5 -0.8 0 -1 2: +cos +sin 0 1 0.7 0.7 0.8 0.5 1 0 3: +(sin+cos) +(sin-cos) 1 1 1.4 0 1.3 -0.3 1 -1 4: -cos -sin -0 -1 -0.7 -0.7 -0.8 -0.5 -1 0 5: +(sin-cos) -(sin+cos) 1 -1 0 -1.4 -0.3 -1.3 -1 -1
Thus, for a rotation angle theta of 0
, the following semantics apply to the outline codes 0..5
:
0: fall through to 1 1: 0 -1 down 2: 1 0 right 3: 1 -1 right down 4: -1 0 left 5: -1 -1 left down
So, what's happening at codes 6
and 7
, and why are there 8 variables defined to encode just 5 distinctive values? Let's see:
Outline Pragmatics
The codes 6
and 7
may be referred to as the pragmatic part of the outline vocabulary. This is, what's happening at oc6
, executed for code 6
:
oc6, szf 6 // flag 6: store or restore? jmp oc9 // set: restore position at oc9 stf 6 // set flag 6 for visted, store position plinst (dac \ssa // compile "dac \ssa" (deposit AC in \ssa) lac (dio \ssi // load "dio \ssi" (deposit IO in \ssi) jmp ocd // compile and next nibble oc9, clf 6 // clear flag 6 plinst (lac \ssa // compile "lac \ssa" (load \ssa) lac (lio \ssi // load "lio \ssi" (load \ssi) jmp ocd // compile and next nibble
So, based on flag 6 set or unset, this either compiles a code that will store the current x and y coordinates as in AC and IO in the variables \ssa
and \ssi
respectively, or will restore the current location from these. (Label ocd
is the final part of the parser/compiler loop, depositing the contents of the accumulator in the current object-code address and advancing to the next nibble or word.)
Since flag 6 is initially cleared just before the start of the loop at label ocj
, code 6
is alternatingly storing and restore the current display location for the outline.
The part covering code 7
is following immediately to the jump table with the vectors for code 1..6
:
plinst (szf 5 /7 code // compile "szf 5" add (4 // add 4 (to oc) dap ocn // deposit in address part of ocn plinst ocn // compile "jmp ocn" (oc+4) plinst (dac \sx1 // compile "dac \sx1" (deposit AC in \sx1) plinst (dio \sy1 // compile "dio \sx1" (deposit IO in \sy1) plinst (jmp sq6 // compile "jmp sq6" (return) plinst (clf 5 // compile "clf 5" (clear flag 5) plinst (lac \scm // compile "lac \scm" (load \scm into AC) plinst (cma // compile "cma" (complement AC) plinst (dac \scm // compile "dac \scm" (\scm = -\scm) plinst (lac \ssm // compile "lac \ssm" plinst (cma // compile "cma" plinst (dac \ssm // compile "dac \ssm" (\ssm = -\ssm) plinst (lac \csm // compile "lac \csm" plinst (lio \ssd // compile "lio \ssd" plinst (dac \ssd // compile "dac \ssd" (swap \csm and \ssd) plinst (dio \csm // compile "dio \csm" (--"--) plinst (lac \ssc // compile "lac \ssc" plinst (lio \csn // compile "lio \csn" plinst (dac \csn // compile "dac \csn" (swap \csn and \ssc) plinst (dio \ssc // compile "dio \ssc" (--"--) plinst ocm // compile "jmp <start+1>" (start over) ocx, jmp . // return ocm, jmp . ocn, jmp .
As we can see by the jump instruction at label ocx
, a code of 7
is ending the compilition. Also, as we've seen all of the code of the outline compiler by now, a code 7
must be the last command of any outline data, else the compiler will not return. (Since the current value of oc
is also left by plinst
in the accumulator, when executing the jump at ocx
, the location of the next instruction follwing immediately after the object code will be returned thus in the accumulator to the main program.)
On the pragmatic side, this is producing the following object code as the final coda of the assembled stream:
szf 5 // flag 5 zero? jmp . + 4 // no, not visited yet, skip next three instructions dac \sx1 // yes, update \sx1 and \sx2 to current outline position dio \sy1 jmp sq6 // return (sq6 is a label in the main program) clf 5 // clear flag 5 lac \scm cma dac \scm // \scm = -\scm lac \ssm cma dac \ssm // \ssm = -\ssm lac \csm lio \ssd dac \ssd // swap \ssd and \csm dio \csm lac \ssc lio \csn dac \csn // swap \csn and \ssc dio \ssc jmp <ocm> // start+1
As we may remember, a "stf 5
" (set flag 5) was the very first instruction compiled at the head of the resulting outline code. Now this flag is checked. If still set, we haven't seen this code production by command 7
yet and jump to the "clf 5
" instruction 4 locations ahead, clearing this flag. The next instructions are either complementing or swapping all values related to left and right movements, then the code jumps to the very beginning, just after the initial set flag 5 to start over with the same code, but now drawing the left side.
If we would return from this second run, as indicated by a cleared flag 5, the code stores the current position of the outline in \sx1
and \sy1
, the x and y coordinates of the spaceship currently handled. Thanks to this, any exhaust trail to be displayed for a thrusting ship will be drawn at the exact tail position, what ever shape would be described by the outline data.
Now, we may provide the complete instruction set of the outline compiler, properly replacing any references to left and right by in and out, referring to either an inward or outward direction relative to the central y-axis:
0: synonymous to 1 1: down 2: out 3: out & down 4: in 5: in & down 6: store /restore current position 7: draw other side / return
Note: Actually, we might exchange the terms "out" and "in". Applying them as described here, we would start in a clockwise motion — as used in Spacewar!. By interchanging them, we would still achieve a visually similar result, but now by drawing the first half of the outline in a counterclockwise motion. This is much like describing (a cross section of) a lathe object by describing the curve defining its surface: It doesn't matter, which side of the object we would actually describe, as long as we're using directions consistently.
Constraints
An attentive reader may have already noticed the following constraints applied to any outline data, to be properly contemplated by any ardent hacker of spaceship outlines (remember the extra space of 4 instruction words appended to each of the data tables?):
- The default orientation is standing on the tail, drawn from the tip downwards (there are only downward and/or sideward movements and store/restore).
- Each outline will be drawn symetrically, mirrored by the y axis. (Dots located at the center will be drawn twice.)
- Each outline should end at the very center and at the very bottom (else any exhaust flames would be drawn in an odd position).
- A spaceship's position, as in
\sx1
and\sy1
, is actually outside the outlines of the ship (just in front of its tip) — therefor there must be some compensation applied (as we'll see this in a future episode). - Since runtime is always an issue (and the combination of
ioh
anddpy-4000
instructions is requiring at least 50 microseconds per outline code, cf. Part 2), each of the spaceships should be drawn by an equal count of outline codes in the interest of a stable frame rate.
It's also this very last constraint, which might shed some light on the else superfluous outline code 0
that is still the very first code of the outline data for the second spaceship, the "wedge", as defined in ot2
: This might have originally served as some kind of elaborated NOP
, spending the runtime consumed by any of the other outline commands (each of them being of the same length and cycle count), while effecting essentially in a void instruction, just to compensate for any timing differences. (Please mind that this just a guess and not confirmed by any historical sources or references.)
Sticking to our usual procedures, this would be just the place to investigate a (prominent) variations of the main theme of the article as to be found in some versions of Spacewar!. — But not this time!
The outline compiler was that a success, it didn't see any variations or modifications at all, just like the data defining the outline of two spaceships.
With nothing else to show, we're closing here with the disassembly of the productions of the outline compiler for both of the spaceships:
The Object Code
Disassembly of the spaceship outline code produced by the outline compiler, locations as in Spacewar! 3.1 (labels c1m
and c2m
inserted by me, N.L.):
spaceship 1 ot1, 111131 111111 111111 111163 311111 146111 111114 700000 loc. instr. opcode symbols 3772 760015 stf 5 stf 5 3773 203225 lac 3225 c1m, lac \sx1 3774 223226 lio 3226 lio \sy1 3775 403223 add 3223 add \ssn 3776 663777 rcl 9s rcl 9s 3777 663777 rcl 9s rcl 9s 4000 423224 sub 3224 sub \scn 4001 663777 rcl 9s rcl 9s 4002 663777 rcl 9s rcl 9s 4003 730000 ioh ioh 4004 724007 dpy-4000 dpy-4000 4005 403223 add 3223 add \ssn 4006 663777 rcl 9s rcl 9s 4007 663777 rcl 9s rcl 9s 4010 423224 sub 3224 sub \scn 4011 663777 rcl 9s rcl 9s 4012 663777 rcl 9s rcl 9s 4013 730000 ioh ioh 4014 724007 dpy-4000 dpy-4000 4015 403223 add 3223 add \ssn 4016 663777 rcl 9s rcl 9s 4017 663777 rcl 9s rcl 9s 4020 423224 sub 3224 sub \scn 4021 663777 rcl 9s rcl 9s 4022 663777 rcl 9s rcl 9s 4023 730000 ioh ioh 4024 724007 dpy-4000 dpy-4000 4025 403223 add 3223 add \ssn 4026 663777 rcl 9s rcl 9s 4027 663777 rcl 9s rcl 9s 4030 423224 sub 3224 sub \scn 4031 663777 rcl 9s rcl 9s 4032 663777 rcl 9s rcl 9s 4033 730000 ioh ioh 4034 724007 dpy-4000 dpy-4000 4035 403235 add 3235 add \ssc 4036 663777 rcl 9s rcl 9s 4037 663777 rcl 9s rcl 9s 4040 423233 sub 3233 sub \csm 4041 663777 rcl 9s rcl 9s 4042 663777 rcl 9s rcl 9s 4043 730000 ioh ioh 4044 724007 dpy-4000 dpy-4000 4045 403223 add 3223 add \ssn 4046 663777 rcl 9s rcl 9s 4047 663777 rcl 9s rcl 9s 4050 423224 sub 3224 sub \scn 4051 663777 rcl 9s rcl 9s 4052 663777 rcl 9s rcl 9s 4053 730000 ioh ioh 4054 724007 dpy-4000 dpy-4000 4055 403223 add 3223 add \ssn 4056 663777 rcl 9s rcl 9s 4057 663777 rcl 9s rcl 9s 4060 423224 sub 3224 sub \scn 4061 663777 rcl 9s rcl 9s 4062 663777 rcl 9s rcl 9s 4063 730000 ioh ioh 4064 724007 dpy-4000 dpy-4000 4065 403223 add 3223 add \ssn 4066 663777 rcl 9s rcl 9s 4067 663777 rcl 9s rcl 9s 4070 423224 sub 3224 sub \scn 4071 663777 rcl 9s rcl 9s 4072 663777 rcl 9s rcl 9s 4073 730000 ioh ioh 4074 724007 dpy-4000 dpy-4000 4075 403223 add 3223 add \ssn 4076 663777 rcl 9s rcl 9s 4077 663777 rcl 9s rcl 9s 4100 423224 sub 3224 sub \scn 4101 663777 rcl 9s rcl 9s 4102 663777 rcl 9s rcl 9s 4103 730000 ioh ioh 4104 724007 dpy-4000 dpy-4000 4105 403223 add 3223 add \ssn 4106 663777 rcl 9s rcl 9s 4107 663777 rcl 9s rcl 9s 4110 423224 sub 3224 sub \scn 4111 663777 rcl 9s rcl 9s 4112 663777 rcl 9s rcl 9s 4113 730000 ioh ioh 4114 724007 dpy-4000 dpy-4000 4115 403223 add 3223 add \ssn 4116 663777 rcl 9s rcl 9s 4117 663777 rcl 9s rcl 9s 4120 423224 sub 3224 sub \scn 4121 663777 rcl 9s rcl 9s 4122 663777 rcl 9s rcl 9s 4123 730000 ioh ioh 4124 724007 dpy-4000 dpy-4000 4125 403223 add 3223 add \ssn 4126 663777 rcl 9s rcl 9s 4127 663777 rcl 9s rcl 9s 4130 423224 sub 3224 sub \scn 4131 663777 rcl 9s rcl 9s 4132 663777 rcl 9s rcl 9s 4133 730000 ioh ioh 4134 724007 dpy-4000 dpy-4000 4135 403223 add 3223 add \ssn 4136 663777 rcl 9s rcl 9s 4137 663777 rcl 9s rcl 9s 4140 423224 sub 3224 sub \scn 4141 663777 rcl 9s rcl 9s 4142 663777 rcl 9s rcl 9s 4143 730000 ioh ioh 4144 724007 dpy-4000 dpy-4000 4145 403223 add 3223 add \ssn 4146 663777 rcl 9s rcl 9s 4147 663777 rcl 9s rcl 9s 4150 423224 sub 3224 sub \scn 4151 663777 rcl 9s rcl 9s 4152 663777 rcl 9s rcl 9s 4153 730000 ioh ioh 4154 724007 dpy-4000 dpy-4000 4155 403223 add 3223 add \ssn 4156 663777 rcl 9s rcl 9s 4157 663777 rcl 9s rcl 9s 4160 423224 sub 3224 sub \scn 4161 663777 rcl 9s rcl 9s 4162 663777 rcl 9s rcl 9s 4163 730000 ioh ioh 4164 724007 dpy-4000 dpy-4000 4165 403223 add 3223 add \ssn 4166 663777 rcl 9s rcl 9s 4167 663777 rcl 9s rcl 9s 4170 423224 sub 3224 sub \scn 4171 663777 rcl 9s rcl 9s 4172 663777 rcl 9s rcl 9s 4173 730000 ioh ioh 4174 724007 dpy-4000 dpy-4000 4175 403223 add 3223 add \ssn 4176 663777 rcl 9s rcl 9s 4177 663777 rcl 9s rcl 9s 4200 423224 sub 3224 sub \scn 4201 663777 rcl 9s rcl 9s 4202 663777 rcl 9s rcl 9s 4203 730000 ioh ioh 4204 724007 dpy-4000 dpy-4000 4205 403223 add 3223 add \ssn 4206 663777 rcl 9s rcl 9s 4207 663777 rcl 9s rcl 9s 4210 423224 sub 3224 sub \scn 4211 663777 rcl 9s rcl 9s 4212 663777 rcl 9s rcl 9s 4213 730000 ioh ioh 4214 724007 dpy-4000 dpy-4000 4215 403223 add 3223 add \ssn 4216 663777 rcl 9s rcl 9s 4217 663777 rcl 9s rcl 9s 4220 423224 sub 3224 sub \scn 4221 663777 rcl 9s rcl 9s 4222 663777 rcl 9s rcl 9s 4223 730000 ioh ioh 4224 724007 dpy-4000 dpy-4000 4225 403223 add 3223 add \ssn 4226 663777 rcl 9s rcl 9s 4227 663777 rcl 9s rcl 9s 4230 423224 sub 3224 sub \scn 4231 663777 rcl 9s rcl 9s 4232 663777 rcl 9s rcl 9s 4233 730000 ioh ioh 4234 724007 dpy-4000 dpy-4000 4235 403223 add 3223 add \ssn 4236 663777 rcl 9s rcl 9s 4237 663777 rcl 9s rcl 9s 4240 423224 sub 3224 sub \scn 4241 663777 rcl 9s rcl 9s 4242 663777 rcl 9s rcl 9s 4243 730000 ioh ioh 4244 724007 dpy-4000 dpy-4000 4245 403223 add 3223 add \ssn 4246 663777 rcl 9s rcl 9s 4247 663777 rcl 9s rcl 9s 4250 423224 sub 3224 sub \scn 4251 663777 rcl 9s rcl 9s 4252 663777 rcl 9s rcl 9s 4253 730000 ioh ioh 4254 724007 dpy-4000 dpy-4000 4255 243237 dac 3237 dac \ssa 4256 323240 dio 3240 dio \ssi 4257 403235 add 3235 add \ssc 4260 663777 rcl 9s rcl 9s 4261 663777 rcl 9s rcl 9s 4262 423233 sub 3233 sub \csm 4263 663777 rcl 9s rcl 9s 4264 663777 rcl 9s rcl 9s 4265 730000 ioh ioh 4266 724007 dpy-4000 dpy-4000 4267 403235 add 3235 add \ssc 4270 663777 rcl 9s rcl 9s 4271 663777 rcl 9s rcl 9s 4272 423233 sub 3233 sub \csm 4273 663777 rcl 9s rcl 9s 4274 663777 rcl 9s rcl 9s 4275 730000 ioh ioh 4276 724007 dpy-4000 dpy-4000 4277 403223 add 3223 add \ssn 4300 663777 rcl 9s rcl 9s 4301 663777 rcl 9s rcl 9s 4302 423224 sub 3224 sub \scn 4303 663777 rcl 9s rcl 9s 4304 663777 rcl 9s rcl 9s 4305 730000 ioh ioh 4306 724007 dpy-4000 dpy-4000 4307 403223 add 3223 add \ssn 4310 663777 rcl 9s rcl 9s 4311 663777 rcl 9s rcl 9s 4312 423224 sub 3224 sub \scn 4313 663777 rcl 9s rcl 9s 4314 663777 rcl 9s rcl 9s 4315 730000 ioh ioh 4316 724007 dpy-4000 dpy-4000 4317 403223 add 3223 add \ssn 4320 663777 rcl 9s rcl 9s 4321 663777 rcl 9s rcl 9s 4322 423224 sub 3224 sub \scn 4323 663777 rcl 9s rcl 9s 4324 663777 rcl 9s rcl 9s 4325 730000 ioh ioh 4326 724007 dpy-4000 dpy-4000 4327 403223 add 3223 add \ssn 4330 663777 rcl 9s rcl 9s 4331 663777 rcl 9s rcl 9s 4332 423224 sub 3224 sub \scn 4333 663777 rcl 9s rcl 9s 4334 663777 rcl 9s rcl 9s 4335 730000 ioh ioh 4336 724007 dpy-4000 dpy-4000 4337 403223 add 3223 add \ssn 4340 663777 rcl 9s rcl 9s 4341 663777 rcl 9s rcl 9s 4342 423224 sub 3224 sub \scn 4343 663777 rcl 9s rcl 9s 4344 663777 rcl 9s rcl 9s 4345 730000 ioh ioh 4346 724007 dpy-4000 dpy-4000 4347 403223 add 3223 add \ssn 4350 663777 rcl 9s rcl 9s 4351 663777 rcl 9s rcl 9s 4352 423224 sub 3224 sub \scn 4353 663777 rcl 9s rcl 9s 4354 663777 rcl 9s rcl 9s 4355 730000 ioh ioh 4356 724007 dpy-4000 dpy-4000 4357 423231 sub 3231 sub \scm 4360 663777 rcl 9s rcl 9s 4361 663777 rcl 9s rcl 9s 4362 423232 sub 3232 sub \ssm 4363 663777 rcl 9s rcl 9s 4364 663777 rcl 9s rcl 9s 4365 730000 ioh ioh 4366 724007 dpy-4000 dpy-4000 4367 203237 lac 3237 lac \ssa 4370 223240 lio 3240 lio \ssi 4371 403223 add 3223 add \ssn 4372 663777 rcl 9s rcl 9s 4373 663777 rcl 9s rcl 9s 4374 423224 sub 3224 sub \scn 4375 663777 rcl 9s rcl 9s 4376 663777 rcl 9s rcl 9s 4377 730000 ioh ioh 4400 724007 dpy-4000 dpy-4000 4401 403223 add 3223 add \ssn 4402 663777 rcl 9s rcl 9s 4403 663777 rcl 9s rcl 9s 4404 423224 sub 3224 sub \scn 4405 663777 rcl 9s rcl 9s 4406 663777 rcl 9s rcl 9s 4407 730000 ioh ioh 4410 724007 dpy-4000 dpy-4000 4411 403223 add 3223 add \ssn 4412 663777 rcl 9s rcl 9s 4413 663777 rcl 9s rcl 9s 4414 423224 sub 3224 sub \scn 4415 663777 rcl 9s rcl 9s 4416 663777 rcl 9s rcl 9s 4417 730000 ioh ioh 4420 724007 dpy-4000 dpy-4000 4421 403223 add 3223 add \ssn 4422 663777 rcl 9s rcl 9s 4423 663777 rcl 9s rcl 9s 4424 423224 sub 3224 sub \scn 4425 663777 rcl 9s rcl 9s 4426 663777 rcl 9s rcl 9s 4427 730000 ioh ioh 4430 724007 dpy-4000 dpy-4000 4431 403223 add 3223 add \ssn 4432 663777 rcl 9s rcl 9s 4433 663777 rcl 9s rcl 9s 4434 423224 sub 3224 sub \scn 4435 663777 rcl 9s rcl 9s 4436 663777 rcl 9s rcl 9s 4437 730000 ioh ioh 4440 724007 dpy-4000 dpy-4000 4441 403223 add 3223 add \ssn 4442 663777 rcl 9s rcl 9s 4443 663777 rcl 9s rcl 9s 4444 423224 sub 3224 sub \scn 4445 663777 rcl 9s rcl 9s 4446 663777 rcl 9s rcl 9s 4447 730000 ioh ioh 4450 724007 dpy-4000 dpy-4000 4451 403223 add 3223 add \ssn 4452 663777 rcl 9s rcl 9s 4453 663777 rcl 9s rcl 9s 4454 423224 sub 3224 sub \scn 4455 663777 rcl 9s rcl 9s 4456 663777 rcl 9s rcl 9s 4457 730000 ioh ioh 4460 724007 dpy-4000 dpy-4000 4461 403223 add 3223 add \ssn 4462 663777 rcl 9s rcl 9s 4463 663777 rcl 9s rcl 9s 4464 423224 sub 3224 sub \scn 4465 663777 rcl 9s rcl 9s 4466 663777 rcl 9s rcl 9s 4467 730000 ioh ioh 4470 724007 dpy-4000 dpy-4000 4471 423231 sub 3231 sub \scm 4472 663777 rcl 9s rcl 9s 4473 663777 rcl 9s rcl 9s 4474 423232 sub 3232 sub \ssm 4475 663777 rcl 9s rcl 9s 4476 663777 rcl 9s rcl 9s 4477 730000 ioh ioh 4500 724007 dpy-4000 dpy-4000 4501 640005 szf 5 szf 5 4502 604506 jmp 4506 jmp . 4 4503 243225 dac 3225 dac \sx1 4504 323226 dio 3226 dio \sy1 4505 602531 jmp 2531 jmp sq6 4506 760005 clf 5 clf 5 4507 203231 lac 3231 lac \scm 4510 761000 cma cma 4511 243231 dac 3231 dac \scm 4512 203232 lac 3232 lac \ssm 4513 761000 cma cma 4514 243232 dac 3232 dac \ssm 4515 203233 lac 3233 lac \csm 4516 223234 lio 3234 lio \ssd 4517 243234 dac 3234 dac \ssd 4520 323233 dio 3233 dio \csm 4521 203235 lac 3235 lac \ssc 4522 223236 lio 3236 lio \csn 4523 243236 dac 3236 dac \csn 4524 323235 dio 3235 dio \ssc 4525 603773 jmp 3773 jmp c1m spaceship 2 ot2, 013113 113111 116313 131111 161151 111633 365114 700000 loc. instr. opcode symbols 4526 760015 stf 5 stf 5 4527 203225 lac 3225 c2m, lac \sx1 4530 223226 lio 3226 lio \sy1 4531 403223 add 3223 add \ssn 4532 663777 rcl 9s rcl 9s 4533 663777 rcl 9s rcl 9s 4534 423224 sub 3224 sub \scn 4535 663777 rcl 9s rcl 9s 4536 663777 rcl 9s rcl 9s 4537 730000 ioh ioh 4540 724007 dpy-4000 dpy-4000 4541 403223 add 3223 add \ssn 4542 663777 rcl 9s rcl 9s 4543 663777 rcl 9s rcl 9s 4544 423224 sub 3224 sub \scn 4545 663777 rcl 9s rcl 9s 4546 663777 rcl 9s rcl 9s 4547 730000 ioh ioh 4550 724007 dpy-4000 dpy-4000 4551 403235 add 3235 add \ssc 4552 663777 rcl 9s rcl 9s 4553 663777 rcl 9s rcl 9s 4554 423233 sub 3233 sub \csm 4555 663777 rcl 9s rcl 9s 4556 663777 rcl 9s rcl 9s 4557 730000 ioh ioh 4560 724007 dpy-4000 dpy-4000 4561 403223 add 3223 add \ssn 4562 663777 rcl 9s rcl 9s 4563 663777 rcl 9s rcl 9s 4564 423224 sub 3224 sub \scn 4565 663777 rcl 9s rcl 9s 4566 663777 rcl 9s rcl 9s 4567 730000 ioh ioh 4570 724007 dpy-4000 dpy-4000 4571 403223 add 3223 add \ssn 4572 663777 rcl 9s rcl 9s 4573 663777 rcl 9s rcl 9s 4574 423224 sub 3224 sub \scn 4575 663777 rcl 9s rcl 9s 4576 663777 rcl 9s rcl 9s 4577 730000 ioh ioh 4600 724007 dpy-4000 dpy-4000 4601 403235 add 3235 add \ssc 4602 663777 rcl 9s rcl 9s 4603 663777 rcl 9s rcl 9s 4604 423233 sub 3233 sub \csm 4605 663777 rcl 9s rcl 9s 4606 663777 rcl 9s rcl 9s 4607 730000 ioh ioh 4610 724007 dpy-4000 dpy-4000 4611 403223 add 3223 add \ssn 4612 663777 rcl 9s rcl 9s 4613 663777 rcl 9s rcl 9s 4614 423224 sub 3224 sub \scn 4615 663777 rcl 9s rcl 9s 4616 663777 rcl 9s rcl 9s 4617 730000 ioh ioh 4620 724007 dpy-4000 dpy-4000 4621 403223 add 3223 add \ssn 4622 663777 rcl 9s rcl 9s 4623 663777 rcl 9s rcl 9s 4624 423224 sub 3224 sub \scn 4625 663777 rcl 9s rcl 9s 4626 663777 rcl 9s rcl 9s 4627 730000 ioh ioh 4630 724007 dpy-4000 dpy-4000 4631 403235 add 3235 add \ssc 4632 663777 rcl 9s rcl 9s 4633 663777 rcl 9s rcl 9s 4634 423233 sub 3233 sub \csm 4635 663777 rcl 9s rcl 9s 4636 663777 rcl 9s rcl 9s 4637 730000 ioh ioh 4640 724007 dpy-4000 dpy-4000 4641 403223 add 3223 add \ssn 4642 663777 rcl 9s rcl 9s 4643 663777 rcl 9s rcl 9s 4644 423224 sub 3224 sub \scn 4645 663777 rcl 9s rcl 9s 4646 663777 rcl 9s rcl 9s 4647 730000 ioh ioh 4650 724007 dpy-4000 dpy-4000 4651 403223 add 3223 add \ssn 4652 663777 rcl 9s rcl 9s 4653 663777 rcl 9s rcl 9s 4654 423224 sub 3224 sub \scn 4655 663777 rcl 9s rcl 9s 4656 663777 rcl 9s rcl 9s 4657 730000 ioh ioh 4660 724007 dpy-4000 dpy-4000 4661 403223 add 3223 add \ssn 4662 663777 rcl 9s rcl 9s 4663 663777 rcl 9s rcl 9s 4664 423224 sub 3224 sub \scn 4665 663777 rcl 9s rcl 9s 4666 663777 rcl 9s rcl 9s 4667 730000 ioh ioh 4670 724007 dpy-4000 dpy-4000 4671 403223 add 3223 add \ssn 4672 663777 rcl 9s rcl 9s 4673 663777 rcl 9s rcl 9s 4674 423224 sub 3224 sub \scn 4675 663777 rcl 9s rcl 9s 4676 663777 rcl 9s rcl 9s 4677 730000 ioh ioh 4700 724007 dpy-4000 dpy-4000 4701 403223 add 3223 add \ssn 4702 663777 rcl 9s rcl 9s 4703 663777 rcl 9s rcl 9s 4704 423224 sub 3224 sub \scn 4705 663777 rcl 9s rcl 9s 4706 663777 rcl 9s rcl 9s 4707 730000 ioh ioh 4710 724007 dpy-4000 dpy-4000 4711 243237 dac 3237 dac \ssa 4712 323240 dio 3240 dio \ssi 4713 403235 add 3235 add \ssc 4714 663777 rcl 9s rcl 9s 4715 663777 rcl 9s rcl 9s 4716 423233 sub 3233 sub \csm 4717 663777 rcl 9s rcl 9s 4720 663777 rcl 9s rcl 9s 4721 730000 ioh ioh 4722 724007 dpy-4000 dpy-4000 4723 403223 add 3223 add \ssn 4724 663777 rcl 9s rcl 9s 4725 663777 rcl 9s rcl 9s 4726 423224 sub 3224 sub \scn 4727 663777 rcl 9s rcl 9s 4730 663777 rcl 9s rcl 9s 4731 730000 ioh ioh 4732 724007 dpy-4000 dpy-4000 4733 403235 add 3235 add \ssc 4734 663777 rcl 9s rcl 9s 4735 663777 rcl 9s rcl 9s 4736 423233 sub 3233 sub \csm 4737 663777 rcl 9s rcl 9s 4740 663777 rcl 9s rcl 9s 4741 730000 ioh ioh 4742 724007 dpy-4000 dpy-4000 4743 403223 add 3223 add \ssn 4744 663777 rcl 9s rcl 9s 4745 663777 rcl 9s rcl 9s 4746 423224 sub 3224 sub \scn 4747 663777 rcl 9s rcl 9s 4750 663777 rcl 9s rcl 9s 4751 730000 ioh ioh 4752 724007 dpy-4000 dpy-4000 4753 403235 add 3235 add \ssc 4754 663777 rcl 9s rcl 9s 4755 663777 rcl 9s rcl 9s 4756 423233 sub 3233 sub \csm 4757 663777 rcl 9s rcl 9s 4760 663777 rcl 9s rcl 9s 4761 730000 ioh ioh 4762 724007 dpy-4000 dpy-4000 4763 403223 add 3223 add \ssn 4764 663777 rcl 9s rcl 9s 4765 663777 rcl 9s rcl 9s 4766 423224 sub 3224 sub \scn 4767 663777 rcl 9s rcl 9s 4770 663777 rcl 9s rcl 9s 4771 730000 ioh ioh 4772 724007 dpy-4000 dpy-4000 4773 403223 add 3223 add \ssn 4774 663777 rcl 9s rcl 9s 4775 663777 rcl 9s rcl 9s 4776 423224 sub 3224 sub \scn 4777 663777 rcl 9s rcl 9s 5000 663777 rcl 9s rcl 9s 5001 730000 ioh ioh 5002 724007 dpy-4000 dpy-4000 5003 403223 add 3223 add \ssn 5004 663777 rcl 9s rcl 9s 5005 663777 rcl 9s rcl 9s 5006 423224 sub 3224 sub \scn 5007 663777 rcl 9s rcl 9s 5010 663777 rcl 9s rcl 9s 5011 730000 ioh ioh 5012 724007 dpy-4000 dpy-4000 5013 403223 add 3223 add \ssn 5014 663777 rcl 9s rcl 9s 5015 663777 rcl 9s rcl 9s 5016 423224 sub 3224 sub \scn 5017 663777 rcl 9s rcl 9s 5020 663777 rcl 9s rcl 9s 5021 730000 ioh ioh 5022 724007 dpy-4000 dpy-4000 5023 403223 add 3223 add \ssn 5024 663777 rcl 9s rcl 9s 5025 663777 rcl 9s rcl 9s 5026 423224 sub 3224 sub \scn 5027 663777 rcl 9s rcl 9s 5030 663777 rcl 9s rcl 9s 5031 730000 ioh ioh 5032 724007 dpy-4000 dpy-4000 5033 203237 lac 3237 lac \ssa 5034 223240 lio 3240 lio \ssi 5035 403223 add 3223 add \ssn 5036 663777 rcl 9s rcl 9s 5037 663777 rcl 9s rcl 9s 5040 423224 sub 3224 sub \scn 5041 663777 rcl 9s rcl 9s 5042 663777 rcl 9s rcl 9s 5043 730000 ioh ioh 5044 724007 dpy-4000 dpy-4000 5045 403223 add 3223 add \ssn 5046 663777 rcl 9s rcl 9s 5047 663777 rcl 9s rcl 9s 5050 423224 sub 3224 sub \scn 5051 663777 rcl 9s rcl 9s 5052 663777 rcl 9s rcl 9s 5053 730000 ioh ioh 5054 724007 dpy-4000 dpy-4000 5055 403236 add 3236 add \csn 5056 663777 rcl 9s rcl 9s 5057 663777 rcl 9s rcl 9s 5060 423234 sub 3234 sub \ssd 5061 663777 rcl 9s rcl 9s 5062 663777 rcl 9s rcl 9s 5063 730000 ioh ioh 5064 724007 dpy-4000 dpy-4000 5065 403223 add 3223 add \ssn 5066 663777 rcl 9s rcl 9s 5067 663777 rcl 9s rcl 9s 5070 423224 sub 3224 sub \scn 5071 663777 rcl 9s rcl 9s 5072 663777 rcl 9s rcl 9s 5073 730000 ioh ioh 5074 724007 dpy-4000 dpy-4000 5075 403223 add 3223 add \ssn 5076 663777 rcl 9s rcl 9s 5077 663777 rcl 9s rcl 9s 5100 423224 sub 3224 sub \scn 5101 663777 rcl 9s rcl 9s 5102 663777 rcl 9s rcl 9s 5103 730000 ioh ioh 5104 724007 dpy-4000 dpy-4000 5105 403223 add 3223 add \ssn 5106 663777 rcl 9s rcl 9s 5107 663777 rcl 9s rcl 9s 5110 423224 sub 3224 sub \scn 5111 663777 rcl 9s rcl 9s 5112 663777 rcl 9s rcl 9s 5113 730000 ioh ioh 5114 724007 dpy-4000 dpy-4000 5115 403223 add 3223 add \ssn 5116 663777 rcl 9s rcl 9s 5117 663777 rcl 9s rcl 9s 5120 423224 sub 3224 sub \scn 5121 663777 rcl 9s rcl 9s 5122 663777 rcl 9s rcl 9s 5123 730000 ioh ioh 5124 724007 dpy-4000 dpy-4000 5125 243237 dac 3237 dac \ssa 5126 323240 dio 3240 dio \ssi 5127 403235 add 3235 add \ssc 5130 663777 rcl 9s rcl 9s 5131 663777 rcl 9s rcl 9s 5132 423233 sub 3233 sub \csm 5133 663777 rcl 9s rcl 9s 5134 663777 rcl 9s rcl 9s 5135 730000 ioh ioh 5136 724007 dpy-4000 dpy-4000 5137 403235 add 3235 add \ssc 5140 663777 rcl 9s rcl 9s 5141 663777 rcl 9s rcl 9s 5142 423233 sub 3233 sub \csm 5143 663777 rcl 9s rcl 9s 5144 663777 rcl 9s rcl 9s 5145 730000 ioh ioh 5146 724007 dpy-4000 dpy-4000 5147 403235 add 3235 add \ssc 5150 663777 rcl 9s rcl 9s 5151 663777 rcl 9s rcl 9s 5152 423233 sub 3233 sub \csm 5153 663777 rcl 9s rcl 9s 5154 663777 rcl 9s rcl 9s 5155 730000 ioh ioh 5156 724007 dpy-4000 dpy-4000 5157 203237 lac 3237 lac \ssa 5160 223240 lio 3240 lio \ssi 5161 403236 add 3236 add \csn 5162 663777 rcl 9s rcl 9s 5163 663777 rcl 9s rcl 9s 5164 423234 sub 3234 sub \ssd 5165 663777 rcl 9s rcl 9s 5166 663777 rcl 9s rcl 9s 5167 730000 ioh ioh 5170 724007 dpy-4000 dpy-4000 5171 403223 add 3223 add \ssn 5172 663777 rcl 9s rcl 9s 5173 663777 rcl 9s rcl 9s 5174 423224 sub 3224 sub \scn 5175 663777 rcl 9s rcl 9s 5176 663777 rcl 9s rcl 9s 5177 730000 ioh ioh 5200 724007 dpy-4000 dpy-4000 5201 403223 add 3223 add \ssn 5202 663777 rcl 9s rcl 9s 5203 663777 rcl 9s rcl 9s 5204 423224 sub 3224 sub \scn 5205 663777 rcl 9s rcl 9s 5206 663777 rcl 9s rcl 9s 5207 730000 ioh ioh 5210 724007 dpy-4000 dpy-4000 5211 423231 sub 3231 sub \scm 5212 663777 rcl 9s rcl 9s 5213 663777 rcl 9s rcl 9s 5214 423232 sub 3232 sub \ssm 5215 663777 rcl 9s rcl 9s 5216 663777 rcl 9s rcl 9s 5217 730000 ioh ioh 5220 724007 dpy-4000 dpy-4000 5221 640005 szf 5 szf 5 5222 605226 jmp 5226 jmp . 4 5223 243225 dac 3225 dac \sx1 5224 323226 dio 3226 dio \sy1 5225 602531 jmp 2531 jmp sq6 5226 760005 clf 5 clf 5 5227 203231 lac 3231 lac \scm 5230 761000 cma cma 5231 243231 dac 3231 dac \scm 5232 203232 lac 3232 lac \ssm 5233 761000 cma cma 5234 243232 dac 3232 dac \ssm 5235 203233 lac 3233 lac \csm 5236 223234 lio 3234 lio \ssd 5237 243234 dac 3234 dac \ssd 5240 323233 dio 3233 dio \csm 5241 203235 lac 3235 lac \ssc 5242 223236 lio 3236 lio \csn 5243 243236 dac 3236 dac \csn 5244 323235 dio 3235 dio \ssc 5245 604527 jmp 4527 jmp c2m
The actual advance over the outline data for each of the spaceships can also be investigated in the illustration at the top of this page.
In case you would have cleared your internal program flag 5 and would be skipping this full loop, there's no more left, but to resort to a final "Stay tuned …"
Vienna, July 2014
www.masswerk.at
In case you would have found any errors or inconsistencies, or would have additional information,
please contact me.
*****
◀ Previous: Part 3: Objects!
▶ Next: Part 5: Maneuvering in Space
▲ Back to the index.