Programming the TI
This month's article and listing continue the game program, "Solitaire", started in last month's column. Although last month's listing included enough of the game to play, all the features had not been included. This month we'll add a way to keep track of each move so you can back up if you want or have the computer replay the whole game or print the moves with a printer.
Keep in mind as you are doing your own programming that there are many ways to accomplish the same thing (and most of the time it doesn't matter which method you choose). Some ways may be more sophisticated or more efficient. In this game I selected the techniques I thought would be easiest to understand. First, let's go back and see how to tell if you are making a legal move.
A Less Complicated Array
To move a peg, you must choose a peg, then jump over one (and only one) peg into a vacant place, or hole. I decided to use an array of numbers where the number 1 represents a peg's location and the number 0 represents a hole. For each location there is a row and a column. This array is the G array. The playing area is shaped like a cross, so there are locations that cannot be used. Rather than define a smaller, more complex array, I used all the elements of the array and used the number 2 for positions off the playing area—where pegs cannot be. I needed two spots around each peg to test the valid jumps, so there are two rows and two columns beyond each peg on the playing surface. The G array thus starts with the zero elements and goes to (12,12). The DATA statements in lines 340–460 define the elements for the starting game board. The border elements contain a 2; a peg is 1; and a hole is 0.
Each position is represented by a row R and a column C. The actual row and column on the screen are calculated by lines 820-830. Lines 850-1090 blink the peg or hole position while waiting in a CALL KEY loop for an arrow key or the ENTER key to be pressed. When an arrow key is pressed, the IF statements make sure the move is still within the playing area. If the G element is a 2, the peg cannot go in that direction.
The program branches to line 1100 if the ENTER key is pressed, and line 1110 makes sure a peg is there to move. Lines 1120–1540 detect the arrow key pressed for the direction of the jump, and the IF statements make sure there is an adjacent peg, then a hole. If a jump cannot be made, there is a low tone and the program branches back to line 850. If a jump can be made, the graphics change and the G elements are updated: The peg moves to a hole and leaves a hole in the first position, and the jumped peg is removed and a hole is shown there.
Keeping Track Of The Moves
The program then branches back to the CALL KEY loop for the next move. This process continues (indefinitely). By the way, you may want to add a routine to check for the end of a game—my program just stays in this loop.
Now let's add a way to keep track of the moves. Since the locations are designated by a row number and a column number, I decided to trace the move by making (R,C) the first position and (R2,C2) the new one. These moves are in the M$ array. To simplify further, by subtracting one from the row or column number used in the G array, all locations will be one-digit numbers. Therefore, the M$ string will be a four-digit number. For example, M$(5) might be 5351, which indicates the peg in (5,3) moves to (5,1). The top row of the cross shape is row 1, and the left-most column is column 1. The center hole is (5,5).
Add line 795 to start with move 1. Line 1514 increments the number of the move. Lines 1115 and 1512 record the row and column numbers of the starting position and ending position of valid moves.
Lines 892–896 and 1152–1156 are added to detect a key press of REDO (FCTN-3), BEGIN (FCTN-5), or FCTN-P for print. Lines 1600-1760 are added to back up one move. Lines 1800-1980 are added to have the computer show how you played the whole game (or a game up to the present position). Lines 1990-2110 print the sequence of moves.
With a record of moves in M$, you can back up—or back up a number of moves. M$ is redefined as F$, then taken apart with the SEG function to get the row and column positions. To back up, a hole is printed in the second location and a peg in the first position. You also need to put a peg back in the position between these two listed positions. SGN is used to figure out the direction between the two locations. If the row is constant, SGN will return 0 and SGN(C2-C) will be 1 or -1 for the middle peg. If C and C2 are the same, then SGN (R2-R) will be 1 or -1. Line 1700 shows the peg on the screen. Lines 1730-1750 reset the G elements.
To have the computer show the game from the start, the screen clears and the original game board is shown. Lines 1820-1960 loop for the first move to the present move. After each move the player must press the space bar to continue. After all the moves are shown, the program is ready for the player to continue playing.
To print the sequence of moves, be sure to put your own printer configuration on line 2010. Line 2080 simply prints a move number, then the first position and second position (using coordinates).
If you wish to save typing effort, you may receive a copy of this (complete) program by sending a copying fee of $3 plus a stamped, self-addressed mailer and a blank cassette or disk to C. Regena, P. O. Box 1502, Cedar City, UT 84720. Please specify the title, "Solitaire" for the TI-99/4A.
Note: This listing is incomplete. Start by loading Solitaire from last month's column; then add these lines. You should then save a copy of the complete program.
105 REM SOLITAIRE PART 2 795 M = 1 892 IF K = 6 THEN 1600 894 IF K = 14 THEN 1800 896 IF K = 34 THEN 2010 1115 N$ = STR$ (R - 1) & STR$ (C - 1) 1152 IF K = 6 THEN 1600 1154 IF K = 14 THEN 1800 1156 IF K = 34 THEN 2010 1512 M$ (M) = N$ & STR$ (R - 1) & STR$ (C - 1) 1514 M = M + 1 1600 M = M - 1 1610 IF M > 0 THEN 1640 1620 CALL SOUND (200, 130, 2) 1630 GOTO 850 1640 F$ = M$ (M) 1650 R = VAL (SEG$ (F$, 1, 1)) + 1 1660 C = VAL (SEG$ (F$, 2, 1)) + 1 1670 R2 = VAL (SEG$ (F$, 3, 1)) + 1 1680 C2 = VAL (SEG$ (F$, 4, 1)) + 1 1690 CALL HCHAR (R2 * 2, C2 * 2 + 4, 105) 1700 CALL HCHAR ((R + SGN (R2 - R)) * 2, (C + SGN(C2 - C)) * 2 + 4, 97) 1710 CALL HCHAR (R * 2, C * 2 + 4, 97) 1730 G (R, C) = 1 1740 G (R2, C2) = 0 1750 G (R + SGN (R2 - R), C + SGN (C2 - C)) = 1 1760 GOTO 820 1800 GOSUB 620 1810 PRINT : "PRESS SPACE FOR NEXT MOVE" 1820 FOR T = 1 TO M - 1 1830 F$ = M$ (T) 1840 R = VAL (SEG$ (F$, 1, 1)) + 1 1850 C = VAL (SEG$ (F$, 2, 1)) + 1 1860 CALL HCHAR (R * 2, C * 2 + 4, 98) 1870 CALL SOUND (100, 1048, 2) 1880 R2 = VAL (SEG$ (F$, 3, 1)) + 1 1890 C2 = VAL (SEG$ (F$, 4, 1)) + 1 1900 CALL HCHAR (R2 * 2, C2 * 2 + 4, 98) 1910 CALL HCHAR ((R + SGN (R2 - R)) * 2, (C + SGN (C2 - C)) * 2 + 4, 105) 1920 CALL HCHAR (R * 2, C * 2 + 4, 105 1930 CALL HCHAR (R2 * 2, C2 * 2 + 4, 97) 1940 CALL KEY (0, K, S) 1950 If K < > THEN 1940 1960 NEXT T 1970 CALL HCHAR (23, 3, 32, 25) 1980 GOTO 820 1990 REM PUT YOUR PRINTER 2000 REM CONFIGURATION HERE 2010 OPEN #1 : "RS232.BA = 600" 2020 FOR T = 1 TO M - 1 2030 F$ = M$ (T) 2040 R$ = SEG$ (F$, 1, 1) 2050 CC$ = SEG$ (F$, 2, 1) 2060 R$ = SEG$ (F$, 3, 1) 2070 C2$ = SEG$ (F$, 4, 1) 2080 PRINT #1 : T, R$; ","; CC$; " TO "; R2$; ", "C2$ 2090 NEXT T 2100 CLOSE #1 2110 GOTO 820 2200 END