[ Exercises | Chapter Index | Main Index ]

Solution for Programming Exercise 3.8


This page contains a sample solution to one of the exercises from Introduction to Programming Using Java.


Exercise 3.8:

Write a GUI program that draws a checkerboard. Base your solution on the sample program SimpleGraphicsStarter.java You will draw the checkerboard in the drawPicture() subroutine, after erasing the code that it already contains.

The checkerboard should be 400-by-400 pixels. You can change the size of the drawing area in SimpleGraphicsStarter.java by modifying the line in main() that says drawingArea.setPreferredSize(new Dimension(800,600)) to change the numbers to 400 instead of 800 and 600. A checkerboard contains 8 rows and 8 columns of squares. If the size of the drawing area is 400, that means that each square should be 50-by-50 pixels. The squares are red and black (or whatever other colors you choose). Here is a tricky way to determine whether a given square should be red or black: The rows and columns can be thought of as numbered from 0 to 7. If the row number of the square and the column number of the square are either both even or both odd, then the square is red. Otherwise, it is black. Note that a square is just a rectangle in which the height is equal to the width, so you can use the subroutine g.fillRect() to draw the squares. Here is a reduced-size image of the checkerboard that you want to draw:

checkerboard


Discussion

The basic algorithm is obvious:

for each row of the checkerboard:
    Draw all the squares in that row

Since any given row contains eight squares, one in each column of the checkerboard, we can expand the body of the for loop into another for loop:

for each of the eight rows of the checkerboard:
    for each of the eight columns:
        Draw the square in that row and column

Each square is a rectangle with height 50 and width 50, so it can be drawn with the command g.fillRect(x,y,50,50), where x and y are the coordinates of the top-left corner of the square. Before drawing the square, we have to determine whether it should be red or black, and we have to set the correct color with g.setColor. So, the algorithm becomes

for each row on the checkerboard:
    for each of the eight columns:
        Compute x,y for the top-left corner of the square
        if it's a red square:
           g.setColor(Color.RED)
        else
           g.setColor(Color.BLACK)
        g.fillRect(x,y,50,50)

The top of the first row of squares is at y=0. Since each square is 50 pixels high, the top of the second row is at y=50, followed by 100 for the third row, then 150, 200, 250, 300, and 350. If we assume that the rows are numbered 0, 1, 2, ..., 7, then the tops are given by y = row*50, where row is the row number. (If you number the rows 1, 2, ..., 8, the formula would be (row-1)*20. The simpler formula in this and in many similar cases is one reason why computer scientists like to start counting with 0 instead of 1.) Similarly, the left edge of the squares in column col is given by x = col*50, where again the columns are numbered 0, 1, 2, ..., 7. I'll use "for (row=0; row<8; row++)" to count off the rows, rather than the equivalent "for (row=0; row<=7; row++)". The 8 reminds me that I am counting off the eight numbers 0, 1, 2, ..., 7. Again, this is typical computer science style.

The only problem remaining is how to determine whether the square is red. As noted in the exercise, a square is red if row and col are either both even or both odd. Since an integer N is even if N%2 is 0, the test could be expressed as

if ((row%2 == 0 && col%2 == 0) || (row%2 == 1 && col%2 == 1))

However, note that this is the same as asking whether row%2 and col%2 have the same value. So the test can be written more simply as "if (row%2 == col%2)". Putting this all together into syntactically correct Java code, the algorithm becomes

for ( row = 0;  row < 8;  row++ ) {
   for ( col = 0;  col < 8;  col++ ) {
       x = 50*col;
       y = 50*row;
       if ( (row % 2) == (col % 2) )
          g.setColor(Color.RED);
       else
          g.setColor(Color.BLACK);
       g.fillRect(x,y,50,50);
   }
}

Of course, the variables row, col, x, and y have to be declared to be of type int. Then, the code goes into the body of the drawPicture()subroutine.

The complete program is shown below. In the original program, the size of the drawing area was 800-by-600. I changed this to 400-by-400, as noted in the exercise. And I changed the title of the window to "Checkerboard" in another line in main().

I also changed the name of the class from SimpleGraphicsStarter to Checkerboard. Remember that this also requires changing the name of the file from SimpleGraphicsStarter.java to Checkerboard.java.


The Solution



import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Checkerboard extends JPanel implements ActionListener {

   public void drawFrame(Graphics g, int frameNumber, int width, int height) {

      int row;   // Row number, from 0 to 7
      int col;   // Column number, from 0 to 7
      int x,y;   // Top-left corner of square

      for ( row = 0;  row < 8;  row++ ) {

         for ( col = 0;  col < 8;  col++) {
            x = col * 50;
            y = row * 50;
            if ( (row % 2) == (col % 2) )
               g.setColor(Color.RED);
            else
               g.setColor(Color.BLACK);
            g.fillRect(x, y, 50, 50);
         } 

      }
      
   }
   
   //------ Implementation details: DO NOT EXPECT TO UNDERSTAND THIS ------
   
   
   public static void main(String[] args) {
      
      JFrame window = new JFrame("Checkerboard");
      Checkerboard drawingArea = new Checkerboard();
      drawingArea.setBackground(Color.WHITE);
      window.setContentPane(drawingArea);
      drawingArea.setPreferredSize(new Dimension(400,400));
      window.pack();
      window.setLocation(100,50);
      window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      window.setResizable(false); // The user can't change the size.
      Timer frameTimer = new Timer(20,drawingArea);
      window.setVisible(true);
      //frameTimer.start(); // commented out so we don't get an animation

   } // end main

   private int frameNum;
   
   public void actionPerformed(ActionEvent evt) {
      frameNum++;
      repaint();
   }
   
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      drawFrame(g, frameNum, getWidth(), getHeight());
   }

}

[ Exercises | Chapter Index | Main Index ]