Learn Programming in Java

<<Previous | ToC | Next >>

Lesson #3: Conditionals & Input

Today we start to make complicated programs. Today we can begin to write a game, where the computer plays Tic-Tac-Toe against a human. But first we need to know how to tell the computer to choose different results based on the values of data. It's called a conditional, and the fundamental conditional is "if/else". Start over with our HelloWorld program, but this time make the interior look like this:
public static void main() {
    int boyz = 7, gulz = 3;
    if (boyz>gulz) System.out.println("Chauvinist!");
    else if (boyz<gulz) System.out.println("Feminist!");
        else System.out.println("Equality!");

Let's look at the structure of those conditionals. Normally we want the condition (inside the parentheses) to be a boolean value, either the result of a compare as here, or else a boolean variable calculated at some other time, or perhaps a composite expression value. You know, even before running this program -- and any decent Java compiler probably does too -- that it's going to print out "Chauvinist!" not "Feminist!". But now we are going to ask the human operator for how many boys and girls there are, and the program actually does something we couldn't know when it was written. Insert these four lines after the declaration and before the first println:

System.out.print("How many boys? ");
boyz = Zystem.ReadInt();
System.out.print("How many girls? ");
gulz = Zystem.ReadInt();

Ordinarily we would use "System" for both input and output, but the Java folks made that unnecessarily complicated, so I made up a fake "Zystem" to use in the beginning. Later on you can look through what I did and see why. And then you won't need it any more. For today, "Zystem.ReadInt()" gets a user-typed number from the console window.

Now after you compile and run it, it will stop and ask how many boys and girls you want it to compute on. Type in the number 4 and press Enter, then the number 5 and press Enter again. You have told the computer something it did not know, then it told you something based on the information it had. Run it a few times and convince yourself that you understand how it works.

Guessing Game

Games are always fun, but most games are pretty complicated and we don't have a lot of tools for dealing with that complexity. So let's do a simple guessing game, where you think of a number, and the computer will ask a few questions and try to guess what the number is. Actually it's not a guess at all, it will do a simple binary search, so it will always come back with the correct answer (unless you cheat), but it will give you an idea what a real program looks like.

The first thing you do when writing any real program is to stop and think about what needs to be done. Suppose you want the computer to guess a number between 1 and 8. It could ask you (eight times) "Is it 1, is it 2, is it 3, ..." but that's both tedious and unnecessary. So let's think about how to divide the search space into smaller portions. Although we start off with eight possible numbers, if we ask "Is it more than 4?" and the answer is "no" then we have reduced the choices to four, 1 to 4. Similarly, if the answer is "yes" we still have reduced the search space to half. So each time the computer wants to ask a question, it can divide its search space approximately in half, until there's only one number left. For an initial search space of eight items, that only takes three questions, like this:

    int hi = 8, lo = 1, mid;
    char ans;
    System.out.println("Think of a number between " + lo + " and " + hi);
    mid = (hi+lo)/2; // initial test @ 4
    System.out.print("Is your number greater than " + mid + " (y/n)? ");
    ans = Zystem.ReadLetter();
    if (ans == 'y') lo = mid+1;
      else hi = mid;
    mid = (hi+lo)/2; // second test @ 2
    System.out.print("Is your number greater than " + mid + " (y/n)? ");
    ans = Zystem.ReadLetter();
    if (ans == 'y') lo = mid+1;
      else hi = mid;
    mid = (hi+lo)/2; // third test @ 1
    System.out.print("Is your number greater than " + mid + " (y/n)? ");
    ans = Zystem.ReadLetter();
    if (ans == 'y') lo = mid+1;
      else hi = mid;
    if (hi==lo) System.out.println("Your number is " + hi);
      else System.out.println("Oops something went wrong");

The first question will always be 4. If not greater, then the range is reduced to 1-4, and the second question is 2, otherwise the range becomes 5-8 and the second question is 6. Can you figure out what the four different possible third questions are? What happens if you give it different starting numbers?

Let's look more closely at how this works.

Using the Debugger

On the left margin of the program code window is a narrow white strip that if you click in it, BlueJ adds a little stop sign at or near where you clicked, like this:

This is called a breakpoint, because when you run the program and it gets here, it will pause and open a Debugger window that looks like this:

For now we are interested only in the "Local variables" panel, which we can enlarge by dragging the dividing lines between the other panels away (up or to the left). When you click on the "Step" button, the program does one statement, which in this case prints one line to the console window, and moves the little arrow in that margin panel to the next statement line, thus:

Step again and the program assigns the value 4 to variable mid, which now also shows up in the "Local variables" panel:

Step a couple more times and the Debugger window goes gray, because the program is not paused at a statement, it's waiting for you to type something into the console window.

Type "y" nd Enter in the console window and the program advances to the next statement line, with the newly defined value in variable ans. The next time you click on Step, the arrow jumps over the "else" line and goes directly to the next evaluation of mid. Do you understand what happened? The condition "(ans == 'y')" evaluated to true, so the statement attached to that test was processed, and not the else-part. Step on down to the next input, but type in "n". See, the condition is false this time, so it updates variable hi and not lo. Each time the program comes to an if/else combination, part of your code gets skipped over. If you draw a line through all the statements that execute -- that is, the computer does what they say to do -- and omit the statements that are skipped because the condition went the other way, it is called the execution path. It is useful to think about the execution path because it will help you to understand why a variable was or was not set (and other things too, as we will see later).

An important part of computer programming is being able to think like a computer, and watching the debugger step through and do its thing is a good way to learn that. Eventually you should be able to think through the steps without watching them most of the time. All of us need to look occasionally, because we make mistakes, and it's sometimes hard to see through what we are thinking (wrong) to what the computer is actually doing.

Next: Iteration & Termination

<<Previous | ToC | Next >>

Revised: 2016 October 17