Picture of Cover

         
Home
Textbook
Software
Robot Examples
Pick3
GraphOne
GraphMultiple
GraphThreads
Checkers
Robots Documentation
Demos of becker.xtras
Java Documentation
Downloads
Installation
Favorite Tools
Change Log
Instructors
 
Printer Friendly Page

Robot Example: Checkers

In the following applet the user may direct robot “checkers” to play a game. To play, click the “Start” button and then click on the checkerboard. The movements of the robots can be controlled with the keyboard. Type the letter labelling the robot you want to move and then either “e” or “w” to move east or west, respectively, or “E” or “W” to jump east or west, respectively.

Much of the source code to set up the checkerboard and robots is shown below. Some of the code is missing, however, so this problem can be used as a homework problem. The following is the problem statement the students received.

In this assignment, you'll be finishing a program that allows two people to play a game of checkers using robots as the “pieces”. To simplify the problem, the version of checkers that you will implement does not handle all of the rules of the standard game. Your task is to implement the rules that we have described so that your version of the game plays exactly as the applet above.

Implement the following changes to the program:

  • Construct the robots:
    • The CBoardCity class currently constructs CompetitionBots. Change it to construct CheckerBots.
    • Modify the CheckerBot class so that it extends CompetitionBot.
    • Each CheckerBot will need a unique id so it knows when it should respond to a command. Use the getNextID method in CBoardCity to provide an id for each robot when it is constructed.
    • Make sure robots are positioned and coloured as shown above.
  • Make the robots respond to your commands:
    • Override the keyTyped method to respond to keyboard commands. This method is inherited by the Robot class from the Sim class. Read the documentation for this method here. This method will be called first with a letter to identify which robot should move. It will be called again with a letter saying which direction it should move. Information will need to be remembered between the two calls.
    • The basic commands are e (move east), w (move west), E (jump east), and W (jump west).
    • Robots that end up on a square already occupied by an opponent should be broken.
  • (Optional) Earn up to 5 bonus marks:
    • When a piece reaches the other side of the board, it becomes a "King" and can move/jump in any diagonal direction. Change the appearance of kings and allow them to turn around with the 'T' command.
    • When a robot lands on any square that is already occupied, it becomes broken.

Hints

  • Most of the work you do will be in the CheckerBot class.
  • You will need to make small modifications in CBoardCity where the robots are created.
  • You will need to make use of services offered by CompetitionBot but do not need to make any changes to the class.
  • You do not need to make any changes to Checkers, OpponentPredicate, or Square.
  • Remember that the focus of the week has been on extending classes with instance variables and overriding methods.

Checkers.java

package examples.checkers;


/*
 * Checkers.java 1.0 
 * Copyright 2003 by Byron Weber Becker.  All rights reserved.
 */
import becker.robots.*;


/** Set up a game of checkers for two players. 
 * 
 * @author Byron Weber Becker */
public class Checkers extends Object
{
   public static void main(String[] args) 
   {  CBoardCity board = new CBoardCity(8, 8);
      board.placeBlackCheckers();
      board.placeRedCheckers();
      CityFrame cf = new CityFrame(board, -1, -1, 10, 10);
   }
}

CBoardCity.java

package examples.checkers;


import becker.robots.*;
import java.awt.Color;
import java.awt.geom.*;


/** Make a robot city look like a checkerboard.  Add robots
 * that can be used to play checkers.
 *
 * @author Byron Weber Becker */
public class CBoardCity extends City
{
          
   // the width of the board     
   private int width;
   // the height of the board
   private int height;
   // the ID to assign to the next checker-playing robot
   private char nextID = 'a';
           
   /** Construct a new city that looks like a checkerboard.
    * @param theWidth number of squares wide
    * @param theHeight number of squares high */    
   public CBoardCity(int theWidth, int theHeight)
   {  super();
      this.width = theWidth;
      this.height = theHeight;
   }
	
   /** Place the red checkers (robots) on the board. */
   public void placeRedCheckers()
   {  for (int str = 0; str < 3; str++)
      {  for (int ave = 0; ave < this.width; ave++)
         {  if (ave % 2 != str % 2)
            {	// Create a red robot checker player here.
            }
         }
      }
   }
	
   /** Place the black checkers (robots) on the board. */
   public void placeBlackCheckers()
   {  for (int str = 5; str < this.height; str++)
      {  for (int ave = 0; ave < this.width; ave++)
         {  if (ave % 2 != str % 2)
            {	// Create a black robot checker player here.
            }
         }
      }
   }
		
   /** Override the default makeIntersection method to make a 
    * customized intersection for a checkboard. 
    * @param ave the avenue for this intersection
    * @param str the street for this intersection */
   protected Intersection makeIntersection(int ave, int str)
   {  return new Square(this, ave, str, this.width, this.height);
   }
	
   /** Override the default method to customize the 
    * intersections with boundary walls.
    * @param i the intersection to customize */
   protected void customizeIntersection(Intersection i)
   {  int ave = i.getAvenue();
      int str = i.getStreet();
		
      if (ave == 0 && str >= 0 && 
		    str < this.height)
      {  this.addBoundaryWall(ave, str, Directions.WEST);
      } else if (ave == this.width - 1 && 
		           str >= 0 && str < this.height)
      {  this.addBoundaryWall(ave, str, Directions.EAST);
      } 
		
      if (str == 0 && ave >= 0 && 
		    ave < this.width)
      {  this.addBoundaryWall(ave, str, Directions.NORTH);
      } else if (str == this.height - 1 && 
		           ave >= 0 && ave < this.width)
      {  this.addBoundaryWall(ave, str, Directions.SOUTH);
      }
		
   }
	
