Question

I'm reading through a programming book and am having trouble understanding a few parts of this code. The program draws a checkerboard, and colors the odd squares black.

import acm.graphics.*;
import acm.program.*;

public class CheckerBoard extends GraphicsProgram   {

public void run()   {
    double squareSize = (double) getHeight() / numRows;
    for(int i = 0; i <= numRows; i++){
        for(int j = 0; j <= numColumns; j++)    {
            double x = j * squareSize;
            double y = i * squareSize;
            GRect square = new GRect(x,y,squareSize,squareSize);
            square.setFilled((i + j) % 2 != 0);
            add(square);
        }
    }
}

private static final int numRows = 8;
private static final int numColumns = 8;

I understand most of the code, but I am still a little confused.

My first question is: How exactly does the program go through the for loops? They are nested, so would it create all of the columns (the j for loop) first? Or does it increment both i and j after the block of code finishes?

Secondly, why do I set x = j, and y = i? x is horizontal and j is vertical, shouldn't I set x = i and y = j? Both seem to yield the same results.

Mostly, I would just like to know how the for loop runs each time around. a basic run or two through the program.

Any help would be appreciated, thanks!

Was it helpful?

Solution

My first question is: How exactly does the program go through the for loops? They are nested, so would it create all of the columns (the j for loop) first? Or does it increment both i and j after the block of code finishes?

Neither, really. Nested loops like this do not increment at the same time: the inner loop will run until j violates the condition (j > numColumns), then the i loop (the outer loop) will increment and the whole inner loop will run again. Also, as @JayElston said, only one square is drawn at a time. What this means is that on each run through the inner loop the program draws one row of squares, one in each column. The outer loop repeatedly draws these rows to create the whole checkerboard. So the idea is that the inner loop does not draw whole columns, but rather the part of each column that is in the row currently being worked on.

Secondly, why do I set x = j, and y = i? x is horizontal and j is vertical, shouldn't I set x = i and y = j? Both seem to yield the same results.

As far as the x=j and y=i, what you've written isn't quite accurate. x is actually set to j times the width of a square, and y is set to i times the width of a square. So if we're on the fourth column, we are four squares horizontally from the starting point, and thus four times the width of a square in the x-direction from the edge. The fact that both yield the same results is a coincidence; it only happens because the checkerboard is square. Change numRows to 15 and run the program, then flip-flop them and run it again and you should see the difference. The first time, the number of rows will be 15 (or 16 if you've written the program with <= in the for loops), as expected from the variable name. But when x=i*squareSize, the number of columns will be 15. Note that x and y are positions at which to draw the squares, not the numbers of the rows and columns. That may make it make more sense.

Mostly, I would just like to know how the for loop runs each time around. a basic run or two through the program.

