Home > Previous Page >  Forth: Ace for Games listing - Your Computer, March, 1983
Archive Search  
Your Computer, March, 1983, page 68
Ralph Hilton get his
teeth into Forth Games.
Have an Ace munch.
WITH FORTH now available for home computers and the release of the Jupiter Ace, users suddenly have a machine and a language ideally structured to games that are fast, involved and without the relative complexity of machine code. Forth's compact programming means one can develop and test each of the elements of the whole program as one builds it up.
The disadvantage of not being able to code from the top down, as in Basic, is overcome easily by either flowcharting the proposed program or doing a simple logical list of its component parts.
The Jupiter Ace I used for this program has an actual memory availability for user Forth words of less than 1K. This may seem very little but it gives one sufficient space to create versions of popular arcade games that contain the main features of the originals and run very close to their speeds. In fact, I found that Pac-Man written in Forth actually runs faster than the game played at the local amusement centre. As it is one of the more popular games and contains many of the building blocks one would use in other games I chose it as the example for this article.
I have included all the main points of the arcade version, except for the power pills which would take up an extra 500 bytes at a rough estimate.
I have assumed that you understand the basic words used in the Ace but include an explanation of the specific techniques involved. To conserve memory the variables and words used have short names but I comment on each separately.
The sequence for the game is as follows. First, the graphics used for the man, ghosts, dots and wall are defined and the screen created. Next the variables are initialised and the man and ghosts placed in their starting positions.
The way the man moves is broken down into the following steps. First, a check to see if an appropriate key has been pressed, and the program continues with this sequence if it has.
The Inkey function on the Ace returns to the stack the ASCII value of the key pressed.
This has to be converted into a number giving the change in position in the display file. The Ace display file is laid out in 24 rows of 32 columns, each at addresses 9216 to 9984. An up or down movement changes the memory location by 32 and a left or right movement changes it by 1. I have used these numbers to give the new location of the man.
Next the program checks to make sure the man does not bump into a wall and continues only if there is no risk of this.
Then a space is put in the man's last position, and the new position is checked to see whether or not it contains a dot. If it does, the score is incremented. If this score means that all the available dots have been eaten, the screen is refilled.
Now the man is moved to his new position which is stored in the appropriate variable. The ghost-moving section comes next. I found that this was most easily done by having a separate variable for each ghost's position which is put into the variable used by the subroutine as each ghost is moved.
The sequence for each ghost starts by checking whether the ghost should move up or down or neither according to the relative position of the man, and then makes sure that it does not hit a wall. A random generator is used to allow the ghost only limited movement - the game would be impossible if the ghost was always correct, and boring if its movement were fully predictable. When a ghost moves, the space it leaves is replaced with a space or dot as appropriate. This is done by a method which is explained fully in the actual coding. The same procedure is used for left and right movement of the ghost. If the man now occupies the same position as one of the ghosts the game ends.


Obviously all these procedures need additional subroutines to generate the random
numbers and refill the screen with dots when required.
The game is loaded in three sections to make full use of the memory but no reloading is necessary to replay.
First, the graphics section is prepared. I have assigned user graphics for the wall and dots as this makes it far easier to type in the screen itself. The graphics are placed into a section of RAM which is calculated as starting at 11264 plus the ASCII code of the character one is defining multiplied by 8. As typing in a list of binary digits is tedious I have converted all the values to decimal.


Here is the listing for the graphics section:
 : NM 36 126 219 90 126 255 126 36 ;

This word puts the values used for the ghost on to the stack. It is a separate word because it is needed several times.
 : GR 8 * 11263 +DUP 
    8 +
    DO
      i C! -1 
    +LOOP
  ;
This word takes nine numbers from the stack; the first eight define the character and the ninth is the ASCII value of the character. It makes a loop, using as its limits the sections of memory at the beginning and end of the space we want to fill. It then puts each of the numbers into its appropriate place. It is taken from the Ace manual.

 : A 85 170 85 170 85 170 85 170 1 GR  Wall
      0   0  0  24 24   0  0   0 2 GR  Dot 
     28  20  8 127  8  20 34  65 3 GR  Man 
 NM 5 GR
 NM 35 GR ;

 
When you have typed this in, A will run the routine and store the characters appropriately. This section should then be saved on tape by starting the tape player then entering

SAVE GRAPHICS

The maze display snappers and gulpers thrive in this sort of environment
Your Computer, March, 1983, page 69
You can then verify it as explained in the manual and delete it from memory using
    FORGET NM
to leave space for the next section, the game itself. For this section first enter the variables, -
0 variable A     The score.
0 variable X     The man's position.
0 variable W     Used for the position of the 
                 ghost being moved. Y and Z 
                 are moved to W as needed.
0 variable Y     The positions of the two
0 variable Z     ghosts.
Only two ghosts have been used - a third would fit in the memory but with the speed at which the program runs would make it almost impossible to win. 0 variable SD This holds the random number. 0 variable K This sets the difficulty level. The subroutines used by the main words need to go in next so that the compiler recognises them when called from the upper words.
 : B This fills the screen with dots wherever 
   there is no wall and is used whenever the 
   dots are all eaten.
   9856 9216
   DO Sets a loop to go over the whole 
   screen.
   i c@ 1 = 0 = Checks that the space does 
   not contain a wall.
   IF
     2 i c! Puts a dot there if it does not. 
   THEN
 LOOP
 5 Y @ c! 5 Z @ c! Puts the ghosts back on 
                   the screen. 
 Y @ Z @ = IF 8 Y @ c! THEN
