Classic Computer Magazine Archive COMPUTE! ISSUE 40 / SEPTEMBER 1983 / PAGE 142

TI Towers

Raymond J Herold

Here's a game that's not only fun to play, but is also a demonstration of the potential of TI BASIC. The author also discusses how ordinary TI BASIC can perform some of the functions available with Extended BASIC.


Programming in TI Extended BASIC - with its powerful screen formatting commands, multiple statement lines, subprogram capability, and sprite graphics - offers something for everyone. However, not everyone is willing to shell out the extra purchase price right away.
    This is especially true for the many first-time computer owners. They are content to "get along" using TI BASIC, which comes with the TI-99/4A. Anyone who thinks that these programmers are struggling along in the stone age should take a closer look. Careful examination will reveal that TI BASIC is a powerful language which outperforms many of the "standard" BASICs offered on other machines.
     "TI Towers" is written in TI BASIC and demonstrates how some of its capabilities may be utilized. The game itself is a version of the ancient game Towers of Hanoi. There are three adjacent spindles, one of which has seven rings on it - the smallest ring on top, the next ring is the second smallest, and so on in pyramid fashion, with the largest ring on the bottom. The object of the game is to get all of the rings onto one of the other two spindles in the same order. You may move only one ring at a. time, and you may not move a larger ring on top of a smaller one. It might sound easy, but it's not.

Problem Solving In The Program
To provide instructions at the beginning of the game, the screen is set to black at line 905, then the instructions are PRINTed (lines 910 - 986). The screen is immediately set to medium red at line 991. This causes a momentary "blackout" of the screen before the instructions are displayed, but is preferable to the slow scroll produced by individually entering numerous PRINT statements.
    The base of the playing board is drawn using the CALL HCHAR at line 7050, which uses the CHARPAT defined in line 7031. The spindles are drawn using the CALL HCHAR statement at lines 7090 - 7094 and the CHARPAT defined in line 7030. The execution time for these commands is quite fast.
    Creating the rings presents something of a problem. Seven rings are required, each larger than the one before. If the first ring consists of a single character position, the second must use three characters; the third, five characters, and so on. The seventh ring requires 15 character positions. Since a ring can be on one of three spindles, the only way to avoid overlapping rings is to have a screen with at least 45 columns per line. With the TI-99/4A, limited to 32, the problem is obvious.
    The solution is to use "half characters." Line 6300 defines a character with all bits on: a "full" character. Line 6320 defines a character with only the leftmost bits on: a "half character" for the right side of a ring. Line 6340 defines a "half character" for the left side. The seven rings required are built in lines 6350 - 6380 by concatenating the character patterns. Figure 1 illustrates this process. Lines 8040 - 8060 load the rings to the screen for the initial game setup.
    Once the game begins, the program has to provide prompts and error messages to the player. Since the PRINT statement causes scrolling, and since the game uses a "fixed" game screen, the PRINT command is not acceptable for displaying messages. An alternative to this is using the TI BASIC command CALL HCHAR, which simulates the PRINT AT command that is so useful in Extended BASIC.
    The message to be printed is moved to the variable MESSAGE$. The desired location for the message is loaded into the variables ROW and COLUMN. The routine starting at line 5001 actually writes the message. The loop initiated at line 5005 is performed the number of times indicated by the length of the message. Line 5010 converts each successive character in the string into its ASCII equivalent. Line 5020 then prints the string, one character at a time, at the position determined by ROW and COLUMN + 1. This same procedure is used to position the rings when they are moved
    Getting information from the player presents a similar problem: the INPUT statement also causes a scroll. To avoid this, we must use the CALL KEY. This command detects a key being pressed and places the ASCII code of the key pressed into a specified variable. Lines 428-434 illustrate how this procedure can be used. Although TI BASIC doesn't have Extended BASIC's BEEP facility, the CALL SOUND command can be used just as effectively to notify the player that a response is necessary.

