Source Code‎ > ‎

Connect Four

My game framework design is an implementation of the model-view-controller pattern. It was designed to be flexible for several reasons. First of all, different types of games need different internal logic to run. Secondly, it promotes code reuse and makes future two player games easier and faster to develop.

I used a model, view, and controller at two levels. The top level includes the FrameworkModel, FrameworkView, and FrameworkController. The lower level is implemented by the particular game that wants to run (C4 or Sticks). The low-level game controller has already been implemented in the game framework: it is Referee. Referee will work for any two-player game that implements the IGame interfaces correctly.

In Figure 1, I have given a top-level picture of the classes I have used. Everything begins with Gui. This is the class that is called when the framework is to be run either as an applet or as an application. If the applet is run as an application, then it takes advantage of the various XML capabilities: saving/restoring games and getting the games from a "config.xml" file. Gui is a specialization of java.applet.Applet, so it is kicked off in either case from its init() method.

One interesting feature of my design in this diagram is my use of the ModelListener & ModelEvent classes. I implemented an event handling system similar to the Java event system. I set up the FrameworkView to implement the ModelListener interface. Then, the model must be setup in such a way that ModelListeners can be added & removed from a list kept by the model. When the model is changed (in this case, when a new game has been created and the new view is ready to be displayed, then the FrameworkModel calls each listener's modelChanged() method. As an added bit of functionality, any object can be passed via the ModelListener system by wrapping the object in a ModelChangedEvent and sending it out to the listener. Then, the listener (presumably knowing what kind of Object it is supposed to receive) can then unwrap the object and cast it to its true form.



Figure 1


Another feature of the design that is very flexible and highly reusable is the GameSettings object. GameSettings is a specialization of java.util.Hashtable, so it can use any objects as keys & data. In order make XMLizing my framework a bit easier, only two objects are XMLized; the GameSettings object and a list of moves. Effectively, GameSettings is an XMLizable Hashtable.

Figure 2


Here we are given a overview of the FrameworkController and the many interfaces that are used in implementing a game. The FrameworkController receives messages from the FrameworkView about user events. Then, serving the responsibility of a controller, it responds to those messages in the appropriate way. Most events lead to making changes in the game's model (the game Layout, which must implement IgameLayout). In the case of XMLization, the message must be relayed back to the top-level object (Gui) in order to save the correct objects. Also, the initFromXML() in FrameworkController is just a stub, since the FrameworkController will be created from a XMLized GameSettings object (details to follow). But, the toXML() method is still used in order to XMLize the history of moves found from the layout.


Figure 3


In figure 3, I have displayed 3 separate sets of objects. The first, in the upper-left, an example of what objects implement the IGame interface. This implementation serves as a factory that produces the necessary IGame objects that are needed by the Referee in order to play a game.

The second is the GameView set of objects. GameView is an abstract class that extends java.awt.Panel. Originally, the intention of having an abstract class here instead of an IgameView interfaces was to allow the Swing functionality a bit later in the development cycle. Even though the Swing functionality was never fully implemented, the object still serves the purpose of displaying a game-independent WinnerBox. Now, each game needs not worry about the panels necessary to display the winning player. I also used the Null Object pattern by designing a NullGameView object. This NullGameView would only be displayed when 1) an error has occurred, and then the NullGameView will display the exception error , or 2) the application is started up, which gives the user time to decided which game he/she loads.

The third set are the Player objects. I have one abstract class Player that takes care of the basic behavior of assigning names and type of piece. Every type of player than subclasses the Player class to write their own player. Computer players implement an additional IComputerPlayer interface, so that the minimax algorithm can be used to make its moves. One unique design decision I made here was to have the Player class implement ActionListener and FocusListener. Human players take advantage of these interfaces. When it becomes a player's turn, that player is added as an Action/Focus listner to all buttons/widgets that inform the framework that a move is going to be made. This makes intuitive sense because in real life, when it becomes a new player's turn, that player than starts paying attention; but when it is not that player's turn, he/she doesn't care what moves are being made. The FocusListener interfaces is used specifically in sticks, when a hand-crafted SticksButton is used. Since Button contains code that depresses the button and such, I wanted to make sure that the button's surface gets repainted when the focus is changed.



