Monkeys at Keyboards: APE Antics
© Michael James Heron and Pauline Belford
Topic: Java Programming
Level: 1
Version: alpha

Expose yourself to your deepest fear - after that, fear has no power, and the fear of freedom shrinks and vanishes. You are free.
Jim Morrison

5 - Repeating Yourself

PreviousTable of ContentsNext
Forum


Chapter Objectives

By the end of this chapter, the reader will be able to:



    5.1

    Introduction

    In this chapter we're going to look at some of the tools that we have for altering the path of execution through our programs through the use of what are known as repetition structures. These are useful structures that allow us to reduce the amount of code we have to write by getting Java to do the work for us.

    When writing a program, we usually encounter circumstances when we are doing the same thing several times. For example, getting Pacman to move forward 12 spaces to get to a piece of food requires us to say main.move( ); twelve times, like so:

    main.move(); 
    main.move();
    main.move();
    main.move();
    main.move();
    main.move();
    main.move();
    main.move();
    main.move();
    main.move();
    main.move();
    main.move();

    It gets a bit tedious, doesn't it? If you're typing that out each time, it'd only be a matter of time before your little fingers were worn away to stubs. It is also easy to get the code wrong - if you need the same statement to run 250 times, or 5000 times, it gets more and more likely that you will add in too many or too few of the commands, and so the program won't do what you want it to do. Errors like this introduced through typing (or even copying and pasting) are called transcription errors.

    Not only that, it also makes debugging (the process of finding errors) harder, as your code becomes very long and unreadable and you need to spend time counting down the number of statements to get an idea for how the program is supposed to behave.

    There's another problem that comes from writing all of this code out again and again - programmers are fundamentally lazy. Oh, you may be thinking to yourself "I'm not lazy! I am young and firm of cheek! I am full of vim and energy!", but I'll prove it to you. Come find me and tell me in person you're not lazy. See, can't be bothered, can you? Any court in the land would declare that as 'case closed'.

    The point is this - if we weren't lazy, we'd be out playing football, cycling or performing some other wholesome activity. Instead, we are sitting at a computer looking up ways to make it do our work for us. That's lazy.

    Anything that takes work away from us and passes it on to the computer is a good thing.

    Luckily for us, we have powerful tools at our disposal known as loops, which make it possible for us to do all this, and keep our code short and easy to read. Moreover, it makes Java do all the work so that we don't have to - and really that's what we should be all about.

    5.2

    The For Loop

    The for loop is the first of these repetition structures, and is used when we know how many times we need to repeat a particular section of code - we may not know it when writing a piece of code, but we know it when the code is running. In technical terms, we refer to this as a bounded loop.


    Terminology Alert!

    A bounded loop is a loop where we have a numerical value that determines how many times we are to iterate.



    Terminology Alert!

    The word iterate just means to repeat, although in a more formal mathematical concept.


    Let's jump in at the deep end at look at the for loop that would make pacman move 12 times. The code for that is as follows:

    int i; 
    for (i = 0; i < 12; i = i + 1) {
    main.move();
    }

    And that's it! See how much more efficient this is? No more pages and pages of repeated instructions - we neatly break all of that off into a simple instruction- 'repeat this piece of code twelve times'.

    So, how does it work? All for loops have the same structure, which can be seen below... and they are broken up into three sections. The first of these is the initialisation section, the second is the continuation section, and the third is the upkeep section. Each of these sections is separated by a semi-colon, in the following way:

    for (initialising; continuation; upkeep) { 
    // Code to repeat
    }

    The for loop takes the following form when turned into code:

    for (counter = start value; counter < end value; counter = counter + 1) 
    {
    // Code to repeat
    }

    In the code we have seen so far, we have seen variables being incremented by one using the following format:

    variable = variable + 1; 

    When working with for loops, we look to be as concise as possible, and so we use a compacted notation for this:

    variable++; 

    It does exactly the same thing (increases the value of the variable by one), it's just quicker to type.

    For loops always begin with the keyword for, which tells Java to expect a for loop.

    For loops need a counter. The counter is an integer variable which keeps track of how many times the for loop has executed. The counter is usually initialised to 0 (to make counting easiest), but you could choose to start at any positive integer.

    The For Loop Exploded
    Fig 5.1: The For Loop Exploded

    Let's look at this code section by section:

    The Initialisation Section

    i = 0; 

    This part of the code initialises the counter variable (which we've called i) and tells the for loop from what number we are going to start counting.

    The Continuation Section

    For loops also need to be told when to stop. This is the second piece of information we add in the brackets.

    i < 12; 

    This bit tells us what number to keep repeating the code until. Every time around the loop, Java checks to see if our counter variable (i) is currently less than the value twelve. If it is, the code within the for loop is repeated again, until it's not.

    The Upkeep Section

    For loops also need to be told to increment the counter.

    i++; 

    Here we are saying "Add 1 to the counter now please"

    Those three sections define all of the information about how a for loop is to repeat, but we then need to provide the information as to what a for loop is to do. This information goes between a pair of curly braces (remember from a previous chapter, the curly braces indicate ownership - anything between the braces of the for loop belongs to the for loop and will be executed when the loop repeats.

    So let's go through the code and see step by step what will happen:

    int i; 
    for (i = 0; i < 12; i++) {
    main.move();
    }

    The first time Java gets to the for loop, the counter (i) is set to 0. It then checks whether 0 is not more than the end value.

    In this case we have set the end value to 12. 0 is not greater than 12, so it moves on to the code inside the for loop braces - this moves pacman forward one step.

    It then increments the counter by 1, and goes back to the beginning of the for loop.

    i is now equal to 1. Java checks whether 1 is less than 12. It is, so pacman moves another space forward, and 1 is added to i. At the end of this, we loop back to the start of the for loop.

    This continues until we have been round the loop 12 times and i is equal to 12. Java checks that i is less than 12, and finds that it is not. It therefore ignores the rest of the for loop, and moves on to execute the next section of code beginning after the closing braces of the For Loop.


    1st time: Pacman moves forward his first step. Counter is incremented to 1
    2nd time: Pacman moves forward his second step. Counter is incremented to 2
    3rd time: Pacman moves forward his third step. Counter is incremented to 3
    4th time: Pacman moves forward his fourth step. Counter is incremented to 4
    5th time: Pacman moves forward his fifth step. Counter is incremented to 5
    6th time: Pacman moves forward his sixth step. Counter is incremented to 6
    7th time: Pacman moves forward his seventh step. Counter is incremented to 7
    8th time: Pacman moves forward his eighth step. Counter is incremented to 8
    9th time: Pacman moves forward his ninth step. Counter is incremented to 9
    10th time: Pacman moves forward his tenth step. Counter is incremented to 10
    11th time: Pacman moves forward his eleventh step. Counter is incremented to 11
    12th time: Pacman moves forward his twelfth step. Counter is incremented to 12

    Let's put all of that together into an Ape program that makes use of a for loop to move pacman forward twelve spaces - we've seen the loop by itself, but lets' look at it in an actual program:

    import draconia.APE.pacman.*; 

    public class Loops {

    public static void main (String [] args) {
    PacmanGame main = new PacmanGame();
    int i;
    main.setMap ("blank");
    main.showGame();
    for (i = 0; i < 12; i++) {
    main.move();
    }

    }

    }

    So we start the program and it begins like so:

    At The Beginning
    Fig 5.2: At The Beginning

    And at the end:

    At The End
    Fig 5.3: At The End

    See, with very little work we make Pacman move twelve spaces along. If we want him to move more (let's say nineteen so that it goes to the end of the side of the map):

    import draconia.APE.pacman.*; 

    public class Loops {

    public static void main (String [] args) {
    PacmanGame main = new PacmanGame();
    int i;
    main.setMap ("blank");
    main.showGame();
    for (i = 0; i < 19; i++) {
    main.move();
    }

    }

    }

    And with no actual work, we make him move further than he did before:

    Moving Him Further
    Fig 5.4: Moving Him Further

    You might be wondering why we check that the counter is less than the end value rather than equal to it. Wouldn't it be simpler to just say for (int i = 0; i == 12; i++)?

    Well, let's look and see what would happen:

    import draconia.APE.pacman.*; 

    public class Loops {

    public static void main (String [] args) {
    PacmanGame main = new PacmanGame();
    int i;
    main.setMap ("blank");
    main.showGame();
    for (i = 0; i == 12; i++) {
    main.move();
    }

    }

    }

    Run this, and nothing happens - Pacman sits there immobile, as if caught in the glare of oncoming headlights.

    Why is this? Well, let's look at what's happening within the loop:

    We start i off at zero. We check the continuation section of the code and repeat if i is equal to twelve, which it isn't. The loop never executes.

    5.3

    Variables and Loops

    For the variables we've been using for our counters in the for loops above, we've declared the variable outside of the loop and then made use of it. This can be useful if we later want to use the variable again for something else. Usually though this isn't the case.

    Java gives us a quicker way to create a counter variable if we are sure we don't want to make use of it outside the loop - we simply declare it at the same time we are initialising it:

    for (int i = 0; i < 10; i++) { 
    }

    Here in our initialisation section, we are declaring a variable called i, and then setting it to zero. We don't need to create the variable elsewhere, but if we try and use it after the loop has finished executing we will get a syntax error:

    import draconia.APE.pacman.*; 

    public class Loops {

    public static void main (String [] args) {
    PacmanGame main = new PacmanGame();
    main.setMap ("blank");
    main.showGame();
    for (int i = 0; i == 12; i++) {
    main.move();
    }

    System.out.println ("Value of i is " + i);
    }

    }

    This causes problems when we try to compile:

    C:\Program Files\Xinox Software\JCreator LE\MyProjects\ForLoops\Loops.java:13: cannot find symbol 
    symbol : variable i
    location: class Loops
    System.out.println ("Value of i is " + i);
    ^
    1 error

    You will see this shorthand quite a lot throughout the notes, so it is important you realise what is happening here - it's just creating a variable that will be used within the for loop and nowhere else within the program. Aside from that, nothing special is happening at all.

    5.4

    Nested For Loops

    In some situations, you will want to repeat a for loop several times. To do this, you could copy and paste the loop the required number of times. For example, in order to get Pacman to walk around the edge of the room clockwise, we could use the following code:

    import draconia.APE.pacman.*; 

    public class UnnestedLoops {

    public static void main (String [] args) {
    PacmanGame main = new PacmanGame();
    main.setMap ("blank");
    main.showGame();
    for (int i = 0; i < 19; i++) {
    main.move();
    }

    main.turnRight();
    for (int i = 0; i < 19; i++) {
    main.move();
    }

    main.turnRight();
    for (int i = 0; i < 19; i++) {
    main.move();
    }

    main.turnRight();
    for (int i = 0; i < 19; i++) {
    main.move();
    }

    main.turnRight();
    }

    }

    If you run the above code you will see that pacman does indeed walk around the room clockwise. But that's an awful lot of code to type out again and again. Or to copy and paste. Wouldn't it be cool if there were some way to make Java do more of the work for us?

    There is! It is possible to put a for loop inside another for loop - a process called nesting. We 'nest' one loop inside another.


    Terminology Alert!

    Putting one for loop inside another is a process known as nesting. We refer to the loops as outer and inner loops. The inner loop is the loop that is being contained within the outer loop.


    We could do this to infinity, so that there were an infinite number of for loops owned by the outermost for loop, but generally we don't want our code to get that complicated.

    For the above case, we just need two for loops. The one that we have repeated 3 times in the above section of code, which gets pacman to walk along the length of one wall, and a second loop which encompasses this loop, and tells it to execute 4 times.

    Let's look at that in terms of how Pacman actually walks around the walls:

    He moves nineteen steps forward
    He turns right

    He moves nineteen steps forward
    He turns right

    He moves nineteen steps forward
    He turns right

    He moves nineteen steps forward
    He turns right

    If we tell Java to move pacman forward 19 times then move right, and put this inside a for loop to execute 4 times, he will move around the whole room for us. And we have only really had to give him two commands rather than the hundred we would have to give if using sequential commands.

    import draconia.APE.pacman.*; 

    public class NestedLoops {

    public static void main (String [] args) {
    PacmanGame main = new PacmanGame();
    main.setMap ("blank");
    main.showGame();
    for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 19; j++) {
    main.move();
    }

    main.turnRight();
    }

    }

    }

    And that's it!

    You may be wondering why we haven't just used i for both for loops. Remember way back in the distant past (well in the section immediately prior to this) when we talked about initialising variables within for loops. There, we showed that these variables are local to the for loop, and we can't access them later on in the program.

    The outer for loop is using the variable i as its counter. The inner for loop is using the variable j as its counter. We need to use two separate counters because they are keeping track of two different things - the outer loop is counting to four and the inner loop is counting to nineteen. Think of it like hands of a clock - the hour hand is pointing to one value, and the minute hand is pointing to another. For every iteration of the hour hand, there are sixty iterations of the minute hand. We use two separate hands of the clock to show this - imagine trying to read a clock that hand one hand to demonstrate both!

    Let's look at what is happening in the program.

    Once APE has been set up, we get to our outer for loop, with i = 0. 0 is less than 4, so the code within this for loop executes.

    The next line it gets to is our inner for loop. j is initialised to 0. It checks that 0 is less than 19, and finds this to be so, and therefore the code within the inner for loop executes and pacman moves forward one step. The counter, j, is then incremented by one and becomes 1.

    The program then moves back to the start of the inner for loop again, and checks if j (which is now equal to 1), is less than 19. It then executes again, causing pacman to move forward another step, and j is then incremented again, now becoming equal to 2. This process continues until j = 19. Java then moves on to the next line of code after the closing brace for the inner for loop, which is main.turnRight(). Pacman therefore turns right, and we reach the end of the outer for loop. At this point, i is incremented by 1, (to become equal to 1) and the program moves back to the start of the outer for loop.

    It then checks if i is less than 4, which it is, and the process begins again. This continues until i = 4 and pacman has made his full circuit of the map.

    5.5

    Conclusion

    So, that's all we need to know about for loops for now. Once you are able to use these then you will seriously reduce the likelihood of getting repetitive strain injury from typing out the same sequential statement thousands of times.

    Nested for loops are more tricky to get your head around initially, but once you get the hang of them you will find them a very useful additional tool in your growing toolkit of programming abilities, like when you get new spells in Warcraft, but it's unlikely you will be able to kill an Orc with a nested for loop.

    Finally, this isn't the final word on for loops. There are also for each loops out there, but we can't look at these until you are able to use arrays. We therefore have more fun with for loops to come! Until then, happy looping.

    Further Reading

    The following table details further reading on the topic in this chapter, and also any external resources that you may find useful.

    ResourceDescription
    Example Programs from this chapterThis is a zip file of all the programs shown in this chapter.

    PreviousTable of ContentsNext

    © 2004-2006 Michael James Heron and Pauline Belford