Project 1 Description
You will be building a gaming site where
computer and human players can try their skills. The general
idea is to allow a game to be chosen for play, and then the
selection of a set of opponents to participate. A game-master
(the computer) runs the game.
This could be a very complicated project. Given that you only
have 4 weeks to do it, we are making the following simplifications:
- The game site is non-networked. That is, all players are expected
to run on the same machine (or at least in same file space) as the game-master.
You won't be writing any network code.
- We will choose the game for you: GoMoku. This is a turn-based,
two-player game where each player places their stone (white or black)
on a space of
an n by n board. The first player to get 5 pieces in a row (horizontal,
vertical, or diagonal) wins.
- We will choose the architecture for you. We will use a variation on
the popular 3-tier, enterprise architecture seen in some e-commerce sites.
So what's left for you to do? Enough :) This is still a complicated project
that will require good team effort to complete. Note that we expect a team
to work alone - please do not ask another team for help or give out your
own solutions. See the information on grading and cheating off the course
page. Our assumption is that you have plenty of resources in your team and
plenty of consultation resources with the 422 staff (2 GTFs and 2 instructors).
The only reason we can foresee being tempted to cheat is if a single group
member is given too hard a task. But that goes against the XP style - programming
is not a solo activity. It is done in pairs. Use your team to solve tough
problems. Get in a mode of working as a team early on.
1. General Architecture
We have chosen to use a standard structure for this problem that is
based on a Model-View-Controller triad, or MVC for short. The model is the
piece of the system that keeps track of the game. The controller is
the piece that actually moves a game along. The view is what the
user sees as the game is being played. Keeping these three pieces
completely separate is a challenge. In particular, Java does not
separate the view and controller in a very clean fashion. Nevertheless,
we will try to keep them separate as best we can. The benefit is that
you can plug and unplug one of the three pieces without necessarily
messing up the other two.
Let's look at the model, first. You will need to write several classes
that make up the model. They are listed in the next section. Note that
some classes and interfaces extend java.io.Serializable. This is to
support the load and save game history methods in the GMI interface (discussed
below).
2. The Model
We need a representation for a rectangular board. Here is the interface you
must use:
/* Represents an n by m board of cells. The top left cell is
{0,0}. The bottom right cell is {n-1,m-1}. The board holds
objects of type PlayingPiece.
*/
interface BoardI extends java.io.Serializable {
PlayingPiece UNOCCUPIED = null; //public static final
/* A constructor that builds an n by n board that has UNOCCUPIED squares:
public xxx( int n ){...}
A constructor that initializes the board to an n by m initial confiugration:
public xxx( PlayingPiece [] [] init ){...}
*/
void setPiece( PlayingPiece piece, int row, int col )
throws SquareOutOfBoundsException;
PlayingPiece getPiece( int row, int col )
throws SquareOutOfBoundsException;
/* Returns the dimensions of the board - n by m. */
int [] getDim();
/* Returns true if the board position == UNOCCUPIED, false otherwise. */
boolean isUnoccupied( int row, int col )
throws SquareOutOfBoundsException;
/* Returns a new BoardI object that is a copy of the current board.
A copy means a non-aliased board representation. The objects on
the board should not be copied, just the representation.
*/
BoardI makeCopy();
} //BoardI
As you can see, your board class will need to implement two constructors and a small number
of methods. You can choose any internal representation for a board - that is why we made
this an interface - you have freedom to choose.
Let's look next at PlayingPiece.
final class PlayingPiece implements java.io.Serializable {
private final PlayerI owner;
private String piece_name;
public PlayingPiece( PlayerI _owner ){
owner = _owner;
}
public PlayingPiece( String name, PlayerI _owner ){
this( _owner );
piece_name = name;
}
public final PlayerI getOwner(){ return owner; };
public final String getPieceName(){ return piece_name; };
public final void setPieceName( String name ){ piece_name = name; }
} //PlayingPiece
The variable piece_name will need to encode the type of piece on the board. For
GoMoku, this will be either "white" or "black". For chess, it could be king, queen,
rook, etc.
Perhaps the most difficult class in the model portion is the one that encapsulates
the rules of the game. We have kept this a separate class to act like the "business
rules" component in popular three-tier enterprise systems. The general idea is that
you keep the rules separate so you can easily change them as your business policies
change. We won't be changing rules in the middle of the game (at least without some
nefarious activity), but it remains a useful exercise to follow the three-tier style.
Below is the abstract class that represents the rules. You will need to implement
this class for any rule set that you need.
Important note: the rules class you develop should *not* count on any
board methods being available other than those specified in the BoardI interface.
In particular, as part of the testing that the cis 422 staff will do at the end
of the project, we will attempt to use your rules class in our own model, i.e., plug
in your rules class to our system. We expect it to work without a hitch.
In general, your classes should not make any assumptions about other classes beyond
what is given in the interface. We will feel free to try out any of your classes
with ours when we evaluate your project.
abstract class RulesI implements java.io.Serializable {
public static final int OK = 0;
public static final int OUT_OF_BOUNDS = 1;
public static final int ALREADY_OCCUPIED = 2;
public static final int PIECE_NOT_ALLOWED_IN_THAT_SQUARE = 3;
public static final int MOVED_MORE_THAN_ALLOWED = 4;
public static final int MOVED_OTHER_PLAYER_PIECE_ILLEGALLY = 5;
public static final int REMOVED_OTHER_PLAYER_PIECE_ILLEGALLY = 6;
public static final int MOVED_OWN_PIECE_ILLEGALLY = 7;
public static final int REMOVED_OWN_PIECE_ILLEGALLY = 8;
public static final int OTHER_NO_GOOD_MOVE = -1;
/* Returns one of static final values. */
public static int okMove( BoardI current, PlayingPiece pp, int row, int col ){
throw new RuntimeException( "Use of dummy body." ); }
/* Assumes b1 is board before p's turn and b2 is board after. Checks
to see if the move p made in b1 (to get to b2) is legal.
*/
public static int compareBoards( BoardI b1, BoardI b2, PlayerI p ){
throw new RuntimeException( "Use of dummy body." ); }
/*
Return the maximum amount of time, in milliseconds, each player should be given
to make a single move.
*/
public static long maxTurnTime(){
throw new RuntimeException( "Use of dummy body." ); }
/*
Return the minimum size of a board dimension (n by m) for this set of Rules to be valid.
*/
public static int [] minSize (){
throw new RuntimeException( "Use of dummy body." ); }
/*
Return TRUE if game is over - win or draw.
*/
public static boolean gameOver( BoardI board ){
throw new RuntimeException( "Use of dummy body." ); }
/* Returns a game-specific representation of the winning lines for
p on board. Returns null if p has no winning lines on b.
*/
public static WinningLinesI getWinningLines(PlayerI p, BoardI board){
throw new RuntimeException( "Use of dummy body." ); }
} //RulesI
Note that all the vars and methods are static. The rules class does not encapsulate
any game state, just the process of checking for legal moves.
The next class we will think about is the "front end" to the model. It is the class
that the controller interacts with. We will give you a bit of a class we built for
testing purposes.
import java.util.*;
import java.io.*; //serialization
class GoMokuModel implements GMI, GameEventGenerator{
...
private void notify( GameEvent ge ){
for( int i = 0; i < gls.size(); i++ ){
GameListener gl = (GameListener) gls.elementAt( i );
gl.gameAction( ge );
}
} //Notify
} //GoMokuModel
There are two interfaces that need to be implemented. We will look at each in turn.
The notify method is not part of either interface, but is a useful helper method.
Feel free to use it. Of course, you will have to fill in the dot dot dot to make
it work.
First let's look at the GMI interface.
interface GMI {
/* Adds a player to game and attaches a name to the player.
Can be a color or some other distinguishing label.
*/
public void addPlayerAndName( PlayerI p, String name );
/* Gets the name of a player. Returns null if no such player. */
public String getName( PlayerI p );
/* Gets the player of a name. Returns null if no such name. */
public PlayerI getPlayer( String name );
/* Adds a set of rules to the game. */
public void setRules( RulesI rules ) throws BadRulesException;
/* Adds a board to the game. */
public void setBoard( BoardI board ) throws BadBoardException;
/* Gives p the next move.
*/
public void nextMove( PlayerI p ) throws BadPlayException;
/* Returns true if p won. */
public boolean isWinner( PlayerI p);
/* Returns true if game is over. Could be a win or a draw.*/
public boolean gameOver( );
/* The entire sequence of game boards. */
public java.util.Vector getGameHistory();
/* Saves serialized version of game history to file_name. */
public void saveGameHistory( String file_name );
/* Loads serialized version of game history from file_name. */
public void loadGameHistory( String file_name );
} //GMI
Notice that GoMokuModel does *not* keep track of who's turn it is.
It leaves that to the controller. Hence, the nextMove method must
take a player in as an argument.
The other interface sets up the model to generate and send events to anyone
who cares to listen, e.g., a viewer.
interface GameEventGenerator {
void addGameListener( GameListenerI gl );
void removeGameListener( GameListenerI gl );
When these two methods are coupled with the notify method, they
allow events to be sent to listeners.
The last set of classes that go with the model are exceptions.
3. The Controller
The controller will be used to both setup a game and move it along. It will also
be responsible for catching any problems (e.g., exceptions) and handling them
cleanly, i.e., aborting the current game and allowing a new one to start.
We can see the power of the MVC idea at this point. I can define various styles of
controllers that will all work with the model. For instance, I could write a controller
that does interactive play with a user stepping through moves. I could write another
controller that zips through as many games as possible in tournament mode. Either controller
should be able to be plugged into the same model - the model does not know who is controlling
it, other than throwing exceptions to those who call its methods.
Cool, huh.
Here is the start of a controller as an example. This controller works from the command line,
i.e., it has no GUI component. Notice that it loads players (i.e., classes that implement
PlayerI) from a url. That is part of your assignment. Your game should be able to load
player classes from any legal url on the net.
import java.net.*
public class CommandLineController implements GameController
{
...
public void playerCallback( PlayerMessage me ){ ... } //from GameController
public static void main (String [] args)
{
if (args.length != 1)
{
System.out.println ("Usage: java CommandLineController jar-directory");
return;
}
CommandLineController clc = new CommandLineController();
...
URLClassLoader ucl;
try
{
//instantiate ucl here
}
catch (MalformedURLException e)
{
System.out.println ("URL not correctly formed.");
System.exit (1);
}
clc.run(ucl); //load players, setup game, play, repeat
}
}
In our version above, the method run asks the user, through the shell, for the
class name of two players to load and then loads them from the url coming in through
the command line.
4. The View
The third piece of the MVC is the view component. The general idea is to have the view listen
for game events and then show them to the user. For example, we could hook up a
(viewing only) interface for the controller above by capturing model events and
then displaying them in a window. To do this, we need something like the following.
import javax.swing.*;
public class ReadOnlyView extends JFrame implements GameListenerI {
...
public void gameAction( GameEvent ge ){
//display stuff as events occur.
}
}
The view listens for GameEvents. Those events include GameStarted, MoveCompleted, BadPlayEvent,
GameOver, WinnerEvent, DrawEvent. You will also need GoMokuWinningLines to let your view know what the
winning lines are. You can find all these classes in the base classes that are given to you.
You must use them as is: if you do not, it will be impossible to plug different views in
to your model/controller, or your view into other model/controllers.
ReadOnlyView is a clean separation between controller and view: the controller
drives the game along and the view just shows the state. In more realistic settings, we
might have a single GUI that will combine both controller and view functions. For instance,
we might expect to have buttons that allow the user to choose what control actions to take.
We would also expect to have windows that give a view of the current state of the game. These
are often mixed together into a single class. However, the more separation you can keep
between them, the more pluggable will be your code. And that is a good thing.
5. The Players
The MVC components we have described make up the game system but do not include any players.
The goal is to allow anyone (from your group, another group, 422 staff) to write a player and
have it compete in your game system. To do this, we clearly need to follow standards - we can't
have people write arbitrary player code and expect it to work in your system. To provide standards,
we will use a player interface. The expectation is that anyone writing a player class that implements
this interface should be able to play in your game system. You can check to make sure that this is
the case when you load players in your controller code.
interface PlayerI extends java.io.Serializable {
/* Single, no-arg constructor, is used to instantiate after loaded. */
void setRules( RulesI rules );
void setGameController( GameController gc );
void setBoardDim( int r, int c );
BoardI makeMove( BoardI current_board ) throws CannotMoveException;
/* Order player's turn is, e.g., 1, 2. */
void setOrder( int i );
} //PlayerI
6. Other Classes
The full set of classes that your group should use is found in the cvs archive under
project1_base. See cvs directions off the course home page.
We have no objection to a group using code or graphics off of the web (outside of
this course). In fact, this is a critical skill - reusing other components. However,
there are two things we want to see: (1) any code or graphics used should be commented in your
code, e.g., "This code taken/modified from url ...", and (2) the code or graphics you
use should be unrestricted in terms of reuse, i.e., it should not be licensed.
Make sure you follow both these rules: we
know most of the GoMoku sites on the net and can spot reuse. On the up side, there is
no penalty for your group using what you can find (again, outside of this course).
If you are unsure about any of this, ask one of us for clarification.
7. General Development Strategy
There are four pieces to your overall project - three from the MVC and the set of players. You might
be tempted to divide them up, one each, among your group members and then all go off and
code them separately. Resist this temptation - it will almost surely fail. Instead, use the XP
style. Divide the problem up into incremental chunks. Get the base chunks working first
and then build on them. For each chunk/task, separate into coding teams and testing teams. A team
can be just one member, but for most you want two. Two member teams should use pair programming.
This means actually two people sitting at the same terminal. I know it sounds weird but it
will save you hours of time.
Below, I've given you a sample XP style development table for a
four member group. There are several things to note about this table:
- Instead of dividing up the problem four ways and all going off separately, the team has
decided to focus all early effort on getting a board class written. This is wise given that the
board is a foundation of the whole system. And with all four concentrating on the board
class, it should be completed quickly. Note that the player class needed in this task can have all
dummy bodies - it is being developed so the PlayingPiece class can be instantiated.
- It is assumed that the development and testing teams will work independently. If they
work together, it defeats the purpose. You want the testing team developing test
cases against the interfaces. This should require minimal communication between development
and testing team.
- The next critical class is rules. Again, the team has decided to put all effort into
getting this developed and debugged. If either the rules or board class is buggy, the
entire system will eventually collapse. This is a challenging task, both coding and testing.
Don't underestimate its effort because board was easy.
- Given that test cases are developed independently of coding, the testing team
can finish and move on to other tasks before coding is complete. For example, the
rules class will take some long hours to develop. The testing team does not have
to wait for this development to finish before starting a new task - it can build its
test harness and move on. The development team can use the test harness when it is
needed. Note that this is a mod to the XP notion of
test first. We
are assuming you will build test cases in parallel.
- Your group must decide how many tasks it can keep going at once. For instance, there is
nothing stopping your group from working on rules and the viewer in parallel: they share only
the need for board. But whether your group can work with parallel tasks going is a decision
for you to make. After each major task is finished, you should hold a short (30 minutes)
Iteration Planning meeting. Use this to map out the next few tasks - not the whole project,
just the next iteration of tasks. To keep this meeting short, consider the notion of
the stand up meeting.
- It will be difficult to know how much work your group can get done at your first
iteration planning meeting. So start small - take on board as the first iteration. At your
next meeting, use the XP notion of
project velocity to guide you in how much to bite off in the next iteration. If your group
is working efficiently and quickly, you may be able to try to get ahead of the curve and find
some time for optional pieces.
- When two names are listed, it is assumed that
pair programming is happening.
Pair programming increases in value during the project. For development and testing
of the board class, pair programming is a warm-up. It may not seem needed for such a
simple task, but do it anyway. It is a good start into the process. Note that you
should also move people around
so that a single group member does not become a knowledge bottleneck.
With the rules class, pair
programming should become a big win - it is non-trivial to develop the rules
methods and to think up test cases. Two heads are better than one on this task.
You will find other tasks where you need to use a reference manual. One member of
the pair can read while other writes.
We've provided the table below to get your group started. You can use some, all or none of it.
Part of your deliverable each week is growing a table with new tasks and task assignments.
When your group meets with
a GTF, he will ask to see the table you have for the upcoming tasks. Note that the GTF will
*not* expect to see the full table filled out at the first meeting. Instead, we will assume
you are using the XP notion of
Iterative Development.
Development Task Description |
Development Task Member(s) |
Testing Task Description |
Testing Task Member(s) |
Develop a board class for GoMoku. |
John, Sue |
Develop a test harness that will exercise board methods. This will include writing a simple
player so that PlayingPiece can be used. |
Mary, Chris |
Develop a rules class for GoMoku. |
Mary, Chris |
Develop a test harness that will pass a variety of boards to rules. Prereq: board class developed and tested. |
John, Sue |
Develop a viewer that simply prints game events to the shell. |
John, Chris |
Build a test harness that implements GameEventGenerator and sends events to the viewer.
| Sue, Mary |
Develop a controller method that will load players from a url. |
Sue, Mary |
Reuse simple player from board testing for loading.
| John |
Develop the GMI method nextMove. Requires a skeleton model class. |
John |
Extend simple player so that it makes a move.
| Chris, Sue |
8. The Deliverables
There are some pieces of the project that are necessary and some that are optional. Your group
needs to finish the necessary pieces to get a passing grade on the project. Our default is that
it will take some work on the optional pieces to get a grade in 85-100 range. However, we will
reserve judgement on this until we get a feel how hard the project is turning out to be across
all groups. If the necessary pieces are just barely getting done, we will shift the grading
scale. In any case, your group should not attempt optional pieces before necessities are complete.
In particular, you cannot use the optional
pieces to make up for poorly developed necessary pieces. For example, writing a really good/nasty player
(fun, but not that hard in relative terms) will not make up for a system that is buggy or does not implement full
functionality of necessary pieces. Don't let one of your group members go off by himself
or herself and hack away on players - bad use of resources.
The necessary pieces are as follows:
- Develop a model and controller that can run a series of games. Players are loaded from a url
site. If a player makes an illegal move, the controller traps it, stops the current game,
and gives the user the option of starting a new game (with new players).
All input can come from the shell. Players can be expected to try to make illegal moves. The view
uses swing classes to show the board as play progresses. Few, if any, exceptions should shut down the
system, i.e., trickle back to the command-line and hence exit the JVM.
- Develop a player that plays honestly. It does not have to be good, just honest.
- Develop a player that tries to make illegal moves. This player should be stealthy.
It should not cause an exception to be thrown. If it cannot make an illegal move without
being detected, then it makes a legal move. BTW: this player can be used as a test case
for the rules class.
- Use cvs as a version control system for your group.
- Use the makefile we provide to jar up everything for turn in.
The optional pieces are as follows. Note that these should be attempted only
after all the necessary pieces are fully tested and running. You can do none, some or all.
- Write one or more players that try to be nasty. Beyond making illegal moves, they
attempt to manipulate the game in unapproved ways. They might also attempt to act as
trojan horses to gain access to resources on the game site, e.g., read/write local files,
do network communication, steal cycles to compute primes, maliciously sink the system by
hogging JVM resources (see Denial of Service attacks).
- Use the nasty players as test cases for your game site. Devise means of stopping them.
BTW: this is much harder than writing the nasty players. Points will be awarded accordingly.
- Replace the shell-based controller with a full swing gui. In essence, meld the viewer into
a GUI that has buttons, etc.
- Write a game suspend method that uses the game history to store current state
and resume it later.
- Write a good player, one that beats at least some humans. (Which humans is the
question :)
9. Group Milestones
Your group will meet with a GTF each week in weeks 2-4. The GTF will keep a folder
for each group. At each meeting he will look for following:
- Attendance. It is expected that each member of the team will show up for a meeting.
We've asked GTFs to keep attendance. Non-attendance at meetings will be factored into
individual's grades at the end of the project.
- Collection of code and results. We have not decided on the form this will take as
of yet. In any case, a record will be placed in your group's folder.
- Evaluation of individual members knowledge of basic project facts. This is our
check that everyone in a group is keeping up. The GTFs keep notes. Non-attendance
of a meeting can be made up once by meeting with an instructor for evaluation.
The specific deliverables by week are as follows.
Week 2
- A board class that is fully tested. Includes the board class, the
testing harness, and test results. Will require a dummy player class
to instantiate PlayingPiece.
- A view class that uses swing components to show a board. A testing
harness that passes GameEvents to the view and demonstrates that the
board changes.
- Each group member demonstrates that he or she knows how to use the makefile. (Will
be on midterm.)
- Each group member demonstrates that he or she knows how to use cvs. (Will be on
midterm.)
- Each group member demonstrates that he or she knows how to use JUnit. (Will be on
midterm.)
Week 3
- A rules class that is fully tested. Includes the rules class, the
testing harness, and test results.
- An honest player that fully implements the PlayerI interface and can
play a game. Testing harness and results.
- A model that implements nextMove correctly, including checking
for illegal moves. Use the honest player as part of test.
- A controller that can get the class names from the user through the shell
and load the player classes from a url coming from the command-line. Use the
honest player as part of test.
- Each group member demonstrates that he or she knows a basic week 3 skill (TBD).
Week 4
- A fully working model - one that completely implements the two model
interfaces. Test code and results. (Note: the GMI checkPlayer method can
simply return true for now.)
- A fully working controller - one that interacts with user through shell
and drives the model. Can play a repeated set of games. Test cases and results.
(Note: the playerCallback method can simply print the message using SOP.)
- Each group member demonstrates that he or she knows a basic week 4 skill (TBD).
Week 5
You will not meet with a GTF week 5 (it is midterm week). But by the end
of week 5, your group must turn in the following:
- Email us your jar file. Between weeks 4 and 5 you need to have integrated the
three pieces of the MVC that you have been developing. Include all files necessary
for us to run your system on our machines. We will try your players and some of
our own. We will also plug in our own classes and run.
- Group member evaluation. You will individually fill out and
turn in a form rating the work of your fellow group members,
including yourself. This form will be provided by us. This is
done in private and will be kept private by the 422 staff.
- Some midterm questions will come from project 1.
As you can see, the above schedule does *not* include any optional pieces - it is for
the bare bones system that will get your group a passing grade. It is up to your group
to decide which, if any, optional pieces to try and how to fit them into the schedule.
In essence, you will need to get ahead of the schedule above, completing some week k
items in week k-1.
The procedure for turning in Project 1 has changed.
See the announcements page for details.
10. XP Caveats
The rules of XP are based
on the idea that you start a project from ground zero. To make this happen in 422, we
would give you nothing other than a statement of the problem - build a game site - through
a set of user stories. It would be up to you to develop the architecture, interfaces and
classes that we are handing you. Much of XP is focused on helping you carry out this task.
But the reality is that we have a 10 week quarter to cram (too) many ideas into your noggin.
It is sad that we must do so much in one course - teach you SE concepts, give you group
programming experience, take on a largish project. But until 423 is taught regularly,
we only have 422. Hence, we decided
to do the architectural and infastructure design for you. We know this is a very cool part of
any project, but it is the most time-intensive and easiest to screw up. Sorry :( You will have
to pick up early design skills some place else.
On the positive side, much of the XP doctrine still applies to your starting point. You still
have to do iterative planning, do pair programming, focus on testing. By the end of the course,
we believe you will have a solid feel for much of XP.