.........1.........2.........3.........4.........5.........6.........7.........8

Mastering Machine Code on Your Spectrum
part 7 of 8 - from ZX Computing Dec'83/Jan'84

We welcome back Toni Baker, author of "Mastering Machine
Code on Your ZX81", who this issue completes the racing car
game she started in the Aug/Sep edition.


Having spent virtually the whole of my article in the
Aug/Sep issue of ZX Computing introducing this program, I
will not waste words providing more introduction. The
program is called Racetrack and I hope you enjoy it!

I have chosen to document this program as I go through it,
in the format of a small description followed by the
relevant code - I hope you can all follow this.

Throughout the article, label names have been printed as
hyphens. However, their correct notation for the Spectrum
should be with an underlined dash. An example of this can be
seen a little further in the text under the heading "STR3" -
the data labels "C-CAR" and "H-CAR" should have been
presented as "C_CAR" and "H_CAR". I hope this does not cause
any problems.

RACETRACK - This data represents the shape of the racetrack.
Each byte represents one step around the track. The first
Hex digit is the position of the left-hand wall plus two,
and the second Hex digit is the position of the right-hand
wall less 12h. So, for instance, the byte '96' implies that
the left wall is at position 9 - 2 = 7, and the right wall
is at position 6 + 12 = 18h.

8000: 96 96 96 96 96 96 96 96 96 96 96 96 96 96 96 96
8010: 96 96 96 96 85 85 74 63 52 41 30 30 30 30 30 30
8020: 41 52 63 63 74 85 96 A7 B8 C9 DA EB FC FC FC FC
8030: FC EB DA C9 B8 B8 B8 B8 B8 B8 B8 B8 B7 B7 B6 C6
8040: C6 C6 B5 A4 93 82 71 60 60 60 60 60 60 61 62 63
8050: 64 65 66 66 66 66 76 76 86 96 A6 B6 B6 B6 C7 C8
8060: C9 C9 B8 A7 96 85 74 63 52 41 52 63 74 63 52 41
8070: 41 41 50 50 50 50 50 50 50 50 50 60 60 60 60 70
8080: 70 70 81 92 A3 B4 C5 D6 E7 F8 F8 F8 F8 F8 F8 F8
8090: F8 E7 D6 C5 B4 A3 A3 A3 A3 A3 A3 A3 A2 A2 A2 A2
80A0: B2 B2 C2 C2 C2 C2 D2 D2 D2 D2 D2 D2 D2 D1 D1 D1
80B0: D1 D1 D1 D1 D1 D1 E1 E1 E1 E1 E1 E1 E0 E0 E0 E0
80C0: E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 DA CB BC BD BC BB
80D0: BA B9 B9 B9 C9 C9 C9 C9 C9 C9 C9 C9 C9 C9 C9 B8
80E0: A7 B6 C5 D4 E5 F6 F6 E5 D4 C3 B2 A1 90 90 A1 B2
80F0: C2 C3 C4 B4 A5 A5 96 A5 A5 96 A5 96 96 96 96 96

STR1 - This is the initial state of the information window at the
top of the screen. It represents PRINT PAPER 6,"
Time    Distance    Distance    
        to go (C)   to go (H)",,"
================================";PAPER 7;

[In the mag there were 34 "=" characters in the above string   ]
[- obviously two too many. The length was defined as 96 bytes  ]
[in the code (at address 83A4) which counts the extra two, but ]
[they were not defined below - should be 11 07 = PAPER WHITE.  ]
[There were nine other printing errors in the listing as well -]
[mostly fatal to the running of the program.                JG.]

