Checkers, anyone?

Develop a Swing-based library that presents a checkers game user interface

1 2 Page 2
Page 2 of 2

Listing 3. Checker.java

import java.awt.Color;
import java.awt.Graphics;

public final class Checker
{
   private final static int DIMENSION = 50;

   private CheckerType checkerType;

   public Checker(CheckerType checkerType)
   {
      this.checkerType = checkerType;
   }

   public void draw(Graphics g, int cx, int cy)
   {
      int x = cx - DIMENSION / 2;
      int y = cy - DIMENSION / 2;

      // Set checker color.

      g.setColor(checkerType == CheckerType.BLACK_REGULAR ||
                 checkerType == CheckerType.BLACK_KING ? Color.BLACK : 
                 Color.RED);

      // Paint checker.

      g.fillOval(x, y, DIMENSION, DIMENSION);
      g.setColor(Color.WHITE);
      g.drawOval(x, y, DIMENSION, DIMENSION);

      if (checkerType == CheckerType.RED_KING || 
          checkerType == CheckerType.BLACK_KING)
         g.drawString("K", cx, cy);
   }

   public static boolean contains(int x, int y, int cx, int cy)
   {
      return (cx - x) * (cx - x) + (cy - y) * (cy - y) < DIMENSION / 2 * 
             DIMENSION / 2;
   }

   // The dimension is returned via a method rather than by accessing the
   // DIMENSION constant directly to avoid brittle code. If the constant was
   // accessed directly and I changed its value in Checker and recompiled only
   // this class, the old DIMENSION value would be accessed from external 
   // classes whereas the new DIMENSION value would be used in Checker. The
   // result would be erratic code.
   
   public static int getDimension()
   {
      return DIMENSION;
   }
}

As with Board, there isn't much to say about Checker. In the draw() method, expressions int x = cx - DIMENSION / 2; and int y = cy - DIMENSION / 2; convert from a checker's center coordinates to the coordinates of its upper-left corner. These coordinates are required by the subsequent fillOval() and drawOval() method calls as their first two arguments. Also, contains() uses the Pythagorean theorem to help it determine if an arbitrary point (x, y) lies within the circle centered at (cx, cy) and having a radius of DIMENSION / 2. Essentially, the difference between these points is determined and used by the Pythagorean equation to determine if (x, y) lies within the circle.

For completeness, Listing 4 presents CheckerType.

Listing 4. CheckerType.java

public enum CheckerType
{
   BLACK_REGULAR,
   BLACK_KING,
   RED_REGULAR,
   RED_KING
}

Demonstrating the checkers GUI library

Now that you've learned about the checkers GUI library's design and implementation, you'll probably want to try it out. I've created a short Checkers application that demonstrate the library. Listing 5 presents its source code.

Listing 5. Checkers.java

import java.awt.EventQueue;

import javax.swing.JFrame;

public class Checkers extends JFrame
{
   public Checkers(String title)
   {
      super(title);
      setDefaultCloseOperation(EXIT_ON_CLOSE);

      Board board = new Board();
      board.add(new Checker(CheckerType.RED_REGULAR), 4, 1);
      board.add(new Checker(CheckerType.BLACK_REGULAR), 6, 3);
      board.add(new Checker(CheckerType.RED_KING), 5, 6);
      setContentPane(board);

      pack();
      setVisible(true);
   }

   public static void main(String[] args)
   {
      Runnable r = new Runnable()
                   {
                      @Override
                      public void run()
                      {
                         new Checkers("Checkers");
                      }
                   };
      EventQueue.invokeLater(r);
   }
}

Assuming that the library's four source files are in the same directory as Checkers.java, compile Listing 5 as follows:

javac Checkers.java

Run the resulting application as follows:

java Checkers

Figure 2 shows the resulting user interface.

Figure 2. A king is distinguished by letter K

A king is distinguished by letter K

Drag each checker over the board. You'll notice that the checker snaps to the middle of the destination square. Also, try dragging a checker onto an occupied square and observe what happens.

Conclusion

This post presented one implementation of a GUI library for a Java checkers game. In a different implementation, I might not record Checkers in a List<PosCheck> collection. Instead, it might be more efficient and lead to clearer code to store them in a Checker[8][8] table and provide translation code between row/column indexes and checker center coordinates. I'm interested in your comments on alternative library implementations.

I plan to revisit the checkers GUI library in a future post and introduce additional capabilities, such as adding a remove() method to the Board class for removing a Checker that's been jumped. Also, I want to introduce logic into Board that a computer player would call to move a checker and possibly jump one or more intermediate checkers. And in a post even further into the future, I'd like to explore some algorithms for a computer player and introduce a complete checkers game.

download
Get the source code for this post's applications. Created by Jeff Friesen for JavaWorld

The following software was used to develop the post's code:

  • 64-bit JDK 7u6

The post's code was tested on the following platform(s):

  • JVM on 64-bit Windows 7 SP1
1 2 Page 2
Page 2 of 2