COMP 150-SEN, Spring 2019
Test case due: Wed, Feb 20 @ 11:59pm
Main project due: Thu, Feb 28 @ 11:59pm
Boardmethods to help with grading:
void clear(), which should remove all pieces from the board, and
void removeAllListeners(), which should remove all listeners.
movesshould take the positions of other pieces on the board into account; that
movePieceshould raise an exception if the location(s) are invalid;
PawnFactory; clarified that
movePieceshould rise an exception if the move is invalid.
In this project, you will implement a chess game simulator. Your simulator will take as input a file that describes the initial locations of pieces on the board and a series of moves of those pieces. Your simulator will then set up the board and execute those moves, checking that all the moves are legal and, at the end, printing the state of the game board.
The real goal of implementing this project, however, is to gain experience with design patterns. More specifically, as part of this project you will implement the following patterns: Singleton, Factory, External Dependency Injection, Observer, and (External) Iterator. Here is a code skeleton to get you started.
This project will also give you a little practice with the essential software engineering skill of solving programming problems by finding library code to do what you want. We'll give you some hints, but fewer than in the last project. So you'll need to spend some time searching on Google and poking around the JDK 11 API. Most of the methods you want are probably in the following:java.nio or java.util.regex. In this and all other projects, you are allowed to use any part of the JDK 11 API you like.
This project doesn't break down into separate steps quite the way the previous one does, but it does break down into modules. So this writeup is organized as a description of the modules you'll need to write. The description is written in an order that's sensible for presentation, but you can implement the different modules in whatever order you want.
Hint: The hardest part of the, in a technical sense, is writing the code to model the moves of all the chess pieces. The rest of the project has much less code, but you will need some time to understand all the design patterns we've crammed into the project. And yes, there are too many design patterns here, but hopefully not as many as this factorial implementation that's been design patterend to death.
Note: You are free to add any helper methods, additional classes, etc, that you'd like to for this project. Just be sure to upload a complete, working program to Gradescope.
Recall that the game of chess is played on and eight-by-eight board with the following initial layout:
Your simulator will be run via the command
java Chess layout moveswhere layout is the name of a file describing the initial locations of pieces on the chessboard, and moves is the name of a file describing a sequence of moves. We've given you one example each of the layout and move files, layout1 and moves1, respectively, where layout1 contains the standard setup of chess pieces on the board. For ideas of other ways you could lay out chess pieces initially, search the web for chess puzzles or chess problems.
You will need to write code in
Chess.java that (a)
reads data from the layout file and sets up the board and then (b)
plays the sequence of moves in the moves files. Of course, you can create
whatever additional methods and classes you need.
If you look in
Chess.java, you'll see a
main method of the usual type. You'll want to add your
code toward the bottom of this method. Notice that the names of the files
you need to read are given on the command line, which means they will
be stored in the
args parameter of
layout file name will be in
args, and the moves file
name will be in
To write this code, you'll need to figure out how to open and read files in Java. We won't tell you how to do this, but if you search the web, look in the JDK documentation, and/or look through the Java textbooks linked from the class web page (see the resources at the bottom of the page), you can figure it out.
There are actually a few different ways to access files in Java. You just have to find one that works. Please don't ask your fellow students for help with this. Pretend that you're working at a company, you need to work with files in Java, and none of your colleagues knows how to do it. This kind of situation happens often, so now is a good time to practice finding the information on your own!
As you process the layout and moves files, you must enforce the following rules about the file. If any of the rules is violated, throw an exception (any exception will do):
#, that line is a comment and should be ignored
xn=cp, indicating that position
xnstarts out with piece
xis a column (
nis a row (
cis a color (
pis a piece kind (
#, that line is a comment and should be ignored
xn-ym, indicating that the piece at position
xnmoves to position
yare columns (
mare rows (
There are six classes representing different kinds of chess pieces:
Pawn. Each of
these classes is a subclass of
Piece, which is a class
rather than an interface because it has some code in it. You need to
add code to all seven of these classes (the six chess piece classes and their
superclass) to match the following design:
Color.WHITE. This typesafe enum is defined in
Color.java. The color is passed to the piece's constructor. You should implement the
Piece, rather than in the subclasses. To do so, you'll probably want to add a field to
toString()method should return the piece name in the form it appears in the layout file, e.g., a black king should return
bk, a white pawn should return
List<String> moves(Board b, String loc)that returns a list containing the locations the piece could legally move to starting from the position
loc, taking the positions of other pieces on the board into account. (However, there should not be any check by this method that the piece is actually at position
locis given in the same notation as the layout file, e.g.,
"a3"is a location. Each piece has a different set of moves. We will use the following movement rules only, which are slightly simplified from the rules of chess:
Aside: Notice that
Piece is an
class, with two
abstract methods. This means that
Piece is somewhere between an interface an a class: It
has some methods (and possibly fields) that are inherited by
subclasses, and it has some methods that must be implemented by
You will need to implement the factory pattern to create chess pieces. Here's how the design should work.
Piece Piece.createPiece(String name)should create an instance of the piece described by its argument in the same format as the layout file, e.g.,
Piece.createPiece("br")should return a black rook.
Piece, there is a corresponding class
CFactorythat has two methods (which we've written for you):
char symbol(), which returns the piece's one-letter symbol (e.g.,
Piece create(Color c), which returns a new instance of the corresponding piece with the given color, e.g.,
PieceFactory p = new PawnFactory(); p.create(Color.WHITE)returns a new white pawn.
Chess.java, there is a sequence of calls of the form
Piece.registerPiece(new PawnFactory()), which makes a new instance of the factory object and passes it to
Piece.registerPiece. You must implement the
registerPiecemethod to store information about the piece (probably in a map) so that the
Piece.createPiecemethod can look in that map to find out how to create such a piece.
Whew, that's pretty complicated! And probably unnecessary for chess. But, it does have the nice (?) feature that it would be easy to create new kinds of chess pieces and add them to the board without having to change too much code.
Next up, you need to write code for class
stores the locations of the pieces, among other things. To give you
practice with another pattern, we've decided that the
Board should be a singleton class. Hence you need to
implement a method
theBoard that returns the singleton
The board itself stores the piece locations in field
pieces, which is a two-dimensional array of
Piece. Notice that, very often, you will need to convert
"a3" into an access into this array. It's
up to you how you do this. You could implement a full-scale adapter
pattern. You could write a utility method or two to convert. Or you
could duplicate code all over the place. Only the last choice is not
You should implement four mutators for
Piece getPiece(String loc)returns the piece at the given location (in the usual notation, e.g.,
nullif the location is empty. It should raise an exception (any exception) if
void addPiece(Piece p, String loc)adds piece
pto the board at the given location. It should raise an exception (any exception) if the location is already occupied or is invalid.
void movePiece(String from, String to)moves the piece at location
to. This method should check that there is a piece at
from(and throw an exception if not), and it should check that the move is valid for that piece. If the move is valid, then location
frombecomes vacant and the piece is placed at position
to. It is possible there was another piece at
to, in which case it has been captured; see below. If the move is invalid or
toare invalid locations,
movePieceshould raise an exception (any exception).
void clear()should remove all pieces from the board.
Board class also supports the
observer pattern, so that listeners can be called back when key events
happen. More precisely, a
BoardListener is an observer
that implements two methods:
void onMove(String from, String to,
Piece p), which is called whenever a move is made on a board;
void onCapture(Piece attacker, Piece captured), which
is called whenever a piece is captured. If a piece is captured, there
should be a call to
onMove first and then a call to
You must implement the observer pattern by modifying
Board.java as follows:
void registerListener(BoardListener bl)should add a listener that should subsequently be called at the appropriate times. (So you will need to modify
movePiecealso.) There can be any number of listeners at any time (zero or more). We will not test the case of the same listener being registered more than once.
void removeListener(BoardListener bl)removes a listener so it will subsequently not be notified of events. Your code can behave however you like at an attempt to remove a listener that wasn't registered, or an attempt to remove a listener that was registered twice.
void removeAllListeners()removes all listeners.
main method registers a
simple observer that listens for updates to the board and prints
out what happened. This could be helpful for debugging.
But wait, there's more! (We promise this is the last part...) The
Board class also supports external iteration. The
BoardExternalIterator interface (sorry for the terribly
long name) defines a method
void visit(String loc, Piece
p). You must implement the
iterate method of
Board so that it takes a
BoardExternalIterator and, for every square on the
board, calls the external iterator's
passing that square's location and the piece at the location, or
null if the location is vacant. The iteration order is up
to you, but it must visit every square of the board. (So,
visit will be called 64 times.)
To help you test your code, we've given you a file
Test.java with another main method that, like the
previous project, runs a test case. You can invoke the tests with
java -ea Test
We've included one sample test case. (Note this test case is a little advanced; you'll have to do a fair amount of work before it passes.) As with the previous project, you must write a test case to share with the class and post it on Piazza. The deadline for posting the test case is given at the top of this web page. You may test any feature of the system that you like.
Put all your code in the code skeleton we have supplied, and upload your solution using Gradescope.