Something that might help would be to include the line System.out.println("i:"+i+"; j:"+j+"; x:"+x+"; x:"+y); in the inner loop right after GRect square.... (as I've demonstrated in my code below) In Java, System.out.println will show things on the console. Putting in that line will make the program spit out a line each time it draws a square, giving the values of i, j, x, and y.

Finally, here's an expanded version of the program with lots of comments. It also tells you about its progress, which hopefully will help you see what's happening. Note that I wouldn't normally use multiline comments (/*...*/) anywhere near this much.

import acm.graphics.GLabel;
import acm.graphics.GRect;
import acm.program.GraphicsProgram;

public class CheckerBoard extends GraphicsProgram {

  public void run() {
    double squareSize = (double) getHeight() / numRows;

    /*
     * Make a variable to carry the number of the square
     * that's being made. So, the first square will be
     * number 0, the second will be number 1, etc.
     */
    int num = 0;

    /*
     * Run the contents once for each number between 0 and
     * numRows Note the < and not <=. Because we're starting
     * from 0, we need to use <. For example, suppose we
     * wrote int i=0; i<=1; i++. We would get our loop run
     * once with i=0 and once with i=1 before i would not be
     * <= 1. Since our numbers in this case are supposed to
     * be the number of rows, we don't want to loop after we
     * do the one before our numRows or numColumns
     */
    for (int i = 0; i < numRows; i++) {
      /*
       * Run the contents of this loop once for each number
       * between 0 and numColumns, including 0, not
       * including numColumns.
       */
      for (int j = 0; j < numColumns; j++) {
        /*
         * Calculate the position for the next square. If
         * we're in column 4, then the next square should be
         * at 4*(the width of each square).
         */
        double x = j * squareSize;
        double y = i * squareSize;

        /*
         * Create a square that's to be put at our x and y
         * positions calculated just above. Make its width
         * squareSize and its height squareSize.
         */
        GRect square = new GRect(x, y, squareSize, squareSize);

        /*
         * Make some text that will be put down. Use the
         * current value of num for its text
         * (Integer.toString just makes that integer into
         * text), and put it at the x-position we're working
         * with plus 1/4 of a squareSize and the y-position
         * we're working with plus 3/4 of a square. This
         * fakes centering the text in the squares.
         */
        GLabel label = new GLabel(Integer.toString(num), x + squareSize * .25,
            y + squareSize * .75);

        /*
         * Tell the user what our i, j, x, y, and num values
         * are.
         */
        System.out.println("i:" + i + "; j:" + j + "; X:" + x + "; Y:" + y
            + "; num: " + num);

        square.setFilled((i + j) % 2 != 0);
        add(square);

        /*
         * Stick that label on the page, just like with the
         * square.
         */
        add(label);

        /*
         * Increment the number variable (add one to it) so
         * the next square is num+1 (if this is square 0,
         * then the next one should be square 1)
         */
        num++;
      }
    }
  }

  // Change this to make the checkerboard non-square.
  private static final int numRows = 8;
  private static final int numColumns = 8;
}

And here's what I get on my console when I run it:

i:0; j:0; X:0.0; Y:0.0; num: 0
i:0; j:1; X:25.0; Y:0.0; num: 1
i:0; j:2; X:50.0; Y:0.0; num: 2
i:0; j:3; X:75.0; Y:0.0; num: 3
i:0; j:4; X:100.0; Y:0.0; num: 4
i:0; j:5; X:125.0; Y:0.0; num: 5
i:0; j:6; X:150.0; Y:0.0; num: 6
i:0; j:7; X:175.0; Y:0.0; num: 7
i:1; j:0; X:0.0; Y:25.0; num: 8
i:1; j:1; X:25.0; Y:25.0; num: 9
i:1; j:2; X:50.0; Y:25.0; num: 10
i:1; j:3; X:75.0; Y:25.0; num: 11
i:1; j:4; X:100.0; Y:25.0; num: 12
i:1; j:5; X:125.0; Y:25.0; num: 13
i:1; j:6; X:150.0; Y:25.0; num: 14
i:1; j:7; X:175.0; Y:25.0; num: 15
i:2; j:0; X:0.0; Y:50.0; num: 16
i:2; j:1; X:25.0; Y:50.0; num: 17
i:2; j:2; X:50.0; Y:50.0; num: 18
i:2; j:3; X:75.0; Y:50.0; num: 19
i:2; j:4; X:100.0; Y:50.0; num: 20
i:2; j:5; X:125.0; Y:50.0; num: 21
i:2; j:6; X:150.0; Y:50.0; num: 22
i:2; j:7; X:175.0; Y:50.0; num: 23
i:3; j:0; X:0.0; Y:75.0; num: 24
i:3; j:1; X:25.0; Y:75.0; num: 25
i:3; j:2; X:50.0; Y:75.0; num: 26
i:3; j:3; X:75.0; Y:75.0; num: 27
i:3; j:4; X:100.0; Y:75.0; num: 28
i:3; j:5; X:125.0; Y:75.0; num: 29
i:3; j:6; X:150.0; Y:75.0; num: 30
i:3; j:7; X:175.0; Y:75.0; num: 31
i:4; j:0; X:0.0; Y:100.0; num: 32
i:4; j:1; X:25.0; Y:100.0; num: 33
i:4; j:2; X:50.0; Y:100.0; num: 34
i:4; j:3; X:75.0; Y:100.0; num: 35
i:4; j:4; X:100.0; Y:100.0; num: 36
i:4; j:5; X:125.0; Y:100.0; num: 37
i:4; j:6; X:150.0; Y:100.0; num: 38
i:4; j:7; X:175.0; Y:100.0; num: 39
i:5; j:0; X:0.0; Y:125.0; num: 40
i:5; j:1; X:25.0; Y:125.0; num: 41
i:5; j:2; X:50.0; Y:125.0; num: 42
i:5; j:3; X:75.0; Y:125.0; num: 43
i:5; j:4; X:100.0; Y:125.0; num: 44
i:5; j:5; X:125.0; Y:125.0; num: 45
i:5; j:6; X:150.0; Y:125.0; num: 46
i:5; j:7; X:175.0; Y:125.0; num: 47
i:6; j:0; X:0.0; Y:150.0; num: 48
i:6; j:1; X:25.0; Y:150.0; num: 49
i:6; j:2; X:50.0; Y:150.0; num: 50
i:6; j:3; X:75.0; Y:150.0; num: 51
i:6; j:4; X:100.0; Y:150.0; num: 52
i:6; j:5; X:125.0; Y:150.0; num: 53
i:6; j:6; X:150.0; Y:150.0; num: 54
i:6; j:7; X:175.0; Y:150.0; num: 55
i:7; j:0; X:0.0; Y:175.0; num: 56
i:7; j:1; X:25.0; Y:175.0; num: 57
i:7; j:2; X:50.0; Y:175.0; num: 58
i:7; j:3; X:75.0; Y:175.0; num: 59
i:7; j:4; X:100.0; Y:175.0; num: 60
i:7; j:5; X:125.0; Y:175.0; num: 61
i:7; j:6; X:150.0; Y:175.0; num: 62
i:7; j:7; X:175.0; Y:175.0; num: 63

OTHER TIPS

The double for-loop is essentially the same as this code:

int i = 0;

while (i <= numRows) {
    int j = 0;

    while (j <= numColumns) {
        double x = j * squareSize;
        double y = i * squareSize;
        GRect square = new GRect(x,y,squareSize,squareSize);
        square.setFilled((i + j) % 2 != 0);
        add(square);

        j++;
    }

    i++;
}

There is one small difference: at the end of the outer while-loop, i will have the value numRows + 1. If you use the for-loop the variable i will be out of scope.

Each time through the inner loop, a single board square is drawn (by adding it to the board). The following three lines of code draw the square:

GRect square = new GRect(x,y,squareSize,squareSize);
square.setFilled((i + j) % 2 != 0);
add(square);

(x,y) in the first line specify the upper left coordinate of the square to be drawn.

The second line determines the square color. As the inner and outer loops iterate, the value of i+j alternates between even and odd.

The squares are added in column order. After one full cycle of the inner loop, a new row of eight squares will be added.

The outer loop iterates once for each row, cycling through the inner loop to add the row.

A for loop is perhaps the most commonly used form of iteration. This loop performs initialization before the first iteration. Then it performs conditional testing and, at the end of each iteration, some form of “stepping.”

Licensed under: CC-BY-SA with attribution
scroll top