by Sol Guber
by Sol Guber
The art of programming is the art of logical thinking. To write a program that is meaningful involves a great deal of foresight and an eye to details. It is a skill that can be learned, yet there is an art to good programs. As in all art forms, different ideas can be expressed in different medias. So, too, in programming. Each language has its own flaws and enhancements. It is very similar to doing a painting in charcoal, in oils, or in pastels. As an example I will write a program in BASIC, FORTH, LOGO, and ACTION!. This will show the flaws and enhancements in each of these languages. I will try to limit myself to using the same variable names and to try to make each version of the game as similar as possible to the others.
First, let me explain the game called BUG HUNT. It is a one player version of the old favorite, BLOCKADE. There is a moving snake on the screen that is controlled by a Joystick. As the snake moves, it tries to eat randomly placed bugs on the screen. It cannot hit its own body, nor can it hit the border. After all the bugs are eaten, the number of bugs is increased, and the speed of the snake is increased. The Joystick controls only the direction of the snake, the worm will move by itself.
Now that we have the idea of the game, let us think of the various parts that need to go together to make it playable. Let us just let the ideas flow in the order that they will appear on the screen. Let us also number the ideas so that we can refer to them later.
1)TITLE-this will show the name of the game
2)BORDOR-around the screen
3)MAKEBUGS-put random bugs on the screen to be eaten
4)INITIALIZE-make variables to the correct values
5)STARTWORM-get worm to move
Now that the worm is moving, we need to do some checking of what the worm is doing. These are the categories:
6)EAT-BUG-eat a bug
7)EAT-BODY-go over the same path
8)EAT-WALL-hit the boundary.
9)CHANGE-DIR-change the direction of the worm under Joystick control
Now that we have the fundamentals we can put in the sounds and other aspects later. We have broken the whole idea down into nine steps, and each of these steps can be further broken down to make the coding that is needed to tell the computer how to play the game.
The major problem of programming is writing the coding that the machine will translate into something that it will understand. There must be a compromise between what the machine wants and what the human wants, but the human wants to write the program in a simple logical manner. Edsger Dijkstra came up with the concept of "structured programming." This says that programs should be made up of simple logical steps. There should be no looping and as simple a structure as possible. For our program there could be six parts called TITLE, START, STARTWORM, UPDATE, CHECKWORM, and RESTART. The program would flow from top to bottom with the only looping being to restart the game. This kind of programming is really possible today. There are languages that allow and enforce this "linear flow" programming.
The languages that will be used to program BUGHUNT will be BASIC, FORTH, ACTION!, and LOGO. These four languages do not have much in common. To use FORTH, LOGO, and ACTION! a basic difference is needed. These two languages use a procedural method of programming. This means that words are defined to do things. In ATARI BASIC this would correspond to the use of GOSUB TITLE to get the system to make the title. The next statement might be GOSUB MAKEBUG, etc., until the whole program was defined in a linear sort of way. This would eliminate GOTO statements, and everything would be done in terms of GOSUB's. This is the way that both FORTH and LOGO work. We set up a word TITLE, and every time TITLE is in the program, a title page is put on the screen. Other words are also defined like MAKEBUG, or CHANGE-DIR. Whenever these words are seen in the program, that action is performed.
The strength of words rather than of GOSUB's is the use of parameter passing. Let us suppose that we have a BASIC subroutine called MAKEBUG defined so that it will put bugs on the screen. Let us suppose that there is a variable called NO that is the number of bugs that MAKEBUG will put on the screen. This is easy to do and would work. However, suppose that we forget that NO is the variable for the number of bugs. To use the subroutine correctly, every variable in it must be used correctly. There can be no variable that changes in the subroutine that is used elsewhere in the program. LOGO uses a parameter list so that you do not have to remember the name of the variable, and the word can be used all through the program without having to remember the details of the word. This is very handy when different people write different parts of a program. Let me explain this further. BASIC is a very bad language for writing large programs since it cannot be easily subdivided. Each variable in the program is global. This means that the same variable will have the same value wherever it is found in the program. You cannot define a X1 that means one thing in one part and something else in another, unless it is just used for temporary storage. If two or more people want to write parts of the program together, each has to know how the other uses each of the variables, so that there is no conflict. A person cannot write a subroutine to add three numbers together and get the average unless each of the holders (variable names) is the same for everybody who uses it. This is not true for procedural languages. In LOGO you can use the word AVERAGE :X1 :X2 :X3, and when AVERAGE is used, it will put the value in :X1 in its local variable, the value :X2 in its local variable, and so forth. All a person needs to know to use AVERAGE is that it needs three numbers after the name when it is used.
FORTH uses a similar procedure for its words. FORTH uses a "push-down" STACK for its values. You put a number on the stack and push it down. Then you put another number on and push that one down, and, finally, push the third number down the stack. When AVERAGE is called, it takes the three top numbers in the stack and finds their average and pushes that number onto the top of the stack. Thus, for a FORTH programmer to use AVERAGE, all she needs to know is that three numbers need to be pushed onto the stack, and the average will be found on the top of the stack.
ACTION! allows both global variables and local variables, as well as variables that are defined only when they are passed as parameters. There is good checking for the use of variables and an error is shown when a variable is not defined before use. Also ACTION! allows you to INCLUDE other parts of programs and allocates space for global variables from this, too. This is a much more sensible method of using variables. Then, if you want to use AVERAGE, you just INCLUDE it and know that it needs three variables as parameters.
BUGHUNT IN BASIC
The BASIC version of the game is relatively straight-forward as most BASIC programs are. There are a great deal of GOTO's and GOSUB's, so the flow of the program is not easy to follow. It is a great deal more convoluted than either of the other two versions and is more difficult to write. However, the simplicity of the program commands compared to the FORTH version shows why BASIC is the first language to be learned. But when it is compared to the LOGO version which is in a closer version of ENGLISH, it shows why children should learn LOGO first.
I will again follow the outline of the program that I used in the beginning and go through each step of the program in order. The first item is the TITLE. Lines 1001-1002 setup the title. First, the Graphics 0 mode is used, then the color is set, and "BUG HUNT" is positioned in the middle of the page. Line 1002 puts two FOR-NEXT loops into the system to shift the colors and to make a varying sound. Since the background is Color Register 2, this is the one that the various colors are put into.
Line 1003 sets the variable SPEED to 25. This will be put into a FOR-NEXT timing loop later in the program. Line 1004 puts the system into the graphics 7 mode, the same as the draw mode in LOGO. It also sets the variable NO, the number of bugs, to 4. Line 1010 puts the X and Y position of the line to position 25,25 on the screen. Line 1012 corresponds to BORDER. It first sets the COLOR to register 3. It then PLOTS a point, and then DRAWTO's to various points around the screen to make the border.
Line 1014 is the first use of a subroutine. It is used to draw the bugs on the screen. The variable NO is used to tell the subroutine how many bugs to draw. The value in NO is not passed in a positive manner. The subroutine just 'assumes' that the value there is the correct one. Let us jump to line 2000 to see this subroutine. Line 2000 starts a FOR-NEXT loop for NO times. Line 2002 picks two random numbers in the correct range for the bug. Line 2004 does a LOCATE on the spot that was selected, and line 2006 examines the variable Z which was the value in LOCATION R1, R2. If the value is background (0) the program continues, otherwise the program goes back to line 2002 and picks new values for R1 and R2. Line 2008 sets up COLOR 2 and plots a point at R1 and R2. Since the dots in Graphics 7 are so small, the bug is made up of four dots around the dot that was picked. This is done in lines 2010-2020. Line 2030 checks the variable I to see if it is greater than NO. If it is not, the program goes back to line 2000, otherwise the program RETURNS to the place where it was called.
Back at line 1014, a message is put on the bottom of the screen to show what level you are playing. Line 1016 sets up COLOR 1. Two variables, DX and DY, are initialized. These two variables show the change in the movement of the worm. If DX is 1, the worm moves to the left. If DX is -1, it moves to the right. If DY is 1, the worm moves down. If DY is -1, it moves up. Since no diagonal moves are allowed, either DX or DY must be 0 when the other has a value.
Line 1020 checks Joystick 0 and puts its value in variable B. If B is 15, corresponding to a neutral position, B is set to S1. Line 1021 makes a sound for the game to make the play more thrilling. Lines 1025-1040 check the value of the Joystick. Depending on the value, either DX or DY is changed to show which way the Joystick is pointing. Line 1042 adds the value of DX and DY to the values of X and Y respectively. Line 1044 changes the sound to give a beating effect.
Lines 1045-1050 are part of the timing loop and are used to make the Joystick more sensitive to changes in direction. The timing loop is just a simple FORNEXT loop. It uses the variable I again just as the loop in 2000 did. If I is used in many spots, as it is here, you must be sure that the old value is not needed. All the I's in the program use the same memory location and each is a GLOBAL variable. It means the same thing all through the program. The Joystick is checked three times to make sure that it has not moved. If it is checked only once at the beginning of the timing loop, it might miss slight changes in the movement. This is needed because the BASIC program is relatively slow.
Line 1060 does a locate on the screen of the next dot. Lines 1065-1075 are a series of IF tests to determine the next action. If the value is 1, the program goes to line 1500 which corresponds to EATBODY. If the value is 3, the program goes to 1400 which corresponds to EAT-WALL. If the value is 2, the program goes to 1600 which corresponds to EAT-BUG. If the value is 0, that point is PLOTed on the screen to increase the length of the worm. Then the program goes back to line 1020 which started the loop.
Lines 1500-1530 correspond to EAT-BODY. Line 1500 puts a message on the screen and then starts a loop to make a noise. Line 1510 puts another message about the trigger on the screen. Line 1530 checks to see if the trigger is pressed. If it is, H1 is set to 0, SUM is set to 0, and the program goes back to 1003 to start again. If the trigger has not been pressed there is an endless loop set up between 1530 and 1520 until the trigger is pressed.
Lines 1400-1410 correspond to EAT-WALL. It is the same as 1500-1520 except that the first message is different. After that, the program is identical, so a simple GOTO 1520 uses the same lines of code.
Lines 1600-1630 correspond to EAT-BUG. Line 1600 increases both H1 and SUM by one. The position of the worm is incremented by the directions, and this point is PLOTed. This is done since the bug is two pixels by two pixels, and we want to count each bug only once. Line 1610 is an IF test to see if Hl is equal to NO-the number of bugs in this level. If it is not, an update is written on the bottom of the screen, and the program returns to 1020. If they are equal, line 1620 makes H1 equal to 0, increases the number of bugs by 2, and increases the level by one. The timer in the loop SPEED is decreased by 10%, and a message is printed on the screen. There is a slight delay, then the program returns to line 1004.
Lines 1650-1680 is just an update of the score and of the level. Messages are printed at the bottom of the screen that say which level you are on and how well you have done. It also plays the BURP noise to show that the worm has eaten the bug.
This is the BASIC version of BUGHUNT. As can be seen, it is fairly complicated if you are trying to debug (excuse the expression) the program. A major advantage of the BASIC program is that you can put STOP's into the program at various points to stop the action. You can then examine the variables and see what is going on. Let us say that we put a 1015 STOP into the program. When the program reaches this line it will stop. However, it is difficult to determine exactly where the program is coming from when it hits this point. It could be the first time through and just setting up the system. It could be after the trigger has been pressed in either EAT-WALL or EATBODY. It could be after a restart when a level has been finished. It is very difficult, and for anyone except the original programmer, almost impossible to determine.
1001 GRAPHICS 0:SETCOLOR 4,5,5:POSITION 10,10:? "BUG HUNT"
1002 REM FOR D=1 TO 6:FOR E1=1 TO 89:SOUND 1,E1,10,10:SETCOLOR 2,El/6,D*2:NEXT E1:NEXT D:50UND 1,0,0,0
1004 GRAPHICS 7
1012 COLOR 3:PLOT 10,3:DRAWTO 150,3:DRAWTO 150,70:DRAWTO 10,70:DRAWTO 10,3
1013 GOSUB 2000
1014 GOSUB 1650
1016 COLOR 1
1020 B=STZCK(0):IF B=15 THEN B=51
1021 SOUND 3,200,10,15
1025 IF B=14 THEN DY=-1:DX=0
1030 IF B=13 THEN DY=1:DX=0
1035 IF B=7 THEN DX=1:DY=0
1040 IF B=11 THEN DX=-1:DY=0
1044 SOUND 3,150,10,15
1045 FOR I=1 TO SPEED/3:NEXT I
1047 FOR I=1 TO SPEED/3:NEXT I
1049 FOR I=1 TO SPEED/3:NEXT I
1050 IF S1=15 THEN S1=S2
1060 LOCATE X,Y,Z
1065 IF Z=1 THEN 1500
1070 IF Z=3 THEN 1400
1075 IF Z=2 THEN 1600
1080 PLOT X,Y
1120 GOTO 1020
1400 ? "YOU ATE THE WALL ":FOR I=1 TO 120:SOUND 3,50,12,12
1405 SOUND 3,40,12,10:NEXT I:SOUND 3,0,0,0
1410 GOTO 1510
1500 ? "YOU ATE YOUR BODY":FOR I=1 To 120:SOUND 3,50,12,12
1505 SOUND 3,40,12,10:NEXT I:SOUND 3,0,0,0
1510 ? "PRESS fire TO BEGIN!"
1520 IF STRIG(0)=0 THEN H1=0:SUM=0:GOTO 1003
1530 GOTO 1520
1605 X=X+DX:Y=Y+DY:PLOT X,Y
1610 IF H1<>N0 THEN GOSUB 1650:GOT0 1020
1621 SPEED=INT(SPEED*0.9):? "NEXT GROUP"
1622 FOR I=1 TO 250:NEXT I
1625 GRAPHICS 7
1630 GOTO 1004
1650 ? "LEVEL ";LVL
1655 ? "THIS ROUND = ";"H1;" TOTAL = "SUM
1660 SOUND 3,0,0,0:SOUND 2,90,10,15
1665 FOR I=1 TO 100:NEXT I
1670 SOUND 2,0,0,0
2000 FOR I=1 TO NO
2004 LOCATE R2,R1,Z
2006 IF Z<>0 THEN 2002
2008 COLOR 2:PLOT R2,R1
2010 PLOT R2,R1+1
2015 PLOT R2+1,R1+1
2020 PLOT R2+1,R1
2030 NEXT I
10 REM CHECK DATA FOR BUG HUNT
1001 DATA 9942,760,267,650,64,939,648,994,5,851,979,108,336,792,742,702,786,319
1044 DATA 6839,345,11,94,13,97,15,548,213,331,328,334,960,923,518,585,929,595
1505 DATA 9560,586,17,801,933,482,954,547,832,666,696,73,931,384,704,113,697,144
1680 DATA 5312,906,211,743,298,385,570,132,229,133,808,897