ZX81 Tic-Tac-Toe

See all articles from Update July 1994
Author(s): Albert Rodriguez
Publication: Update Magazine
Pub Details: Update July 1994
Date: July 1994
Pages: 13-16

Copyright (C) 1983

DOCUMENTATION

PART II

To clearly know what is being discussed next, the reader should have nearby a copy of the program list and its declarations (see below). The actual data stored within certain arrays in the variable store is not necessary to understand what follows. (A complete listing of the program, declarations and array content, are available for $6.20, P&H included, to whomever may decide to key in this program themselves rather than purchase it in cassette form for $12.00. Foreign buyers add $2.00 more for the cassette and $1.00 more for the listing and materials).

The program, on tape, is not listable on the screen. This precaution was taken so that a user would not accidentally disrupt the program if he/she happened to gain access to the code area of the program. To avoid reloading the program, a user, whenever he/she has access to this area, should key in GOTO 7 to restart the game (see Profile sheet for instructions about how to stop and re-start this program). No-money-back guarantee are the terms applicable to whomever buys this program in cassette form or not.

The program has the LOAD name: “TTT”. When storing a program in cassette, it is better to give it a name, specially when the tape contains other different programs. The procedure is, of course, to use a REM statement with the name of the program within a pair of quotations (see the Chapter in the User Manual regarding LOAD/SAVE).

The program is self-running and this is possible because of line number 5. This line permits the program to begin execution immediately after it is loaded. It also eliminates the danger of a user accidentally erasing any data contained in the variable store by entering RUN. Any program written with a SAVE command, after it is loaded, will begin to execute from the first line after this command.

Lines 7 through 12 are in charge of initializing the character array C$(9). This array is initialized before the beginning of each game with the numbers 1 through 9. These values are what first appear in each square of the game board and permit a player to make a move during a game. The way the loop is structured is interesting from a programming viewpoint. This way of initializing a character array is faster and consumes less memory than, say, using LET and listing each individual array element in consecutive order.

In lines 16 through 18 the number array N(9) is initialized with zeroes before each new game. This array appears in the driver by the name of COUNTR. This array is used by this routine to store how many times during a game a particular move is made. This is important because it prohibits any one square in the game board from being used more than once during an actual game.

Line 34 initializes the number variable CTR, which is used to keep track of the total number of moves made during a game. When CTR equals nine, then it cues the driver called DRW. This routine does what its name says: given 9 consecutive moves and no winner, the game must end in a draw.

Line 35 is really interesting. This line lets the character variable F$ be used further down the program by pre-assigning it at the beginning of each game. F$, in this program, acts as a “flag;” it is what tells the computer that a game has finished in either a win or a draw.

Lines 112 through 120 compose what is actually the main program within my overall program. It has 5 subroutines and two drivers (see declarations below). After the last driver, at line 119, terminates execution (i.e., when a game being played ends either in a win or a draw), then line 120 permits the start of a new game by letting the program reexecute again from line 7. This way of structuring a program, which involves integrated multi-functional routines, is convenient in that it first allows a programmer to outline the principal areas of his/her program, then, the rest of the time can be devoted to writing each specific section of the overall work. (I credit this suggestion to Dr. William T. Kraynek, Associate Professor, Mathematical Sciences Department, Florida International University, Tamiami Campus, Miami, Florida).

From lines 1001 to 1019 two things happen. Subroutine MSG prints a message on the screen for three seconds, urging the player to beat the computer. After clearing the screen, another set of instructions appear for 12 seconds, informing the user how to stop and restart the game. The length of time that each message appears can be reduced by pressing any key, except the space key, while each message is being displayed. These messages are displayed once per each new game.

Lines 2001 through 2012 is the subroutine BRD. This section prints on screen, once per game, the playing board. The vertical and horizontal lines of the board are made of the characters “I” and “-“, respectively. The routine is made of two For/Next loops and a “counter” by the name of C. The variable C is what informs the computer that three sets of vertical lines and two sets of horizontal lines have been printed and that it may proceed with its next instructions.

Lines 3001 through 3015 is the subroutine PSTN. This name, actually, is an abbreviation for the word “position.” This routine is continually called upon to display the actual moves that are either made or remain to be made before and during a game. The row coordinates, from top to bottom, are 2, 7, and 11; the column coordinates, from left to right, are 2, 7, and 13. This routine prints the content of each element in the array C$(9) at pre-determined locations on the game board, in row form, beginning with the highest and ending with the lowest row.

Lines 4003 through 4010 is the subroutine INSTRCS, which stands for “instructions.” Once, per game, this section displays on the screen the name of the game, the year it was copyrighted, its author’s name, who gets to play with either of the characters (in inverse video) “O” and “X”, and who gets the first move. The player is assigned “O” and it is he/she who always gets to make the first move. Once a game begins, the instructions at the bottom of the screen, about who moves with what, and who moves first, are erased.

Lines 5000 through 5017 compose the subroutine RDAPRV. The basic functions of this routine are to read in the move made by a player during a game, then to determine if the move is included within the only acceptable type of moves that should be made during a game. Only the numbers 1 through 9 are acceptable moves. This routine is what is called a “search” routine. It seeks to match what is entered with what can only be an acceptable move. If the move is acceptable, the game proceeds with the rest of the instructions in the program. If the move entered is unacceptable, then, three things happen: an error message is displayed for two seconds, it self-erases, and the player is allowed another move. Whether or not a move that is made is acceptable, what is entered by a player is always displayed on the screen to let him know exactly what he did enter.