When a ghost leaves a position then 3 is subtracted from the ASCII value of the character so that it is left as it was; dots use 2 and spaces 32 so the ghost is given values 5 and 35, and 3 is added to the ASCII when the ghost is moved there. Here if the two ghosts
are in the same place when all the dots are eaten then 2 + 3 + 3 has to go in that space giving a dot when they both leave.
K @ DUP 2 > IF 1- THEN K ! Increases the difficulty level if it is not at maximum;
 : RND This is taken from the Ace manual and 
       covered there.
   SD @ 75 u* 75 0 D + 
   OVER OVER u< - - 1-
   DUP SD!
      u* SWAP DROP ;
 : CPS
This is used to add 3 to the position that the ghost moves into and add 253 when it leaves. Adding 253 achieves the same as taking away 3 as one is using a single byte.
   SWAP OVER c@ + SWAP c! ;
Next the main routines are typed in. M is the routine for moving the man complete with associated checks and score changing. The comments could be typed into the machine but would take up valuable memory and so should be omitted.
 : M
   INKEY DUP DUP
   52 >SWAP 57 <AND
   This checks that the key is one of
   the cursor 
   control keys 5 to 8; these have ASCII
    values 53 through 56.
	
	
 IF
   52 - DUP Puts the number into the
        range 1 to 4
   4 MOD 1 > 31 * 1 + MOD gives the
     remainder after dividing by the
     preceding number so cursor keys
	 6 and 7 will leave 32 on the 
	 stack while keys 5 and 8 leave
	  1 on the stack.
 SWAP 3 < -2 * 1 + * This multiplies 
                        the 32 or 1 obtained
                        by -1 if keys 5 or
                        6 were pressed.
 X @ + DUP c@ DUP Leaves on the stack 
   the new value of X and two copies of 
   what X currently contains.
 1 = 0 =
 
 IF Continue only if one will not collide
   with a wall.
   32 X @ c! Put a space in the old position 
             of the man.
   2 =	
   
  IF Check if the man is eating a dot.
   A @ 1+ DUP DUP A ! 21 O AT .
   326 MOD 0= IF B THEN Add 1 to the
   score; print the score; check whether all
   the dots have been eaten and refill 
   screen if more left.
  THEN
   
  3 OVER c! X ! Put the man in the new
                position and store the
                value of X.
   99 40 BEEP 
  ELSE
   DROP DROP Removes unused numbers 
            from stack.
   THEN 
  ELSE 
   DROP 
  THEN ;
The routines G and H are used together. H used twice by G to actually move the ghost. l should be typed in before G.
  : G W @ DUP X @ 16 - <32 * Compares
    the values of X and W to see whether or
    not the ghost should move down. It puts
    32 on the stack if it should.
    SWAP X @ 16 + > - 32 * + H puts - 32
       on the stack if the ghost should move
       up, and then uses H to move it appropriately.
    W @ 32 MOD X @32 MOD > - 2 * 1 + H
    Puts 1 or -1 on the stack after comparing
    the horizontal positions of X and W to 
    move ghost left or right.
  : H W @ + DUP c@ Finds the new position
                   of the ghost.
    1 = 0 = Makes sure that it is not in
             a wall
    K @ RND 0= AND Uses the difficulty
                   variable K and RND to
                   limit the probability of
                   the ghost's movement
 IF
   253 W @ CPS Puts a space or dot where
               the ghost was.
   3 OVER CPS Puts the ghost on the
              screen.
   W ! Stores the new position of the ghost
 ELSE
  DROP 
 THEN ;
The routines are now linked together by the program word which is Run.
 : RUN FAST
    9249 X ! 9339 Y ! 9479 Z ! Sets initial
                    positions of man and ghosts.
  0 A ! Zeros score. 6 K ! Sets initial
                           difficulty. 
  B                   Fills the screen with dots.
  39249 c!       Puts the man on the screen. B
  ;B                       puts on the ghosts.
  BEGIN                 The main control loop.
    M                                Move man.
    Z @ W ! G W @ Z !    Moves the ghost Z by 
      putting its value into W which is used
      by H.
    Y @ W ! G W @ Y !     Does the same for Y.
    X @ DUP Y @ = SWAP Z @ = OR 
  UNTIL Compares X to Z and Y. If either 
        equal X then the procedure ends 
        otherwise it goes back to Begin.
  SLOW
  999 999 BEEP ;
The game is stored entering
       SAVE RUN 
The screen is created and, then saved as a series of bytes. Enter
     : Z INVIS CLS."
leaving enough space between the CLS and ." so that there is only one space left at the end of the line. Use Shift 9 to put the Ace in graphics mode then, using A for the wall and B for the dots, type in the 20 lines of screen per the attached diagram. On the next line type " 5 -
Entering Z will now give you the screen in the correct position and it can be saved on to tape by entering
     8192 768 BSAVE screen 
Start the tape and press enter. Clear the memory with
     FORGET Z
The program is now loaded with

     LOAD GRAPHICS
     A
     FORGET NM

Enter these three together and then start the tape. Stop the tape when you see the cursor.
    INVIS LOAD RUN 0 0 BLOAD SCREEN
Enter this and then restart the tape. Stop it when the screen is full. You can now play the game by entering Run.


If you have queries about the program I can answer them. Write to me with stamped, addressed envelope at xx Grimston Avenue, Folkestone, Kent.