Lesson 3: Conditions and Branching
Going back to our first program, wouldn't it be cool that instead of the general Hello World, we could say Good Morning World!, Good Afternoon World!, or Good Evening World! depending on the time of day? For our next program we'll make the computer say Good Morning World! if the time is earlier than 12PM, Good Afternoon World! if the time is between 12PM and 6PM and Good Evening World! if the time is greater than 6PM. Type the following program into your IDE then execute it to see it in action.
Figure 1: Good evening
Before we analyze the program let's talk about the use of the < and > characters first. Just as you learned in math class the < character means less than and the > character means greater than. These characters are known as relational operators because they test the relationship between values.
The first line in the main program section gathers the current hour from the computer:
Hour% = VAL(TIME$) ' get the current hour (military time 0-23)
An integer variable named Hour% has been declared to hold the current hour of the day. TIME$ is a QB64 function that can retrieve the current time from the computer. As you may have guessed the time is returned as a string of characters because of the string identifier ( $ ) at the end of the command. TIME$ returns the current time in the format "HH:MM:SS" in 24 hour military time. So, for instance, 6PM is returned as "18:00:00".
VAL() is also a QB64 function. Think of a function as small ready to use program that performs a specific task. In the case of VAL() it returns the value of a string. In other words it converts any numeric characters contained in the string to an actual numeric value and returns that value either to be evaluated or placed within a variable such as our program did. VAL() will stop converting numbers when it reaches a non-numeric character within the string it is converting. Since the first two characters of TIME$ are the hour, VAL() will grab the first two characters, convert them to a numeric value, and then return that numeric value. In our program that numeric value is placed in Hour% because we told it to equal ( = ) the numeric result that VAL() returns. Here is the process broken down using the 6PM example:
TIME$ returns the time as a string of characters. Since TIME$ is contained within VAL()'s parenthesis it is handled first due to the order of operations.
Hour% = VAL("18:00:00")
The first two characters of the string are grabbed by VAL() because they are numeric characters. When VAL() sees the colon ( : ) it stops grabbing characters.
Hour% = VAL("18")
Now that VAL() contains only numeric characters in string format it converts those characters to an actual numeric value and returns it.
Hour% = 18
The next three lines of code is actually a statement wrapped inside of another statement.
IF Hour% < 12 THEN ' is current hour less than 12? (before noon)
PRINT "Good Morning World!" ' yes, it must be morning
END IF
The IF...THEN...END IF is a statement construct used for true or false conditional testing, otherwise known as Boolean logic. The code contained in between the IF and THEN key words is known as a condition. This condition is evaluated to either having a true or false outcome. If the condition is evaluated to be true then anything that follows the THEN key word is executed. However, if the condition is evaluated to being false then anything following the THEN key word is ignored. We previously set Hour% to 18 so let's go ahead plug that value into the three lines of code to see what happens.
The number 18 is substituted for Hour%:
IF 18 < 12 THEN ' is current hour less than 12? (before noon)
PRINT "Good Morning World!" ' yes, it must be morning
END IF
Then the condition 18 < 12 is examined. Is 18 less than 12? No, so the condition evaluates to false:
IF FALSE THEN ' is current hour less than 12? (before noon)
PRINT "Good Morning World!" ' yes, it must be morning
END IF
Since the condition evaluated to false anything following the THEN statement will be ignored. Since 18 in military time is 6PM it can't possibly be morning so our IF...THEN statement prevented the code from printing that it is morning. Let's move onto the next three lines of code in the same manner.
The number 18 is once again substituted for each Hour%:
IF 18 > 11 AND 18 < 18 THEN ' is the current hour 12 to 17? (noon to 5PM)
PRINT "Good Afternoon World!" ' yes, it must be afternoon
END IF
Here we have two conditions being evaluated, 18 > 11 and 18 < 18, separated by the use of the AND Boolean conditional operator. By using the AND conditional operator both conditions must evaluate to true to make the entire statement true. In other words this AND this must be true for the entire statement to be true. There will be more discussion on Boolean topics in a later lesson.
The first condition will evaluate to false since 18 is not greater than 11. The second condition will also evaluate to false sine 18 is not less than 18. If any condition on either side of the AND operator is false the entire statement becomes false. Once again, since 18 in military time is 6PM it can't possibly be afternoon so the IF...THEN statement prevented the code from printing that it's the afternoon.
IF FALSE AND FALSE THEN ' is the current hour 12 to 17? (noon to 5PM)
PRINT "Good Afternoon World!" ' yes, it must be afternoon
END IF
Finally let's examine the last three lines of code again substituting the number 18 for Hour%:
IF 18 > 17 THEN ' is current hour greater than 17? (after 5PM)
PRINT "Good Evening World!" ' yes, it must be evening
END IF
The condition is examined and evaluated as true since 18 is in fact greater than 17.
IF TRUE THEN ' is current hour greater than 17? (after 5PM)
PRINT "Good Evening World!" ' yes, it must be evening
END IF
Since the condition this time evaluated to true the statement allows the code following THEN to be executed resulting in "Good Evening World!" printed to the screen. Save this program as HelloTime.BAS before continuing.
What IF?
The IF...THEN statement construct can be used in a number of different ways to perform conditional testing. Let's start out with a simple program and then change it to see the different methods that can be used. Type the following code into your IDE and then execute it to see it in action.
The user is asked to enter a number between 1 and 100 with the result getting stored into Value%. In all previous example code that contained IF...THEN statements there was an associated END IF line of code to show where the IF...THEN statements ends. However, you do not need the END IF statement if only one action is to be performed after the THEN statement as seen in the code above. For example, this line of code:
IF Value% < 1 THEN PRINT "That number is less than one!"
only has the PRINT statement as the single action to be performed if the condition evaluates to true.
While the program works as written there is another, more efficient method, to group the IF...THEN statements together using a modified version of the IF...THEN statement construct. Modify your code with the changes below.
The ELSEIF and ELSE statements are two optional statements you can use with IF...THEN statement constructs. ELSEIF allows for another condition to be tested if the previous condition evaluated to false. The ELSE statement can be considered a "catch all" having statements after it executed only if every IF and ELSEIF above it had their conditions all evaluate to false. Let's say the user entered the numeric value 123 in the program above. The program flow would look like this:
The numeric value 123 is substituted for Value% in the IF line:
IF 123 < 1 THEN
This condition will obviously evaluate to false since 123 is not less than 1. Program flow will continue on to the ELSEIF statement:
ELSEIF 123 > 100 THEN
This condition will equate to true since 123 is greater than 100. Here, the action associated with the ELSEIF statement is acted upon resulting in "That number is greater than one hundred!" being printed to the screen. When a condition that evaluates to true has been encountered, and the associated action performed, the remaining IF...END IF statement structure is then ignored. Let's look at the program flow again this time having the user enter the numeric value of 55.
The numeric value 55 is substituted for Value% in the IF line:
IF 55 < 1 THEN
This again is false so the program flow will continue on to the ELSEIF statement:
ELSEIF 55 > 100 THEN
Again, another false evaluation. Since there are no more ELSEIF statements to process program flow continues to the ELSE statement since every condition above has evaluated to false. Logically, if the numeric value the user entered was not less than one nor was it greater than one hundred then it must be a number in the range we are looking for. There was no need to perform a third test as we did in the first program example. This is much more efficient.
"Thank you for following directions."
Many actions can be taken within IF...THEN...END IF blocks of code. Modify the code one more time to see this principle in action.
The above code shows multiple actions within the IF and ELSEIF code blocks, in this case two PRINT statements. You can have as many actions within code blocks as you wish. You can even embed more IF statements inside if you like. Save this code as 1to100.BAS before continuing on.
IF will also evaluate to true when testing against any non-zero value. The following IF statement will evaluate to false because the value contained in Test% is zero:
Test% = 0
IF Test% THEN PRINT "A non-zero value"
The PRINT statement will not get performed because a numeric value of zero is seen as false. changing the value of Test% to anything other than zero will result in the IF statement evaluating to true.
Test% = 99
IF Test% THEN PRINT "A non-zero value"
This time the PRINT statement will get performed.
Many times at the top of BASIC source code you'll see the following two lines:
CONST FALSE = 0
CONST TRUE = NOT FALSE
These are used as Boolean flags to set variables to true and false for IF testing purposes. The constant TRUE will equal the value of -1 (non-zero) because of the NOT Boolean operator statement reversing the value of the constant FALSE.
Test% = TRUE
IF Test% THEN
PRINT "Evaluated to TRUE"
ELSE
PRINT "Evaluated to FALSE"
END IF
Just in CASE
Another form of conditional testing can be performed using the SELECT CASE...END SELECT statement construct that provides many powerful options for testing conditions. Let's take the first program from this lesson and rewrite it using SELECT CASE.
Conditional checks are performed using the CASE statement based off of a value to evaluate determined by the SELECT CASE line of code.
SELECT CASE Hour% ' what is the current hour?
The variable Hour% is now used by the CASE statements to perform evaluations based on its value.
CASE IS < 12 ' is it less than 12?
PRINT "Good Morning World!" ' yes, it must be morning
CASE 12 to 17 ' is it 12 to 17?
PRINT "Good Afternoon World!" ' yes, it must be afternoon
CASE IS > 17 ' is it greater than 17?
print "Good Evening World!" ' yes, it must be evening
A block of code is created between each CASE statement to carry out additional statements if the CASE statement evaluates to true. Each CASE statement acts like a separate IF statement but with a much cleaner syntax. Save your program as HelloCase.BAS before typing in the next piece of code.
The variable Number% is used as the evaluator for the CASE statements that follow.
SELECT CASE Number% ' what's the value?
CASE statements allow multiple checks on the same line by separating them with commas (,).
CASE IS < 1, IS > 10 ' is it within range?
If either condition is true the block of code that follows will be entered. The same is true for this line of code:
CASE 2, 4, 6, 8, 10 ' was it an even number?
If Number% contains any of the values following the CASE statement then the condition becomes true and the block of code is entered. If you had to do this with an IF statement if would look like this:
IF Number% = 2 OR Number% = 4 OR Number% = 6 OR Number% = 8 OR Number% = 10 THEN
As you can see using CASE is a much cleaner and easier way to test for many conditions on the same line.
Just like IF statements the SELECT CASE construct has an ELSE clause to act as a "catch all" when none of the previous CASE statements evaluated to true.
CASE ELSE ' it must be an odd number
The following forms of CASE can be used with the SELECT CASE construct.
CASE Value
Here a single value is checked such as a numeric or string value. Examples would be CASE 10, CASE Number%, CASE "Mississippi", or CASE Pname$.
CASE Value1 TO Value2
A range of values can be checked such as CASE 1 TO 10, CASE -50 TO 100, or CASE n1% TO n2%.
CASE Value1, Value2, Value3, ...
Multiple values can be checked at the same time such as CASE 1, 3, 5 or CASE "A", "B", "C".
CASE IS > Value
Values can be checked against relational operators which include less than ( < ), greater than ( > ), equal to ( = ), less than or equal to ( <= ), greater than or equal to ( >= ) and not equal to ( <> ).
By using commas you can mix and match these various forms of CASE on one line.
CASE 1, 5 TO 10, 15 ' check for 1, 5, 6, 7, 8, 9, 10, and 15
CASE IS < 1, IS > 10 ' check for a value outside the range of 1 to 10
CASE -10 TO -1, 1 TO 10 ' check for values within these ranges
CASE "A", "B", "C", "D", "F" ' check for these string values (grades)
SELECT CASE can be used as an alternative to multiple ELSEIF statements and it makes code cleaner and easier to read. The major difference between multiple ELSIF statements and SELECT CASE is that SELECT CASE can only test for one condition while multiple ELSEIF statements can check for many different conditions. Take this code for example:
IF Count% = 1 THEN
' do this code
ELSEIF Count% = 2 THEN
' do this code
ELSEIF Count% > 10 THEN
' do this code
ELSE
' do this code
END IF
The code above lends itself well to being converted to a SELECT CASE construct because only one variable, Count%, is being checked for different conditions. Here is the same code written with SELECT CASE.
SELECT CASE Count%
CASE 1
' do this code
CASE 2
' do this code
CASE IS > 10
' do this code
CASE ELSE
' do this code
END SELECT
However, the following IF...END IF construct would not be possible to do using a SELECT CASE statement.
IF Count% = 1 THEN
' do this code
ELSEIF Player% = 2 THEN
' do this code
ELSEIF Score% < 100 THEN
' do this code
ELSE
' do this code
END IF
The reason is that three different variables are being evaluated in the above example and there is no mechanism to allow SELECT CASE to test for more that one condition at a time. Again, the main reason to use SELECT CASE is the versatility it offers when checking a condition and the readability it provides to the programmer. Many times you'll see programmers use SELECT CASE in the following configuration.
Frame% = Frame% + 1 ' increment frame counter
SELECT CASE Frame% ' which frame is game on?
CASE 1: UpdateScores ' execute the score update subroutine
CASE 2: AddEnemy ' execute the enemy adding subroutine
CASE 3: ToggleEnemy ' execute the enemy appearance subroutine
CASE 30: Frame% = 0 ' reset frame counter after 30 frames
END SELECT
Notice the use of a colon ( : ) after each CASE statement. Colons are a throwback from the early days of BASIC that allow multiple command statements to be placed on the same line of code. QB64 still supports the use of colons for compatibility reasons however they make code difficult to read and are rarely used. Sometimes though, as with the example above, they actually aid in enhancing code readability.
Branching
The next portion of this lesson is a controversial subject in the programming world. There is a command in BASIC called GOTO that allows program execution to jump from one place to another within the source code. Most programmers avoid using this command because it is considered poor programming style to use them. Other programmers use them because they say using them keeps with the spirit of the BASIC language. My personal opinion is that the GOTO command should be avoided because it can create what is known as spaghetti code, that is code that's hard to follow like a strand of spaghetti within a pile of thousands. However, the command does exist and you need to be aware of it in case you run across them within someone else's code.
So far all of the example programs you have worked with started at the top of the source code and proceeded toward the bottom on line at a time. The GOTO command allows you to jump backward or forward within the source code enabling reuse of the code. For example, type in the following program into your IDE and then execute it to see GOTO in action.
What the program has done is set up a loop until a certain condition is met. In order to use the GOTO command you need to create jump points called labels within your source code. Labels follow the same naming rules as variables and are followed by a single colon ( : ).
START: ' a label GOTO can jump to
The label called START can now be used by a GOTO statement as a jump point. The program continues on by printing the value of the variable Count% and then incrementing, or adding 1, to the value of Count%. The last line of code is where the jump happens.
IF Count% < 25 THEN GOTO START ' go back if counter less than 25
If the value in Count% is less than 25 then GOTO directs program flow back to the label named START and the process starts over again. This looks harmless enough in a simple program as above, but let's up the ante a bit. Type in the following program and execute it.
Granted, I've taken the use of GOTO to a bit of an extreme in this example, however, even this little program is difficult to follow at best. The use of GOTO may seem like a good idea at first but before you know it your code becomes an absolute mess to decipher. In later lessons you will learn superior alternatives to using GOTOs for looping. Save this program as NoNoGoto.BAS before continuing.
Your Turn
Create a Guess The Number game that exhibits the following features:
- The program should display the game's rules to the player.
- The number should be in the range of 1 to 100.
- The program keeps track of how many guesses the user made until guessing the correct number.
- The program should tell the player if the number guessed is too high or low.
- The program will use GOTO to create a loop.
- The program should end once the user correctly guesses the number.
- Don't forget to document your code using remarks.
The commands you will need to use in order to create this game are PRINT, INPUT, GOTO, IF...THEN and DIM. Save the program as Guess.BAS to your hard drive. Figure 2 below shows a screen shot of how your Guess The Number game should play out.
Figure 2: An example game of Guess the Number
Commands and Concepts Learned
New commands introduced in this lesson:
TIME$
VAL()
IF ... THEN
AND
END
GOTO
SELECT CASE ... END SELECT
CASE
TO
IS
CASE ELSE
COLON (:)
New concepts introduced in this lesson:
relational operators
functions
nesting
order of operations
Boolean
conditions
indenting
loops
labels