Figure 4


In figure 4, I tried to tie up all the lose ends. One things to note here include that Referee implements Runnable. My reasoning for this will be seen near the end of this report. The strategies implement IGameStrategy, not much else to say about that. I have included a NullGameMove as an implementation of IGameMove. This allows the referee to be able to "skip" a player; if the Referee gets a NullMove, than it just switches players and moves on. This handy feature is utilized by my UndoMove method in FrameworkController. The layouts for each game C4Layout & SticksLayout each implement IGameLayout. The Layout classes are the models for the game; they provide the data & logic of how each game works, and know nothing about the view. For each game I implemented, it became helpful to use classes like Cell & Pile to keep things tidy.



Figure 5

I have included figure 5 in order to describe the initialization sequence. The top-level object Gui first creates a FrameworkController object, and then passes that along to the constructor for FrameworkView. Intuitively it seems that we would need to have created the FrameworkModel before the View & Controller, but not in this case. Here I use a static FrameworkModel that keeps a static list of ModelListeners and a static GameView attribute. The model keeps track of the current GameView, and when we want to change that view, all we need to do is call the set() method on FrameworkModel, and the model takes care of the rest.



Figures 6a & 6b

Figure 7


Figures 6 & 7 both describe the same phenomena, the submission of a move and the response of the Referee. Figure 6a is a sequence diagram that represents the submission of a move by a user. As seen from that diagram, the move that is calculated from the HumanPlayer's actionPerformed() method is then simply placed in a Hashtable.

The referee implements Runnable, so it can spin off a new thread. This thread just checks to see if a move has been placed in the received Hashtable, and if there is no move, the thread goes to sleep for 100 ms. The reason for having submitMove() work in this unusual manner allows the GameView time to repaint itself. The GameView panel will not repaint() until the thread that called repaint is no longer active. So, by going to deactivating the thread after submitting a move; I am allowing the AWT paint() methods to occur promptly (and not just be scheduled for a later time).

The process of creating the new thread can be seen easily in the Figure 7 state diagram. The upper half of the diagram shows the initialization, and then the lower half runs in a continuous loop that repeats the same logic over & over again (including going to sleep now & then).

Figure 8


Finally, the last UML model is an object diagram. I used an example game of sticks to fill out the data for each object at a snapshot in time. From this figure, it is easy to see that very little data is actually being kept in each object; but it is also easy to see how the behavior is encapsulated. Another things to notice here is the high-coupling in places. It appears that FrameworkController must know about several objects, but in reality, these objects are just interfaces so it is not such a major factor. It does, however, effect the code's level of reusability.

All in all, I am satisfied with my design. I feel that I generalized the framework to a maximum degree, at the expense of not having enough time to create an awesome View for each game. I implemented all the required features, plus the following 3 bonuses: XML-configurable framework (in application mode).  Runs as an Applet & as an Application.  Uses an intuitive point & click interfaces with no typing.


Please Note: Save/Restore buttons are inactive when this application is

running as an applet, due to security restrictions on Java Applets.

<APPLET CODE="cs4448.gameFramework.Gui.class" CODEBASE="./" ARCHIVE="hw6.jar,xerces.jar,jdom.jar,collections.jar" WIDTH="600" HEIGHT="400"></APPLET>


SelectionFile type iconFile nameDescriptionSizeRevisionTimeUser
ċ

Download
  253k v. 1 Jan 9, 2011, 5:05 PM Darin Gillis
ċ

Download
  54k v. 1 Jan 9, 2011, 5:06 PM Darin Gillis
ċ

Download
  104k v. 1 Jan 9, 2011, 5:06 PM Darin Gillis
ċ

Download
  984k v. 1 Jan 9, 2011, 5:07 PM Darin Gillis
Comments