[Note that as the cars are moving down the screen the effect of]
[the keys is reversed. Thus Caps Shift, on the left of the key-]
[board, moves the car left from its point of view, but right   ]
[from the player's point of view, and vice versa for Space.    ]
[Symbol Shift is the accelerator key.                       JG.]

8100: 11 06 54 69 6D 65 20 20 20 20 44 69 73 74 61 6E
8110: 63 65 20 20 20 20 44 69 73 74 61 6E 63 65 20 20
8120: 20 20 20 20 20 20 20 20 20 20 74 6F 20 67 6F 20
8130: 28 43 29 20 20 20 74 6F 20 67 6F 20 28 48 29 20
8140: 20 20 06 06 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D
8150: 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D 3D
8160: 3D 3D 3D 3D

8164  11                   [Undefined in the magazine. JG.]
8165  07                   [Undefined in the magazine. JG.]

STR2 - This represents PRINT TAB 7;"graphic shift 8";TAB 18;"graphic shift 8";

8166: 00 00 17 07 00 8F 17 18 00 8F

STR3 - This represents PRINT AT 5,10;INK 1;"car c";INK
0;"  ";INK 2;"car h";INK 0;. The data C-CAR (computer's car)
and H-CAR (human's car) are obviously included within this
string (at addresses 8171 and 8180 respectively).

816E: 16 05 0A
8171: 10 01 8E 8D 14 01 43 14 00 8E 8D 10 00
817E: 20 20
8180: 10 02 8E 8D 14 01 48 14 00 8E 8D 10 00

TIME, DISTC and DISTH - These are the strings AT 2,0;INK
0;PAPER 6;"0000";, etc, which are printed in the information
window during the game.

818D: 16 02 00 10 00 11 06 30 30 30 30
8198: 16 02 0A 10 00 11 06 32 30 30 30
81A3: 16 02 16 10 00 11 06 32 30 30 30

The following are various calling points which PRINT AT various
parts of the screen. The labels used are fairly self-explanatory.

81AE  3D       AT 5,A-3    DEC  A
81AF  3D       AT 5,A-2    DEC  A
      3D                   DEC  A
81B1  1605     AT 5,A      LD   D,#05
      1802                 JR   AT D,A
81B5  1615     AT 15,A     LD   D,#15
      5F       AT D,A      LD   E,A
      1813                 JR   AT D,E

This subroutine will erase the previous image of a car from the
screen (if one exists) and moves the print position one square
down ready to re-print the car having moved forward, if necessary.
It requires D,E be the PRINT AT co-ordinates of the
existing position of the car.

81BA  CDCD81   ERASE-CAR   CALL AT D,E         Print at D,E if on screen
      300D                 JR   NC,BANANA      Jump if not on screen
      3E11                 LD   A,"paper"
      D7                   RST  #10
      3E07                 LD   A,"white"
      D7                   RST  #10            Print PAPER 7;
      0605                 LD   B,#05
      3E20     APPLE       LD   A,"space"
      D7                   RST  #10            Overwrite with spaces
      10FB                 DJNZ APPLE
      14       BANANA      INC  D              Move AT co-ordinates to next line
               AT D,E      $                   Move print position accordingly

This subroutine moves the print position to AT co-ordinates D,E if
this is on the screen. If this is not on the screen, the subroutine
returns NO CARRY.

81CD  7A       AT D,E      LD   A,D
      D604                 SUB  #04
      FE12                 CP   #12
      D0                   RET  NC             Return if not on screen
      3E16                 LD   A,"at"
      D7                   RST  #10
      7A                   LD   A,D
      D7                   RST  #10
      7B                   LD   A,E
      D7                   RST  #10            Print AT D,E;
      37                   SCF                 Indicate coordinates on screen
      C9                   RET

This next subroutine is equivalent to PRINT AT 15h,A;"graphic shift 8";.

81DC  CDB581   AT 15,A-G   CALL AT 15,A        Print at 15h,A;
      3E10                 LD   A,"ink"
      D7                   RST  #10
      3E00                 LD   A,"black"
      D7                   RST  #10            Print INK 0;
      3E8F                 LD   A,"graphic shift 8"
      D7                   RST  #10            Print "graphic shift 8";
      C9                   RET

The next subroutine will print either the human car of the computer
car, depending on which address it is called from.

81E9  118081   PR-HC       LD   DE,H-CAR       Point to start of string
      1803                 JR   +03
81EE  117181   PR-CC       LD   DE,C-CAR       Point to start of string
      010D00               LD   BC,#000D       BC:=length of string
      3E11                 LD   A,"paper"
      D7                   RST  #10
      3E07                 LD   A,"white"
      D7                   RST  #10            Print PAPER 7;
      C33C20               JP   PR-STRING      Print the appropriate car

The next subroutine decrements either the human's distance to
go or the computer's distance to go. If this distance reaches
zero, then the screen is inverted. The subroutine requires that HL
points to the last byte of the string in question (ie. 81A2 for the
computer, 81AD for the human).

81FD  E5       DEC-DIST    PUSH HL             Stack address of last byte
      7E       PEAR        LD   A,(HL)         A:=next digit
      FE30                 CP   "0"
      2005                 JR   NZ,ORANGE      Jump unless digit equals zero
      3639                 LD   (HL),"9"       Change digit to nine
      2B                   DEC  HL             and consider next digit left
      18F6                 JR   PEAR
      35       ORANGE      DEC  (HL)           Decrement digit
      E1                   POP  HL             HL:=address of last byte
      E5                   PUSH HL
      0604                 LD   B,#04
      3E30                 LD   A,"0"
      BE       STRAWBERRY  CP   (HL)           Check whether distance has
      2B                   DEC  HL             reached 0000
      2011                 JR   NZ,PEACH       Jump if not
      10FA                 DJNZ STRAWBERRY
      210040               LD   HL,D-FILE      Point to 1st byte of screen
      7E       LEMON       LD   A,(HL)
      EEFF                 XOR  #FF
      77                   LD   (HL),A         Invert next byte
      23                   INC  HL             Point to next byte
      7C                   LD   A,H
      FE58                 CP   #58            Continue until end of screen
      20F6                 JR   NZ,LEMON       reached
      CF                   RST  #08            Return to BASIC
      FF                   DEFB #FF
      E1       PEACH       POP  HL             HL points to last byte
      01F6FF               LD   BC,#FFF6
      09                   ADD  HL,BC          HL points to first byte
      010B00               LD   BC,#000B       BC:=length of string
      EB                   EX   DE,HL          DE:=address of string
      C33C20               JP   PR-STRING      Print the string

This next subroutine finds the position of the racetrack walls at
any point on the route. Referring to the diagram in Fig.1, the 
subroutine finds B and C assuming that L is known.

8230  E5       EDGES       PUSH HL             Stack the initial value of H
      2680                 LD   H,#80          HL points to byte in
                                               RACETRACK data
      7E                   LD   A,(HL)
      1F                   RRA
      1F                   RRA
      1F                   RRA
      1F                   RRA
      E60F                 AND  #0F            Isolate 1st hex digit
      47                   LD   B,A            Assign B as required
      7E                   LD   A,(HL)
      E60F                 AND  #0F            Isolate 2nd hex digit
      C610                 ADD  A,#10
      4F                   LD   C,A            Assign C as required
      E1                   POP  HL             Restore H
      C9                   RET

This next subroutine tests whether or not a car has crashed. It
requires that D, E, H and L are assigned as in Fig.2 (where car 
one is the car being tested, and car two is the other car). It
returns ZERO if the car has crashed, NON-ZERO if the car has not
crashed.

8243  CD3082   CRASH-TEST  CALL EDGES          Assign B and C to indicate
                                               position of racetrack walls
      7C                   LD   A,H
      B8                   CP   B              Test for collision with left-
      C8                   RET  Z              hand wall
      B9                   CP   C              Test for collision with right-
      C8                   RET  Z              hand wall
      7D                   LD   A,L
      BB                   CP   E
      C0                   RET  NZ             Exit unless level with other car
      7C                   LD   A,H
      92                   SUB  D              A:=distance between cars
      C604                 ADD  A,#04
      FE09                 CP   #09            Are they in collision range?
      3802                 JR   C,LIME         Jump if so
      A7                   AND  A              Reset zero flag
      C9                   RET                 and exit
      BF       LIME        CP   A              Set zero flag
      C9                   RET                 and exit

This next subroutine checks whether or not the human car has
crashed. If so, then the screen will flash and the game will
be over.

825A  2AAE5C   HCRASH-TEST LD   HL,(HC)        HL:=position of human car
      ED5BB05C             LD   DE,(CC)        DE:=position of comp car
      CD4382               CALL CRASH-TEST     Test for a crash
      C0                   RET  NZ             Return unless crashed
      210058               LD   HL,ATTRS       HL points to attribute file
      CBFE     MELON       SET  7,(HL)         Flash next square
      23                   INC  HL             Point to next attribute
      7C                   LD   A,H
      FE5B                 CP   #5B            Repeat for whole of
      20F8                 JR   NZ,MELON       attribute file
      CF                   RST  #08
      FF                   DEFB #FF

This subroutine checks whether or not the Space key is depressed
at any instant. It returns NO CARRY if the Space key is pressed,
and CARRY otherwise.

8272  3E7F     SPACE-KEY   LD   A,#7F
      DBFE                 IN   A,(#FE)        Scan segment 7 of keyboard
      1F                   RRA                 Move SPACE bit into Carry
      C9                   RET

The purpose of this next subroutine is to print a space character
(a white square).

8278  3E11     PR-SPACE    LD   A,"paper"
      D7                   RST  #10
      3E07                 LD   A,"white"
      D7                   RST  #10            Print PAPER 7;
      3E20                 LD   A,"space"
      D7                   RST  #10            Print " ";
      C9                   RET

And now for the interesting parts. This subroutine moves the
human car left or right as required.

8282  3EFE     HC-LR       LD   A,#FE
      DBFE                 IN   A,(#FE)        Scan segment 0 of keyboard
      1F                   RRA                 Move Caps Shift bit into Carry
      3015                 JR   NC,GRAPE       Jump if Caps Shift pressed
      CD7282               CALL SPACE-KEY
      D8                   RET  C              Return unless Space pressed
      3AAF5C               LD   A,(HC-H)       A:=horizontal co-ordinate
                                               of centre of human car
      CDAE81               CALL AT 5,A-3       Print AT 5,A-3;
      CDE981               CALL PR-HC          Print human car
      CD7882               CALL PR-SPACE       Print space
      FD3575               DEC  (HC-H)         Change horizontal co-ordinate
      18BC                 JR   HCRASH-TEST    Check for a crash
      CD7282   GRAPE       CALL SPACE-KEY
      D0                   RET  NC             Return if both Caps Shift
                                               and Space pressed together
      3AAF5C               LD   A,(HC-H)       A:=horizontal co-ordinates
                                               of car
      CDAF81               CALL AT 5,A-2       Print AT 5,A-2;
      CD7882               CALL PR-SPACE       Print space
      CDE981               CALL PR-HC          Print human car
      FD3475               INC  (HC-H)         Change horizontal co-ordinate
      18A7                 JR   HCRASH-TEST    Check for a crash

This subroutine assigns A, B and C as in Fig.1. A returns the
position of the exact centre of the racetrack at that point. The
subroutine also returns ZERO if the car is already at the centre,
CARRY if the car is to the right of centre, and NO CARRY if
the car is to the left of centre. The subroutine requires H and L
to be previously assigned.

82B3  CD3082   CENTRE      CALL EDGES          Assign B and C as required
      78                   LD   A,B
      81                   ADD  A,C
      CB3F                 SRL  A              A:=(B+C)/2
      BC                   CP   H              Assign flags
      C9                   RET

This next subroutine works out the print position of the computer's
car. It assumes that at the start of the routine HL contains
the co-ordinates of this car, and DE the co-ordinates of the
human car. It will also store the car's co-ordinates.

82BC  22B05C   POSN        LD   (CC),HL        Store co-ordinate
      7D                   LD   A,L            A:=vertical co-ordinate
      93                   SUB  E              A:=vertical distance between cars
      C605                 ADD  A,#05          A:=Y co-ordinate of print postn
      57                   LD   D,A
      5C                   LD   E,H            E:=position of centre of car
      1D                   DEC  E
      1D                   DEC  E              E:=X co-ordinate of print postn

82C7  C9                   RET                 [Undefined in the magazine. JG.]

This next subroutine moves the computer car left or right as
required. It identifies two different cases: (i) if the human car is in
the vicinity, and (ii) if the human car is not in the vicinity. Each
case uses its own algorithm.

82C8  2AB05C   CC-LR       LD   HL,(CC)
      ED5BAE5C             LD   DE,(HC)
      7B                   LD   A,E            A:=vertical co-ordinate of
                                               human car
      95                   SUB  L
      3C                   INC  A
      FE10                 CP   #10
      3805                 JR   C,PINEAPPLE    Jump if human in vicinity
      CDB382               CALL CENTRE         BC:=wall positions
      1812                 JR   GRAPEFRUIT     surrounding computer car
      EB       PINEAPPLE   EX   DE,HL
      CDB382               CALL CENTRE         BC:=wall positions
      EB                   EX   DE,HL          surrounding human car
      7A                   LD   A,D
      3805                 JR   C,MANGO        Jump if human car is to the
                                               right of centre
      81                   ADD  A,C
      C604                 ADD  A,#04
      1803                 JR   PLUM
      80       MANGO       ADD  A,B
      D604                 SUB  #04
      1F       PLUM        RRA                 A:=centre of largest gap
      BC                   CP   H
      C8       GRAPEFRUIT  RET  Z              Return if no movement required
      3802                 JR   C,GOOSEBERRY   Jump if left movement required
      24                   INC  H
      24                   INC  H
      25       GOOSEBERRY  DEC  H              H:=new co-ordinate of centre
                                               of car
      08                   EX   AF,AF'
      CD4382               CALL CRASH-TEST     Test for crash
      C8                   RET  Z              Don't move if it would cause
                                               a crash
      CDBC82               CALL POSN           Find print position of car
      08                   EX   AF,AF'         Restore flags
      380B                 JR   C,DAMSON       Jump if left movement required
      1D                   DEC  E
      CDCD81               CALL AT D,E         Print AT D,E; (if on screen)
      D0                   RET  NC             Return if off screen
      CD7882               CALL PR-SPACE       Print a space
      C3EE81               JP   PR-CC          Print computer car and exit
      CDCD81   DAMSON      CALL CALL AT D,E    Print AT D,E; (if on screen)
      D0                   RET  NC             Return if not on screen
      CDEE81               CALL PR-CC          Print computer car
      C37882               JP   PR-SPACE       Print a space and exit

This next subroutine moves the human car downwards.

8313  1605     HC-DOWN     LD   D,#05
      FD5E75               LD   E,(HC-H)
      1D                   DEC  E
      1D                   DEC  E
      CDBA81               CALL ERASE-CAR      Overwrite old car
      CDE981               CALL PR-HC          Print new car below it
      FD3474               INC  (HC-V)         Change vertical co-ordinate
      CD5A82               CALL HCRASH-TEST    End game if crashed
      21AD81               LD   HL,DISTH+0A
      CDFD81               CALL DEC-DIST       Decrement distance to go
      0613                 LD   B,#13
      CD000E               CALL CL-SCROLL      Scroll lower part of screen
      3AAE5C               LD   A,(HC-V)
      C611                 ADD  A,#11
      6F                   LD   L,A            L:=vertical co-ordinate of
                                               new line visible
      CD3082               CALL EDGES          BC:=wall positions at this point
      78                   LD   A,B
      3D                   DEC  A
      3D                   DEC  A
      CDDC81               CALL AT 15,A-G      Print left wall
      79                   LD   A,C
      3C                   INC  A
      3C                   INC  A
      C3DC81               JP   AT 15,A-G      Print right wall and exit

And this subroutine moves the computer car downwards.

8346  2AB05C   CC-DOWN     LD   HL,(CC)
      2C                   INC  L              L:=new vertical co-ordinate
      ED5BAE5C             LD   DE,(HC)
      CD4382               CALL CRASH-TEST
      C8                   RET  Z              Exit if this move would crash
      CDBC82               CALL POSN           DE:=PRINT AT co-ordinates
      15                   DEC  D
      CDBA81               CALL ERASE-CAR      Overwrite previous car
      DCEE81               CALL C,PR-CC        Print new car if on screen
      21A281               LD   HL,DISTC+0A    Point to last byte of string
      C3FD81               JP   DEC-DIST       Decrement distance to go
                                               and exit

The overall computer's move is therefore produced by the
following subroutine.

8362  CD4683   MOVE-CC     CALL CC-DOWN
      C3C882               JP   CC-LR

The following routine tests whether or not the accelerator
(Symbol Shift) key is pressed, and exits if it is not,
after a short pause.

8368  CD7282   MOVE-HC-A   CALL SPACE-KEY      A:=scan of keyboard segment 7
      1F                   RRA                 Move Symbol Shift bit into Carry
      3009                 JR   NC,MOVE-HC     Jump if Symbol Shift pressed
      010008               LD   BC,#0800
      0B       DELAY       DEC  BC
      78                   LD   A,B
      B1                   OR   C
      20FB                 JR   NZ,DELAY
      C9                   RET
               MOVE-HC     $

And now the overall human's move can be produced, thus:

8377  CD1383   MOVE-HC     CALL HC-DOWN
      C38282               JP   HC-LR

The whole program may now be written. This is the start of the
program - USR should point to this address.

837D  213030   START       LD   HL,#3030       H:=L:="0"
      229481               LD   (TIME+07),HL
      229681               LD   (TIME+09),HL   TIME:="0000"
      22A181               LD   (DISTC+09),HL
      22AC81               LD   (DISTH+09),HL
      213230               LD   HL,#3032       H:="0", L:="2"
      229F81               LD   (DISTC+07),HL  DISTC:="2000"
      22AA81               LD   (DISTH+07),HL  DISTH:="2000"
      210013               LD   HL,#1300
      22AE5C               LD   (HC),HL        Assign initial human co-ords
      260C                 LD   H,#0C
      22B05C               LD   (CC),HL        Assign initial comp co-ords
      AF                   XOR  A
      323C5C               LD   (TVFLAG),A     Print to upper part of screen
83A4  016600               LD   BC,#0066
      110081               LD   DE,STR1
      CD3C20               CALL PR-STRING      Print information window
      0612                 LD   B,#12
      C5       CHERRY      PUSH BC
      010800               LD   BC,#0008
      116681               LD   DE,STR2
      CD3C20               CALL PR_STRING      Print walls
      C1                   POP  BC
      10F3                 DJNZ CHERRY
      011F00               LD   BC,#001F
      116E81               LD   DE,STR3
      CD3C20               CALL PR-STRING      Print cars
      CD6283   MAIN-LOOP   CALL MOVE-CC
      CD7783               CALL MOVE-HC
      CD6283               CALL MOVE-CC
      CD6883               CALL MOVE-HC-A
      CD6283               CALL MOVE-CC
      CD7783               CALL MOVE-HC
      CD6883               CALL MOVE-HC-A
      219781               LD   HL,TIME+0A     HL:=points to last byte of TIME
      7E       TOMATO      LD   A,(HL)         A:=next digit
      FE39                 CP   "9"
      2005                 JR   NZ,RASPBERRY
      3630                 LD   (HL),"0"
      2B                   DEC  HL
      18F6                 JR   TOMATO
      34       RASPBERRY   INC  (HL)           Increase digit
      118D81               LD   DE,TIME
      010B00               LD   BC,#000B
      CD3C20               CALL PR-STRING      Print TIME string
      18D2                 JR   MAIN-LOOP


--
Another Fine Product transcribed by:
Jim Grimwood (jimg@globalnet.co.uk), Weardale, England
--
