The goal of this assignment is to practice writing classes that implement interfaces.
If this lab runs long, you should be sure to commit what you have and hand it in at the end of today's lab period.
This project asks you to finish a program that allows two people to play chess on the computer. Most of your work will be in writing code that determines whether or not a move is legal. Most of the necessary information about the game is contained in this project description, but if you're unfamiliar with the rules of chess, you may find a rules of chess reference helpful.
A large portion of the program is already written. Clone the repository from the class directory to get started:
$ cd csci235 $ hg clone /cslab/class/csci235/labs/lab8 $ cd lab8
Open Piece.java
in Emacs.
The Piece
interface is a supertype for classes
that represent the various pieces of chess.
It declares methods to check what color the piece is, tell the piece
what its position on the the board is, make a string representation of it,
and determine whether a move is legal for that piece (more on that last
part later...). Each kind of piece (King, Queen, Rook, etc) will have its
own class that implements Piece
.
A piece also has a color, which we will indicate using a boolean value
(true=black, false=red; red is chosen instead of white because red is
slightly easier to see in the GUI).
You might want to also look at the
javadoc for this interface.
ChessBoard
is a class that represents a board.
You will not need to make any changes to this file.
In fact, you do not really need to know how it works
(though it would be a helpful exercise for you to read it carefully
and understand it), only what it does.
It is an 8x8 grid that can contain chess pieces.
Positions are indicated by row,column pairs. For example,
the position in the upper lefthand corner is position 0 0, and
the position in the lower righthand corner is position 7 7.
The most important thing that you will need to do is determine what
piece (if any) is at a certain position; so look closely at the
description of the method pieceAt()
. If there is no
piece, that is indicated by the value null
. I have
provided stripped down javadoc for
this class.
Chess
has the main method (though most of the
work is in the Chess
constructor).
It displays a new window that shows the chess board.
Pieces are marked by letters indicated what kind of piece it is.
When it is a player's turn, he or she can click on a piece he or
she wants to move (at which point the space the piece is currently
on will turn green) and then click on the space to which
the piece should move.
If the program determines that such a move is possible, then
the piece disappears from the original space and appears in the
indicated space.
(If the user changes his or her mind before clicking on the destination,
clicking on the original space a second time unselects that piece.)
Try out the game as it is so far, which is how we left it at the end of class yesterday, when we completed the implementation for kings.
$ javac *.java $ java Chess &
Next open Chess.java
in Emacs (if you haven't already);
most of it is GUI stuff you can ignore. Note that the constructor
sets up the board by calling the populate()
method in
class ChessLib
.
If you look at ChessLib.java
, you'll find that it
places the kings in appropriate places. As you implement other
kinds of pieces, you will need to update populate()
to
place them on the board.
Very important: You will have no reason to modify
Chess
, ChessBoard
or Piece
.
Your task is to fix the implementation of the classes for the
various kinds of pieces, as we did in class for King
.
(We won't worry about the rule that says that a king can't move into
check.)
You won't have to worry about the row, column values being out-of-bounds; the game ensures that for you.
Now write a new class Knight
that also implements the
interface Piece
. The knight will have to display as
N
(because the king has K
). A knight can
move three spaces
in an L-shape (two vertically and one horizontally, or vice versa).
The knight is unique in that it can move through other pieces.
If you'd like to make your Knight
from the
King
, you can start by copying it using Mercurial:
$ hg copy King.java Knight.javaThat will record the history nicely; if you create
Knight.java
some other way, you will need to tell Mercurial
about the additional file:
$ hg add Knight.java
After changing the letter displayed, your work will be to write
canMoveTo()
correctly.
Instead of testing separately for each of the eight legal
destinations, you might think carefully about whether you can describe
the cases arithmetically. As a hint, recall that there are useful
methods in classes Math
and Integer
.
You will need to create the knights and place them on the board;
that is done in ChessLib.populate()
. (See the Wikipedia
page if you aren't sure where to put them.) And remember to commit
when you've finished with knights.
Now write a new class Rook
that also implements the
interface Piece
. The rook should be able to move to any
square in the same row or column, but it cannot move through another
piece and it cannot move onto a square occupied by a piece of the same
color. A rook should display as the letter R
(instead of
the king's K
).
You probably want to complete your new class in stages. If you copy one of the classes you've already written, you'll be able to run the program once you:
populate
).
That leaves the old rules in place about where it can move, which will be wrong, but at least you can run the program. Then you can tackle the three constraints on legal moves, one at time:
You should feel free to hg commit
after each step that
you successfully test.
To allow you to move more quickly through the various pieces, I
have provided a method ChessHelp.pathIsOpen()
that you
can use to test the path between two positions. Here is the
documentation from its source:
/** * Are the spaces between two positions all empty? * @param board The board * @param startRow The vertical position from which to move a piece * @param startCol The horizontal position from which to move a piece * @param endRow The vertical position to which to move a piece * @param endCol The horizontal position to which to move a piece * @return Whether the path is all empty. * PRECONDITION: move is either rectangular or diagonal */ public static boolean pathIsOpen(ChessBoard board, int startRow, int startCol, int endRow, int endCol);Note that it checks the positions between the endpoints, but not the start and end positions. Also, notice the precondition: this method will throw an exception if you violate the precondition.
Now complete classes Bishop
(display as
B
) and Queen
(display as Q
). A
bishop can move any number of spaces diagonally; a queen can move
either diagonally or within a row or column. As with the rook, they
can not move through an occupied square, and they should not move onto
a space occupied by a piece of the same color.
Think carefully about how to write this code. If you find that you
want to have a static method that can be called from more than one class, you
can put it in class ChessLib
.
Pawns are the most difficult. They must obey the following rules:
Before a pawn becomes a queen, it should print out "P", but afterwards, it should print out "Q". (Hint)
Don't forget to update populate()
.
pathIsOpen()
Write your own method or methods (in class ChessLib
) to replace
your calls to the provided pathIsOpen()
method.
If you have time and would like to earn some extra credit, you may implement one or both of the following features:
In the directory where you have your files, run the command
/cslab/class/csci235/bin/handin lab8 .
Note the dot: that means to turn in everything in the current directory (including your Mercurial repository).
You should turn in whatever you have done at the end of lab time.
If you want to keep working, you may do so and turn that in later as
lab8b
. Here is a reminder
about how to copy your repository to
your account.