The first driver in the program appears in line 6000 through 6018. Its name is COUNTR. Its function is that it does not allow a player to make the same move, he/she or the computer makes, more than once. It too acts like a search routine by determining which acceptable move was entered; then, it stores in the number array N(9) the number of times that move was made. If a move in a game is made twice or more, an error message is displayed for two seconds, self-erases and allows another move by calling subroutine RDAPRV. If the move that was made has not been made before, the program then continues executing.

Lines 7001 through 7011 comprise the driver GAME. This routine has this name because it actually acts as the central processor of the program. An explanation of its intricate functions should make all other remaining sections of this program understandable to the reader. Its functions can be subdivided basically into six areas. First, after a player makes a move, GAME performs a search for the location on the game board that the player has chosen to move in (lines 7001-7003). Second, it assigns the character “O” to this location. Third, at line 7005 it calls the driver IN (lines 7012-7015). IN is responsible for three things: printing the “O” character in its chosen location by calling subroutine PSTN; finding what is where on the game board by calling subroutine RCD, lines 7026-7053 (RCD determines the entire code-sum of all characters at the nine locations on the game board. It does this in terms of adding the three rows, three columns, and both a top-right to bottom-left and a top-left to bottom-right diagonals. It performs this operation every time a move is made by the player); checking to see if the game has ended in a draw by calling driver CHK, lines 7054-7085 (a draw is only possible in this program if all nine possible moves are made. Since the player is the only one to make the ninth move in any game, CHK searches for a draw, each time after the player makes its next move). If a draw does occur, then, GAME returns to the main program for the start of a new game. If a draw does not occur, then, fourth, the subroutine PKMV (lines 7100-7160) is called. PKMV is the arithmetic/logic module of the overall program. After subroutine RCD has determined the code-sum of the playing board, PKMV searches for the most optimal move that the computer can make under the circumstances. The total number of optimal moves that can be made by moving either second, fourth, sixth and eighth (which are the turns allowed the computer versus the five odd turns allowed the player) are, in this program, only 305 moves. After picking its best move from among these 305 moves, then, fifth, the computer (by calling the driver OUT) does three things: it searches for the location on the game board that the computer has chosen to move in; it assigns the character “X” to the location on the board that was pre-determined by subroutine PKMV; it prints the said character in its proper location, and it checks for a win in the game. (The computer checks for a win in a game only after each time that it makes its move, since it has always the last move prior to the ninth move, and such move, if ever made, will always result in any game ending in a draw, given that this program was designed to always let the computer move optimally against its opponent.) If a win is obtained, then driver CHK will execute the corresponding driver routine that draws a black graphic line wherever three characters of the same type appear along a row, column or diagonal (these routines can be found from lines 9003 through 9077). After displaying a prompt along with the preceding line, then driver GAME returns to the main program to set up a new game. If no win is obtained, then, sixth, the program calls driver SETUP. This routine clears, from the bottom of the screen, all information about the move that was last made by the player along with any instructions appearing at the beginning of a game and between moves made by the player. SETUP, next, calls the driver COUNTR to record the move made by the computer. Later it displays a prompt message that lets the player know that he/she can make his/her next move. Finally, it calls subroutine RDAPRV, then driver COUNTR, before returning to the driver GAME and re-executing this section all over again. The process of functions just described about the driver GAME continue until a game ends either in a win or a draw. At this time, the driver returns to the main program and the latter re-executes from line 7 onward, to start a run of a new game.

Ultimately, after finishing this program, I can confidently say that the ZX81 is an excellent medium with which to learn good programming habits given, of course, certain clearly definable parameters. It is definitely a resourceful workhorse with which someone can accomplish any fundamental task of producing entertaining and practical software. It is hoped that this paper may enhance the knowledge of its users as well as serve as a tribute to a very fine machine.


“ZX81 TIC-TAC-TOE” PROGRAM DECLARATIONS

1. Number Arrays: N(9), L(8), T(215), U(22), S(13), B(16), F(15).

2. Character Arrays: C$(9), M$(215), R$(22), N$(22), A$(13), O$(13), D$(16), E$(16), G$(15), H$(15).

3. Variable Constants: E=2, F=7, G=13, SCR=567, OVER=7070.

4 Number Variables: A, B, C, D, H, I, J, K,LN, P, Q, R, S, W, X, Y.

5. Character Variables: P$, F$, I$, K$, B$, J$.

6. Drivers: COUNTR=6000, GAME=7001, IN=7012, OUT=7016, ASGN=7020, CHK=7054, DRW=9085, SETUP=8001, LINE I=9003, LINE II=9008, LINE III=9011, LINE IV=9022, LINE V=9027, LINE VI=9030, LINE VII=9044, LINE VIII=9061.

7. Subroutines: MSG=1001, BRD=2001, PSTN=3001, INSTRCS=4003, RDAPRV=5000, PKMV=7100, DSPLY=9078, PLOT I=9014, WIN=9081, PLOT II=9034, RCD=7026,

8. Keywords: REM, SAVE, PAUSE, LET, FOR/TO/NEXT, IF/AND/THEN/STEP, GOSUB/RETURN, INPUT, PLOT, GOTO, PRINT, CLS.

9. Functions: CHR$, AT, TAB, CODE.

10. Symbols: ” “, $, ,, ;, “”, +, =, ( ), -.