;
;	Disassembled by:
;		DASMx object code disassembler
;		(c) Copyright 1996-1999   Conquest Consultants
;		Version 1.30 (Oct  6 1999)
;
;	File:		capture.bin
;
;	Size:		2048 bytes
;	Checksum:	ED34
;	CRC-32:		AEB803E4
;
;	Date:		Thu Nov 07 11:31:02 2002
;
;	CPU:		Signetics 2650 (2650 family)
;
;$VER: 1.0 (14.11.2002)
;Disassembled by Amigan Software in November 2002.
;Please inform us of any errors found...
;URL:   http://amigan.1emu.net/
;EMail: amigansoftware@gmail.com
;
z     equ  0
eq    equ  z
p     equ  1
gt    equ  p
n     equ  2
lt    equ  n
un    equ  3
;
	org	00000H
;
        eorz    r0              ;r0 = 0;
        bctr,un BOOT            ;goto BOOT;
;
	db	017H
;
BOOT:
	lpsu
	lpsl
	ppsu	020H
	ppsl	002H
        lodi,r1 020H            ;r1 = $20;
BOOT_1:
;Clear memory from $18E0..$18FF (various system registers and user RAM)
        stra,r0 18DFh,r1        ;*($18DF + r1) = r0; // set current character line to 0
        bdrr,r1 BOOT_1          ;if (--r1 != 0) goto BOOT_1
        lodi,r1 011H            ;r1 = %00001011;
        stra,r1 18E0h           ;*(18E0) = r1 [$11]; // set character '1' as level number, unlimited time
        lodi,r1 000H            ;r1 = $0;
BOOT_2:
;Clear memory from $1900..$19FF (various system registers)
        stra,r0 18FFh,r1        ;*($18FF + r1) = r0 [$0];
        bdrr,r1 BOOT_2          ;if (--r1 != 0) goto BOOT_2;
        stra,r0 19F8h           ;*($19F8) = r0 [$0]; // clear low-res bit
        lodi,r0 008H            ;r0 = $8;
        stra,r0 19F9h           ;*($19F9) = r0 [$8];
;set background colour to 0 (white), tile 0 colour to 1 (yellow)
        lodi,r1 028H            ;r1 = $28; // iterations of loop
BOOT_3:
;Set up user-defined characters
        loda,r0 07D2h,r1        ;r0 = *($7D2 + r1); // ROM area
        stra,r0 1997h,r1        ;*($1997 + r1) = r0; // user defined characters
        bdrr,r1 BOOT_3          ;if (--r1 != 0) goto BOOT_3;
;That was code that is only ever used to boot
;Now we are at the point of the title screen
TITLESCREEN:
;Level and 'difficulty' (set time) might have been changed;
;eg. level is not necessary 1
        eorz    r0              ;r0 = 0;
        stra,r0 1ACBh           ;*($1ACB) = r0 [0]; // user RAM
        lodi,r1 0E0H            ;r1 = $E0; // loop iterator
TITLESCREEN_1:
;clear entire display ($1800..$18CF)
;and clear user RAM ($18D0..$18DF and $1A00..$1ADF)
        stra,r0 17FFh,r1        ;*($17FF + r1) = r0; // (mostly) screen display (r1 % 16,r1 / 16)
        stra,r0 19FFh,r1        ;*($19FF + r1) = r0; // user RAM
        bdrr,r1 TITLESCREEN_1   ;if (--r1 != 0) goto TITLESCREEN_1;
        stra,r1 18FDh           ;*($18FD) = r1 [0]; // sound pitch, etc.
        stra,r1 18F6h           ;*($18F6) = r1 [0]; // sprite coordinates, etc.
        lodi,r0 002H            ;r0 = $2;
;set sprite 2 to colour 0, sprite 3 to colour 2, both non-doublescanned
        stra,r0 19FAh           ;*($19FA) = r0 [$2];
        lodi,r0 0EDH            ;r0 = $ED;
        stra,r0 18FCh           ;*($18FC) = r0 [$ED]; // set crtc vertical position register
TITLELOOP:
        bsta,un WAIT            ;gosub WAIT;
        lodi,r1 005H            ;r1 = $5;
setup_1:
;print "LEVEL"
        loda,r0 0784h,r1        ;r0 = *($784 + r1); // ROM area
        stra,r0 1814h,r1        ;*(1814 + r1) = r0; // upper screen display (5..9, 1)
        bdrr,r1 setup_1         ;if (--r1 != 0) goto setup_1;
        lodi,r1 008H            ;r1 = $8;
TITLELOOP_2:
;print "SET TIME"
        loda,r0 077Ch,r1        ;r0 = *($77C + r1); // ROM area
        stra,r0 1843h,r1        ;*($1843 + r1) = r0; // upper screen display
        bdrr,r1 TITLELOOP_2     ;if (--r1 != 0) goto TITLELOOP_2;
        lodi,r1 007H            ;r1 = $7; // loop iterator (loop 7 times)
TITLELOOP_3:
;print "CAPTURE"
        loda,r0 078Eh,r1        ;r0 = *($78E + r1); // ROM area
        stra,r0 1884h,r1        ;*($1884 + r1) = r0; // upper screen display
        bdrr,r1 TITLELOOP_3     ;if (--r1 != 0) goto TITLELOOP_3;
;end of loop
;get level from user ram ($18E0) (ROM locations $96..$97 hold $18E0), put into r0
        lodr,r0 *0096h          ;r0 = *(96);
        bsta,un MAKEDIGITS      ;gosub MAKEDIGITS;
;Print level number
        stra,r0 181Bh           ;*($181B) = r0; // upper screen display
        bsta,un TIME            ;gosub TIME;
        loda,r0 18E0h           ;r0 = *(18E0); // get level from user RAM
        andi,r0 002H            ;r0 &= %00000010; // extract bit 1 ('limited time' bit)
        bcfr,eq TITLELOOP_5     ;if (!=) goto TITLELOOP_5; // if set then skip clearing "SET TIME", etc.
        lodi,r1 020H            ;r1 = $20; // loop iterator (loop $20 (32) times)
TITLELOOP_4:
;unlimited time, so clear the "TIME" and "SET TIME" message lines
        stra,r0 182Fh,r1        ;*(182F + r1) = r0;
        bdrr,r1 TITLELOOP_4     ;if (--r1 != 0) goto TITLELOOP_4;
;end of loop
        bctr,un TITLELOOP_10    ;goto TITLELOOP_10; // skip forwards
TITLELOOP_5:
;get the monotonic incrementor
        loda,r0 18D5h           ;r0 = *(18D5); // get a value from user RAM
        andi,r0 00FH            ;r0 &= %00001111; // extract low nybble
        bctr,gt TITLELOOP_10    ;if (>) goto TITLELOOP_10;
;if incrementor is an even multiple of 16
;in other words, once every 16 times
        bsta,un READKEYS        ;gosub READKEYS;
        lodi,r1 004H            ;r1 = $4;
        loda,r0 18E0h           ;r0 = *(18E0); // get level variable
;if level is 6 (ie. 2-player mode) and limited time
        comi,r0 062H            ;compare r0 with %01100010
;if so then check p2's input
        bctr,eq TITLELOOP_6     ;if (==) goto TITLELOOP_6; // goto TITLELOOP_6 with r1 = $4
;else (if not)
        lodi,r0 003H            ;r0 = $3;
        stra,r0 1ACBh           ;*($1ACB) = r0 [$3];
;change to player 1
        rrr,r1                  ;rotate r1 to the right once (r1 = [$2])
TITLELOOP_6:
;Up   to decrease seconds, down  to increase seconds
;Left to decrease minutes, right to increase minutes
;minutes/seconds are in BCD format
;(ie. highest nybble and lowest nybble are separate digits)
;when r1 = 4, checking p2's left/right, interested in minutes
;when r1 = 3, checking p2's up  /down,  interested in seconds
;when r1 = 2, checking p1's left/right, interested in minutes
;when r1 = 1, checking p1's up  /down,  interested in seconds
;get status we are interested in
        loda,r0 1ABFh,r1        ;r0 = *(1ABF + r1); // $1AC0..$1AC3
;if not less than zero (ie. user not holding left/up)
        bcfr,lt TITLELOOP_7         ;if (!(<)) goto TITLELOOP_7;
        lodi,r0 099H            ;r0 = $99;
TITLELOOP_7:
;r0 is $99, $0 or $1 depending on buttons
;($99 is up/left, $0 is centred, $1 is down/right)
;change to $FF, $66, or $67
        addi,r0 066H            ;r0 += $66;
;add this to the current value
        adda,r0 1AC8h,r1        ;r0 += *(1AC8 + r1); // user RAM
;see the 2650 User Manual p. 89 for information about the DAR opcode,
;but basically, $66 is subtracted
        dar,r0                  ;decimal adjust r0
;if going from 59 minutes to 60 minutes
        comi,r0 060H            ;compare r0 against $60
        bctr,eq TITLELOOP_8         ;if (==) then goto TITLELOOP_8; // set minutes to zero
;else if going from 0 minutes to 99 minutes
        comi,r0 099H            ;compare r0 against $99
        bcfr,eq TITLELOOP_9         ;if (!=) then goto TITLELOOP_9; // done checking minutes
        lodi,r0 059H            ;r0 = $59; // set minutes to 59
        bctr,un TITLELOOP_9         ;goto TITLELOOP_9; // skip setting this to zero
TITLELOOP_8:
;set minutes to zero
        eorz    r0              ;r0 = 0;
TITLELOOP_9:
;store time for this player in user variables RAM
        stra,r0 1AC8h,r1        ;*(1AC8 + r1) = r0;
;done checking this player/direction
;go to next direction and/or player
        bdrr,r1 TITLELOOP_6     ;if (--r1 != 0) goto TITLELOOP_6;
TITLELOOP_10:
;check console buttons
        bsta,un BUTTONS         ;gosub BUTTONS;
;if user didn't press START
        bcfa,eq TITLELOOP       ;if (!=) goto TITLELOOP;
;user pressed START, begin new game
NEWGAME:
        lodi,r1 004H            ;r1 = $4;
NEWGAME_1:
;restore time values
;copy allowed time ($1AC9..$1ACC) to $1AC5..$1AC8 and also to $18EB..$18EE
        loda,r0 1AC8h,r1        ;r0 = *($1AC8 + r1);
        stra,r0 1AC4h,r1        ;*($1AC4 + r1) = r0;
        stra,r0 18EAh,r1        ;*($18EA + r1) = r0;
        eorz    r0              ;r0 = 0;
;clear $1AC9..$1ACC
        stra,r0 1AC8h,r1        ;*($1AC8 + r1) = r0 [0];
        bdrr,r1 NEWGAME_1       ;if (--r1 != 0) goto NEWGAME_1; // if p2, now do p1
        lodi,r1 0C5H            ;r1 = $C5;
NEWGAME_2:
;clear $1800..$18CF (display memory)
;in other words, clear the entire display except for $18C5..$18CF (part of bottom line)
        stra,r0 17FFh,r1        ;($17FF + r1) = r0; // display memory
;also clear some user memory
        stra,r0 19FFh,r1        ;($19FF + r1) = r0; // user RAM
        bdrr,r1 NEWGAME_2       ;if (--r1 != 0) goto NEWGAME_2;
;end of loop
        bsta,un CLEARLINE       ;gosub CLEARLINE;
;add scores together
        loda,r0 18E1h           ;r0 = *($18E1); // user RAM (player 1's score)
        adda,r0 18E6h           ;r0 += *($18E6); // user RAM (player 2's score)
        comi,r0 008H            ;compare r0 against $8
;if the scores added together aren't at least 8
;(ie. less than 8 filled squares on the screen),
;don't bother adding that game to last-games list
        bctr,lt NEWGAME_4       ;if (<) goto NEWGAME_4; // if less than 8
        lodi,r1 004H            ;r1 = $4;
NEWGAME_3:
;push down the old scores, insert the new scores
;copy from $18E1..$18E4 to $18E2..$18E5, in reverse order (overlapping copy)
;and  from $18E6..$18E9 to $18E7..$18EA, in reverse order (overlapping copy)
        loda,r0 18E0h,r1        ;r0 = *($18E0 + r1); // user RAM
        stra,r0 18E1h,r1        ;*($18E1 + r1) = r0; // user RAM
        loda,r0 18E5h,r1        ;r0 = *($18E5 + r1); // user RAM
        stra,r0 18E6h,r1        ;*($18E6 + r1) = r0; // user RAM
        bdrr,r1 NEWGAME_3       ;if (--r1 != 0) goto NEWGAME_3;
NEWGAME_4:
;board is drawn right-to-left, bottom-to-top of screen
        lodi,r2 078H            ;r2 = $78; // offset into display memory
        lodi,r0 07CH            ;r0 = $7C; // empty board symbol
NEWGAME_5:
        lodi,r3 008H            ;r3 = $8; // inner loop iterator