Manipulating The Rings
The location of the rings is stored in the variable ARRAY. ARRAY is dimensioned by the number of spindles (3) and the number of allowable rings plus one. The additional element permits checking the spindles when no rings are present. The rings are initially assigned the numbers 1 through 7 and placed on the center spindle in lines 6250 - 6260. Ring 1 is the smallest; ring 7 the largest. Figure 2 shows the contents of ARRAY at the beginning of the game. Figure 3 shows what the contents of ARRAY would be if the two smallest rings were on the first spindle, the third smallest ring on the third spindle, and the rest on the middle spindle. Lines 1005 and 1008 find the "top" of the array for the corresponding sending and receiving spindles. For example, using Figure 3, RINGS(1) would contain 2 (number of rings). Subtracting this from 8 would give the sixth position of the first spindle, the top ring.
    Lines 1020 and 1025 check to make sure that a large ring is not placed on top of a smaller one. When a valid move is made, the location of the rings is updated in lines 1100 - 1130. The variable RINGS keeps track of how many rings are on each spindle. The rings are moved by placing the appropriate RINGPAT$ in the new location. The ring at the old location is erased by moving BAND$ to it (lines 1530 -1535). BAND$ defines only the spindle character (line 6390). When one of the two side spindles gets all seven rings, the game is over. Lines 482 and 484 determine this condition by checking the first and third spindle counters for 7.
    TI BASIC can be quite effective when used to its potential. This article and game have perhaps given you some ideas for your own programs.

Figure 1


Figure 2: Contents of ARRAY


----- Spindles ----



0
1
0



0
2
0
R


0
3
0
I


0
4
0
N


0
5
0
G


0
6
0
S


0

7
0




Figure 3: Contents of ARRAY


----- Spindles ----



0
0
0



0
0
0
R


0
0
0
I


0
4
0
N


0
5
0
G

top---
1
6
0
S


2

7
3




TI Towers

