We have already seen how useful the REPEAT ... UNTIL construct can be to keep a program running and repeating itself until a special condition has been met. The main purpose of this module is to look at other ways of making a section of a program repeat itself.
This construct is a highly useful one, and can be varied in a number of ways. In its simplest form it simply counts the number of times it performs a loop and then continues on to the following code. Type in the following code to see how it works.
Rem Prog3
REM Demonstration of simple FOR NEXT loop
number = 9
FOR X%=1 TO number
PRINT "X% = ":X%
NEXT X%
PRINT"The loop has now been completed"
END
It should be clear that the loop is run, first with X%=1, then with X%=2, etc until X%=number (which is itself 9). It then exits the loop, prints the statement saying so, and ends.
There are one or two 'extra' bits included here at the same time. Firstly, note the use of the REM statement. A program of any length can be a highly confusing list of code, and the insertion of REM statements helps to clarify the purpose of each section, not only for someone else if they want to explore your code, but also for yourself! If you come back to a program you have written even just a couple of weeks or so after it was first done it can take a few moments to decipher what it was doing - and after a few months it only gets more difficult, so the REM statement can be a great time-saver in the long run.
In the second line I set the variable number to be equal to 9, and then used this as the upper limit in the FOR statement by writing 'FOR X%=1 TO number'. I could more easily have left out the second line and written the FOR statement as
FOR X%=1 TO 9
This would have worked in exactly the same way - try it, if you like! The reason I used the variable was only to demonstrate that we can use either method. Quite often, the upper limit will already be held by the program in a variable, and if you use this number a lot it can be helpful to set the variable early in the program and use it in this way. If you change the variable later you only have to alter the program in one place rather than every time you write a FOR NEXT loop based on this number.
Thirdly, programmers all have their own customs and practices. One of mine is to use X%, Y% and Z% as my main count variables in FOR NEXT loops. If I need more then I will use U%, V%, W%, but this does not happen very much. The point here is that by keeping to your own personal convention, you will not start using that variable for something else by mistake, and thereby introducing unnecessary bugs into your programs. You will find that enough bugs creep in without adding the more obvious ones!
In line 4 of our program we have used a more complex structure to print out a statement. Anything between quotes is called a string and will be printed exactly as typed. The semi-colon is there to make sure that the value of X% is printed immediately after the string "X% = ". If we had used a comma in place of the semi-colon then the value of X% would have been spaced to the next tab position.
Line 5 reads 'NEXT X%'. Superficially this looks helpful to know that it is the loop based on the value of X% that is being checked, but it is not essential. This line could have been written as simply 'NEXT'. Again, different programmers have different views, but for me, so long as I am indenting my loops correctly, then the X% is redundant, simply clutters up the listing, and so I normally miss it out. In these tutorials we will miss out the variable in the NEXT statement from now on.
We do not always want to run through the variable in a FOR NEXT loop just an integer at a time. For example, we could use a FOR NEXT loop to list the results of multiplying a number by multiples of 3 by stepping up 3 at a time:
REM Prog3a
REM Demonstrating the STEP keyword
t%=1
FOR X%=3 TO 15 STEP 3
t%=t%*X%
PRINT X%,t%
NEXT
END
In this example, notice that we have tabulated the results this time by using the comma in the PRINT statement. Note also that it was necessary to define the value of t% before we started the loop. (If you don't do this, the program will assume that t% is zero, with rather boring results.) We have also included an important 'feature' of the FOR NEXT loop which can often lead to bugs - each time the loop is followed, t% has changed, and we use the new value of t% each time the loop is done. If you didn't want this to happen, how would you modify the code? (Hint: you need to use another variable for the result - p%, say. See if you can successfully make this change.)
We stepped up in this version by 3's, but we can also step backwards. The following statements are equally valid:
FOR X%=10 TO 1 STEP -1
FOR X%=100 TO 10 STEP -5
but remember to avoid statements like
FOR X% = 100 TO 10 STEP -4
because in this example X% will never = 10, and the program will loop forever!
In BASIC there are essentially three types of loop, of which we have now met two: the FOR NEXT loop and the REPEAT UNTIL loop. Both of these are always executed at least once, and cannot make a decision for themselves as to how often they will loop until they reach the end of the first loop. In certain circumstances it is more helpful to set up the program so that it will ignore the loop completely if an appropriate condition has not already been met. For this we need the WHILE ... ENDWHILE construct. Type in the following example to see how it works.
REM Prog3b
REM Demonstration of the WHILE construct
G=GET
WHILE G>96
PRINT CHR$(G)
G=GET
ENDWHILE
END
When this program is run, nothing appears to happen because the first line requires you to press a key (the G=GET statement). As soon as you press any key, the task window will open as with other programs we have written so far. The number 96 divides capital letters from lower case, so if you begin by typing a capital letter, G will not be greater than 96, the loop is not entered, and the program will stop. So long as you enter a lower case letter, the program will loop the loop.
Notice that another keyword has crept in here - CHR$. This keyword will change a number (G in this case) into the string it represents, so if G=113, CHR$(G) equals 'q'. In this case, we are using CHR$ to print out the key that you have pressed.
There are too many puns inherent in this module, so apologies for those who cringe at them but it does help to tie together (sorry again!) the ideas we are covering. The main topic has been about loops, but we have taken the opportunity to say a little more about strings, and it seems too good an opportunity to be missed to insert a quick look at the keyword NOT.
NOT may appear to be a superfluous keyword in that (I think) it is always possible to use some other form to avoid its use. It does, however, sometimes make a program more easily understood because it more closely reflects ordinary speech. In this respect it is akin to using TRUE and FALSE rather than -1 or 0. (Did you get these values correct in the last module?) Some examples of how the word is used are:
WHILE X% NOT 1
IF S% NOT TRUE THEN S% = TRUE
Here is a simple program that demonstrates a nice linguistic emphasis:
REM Prog3c
REM Using NOT
REPEAT
G=GET
IF G>96 lowercase=TRUE ELSE lowercase = FALSE
IF NOT lowercase THEN
PRINT"This is upper case "+CHR$(G)
ELSE
PRINT"This is lower case "+CHR$(G)
ENDIF
UNTIL lowercase=NOT TRUE
END
We could, of course, have written the penultimate line as 'UNTIL lowercase=FALSE', but we had to get an extra NOT in somewhere!
'Typical result of running Prog3c'
Notice one extra feature of strings slipped in here - the use of '+' in the PRINT statements. The point here is that we can tie strings together by putting + signs between them. Here are a couple more examples:
A$ = B$ + " is number 1."
Number$ = "Number "+X%
And if that hasn't got you all tangled up, then well done!
In this module we have covered a lot of ground. The main points covered have been:
In addition, we have remarked on one or two elements of style, using REM statements to make programs easier to follow, and keeping to conventions (such as only using X% as a counter) in order to avoid simple bugs creeping into your programs.
In programs Prog3b and Prog3c we had the problem that nothing appears to happen when the program is first run until you press a key. It would be nicer if something appeared on screen to tell us what to do. Now that should be easy enough ...
If you did not succeed in this last modification, this might give you a clue. In some programs, especially in BBC days, a line would appear on screen in the form
Press a key ?
If we put in a PRINT statement with the words 'Press a key: ' followed by a semi-colon, it acts as a prompt and the next line of print will continue on the same line.
Loops can be nested. For example
FOR X%=1 TO 10
FOR Y%=2 TO 12 STEP 2
PRINT X%,Y%,X%*Y%
NEXT
NEXT
END
is perfectly valid. (You can type this in and see what happens, but try to work it out yourself first.)
Use this kind of structure to write a program that will set out a multiplication table for numbers 1 to 8. Change it to list only even numbers, or numbers from 6 to 12.
Vary the program Prog3b by experimenting with different conditions for the WHILE statement.