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:

  1. 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.

  2. 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.

  3. 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:

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:

  1. 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.

  2. Develop a player that plays honestly. It does not have to be good, just honest.

  3. 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.

  4. Use cvs as a version control system for your group.

  5. 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.

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:

  1. 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.

  2. 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.

  3. 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

  1. 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.

  2. 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.

  3. Each group member demonstrates that he or she knows how to use the makefile. (Will be on midterm.)

  4. Each group member demonstrates that he or she knows how to use cvs. (Will be on midterm.)

  5. Each group member demonstrates that he or she knows how to use JUnit. (Will be on midterm.)

Week 3

  1. A rules class that is fully tested. Includes the rules class, the testing harness, and test results.

  2. An honest player that fully implements the PlayerI interface and can play a game. Testing harness and results.

  3. A model that implements nextMove correctly, including checking for illegal moves. Use the honest player as part of test.

  4. 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.

  5. Each group member demonstrates that he or she knows a basic week 3 skill (TBD).

Week 4

  1. 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.)

  2. 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.)

  3. 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:

  1. 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.

  2. 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.

  3. 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.