Maze Race
Mike Peterson
Cheyenne, WY
With versions of this excellent game for PET/CBM Microsoft and Atari BASICs, this should provide hours of amusement. It will run on computers with 8K or more of RAM memory.
I was impressed by the Maze algorithm that appeared in COMPUTE!, December, 1981, #19. After watching the maze form several times, I had an idea for a program that incorporated the maze algorithm.
First, I modified the routine so that two symmetrical mazes would be formed. One starts in the upper left corner of the screen while the other starts in the lower right. By POKEing a 32 ($20) in the center of the screen, identical (but opposite) mazes are formed. As one goes left, the other goes right. And as one goes down, the other goes up. This continues until the screen is full and the algorithm completed. The mazes are then linked together in the screen's middle and a "target" character is POKEd in the center.
Now, depending upon your choice of options during initialization, you race against a human opponent (or the computer) to the center of the maze. If you select the two-player option, I strongly recommend the use of joysticks. The program will process both player's joystick input during each cycle. On the keyboard, one player can prevent the other's input by holding a key pressed.
With the one-player version, you will always be on the right and use the right joystick or the number pad to control your movement. The computer will not begin until after your first input. Since the computer doesn't know the best path to follow, and strays down dead-end paths, it is easy to beat. My daughter loses just often enough to keep her interested and make each game a new challenge.
Through experimentation with the joysticks, I found that the left joystick sets the high four bits and the right joystick sets the low four bits of the byte at address 59471 ($E84F). The byte, A, can be separated into a left value and a right value with : A= PEEK(59471) : L = (A/16) AND 15 : R = A AND 15. If both joysticks are in the same position, L = R. An array with 15 elements can be used to determine the new position of each player, move there if not off the screen, and then erase the previous position. The following table shows all possible joystick values, positions, and screen movement offsets:
Lor R | POSITION | OFFSET |
0 | not used | 0 |
1 | left/button | -1 |
2 | right/button | + 1 |
3 | button | 0 |
4 | not used | 0 |
5 | left/up | -41 |
6 | right/up | -39 |
7 | up | -40 |
8 | not used | 0 |
9 | left/down | +39 |
10 | right/down | +41 |
11 | down | + 40 |
12 | not used | 0 |
13 | left | -1 |
14 | right | + 1 |
15 | center | 0 |
Note: with the button pressed only the row can be determined. |
Another feature of this program is the "flipping" of the marker that arrives in the center of the screen's maze first. This is performed by XORing the byte in the center screen address with 128 ($80). The result of an XOR with 128 is that RVS characters become normal characters and vice versa.
Since BASIC doesn't provide us with an XOR function, I consulted a Boolean Algebra text and found the AND, OR, and NOT gates used to produce the XOR truth table. In BASIC, XOR would be this : Y = ((X AND (NOT 128)) OR ((NOT X) AND 128)).
Program 1. Atari Version
Atari Notes After the dual maze has been generated, select the number of players (player vs. computer or player vs. player) by pressing SELECT. When ready to play, press START. To re-start the game, press START. Use joysticks plugged into jacks one and two to play. |
100 REM *** MAZE RACE *** 110 REM *** ATARI VERSION *** 120 DIM A(3):REM SET UP DIRECTION TABLE 130 A(0) = 2 : A(1)=-80 = A(2) = -2 : A(3) = 80 140 WL = 128: HL = 0: SC = PEEK(88) +256*PEEKC (89) : A = SC + 43 : C = SC + 877 150 GRAPHICS 0 : POKE 752, 1 : SETCOLOR 2, INT (16*RND(0)), 4 : POKE 712, PEEK (710) 160 FOR I = 1 TO 23170 PRINT "| |" 180 NEXT I 190 REM GENERATE THE MAZE! 200 POKE A, 5 : POKE C, 2 : POKE SC + 499, HL 210 J = INT(RND(0)*4) : X = J 220 B = A + A (J) : D = C - A(J) : IF PEEK(B)<>WL THEN 240 230 POKE B, J + 1 : POKE D, J + 1 : POKE A + INT(A(J)/2), HL : POKE C-INT(A(J)/2), HL : A = B : C = D : GOTO 210 240 J = (J + 1)*(J<3) : IF J<>X THEN 220 250 J = PEEK(A) : POKE A, HL : POKE C, HL : IF J<5 THEN A = A - A (J-1) : C = C + A(J-l) : GOTO 210 260 A = SC + 43 : C = SC + 877 : J = 2 270 POKE A, 84 : POKE C, 111 : POKE SC + 459, 10 : POKE SC + 460, HL : POKE SC + 458, HL 280 DIM M(15) : FOR I = 0 TO 15 : M(I) = 0 : NEXT I : NP = 0 290 M(14) = -40 : M(13) = 40 : M(11) = -1 : M(7) = 1 : M(7) = 1 : M(10) = -41 : M(6) = -39 300 M(9) = 39 : M(5) = 41 : PLR = l 310 DIM MS$(20) : MS$ = "Maze Race" : FOR I = 1 TO LEN(MS$) : POSITION 0, I + 5 : ? MS$(I, I) : NEXT I 320 POSITION 9, 23 :? "One Player Vs. Computer"; 330 K = PEEK(53279) : IF K = 7 THEN 330 340 IF K = PEEK(53279) THEN 340 350 IF K = 6 THEN 400 360 IF K = 3 THEN 330 370 NP = 1 - NP : IF NP = 0 THEN 320 380 POSITION 9, 23:? " Player Vs. Player"; 390 GOTO 330 400 PLR = 1-PLR 410 IF PLR = 0 OR NP THEN 440 420 B = A + INT(A(J)/2) : Y = PEEK(B) : IF Y = HL OR Y = 10 THEN POKE B, 84 : POKE A, HL : A = B : J = (J + 2)-4*(J>1) 430 J = (J-l) + 4*(J = 0) : GOTO 480 440 IF PLR THEN 470 450 D = C + M(STICK(PLR)) : IF PEEK(D) = HL OR PEEK(D) = 10 THEN POKE D, 111 : POKE C, HL : C = D 460 GOTO 480 470 B = A + M(STICK(PLR)) : IF PEEK(B) = HL OR PEEK(B) = 10 THEN POKE B, 84 : POKE A, HL : A = B 480 REM SOMEONE WON 490 IF A<>SC + 459 AND C<>SC + 459 THEN 400 500 P = PEEK(SC + 459) : PF = 0 510 FOR I = 1 TO 50 : POKE SC + 459, P + 128*PF : PF = 1-PF : NEXT I 520 REM 530 IF C = SC + 459 THEN 560 540 IF NP THEN POSITION 9, 23 : ? " Player 2 Won! "; : Goto 580 550 POSITION 9, 23 : ? " I WIN! " : GOTO 580 560 IF NP THEN POSITION 9, 23 : ? " Player 1 Won! "; : GOTO 580 570 POSITION 9,23 : ? " You win! "; 580 IF PEEK( 53279)<>6 THEN 580 590 RUN
If you want to make Maze Race (for Atari) more challenging, add the following lines. They cause the screen to blank out during the maze generation, preventing a "sneak preview." A side effect is that this decreases the time necessary to generate the maze: 155 POKE 559,0 325 POKE 559,34 |
Program 2. Microsoft Version
10 REM *** MAZE RACE *** 20 REM * MIKE PETERSON * 30 REM ** CHEYENNE, WY ** 40 REM 50 REM MAZE GENERATOR BY CHARLES BOND 60 REM COMPUTE! : DECEMBER, 1981 70 REM 80 GOTO 120 90 POKE 167,0 100 GETZ$ : IFZ$ = ""THEN 100 110 PRINTZ$ : Z = VAL (Z$) : POKE 167, 1 : RETURN 120 PRINT " {CLEAR} {05 DOWN}" : PRINTTAB (15) "MAZE RACE {02 DOWN}" 130 PRINTTAB (5) "HOW MANY PEOPLE ARE PLAYING? {LEFT}"; : GOSUB 90 : NP = Z-1 : PRINT 140 IF Z> 2 THEN PRINT TAB (5) "SORRY, ONLY 2 CAN PLAY. {DOWN}" : GOTO 130 150 IF Z = 0 THEN PRINTTAB (5) "PLEASE ENTER 1 OR. 2. {DOWN}" : GOTO 130 160 PRINTTAB (7) "ARE YOU USING JOYSTICKS ? {L LEFT}"; : GOSUB 90 : PRINT 170 IFZ$ = "Y" THEN JJ = 1 : GOTO 190 180 IFZ$ <> "N" THEN PRINTTAB (7) "PLEASE ENTER Y OR N. {DOWN} " : GOTO 160 190 IFNPTHENPRINT" {DOWN} LEFT PLAYER = Q : RIGHT PLAYER = W" : GOTO 210 200 PRINT" {DOWN} I AM THE Q : YOU ARE THE W" 210 IFJJTHENPRINT"{DOWN} USE THE JOYSTICK TO MOVE AROUND" : GOTO 250 220 IFNPTHENPRINT" {DOWN} Q USES W FOR UP, A FOR LEFT, D FOR RIGHT," 230 IFNPTHENPRINT"AND X FOR DOWN." 240 PRINT" {DOWN} W USES 8 FOR UP, 4 FOR LEFT, 6 FOR RIGHT, AND 2 FOR DOWN." 250 PRINT" {DOWN} PRESS ANY KEY TO BEGIN *{LE LEFT} "; : GOSUB 90 260 DIMM (255) : JS = 151 : IFJJTHENJS = 59471 : GOTO 290 270 M(18) = 40 : M(42) = -1 : M(41) = 1 : M(50) = -40 280 M(24) = 40 : M(48) = -1 : M(47) = 1 : M(56) = -40 : GOTO 300 290 M(7) = -40 : M(11) = 40 : M(13) = -1 : M(14) = 1300 DIM A(3): A(0) = 2 : A(1) = -80 : A(2) = -2 : A(3) = 80 : WL = 160 : HL = 32 : SC = 32768 310 BL$ = "{REV} ~ {OFF}" 320 A = SC + 81 : C = SC + 917 330 PRINT "{CLEAR}" : FOR I = 1 TO 23 : PRINT BL$ : NEXT 340 POKE A, 4 : POKE C, 1 : POKE SC + 499, HL 350 J = INT(RND (TI) * 4) : X = J 360 B = A + A (J) : D = C - A(J) : IF PEEK(B) < > WL THEN 380 370 POKE B, J : POKED, J : POKE A + A(J)/2, HL : POKE C - A(J)/2, HL : A = B : C = D : GOTO 350 380 J =(J + 1) * -(J < 3) : IF J <> X THEN 360 390 J = PEEK (A) : POKE A, HL : POKE C, HL : IF J < 4 THEN A = A - A(J) : C = C + A(J) : GOTO 350 400 POKE SC + 498, HL : POKE SC + 499, 42 : POKE SC + 500, HL : A = SC + 81 : C = SC + 917 410 POKE A, 81 : POKE C, 87 : J = 2 : K = 2 420 PP = PEEK(JS) : IF PP = 255 THEN 420 430 PP = PEEK(JS) 440 IF NP THEN 470 450 B = A + A(J)/2 : Y = PEEK(B) : IFY = HLORY = 42 THEN POKE B, 81 : POKE A, HL : A = B : J = (J + 2) + 4 * (J >1) 460 J = (J - 1) - 4 * (J = 0) : GOTO 510 470 IF JJ THEN 500 480 IF PP <> 24 AND PP <> 48 AND PP <> 47 AND PP <>56 THEN 520 490 B = A + M(PP) : IF PEEK (B) = HLOR PEEK (B) = 42 THEN POKE B, 81 : POKE A, HL : A = B : GOTO 510 500 Q = (PP/16) AND 15 : B = A + M (Q) : IF PEEK (B) = HLOR PEEK (B) = 42 THEN POKE B, 81 : POKE A, HL : A = B 510 IF JJ THEN 540 520 IF PP <> 18 AND PP <> 42 AND PP <> 41 AND PP <> 50 THEN 550 530 D = C + M(PP) : IF PEEK (D) = HLOR PEEK(D) = 42 THEN POKE D, 87 : POKE C, HL : C = D : GOTO 550 540 Q = (PP AND 15) : D = C + M(Q) : IF PEEK(D) = HLOR PEEK (D) = 42 THEN POKED, 87 : POKE C, HL : C = D 550 IF A <> SC + 499 AND C <> SC + 499 THEN 430 560 FOR I = 0 TO 99 : W = PEEK (SC + 499) : X = (WAND(NOT 128)) OR ((NOT W)AND 128) : POKE SC + 499, X 570 NEXT 580 PRINT "ANOTHER GAME ?{LEFT}"; : GOSUB 90 590 IF Z$ = "Y" THEN 320 600 IF Z$ <> "N" THEN PRINT "{02 UP}" : GOTO 580