100 DIM ARRAY(3,8)
110 DIM RINGS(3)
120 DIM RINGPAT$(7)
130 REM
140 REM INTRODUCTION
150 REM
160 CALL CLEAR
170 CALL SCREEN(9)
180 GOSUB 1930
190 MESSAGE$=M1$
200 ROW=5
210 COLUMN=11
220 GOSUB 1850
230 MESSAGE$=M2$
240 ROW=18
250 COLUMN=3
260 GOSUB 1850
270 MESSAGE$=M3$
280 ROW=20
290 COLUMN=9
300 GOSUB 1850
310 CALL SOUND(200,1000,4)
320 CALL KEY(3,KEY,STATUS)
330 IF STATUS=0 THEN 320
340 IF KEY=89 THEN 1070
350 IF KEY<>78 THEN 270
360 REM
370 REM BEGIN GAME
380 REM
390 IF MOVES=-HIGHSCORE THEN 410
400 HIGHSCORE=MOVES
410 GOSUB 2260
420 IF HIGHSCORE<>0 THEN 440
430 HIGHSCORE=99999
440 MOVES=0
450 REM
460 REM PLAY GAME LOOP
470 REM
480 ROW=1
490 COLUMN=28
500 MESSAGE$=STR$(MOVES)
510 GOSUB 1850
520 ROW=23
530 COLUMN=1
540 MESSAGE$=M6$
550 GOSUB 1850
560 CALL SOUND(250,1000,4)
570 CALL KEY(3,KEY,STATUS)
580 IF STATUS=0 THEN 570
590 IF KEY<49 THEN 1700
600 IF KEY:51 THEN 1700
610 CALL HCHAR(23,13,KEY)
620 MOVEFRSM=VAL(CHR$(KEY))
630 COLUMN=16
640 MESSAGE$=M7$
650 GOSUB 1850
660 CALL SOUND(250,1000,4)
670 CALL KEY(3,KEY,STATUS)
680 IF STATUS=0 THEN 670
690 IF KEY<49 THEN 1700
700 IF KEY?51 THEN 1700
710 CALL HCHAR(23,26,KEY)
720 MOVETO=VAL(CHR$(KEY))
730 IF MOVEFROM=MOVETO THEN 1700
740 GOSUB 1350
750 MOVES=MOVES+i
760 CALL HCHAR(23,1,32,30)
770 IF RINGS(1)=7 THEN 800
780 IF RINGS(3)=7 THEN 800
790 GOTO 450
800 REM
810 REM GAME COMPLETED
820 REM
830 FOR X=1 TO 20
840 CALL HCHAR(23,1,4--,31)
850 CALL SOUND(150,X*400,21-X)
860 CALL HCHAR(23_,1_,32,31)
670 NEXT X
880 ROW=23
890 COLUMN=2
900 MESSAGE$=M8$
910 GSSUB 1850
920 FOR DELAY=1 TO 1500
930 NEXT DELAY
940 ROW=24
950 MESSAGE$=M9$
960 GOSUB 1850
970 CALL SOUND(300,1000,4)
980 CALL KEY(3,KEY,STATUS)
990 IF STATUS=0 THEN 980
1000 IF KEY=89 THEN 1050
1010 IF KEY<778 THEN 970
1020 CALL CLEAR
1030 PRINT "GAME OVER"
1040 STOP
1050 GOSUB 1930
1060 GOTO 360
1070 REM
1080 REM[ INSTRUCTIONS
1090 REM
1100 CALL SCREEN(1)
1110 PRINT "TI TOWERS IS A VERSION
     OF"
1120 PRINT
1130 PRINT "THE GAME TOWERS OF HANG
     I."
1140 PRINT
1150 PRINT "THE OBJECT OF THE GAME
     IS TO"
1160 PRINT
1170 PRINT "MOVE THE RINGS ON THE C
     ENTER"
1180 PRINT
1190 PRINT "SPINDLE TO ONE OF THE T
     WO"
1200 PRINT
1210 PRINT "SIDE SPINDLES. YOU MAY
      ONLY"
1220 PRINT
1230 PRINT "MOVE ONE RING AT A TIME
     , AND"
1240 PRINT
1250 PRINT "YOU MAY NOT PLACE A LAR
     GE"
1260 PRINT
1270 PRINT "RING ON TOP OF A SMALL
     ONE."
1280 PRINT
1290 PRINT
1300 PRINT "PRESS ANY KEY TO'BEGIN"
1310 CALL SCREEN(9)
1320 CALL KEY(3,KEY,STATUS)
1330 IF STATUS=O THEN 1320
1340 GOTO 360
1350 REM
1360 REM ANALYZE MOVE
1370 REM
1380 SUB1=8-RINGS(MOVEFROM)
1390 SUB2=8-RINGS(MOVETO)
1400 IF ARRAY(MOVEFROM,SUB1)?ARRAY(
     MOVETO,SUB2)THEN 1700
1410 IF RINGS(MOVEFROM)=0 THEN 1700
1420 GOSUB 1480
1430 RINGS(MOVEFROM)=RINGS(MOVEFROM
     )-1
1440 RINGS(MOVETO)=RINGS(MOVETO)+1
1450 ARRAY(MOVETO,SUB2-1)=ARRAY(MOV
     EFROM,SUB1)
1460 ARRAY(MOVEFROM,SUB1)=0
1470 RETURN
1480 REM
1490 REM MOVE RING
1500 REM
1510 ROW=7+(2*(7-RINGS(MOVEFROM)))
1520 COLUMN=19
1530 IF MOVEFROM<?1 THEN 1550
1540 COLUMN=3
1550 IF MOVEFROM<f2 THEN 1570
1560 COLUMN=11
1570 MESSAGE$=BAND$
1580 GOSUB 1850
1590 ROW=19-(2*(RINGS(MOVETO)))
1600 COLUMN=22
1610 IF MOVETO<>1 THEN 1630
1620 COLUMN=6
1630 IF MOVETO<>2 THEN 1650
1640 COLUMN=14
1650 XX=ARRAY(MOVEFROM,SUB1)
1660 COLUMN=COLUMN-(INT(LEN(RINGPAT
     $(XX)))/2)
1670 MESSAGE$=RINGPAT$(XX)
1680 GOSUB 1850
1690 RETURN
1700 REM
1710 REM ERROR IN MOVE
1720 REM
1730 ROW=24
1740 COLUMN=1
1750 MESSAGE$=E1$
1760 CALL SOUND(900,200,1)
1770 GOSUB 1850
1780 FOR DELAY=1 TO 200
1790 NEXT DELAY
1800 CALL HCHAR(23,1,32,32)
1810 CALL HCHAR(24,1,32,32)
1820 MOVEFROM=0
1830 MOVETO=0
1840 GOTO 520
1850 REM
1860 REM WRITE MESSAGES
1870 REM
1880 FOR I=1 TO LEN(MESSAGE$)
1890 CHAR=ASC(SEG$(MESSAGE$,I,1))
1900 CALL HCHAR(ROW,COLUMN+I,CHAR)
1910 NEXT I
1920 RETURN
1930 REM
1940 REM INITIALIZE AREAS
     {5 SPACES}
1950 REM
1960 M1$="TI TOWERS"
1970 M2$="DO YOU NEED INSTRUCTIONS?
     "
1980 M3$="REPLY Y OR N"
1990 M4$="BEST SCORE:"
2000 M5$="MOVES:"
2010 M6$="MOVE FROM?"
2020 M7$="MOVE TO?"
2030 M8$="f3 SPACES}*** YOU DID IT
     ***{6 SPACES}"
2040 M9$="PLAY AGAIN - Y OR N"
2050 E1$="** INVALID MOVE - TRY AGA
     IN"
2060 RINGS(1)=0
2070 RINGS(2)=7
2080 RINGS(3)=0
2090 FOR I=1 TO 8
2100 ARRAY(2,I)=I
2110 NEXT I
2120 ARRAY(1,8)=8
2130 ARRAY(3,8)=8
2140 CALL CHAR(128,"FFFFFFFFFFFFFFF
     F")
2150 CALL CHAR(131,"F0F0F0F0F0F0F0F
     0")
2160 CALL CHAR(133,"0F0F0F0F0F0F0F0
     F")
2170 RINGPAT$(1)=CHR$(128)
2180 RINGPAT$(2)=CHR$(133)&CHR$(128
     )&CHR$(131)
2190 RINGPAT$(3)=CHR$(128)&CHR$(128
     )&CHR$(128)
2200 RINGPAT$(4)=CHR$(133)&CHR$(128
     )&CHR$(128)&CHR$(128)&CHR$(131
     )
2210 RINGPAT$(5)=CHR$(128)&CHR$(128
     )&CHR$(128)&CHR$(128)&CHR$(128
     )
2220 RINGPAT$(6)=CHR$(133)&CHR$(128
     )&CHR$(128)&CHR$(128)&CHR$(128
     )&CHR$(128)&CHR$(131)
2230 RINGPAT$(7)=CHR$(128)&CHR$(128
     )&CHR$(128)&CHR$(128)&CHR$(128
     )&CHR$(128)&CHR$(128)
2240 BAND$=CHR$(32)&CHR$(32)&CHR$(3
     2)&CHR$(36)&CHR$(32)&CHR$(32)&
     CHR$(32)
2250 RETURN
2260 REM
2270 REM SET UP GAME BOARD
2280 REM
2290 CALL CLEAR
2300 CALL SCREEN(8)
2310 CALL CHAR(36,"1818181818181818
     ")
2320 CALL CHAR(37,"FFFFFFFFFFFFFFFF
     ")
2330 CALL COLOR(1,13,1)
2340 CALL COLOR(13,7,1)
2350 CALL HCHAR(20,2,37,30)
2360 GOSUB 2510
2370 ROW=1
2380 COLUMN=1
2390 MESSAGE$=M4$
2400 GOSUB 1850
2410 COLUMN=21
2420 MESSAGE$=M5$
2430 GOSUB 1850
2440 CALL HCHAR(21,7,49)
2450 CALL HCHAR(21,15,50)
2460 CALL HCHAR(21,23,51)
2470 COLUMN=13
2480 MESSAGE$=STR$(HIGHSCORE)
2495 GOSUB 1850
2500 RETURN
2510 REM
2520 REM INITIAL RING SETUP
2530 REM
2540 CALL VCHAR(6Z7,36,14)
2550 CALL VCHAR(6,15,36,14)
2560 CALL VCHAR(6,23,36,14)
2570 FOR X=1 TO 7
2580 ROW=5+(X*2)
2590 COLUMN=14-(INT(LEN(RINGPAT$(X)
     ))/2)
2600 MESSAGE$=RINGPAT$(X)
2610 GOSUB 1850
2620 NEXT X
2630 RETURN