NEWGAME_6:
;draw a row of $7C (UDC #4) (empty board symbol)
        stra,r0 1843h,r2        ;*(1843 + r2) = r0; // display memory
        addi,r2 0FFH            ;r2 += $FF [-1]; // subtract 1 from r2 (one x-square)
        bdrr,r3 NEWGAME_6       ;if (--r3 != 0) goto NEWGAME_6;
        addi,r2 0F8H            ;r2 += $F8 [-8]; // subtract 8 from r2 (one y-square)
        bctr,gt NEWGAME_5       ;if (>) goto NEWGAME_5;
;board now completely drawn
;now put two starting counters on board for each player
        lodi,r0 0BEH            ;r0 = $BE; // $BE is player 2's symbol (UDC #6) ($3E, but in red so +$80)
        stra,r0 1877h           ;*($1877) = r0 [$BE]; // screen
        stra,r0 1888h           ;*($1888) = r0 [$BE]; // screen
        lodi,r0 0FDH            ;r0 = $FD; // $FD is player 1's symbol (UDC #5) ($3D, but in black so +$C0)
        stra,r0 1878h           ;*($1878) = r0 [$FD]; // screen
        stra,r0 1887h           ;*($1887) = r0 [$FD]; // screen
        lodi,r1 005H            ;r1 = $5; // loop iterator
NEWGAME_7:
;print "SCORE"
        loda,r0 0789h,r1        ;r0 = *($789 + r1); // ROM area
        stra,r0 1805h,r1        ;*($1805 + r1) = r0; // upper screen display
        bdrr,r1 NEWGAME_7       ;if (--r1 != 0) goto NEWGAME_7;
        lodi,r0 0FDH            ;r0 = $FD; // player 1's symbol
;draw player 1's symbol
        stra,r0 1812h           ;*($1812) = r0 [$FD]; // screen
        lodi,r0 0BEH            ;r0 = $BE; // player 2's symbol
;draw player 2's symbol
        stra,r0 181Dh           ;*($181D) = r0 [$BE]; // upper screen display
        lodi,r3 000H            ;r3 = $0;
;get level from user ram ($18E0) (ROM locations $172..$173 hold $18E0), put into r1
        lodr,r1 *0172h          ;r1 = *(172); // get value at user RAM $18E0 through pointer at ROM $172, put into r1
        andi,r1 0F0H            ;r1 &= %11110000; // extract high nybble of r1 (level nybble)
;now we have the level in r1
        comi,r1 060H            ;compare r1 with %01100000 (test the extracted nybble against $6)
;if level is 6 (ie. 2-player mode)
        bctr,eq LASTSCORES     ;if (==) goto LASTSCORES; // if both bits are clear
NEWGAME_8:
;put p2's extra counters on the board
;decrement level by 1
        subi,r1 010H            ;r1 -= %00010000;
;if zero then we are done, skip ahead
        bctr,eq LASTSCORES     ;if (==) goto LASTSCORES; // if r1 is zero
;look up the relevant coordinate in $7B7..$7BA (ROM constants area)
        loda,r0 07B6h,r3+       ;r0 = *(7B6 + ++r3); // ROM area
        strz    r2              ;r2 = r0;
        lodi,r0 0BEH            ;r0 = $BE;
;now put one of p2's counters at location (r2 % 16,r2 / 16)
        stra,r0 1844h,r2        ;*($1844 + r2) = r0 [$BE]; // screen display
        bctr,un NEWGAME_8       ;goto NEWGAME_8;
;end of loop
LASTSCORES:
;prints the last (previous) 4 scores of each player
;if limited time, also prints the allowed time for each player
        bsta,un SCORES          ;gosub SCORES;
        lodi,r2 030H            ;r2 = $30; // r2 will be $30, $20, $10, then $0
        lodi,r3 004H            ;r3 = $4; // loop iterator
LASTSCORES_1:
;get number for p1
        loda,r0 18E1h,r3        ;r0 = *($18E1 + r3); // user RAM
        bstr,un *0164h          ;gosub *(164); // gosub to $713 (MAKEDIGITS)
                                ;INFO: indirect jump
;r0 is holding column  0 digit
;r1 is holding column  1 digit
        stra,r0 1860h,r2        ;*(1860 + r2) = r0; // draw number in column 0
        lodz    r1              ;r0 = r1;
        stra,r0 1861h,r2        ;*(1861 + r2) = r0; // draw number in column 1
;get number for p2
        loda,r0 18E6h,r3        ;r0 = *($18E6 + r3); // upper screen display
        bsta,un MAKEDIGITS      ;gosub MAKEDIGITS;
;r0 is holding column 14 digit
;r1 is holding column 15 digit
        stra,r0 186Eh,r2        ;*(186E + r2) = r0; // draw number in column 14
        lodz    r1              ;r0 = r1;
        stra,r0 186Fh,r2        ;*(186F + r2) = r0; // draw number in column 15
        subi,r2 010H            ;r2 -= $10; // go up by one y-line for the next iteration
;numbers are drawn from bottom to top of screen
        bdrr,r3 LASTSCORES_1    ;if (--r3 != 0) goto LASTSCORES_1;
;end of loop
        loda,r0 18E0h           ;r0 = *(18E0);
;check 'limited time' flag
        andi,r0 002H            ;r0 &= %00000010;
;if not timed, skip ahead
        bctr,eq MAINLOOP        ;if (==) goto MAINLOOP; // if bit 1 is clear
        loda,r0 07C7h           ;r0 = *(7C7); // grab $07 from ROM constants area, put into r0
        loda,r1 07C8h           ;r1 = *(7C8); // grab $C9 from ROM constants area, put into r1
;print the upper time (allowed time)
        bsta,un SHOWTIME        ;gosub SHOWTIME;
;print the upper colons (:) onto the screen
        lodi,r0 0FFH            ;r0 = $FF; // $FF is black UDC #7 (:)
        stra,r0 1822h           ;*(1822) = r0 [$FF]; // screen display
        stra,r0 182Dh           ;*(182D) = r0 [$FF]; // screen display
;Main game loop
MAINLOOP:
        bsta,un DRAWSPRITE      ;gosub DRAWSPRITE;
MAINLOOP_1:
        bsta,un OFTEN           ;gosub OFTEN;
;the monotonic incrementor is in r1 at this point
        andi,r1 00FH            ;r1 &= %00001111; // test low nybble
;if an even multiple of 16, go ahead and read the keys, etc.
        bctr,eq MAINLOOP_2      ;if (==) goto MAINLOOP_2;
        andi,r1 007H            ;r1 &= %00000111;
;else if not an even multiple of 8, go back to start
        bcfr,eq MAINLOOP_1      ;if (!=) goto MAINLOOP_1;
;else it is an even multiple of 8 (but not of 16)
        bsta,un CLEARSPRITE     ;gosub CLEARSPRITE;
        bctr,un MAINLOOP_1      ;goto MAINLOOP_1;
;end of main input loop
MAINLOOP_2:
        bsta,un READKEYS        ;gosub READKEYS;
;set for player 1
        lodi,r1 080H            ;r1 = $80;
;get current player from user ram ($1A27) (ROM locations $1D6..$1D7 hold $1A27), put into r2
        lodr,r2 *01D6h          ;r2 = *(1D6);
;if current player is 1, skip forwards
        bctr,eq MAINLOOP_3      ;if (==) goto MAINLOOP_3;
;else set for player 2
        lodi,r1 040H            ;r1 = $40;
MAINLOOP_3:
;extract the firebutton bit for the player we are interested in
        andz    r1              ;r0 &= r1;
        bctr,eq MAINLOOP_7      ;if (==) goto MAINLOOP_7; // if zero (ie. no bits shared between r0 and r1)
;firebutton was pressed
        lodi,r0 02EH            ;r0 = $2E; // high note (F#5)
        bsta,un PLAYNOTE        ;gosub PLAYNOTE;
;get cursor position from user ram ($18DE) (ROM locations $1D0..$1D1 hold $18DE), put into r1
        lodr,r1 *01D0h          ;r1 = *(1D0);
        loda,r0 1844h,r1        ;r0 = *(1844 + r1); // look at screen at cursor position
;check whether the square is empty
        comi,r0 07CH            ;compare r0 against $7C (UDC #4, or in other words, the empty board symbol)
;if square doesn't already have a counter in it
        bctr,eq MAINLOOP_6      ;if (==) goto MAINLOOP_6;
MAINLOOP_4:
;illegal move handler
        bsta,un CLEARLINE       ;gosub CLEARLINE;
        lodi,r1 005H            ;r1 = $5; // loop iterator (loop quince)
MAINLOOP_5:
;print "ERROR"
        loda,r0 0795h,r1        ;r1 = *(795 + r1);
        stra,r0 18C5h,r1        ;*(18C5 + r1) = r0;
        bdrr,r1 MAINLOOP_5      ;if (--r1 != 0) goto MAINLOOP_5;
        bctr,un MAINLOOP_1      ;goto MAINLOOP_1;
MAINLOOP_6:
        bsta,un CLEARSPRITE     ;gosub CLEARSPRITE;
        bstr,un MOVED           ;gosub MOVED;
        bcta,un LASTSCORES      ;goto LASTSCORES;
MAINLOOP_7:
;a player wants to move the cursor
        loda,r0 18DEh           ;r0 = *(18DE);
;copy current cursor position into $18DF (old cursor position)
        stra,r0 18DFh           ;*(18DF) = r0;
;put current player into r1
        loda,r1 1A27h           ;r1 = *(1A27);
;r0 is *(1AC0) for p1 or *(1AC2) for p2
;in other words, r0 is left/right controller status for the current player
        adda,r0 1AC0h,r1        ;r0 += *(1AC0 + r1);
        andi,r0 007H            ;r0 &= %00000111;
;r0 is now $7 for left, $1 for right, $0 for centered
        strz    r2              ;r2 = r0;
;copy into r2
;r0 is *(1AC1) for p1 or *(1AC3) for p2
;in other words, r0 is up/down controller status for the current player
        loda,r0 1AC1h,r1        ;r0 = *(1AC1 + r1);
        rrl,r0                  ;rotate r0 to the left quarce...
        rrl,r0                  ;(swaps nybbles)...
        rrl,r0                  ;...
        rrl,r0                  ;...
;r0 is now $FF for up, $10 for down, $0 for centered
        andi,r0 0F0H            ;r0 &= $11110000; // extract y-coords
;r0 is now $F0 for up (-16), $10 (+16) for down, $0 for centered
;(in other words, the delta (0,-1), (+1,0) or (0,0)
;put new board coords (only y is actually new, x is still old) into r0
        addr,r0 *01D0h          ;r0 += *(*(1D0)); // r0 += *(18DE);
;extract y-coord from new board coords (clear x-coord)
        andi,r0 070H            ;r0 &= $01110000; // extract bits 6..4
;set x-coord to new x-coord
        addz    r2              ;r0 += r2;
;update cursor position variable in RAM
        strr,r0 *01D0h          ;*(*(1D0)) = r0; // copy r0 to RAM area ($18DE) pointed to at ROM location $1D0
;get the delta of the move which was just made
        subr,r0 *01D3h          ;r0 -= *(*(1D3)); // r0 -= *(18DF);
;if it was zero (ie. we didn't move) then we are done
        bctr,eq *01FAh          ;INFO: indirect jump
                                ;goto *(1FA); // goto to $189 (MAINLOOP)
;otherwise we did move, so clear the line and play a note, then we are done
        bstr,un *01B9h          ;INFO: indirect jump
                                ;gosub *(1B9); // gosub to $578 (CLEARLINE)
;play cursor movement note
        lodi,r0 008H            ;r0 = $8; // desired pitch is $8
        bsta,un PLAYNOTE        ;gosub PLAYNOTE;
        bcta,un MAINLOOP        ;goto MAINLOOP;
;Subroutine---------------------------------------------------------------
MOVED:
;called when the player has pressed fire
        lodi,r1 002H            ;r1 = $2; // means player 2
;get current player from user ram ($1A27) (ROM locations $1D6..$1D7 hold $1A27), put into r2
        lodr,r2 *01D6h          ;r2 = *(1D6);
;copy *(1A27) (current player) into $1A20 (current thinking player)
        stra,r2 1A20h           ;*(1A20) = r2;
;if player 1's turn
        bctr,eq MOVED_1         ;if (==) goto MOVED_1;
        lodi,r1 000H            ;r1 = $0; // means player 1
MOVED_1:
;r1: other   thinking player (0 or 2)
;r2: current thinking player (0 or 2)
        strr,r1 *0236h          ;*(*(236)) = r1; // copy r1 to user RAM ($1A21) pointed to at ROM location $236
        lodi,r3 0BEH            ;r3 = $BE; // player 2 symbol
        lodi,r1 0FDH            ;r1 = $FD; // player 1 symbol
        lodz    r2              ;r0 = r2;
;if player 1, skip ahead
        bctr,eq MOVED_2         ;if (==) goto MOVED_2;
        lodi,r3 0FDH            ;r3 = $FD; // player 1 symbol
        lodi,r1 0BEH            ;r1 = $BE; // player 2 symbol
MOVED_2:
;human move
;r0, r2: current player (0 or 2)
;r1:     symbol of the current player
;r3:     symbol of the other   player
;update variables in RAM
        strr,r1 *024Bh          ;*(*(24B)) = r1; // copy r1 to user RAM ($1A22) pointed to at ROM location $24B
        stra,r3 1A23h           ;*(1A23) = r3;
;copy cursor position from $18DE into $1A28 for FLIP
        loda,r1 18DEh           ;r1 = *(18DE);
        stra,r1 1A28h           ;*(1A28) = r1;
        eorz    r0              ;r0 = 0;
;clear mode1 and mode2 flags for FLIP
        stra,r0 1A3Bh           ;*(1A3B) = r0 [0]; // set mode2 to 'real board'
        stra,r0 1AC4h           ;*(1AC4) = r0 [0]; // set mode1 to 'pretend move'
;call FLIP to do a pretend move on the real board (to check validity of move)
        bstr,un *0233h          ;gosub *(233); // gosub to $35F (FLIP)
                                ;INFO: indirect jump
        comi,r0 000H            ;compare r0 against $0
;if illegal move (no flips possible with that move)
        bcta,eq MAINLOOP_4      ;if (==) goto MAINLOOP_4;
;valid move
        lodi,r0 001H            ;r0 = $1;
        stra,r0 1AC4h           ;*(1AC4) = r0 [$1]; // set mode1 to 'real move'
;*(1A28) and *(1A3B) are always still 0 and *(18DE) respectively at this point
;call FLIP to do a real move on the real board
        bsta,un FLIP            ;gosub FLIP;
;copy $1A21 (other thinking player) to $1A27 (current player)
        loda,r2 1A21h           ;r2 = *(1A21);
        strr,r2 *025Fh          ;*(*(25F)) = r2; // copy r2 to user RAM ($1A27) pointed to at ROM location $25F
;compare level nybble to 6 (ie. check whether 2-player mode)
        loda,r0 18E0h           ;r0 = *(18E0);
        tmi,r0  060H            ;test bits of (r0 & %01100000)
        bcfr,eq MOVED_5         ;if (!=) goto MOVED_5;
;we are in 1-player mode
        bsta,un CHECKFORFEIT    ;gosub CHECKFORFEIT;
;if best coords are still (-1,-1), forfeit
        loda,r0 1A24h           ;r0 = *(1A24);
        bctr,lt MOVED_3         ;if (<) goto MOVED_3;
        retc,un                 ;return;
MOVED_3:
;copy value of $1A22 (current player's symbol) into $18C1 (display memory)
        loda,r0 1A22h           ;r0 = *(1A22);
        stra,r0 18C1h           ;*(18C1) = r0;
        lodi,r2 00CH            ;r2 = $C; // loop iterator (loop 12 times)
MOVED_4:
;copy $79B..$7A6 ("FORFEIT MOVE") to $18C3..$18CE (screen)
        loda,r0 079Ah,r2        ;r0 = *(79A + r2);
        stra,r0 18C2h,r2        ;*(18C2 + r2) = r0;
        bdrr,r2 MOVED_4         ;if (--r2 != 0) goto MOVED_4;
;end of loop
;change current player and return to caller
;get current player from user ram ($1A27) (ROM locations $25F..$260 hold $1A27), put into r2
        lodr,r2 *025Fh          ;r2 = *(*(25F));
        eori,r2 002H            ;Exclusive OR r2 with %00000010; // change player
        stra,r2 1A27h           ;*(1A27) = r2;
        bcta,un MOVED_15        ;goto MOVED_15;
MOVED_5:
;CHECKFORFEIT calls this section directly
;r2 is passed with the current player
;store current player at $1A20 (current thinking player)
        stra,r2 1A20h           ;*(1A20) = r2;
;change current player (0 becomes 2 or 2 becomes 0)
        eori,r2 002H            ;Exclusive OR r2 with %00000010
        strr,r2 *0236h          ;*(*(236)) = r2; // copy r2 to user RAM ($1A27) pointed to at ROM location $236
;get current player's symbol from user ram ($1A22) (ROM locations $24B..$2FC hold $1A22), put into r1
        lodr,r1 *024Bh          ;r1 = *(24B);
;get other player's symbol from user ram ($1A23) (ROM locations $270..$271 hold $1A23), put into r2
        lodr,r2 *0270h          ;r2 = *(270);
;swap $1A22 with $1A23 (in other words, swap symbols)
        stra,r1 1A23h           ;*(A123) = r1;
        strr,r2 *024Bh          ;*(*(24B)) = r2; // copy r2 to user RAM ($1A22) pointed to at ROM location $24B
        bsta,un SCORES          ;gosub SCORES;
;swap players and update SCORES
MOVED_6:
;artificial intelligence
        eorz    r0              ;r0 = 0;
        strz    r2              ;r2 = r0 [0]; // useless!
;set AI coordinates (at $1A26) to (0,0)
        strr,r0 *02A2h          ;*(*(2A2)) = r0 [0]; // copy r0 [0] to user RAM ($1A26) pointed to at ROM location $2A2
;clear contents of $1A25 (best worth)
        stra,r0 1A25h           ;*(1A25) = r0 [0];
        lodi,r0 0FFH            ;r0 = $FF;
;set best coords to (-1,-1)
;set contents of $1A24 to $FF (-1,-1)
        stra,r0 1A24h           ;*(1A24) = r0 [$FF];
MOVED_7:
;goes through each square on the board
;jumps to MOVED_10 when an empty square is found
;jumps to MOVED_14 when all squares have been checked
;get AI coordinates from user ram ($1A26) (ROM locations $2A2..$2A3 hold $1A26), put into r2
        lodr,r2 *02A2h          ;r2 = *(2A2);
        loda,r0 1844h,r2        ;r0 = *(1844 + r2);
;look here
        comi,r0 07CH            ;compare r0 against $7C (empty board symbol)
;if empty then skip ahead
        bctr,eq MOVED_10        ;if (==) goto MOVED_10;
MOVED_8:
;get AI coordinates from user ram ($1A26) (ROM locations $2A2..$2A3 hold $1A26), put into r2
        lodr,r2 *02A2h          ;r2 = *(2A2);
;test x-coordinate
        tmi,r2  007H            ;test bits of (r2 & $00000111) // test bits 2..0 of r2
;TMI tests the bits specified in the operand against the specified register
;if x-coord is 7, skip forwards
        bctr,eq MOVED_9         ;if (==) goto MOVED_9;
;increment x-coords by 1, leave y-coord alone
        addi,r2 001H            ;r2++;
;store changed AI coords back into RAM
        strr,r2 *02A2h          ;*(*(2A2)) = r2; // copy r2 to user RAM ($1A26) pointed to at ROM location $2A2
        bctr,un MOVED_7         ;goto MOVED_7;
;end of loop
MOVED_9:
;x is 7
;test whether 7 is also 7
        tmi,r2  077H            ;test bits of (r2 & %01110111) // test bits 6..4 and 2..0 of r2
;if x- and y-coords are both 7, we are done
        bcta,eq MOVED_14        ;if (==) goto MOVED_14;
;otherwise (else)
;extract the y-coord, set x-coord to 0
        andi,r2 070H            ;r2 &= %01110000;
;increment y-coord by 1, leave x-coord as 0
        addi,r2 010H            ;r2 += %00010000;
;store changed AI coords back into RAM
        stra,r2 1A26h           ;*(1A26) = r2;
;go back to increasing the x-values (ie. do next row)
        bctr,un MOVED_7         ;goto MOVED_7;
MOVED_10:
;board is empty at this position
;do a pretend move here and see how many counters would be flipped
;set up arguments for FLIP
        eorz    r0              ;r0 = 0;
        stra,r0 1AC4h           ;*(1AC4) = r0 [0]; // set mode1 to 'pretend move'
        stra,r2 1A28h           ;*(1A28) = r2;
;call FLIP to do a pretend move on the real board
        bsta,un FLIP            ;gosub FLIP;
        comi,r0 000H            ;compare r0 against $0
;if that move wouldn't flip any counters
        bctr,eq MOVED_8         ;if (==) goto MOVED_8;
;otherwise put how many counters it would flip into $18D1
        stra,r0 18D1h           ;*(18D1) = r0;
        lodi,r3 004H            ;r3 = $4; // loop iterator (loop quarce)
;we want to look at each of the four corners in turn
        lodi,r2 000H            ;r2 = $0;
MOVED_11:
        loda,r0 07B6h,r2+       ;r0 = *(7B6 + ++r2);
;compare corner coordinates against *(1A26) (AI coordinate)
        comr,r0 *02A2h          ;compare r0 against *(*(2A2))
;if we are looking at a corner
        bcta,eq MOVED_13        ;if (==) goto MOVED_13;
        bdrr,r3 MOVED_11        ;if (--r3 != 0) goto MOVED_11;
;end of loop
;this is not a corner
;get how many counters it would flip
        loda,r0 18D1h           ;r0 = *(18D1);
;get AI coordinates from user ram ($1A26) (ROM locations $2A2..$2A3 hold $1A26), put into r2
        lodr,r2 *02A2h          ;r2 = *(2A2);
        andi,r2 070H            ;r2 &= %01110000; // extract y-coord
        rrr,r2                  ;rotate r2 to the right quarce...
        rrr,r2                  ;...
        rrr,r2                  ;...
        rrr,r2                  ;...
;now y-coord is in the lower nybble of r2, upper nybble is clear
;check the intrinsic worth of this y-coord (intrinsic worth of this row)
;add y-worth to r0
        adda,r0 07A7h,r2        ;r0 += *(7A7 + r2);
;get AI coords from user ram ($1A26) (ROM locations $2A2..$2A3 hold $1A26), put into r2
        lodr,r2 *02A2h          ;r2 = *(2A2);
        andi,r2 007H            ;r2 &= %00000111; // extract x-coord
;now x-coord is in the lower nybble of r2, upper nybble is clear
;check the intrinsic worth of this x-coord (intrinsic worth of this column)
;add x-worth to r0
        adda,r0 07A7h,r2        ;r0 += *(7A7 + r2);
;add 48 to r0
        addi,r0 030H            ;r0 += 48;
;so r0 is:
;   intrinsic worth of row (0..4)
; + instrinsic worth of column (0..4)
; + number of counters that would be flipped
; + 48
;if called by CHECKFORFEIT, skip forwards
        loda,r1 1A2Dh           ;r1 = *(1A2D);
        bcfr,eq MOVED_12        ;if (!=) goto MOVED_12;
;otherwise
        lodi,r1 001H            ;r1 = $1;
        bsta,un THINK           ;gosub THINK;
MOVED_12:
;check whether the move we just considered is the best found so far
        coma,r0 1A25h           ;compare r0 against *(1A25)
;if not the best, try next coord
        bcfr,gt *02F5h          ;goto *(2F5); // goto $28C (MOVED_8)
                                ;INFO: indirect jump
;if the best
;store this worth as the best worth
        stra,r0 1A25h           ;*(1A25) = r0;
;copy from $1A26 (AI coordinates) to $1A24 (best coords, or coords of best move)
        loda,r2 1A26h           ;r2 = *(1A26); // AI coords
        stra,r2 1A24h           ;*(1A24) = r2;
        bcta,un MOVED_8         ;goto MOVED_8;
MOVED_13:
;we found a corner
;r0 is the move which is under consideration
;set best coords to this
        stra,r0 1A24h           ;*(1A24) = r0;
MOVED_14:
;we are done
;if called by CHECKFORFEIT, return there
        loda,r0 1A2Dh           ;r0 = *(1A2D);
        retc,gt                 ;if (>) return;
;otherwise
;get best coords from user ram ($1A24) (ROM locations $2F8..$2F9 hold $1A24), put into r0
        lodr,r0 *02F8h          ;r0 = *(2F8);
;if best coords are still (-1,-1) then forfeit
        bcta,lt MOVED_3         ;if (<) goto MOVED_3;
;get ready to call FLIP
        lodi,r0 001H            ;r0 = $1;
        stra,r0 1AC4h           ;*(1AC4) = r0 [$1]; // set mode1 to 1 (real move)
;get AI coords from user ram ($1A26) (ROM locations $2A2..$2A3 hold $1A26), put into r2
        lodr,r0 *02F8h          ;r0 = *(2F8);
;set user cursor position to wherever the console is moving
        stra,r0 18DEh           ;*(18DE) = r0;
        stra,r0 1A28h           ;*(1A28) = r0;
;mode2 is set to $0 by THINK
;call FLIP to do the console's real move on the real board, at coord *(1A28)
        bsta,un FLIP            ;gosub FLIP;
;copy $1A21 (other thinking player) into $1A27 (current player)
        loda,r0 1A21h           ;r0 = *(1A21);
        stra,r0 1A27h           ;*(1A27) = r0; // current player is in $1A27
        bsta,un CLEARLINE       ;gosub CLEARLINE;
MOVED_15:
        bsta,un CHECKFORFEIT    ;gosub CHECKFORFEIT;
;get AI coords from user ram ($1A26) (ROM locations $2A2..$2A3 hold $1A26), put into r2
;if best coords are still (-1,-1) then forfeit
        lodr,r0 *02F8h          ;r0 = *(2F8);
        bctr,lt MOVED_16        ;if (<) goto MOVED_16;
        retc,un                 ;return;
MOVED_16:
;console is forfeiting
        loda,r0 1A22h           ;r0 = *(1A22);
;print current (forfeiting) player's symbol (next to "FORFEIT MOVE" message)
        stra,r0 18C1h           ;*(18C1) = r0;
        lodi,r2 00CH            ;r2 = $C; // loop iterator (loop 12 times)
        eorz    r0              ;r0 = 0;
MOVED_17:
;print "FORFEIT MOVE"
        loda,r0 079Ah,r2        ;r0 = *(79A + r2);
        stra,r0 18C2h,r2        ;*(18C2 + r2) = r0;
        bdrr,r2 MOVED_17        ;if (--r2 != 0) goto MOVED_17;
;end of loop
;change current player
        loda,r2 1A27h           ;r2 = *(1A27);
        eori,r2 002H            ;Exclusive OR r2 with %00000010
        strr,r2 *0336h          ;*(*(336)) = r2; // copy r2 to user RAM ($1A27) pointed to at ROM location $336
        bsta,un CHECKFORFEIT    ;gosub CHECKFORFEIT;
;if best coords are still (-1,-1) then delay
        loda,r0 1A24h           ;r0 = *(1A24);
        bcfr,lt MOVED_18        ;if (!(<)) goto MOVED_18;
;copy $1A24 (best coords) into $1A27 (current player)
        strr,r0 *0336h          ;*(*(336)) = r0; // copy r0 to user RAM ($1A27) pointed to at ROM location $336
        bcta,un OFTEN_3         ;goto OFTEN_3;
MOVED_18:
;delay so that players can read message
;wait until monotonic incrementor is zero (ie. a multiple of 256)
;this will be a varying amount of time depending on
;the current value of the monotonic incrementor
        bsta,un WAIT            ;gosub WAIT;
        bcfr,eq MOVED_18        ;if (!=) goto MOVED_18;
        bcta,un MOVED_6         ;goto MOVED_6;
;Subroutine---------------------------------------------------------------
CHECKFORFEIT:
;This routine checks whether there are any possible moves for the current
;player, and returns the best coord in $1A2D.
;set variable $1A2D to $1 (turn CHECKFORFEIT mode on)
        lodi,r0 001H            ;r0 = $1;
        stra,r0 1A2Dh           ;*(1A2D) = r0 [$1]; // $1A2D is in user RAM
;get current player from user ram ($1A27) (ROM locations $336..$337 hold $1A27), put into r2
        lodr,r2 *0336h          ;r2 = *(336);
        bsta,un MOVED_5         ;gosub MOVED_5;
;clear variable $1A2D (turn CHECKFORFEIT mode off)
        eorz    r0              ;r0 = 0;
        strr,r0 *0354h          ;*(*(354)) = r0; // copy r0 to user RAM ($1A2D) pointed to at ROM location $354
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
FLIP:
;$1A28 is the square for FLIP to check around
;registers r0..r2 are destroyed
        bsta,un OFTEN           ;gosub OFTEN;
;clear r0, r2 and $1A2B (return code)
        eorz    r0              ;r0 = 0;
        strz    r2              ;r2 = r0 [0];
        stra,r0 1A2Bh           ;*(1A2B) = r0 [0]; // return code
;start of loop (Gavin/Monty is a plagiarist who loves to suck cocks)
FLIP_1:
;check the 8 squares around *($1A28)
;r1 is coordinates we are looking at
;r2 is which direction we are examining (0..7)
;get flip-coords from $1A28
        loda,r0 1A28h           ;r0 = *(1A28);
;adjust coords by current direction delta, put result in r0 and r1
        adda,r0 07AFh,r2        ;r0 += *(7AF + r2); // ROM constants area
        strz    r1              ;r1 = r0;
;check whether y-coord is 8 or -1, if so, coord is off-board and thus not checked
        tmi,r0  080H            ;test bits of (r0 & %10000000); // test high bit of high nybble
        bctr,eq FLIP_3      ;if (==) goto FLIP_3;
;check whether x-coord is 8 or -1, if so, coord is off-board and thus not checked
        tmi,r0  008H            ;test bits of (r0 & %00001000); // test high bit of low nybble
        bctr,eq FLIP_3      ;if (==) goto FLIP_3;
;get character on real board at coords (r1 % 16,r1 / 16), put into r0
        loda,r0 1844h,r1        ;r0 = *(1844 + r1);
;get mode2 from user ram ($1A3B) (ROM locations $3AF..$3B0 hold $1A3B), put into r3
        lodr,r3 *03AFh          ;r3 = *(3AF);
;if mode2 is 0, don't touch the spare board
        bctr,eq FLIP_2      ;if (==) goto FLIP_2; // skips forwards
;mode2 is 1
;copy from real board to spare board
        loda,r0 1A44h,r1        ;r0 = *(1A44 + r1);
FLIP_2:
;compare character on board here to enemy symbol
        coma,r0 1A23h           ;compare r0 against *(1A23) (enemy symbol)
        bctr,eq FLIP_4      ;if (==) goto FLIP_4;
FLIP_3:
;finished here
;check whether done
        loda,r0 07AFh,r2        ;r0 = *(7AF + r2); // ROM constants area
        comi,r0 011H            ;compare r0 against $11 (final direction)
;if all directions done, clean up and return to caller
        bcta,eq FLIP_11     ;if (==) goto FLIP_11;
;do next direction
        addi,r2 001H            ;r2++;
        bctr,un FLIP_1      ;goto FLIP_1;
;end of loop
FLIP_4:
        eorz    r0              ;r0 = 0;
;clear $1A29 (length of line)
        strr,r0 *039Bh          ;*(*(39B)) = r0 [0]; // copy r0 [0] to user RAM ($1A29) pointed to at ROM location $39B
;get this delta
        loda,r0 07AFh,r2        ;r0 = *(7AF + r2); // ROM constants area
        stra,r0 1A2Ah           ;*(1A2A) = r0;
FLIP_5:
;determine whether we have enemy counters to flip in this direction
;jumps to appropriate code if so
;increment variable $1A29 (length of line) by 1
        loda,r0 1A29h           ;r0 = *(1A29);
        addi,r0 001H            ;r0++;
        strr,r0 *039Bh          ;*(*(39B)) = r0; // copy r0 to user RAM ($1A29) pointed to at ROM location $39B
;move cursor further along line
        addr,r1 *0398h          ;r1 += *(*(398)); // r1 += *(1A2A);
;if y is -1 or 8 (ie. have moved off the board, can't flip)
        tmi,r1  080H            ;test bits of (r1 & %10000000); // test high bit of high nybble
        bctr,eq FLIP_3      ;if (==) goto FLIP_3;
;if x is -1 or 8 (ie. have moved off the board, can't flip)
        tmi,r1  008H            ;test bits of (r1 & %00001000); // test high bit of low nybble
        bctr,eq FLIP_3      ;if (==) goto FLIP_3;
;get character on the board at the cursor coords of (r1 % 16,r1 / 16), put into r0
        loda,r0 1844h,r1        ;r0 = *(1844 + r1);
;if mode2 is 0, don't get character from the spare board
        loda,r3 1A3Bh           ;r3 = *(1A3B);
        bctr,eq FLIP_6      ;if (==) goto FLIP_6; // skips forwards
;if mode2 is 1, get character from the spare board
        loda,r0 1A44h,r1        ;r0 = *(1A44 + r1);
FLIP_6:
;see if there is a friendly counter here to terminate the line
        coma,r0 1A22h           ;compare r0 against *(1A22) // current player's symbol
        bctr,eq FLIP_7      ;if (==) goto FLIP_7;
        comi,r0 07CH            ;compare r0 against $7C (empty board symbol)
;line terminated by a space instead of a friendly counter, can't flip counters
        bctr,eq FLIP_3      ;if (==) goto FLIP_3;
;enemy counter here, move further along
        bctr,un FLIP_5      ;goto FLIP_5;
FLIP_7:
;line is terminated correctly, let's flip the line of counters
        loda,r0 1A2Bh           ;r0 = *(1A2B);
;*($1A2B) += *(1A29); // counters flipped += length of line;
        addr,r0 *039Bh          ;r0 += *(*(39B)); // r0 += *(1A29);
        strr,r0 *03C2h          ;*(*(3C2)) = r0; // copy r0 to user RAM ($1A2B) pointed to at ROM location $3C2
        loda,r0 1AC4h           ;r0 = *(1AC4);
;if mode1 is 0, done here (we didn't really want to do any flipping)
        bcta,eq FLIP_3      ;if (==) goto FLIP_3;
;mode1 is 1
;get current player's symbol from user ram ($1A22) (ROM locations $3B7..$3B8 hold $1A22), put into r0
        lodr,r0 *03B7h          ;r0 = *(3B7);
;copy flip-coord into r1
        loda,r1 1A28h           ;r1 = *(1A28);
;copy *(1A29) (length of line) to $18D7 (counters remaining to be flipped)
;get length of line from user ram ($1A29) (ROM locations $39B..$39C hold $1A29), put into r3
        lodr,r3 *039Bh          ;r3 = *(39B);
        strr,r3 *03EFh          ;*(*(3EF)) = r3; // copy r3 to user RAM ($18D7) pointed to at ROM location $3EF
;put current player's symbol onto spare board at the actual square that the player chose
        stra,r0 1A44h,r1        ;*(1A44 + r1) = r0;
;get mode2 from user ram ($1A3B) (ROM locations $3AF..$3B0 hold $1A3B), put into r3
        lodr,r3 *03AFh          ;r3 = *(3AF);
;if mode2 is 1, don't put current player's symbol onto real board
        bcfr,eq FLIP_8      ;if (!=) goto FLIP_8;
;put current player's symbol onto real board at the actual spot that the player chose
        stra,r0 1844h,r1        ;*(1844 + r1) = r0;
FLIP_8:
;preserve r0
        strr,r0 *03ECh          ;*(*(3EC)) = r0; // copy r0 to user RAM ($1A3C) pointed to at ROM location $3EC
        lodi,r0 010H            ;r0 = $10; // desired pitch is $10;
;copy into user RAM
        stra,r0 18D0h           ;*(18D0) = r0 [$10]; // user RAM
;play the note of a new line of flips starting ($10)
        bsta,un PLAYNOTE        ;gosub PLAYNOTE;
;restore r0
        loda,r0 1A3Ch           ;r0 = *(1A3C);
;get number of counters remaining to be flipped
        loda,r3 18D7h           ;r3 = *(18D7);
FLIP_9:
;flip a counter
;r0 is the symbol of the current player
;adjust coord by delta (ie. move further along this line)
        adda,r1 1A2Ah           ;r1 += *(1A2A);
;put current player's symbol onto spare board here
        stra,r0 1A44h,r1        ;*(1A44 + r1) = r0;
;update variable $18D7 (counters needing to be flipped)
        strr,r3 *03EFh          ;*(*(3EF) = r3; // copy r3 to user RAM ($18D7) pointed to at ROM location $3EF
;get mode2
        loda,r3 1A3Bh           ;r3 = *(1A3B);
;if mode2 is 1, don't put current player's symbol onto real board
        bcfr,eq FLIP_10         ;if (!=) goto FLIP_10; // skip forwards
;if mode2 is 0, put current player's symbol onto real board
        stra,r0 1844h,r1        ;*(1844 + r1) = r0;
FLIP_10:
;preserve r0
        strr,r0 *03ECh          ;*(*(3EC)) = r0; // copy r0 to user RAM ($1A3C) pointed to at ROM location $3EC
;get current pitch
        loda,r0 18D0h           ;r0 = *(18D0);
;increase current pitch (ie. higher note)
        addi,r0 008H            ;r0 += 8;
;play counter-flipping sound (pitch of $18 for 1st counter in this line
;to be flipped, $20 for 2nd counter, etc, $28, $30, $38 or $40).
        stra,r0 18D0h           ;*(18d0) = r0; // user RAM
        bsta,un PLAYNOTE        ;gosub PLAYNOTE;
;restore r0
;get preserved value of r0 from user ram ($1A3C) (ROM locations $3EC..$3ED hold $1A3C), put into r0
        lodr,r0 *03ECh          ;r0 = *(3EC);
;get counters needing to be flipped from user ram ($18D7) (ROM locations $3EF..$3F0 hold $18D7), put into r3
        lodr,r3 *03EFh          ;r3 = *(3EF);
;check whether there are still more counters to be flipped
        bdra,r3 FLIP_9      ;if (--r3 != 0) goto FLIP_9;
        bcta,un FLIP_3      ;goto FLIP_3;
FLIP_11:
;cleanup and shutdown section
;if mode1 is 1 and mode2 is 0, scores are updated before exit
;if mode1 is 0, clean up and exit
        loda,r0 1AC4h           ;r0 = *(1AC4);
        bctr,eq FLIP_12     ;if (==) goto FLIP_12;
;mode1 is 1
;get mode2 from user ram ($1A3B) (ROM locations $3FA..$3FB hold $1A3B), put into r0
        lodr,r0 *03FAh          ;r0 = *(3FA);
;if mode2 is 0, update scores and current player indicator ('+' character)
        bsta,eq SCORES          ;if (==) gosub SCORES;
FLIP_12:
;$1A2B (counters flipped) is copied into r0 for the convenience of the caller
        loda,r0 1A2Bh           ;r0 = *(1A2B);
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
THINK:
;r0 is the current worth of this board coordinate
;r1 is always $1 at entry
        rrl,r1                  ;rotate r1 to the left once (now r1 is %10000000)
        subi,r1 001H            ;r1--;             // now r1 is %01111111 ($79)
;$79 is offset into board
        strr,r1 *0465h          ;*(*(465)) = r1; // copy r1 [$79] to user RAM ($1A3A) pointed to at ROM location $465
;preserve r2 for caller
        stra,r2 1A36h           ;*(1A36) = r2;
;get current player in r2
        loda,r2 1A27h           ;r2 = *(1A27);
;preserve current player ($1A27) at $1A35
        stra,r2 1A35h           ;*(1A35) = r2;
;set $1A37 (if p1) or $1A39 (if p2) to current worth
        stra,r0 1A37h,r2        ;*(1A37 + r2) = r0;
        eorz    r0              ;r0 = 0;
;set other player's worth ($1A37/$1A39) to zero
        eori,r2 002H            ;Exclusive OR r2 with $2
        stra,r0 1A37h,r2        ;*(1A37 + r2) = r0 [0];
        lodi,r1 007H            ;r1 = $7; // loop iterator (loop 7 times)
THINK_1:
;preserve $1A20..1A26 at $1A2E..$1A34
        loda,r0 1A1Fh,r1        ;r0 = *(1A1F + r1);
        stra,r0 1A2Dh,r1        ;*(1A2D + r1) = r0;
        bdrr,r1 THINK_1         ;if (--r1 != 0) goto THINK_1;
;end of loop
;now copy the real board into the spare board
;the spare board is in lower display memory
;since we are using low-resolution mode (128x104) we can use lower display
; memory as normal user variable RAM
        lodi,r1 078H            ;r1 = $78; // loop iterator (loop for each counter)
THINK_2:
        loda,r0 1843h,r1        ;r0 = *(1843 + r1); // look at the board here
        stra,r0 1A43h,r1        ;*(1A43 + r1) = r0; // copy into spare board
        bdrr,r1 THINK_2         ;if (--r1 != 0) goto THINK_2;
;end of loop
;get ready to call FLIP
        loda,r2 1A26h           ;r2 = *(1A26);
;copy AI coords into $1A28
        stra,r2 1A28h           ;*(1A28) = r2;
        lodi,r0 001H            ;r0 = $1;
        stra,r0 1AC4h           ;*(1AC4) = r0 [$1]; // set mode1 to 'real move'
        stra,r0 1A3Bh           ;*(1A3B) = r0 [$1]; // set mode2 to 'spare board'
;call FLIP to do a real move on the spare board
        bsta,un FLIP            ;gosub FLIP;
;get square being thought about from user ram ($1A3A) (ROM locations $465..$466 hold $1A3A), put into r2
        lodr,r2 *0465h          ;r2 = *(465);
THINK_3:
        stra,r2 1A3Ah           ;*(1A3A) = r2;
;copy $1A20 to $1A21, then change $1A20
;(in other words, change $1A20 and $1A21, or swap them)
        loda,r2 1A20h           ;r2 = *(1A20);
        stra,r2 1A21h           ;*(1A21) = r2;
        eori,r2 002H            ;Exclusive OR r2 with $2
        stra,r2 1A20h           ;*(1A20) = r2;
;swap symbols
        loda,r1 1A22h           ;r1 = *(1A22); // current player's symbol
        loda,r2 1A23h           ;r2 = *(1A23); // other player's symbol
        strr,r1 *0476h          ;*(*(476)) = r1; // copy r1 to user RAM ($1A23) pointed to at ROM location $476
        strr,r2 *0473h          ;*(*(473)) = r2; // copy r2 to user RAM ($1A22) pointed to at ROM location $473
;set best coords ($1A24) to -1
;clear $1A25 (best worth) and $1A26 (AI coords)
        lodi,r2 000H            ;r2 = $0;
        strr,r2 *04A7h          ;*(*(4A7)) = r2 [0]; // clear user RAM ($1A26) pointed to at ROM location $4A7
        stra,r2 1A25h           ;*(1A25) = r2 [0];
        lodi,r0 0FFH            ;r0 = $FF;
        stra,r0 1A24h           ;*(1A24) = r0 [$FF];
THINK_4:
;get AI coords from user ram ($1A26) (ROM locations $4A7..$4A8 hold $1A26), put into r2
        lodr,r2 *04A7h          ;r2 = *(4A7);
;read from spare board at this coord
        loda,r0 1A44h,r2        ;r0 = *(1A44 + r2);
        comi,r0 07CH            ;compare r0 against $7C (empty board symbol)
;if empty
        bctr,eq THINK_7         ;if (==) goto THINK_7;
THINK_5:
;get AI coords from user ram ($1A26) (ROM locations $4A7..$4A8 hold $1A26), put into r2
        lodr,r2 *04A7h          ;r2 = *(4A7); // get $1A from ROM location $4A7, put into r2
        tmi,r2  007H            ;test bits of (r2 & %00000111); // test bits 2..0 of r2
        bctr,eq THINK_6         ;if (==) goto THINK_6;
        addi,r2 001H            ;r2++;
;copy AI coords back into RAM
        strr,r2 *04A7h          ;*(*(4A7)) = r2; // copy r2 to user RAM ($1A26) pointed to at ROM location $4A7
        bctr,un THINK_4         ;goto THINK_4;
THINK_6:
;test whether x and y are both 7
;in other words, check whether we have we finished the entire board
        tmi,r2  077H            ;test bits of (r2 & %01110111);
        bcta,eq THINK_13        ;if (==) goto THINK_13;
;otherwise
        andi,r2 070H            ;r2 &= %01110000; // extract y-coord
        addi,r2 010H            ;r2 += %00010000; // increment y-coord by 1 (ie. move down by one)
;copy AI coords back into RAM
        stra,r2 1A26h           ;*(1A26) = r2;
        bctr,un THINK_4         ;goto THINK_4;
THINK_7:
;found an empty square here at this coordinate
;set up arguments for FLIP
        eorz    r0              ;r0 = 0;
        stra,r0 1AC4h           ;*(1AC4) = r0 [0]; // set mode to 'pretend move'
        stra,r2 1A28h           ;*(1A28) = r2; // *(1A28) = *(1A26);
;call FLIP to do a pretend move on the spare board
        bsta,un FLIP            ;gosub FLIP;
        comi,r0 000H            ;compare r0 against $0
;if that move would be no good then jump back to THINK_5
        bctr,eq THINK_5         ;if (==) goto THINK_5;
;that move would be valid
;get AI coords from user ram ($1A26) (ROM locations $4A7..$4A8 hold $1A26), put into r2
        lodr,r1 *04A7h          ;r1 = *(4A7);
;if y is 7, check corners
        comi,r1 06FH            ;compare r1 against %01101111 (y == 6, x == 7)
        bctr,gt THINK_8         ;if (>) goto THINK_8;
;else if y is 0, check corners
        comi,r1 008H            ;compare r1 against %00001000 (y == 0, x == 8)
        bctr,lt THINK_8         ;if (<) goto THINK_8;
;else if x is 7, check corners
        tmi,r1  007H            ;test bits of (r1 & %00000111);
        bctr,eq THINK_8         ;if (==) goto THINK_8;
;else if x is not 0, don't check corners
        andi,r1 007H            ;r1 &= %00000111;
        bcfr,eq THINK_12        ;if (!=) goto THINK_12;
THINK_8:
;r0 is holding number of squares that would be flipped if you moved here
;corner-checking routine
;increase worth by 4 for being on edge of board
        addi,r0 004H            ;r0 += $4;
        strz    r1              ;r1 = r0;
        lodi,r3 004H            ;r3 = $4; // loop iterator (loop quarce)
        lodi,r2 000H            ;r2 = $0; // offset into constant data area
THINK_9:
;look at each corner of the board
        loda,r0 07B6h,r2+       ;r0 = *(7B6 + ++r2);
;compare r0 against *(1A26) (AI coords)
        comr,r0 *04A7h          ;compare r0 against *(*(4A7))
;if not a corner, loop again
        bcfr,eq THINK_10        ;if (!=) goto THINK_10;
;AI coords are at a corner
;add (a further) 10 to worth of move for being at corner of board
        addi,r1 00AH            ;r1 += 10;
        bctr,un THINK_11        ;goto THINK_11;
THINK_10:
        bdrr,r3 THINK_9         ;if (--r3 != 0) goto THINK_9;
;end of loop
THINK_11:
;copy worth from r1 into r0
        lodz    r1              ;r0 = r1;
THINK_12:
        coma,r0 1A25h           ;compare r0 (worth) against *(1A25) (best worth)
;if not the best worth (best possible move found so far), check another possible move
        bcfa,gt THINK_5         ;if (!(>)) goto THINK_5;
;otherwise, set best worth to this worth
        strr,r0 *04E1h          ;*(*(4E1)) = r0; // copy r0 to user RAM ($1A25) pointed to at ROM location $4E1
;copy $1A26 to $1A24 (set best coords to these coords)
        loda,r2 1A26h           ;r2 = *(1A26);
        stra,r2 1A24h           ;*(1A24) = r2;
;check another possible move
        bcta,un THINK_5         ;goto THINK_5;
THINK_13:
;now we have checked the entire board
        loda,r0 1A24h           ;r0 = *(1A24);
;if best coord is still (-1,-1), skip flipping
        bctr,lt THINK_14        ;if (<) goto THINK_14;
;set up arguments for FLIP
        stra,r0 1A28h           ;*(1A28) = r0; // *(1A28) = *(1A24);
        lodi,r0 001H            ;r0 = $1;
        stra,r0 1AC4h           ;*(1AC4) = r0 [$1];
;call FLIP to do a real move on the spare board
        bsta,un FLIP            ;gosub FLIP;
THINK_14:                  
        loda,r0 1A25h           ;r0 = *(1A25); // worth of best possible move
        loda,r1 1A20h           ;r1 = *(1A20); // current thinking player (0 or 2)
;best worth += worth for this player;
        adda,r0 1A37h,r1        ;r0 += *(1A37 + r1);
;worth for this player = best worth;
        stra,r0 1A37h,r1        ;*(1A37 + r1) = r0;
        loda,r2 1A3Ah           ;r2 = *(1A3A);
;if there are more squares to think about
        bdra,r2 THINK_3         ;if (--r2 != 0) goto THINK_3;
;end of loop
;change r1
        eori,r1 002H            ;Exclusive OR r1 with $2
        strz    r2              ;r2 = r0;
;r0 and r2 are holding best worth
;subtract best worth from other player's worth
        loda,r0 1A37h,r1        ;r0 = *(1A37 + r1);
        subz    r2              ;r0 -= r2;
;r0 and r2 are holding best worth, modified as mentioned above
        strz    r2              ;r2 = r0;
;restore $1A20..$1A27 from $1A2E..$1A35
        lodi,r1 008H            ;r1 = $8; // loop 8 times
THINK_15:
        loda,r0 1A2Dh,r1        ;r0 = *(1A2D + r1);
        stra,r0 1A1Fh,r1        ;*(1A1F + r1) = r0;
        bdrr,r1 THINK_15        ;if (--r1 != 0) goto THINK_15;
;end of loop
;r1 is always 0 at this point
;set mode2 to 0 (real board)
        stra,r1 1A3Bh           ;*(1A3B) = r1 [0]; // mode2
;put result into r0 for convenience of caller
        lodz    r2              ;r0 = r2;
;restore preserved r2 into r1 (bug - should restore into r2)
        loda,r1 1A36h           ;r1 = *(1A36);
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
;prints scores and the green '+' current player indicator
SCORES:
        eorz    r0              ;r0 = 0;
        stra,r0 18E1h           ;*(18E1) = r0 [0]; // zero player 1's score
        stra,r0 18E6h           ;*(18E6) = r0 [0]; // zero player 2's score
        lodi,r2 006H            ;r2 = $6;
        lodi,r3 0BEH            ;r3 = $BE; // player 2's symbol
SCORES_1:
        lodi,r1 078H            ;r1 = $78;
SCORES_2:
        loda,r0 1843h,r1        ;r0 = *(1843 + r1);
        comz    r3              ;compare r0 against r3
        bcfr,eq SCORES_3        ;if (!=) goto SCORES_3;
        loda,r0 18E0h,r2        ;r0 = *(18E0 + r2);
        addi,r0 067H            ;r0 += $67;
        dar,r0                  ;decimal adjust r0
        stra,r0 18E0h,r2        ;*(18E0 + r2) = r0;
SCORES_3:
        bdrr,r1 SCORES_2        ;if (--r1 != 0) goto SCORES_2;
        lodi,r3 0FDH            ;r3 = $FD; // player 1's symbol
        addi,r2 0FBH            ;r2 += $FB; // subtract 5
        bcfr,lt SCORES_1        ;if (!(<)) goto SCORES_1;
;get player 1's score from user ram ($18E1) (ROM locations $52F..$530 hold $18E1), put into r0
        lodr,r0 *052Fh          ;r0 = *(52F);
        bsta,un MAKEDIGITS      ;gosub MAKEDIGITS;
        stra,r0 1800h           ;*(1800) = r0; // print p1's tens digit at 0,0
        stra,r1 1801h           ;*(1801) = r1; // print p2's ones digit at 1,0
;get player 2's score from user ram ($18E6) (ROM locations $532..$533 hold $18E6), put into r0
        lodr,r0 *0532h          ;r0 = *(532);
        bstr,un *0554h          ;gosub *(554); // gosub to $713 (MAKEDIGITS)
                                ;INFO: indirect jump
        stra,r0 180Eh           ;*(180E) = r0; // print p2's tens digit at 0,14
        stra,r1 180Fh           ;*(180F) = r1; // print p2's ones digit at 0,15
;r0 is p2's character, r2 is p1's character
        eorz    r0              ;r0 = 0; // ' ' (space) character
        lodi,r2 076H            ;r2 = $76; // green '+' character
        loda,r1 1A27h           ;r1 = *(1A27); // current player
        bctr,eq SCORES_4        ;if (==) goto SCORES_4; // if player is 1, skip forwards
        strz    r2              ;r2 = r0; // put r0 [0 or ' '] into p1's position
        lodi,r0 076H            ;r0 = $76; // green '+' character
SCORES_4:
;indicate whose turn it is
;r2 is p1 indicator, r0 is p2 indicator
        stra,r2 1814h           ;*(1814) = r2; // print appropriate character for p1 ('+' or ' ')
        stra,r0 181Bh           ;*(181B) = r0; // print appropriate character for p2 ('+' or ' ')
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
CLEARLINE:
        lodi,r1 010H            ;r1 = $10; // loop iterator (loop 16 times)
        eorz    r0              ;r0 = 0;
CLEARLINE_1:
;clear $18C0..18CF (bottom line of screen)
        stra,r0 18BFh,r1        ;*(18BF + r1) = r0;
        bdrr,r1 CLEARLINE_1     ;if (--r1 != 0) goto CLEARLINE_1;
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
CLEARSPRITE:
;sets sprite pointer to $FF, to clear it from the screen
        lodi,r0 0FFH            ;r0 = $FF;
        stra,r0 18F7h           ;*(18F7) = r0 [$FF];
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
DRAWSPRITE:
;This subroutine derives a sprite position for the cursor sprite, based
;on the cursor position held in $18DE, and draws the sprite.
        loda,r0 18DEh           ;r0 = *(18DE);
        rrl,r0                  ;rotate r0 to the left thrice...
        rrl,r0                  ;...
        rrl,r0                  ;...
        andi,r0 078H            ;r0 &= %01110111;
        addi,r0 04BH            ;r0 += %01001011; // add 75 to r0
        strr,r0 *0584h          ;*(*(584)) = r0; // copy r0 to sprite pointer ($18F7) pointed to at ROM location $584
;get cursor position from user ram ($18DE) (ROM locations $588..$589 hold $18DE), put into r1
        lodr,r1 *0588h          ;r1 = *(588);
        andi,r1 070H            ;r1 &= %01100000 // clear bits 7 and 4..0
        addi,r1 051H            ;r1 += $51;
        lodi,r0 0FFH            ;r0 = $FF;
        subz    r1              ;r0 -= r1;
;set sprite 3's y-coords to r0
        stra,r0 18F6h           ;*(18F6) = r0;
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
PLAYNOTE:
;arguments: r0 is the desired pitch of note
;preserve r1 for the caller
        stra,r1 18D8h           ;*(18D8) = r1; // user RAM
        lodi,r3 000H            ;r3 = $0;
;if 'spare board' mode, don't play note
        loda,r1 1A3Bh           ;r1 = *(1A3B); // mode2
        bctr,gt PLAYNOTE_2      ;if (>) goto PLAYNOTE_2
        strr,r0 *05B9h          ;*(*(5B9)) = r0; // copy r0 (pitch) to custom chip register ($18FD) pointed to at ROM location $5B9
        lodi,r0 00FH            ;r0 = $F;
        stra,r0 18FEh           ;*(18FE) = r0 [$F]; // set volume to $F (maximum)
        lodi,r3 008H            ;r3 = $8; // this is the delay factor, ie. how long to hold the note being played before continuing
PLAYNOTE_1:
;call the WAIT routine eight times
        bsta,un WAIT            ;gosub WAIT;
        bdrr,r3 PLAYNOTE_1      ;if (--r3 != 0) goto PLAYNOTE_1;
PLAYNOTE_2:
        stra,r3 18FDh           ;*(18FD) = r3 [0]; // turn off sound
;get stored r1 from user ram ($) (ROM locations $5A1..$5A2 hold $18D8), put into r1
;restore r1 for the caller
        lodr,r1 *05A1h          ;r1 = *(5A1);
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
;Returns $80 is nothing is pressed, $0 if START is pressed
BUTTONS:                                                             ;$5BE
        loda,r0 18D5h           ;r0 = *(18D5); // user RAM
        andi,r0 00FH            ;r0 &= %00001111; // extract low nybble of r0
;ensure the monotic incrementor is an even multiple of 16
;in other words, once every 16 times
        retc,gt                 ;if (>) return; // return unless clear
;get level from user ram ($18E0) (ROM locations $5EA..$5EB hold $18E0), put into r2
        lodr,r2 *05EAh          ;r2 = *(5EA); // get level from user ram ($18E0) (ROM locations $5EA..$5EB hold $18E0), put into r2
;get console buttons ($1908) (ROM locations $5D3..$5D4 hold $1908), put into r0
        lodr,r0 *05D3h          ;r0 = *(5D3); // get console buttons (ROM locations $5D3..$5D4 hold $1908), put into r0
;r0 = console buttons, r2 = level
        andi,r0 002H            ;r0 &= %00000010; // extract OPTION bit
        bcfr,eq BUTTONS_4       ;if (!=) goto BUTTONS_4; // if pressed
;get console buttons ($1908) (ROM locations $5D3..$5D4 hold $1908), put into r0
        lodr,r0 *05D3h          ;r0 = *(5D3); // get console buttons (ROM locations $5D3..$5D4 hold $1908), put into r0
        andi,r0 001H            ;r0 &= %00000001; // extract START bit
        bctr,eq BUTTONS_2       ;if (==) goto BUTTONS_2; // if not pressed
BUTTONS_1:
;START button is down
;wait for START button to be released
        loda,r0 1908h           ;r0 = *(1908); // look at console buttons
        andi,r0 001H            ;r0 &= %00000001; // extract START bit
        bcfr,eq BUTTONS_1       ;if (!=) goto BUTTONS_1; // while down
;set return code and return to caller
        eorz    r0              ;r0 = 0;
        retc,un                 ;return;
BUTTONS_2:
        loda,r0 1908h           ;r0 = *(1908); // look at console buttons
        andi,r0 004H            ;r0 &= %00000100; // extract DIFFICULTY bit
;if DIFFICULTY bit is clear, then nothing is down
        bctr,eq BUTTONS_6       ;if (==) goto BUTTONS_6;
;DIFFICULTY button is down
;the last two bits of the level byte are flipped
;bit 1 is the 'limited time' flag
;bit 0 seems to be another copy of the 'limited time' flag
        eori,r2 003H            ;Exclusive OR r2 with %00000011      ;$5E2
        lodi,r0 004H            ;r0 = $4; // set note pitch
BUTTONS_3:
;OPTION or DIFFICULTY is down
;r0 has already been set to the desired pitch of the note
        bsta,un PLAYNOTE        ;gosub PLAYNOTE;
;copy the (possibly modified) level from r2 back into $18E0
        stra,r2 18E0h           ;*(18E0) = r2;
;reset to startup screen
        bcta,un TITLESCREEN     ;goto TITLESCREEN;
BUTTONS_4:
;OPTION button is down, so change level
        addi,r2 010H            ;r2 += %00010000; // add character '1' (%00010000: high nybble is 1) to level
        comi,r2 070H            ;compare level with character '6' (%01100000: high nybble is 6)
;if level less than 6
        bcfr,gt BUTTONS_5       ;if (!(>)) goto BUTTONS_5;
;set level to '0'
        andi,r2 00FH            ;r2 &= %00001111; // clear high nybble (level), preserve low nybble (colour)
;set level to '1'
        iori,r2 010H            ;r2 |= %00010000; // set bit 4 of r2
;level is now 0001xxxx
BUTTONS_5:
        lodi,r0 00CH            ;r0 = $C; // desired pitch of note
;play note, store new level and return
        bctr,un BUTTONS_3       ;goto BUTTONS_3;
BUTTONS_6:
;nothing is down
;set return code and return to caller
        lodi,r0 080H            ;r0 = $80;
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
;All of these (OFTEN..4, VICTORY..1, GAMEOVERLOOP, STARTBUTTON..1,
;TIEGAME..1, TICK..1, OFTEN_CLEANEXIT) are part of super-routine OFTEN,
;the renaming is merely to assist comprehension of the purposes of the
;various sections.
OFTEN:
;preserve r2 and r3 for the caller
        stra,r2 18DAh           ;*(18DA) = r2; // user RAM
        stra,r3 18DBh           ;*(18DB) = r3; // user RAM
        bsta,un BUTTONS         ;gosub BUTTONS;
        bcta,eq STARTBUTTON     ;if (==) goto STARTBUTTON; // if zero then START was pressed
        bsta,un WAIT            ;gosub WAIT;
        andi,r1 03FH            ;r1 &= %00111111;
;check whether monotonic incrementor is an even multiple of 64
        bcta,gt OFTEN_CLEANEXIT ;if (>) goto OFTEN_CLEANEXIT;
;yes, it is an even multiple of 64
;(or in other words, another second has passed)
        bsta,un TIME            ;gosub TIME; // update time display
        lodi,r3 0FDH            ;r3 = $%11111101;
;get level from user ram ($18E0) (ROM locations $5EA..$5EB hold $18E0), put into r2
        lodr,r0 *05EAh          ;r0 = *(*(5EA));
;test the 'limited time' bit
        andi,r0 002H            ;r0 &= %00000010; // extract bit 1 from r0
;if unlimited time then skip forwards
        bctr,eq OFTEN_3         ;if (==) goto OFTEN_3;
;else
        lodi,r2 004H            ;r2 = $4; // loop iterator (loop quarce)
OFTEN_1:
;subtract used minutes from allowed minutes
        loda,r0 1AC3h,r2        ;r0 = *(1AC3 + r2); // user RAM
        suba,r0 1AC7h,r2        ;r0 -= *(1AC7 + r2); // user RAM
        bcfr,eq OFTEN_2         ;if (!=) goto OFTEN_2; // skip forwards
;subtract used seconds from allowed seconds
        loda,r0 1AC4h,r2        ;r0 = *(1AC4 + r2); // user RAM
        suba,r0 1AC8h,r2        ;r0 -= *(1AC8 + r2); // user RAM
        bctr,eq VICTORY         ;if (==) goto VICTORY;
OFTEN_2:
        lodi,r3 0BEH            ;r3 = $BE;
        addi,r2 0FFH            ;r2 += $FF;
        bdrr,r2 OFTEN_1         ;if (--r2 != 0) goto OFTEN_1;
;end of loop
OFTEN_3:
;r3 needs to be set to the winner's symbol before jumping to VICTORY
        lodi,r3 0BEH            ;r3 = $BE; // player 2's symbol
        loda,r0 18E1h           ;r0 = *(18E1); // player 1's score
;if p2 wins
        bctr,eq VICTORY         ;if (==) goto VICTORY; // if p1's score is zero
        lodi,r3 0FDH            ;r3 = $FD; // player 1's symbol
        loda,r0 18E6h           ;r0 = *(18E6); // player 2's score
;if p1 wins
        bctr,eq VICTORY         ;if (==) goto VICTORY; // if p2's score is zero
;both scores are nonzero, add scores
        addr,r0 *063Ah          ;r0 += *(*(63A)); // r0 += *(18E1);
;now r0 is both scores added together
        addi,r0 066H            ;r0 += $66; // $66 means we don't want to adjust the value
        dar,r0                  ;decimal adjust r0
        comi,r0 064H            ;compare r0 against $64 (which translates to 64)
;if the board is not completely filled
        bcfa,eq TICK            ;if (!=) goto TICK;
OFTEN_4:
;game is now over (board is completely filled)
;r0 is $64 at this point
        subr,r0 *063Ah          ;r0 -= *(*(63A)); // r0 -= *(18E1); // subtract p1's score
        comi,r0 032H            ;compare r0 against $32
;if 32 squares filled each then the game is a tie
        bctr,eq TIEGAME         ;if (==) goto TIEGAME;
        bctr,lt VICTORY         ;if (<) goto VICTORY; // winner is player 1
        lodi,r3 0BEH            ;r3 = $BE; // winner is player 2
VICTORY:
;r3 has the winner's symbol
        bsta,un CLEARLINE       ;gosub CLEARLINE;
        stra,r3 18C3h           ;*(18C3) = r3; // draw winner's symbol on screen
        lodi,r2 004H            ;r2 = $4; // loop iterator (loop 4 times)
VICTORY_1:
;Copy $779..77C ("WINS") (ROM constants area) to $18C6..$18CA (screen)
        loda,r0 0778h,r2        ;r0 = *(778 + r2);
        stra,r0 18C5h,r2        ;*(18C5 + r2) = r0;
        bdrr,r2 VICTORY_1       ;if (--r2 != 0) goto VICTORY_1;
;End of loop
GAMEOVERLOOP:
;infinite loop, just keep waiting until the user presses START
        bsta,un WAIT            ;gosub WAIT;
        bsta,un BUTTONS         ;gosub BUTTONS;
        bcfr,eq GAMEOVERLOOP    ;if (!=) goto GAMEOVERLOOP;
STARTBUTTON:
;user has pressed (and released) START, so start a new game
        lodi,r1 004H            ;r1 = $4; // loop iterator (loop 4 times)
STARTBUTTON_1:
;copy user RAM from $18EB..$18EE to $1AC9..1ACB
;set allowed seconds for each player back to their original values
        loda,r0 18EAh,r1        ;r0 = *(18EA + r1);
        stra,r0 1AC8h,r1        ;*(1AC8 + r1) = r0;
        bdrr,r1 STARTBUTTON_1   ;if (--r1 != 0) goto STARTBUTTON_1;
;end of loop
        bcta,un NEWGAME         ;goto NEWGAME; // start new game
;Copies $771..$778 ("TIE GAME") (ROM constants area) to $18C4..18CB (screen)
TIEGAME:
        lodi,r2 008H            ;r2 = $8; // loop iterator (loop 8 times)
        bstr,un *065Ah          ;gosub *(65A); // gosub to $578 (CLEARLINE)
                                ;INFO: indirect jump
TIEGAME_1:
;Print "TIE GAME"
        loda,r0 0770h,r2        ;r0 = *(770 + r2);
        stra,r0 18C3h,r2        ;*(18C3 + r2) = r0;
        bdrr,r2 TIEGAME_1       ;if (--r2 != 0) goto TIEGAME_1;
;end of loop
        bctr,un GAMEOVERLOOP    ;goto GAMEOVERLOOP;
TICK:
;get current player (0 for p1, 2 for p2)
        loda,r2 1A27h           ;r2 = *(1A27); // user RAM
;if best coords are still (-1,-1), board is filled
        bcta,lt OFTEN_4         ;if (<) goto OFTEN_4;
;get seconds used by this player
        loda,r0 1ACAh,r2        ;r0 = *(1ACA + r2);
        addi,r0 067H            ;r0 += $67; // increment by one
        dar,r0                  ;decimal adjust r0
        comi,r0 060H            ;compare r0 with $60 (translates to 60)
;if seconds counter is not 60, skip forwards
        bcfr,eq TICK_1   ;if (r0 != $60) goto FILLEBOARD_1;
;another minute of time has passed, increment minutes used by this player
        loda,r0 1AC9h,r2        ;r0 = *($1AC9 + r2); // user RAM ($1AC9 for p1's mins, $1ACB for p2's mins)
        addi,r0 067H            ;r0 += $67; // increment by one
        dar,r0                  ;decimal adjust r0
;update player's minutes variable in RAM
        stra,r0 1AC9h,r2        ;*($1AC9 + r2) = r0; // user RAM
        eorz    r0              ;r0 = 0;
TICK_1:
;update player's seconds variable in RAM
        stra,r0 1ACAh,r2        ;*($1ACA + r2) = r0; // user RAM
OFTEN_CLEANEXIT:
;restore registers and return to caller
        loda,r2 18DAh           ;r2 = *($18DA); // user RAM
        loda,r3 18DBh           ;r3 = *($18DB); // user RAM
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
WAIT:
        tpsu    080H            ;test upper status register against $80
        bcfr,eq WAIT            ;if (!=) goto WAIT; // if nonzero then try again
WAIT_1:
        tpsu    080H            ;test upper status register against $80 (again)
        bctr,eq WAIT_1          ;if (==) goto WAIT_1; // if zero then try again
;increment the monotonic incrementor
        loda,r1 18D5h           ;r1 = *(18D5); // user RAM area
        addi,r1 001H            ;r1++;
;copy back to RAM
        strr,r1 *06B9h          ;*(*(6B9)) = r1; // copy r1 to user RAM ($18D5) pointed to at ROM location $6B9
;monotonic incrementor is in r1 when returning
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
;This routine prints the digits of the time onto the screen
;caller passes r0 and r1 (address of constant data)
;r0 is high byte of constant data address
;r1 is low  byte of constant data address
SHOWTIME:
;set the pointer variable $18DC..$18DD into the ROM constants area, either:
; $7C9 (if called from LASTSCORES)
; $7BD (if called from TIME)
        stra,r0 18DCh           ;*(18DC) = r0; // user RAM
        stra,r1 18DDh           ;*(18DD) = r1; // user RAM
        lodi,r2 004H            ;r2 = $4; // loop iterator (loop quarce)
        lodi,r3 000H            ;r3 = $0; // offset
;put high byte of address into r0
        loda,r0 *18DCh          ;r0 = *(18DC);
;set high byte of address at $18D1..$18D2 to r0
        stra,r0 18D1h           ;*($18D1) = r0; // user RAM (store r0)
;set r0 to *(18DD), which is the low byte of the passed address
;get high
        loda,r0 *18DCh,r3+      ;r0 = *(18DC + ++r3);
;$18DC..$18DD holds the base address of constant data ('constant data address')
;r3 is now 1
;loop quarce, for four pairs of digits
;(p1 mins, p1 secs, p2 mins, p2 secs)
SHOWTIME_2:
;$18D1..$18D2 holds the display address
;set low byte of address at $18D1..$18D2 to r0
;update variable in RAM (adjust pointer to display memory)
        stra,r0 18D2h           ;*(18D2) = r0; // user RAM
;set $18D3 to high byte of desired display location for this digit pair
        loda,r0 *18DCh,r3+      ;r0 = *(*($18DC) + ++r3); // user RAM
        stra,r0 18D3h           ;*($18D3) = r0; // user RAM
;set $18D4 to low byte of desired display location for this digit pair
        loda,r0 *18DCh,r3+      ;r0 = *(*($18DC) + ++r3); // user RAM
        stra,r0 18D4h           ;*($18D4) = r0; // user RAM
        loda,r0 *18D1h          ;r0 = *(*($18D1)); // user RAM
;r0 is the contents of the digit pair we want to print
;r0 holds packed number (one nybble per digit) for MAKEDIGITS
        bstr,un MAKEDIGITS      ;gosub MAKEDIGITS;
;r0 now holds tens digits, r1 now holds ones digit
;copy tens digit into address pointed to by $18D3..$18D4
;(which will be an address in display memory)
;in other words, print tens digit
        stra,r0 *18D3h          ;*(*(18D3)) = r0; // user RAM
        lodz    r1              ;r0 = r1;
        lodi,r1 001H            ;r1 = $1;
;copy ones digit into address immediately following the one pointed to $18D3..18D5
;(which will be an address in display memory)
;in other words, print ones digit
        stra,r0 *18D3h,r1       ;*(*(18D3) + r1 [$1]) = r0; // copy r0 into $18D4
;get low byte of address $18D1..$18D2 (ROM locations $6D4..$6D5 hold $18D2), put into r0
        lodr,r0 *06D4h          ;r0 = *(6D4);
;increment (low byte of) data address by 1
;would not work properly if crossing a 256-byte boundary (which does not occur)
        addi,r0 001H            ;r0++;
;check whether more digit pairs to print
        bdrr,r2 SHOWTIME_2      ;if (--r2 != 0) goto SHOWTIME_2;
;end of loop
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
;print "TIME"
TIME:
        lodi,r2 004H            ;r2 = $4; // loop iterator (loop quarce)
TIME_1:
        loda,r0 0780h,r2        ;r0 = *($780 + r2); // ROM area
        stra,r0 1835h,r2        ;*($1835 + r2) = r0; // upper screen display
        bdrr,r2 TIME_1          ;if (--r2 != 0) goto TIME_1;
;end of loop
;put $7BD in r0/r1 pair
        loda,r0 07BBh           ;r0 = *($7BB); // grab $07 from $7BB (ROM constants area), put in r0
        loda,r1 07BCh           ;r1 = *($7BC); // grab $BD from $7BC (ROM constants area), put in r1
;print the lower time (used time)
        bsta,un SHOWTIME        ;gosub SHOWTIME;
;print the lower colons (:) onto the screen
        lodi,r0 0FFH            ;r0 = $FF; // $FF is black UDC #7 (:)
        stra,r0 1832h           ;*($1832) = r0 [$FF]; // screen display
        stra,r0 183Dh           ;*($183D) = r0 [$FF]; // screen display
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
MAKEDIGITS:
;This subroutine converts a packed decimal number (high nybble holds high
;digit, low nybble holds low digit), stored in r0, into two red digits,
;each stored as a byte (in r0 and r1), ready for display on the screen.
        strz    r1              ;r1 = r0;
;we are going to be using r1 for the high (tens) digit...
;...and r0 for the low (ones) digit
        rrr,r0                  ;rotate r0 to the right quarce...
        rrr,r0                  ;...
        rrr,r0                  ;...
        rrr,r0                  ;...
        andi,r0 00FH            ;r0 &= %00001111;
        iori,r0 090H            ;r0 |= %10010000;
;r0 is now %1001xxxx, where xxxx are bits 7..4 of passed r0
;Or, in other words, $90 + bits 7..4 of passed r0
;Breaks down as $80 for red, $10 to get to digits section of character set
        andi,r1 00FH            ;r1 &= %00001111;
        iori,r1 090H            ;r1 |= %10010000;
;r1 is now %1001xxxx, where xxxx are bits 3..0 of passed r0
;Or, in other words, $90 + bits 3..0 of passed r0
;Breaks down as $80 for red + $10 to get to digits section of character set
        retc,un                 ;return;
;Subroutine---------------------------------------------------------------
;Routine to check player buttons
;-- Fi --
;-- Up --
;Lt -- Rt
;-- Dn --
READKEYS:
        lodi,r2 004H            ;r2 = $4; // loop iterator (loop quarce)
        eorz    r0              ;r0 = 0;
READKEYS_1:
;clear (zero) user RAM from $1AC0..1AC3
        stra,r0 1ABFh,r2        ;*($1ABF + r2) = r0 [0];
        bdrr,r2 READKEYS_1      ;if (--r2 != 0) goto READKEYS_1;
;end of loop
;we check p2 first, then p1
;when r2 is $4 we are checking p2, when r2 is $0 we are checking p1
        lodi,r2 004H            ;r2 = $4;
READKEYS_2:
        lodi,r1 0FFH            ;r1 = $FF;
;examine '1'/'4'/'7'/'E' column
        loda,r0 1900h,r2        ;r0 = *($1900 + r2);
;extract bit 1 ('7' (left) button)
        andi,r0 002H            ;r0 &= $2;
;if set (left is pressed) then skip forwards...
        bcfr,eq READKEYS_3      ;if (!=) goto READKEYS_3;
;else
;examine '2'/'5'/'8'/'0' column
        loda,r0 1901h,r2        ;r0 = *($1901 + r2);
;extract bits 2 and 0 ('5' (up) and '0' (down) buttons)
        andi,r0 005H            ;r0 &= %00000101;
;if set (button(s) pressed) then skip forwards
        bcfr,eq READKEYS_4      ;if (!=) goto READKEYS_4;
;else...
;examine '3'/'6'/'9'/'E' column
        loda,r0 1902h,r2        ;r0 = *($1902 + r2);
;extract bit 1 ('9' (right) button)
        andi,r0 002H            ;r0 &= %00000010;
;if clear (button not pressed) then skip forwards...
        bctr,eq READKEYS_6      ;if (==) goto READKEYS_6;
;else ('9' (right) is pressed)
        lodi,r1 001H            ;r1 = $1;
READKEYS_3:
;left or right is being pressed
;if r2 is $0 (p1) it stays zero, but if it is $4 (p2) it becomes $2
        rrr,r2                  ;rotate r2 to the right once
        lodz    r1              ;r0 = r1;
        stra,r0 1AC0h,r2        ;*($1AC0 + r2) = r0;
        bctr,un READKEYS_6      ;goto READKEYS_6;
READKEYS_4:
;up or down is being pressed, determine which one it is
        comi,r0 001H            ;compare r0 with $1 ('0' (down) button)
;if bit is set, then down is pressed
        bcfr,eq READKEYS_5      ;if (!=) goto READKEYS_5;
;it wasn't down, so it must be up
        lodi,r1 001H            ;r1 = $1;
READKEYS_5:
;if r2 is $0 (p1) it stays zero, but if it is $4 (p2) it becomes $2
        rrr,r2                  ;rotate r2 to the right once
        lodz    r1              ;r0 = r1;
        stra,r0 1AC1h,r2        ;*($1AC1 + r2) = r0;
READKEYS_6:
        comi,r2 000H            ;compare r2 with $0
;if we just checked p1 then we are finished, skip ahead
        bctr,eq READKEYS_7      ;if (==) goto READKEYS_7;
;otherwise we just checked p2, and now want to check p1
        lodi,r2 000H            ;r2 = $0;
        bctr,un READKEYS_2      ;goto READKEYS_2;
READKEYS_7:
;both players have already been checked for directions
;now check for firebuttons
;examine p1 '2'/'5'/'8'/'0' button column
        loda,r2 1901h           ;r2 = *($1901);
;look specifically for bit 3, which is button '2' (mask out other bits)
        andi,r2 008H            ;r2 &= %00001000;
        rrl,r2                  ;rotate r2 to the left quarce...
        rrl,r2                  ;...
        rrl,r2                  ;...
        rrl,r2                  ;...
;now bit 7 of r2 holds status of p1's button '2'
;examine p2 '2'/'5'/'8'/'0' button column
        loda,r0 1905h           ;r0 = *($1905);
;look specifically for bit 3, which is button '2' (mask out other bits)
        andi,r0 008H            ;r0 &= %00001000;
        rrl,r0                  ;rotate r0 to the left thrice...
        rrl,r0                  ;...
        rrl,r0                  ;...
;now bit 6 of r0 holds status of p2's button '2'
        iorz    r2              ;r0 |= r2;
;Inclusive OR the two registers together...
;now bit 7 of r0 holds p1's button '2' (fire) status
;and bit 6 of r0 holds p2's button '2' (fire) status
        retc,un                 ;return;
;the firebutton doesn't have a RAM location, returns values in registers
;Constant data area-------------------------------------------------------
;"TIE GAME", "WINS", "SET ", "TIME", "LEVEL", "SCORE", "CAPTURE", "ERROR",
;"FORFEIT MOVE"
;
;Note that the first byte after some labels (ie. the byte actually at the
;label) belongs to the previous label's data.
        db      06DH, 062H, 05EH, 000H ;T, I, E, <space>,
        db      060H, 05AH, 066H       ;G, A, M
L0778:
        db      05EH, 070H, 062H, 067H ;E, W, I, N
L077C:
        db      06CH, 06CH, 05EH, 06DH ;S, S, E, T
L0780:
        db      000H, 06DH, 062H, 066H ;<space>, T, I, M
L0784:
        db      05EH, 065H, 05EH, 06FH ;E, L, E, V,
        db      05EH                   ;E
L0789:
        db      065H, 0ACH, 09CH, 0A8H ;L, S, C, O,
        db      0ABH                   ;R
L078E:
        db      09EH, 0DCH, 0DAH, 0E9H ;E, C, A, P,
        db      0EDH, 0EEH, 0EBH       ;T, U, R
L0795:
        db      0DEH, 05EH, 06BH, 06BH ;E, E, R, R,
        db      068H                   ;O
L079A:
        db      06BH, 05FH, 068H, 06BH ;R, F, O, R,
        db      05FH, 05EH, 062H, 06DH ;F, E, I, T,
        db      000H, 066H, 068H, 06FH ;<space>, M, O, V,
        db      05EH                   ;E
L07A7:
;this is how good each row/column position is.
;eg. rows 0 and 7 (top and bottom rows) are most highly regarded,
;rows 1 and 6 are least regarded.
;used by MOVED.
        db      004H, 000H, 003H, 002H ;4, 0, 3, 2,
        db      002H, 003H, 000H, 004H ;2, 3, 0, 4
L07AF:
;deltas, to enable checking of the squares around a given square
;239 240 241
;255       1
; 15  16  17
        db      001H, 0F1H, 0F0H, 0EFH ;1 (+1,0), 241 (+1,-1), 240 (0,-1), 239 (-1,-1),
        db      0FFH, 00FH, 010H       ;255 (-1,0), 15 (-1,+1), 16 (0,+1)
L07B6:
;first byte belongs to L07AF, and needs to be $11
;board coordinates for console's extra counters in levels 2..5
;ie. corner coordinates
        db      011H, 000H, 070H, 007H ;17 (+1,+1), (0,0), (0,7), (7,0)
        db      077H                   ;(7,7)
L07BB:
;passed by TIME to SHOWTIME
        db      007H                   ;$7BD (where to look for constants)
L07BC:
;these are addresses of variables, used by SHOWTIME
;means "get values starting at $1AC9, and put pairs of digits at display
;locations starting at $1830, $1833, $183B, and $183E"
;in other words, this is for showing the lower (used) time
        db      0BDH, 01AH, 0C9H, 018H ;$1AC9, $1830
        db      030H, 018H, 033H, 018H ;$1833, $183B
        db      03BH, 018H, 03EH       ;$183E
L07C7:
;passed by LASTSCORES to SHOWTIME
        db      007H                   ;$7C9 (where to look for constants)
L07C8:
;these are addresses of variables, used by SHOWTIME
;means "get values starting at $1AC5, and put pairs of digits at display
;locations starting at $1820, $1823, $182B, and $182E"
;in other words, this is for showing the upper (allowed) time
        db      0C9H, 01AH, 0C5H, 018H ;$C9, $1AC5, $1820,
        db      020H, 018H, 023H, 018H ;$1823, $182B,
        db      02BH, 018H             ;$182E
L07D2:
;first byte belongs to L07C8
        db      02EH, 000H, 018H, 018H ;User-defined characters
        db      07EH, 07EH, 018H, 018H ;(set up by BOOT)
	db	000H, 0FFH, 081H, 081H
	db	081H, 081H, 081H, 081H
	db	0FFH, 0FFH, 099H, 099H
	db	0E7H, 0E7H, 099H, 099H
	db	0FFH, 0FFH, 0E7H, 0E7H
	db	099H, 099H, 0E7H, 0E7H
	db	0FFH, 000H, 018H, 018H
	db	000H, 000H, 018H, 018H
        db      000H, 094H, 03BH, 04CH ;byte containing '$94' is start of junk
	db	005H, 001H
        end
Notes---------------------------------------------------------------------
Note that the '+' character ($36) is not the same as UDC #3 (the cursor
position symbol), which is $3B.
  Also note that UDCs 0-3 are sprites, whereas UDCs 4-7 are true UDCs.
Thus, the cursor position indicator is actually a sprite.

   $3B      $3C      $3D     $3E      $3F    intrinsic character code
           green    black    red     black   usual colour
            $7C      $FD     $BE      $FF    coloured character code
 UDC #3   UDC #4   UDC #5   UDC #6   UDC #7  UDC number (0..7)
........ ######## ######## ######## ........
...##... #......# #..##..# ###..### ...##...
...##... #......# #..##..# ###..### ...##...
.######. #......# ###..### #..##..# ........
.######. #......# ###..### #..##..# ........
...##... #......# #..##..# ###..### ...##...
...##... #......# #..##..# ###..### ...##...
........ ######## ######## ######## ........

    --0- --1- --2- --3- --4- --5- --6- --7- --8- --9- -10- -11- -12- -13- -14- -15-
 0: 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 180A 180B 180C 180D 180E 180F
 1: 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 181A 181B 181C 181D 181E 181F
 2: 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 182A 182B 182C 182D 182E 182F
 3: 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 183A 183B 183C 183D 183E 183F
 4: 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 184A 184B 184C 184D 184E 184F
 5: 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 185A 185B 185C 185D 185E 185F
 6: 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 186A 186B 186C 186D 186E 186F
 7: 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 187A 187B 187C 187D 187E 187F
 8: 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 188A 188B 188C 188D 188E 188F
 9: 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 189A 189B 189C 189D 189E 189F
10: 18A0 18A1 18A2 18A3 18A4 18A5 18A6 18A7 18A8 18A9 18AA 18AB 18AC 18AD 18AE 18AF
11: 18B0 18B1 18B2 18B3 18B4 18B5 18B6 18B7 18B8 18B9 18BA 18BB 18BC 18BD 18BE 18BF
12: 18C0 18C1 18C2 18C3 18C4 18C5 18C6 18C7 18C8 18C9 18CA 18CB 18CC 18CD 18CE 18CF

    --0- --1- --2- --3- --4- --5- --6- --7- --8- --9- -10- -11- -12- -13- -14- -15-
 0: 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 180A 180B 180C 180D 180E 180F
 1: 1810 1811 1812 1813 1814   L    E    V    E    L  181A   #  181C 181D 181E 181F
 2: 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 182A 182B 182C 182D 182E 182F
 3: 1830 1831   :  1833 1834 1835   T    I    M    E  183A 183B 183C   :  183E 183F
 4: 1840 1841 1842 1843   S    E    T         T    I    M    E  184C 184D 184E 184F
 5: 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 185A 185B 185C 185D 185E 185F
 6: 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 186A 186B 186C 186D 186E 186F
 7: 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 187A 187B 187C 187D 187E 187F
 8: 1880 1881 1882 1883 1884   C    A    P    T    U    R    E  188C 188D 188E 188F
 9: 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 189A 189B 189C 189D 189E 189F
10: 18A0 18A1 18A2 18A3 18A4 18A5 18A6 18A7 18A8 18A9 18AA 18AB 18AC 18AD 18AE 18AF
11: 18B0 18B1 18B2 18B3 18B4 18B5 18B6 18B7 18B8 18B9 18BA 18BB 18BC 18BD 18BE 18BF
12: 18C0 18C1 18C2 18C3 18C4 18C5 18C6 18C7 18C8 18C9 18CA 18CB 18CC 18CD 18CE 18CF

    --0- --1- --2- --3- --4- --5- --6- --7- --8- --9- -10- -11- -12- -13- -14- -15-
 0: 1800 1801 1802 1803 1804 1805   S    C    O    R    E  180B 180C 180D 180E 180F
 1: 1810 1811  p1  1813  p1  1815 1816 1817 1818 1819 181A  p2  181C  p2  181E 181F
 2: 1820 1821   :  1823 1824 1825 1826 1827 1828 1829 182A 182B 182C   :  182E 182F
 3: 1830 1831   :  1833 1834 1835   T    I    M    E  183A 183B 183C   :  183E 183F
 4: 1840 1841 1842 1843   #    #    #    #    #    #    #    #  184C 184D 184E 184F
 5: 1850 1851 1852 1853   #    #    #    #    #    #    #    #  185C 185D 185E 185F
 6:   0    0  1862 1863   #    #    #    #    #    #    #    #  186C 186D   0    0
 7:   0    0  1872 1873   #    #    #   p2   p1    #    #    #  187C 187D   0    0 
 8:   0    0  1882 1883   #    #    #   p1   p2    #    #    #  188C 188D   0    0 
 9:   0    0  1892 1893   #    #    #    #    #    #    #    #  189C 189D   0    0
10: 18A0 18A1 18A2 18A3   #    #    #    #    #    #    #    #  18AC 18AD 18AE 18AF
11: 18B0 18B1 18B2 18B3   #    #    #    #    #    #    #    #  18BC 18BD 18BE 18BF
12: 18C0   #  18C2   F    O    R    F    E    I    T         M    O    V    E  18CF

black: add $C0
red:   add $80
green: add $40
white: add $00

Colours: 0 white
         1 yellow
         2 cyan
         3 green
         4 magenta
         5 red
         6 blue
         7 black

2......4 Levels 1..5 are 1-player, level 6 is 2-player.
........ Level 2 has extra p2 square  at 0,0.
........ Level 3 has extra p2 squares at 0,0, 0,7.
...##... Level 4 has extra p2 squares at 0,0, 0,7, 7,0.
...##... Level 5 has extra p2 squares at 0,0, 0,7, 7,0, 7,7.
........
........
3......5

Variable List------------------------------------------------------------
$18D0: pitch of note to play for this counter being flipped over to the
 other player: $10, $18, $20, $28, $30, $38, $40.
$18D1: how many counters would be flipped
$18D1..$18D2: pointer to display memory (used in SHOWTIME)
$18D3: tens digit (used in SHOWTIME)
$18D4: ones digit (used in SHOWTIME)
$18D5 is a monotonic incrementor (ticker)
$18D6: unused
$18D7: number of counters remaining to be flipped (used in FLIP)
$18D8: is used to preserve r1 by PLAYNOTE
$18D9: unused
$18DA is used to preserve r3 by OFTEN
$18DB is used to preserve r2 by OFTEN
$18DC..$18DD: pointer to constant data (used in SHOWTIME)
$18DE: current cursor position (high nybble is y, low nybble is x)
 (cursor position is with respect to origin of board at 0,0, not origin of screen)
$18DF: old cursor position (high nybble is y, low nybble is x) (used in MAINLOOP)
 (cursor position is with respect to origin of board at 0,0, not origin of screen)
$18E0: level/limited time
 level in high nybble (bits 7..4)
 bit 1 is the 'limited time' flag
 bit 0 seems to be another copy of the 'limited time' flag
$18E1: player 1's score
$18E2..$18E5: last four p1 scores (newest at lower addresses)
$18E6: player 2's score
$18E7..$18EA: last four p2 scores (newest at lower addresses)
$18EB: p1's allowed mins, storage area to keep it safe during gameplay
$18EC: p1's allowed secs, storage area to keep it safe during gameplay
$18ED: p2's allowed mins, storage area to keep it safe during gameplay
$18EE: p2's allowed secs, storage area to keep it safe during gameplay
$18EF: unused
$1A20: current thinking player, 0 or 2
$1A21: other thinking player, 0 or 2
$1A22: current player's symbol
$1A23: other player's symbol
$1A24: coordinates of best move found so far
$1A25: worth of best move found so far (used in THINK)
$1A26: artificial intelligence coordinates (used in MOVED and THINK)
 (holds the coordinates of the move the console is now thinking about)
$1A27: current player (0 for p1, 2 for p2)
$1A28: coords passed to FLIP
$1A29: length of line
$1A2A: delta of the current direction (used in FLIP)
$1A2B: return code of FLIP (how many counters were flipped)
$1A2C: unused
$1A2D: set by CHECKFORFEIT while calling MOVED_5, otherwise clear
$1A2E..$1A35: is used to preserve $1A20..$1A27 by THINK
$1A36: is used to preserve r2 by THINK
$1A37: worth of p1's thinking
$1A38: unused
$1A39: worth of p2's thinking
$1A3A: squares left to think about (used in THINK)
$1A3B: mode2 argument for FLIP
 (which board to use) (0 = real board, 1 = spare board)
$1A3C: is used to preserve r0 by FLIP
$1A3D..$1A43: unused
$1A44..$1ABB: spare board, used for thinking
$1ABC..$1BF: unused
$1AC0 holds the left/right status for p1
 ($0 = nothing, $1 = right, $FF (-1) = left)
$1AC1 holds the up/down    status for p1
 ($0 = nothing, $1 = up,    $FF (-1) = down)
$1AC2 holds the left/right status for p2
 (same format as for p1)
$1AC3 holds the up/down    status for p2
 (same format as for p1)
$1AC4: mode1 argument for FLIP
 (1 = real move, change board(s), 0 = pretend move, evaluate only)
$1AC5: p1's used    minutes
$1AC6: p1's used    seconds
$1AC7: p2's used    minutes
$1AC8: p2's used    minutes
$1AC9: p1's allowed minutes
$1ACA: p1's allowed seconds
$1ACB: p2's allowed minutes
$1ACC: p2's allowed seconds
Subroutines--------------------------------------------------------------
MOVED subroutine:
 called by MAINLOOP.
 calls FLIP, THINK, CLEARLINE, CHECKFORFEIT, WAIT.
 can jump to MAINLOOP_4 or OFTEN_3, or return to caller.
OFTEN:
 called by MAINLOOP and FLIP.
 MOVED can jump into OFTEN_3.
 calls BUTTONS, WAIT, TIME, BUTTONS.
 can jump to NEWGAME, or return to caller.
FLIP:
 called by MOVED and THINK.
 calls OFTEN and PLAYNOTE.
 returns to caller.
MAINLOOP:
 LASTSCORES runs into it.
 MOVED can jump to MAINLOOP_4.
 calls OFTEN, CLEARSPRITE, READKEYS, PLAYNOTE, MOVED.
 jumps to (eventually) LASTSCORES.
THINK:
 called by MOVED.
 calls FLIP.
 returns to caller.
CHECKFORFEIT:
 only called by MOVED.
 calls MOVED_5.
 returns to caller.
MAINLOOP:
 LASTSCORE jumps or runs into it
 calls DRAWSPRITE.
LASTSCORES:
 jumped to by NEWGAME and MAINLOOP.
 calls SCORES, MAKEDIGITS, SHOWTIME.
 runs into MAINLOOP.

Service subroutines:
BUTTONS (subroutine)
 called by TITLELOOP, GAMEOVERLOOP and OFTEN.
 doesn't call anything.
 returns $0 for START button, $80 otherwise, in r0
 can jump back to TITLESCREEN.
WAIT (subroutine)
 returns monotonic incrementor in r1.
 doesn't call anything.
 called by TITLELOOP, MOVED_5, PLAYNOTE, OFTEN, GAMEOVERLOOP.
SHOWTIME (subroutine)
 preserves r0 and r1 for caller
 called by LASTSCORES and TIME.
 calls MAKEDIGITS.
 returns to caller.
TIME (subroutine)
 called by TITLELOOP and OFTEN.
 calls SHOWTIME.
 returns to caller.
MAKEDIGITS (subroutine)
 called by TITLELOOP, LASTSCORES, SCORES, SHOWTIME.
 doesn't call anything.
 returns to caller.
READKEYS (subroutine)
 called by TITLELOOP and ALICE.
 doesn't call anything.
 returns to caller.
SCORES (subroutine)
 called by LASTSCORES, MOVED_5, FLIP
 doesn't call anything.
 returns to caller.
CLEARLINE (subroutine)
 called by NEWGAME, MAINLOOP, SIOBHAN, MOVED, VICTORY, TIEGAME.
 doesn't call anything.
 returns to caller.
CLEARSPRITE (subroutine)
 called only by MAINLOOP.
 doesn't call anything.
 returns to caller.
DRAWSPRITE (subroutine)
 called only by MAINLOOP.
 doesn't call anything.
 returns to caller.
PLAYNOTE (subroutine)
 r0 is the desired pitch, r1 is preserved for the caller.
 calls WAIT.
 returns to caller.

Root-Level Flow Diagram---------------------------------------------------
     BOOT
       |
      \|/
  TITLESCREEN*
       |
      \|/
   TITLELOOP
       |
      \|/
   NEWGAME**
       |
      \|/
   LASTSCORES---+
       |       /|\
      \|/       |
   MAINLOOP-->--+

*  BUTTONS service subroutine can jump directly to TITLESCREEN.
** OFTEN service subroutine can jump directly to NEWGAME.

MOVED normally can call CHECKFORFEIT which calls MOVE,
 but when called by CHECKFORFEIT, MOVED never calls CHECKFORFEIT.
 Thus, infinite recursion is not possible.