   /** Add a boundary wall to the give intersection
    * @param a the wall's avenue
    * @param s the wall's street
    * @param c the wall's corner on the intersection */
   private void addBoundaryWall(int a, int s, int c)
   {  Wall w = new Wall(this, a, s, c);
      ColoredIcon ci = (ColoredIcon) w.getIcon();
      ci.setColor(Color.white);		
   }
	
   /** Generate the next ID to use to identify a robot.
    * Skip the letters used for commands. 
    * @return a character ID */
   private char getNextID()
   {  if (this.nextID == 'e' || this.nextID == 'w')
      {  this.nextID++;
      }	
		
      char answer = this.nextID;
      this.nextID++;
      return answer;
   }
}

CompetitionBot.java

package examples.checkers;
import becker.robots.*;


/** A kind of robot that can play games requiring an 
 * opponent to be removed from the board. 
 *
 * @author Byron Weber Becker */
public class CompetitionBot extends RobotSE
{
   // constants to identify which side each robot is on
   public static final int SIDE_1 = 1;
   public static final int SIDE_2 = 2;
   
   // an object needed to find opponents on the 
   // same intersection as this robot
   private OpponentPredicate oppPredicate;
	
   // which side is this robot on?  One of {SIDE_1, SIDE_2}.
   private int side;
	
   /** Construct a new robot
    * @param aCity the city it will be in
    * @param anAve the avenue
    * @param aStr the street
    * @param aDir the direction it faces
    * @param aSide the team/side it's on */
   public CompetitionBot(City aCity, int anAve, int aStr, 
	                      int aDir, int aSide)
   {  super(aCity, anAve, aStr, aDir);
      this.side = aSide;
		
      if (aSide == SIDE_1)
      {  this.oppPredicate = new OpponentPredicate(SIDE_2);
      } else
      {  this.oppPredicate = new OpponentPredicate(SIDE_1);
      }
   }
	
   /** Which side/team is this robot on?
    * @return this robot's side/team */
   public int getSide()
   {  return this.side;
   }
	
   /** Is this robot on the same intersection as a robot on the  
    * opposing side/team? 
    * @return true if this robot is beside an opposing robot; 
    *         false otherwise */
   public boolean isBesideOpponent()
   {  return this.isBesideThing(this.oppPredicate);
   }
	
   /** Remove a robot from the opposing team from this
    *  robot's intersection. This robot breaks if there
	 *  is no such robot. */
   protected void removeOpponent()
   {  if (this.isBesideOpponent())
      {  CompetitionBot cb = 
            (CompetitionBot)this.examineThing(this.oppPredicate);
         Square sq = (Square) this.getIntersection();
         sq.removeThing(cb);
         cb.breakRobot();
      } else
      {	// error -- wasn't beside a robot
         this.breakRobot();
      }
   }
	
}

CheckerBot.java

This is the primary class for students to complete.

package examples.checkers;
import becker.robots.*;
import java.awt.Color;


/** A checker-playing robot.
 *
 * @author Byron Weber Becker */
public class CheckerBot extends RobotSE
{
   // rename constants to make sense for Checkers
   public static final int RED = CompetitionBot.SIDE_1;
   public static final int BLACK = CompetitionBot.SIDE_2;


}

OpponentPredicate.java

package examples.checkers;


import becker.robots.*;


/** A predicate class used to find robots on a particular team. 
 *
 * @author Byron Weber Becker */
public class OpponentPredicate implements Predicate
{
   private int side;
	
   public OpponentPredicate(int aSide)
   {  super();
      this.side = aSide;
   }
	
   /** Return true if this thing is a CompetitionBot from 
    * the opposite team as this.side. */
   public boolean isOK(Thing t)
   {  if (t instanceof CompetitionBot)
      {  CompetitionBot cb = (CompetitionBot) t;
         return cb.getSide() == this.side;
      } 
		
      return false;
   }
}

Square.java

package examples.checkers;
import becker.robots.*;
import java.awt.geom.*;
import java.awt.Color;


/** A "square" on a checkerboard.
 *
 * @author Byron Weber Becker */
public class Square extends Intersection
{
   private Icon redSquare = new ShapeIcon(
	      new Rectangle2D.Double(0.0, 0.0, 1.0, 1.0),
         Color.red.darker());
   private Icon blackSquare = new ShapeIcon(
	      new Rectangle2D.Double(0.0, 0.0, 1.0, 1.0),
         Color.black);
   private Icon greenSquare = new ShapeIcon(
	      new Rectangle2D.Double(0.0, 0.0, 1.0, 1.0),
         Color.green.darker());

   /** Construct the square. 
    * @param aCity the city it will be in
    * @param anAve the avenue
    * @param aStr the street
    * @param boardWidth the width of the entire board
    * @param boardHeight the height of the entire board*/
   public Square(City aCity, int anAve, int aStr, 
	              int boardWidth, int boardHeight)
   {  super(aCity, anAve, aStr);
      if (anAve < 0 || anAve >= boardWidth || 
		    aStr < 0 || aStr >= boardHeight)
      {  this.setIcon(this.greenSquare);
      } else if (anAve % 2 == aStr % 2)
      {  this.setIcon(this.redSquare);
      } else
      {  this.setIcon(this.blackSquare);
      }

   }
	
   /** Remove the given robot from this square.  (This needs 
    * to be here simply to make the method public -- it's 
	 * protected in the superclass.
    * @param bot The robot to remove */
   public void removeThing(CompetitionBot cb)
   {  super.removeThing(cb);
   }
}


Contact: bwbecker@learningwithrobots.com.