Citation
BGF

Material Information

Title:
BGF a framework for board game applets
Creator:
Wood, David R
Place of Publication:
Denver, CO
Publisher:
University of Colorado Denver
Publication Date:
Language:
English
Physical Description:
v, 120 leaves : illustrations ; 29 cm

Subjects

Subjects / Keywords:
Computer software -- Development ( lcsh )
Object-oriented programming (Computer science) ( lcsh )
Java (Computer program language) ( lcsh )
Computer software -- Development ( fast )
Java (Computer program language) ( fast )
Object-oriented programming (Computer science) ( fast )
Genre:
bibliography ( marcgt )
theses ( marcgt )
non-fiction ( marcgt )

Notes

Bibliography:
Includes bibliographical references (leaves 119-120).
General Note:
Submitted in partial fulfillment of the requirements for the degree, Master of Science, Computer Science
General Note:
Department of Computer Science and Engineering
Statement of Responsibility:
by David R. Wood.

Record Information

Source Institution:
|University of Colorado Denver
Holding Location:
|Auraria Library
Rights Management:
All applicable rights reserved by the source institution and holding location.
Resource Identifier:
37364277 ( OCLC )
ocm37364277
Classification:
LD1190.E52 1996m .W66 ( lcc )

Downloads

This item has the following downloads:


Full Text
BGF: A FRAMEWORK FOR BOARD GAME APPLETS
by
David R. Wood
B.S., University of Colorado at Boulder, 1993
A thesis submitted to the
University of Colorado at Denver
in partial fulfillment
of the requirements for the degree of
Master of Science
Computer Science
1996


This thesis for the Master of Science
degree by
David R. Wood
has been approved
by
Tom Altman
Miloje Radenkovic


Wood, David R. (M.S., Computer Science)
BGF: A Framework for Board Game Applets
Thesis directed by Professor Boris Stilman
ABSTRACT
An object-oriented framework is a reusable design consisting of a set of abstract classes and
reusable concrete components which simplifies the creation of applications sharing common
characteristics. The Board Game Framework (BGF) is an object-oriented framework for the
development of strategic board games using the Java programming language. The
framework provides abstractions for common concepts such as board, space, piece, player,
strategy, and move. In addition to providing these basic abstractions, the framework encodes
knowledge about how the objects in the system interact, establishing the overall flow of any
application built with the framework. This thesis describes the BGF in detail, beginning with
a brief overview of each class in the framework. Next, a detailed design pattern-based
analysis of the interactions between the classes is given, including discussion of how the Java
programming language affects the use of certain patterns. Within this section, a new
Java-specific design pattern (Abstract Singleton) is presented. Finally, a cookbook for creating
applications using the framework is presented. This section gives detailed instructions for the
development of BGF applications, drawing extensively from two complete sample
applications built using the framework. The framework is shown diagramatically using the
Unified Modeling Language (UML).
This abstract accurately represents the content of the candidates thesis. I recommend its
publication.
Signed
111
Boris Stilman


CONTENTS
Chapter
1. Introduction .................................................... 1
1.1 Conventions ................................................... 2
2. Framework Overview............................................... 3
2.1 Class BGFApplet ............................................... 3
2.2 Class BGFBoard ................................................ 3
2.3 Class BGFBoardEnumeration ..................................... 3
2.4 Class BGFBoardView............................................. 3
2.5 Class BGFSpace ................................................ 4
2.6 Class BGFSpaceView ............................................ 4
2.7 Class BGFPiece ................................................ 4
2.8 Class BGFPieceView ............................................ 4
2.9 Class BGFPlayer ............................................... 4
2.10 Class BGFOnePiecePlayer ....................................... 4
2.11 Class BGFStrategy ............................................. 4
2.12 Class BGFGUIStrategy .......................................... 5
2.13 Class BGFOneSpaceGUIStrategy .................................. 5
2.14 Class BGFTwoSpaceGUIStrategy .................................. 5
2.15 Class BGFMove.........
2.16 Class BGFNewPieceMove
2.17 Class BGFMovePieceMove ........................................ 5
2.18 Class BGFMoveProcessor ........................................ 5
2.19 Interface BGFMoveController ................................... 5
2.20 Class BGFGameMaster ........................................... 6
2.21 Class BGFCommand .............................................. 6
2.22 Class BGFNewGameCommand ....................................... 6
2.23 Class BGFSpaceSelectedCommand ................................. 6
2.24 Class BGFTakeBackCommand ...................................... 6
2.25 Class BGFWhoPlaysCommand ...................................... 6
2.26 Class BGFCommandProcessor ..................................... 6
2.27 Class BGFFactory .............................................. 6
2.28 Class BGFGameOverStatus ....................................... 7
2.29 Class BGFYVinningSpacesGameOverStatus ......................... 7
2.30 Class BGFWhoPlaysDialog........................................ 7
2.31 Class BGFInvalidSingletonlnstantiationException ............... 7
3. Design Patterns ................................................. 8
3.1 Model-View-Controller ......................................... 9
3.2 Observer ..................................................... 10
3.3 Singleton .................................................... 11
IV
m m


3.3.1 Abstract Singleton ............................................... 12
3.4 Template Method ...................................................... 16
3.4.1 Prees Metapatterns ............................................... 18
3.5 Abstract Factory ..................................................... 18
3.6 Factory Method ....................................................... 20
3.7 Strategy.............................................................. 20
3.8 Command .............................................................. 22
3.9 Iterator ............................................................. 25
3.10 Prototype ............................................................ 26
3.11 Chain of Responsibility............................................... 27
4. Developers Guide ...................................................... 29
4.1 The Example Games .................................................... 29
4.2 First Steps .......................................................... 30
4.3 Seeing the Game ...................................................... 34
4.4 Additional Required Classes .......................................... 39
4.5 Optional Classes ..................................................... 43
4.5.1 Extending BGFCommand .............................................. 43
4.5.2 Extending BGFStrategy ............................................. 44
4.5.3 Extending BGFPlayer ............................................... 46
4.5.4 Extending BGFMove ................................................. 46
4.6 Developers Guide Summary ............................................ 48
5. Conclusion ............................................................. 49
Appendix
A. Notation ............................................................... 50
B. BGF Source Code ........................................................ 54
References..................................................................119
v


1. Introduction
Joshua: Shall we play a game?
David: Love to. How about Global Thermonuclear War?
Joshua: Wouldnt you prefer a good game of chess?
WarGames, MGM/UA Entertainment Co., 1983.
An object-oriented framework is a reusable design consisting of a set of abstract classes and
reusable concrete components which simplifies the creation of applications sharing common
characteristics. This thesis discusses an object-oriented framework called the Board Game
Framework (BGFj. The purpose of the framework is to simplify the process of writing strategic
board game programs using the Java programming language. While the framework focuses
on the toy domain of strategic board game applet development, the design principles and
patterns discussed here are applicable to a very wide range of software engineering domains,
so the thesis should be of interest to anyone involved in object-oriented software engineering.
The strategic board game domain was chosen because it contains generally familiar
abstractions (namely board, space, piece, player, strategy, and move) which people can easily
understand, allowing the reader to focus on the framework design rather than struggling with
confusing domain-specific jargon.
The basic abstractions listed in the previous paragraph form the basis of any game
implemented using the BGF. Such games must be played on a board with a two-dimensional
grid of spaces (games with non-rectangular boards such as Abalone could also be
accommodated by creating additional, unused spaces) upon which pieces of some type are
placed or moved. The pieces belong to particular players (games may have as few or as many
players as necessary) who employ various strategies to determine which moves should be made.
The following is a limited sampling of games which could be created with the BGF:
Tic-Tac-Toe, Connect-4, Checkers, Chess, Go, Quixo, Quarto, Terrace, Abalone, Pente,
Life, Stratego, Chinese-Checkers.
In the future, the strategy abstraction could be used to demonstrate Linguistic Geometry
[Stil96] techniques (used to reduce many complex problems to board game problems) in a
web-based environment.
The remainder of this section provides an overview of the rest of the thesis.
Section 2 gives a brief overview of the classes found in the framework. These include both
abstract framework classes and reusable, concrete components. The purpose of this section is
not to fully define each class, but rather to simply introduce the classes so they will be familiar
in later sections.
1


Section 3 discusses the use of design patterns in the BGF. Each pattern used in the BGF is
explained using text as well as class diagrams and sequence diagrams drawn using the
emerging standard for design modeling, the Unified Modeling Language. The section explains
how the different parts of the system work together in experience-proven ways to create a
framework that is both easy to extend and easy to understand.
Section 4 provides detailed instructions for the creation of complete applications using the
BGF. Existing sample applications (Tic-Tac-Toe and Quixo) are used to show exactly which
classes need to be extended, which methods must be implemented, which methods may
optionally be overridden, and what types of additional subclasses may optionally be added to
enhance the application.
The appendices include an overview of the modeling techniques used and the complete code
listing for the framework classes.
1.1 Conventions
The following conventions are used throughout the thesis:
> fixed-width font like this indicates program code
^ italics followed by a parenthetical number (e.g. Command (233)) reference a design pattern
(and page number) from the book Design Patterns: Elements of Reusable Object-Oriented Software
[GHJV95]
^ the following coding conventions are used:
class (and interface) names in the BGF begin with the letters BGF
method names begin with capital letters (to clearly distinguish from Java-provided
methods which always start with lower-case letters)
field names begin with an underscore (_rows)
method parameters begin with a lower-case p (pGraphics)
constants (static final fields) start with a lower-case k (kWidth)
2


2. Framework Overview
abstraction n. 1. (a) any model that includes the most
important, essential, or distinguishing aspects of something
while suppressing or ignoring less important, immaterial, or
diversionary details, (b) the result of removing distinctions so
as to emphasize commonalties.
Booch, Firesmith, Henderson-Sellers, Martin, Odell,
Dictionary of Object Technology
The BGF is best understood by looking at the various design patterns used in its construction.
This will be done in detail in the next section. The purpose of the present section is to
provide a brief overview of the classes which make up the framework in order to give the
reader sufficient background for the section on patterns.
2.1 Class BGFApplet
The BGFApplet abstract class is a subclass of j ava applet. Applet which provides
basic setup functionality for BGF applications running as applets. It also provides a main ()
function, allowing the applet to be run as an application (without a web browser).
2.2 Class BGFBoard
The BGFBoard abstract class represents the concept of a game board. It is made up of
some number of spaces (BGFSpace) arranged in a two-dimensional array. BGFBoard
subclasses are responsible for the detection of the end of a game (they must know, for
example, how to recognize checkmate in chess).
2.3 Class BGFBoardEnumeration
The BGFBoardEnumeration class implements the java .util. Enumeration
interface, providing sequential access to the spaces on the board.
2.4 Class BGFBoardView
The BGFBoardView class is a subclass of j ava. awt. Canvas which represents the GUI
view of the BGFBoard. It handles the drawing of the board as well as input from the GUI
such as mouse-clicks on the board. This class also implements a technique called
double-buffering which allows board updates to be displayed without visible flicker.
3


2.5 Class BGFSpace
The BGFSpace class represents a single space on a game board. A BGFSpace may have a
relation to a BGFPiece located on the space.
2.6 Class BGFSpaceView
The BGFSpaceView class provides a graphical representation of a BGFSpace on the
display.
2.7 Class BGFPiece
The BGFPiece class represents any piece belonging to a particular player in a game.
2.8 Class BGFPieceView
The BGFPieceView abstract class provides the GUI representation of a BGFPiece.
Subclasses of BGFPieceView must know how to draw the specific piece onto a specified
board location.
2.9 Class BGFPlayer
The BGFPlayer class represents the most basic concept of a player in any game. The
BGFStrategy class (see section 2.11) is actually responsible for determining how to make a
move. This class simply represents the participants in the game, such as Black and White in
chess or X and 0 in Ttc-Tac-Toe.
2.10 Class BGFOnePiecePlayer
The BGFOnePiecePlayer is a subclass of BGFPlayer used with players for which a
move involves the placement of a single type of piece (unique to the player) on a given space
on the board. This class is responsible for the creation of new pieces when requested by the
BGFOneSpaceGUIStrategy class.
2.11 Class BGFStrategy
The BGFStrategy abstract class provides an overall flow of control for the process of
generating a new move. Strategies for move generation might include accepting GUI input,
generating a move based on a search algorithm, retrieving a move from a network
connection, etc. Regardless of the details, BGFStrategy provides the overall flow.
4


2.12 Class BGFGUIStrategy
The BGFGUIStrategy abstract class is a subclass of BGFStrategy which provides much
of the functionality for allowing human players to generate moves.
2.13 Class BGFOneSpaceGUIStrategy
The BGFOneSpaceGUIStrategy class is a subclass of BGFGUIStrategy which can be
used for games in which a move is made by selecting a single space onto which a new piece is
to be placed.
2.14 Class BGFTwoSpaceGUIStrategy
The BGFTwoSpaceGUIStrategy class is a subclass of BGFGUIStrategy which can be
used by games in which a move is made by selecting a space containing a piece, then
selecting a second space to which the piece on the first space is to be moved.
2.15 Class BGFMove
The BGFMove abstract class represents any single move in a game. Moves are instantiated
as objects, allowing them to be stored (and later undone) and executed.
2.16 Class BGFNewPieceMove
The BGFNewPieceMove class is a subclass of BGFMove representing simple moves
involving the creation of a new piece (BGFPiece) to be placed on a single space
(BGFSpace). Games such as Tic-Tac-Toe, Connect-4, and Othello can use this class directly.
2.17 Class BGFMovePieceMove
The BGFMovePieceMove class is a subclass of BGFMove representing moves involving the
movement of a single piece from one space on the board to another.
2.18 Class BGFMoveProcessor
The BGFMoveProcessor class provides a mechanism for the submission of moves
throughout the course of a game. It also provides interfaces for taking back (undoing) moves
and for clearing out all previous moves (new game).
2.19 Interface BGFMoveController
The BGFMoveController interface specifies methods for handling notification of illegal
moves and illegal take-backs.
5


2.20 Class BGFGameMaster
The BGFGameMaster class handles the basic flow of the game. It is responsible for
requesting moves from each player in the game in sequence, alerting players that it is no
longer their move (perhaps because the previous move has been taken back), resetting the
model when a new game is requested, etc. Application builders using the BGF need not
worry about any of these issues as everything is handled by this concrete class.
2.21 Class BGFCommand
The BGFCommand abstract class represents any basic command entered from the GUI to be
implemented by the application.
2.22 Class BGFNewGameCommaxid
The BGFNewGameCommand class is a subclass of BGFCommand which simply notifies the
BGFGameMaster that a new game has been requested.
2.23 Class BGFSpaceSelectedCommand
The BGFSpaceSelectedCommand class is a subclass of BGFCommand which notifies the
BGFGameMaster that a space on the board has been selected.
2.24 Class BGFTakeBackCommand
The BGFTakeBackCommand class is a subclass of BGFCommand representing a request
from the GUI to take back the previous move or moves.
2.25 Class BGFWhoPlaysCommand
The BGFWhoPlaysCommand class is a subclass of BGFCommand which brings up the
BGFWhoPlaysDialog window (described in section 2.30).
2.26 Class BGFCommandProcessor
The BGFCommandProcessor class accepts BGFCommand objects and executes the
commands.
2.27 Class BGFFactory
The BGFFactory abstract class provides an interface for the creation of application-specific
objects (pieces, player strategies, etc.) without requiring the creator (usually an object within
the BGF) to know the actual concrete type of the object being created.
6


2.28 Class BGFGameOverStatus
The BGFGameOverStatus class is basically just a grouping of two attributes: a boolean
value indicating whether of not the game is over, and a reference to a BGFPlayer
representing the player (if any) who has won the game.
2.29 Class BGFWinningSpacesGameOverStatus
The BGFWinningSpacesGameOverStatus class is a subclass of
BGFGameOverStatus which adds the ability to store the spaces on the board involved in
the final, winning position. This simplifies the process of visually showing the pieces making
up the winning position.
2.30 Class BGFWhoPlaysDialog
The BGFWhoPlaysDialog class is a subclass of java awt .Dialog which allows the
user to select a strategy for each player in the game before starting a new game.
2.31 Class BGFInvalidSingletonlnstantiationException
The BGFInvalidSingletonlnstantiationException class is a subclass of
java lang. Exception which is used to indicate an attempt to create an instance of a
singleton class via means other than the static Instance () method.
7


3. Design Patterns
Certain rare people seem to be able to tap into some magic vein
in which flow incredibly catchy patterns, deeply intoxicating to
the human spirit.
Douglas R. Hofstadter, Metamagical Themas: Questing
for the Essence of Mind and Pattern
The use of design patterns is critical to the development of a comprehensible, reusable
software framework. A design pattern is an element of reusable architecture that has been
shown to solve a common problem. The use of patterns in software design is commonly
linked back to the work of architect Christopher Alexander and his book A Pattern Language
[AIS77], Perhaps more than anything, Alexanders work suggested that fundamental ideas
which had been used by experts and shown to work could be documented in a clear,
consistent format to be reused by others. In software engineering, this format typically
consists a pattern name, a problem, a solution, and consequences of applying the pattern. In
Design Patterns: Elements of Reusable Object-Oriented Software [GHJV95], Gamma et. al. provide a
catalog of 23 such patterns, ten of which are discussed in this section. Since the publishing of
Design Patterns, several other works have been published on the subject of design patterns.
The works of Pree [Pree95], Coad [CNM96], Vlissides et. al. [PLoP95], and Buschmann et.
al. [BMRSS96] are also discussed in this section.
What follows is a description of the patterns which appear in the BGF. It is this section
which should most help the reader to understand the relationships between the classes
(described in the previous section) which make up the framework. Most of the patterns
discussed in this section are from the Design Patterns book, though ideas are also incorporated
from the other works mentioned above. Additionally, a new Abstract Singleton design pattern is
presented using the standard pattern format.
The patterns described in this section are shown diagrammatically using the Unified Modeling
Language (UML). An overview of the subset of the UML pertinent to the diagrams in this
section is presented in Appendix A.
In effect, as you build each pattern into the design, you will
experience a single gestalt that is gradually becoming more and
more coherent.
Christopher Alexander, A Pattern Language
8


3.1 Model-View-Controller
The Model-View-Controller architectural pattern (MVC) divides an interactive
application into three components. The model contains the core functionality and
data. Views display information to the user. Controllers handle input. Views and
controllers together comprise the user interface. A change-propagation mechanism
ensures consistency between the user interface and the model. [BMRSS96]
The BGF makes use of MVC to separate the display aspects of the game from the details of
the underlying model, allowing displays (views) to be modified or replaced without any threat
of affecting, for example, the rules of the game. To support the mew aspect of MVC, the BGF
provides the abstract classes BGFBoardView, BGFSpaceView, and BGFPieceView.
Each of these has an underlying model abstraction: BGFBoard, BGFSpace, and
BGFPiece, respectively. The controller distinction is less clear, but the key controller
responsibilities lie primarily in the BGFBoardView and BGFApplet classes. The class
diagram in Figure 3.1 shows the relationships between these classes (relations between the
model classes are left out here to simplify the diagram).
Observer
Figure 3.1
The key aspect of this diagram is the navigability direction from the view classes to the model
classes. Note that BGFBoard, BGFSpace, and BGFPiece are unaware of the existence of
the view objects.
When the BGFBoardView class is instantiated, it creates a two-dimensional array of
BGFSpaceView objects. The bounds of this array are specified by the BGFBoard class
(which knows how many rows and columns the board has). Each BGFSpaceView contains
a Rectangle object which specifies the location and size of the space on the display. When
a piece is placed on a space, the BGFSpaceView object creates a new BGFPieceView
object and tells it to draw itself within the Rectangle specified by the BGFSpaceView. It
maintains a link to the BGFPieceView object so that it can tell it to draw itself at any time
in the future. If the piece is later removed from the space, the BGFSpaceView object will
9


update its BGFPieceView reference to null and draw a blank space any time it is told to
draw itself.
Notice that the discussion of the view classes to this point has barely mentioned application
specific extensions of these classes. This is because much of the work of creating the display is
done directly within the BGF classes. In fact, BGFPieceView is the only abstract view class.
In the BGFBoardView class, the only method which may need to be overridden is the
Draw () method, responsible for rendering the specific game board on a given Graphics
object. All the other interaction between the BGFBoardView and its BGFSpaceView
objects is handled directly by BGFBoardView. This includes creating the spaces, handling
mouse clicks (here, BGFBoardView takes on the controller role in MVC), repainting the
screen, etc. Similarly, subclasses of BGFSpaceView need only (optionally) override the
Draw (), DrawEmpty (), and ShowGameOver () methods to supply any application
specific display. Finally, the BGFPieceView class contains just two methods which may
need to be overridden: Draw () and ShowGameOver ().
The interaction between the model classes and the view classes is handled using the Observer
pattern, discussed next.
3.2 Observer
The Observer (293) (or Publisher-Subscriber [CNM95]) pattern defines a one-to-many
dependency between objects so that when one object changes state, all its dependents are
notified and updated automatically. [GHJV95] The most common use of this pattern is as
a way to decouple the user interface from the underlying model. As was briefly described in
the section on MVC, the BGF uses this pattern for this very purpose. In fact, the Java utility
package provides everything needed to implement the basic Observer pattern. The class
j ava util. Observable provides the necessary interface methods to act as the subject
in the pattern. These methods provide the ability to add observers and to notify these
observers when something in the model has changed. In the BGF, the BGFBoard and
BGFSpace classes are defined as subclasses of Observable. This is the extent to which
the model classes know about the view classes in the BGF. Any time a change is made to the
state of the game, the observables simply call setChanged () and
notifyObservers (), methods completely defined in the Observable class. It is then
up to Observable to notify any view objects registered with the modified object that the
state of the model has changed.
The BGFBoard class notifies observers when the game is over (some special information
might be displayed to the screen) and when a game which was over becomes not-over as a
result of the last move (or moves) being taken back. The BGFSpace class notifies its
observers any time a piece is placed on it or removed.
The other key participant in the Observer pattern is the Observer interface. Again, Java
assists by providing an interface containing a single update () method. This is the method
10


\
called by instances of the Observable class any time the notifyObservers () method
is called. In the BGF, the BGFBoardView and BGFSpaceView classes implement this
interface, accepting update () calls and updating the display accordingly. Figure 3.2 shows
a simple notification occurring as a result of a piece being placed on a particular space. Note
that the first two vertical lines represent the same instance (sp 1) of BGFSpace. The time
lines are broken to show that the subscription request made by the BGFSpaceView occurs
at some time earlier (during setup) in the program.
Figure 3.2
3.3 Singleton
The Singleton (127) pattern provides a mechanism for restricting the number of instances of a
given class, and for providing global access to the singleton instance [GHJV95]. This pattern
is used throughout the BGF for classes which will only have a single instance throughout the
life of the applet. These classes include BGFGameMaster, BGFMoveProcessor, and
BGFCommandProcessor which employ the simplest possible Singleton implementation, as
well as BGFFactory and BGFBoard which use an extension of the Singleton pattern which
allows the singleton object to be an instance of some unknown subclass. This extension to the
Singleton pattern is described by a new pattern (or idiom in [BMRSS96]) presented at the end
of this section.
The following code segment shows the implementation of the Singleton pattern for the
BGFGameMaster class.
public final class BGFGameMaster
{
private BGFGameMaster() {}
static public synchronized BGFGameMaster Instance!)
{
11


if (_instance == null)
_instance = new BGFGameMaster();
return _instance;
}
private static BGFGameMaster _instance;
}
The non-public constructor, static Instance () method and single instance variable shown
here are the fundamental elements involved in the Singleton pattern. Note that in Java, the
Instance () method should be declared with the synchronized modifier to ensure that
only one a single instance can possibly be created. This is discussed further in the next
section.
3.3.1 Abstract Singleton
The Singleton pattern described in Design Patterns devotes about a page and a half to a section
on subclassing singleton classes. Unfortunately, none of the solutions suggested is wholly
satisfactory. The primary difficulty' discussed in this section is that the base class must be able
to create the proper instance of a particular subclass (without, of course, being hard-coded to
know which subclasses exist). Some configuration mechanism must exist to inform the base
class about the various subclasses which might be used in such a way that a particular
subclass instance can be returned. In C++, this is quite difficult, requiring an instance of
each subclass to be created statically and passed into a static Configure () method on the
base class along with an identifying string (or other identifier). Then, an environment
variable (or, perhaps a separate configuration method) specifies which of these instances
should be returned by the Instance () method. Using this technique may by very
impractical for singleton hierarchies which cannot reasonably allow the instantiation of each
concrete subclass.
The difficulties discussed above can be eliminated by using several important Java language
features. What follows is a new design pattern called Abstract Singleton which provides a clean
solution to the problem of subclassing a singleton. The pattern description below follows the
basic format used in the Design Patterns book.
3.3.1.1 Name
Abstract Singleton
3.3.1.2 Intent
From a collection of subclasses of a common abstract base class, ensure that only a single
instance of a single subclass is created, and provide global access to this instance.
12


3.3.1.3 Motivation
As described in the Singleton pattern, it is important for some classes to have exactly one
instance. The Singleton pattern also points out that the Singleton class may be abstract,
implying that what is really desired is a single instance of some arbitrary subclass, not simply
a single instance of a known, concrete class. Such situations are common in framework
design in which the framework defines the abstract base class, but leaves the implementation
of concrete subclasses to the application developer.
3.3.1.4 Applicability
Use the Abstract Singleton pattern when
there must be exactly one instance taken from a collection of classes which extend a
common base class, and this instance must be accessible to clients from a well-known
access point.
all possible concrete subclasses cannot be enumerated a priori
3.3.1.5 Structure
AbstractSingleton
static _uniguelnstance singletonData static Class _singleClass
static lnstance() singleClass = inputClass1^
OperationQ

A
ConcreteSingleton
concreteData
OperationQ
Figure 3.3
3.3.1.6 Participants
AbstractSingleton
defines a static Instance () operation which allows clients access to its unique
instance.
defines a static Configure () operation which allows clients to specify which
subclass should be instantiated.
13


defines a protected constructor which throws an exception if called directly
(rather than by the Instance () method),
responsible for creating the unique instance.
ConcreteSingleton
defines a public constructor to be used by the Instance () method of the
AbstractSingleton class.
3.3.1.7 Collaborations
Clients configure the Abstract Singleton class during initialization, specifying the
appropriate concrete class (possibly by accessing an input parameter or reading an
input file).
Clients access an Abstract Singleton instance solely through the Instance () method.
3.3.1.8 Consequences
The Abstract Singleton pattern has several benefits:
All those given for the Singleton pattern.
Creation of a single instance from all possible subclasses without requiring the
instantiation and registration of each subclass.
The impact on the application developer (any creator of concrete subclasses) using
the Abstract Singleton is minimal.
Subclass creators are forced (by the compiler) to comply with the intent of the
pattern, thus minimizing possible mistakes.
3.3.1.9 Implementadon/Sample Code
There are several key steps in the implementation of the Abstract Singleton pattern in Java.
First, a static Configure () method should be created to allow the application to specify
which concrete class should be created. This method can be defined to take either a
java. lang.Class object, or a java lang. String object. In either case, the
purpose of Configure () is to store the specified class in a static member variable for use
in the Instance () method. Examples of both possible implementations are shown below.
public static void Configure(String s) throws ClassNotFoundException
{
_class = Class.forName(s);
}
or...
public static void Configure(Class c)
{
_class = c;
}
The next important method is the Instance () method.
public static synchronized AbstractSingleton Instance()
throws IllegalAccessException, InstantiationException
14


{
if (_instance == null)
{
_createlnstance = true;
_instance = (AbstractSingleton)_class.newlnstance();
_createlnstance = false;
}
return ..instance;
}
Since Java is a multi-threaded language, it is important that this method be synchronized.
Making a static method synchronized causes the method to block until it obtains the lock on
its Class object. This is necessary is to ensure that two threads which simultaneously call
Instance () cannot each create a new instance (having found that no instance had
previously been created), violating the basic premise that only one instance will ever exist at a
given time. Unfortunately, synchronizing this method is not enough to ensure that only a
single instance will be created. In fact, the above implementation illuminates a newly created
hole which would allow (possibly accidental) instantiation of subclass instances.
This hole arises from the requirements of the Class newlnstance () method. This
method creates a new instance of the specified class by calling the empty argument
constructor for that class. In order for this method to work, this constructor must be
accessible. In Java, this means that the constructor must be declared with default
vpackage-level) protection, or be declared public. Making the constructor public creates the
problem that an application, possibly unaware that the Abstract Singleton pattern is being used,
could now create an instance of the concrete subclass by simply using new. The
implementation of the Abstract Singleton constructor closes this hole.
protected AbstractSingleton()
throws InvalidSingletonlnstantiationException
r
synchronized(this.getClass())
{
if (AbstractSingleton._createlnstance == false)
throw new InvalidSingletonlnstantiationException();
}
}
The only way this constructor will actually create a new instance is if the
_createlnstance member variable has been set to true. Since this is only done within
the Instance () method, we (almost) ensure that the only way a new instance can be
created is through the use of the Instance () method. However, one last loophole must
be filled in order to avoid the following scenario:
Thread A calls Instance (), which sets the _createlnstance field to true.
Thread B calls new ConcreteSingleton () just before Thread A is able to
create the new instance.
15


Thread B enters the constructor for AbstractSingleton (called from the
constructor for the ConcreteSingleton), sees that _createlnstance is
true, and returns successfully.
Such a race condition would allow an instance (in theory, many instances) to be created
without going through the Instance () method. It might seem that a logical solution
would be to declare the constructor to be synchronized so that it could not run until the
Instance () method completed. This, however, will not work. Java does not allow
constructors to be synchronized since the synchronized modifier causes an object-level
lock to be obtained, and there is no possibility of another thread accessing an object while the
object is still being created. Rather than locking the instance being created, synchronization
should occur on the same object Instance () is synchronized on: the Class object
representing the AbstractSingleton class. This can be done using a synchronized
statement rather than the synchronized modifier. As shown above, the body of the
constructor is wrapped in a synchronized block, requiring the class-level lock to be
obtained before processing can continue. By doing so, the race-condition scenario described
above cannot occur. The new ConcreteSingleton () call would either enter before
the Instance () call (in which case the constructor would throw an exception, resulting in
no new object being created), or the new call would enter the constructor after
Instance () had set the _createlnstance field, but would be forced to block until
Instance () returned, by which time _createlnstance would have been set back to
false, again resulting in an exception being thrown.
As a result of the above implementation, a single requirement is imposed on the concrete
subclasses of AbstractSingleton. Each such subclass must provide a public
parameterless constructor which throws the same exception thrown by the
AbstractSingleton constructor. The following will suffice:
public ConcreteSingleton()
throws InvalidSingletonlnstantiationException {}
The addition of this throws clause is enforced at compile-time (alternately, the constructor
could call super () explicitly and catch the exception), so there is no worry of an
application developer forgetting to add it. Furthermore, code which attempts to create an
instance of such a subclass using new will fail to compile unless it catches the exception.
Finally, code which (for whatever reason) chooses to create an instance using the
Class newlnstance () method will fail at runtime since the AbstractSingleton
constructor will throw the exception as described above.
3.4 Template Method
The Template Method (325) pattern lets subclasses redefine certain steps of an algorithm
without changing the algorithm's structure. [GHJV95] This is perhaps the simplest and
most common pattern described in Design Patterns. The idea is simply to define a skeleton, or
template, algorithm within a base class which calls another method, usually abstract, allowing
part of the algorithm to be variable without changing the overall structure of the base classs
16


algorithm. This simple concept is used throughout the BGF and can be identified by the
presence of the word Hook in the name of the primitive operation called by the template
method. Using Template Method simplifies the job of the application developer since as much
code as possible is written within the template method. This also reduces possible errors
which could arise if certain methods were required to perform certain actions in order for the
framework (template) method to work. As a simple example, the GameOver () method on
the BGFBoard class is implemented as a template method. If this technique was not used,
GameOver () would be an abstract method and might be specified in a manner similar to
the following.
j *
* Determine if the game is over. NOTE: THIS METHOD MUST CALL
* setChanged() and notifyObservers() IF THE GAME IS OVER IN
* ORDER FOR THE GUI TO BE UPDATED!!!
*/
public abstract BGFGameOverStatus GameOver();
By using the Template Method pattern, the requirements of GameOver () are moved out of
the methods comments and into the code.
public BGFGameOverStatus GameOver()
{
BGFGameOverStatus s = GameOverHook();
if (s.IsGameOver() == true)
{
setChanged();
notifyObservers(s);
}
return s;
}
With this implementation, the application developer is only responsible for writing a method
called GameOverHook () which returns the status of the game. The template method takes
care of the notification process. A sample call sequence for a game which has just completed
is shown in Figure 3.4.
17


GameOver
amov:BGFGOS
GameOverHook
amov:BGFGOS
setChanged
notifyObservers
amoviObiect
>
qmov:BGFGfnOvStat
Figure 3.4
This is just one of many examples of the use of the Template Method pattern throughout the
BGF. Additional examples will be seen during the discussion of the other patterns used by
BGF.
3.4.1 Prees Metapattems
The Template Method pattern is also one of six basic metapattems described by [Pree95]. In this,
book, Pree defines template methods more generally as a means of defining abstract
behavior or generic flow of control or the relationship between objects. Here, a template
method not only calls methods declared in the base class and implemented by concrete
subclasses, but it may also call any methods on objects it is related to by any of Prees six
basic metapattern relationships. Thus, almost any non-trivial method becomes a template
method. The metapattern used to describe the scenario discussed in the Template Method
pattern is the simplest of the six, and is given the name Unification to reflect that the template
method and the hook method are declared in the same class. The issue of whether the hook
method is actually defined in the base class or in a concrete subclass is not considered
important in this level of analysis.
3.5 Abstract Factory
The intent of the Abstract Factory (87) pattern is to provide an interface for creating families
of related or dependent objects without specifying their concrete classes. [GHJV95] In the
BGF, an abstract factory class, BGFFactory, provides interfaces which enable other classes
in the framework to create instances of concrete application classes without knowledge of the
specific classes being instantiated. This is done by declaring abstract methods such as
CreateSpace () and CreatePlayers () which subclasses of BGFFactory must
18


define to create instances of the appropriate classes. For example, the Tic-Tac-Toe
application has a TTTFactory class which defines the CreateBoardView () method as
follows:
public BGFBoardView CreateBoardView(BGFBoard pBoard)
{
return new TTTBoardView(pBoard);
}
With this interface, classes in the BGF are able to create new instances of the class
TTTBoardView without knowing such a class exists (which is, of course, quite desirable
since the framework cannot know the names of the concrete subclasses which will be created
by a given application).
Like most abstract factory classes, only one instance of BGFFactory should ever be created.
To enforce this, the BGF uses the Abstract Singleton pattern described in the previous section.
The sequence diagram in Figure 3.5 shows the initialization of BGFFactory.
Figure 3.5
Figure 3.6 shows the simple process of obtaining a new object from the factory. Note that the
BGFApplet has access to the TTTFactory (which it views only as a BGFFactory) via
the Instance () method just shown.
19


Figure 3.6
3.6 Factory Method
Probably the most critical aspect of the Abstract Factory pattern described above is the use of
another pattern: Factory Method (107). This pattern defines an interface for creating an
object, but [lets] subclasses decide which class to instantiate. [GHJV95] The
CreateBoardView () method described above is just one of several factory methods
declared by BGFFactory.
The BGFFactory class contains the most exact use of this pattern in the BGF, but it is not
the only class in which the basic concepts behind Factory Method are used. The
BGFOneSpaceGUIStrategy class is a class used by games for which a move consists of
the placement of a single (new) piece on an empty space on the board. Such games include
Tic-Tac-Toe, Othello, and Connect-4. In these games, the strategy object defers the creation of
the new piece to the BGFOnePiecePlayer object to which the strategy is attached. In a
pure interpretation of the Factory Method pattern, BGFOnePiecePlayer would be a Creator
class, responsible for declaring an abstract factory method for the creation of a new
BGFPiece object. In this scenario, however, the only method subclasses of
BGFOnePiecePlayer would have to override would be this factory method. Rather than
force the application developer to create subclasses of BGFOnePiecePlayer (for X and 0
in Tic-Tac-Toe for example), the type of piece to be created is simply specified as a parameter
to the BGFOnePiecePlayer constructor by passing an object of type Class. As
described previously, new instances can be created using the newlnstance () method on a
Class object. This eliminates the need for parallel class hierarchies one for the
BGFPiece classes and one for the BGFOnePiecePlayer classes which create them.
3.7 Strategy
The Strategy (315) design pattern lets the algorithm vary independently from clients that use
it. [GHJV95] In the BGF, this pattern is used to implement player strategies. Each
player in the game has a corresponding strategy which defines how the player selects its next
move. Such strategies might include randomly selecting a move, performing a complex
search algorithm, or simply waiting for input from the GUI. By decoupling the strategy from
the player, the players can easily change strategies from game to game without having to
20


replace the actual BGFPlayer objects. The BGF encourages such behavior by fixing the
players during the initialization of the applet and providing an interface for the selection of a
strategy for each player before the start of each game. It should be noted that BGFPlayer
objects correspond to the abstract concepts of players for a given game. In chess, for
example, the players are Black and White, while the strategies might include Human,
NoviceComputer, and MasterComputer. The class diagram in Figure 3.7 shows the strategy classes'
provided by the BGF, as well as sample application level classes.
Figure 3.7
Note that while BGFStrategy and BGFGUIStrategy are abstract classes, the
BGFOneSpaceGUIStrategy and BGFTwoSpaceGUIStrategy classes are concrete
and may be used directly.
BGFStrategy defines the overall flow of the move-making process. The initial method
executed is called Run (). This method sets several state variables and then calls Move ().
The Move () method calls the MoveHook () method repeatedly until a valid move is
generated (MoveHook () is free to generate invalid moves and rely on Move () to catch
them). MoveHook () is an abstract method responsible for somehow creating a BGFMove
object and passing it to TryMove () for validation. The MoveHook () method may be
implemented in numerous ways. As an example, the TTTRandomStrategy () class
implements the method by generating a move based on two random numbers (row and
column). More intelligent strategies might use a complex search algorithm to find the best
move. Yet another example of the MoveHook () method is the method used by
BGFGUIStrategy. This method simply waits for input from the GUI and creates a move
based on the selected space or spaces.
As mentioned above, the MoveHook () method is expected to call TryMove () in order to
submit its move. The MoveHook () method obtains a reference (see the above discussion of
21


the Singleton pattern) to the BGFMoveProcessor instance and submits the move. The
details of the processing of moves is discussed later with respect to the Command pattern. For
now, it is sufficient to know that the submission of the move to the BGFMoveProcessor
will result in the _validLastMove data field in BGFStrategy being set. The Move ()
method then checks this flag, calling Move () recursively if the flag is set to false and
returning normally otherwise. The recursion continues until MoveHook () generates a valid
move.
Figure 3.8 shows the (non-recursive) scenario described above for a player using the
TTTRandomStrategy class. Note that the details of the SubmitMove () method on the
BGFMoveProcessor class are not shown here. See the discussion of the Command (233)
pattern for details on the BGFMove () class and its collaborators.
Run
s1:BGFStrateqy s1:TTTRandStrat
Move
MoveHook
T ryMove
mv1:NPM
SubmitMove
mv1:NPM
nrip:BGFMoveProc
<-+l
mv1 :BGFNewPieceMv
Figure 3.8
3.8 Command
The Command (233) pattern allows requests to be encapsulated as objects, thereby letting you
parameterize clients with different requests, queue or log requests, and support undoable
operations. [GHJV95] Buschmann, et. al. [BMRSS96] and Sommerlad [PLoP95] describe
a slightly more detailed version of this pattern called the Command Processor pattern. Ideas
from both patterns are used in the BGF in two parts of the system. The basic strategy behind
these patterns is to create a class for each basic command in the system (or some area of the
system), allowing instances of these Command classes to be created and passed to a Command
Processor to be executed. The Command Processor may queue requests, store them for future
undo, etc. Each command is responsible for knowing what other objects (suppliers) it needs to
interact with. In addition, commands may (depending on the nature of the system) need to
store state information to allow the command to be undone at some later time.
22


The simplest instantiation of the Command patterns in the BGF involves the handling of basic
GUI-generated commands. Figure 3.9 shows the classes defined in the BGF directly related
to this pattern.
Figure 3.9
In this case, the BGF takes advantage of very little that the Command patterns have to offer.
Commands are not logged and cannot be undone. However, the pattern still provides a
clean abstraction for the addition of new commands (applications are free to add new buttons
to the display and create new BGFCommand subclasses). In addition, the pattern provides
the flexibility to add logging and undo features in the future without requiring major
restructuring of the framework.
The other area of the framework in which the Command Processor pattern is used involves the
handling of the moves made in the games. Unlike the basic commands described above,
moves in a game should be logged and should have the ability to be undone. This allows
games to be saved (although this is not a feature of the framework since Java applets are
restricted from writing to the local filesystem), and allows players to take back errant moves
while properly restoring the board to its previous state. In order to provide this functionality,
the BGFMoveProcessor has a considerably larger interface than the
BGFCommandProcessor. This interface, as well as those of related types, is shown in
Figure 3.10.
23


Figure 3.10
The interface to BGFMoveProcessor provides methods to submit moves for execution,
undo the last move, and start a new game (which clears out all old moves).
BGFMoveProcessor keeps a stack of BGFMove objects representing valid moves which
have been made in a game. New moves are sent to the BGFMoveProcessor by a call to
the SubmitMove () method which immediately calls the Execute () method on the
input BGFMove object. If this method returns true, the move is pushed on the stack. If
Execute () returns false, indicating that the move was invalid, the move is not stored
and Submi tMove () returns immediately. The Undo () method takes no parameters,
relying on the internal stack to determine which move to undo. It first peeks at the top
item on the stack and calls its Undo () method. Like Execute (), Undo () returns a
boolean indicating the validity of the undo. Some games may not allow moves to be taken
back in certain situations. This return value allows this fact to be captured in a generic way.
If the Undo () method returns true, the BGFMove object is popped from the stack; if not,
the stack is unchanged.
The other major participant in this use of the Command Processor pattern is the
BGFMoveController interface. In Java, a collection of abstract methods (as well as
constant (final) static variables) may be collected into an interface. Classes may implement as
many interfaces as they want, though they may only extend (be a subclass of) one class. A class
which implements the BGFMoveController interface must provide implementations for
the two methods NotifylnvalidMove () and NotifylnvalidUndo (). Since there
is no meaningful default behavior and no additional methods to be associated with the move
controller, these methods are grouped into an interface to allow as much flexibility to the
application developer as possible. In the Command Processor pattern, the controller class is
defined as the class which creates command objects and transfers these objects to the
command processor. This definition is consistent with the intent of the
24


BGFMoveController interface, though there is nothing to stop classes which do not
implement this interface from creating and submitting BGFCoiranand objects. In the BGF,
the role of the controller (with respect to this instantiation of the Command pattern) is extended
to provide two callback routines for all BGFMove objects. These are the
NotifylnvalidMove () and NotifylnvalidUndo () methods mentioned above.
The constructor for BGFMove takes an object which implements the
BGFMoveController interface as a parameter. When a move is executed or undone
illegally, the BGFMove object calls the appropriate notification method to reflect the failure.
For this reason, it makes sense that the object submitting the move also be the
BGFMoveController which receives the notification. Note that pulling the notification
methods out of the BGFStrategy class (currently, the only class in the system which
implements the BGFMoveController interface) allows additional classes (such as a saved
game reader) to be created which also participate in this Command pattern.
Figure 3.11 shows the creation and submission of a move by a
BGFOneSpaceGUIStrategy object. In this scenario, the move is rejected (by the
PlacePiece () method on BGFSpace) and a notification is sent back to the strategy
object.
Figure 3.11
3.9 Iterator
The Iterator (257) pattern provides a way to access the elements of an aggregate object
sequentially without exposing its underlying representation. [GHJV95] The Java utility
package supports this pattern through the Enumeration interface. This is a very simple
interface, providing two methods: hasMoreElements () and nextElement (). Classes
implementing this interface provide easy access to an aggregate object. In the BGF, this
25


pattern (and the Enumeration interface, specifically) is used to provide an easy way to
iterate over all spaces on the board. In this case, the board is the Aggregate and the
BGFBoardEnumeration class is the Iterator. An object wishing to iterate over all spaces
on the board may simply call the GetBoardEnumeration () method on the BGFBoard
instance to obtain a new BGFBoardEnumeration object. Then, a simple loop like the
following can be used:
BGFBoardEnumeration enum = board.GetBoardEnumeration();
while (enum.hasMoreElements() == true)
{
BGFSpace space = (BGFSpace)enum.nextElement();
// do something with space
}
The Iterator pattern describes an additional abstract class which provides an interface for the
abstract creation of iterators. There was no need for this abstraction in this particular use of
the pattern, so the iterator creation method was placed directly in the BGFBoard class.
3.10 Prototype
The Prototype (117) pattern creates new instances of objects by cloning an existing prototype
instance. [GHJV95] The BGF does not implement this pattern directly, but it does employ
the fundamental concept of using prototype objects to create new instances. The actual
implementation of these ideas in the BGF, and the motivation behind it, is somewhat
unusual.
Languages which treat classes as first class objects (such as Smalltalk and Java) have little
need for the Prototype pattern since Class objects can be used with the newlnstance ()
method to create new instances. In the BGF, a combination of this strategy and the Prototype
pattern as it is defined is used for the creation of new BGFStrategy objects. The goal is to
present the user with a list of strategies from which to chose, creating the appropriate
instance based on the chosen strategy. It is the presentation issue which shows the limitation
of passing Class objects. The dialog box (BGFWhoPlaysDialog) receives an array of
strategies to be displayed and later instantiated. If the input was an array of Class objects,
the only way the choices could be displayed to the user would be to display the name of the
class obtained by parsing the output of the Class toString () method. Clearly, this
would not be ideal since it would require the use of class names which could be directly
displayed to the user (which would, among other things, require that names have no
embedded spaces). The next option would be to use the Prototype pattern directly and
implement a clone () method on the strategy objects. This would be a fairly reasonable
solution, especially considering that the Object class in Java defines a clone () method
which can be used simply by specifying that a class implements the Cloneable interface.
The problem with this option is that each BGFStrategy object corresponds to a single
BGFPlayer object, so the clone () method would have to be overridden to ensure that
the player reference in the strategy object being cloned was not replicated (since this would
result in two BGFStrategy objects pointing to the same BGFPlayer object).
26


Instead of either of these approaches, the BGF uses a simple combination. The input to the
BGFWhoPlaysDialog constructor is an array of prototype BGFStrategy objects,
created solely for this purpose within BGFFactory. The BGFStrategy class has a
_name member variable which can be accessed and displayed to the user. Once the user
selects a strategy, the Class object for the selected BGFStrategy object is obtained (via
the getClass () method defined on Object), and the newlnstance () method is
called. This allows the default constructor to be used rather than having to add a clone ()
method to BGFStrategy. Figure 3.12 shows the flow of control for the creation of a new
BGFStrategy instance.
d1:BGFDialoa s1:TTTRandStrat randStrat:Class

p1:BGFOnePcPlvr
getClass ^
P
rand: Class
newlnstance
s2:TTTRandStrat
*
s2:TTTRandStrat
T
SetStrateav
s2:TTTRandStrat
hr*
Figure 3.12
3.11 Chain of Responsibility
The Chain of Responsibility (223) pattern avoids coupling of a request to its receiver by giving
more than one object a chance to handle the request. [GHJV95] The BGF does not
implement this pattern itself, but it does rely on the fact that it is implemented by the AWT.
The simple layout of the BGF interface includes a Panel on which several Button objects
are placed. This Panel is itself contained within the BGFApplet (which is a subclass of
Applet, itself a subclass of Panel). The event-handling mechanism in Java passes events
up the containment chain until the event is handled. This means that it is not necessary to
create subclasses of java awt. Button for each button placed on the display solely for the
purpose of performing a certain action when the button is clicked. Thanks to the use of Chain
of Responsibility, the event indicating the pressing of a button is passed from the Button to its
enclosing Panel and finally to the enclosing BGFApplet object which handles it by
overriding the action () method it inherits from the j ava. awt. Component class.
Figure 3.13 shows the detailed calling sequence which occurs as the result of a button being
pressed, starting with the Event being delivered to the Button object. Note that the
handleEvent () method takes an Event object as a parameter, and that action () takes
both an Event and an Object parameter. These parameters are not shown in the
diagram in order to keep it readable. It should also be pointed out that the
HandleButton () method on BGFApplet does more than just return true. Based on
which button was selected, this method creates the appropriate BGFCommand object and
27


sends it to the BGFCommandProcessor.
Figure 3.13
28


4. Developers Guide
I soon can leam how to do it if youll let me see it done;
I can watch your hands in action, but your tongue too fast may run.
And the lecture you deliver may be very wise and true,
But Id rather get my lessons by observing what you do.
Edgar A. Guest, Sermons We See (from Peter Coads Object
Models: Strategies, Patterns, & Applications)
This section provides a detailed cookbook for creating applications using the BGF. Each
method requiring an application-specific implementation (as well as those methods which
may be optionally overridden) is explained, and extensive examples from implemented games
are provided. The explanation follows a logical conceptual flow, starting with the core model
objects and adding details as they become necessary.
4.1 The Example Games
This section will draw on examples from two games implemented using the BGF. The
simplest of these games is Tw-Tac-Toe. The other game, Quixo, is a bit more complex and
presumably less familiar. Quixo is played on a 5x5 board with 25 cubic pieces. Each cube has
four blank sides and two sides with unique symbols (in the BGF version, the other two sides
are given unique colors). Initially, all cubes are placed such that a blank side shows. Each
player, in turn, picks up a cube showing either a blank side or her own symbol from the
perimeter and slides blocks over from any side to fill in the space made by the removal of the
piece. The removed piece is then placed in the newly opened perimeter space, with the
symbol of the player making the move now showing. The goal of the game is to get five of
your pieces in a row (vertically, horizontally, or diagonally) before your opponent. Figure 4.1
shows a sample move by player X.
29


this piece can be moved
I
here-
here
t
moved here, pushed blocks up
Figure 4.1
4.2 First Steps
The first classes to be developed are the easiest to conceptualize since they represent physical,
tangible objects. These classes will be MyGameBoard, MyGameSpace and
MyGamePiece (for this purpose of this section, all new classes will be prefixed with
"MyGame. The examples used all begin with either TTT (Tic-Tac-Toe) or Quixo). Each
compilation unit must begin by importing the BGF package. Either of the following syntax
options is acceptable:
import EDU.cudenver.BGF.*; // or...
import EDU.cudenver.BGF.BGFBoard; // different for each class
Each class declaration begins with something like:
public class MyGameBoard extends BGFBoard
{ // ... the good stuff...
For the remainder of this section, the import and class lines will be omitted.
The first class to examine is the MyGameBoard class, for which a constructor must be
created which passes the width and height of the board on to the superclass constructor. This
is all the constructor needs to do, so the following will suffice:
public MyGameBoard() throws BGFInvalidSingletonlnstantiationException
{
super(_width, _height); II dimensions of the board
}
Notice that this constructor is defined to throw
BGFInvalidSingletonlnstantiationException. This is because the
BGFBoard constructor also throws this exception. This helps to ensure that instances of this
class will not be created using new or Class newlnstance (), but instead only through
30


the static BGFBoard. Instance () method. The details of this strategy are discussed in
section 3.3.1.
Next, a NewGameHook () method may be needed. This is not an abstract method, so if no
setup of the board is required, this method may be left out. This is the case for Tic-Tac-Toe,
since the board is initially empty. In Quixo, the board is initially covered with 25 blocks, so
these pieces must be created and placed on the board. The BGFBoardEnumeration class
is used to iterate over the spaces, placing a new piece on each space. Heres the code from
QuixoBoard.j ava.
protected void NewGameHook(BGFPlayer[] pPlayers)
{
try
{
BGFBoardEnumeration enum = GetBoardEnumeration();
while (enum.hasMoreElements() == true)
{
BGFSpace space = (BGFSpace)enum.nextElement();
space.PlacePiece(new QuixoPiece());
}
}
II...
}
Notice that this method receives the (ordered) list of players involved in the game which may
be needed if pieces belonging to specific players need to be created.
The only other method needed for MyGameBoard is the GameOverHook () method.
This is typically one of the more involved methods in the application. This method must
examine the state of the board and return a BGFGameOverStatus object indicating
whether or not the game is over and, if so, who the winner (if any) is. How this is determined
is very game-specific, and so wont be covered in detail here. The important thing is to
understand the interface to the BGFGameOverStatus class.
public BGFGameOverStatus(boolean pGameOver,BGFPlayer pWinner)
public BGFGameOverStatus() //-> BGFGameOverStatus(false,null)
public void SetGameOver(boolean pGameOver)
public void SetWinner(BGFPlayer pWinner)
These are the public constructors and methods available in BGFGameOverStatus. If
additional information is needed, this class may be extended as necessary. In fact, the BGF
includes an extension of this class called BGFWinningPiecesGameOverStatus. This
class adds a data member to hold an array of BGFSpace objects which were involved in
creating a winning position (such as the 3-in-a-row in Tic-Tac-Toe). The complete class
declaration is shown below.
public class BGFWinningSpacesGameOverStatus
extends BGFGameOverStatus
{
public BGFSpace[] GetWinningSpaces()
31


{
return _winningSpaces;
}
public void SetWinningSpaces(BGFSpace[] pWinningSpaces)
{
_winningSpaces = pWinningSpaces;
}
private BGFSpace[] _winningSpaces;
}
Additional subclasses of BGFGameOverStatus or even
BGFWinningSpacesGameOverStatus may be created as needed by the application.
There is generally no need to extend the BGFSpace class, so the next class to consider is
MyGamePiece. Like BGFSpace, BGFPiece is not an abstract class, so it may not need to
be extended either. However, depending on the game, it may be necessary to override the
IsMoveableBy () and IsMoveableTo () methods. In Tic-Tac-Toe, this wasnt
necessary since pieces on the board cant be moved at all (the BGFMove class used in
Tic-Tac-Toe never has any need to call these methods). The default implementation of
IsMoveableBy () allows a piece to be moved by the player who owns the piece. This may
be sufficient for some games, but many have additional restrictions. If so (as in Quixo), the
method may be overridden. In Quixo, a piece is moveable by player A if the piece is
blank-side-up or if player As side is showing. In addition, the piece must be on the perimeter
of the board. An additional (protected) method is added to QuixoPiece to help the
IsMoveable() method. Heres the code:
public boolean IsMoveableBy(BGFPlayer pPlayer)
{
BGFPlayer pi = GetPlayer();
if ((pi == null) || (pi == pPlayer))
return IsMoveable();
else
return false; // owned by someone else
}
protected boolean IsMoveable()
{
BGFSpace s = GetSpace();
int row = s.GetRow();
int col = s.GetColf);
if (((row == 0) || (row ==
|| ((col == 0) II (col ==
return true;
else
return false;
)
// must be on the edge
4) )
4) ) )
In addition to IsMoveableBy (), the BGFPiece class declares an IsMoveableTo ()
method which allows a piece to restrict where the spaces to which it may be moved (possibly
based on its current location). This method takes a BGFSpace object representing the target
32


space. In chess, each piece type would have an IsMoveableTo () method. The
BishopPiece class, for example, would check to ensure that the new space was reachable
on a non-blocked diagonal path from the current space. In Quixo, the following method is
used:
public boolean IsMoveableTo(BGFSpace pSpace)
{
BGFSpace s = GetSpace();
if (s == pSpace)
return false; // must move it somewhere else
int fromRow = s.GetRowf); int fromCol = s.GetCol();
int toRow = pSpace.GetRowf); int toCol = pSpace.GetCol();
if (fromRow == toRow) // same row
{
if ((toCol == 4) || (toCol == 0)) // move to one side
return true;
return false;
}
if (fromCol == toCol) // same col
{
if ((toRow == 4) || (toRow == 0)) //to top or bottom
return true;
return false;
}
return false; // not same row OR same col
}
Everything needed for the basic model classes MyGameBoard, MyGameSpace, and
MyGame Piece has now been covered. The following list summarizes what needs to be
done for these classes:
> MyGameBoard
constructor to pass width and height to BGFBoard constructor which lists the
BGFInvalidSingletonlnstantiationException in its throws clause
GameOverStatus () method to determine if the game is over
NewGameHook () method to set up board (optional)
y MyGameGameOverStatus (optional)
any additional data needed to represent a game-over situation
> MyGameSpace
no class needed
y MyGamePiece
may need no subclass
may need one subclass for each piece type in the game
IsMoveableBy () method to determine if a piece may
(optional)
IsMoveableTo () method to determine if a piece may
(optional)
be moved by a given player
be moved to a given space
33


4.3 Seeing the Game
Now that the basic conceptual classes have been created, the game must be made visible to
the user. This section will focus on the creation of the primary view classes
MyGameBoardView, MyGameSpaceView, and MyGamePieceView. First, it is
important to understand the interactions between the base classes for these view classes since
a great deal of the work is done directly within them.
The BGFBoardView class, which inherits from j ava awt. Canvas, is responsible for
painting the board, spaces, and pieces to the screen. It delegates part of this painting process
to the BGFSpaceView and BGFPieceView classes as one would expect. As part of this
responsibility, BGFBoardView uses a technique called double-buffering to make screen
updates as smooth as possible. Double-buffering involves drawing everything to an off-screen
image then later drawing the completed image to the real Graphics object once
everything has been drawn, making the update of the display more smooth. By-
implementing this technique at this level, other view classes in the BGF and in BGF
applications are relieved from having to worry about it.
Just as BGFBoard keeps references to many BGFSpace objects, BGFBoardView objects
keep references to many BGFSpaceView objects. When a request is made to repaint the
board, the BGFSpaceView objects are asked to draw themselves. Each BGFSpaceView
object acts as an Observer of its respective BGFSpace object, receiving notification each time
a piece is moved to or moved off the space it is watching. When this happens, the
BGFSpaceView object notifies the BGFBoardView which contains it that it needs to be
repainted. The BGFBoardView can then repaint the portion of the board containing the
space. Each BGFSpaceView object has a reference to a BGFPieceView object (which
may be null if there is no piece on the space). It is the BGFPieceView objects which
must know how to render themselves on the board.
Given this brief overview of the interaction between these classes, it is now possible to
examine what needs to be done to extend them.
The MyGameBoardView class must define a constructor which takes a reference to the
BGFBoard object to be observed and forwards this reference on to the BGFBoardView
constructor along with the width and height of the game board (in pixels). In Tic-Tac-Toe, the
following code is used:
public TTTBoardView(TTTBoard pBoard)
{
super(pBoard, kBoardWidth, kBoardHeight);
}
In this case, two constants are used to hold the width and height of the board. In addition to
providing a constructor, MyGameBoardView may also implement a method called
Draw (). This method, as its name suggests, draws the board on the input graphics context.
It is important to note that the drawing of individual spaces on the board should not be done
34


by this method. Instead, only things which appear outside the spaces (such as a border
around the board) or between the spaces (see the Tic-Tac-Toe example below) should be
drawn here. Games with no such additional graphics may use the default Draw () method
which does nothing (in fact, the BGFBoardView class is not abstract and so may be used as
it is if the Draw () method is not overridden). The following example shows the Draw ()
method for the Tic-Tac-Toe program. This method draws four long, narrow rectangles to
create the four lines which make up the board.
public void Draw(Graphics pGraphics)
{
pGraphics.setColor(Color.black);
pGraphics.fillRect(kSpaceWidth, 0, kLineThickness, kBoardHeight)
pGraphics.fillRect((kSpaceWidth*2)+kLineThickness, 0,
kLineThickness, kBoardHeight);
pGraphics.fillRect(0,kSpaceHeight,kBoardWidth, kLineThickness);
pGraphics.fillRect(0,(kSpaceHeight*2)+kLineThickness,
kBoardWidth,kLineThickness);
)
This is an example of drawing board contents which are within the board, but not drawn by
the BGFSpaceView objects. Chess, in contrast, would have the BGFSpaceView objects
in charge of drawing the different colored squares. The Quixo example below shows a
Draw () method which simply draws a filled border around the playing area.
public void Draw(Graphics pGraphics)
{
pGraphics.setColor(Color.black);
pGraphics.fillRoundRect(0,0,
(kPieceSize*kGridSize)+(kBorderSize*2),
(kPieceSize*kGridSize)+(kBorderSize*2), kArc, kArc);
}
No other methods need to be written for the BGFBoardView class.
The MyGameSpaceView class is fairly similar. It should take as input the
BGFBoardView which contains it and the BGFSpace which it observes. The constructor
for BGFSpaceView takes these same tw'o parameters plus a j ava awt. Rectangle
object representing the placement of this space on the board. In order to create this
rectangle, the MyGameSpaceView constructor will generally perform a calculation based
on the row and column of the input BGFSpace object. The example below comes from the
Tic-Tac-Toe program. Here, the TTTSpaceView constructor uses public constants for the
size of each space (and the space between each space) defined in the TTTBoardView class
to calculate the coordinates of the space based on the row and column of the input
BGFSpace.
public TTTSpaceView
(
BGFBoardView pBoardView,
BGFSpace pSpace
)
{
35


super( pBoardView,
pSpace,
new Rectangle(
pSpace.GetCol()*TTTBoardView.kSpaceAndLineWidth,
pSpace.GetRow()*TTTBoardView.kSpaceAndLineHeight,
TTTBoardView.kSpaceWidth,
TTTBoardView.kSpaceHeight)) ;
}
It should be noted that BGFSpaceView is not an abstract class. Applications are free to use
this class directly if they require no special behavior. However, most games will want to
override some or all of the three methods discussed below.
The first is the ShowGameOver () method, the purpose of which is to provide a way to
visually indicate that the game is now over (or, perhaps, that it was over, but is now back in
progress due to a player taking back the winning or (more likely!) losing move). An example
of the use of this method might be to draw a line through the spaces connecting the pieces
making up a three-in-a-row in Tic-Tac-Toe. Another option, shown here, would be to
highlight the winning pieces. In this case, its really up to the MyGamePieceView objects
to show this information, but ShowGameOver () is overridden to help them out.
public
{
if
{
}
boolean ShowGameOver(BGFGameOverStatus pStatus)
(_pieceView != null)
// if the game is not over, tell the piece to make sure color
// is correct (used for taking back last move of the game)
if (pStatus.IsGameOver() == false)
return _pieceView.ShowGameOver(pStatus);
if(pStatus.GetWinner() == null)
return false; // game was a draw
// if the game IS over, tell the piece if it is one of those
// making the 3-in-a-row
BGFSpace[] spaces =
((TTTGameOverStatus)pStatus).GetWinningSpaces();
for (int i=0;i {
if (spaces[i] == _space)
return _pieceView.ShowGameOver(pStatus);
}
return false;
}
The return value of this method indicates whether or not this space would like to be redrawn.
If nothing has changed, the BGFBoardView calling this method has no reason to redraw
each space on the board. Note that the default method defined in BGFSpaceView simply
forwards the call on to its BGFPieceView object (if it has one).
36


The other two methods which may need to be overridden in subclasses of BGFSpaceView
are the Draw () and DrawEmpty () methods. These are called to render a space on the
board along with any piece which might lie on the space. The default versions of these
methods (shown below) assume that the space has no intrinsic visual quality, drawing a blank
space in the case of DrawEmpty () and forwarding calls to the Draw () method on to
BGFPieceView.
protected void DrawEmpty(Graphics pGraphics)
{
pGraphics.setColor(_boardView.getBackground());
pGraphics.fillRect(_rect.x, _rect.y, _rect.width, _rect.height);
}
protected void Draw(Graphics pGraphics)
{
if (_pieceView != null)
_pieceView.Draw(pGraphics, _rect);
else
DrawEmpty(pGraphics) ;
}
For some applications, this will work perfectly. In fact, neither Tic-Tac-Toe nor Quixo override
either method. However, games like chess might have DrawEmpty () methods responsible
for drawing the properly colored space on the board.
Finally, the MyGamePieceView class must be created to do the actual rendering of the
pieces on the board. The constructor for this class simply passes the BGFPiece object being
observed up to the superclass.
For games with multiple piece types, multiple subclasses of BGFPieceView should be
created, each with its own Draw () method. It may be useful to create an abstract superclass
as a subclass of BGFSpaceView from which the various game-specific classes extend. This
strategy' is used in the Tic-Tac-Toe program to allow the generic TTTPieceView class to
implement the ShowGameOver () method while the TTTXPieceView and
TTTOPieceView classes each define their own Draw () method. Keep in mind that since
TTTPieceView does not implement Draw (), it must be defined as abstract and it must
declare the abstract Draw () method as shown below.
public abstract class TTTPieceView
extends BGFPieceView
{
// ...
abstract protected void Draw
(
Graphics pGraphics,
Rectangle pRect
) ;
II ...
}
37


The ShowGameOver () method discussed earlier is shown here. For Tic-Tac-Toe, the
winning pieces are shown in a different color. In this implementation (as was shown when
looking at the TTTPieceView class), the only time this method will be called is when the
piece is involved in a win, or when the game is not over.
public boolean ShowGameOver(BGFGameOverStatus pStatus)
{
Color oldColor = _color;
if (pStatus.IsGameOver() == true)
_color = kGameOverColor;
else
_color = _normalColor;
if (_color == oldColor)
return false;
else
}
return true;
The final method to be added to MyGamePieceView is the Draw () method. A wide
variety of techniques could be used here. The developer is free to use any available AWT
methods to render the piece on the input Graphics within the input Rectangle. This
may involve the use of any of the basic drawing methods available to the Graphics class, or
it may involve loading an image and drawing that image to the Graphics. As previously
noted, the BGFBoardView class implements a technique called double-buffering so the
Draw () methods on BGFSpaceView and BGFPieceView may freely draw directly to
the input Graphics object, without worrying about screen flicker.
The Draw () method for Quixo is shown below. This method uses the draw3DRect ()
method several times to create the look of a three-dimensional block. Note the use of the
Graphics translate () method. This allows the origin to be set to the upper-left
corner of the input rectangle, making future drawing methods more straight forward. Its
important to then reset the origin before exiting the method so that future uses of the same
Graphics object will have the original origin.
protected void Draw
(
Graphics pGraphics,
Rectangle pRect
)
{
Color pieceColor =
QuixoPieceView.GetColor(GetPiece().GetPlayerO);
pGraphics.setColor(pieceColor);
pGraphics.translate(pRect. x, pRect.y);
int x = 0, y = 0;
int w = pRect.width 1;
int h = pRect.height 1;
for (int i=0;i {
pGraphics.draw3DRect(x++, y++, w, h, true);
w = 2 ;
38


h -= 2;
}
pGraphics.fill3DRect(x, y, w+1, h+1, true);
pGraphics.translate(-pRect.x, -pRect.y); // back like it was
}
Nothing further needs to be done for the primary view classes. To summarize:
> MyGameBoardView {optional)
constructor which passes the total dimensions of the board to BGFBoardView
Draw () method to render anything not contained in a space (optional)
> MyGameSpaceView (optional)
constructor which passes a Rectangle specifying the size and location of the space
on to the BGFSpaceView constructor
ShowGameOver () method to reflect the end of a game (optional)
Draw () and DrawEmpty () methods to show the space and its piece (optional)
> MyGamePieceView
constructor which does nothing but pass the BGFPiece up to its super
ShowGameOver () method to reflect the end of the game {optional)
Draw () method to render the piece
4.4 Additional Required Classes
At this point, the primary conceptual and visual classes have been created. There are just
two more classes which must be completed to create a working BGF applet. The first of
these is the MyGameFactory class. This is the class which allows methods in the BGF
classes to generically create instances of concrete subclasses without knowing what type of
object is being created. There are quite a few abstract methods in the interface, but
implementing them is generally quite simple.
public abstract class BGFFactory
{
public abstract BGFBoardView CreateBoardView(BGFBoard pBoard);
public abstract BGFPieceView CreatePieceView(BGFPiece pPiece);
public abstract BGFSpaceView CreateSpaceView(BGFBoardView
pBoardView, BGFSpace pSpace);
public abstract BGFPlayer[] CreatePlayers();
public abstract BGFStrategy[] CreatePrototypeStrategies();
public BGFSpace CreateSpace(int pRow, int pColumn)
{
return new BGFSpace(pRow, pColumn);
}
public BGFMovePieceMove CreateMovePieceMove(BGFMoveController
pMoveCon, BGFPlayer pPlayer, BGFPiece pPiece, BGFSpace
pFromSpace, BGFSpace pToSpace)
{
return new BGFMovePieceMove(pMoveCon, pPlayer, pPiece,
pFromSpace, pToSpace);
39


}
II...
)
The first three methods should simply return a new instance of the appropriate concrete class
using the input parameters as constructor parameters. The CreatePlayers () method
returns an array containing newly created instances of the players in the game. The order of
the array should reflect the order in which the players make their moves (e.g. player [ 0 ]
would be white in chess, while player [ 1 ] would be black since white always moves first).
Remember that the players in the game represent the different sides of the game, not the
strategy used to play the game, so the objects created here should persist throughout the life
of the applet. The next method, CreatePrototypeStrategies () is used to create an
instance of each possible BGFStrategy subclass available to the players in the game.
These objects are used to populate the BGFWhoPlaysDialog object. The reason objects
are created here is that the dialog really needs two pieces of information: the name of the
strategy (to display to the user), and the type of the object to create if the user selects a given
strategy. The objects are called prototypes because they are never used directly. Instead,
the name of the strategy is used to populate the display, and the Object. GetClass ()
method is used on the object to obtain the Class object representing the strategy class so
that Class .newlnstance () may then be used to create a unique BGFStrategy
instance for each player (multiple players might use the same strategy, so unique instances
must be created rather than directly using the prototype object). The Quixo
implementations of these last two methods are shown below.
public BGFStrategy!] CreatePrototypeStrategies!)
{
BGFStrategy!] strategies = new BGFStrategy[2];
strategies[0] = new BGFTwoSpaceGUIStrategy();
strategies[1] = new QuixoRandomStrategy();
return strategies;
}
public BGFPlayer!] CreatePlayers!)
{
BGFPlayer[] players = new BGFPlayer[2];
players[0] = new BGFPlayer(kPlayerlName) ;
players[1] = new BGFPlayer(kPlayer2Name);
return players;
}
Note that Quixo uses strategy and player classes provided by the BGF, as well as its own
random strategy class. The result of these two methods is the eventual creation of a Who
Plays dialog box like the one shown in Figure 4.2. Note that each player may choose from
any of the possible strategies.
40


Player 1 Player 2
Human Human
v-Randomizer vRandomizer
OK I
Figure 4.2
The last two methods listed in the BGFFactory interface provide default implementations.
The first is the CreateSpace () method which simply returns a new instance of the
BGFSpace base class. Applications which create their own BGFSpace subclasses must also
override this method to create the proper space type. The other method providing a default
implementation is the CreateMovePieceMove () method. The purpose of this method
is to allow the generic creation of a BGFMove object subclass representing a move in which a
piece is moved from one space to another. Such move classes will typically have some
class-specific behavior and will therefore be subclassed. The default behavior creates a
generic BGFMovePieceMove object, ensuring that games which do not need such moves
are not forced to provide an implementation of this method and providing a simple
implementation for games which can directly use the BGFMovePieceMove class as it is
defined.
One additional item which must be added to the MyGameFactory class is a public
zero-parameter constructor. This constructor (like the MyGameBoard constructor) must list
the BGFInvalidSingletonlnstantiationException in its throws clause. The
constructor may be as simple as the following:
public MyGameFactory() throws
BGFInvalidSingletonlnstantiationException { }
A class with responsibilities directly related to those in MyGameFactory will be the
MyGameApplet class. This class inherits from BGFApplet, which in turn extends
j ava. awt. Applet. The methods needed in MyGameApplet provide the applet with
various types of initial setup data. The BGF uses a technique for the initialization of Abstract
Singleton classes based on Javas exposure of the type system at runtime. In Java, each class in
the system has a corresponding Class object which can be used for, among other things, the
creation of new instances of a class. Furthermore, a Class object can be obtained at any
time by passing the name of the class to the static Class f orName () method. To take
advantage of these conveniences, the BGFApplet class declares two abstract methods
namedGetFactoryClassName() and GetBoardClassName(). The
implementation of these two methods in BGFApplet subclasses simply involves returning a
String containing the Jiilly qualified name of the respective concrete classes. The
implementations for the Tic-Tac-Toe program are shown below.
static private final String kFactoryClassName =
"EDU.cudenver.BGF.TTT.TTTFactory";
static private final String kBoardClassName =
41


"EDU.cudenver.BGF.TTT.TTTBoard";
protected String GetFactoryClassName()
{
return kFactoryClassName;
}
protected String GetBoardClassName()
{
return kBoardClassName;
}
These two simple methods allow the BGFFactory and BGFBoard singleton classes to be
configured to create the correct concrete object. For more details on Abstract Singletons, refer
to section 3.3.1.
The BGFApplet class provides a very basic user interface consisting of three buttons
(anchored to the top of the applet) and the board (set in the center). The class makes use of
an AddButtons () method to place the buttons on a Panel to be displayed on the applet.
This method may be overridden in order to add additional buttons, or to remove unwanted
buttons. If buttons are added, the HandleButton () method must also be overridden to
provide the desired action for this button. Overriding versions of these two methods will
likely want to call super. AddButton () and super. HandleButton () in order to
invoke the overridden methods from within the subclass implementation; otherwise, the
buttons provided by BGFApplet will no longer appear or function. Possible
implementations of these methods are shown below.
protected void AddButtons(Panel pPanel)
{
super.AddButtons(pPanel);
pPanel.add(new Button("Save Game"));
}
protected void HandleButton(Button pButton)
{
super.HandleButton(pButton);
BGFCommand command = null;
if ("Save Game".equals(pButton.getLabel()) == true)
{
command = new MyGameSaveGameCommand();
}
if (command != null)
{
BGFCommandProcessor cp = BGFCommandProcessor.Instance();
cp.SubmitCommand(command);
}
}
The BGFCommand and BGFCommandProcessor classes are discussed in the next section.
The important thing to notice here is that both methods call the methods they override to
allow the BGFApplet methods to perform their default action. If the goal was to remove
certain buttons from BGFApplet, the AddBut tons () method would not call
42


super. AddButtons (), but would need to add any buttons defined in
BGFApplet. AddButtons () which it did want to keep.
Nothing further needs to be done for the BGFApplet class. This section added:
> MyGameFactory
zero-argument constructor which does nothing, but declares itself to throw the
BGFInvalidSingletonlnstantiationException
CreateBoardView () factory method
CreatePieceView () factory method
CreateSpaceView () factory method
CreatePlayers () factory method
CreatePrototypeStrategies () factory method
CreateSpace () factory method {optional)
CreateMovePieceMove () factory method (optional)
> MyGameApplet
GetBoardClassName() method which returns MyGameBoard
(fully-qualified)
GetFactoryClassName () method which returns MyGameFactory
(fully-qualified)
AddButtons() method which calls super .AddButtons () unless you want to
remove the default buttons {optional)
HandleButtons () method which calls super HandleButtons () unless the
default buttons have been removed {optional)
4.5 Optional Glasses
The previous sections described classes in the BGF which must be extended by each
implementation. This section discusses four BGF classes which are not abstract, but may
require extension for certain types of games. For each of the four classes, some reusable
concrete components already exist in the framework. The developer must determine
whether the existing classes will suffice for each new application.
The BGF classes covered in this section are BGFCommand, BGFStrategy, BGFPlayer,
and BGFMove.
4.5.1 Extending BGFCommand
The BGFCommand class is used to encapsulate any type of command received from the user.
The BGF provides four subclasses of BGFCommand:
BGFNewGameCommand
BGFTakeBackCommand
BGFWhoPiaysCommand
BGFSpaceSelectedCommand
43


These commands are created as a result of input from the GUI. The implementation of
these classes is very simple, though new commands could be more complex. Each of the
commands listed above simply retrieves the BGFGameMaster object and calls an
appropriate method on that object. The implementation of BGFTakeBackCommand is
shown below as an example.
public class BGFTakeBackCommand
extends BGFCommand
{
public BGFTakeBackCommand(int pCount)
{
_count = pCount;
}
public void ExecuteHook()
{
BGFGameMaster gm = BGFGameMaster.Instance();
gm.TakeBack(_count);
}
private int _count;
}
Applications which add additional buttons or other GUI components to the display should
create new subclasses of BGFCommand to execute the appropriate command. The only
requirement of BGFCommand subclasses is that they provide an ExecuteHook () method
which performs the desired action. The BGFCommand base class takes care of executing
each command in a new thread, allowing the GUI thread to return as quickly as possible.
The implementation of BGFCommand is shown below to give an understanding of where the
ExecuteHook () method fits in the overall flow.
abstract public class BGFCommand
implements Runnable
{
abstract protected void ExecuteHook();
public void run()
{
ExecuteHook();
}
public void Execute!)
{
Thread t = new Thread(this);
t.startO; // calls run()
}
}
4.5.2 Extending BGFStrategy
The BGFStrategy class is responsible for the creation of BGFMove objects any time the
player emploring the strategy is asked to make a move. For applications which include
intelligent computerized players, this class will be the most complex in the entire
application since it must generate (possibly with the help of other application-specific classes)
the computers moves. However, BGFStrategy is not used exclusively for
44


computer-generated moves. Any move in the game should ultimately be generated by a
BGFStrategy object. This includes moves based on input from the GUI, moves retrieved
via a network connection or Remote Method Invocation (RMI), etc. The BGF provides
several concrete reusable components for handling moves generated from the GUI. These
include:
BGFGUIStrategy
BGFOneSpaceGUIStrategy
BGFTwoSpaceGUIStrategy
The last two of these inherit from the first, which is an abstract extension of the abstract base
class BGFStrategy.
Both BGFOneSpaceGUIStrategy and BGFTwoSpaceGUIStrategy may be used
directly by an application. The first is used for games in which a move is generated by
clicking a single space on the board and placing a new piece (created by the
BGFOnePiecePlayer class) on that space. BGFTwoSpaceGUIStrategy is used in
games in which a move is made by first clicking on a piece to be moved, and then clicking on
a space to which the piece is to be moved. These classes extend BGFGUI Strategy by
providing unique implementations of the abstract method HandleSpaceSelection ()
defined by BGFGUI Strategy. The purpose of this method is to record the fact that a
space on the board has been clicked and respond accordingly. The method from
BGFOneSpaceGUIStrategy is shown below.
protected boolean HandleSpaceSelection()
{
BGFPiece newPiece = ((BGFOnePiecePlayer)_player).GetNewPiece();
BGFNewPieceMove move =
new BGFNewPieceMove(this, newPiece, _selectedSpace);
TryMove(move);
return true; // indicating that a move has been tried
}
The HandleSpaceSelection () method is similar (but a bit more involved) for the
BGFTwoSpaceGUIStrategy class shown below.
protected boolean HandleSpaceSelection()
{
if (_firstSpace == null)
{
// See if this space has a piece owned by this player
BGFPiece p = _selectedSpace.GetPiece();
if ((p != null) && p.IsMoveableBy(GetPlayer()))
{
_firstSpace = _selectedSpace;
_movingPiece = p;
}
return false; //no move tried yet
45


}
else
{
BGFFactory factory = BGFFactory.Instance();
BGFMove move =
factory.CreateMovePieceMove(this,
GetPlayer(),
_movingPiece,
_f irstSpace,
_selectedSpace);
_movingPiece = null;
_firstSpace = null;
TryMove(move);
return true; // a move has been tried
}
}
Note that the return value from this method simply indicates whether or not a move has been
created and submitted via TryMove (); the return value has no reflection on whether or not
the move was successful.
4.5.3 Extending BGFPlayer
The BGFPlayer class is used to represent the players in a game. Instances of BGFPlayer
(or its subclasses) are created at initialization and persist throughout the game. This class
only needs to be extended if a new BGFStrategy class is created which requires some
specific operation to be performed by the player, otherwise the BGFPlayer and
BGFOnePiecePlayer classes (neither of which is abstract) may be used directly.
BGFOnePiecePlayer is an example of a class which is needed to satisfy a particular
BGFStrategy subclass the BGFOneSpaceStrategy class. This strategy class requires
a BGFPiece object associated with a particular player to be created each time a move is
made. This strategy/player combination is used in games like Tic-Tac-Toe and Connect-4, in
which each move consists of creating a new piece whose type (X/O, Black/Red) is specific to
the player making the move.
If no new strategy/player combination is needed, the BGFPlayer and
BGFOnePiecePlayer classes should be used directly.
4.5.4 Extending BGFMove
Instances of BGFMove subclasses are used to represent and record each move made in a
game. Each BGFMove object must contain enough data to make a move and to later be able
to undo that move if it is taken back. These two actions are performed within the abstract
methods HookExecute () and HookUndo (). Like the other classes discussed in this
section, BGFMove has concrete, reusable subclasses already defined in the BGF. These
include:
46


BGFMovePieceMove
BGFNewPieceMove
The BGFMovePieceMove class is used in games in which a move consists of a given player
moving a piece from one space on the board to another and undoing the move consists of
moving the piece back to the original space. This class implements the HookExecute ()
method as follows:
public boolean HookExecute()
{
if (_piece.IsMoveableBy(_player) == false)
return false;
if (_fromSpace.GetPiece() != _piece)
return false;
if (_piece.IsMoveableTo(_toSpace) == false)
return false;
return MakeMove();
}
Notice that the last line provides another hook, allowing subclasses with the same basic move
rules (a player moves a piece from one space to another), but additional game-specific details,
to extend this class rather than having to extend BGFMove directly. The default
MakeMove () method is fairly simple.
protected boolean MakeMove()
{
if (_toSpace.PlacePiece(_piece) == false)
return false;
_fromSpace.ClearSpace();
return true;
}
Games in which a piece might be captured, for example, would need to override this method
to save the captured piece for use in Undo ().
Note that if BGFMovePieceMove is extended to override MakeMove () and
HookUndo (), the CreateMovePieceMove () method on the BGFFactory class
should also be overridden in MyGameFactory to instantiate the new subclass. It is through
this factory method that new moves of this type are created by BGFTwoSpaceStrategy
objects.
The other subclass of BGFMove provided by the BGF is the BGFNewPieceMove class.
This class is used in games in which each move consists of the placement of a new piece onto
an unoccupied space on the board. It provides the following implementations of
HookExecute() and HookUndo().
public boolean HookExecute()
{
return _space.PlacePiece(_piece);
)
47


public boolean HookUndo()
{
return _space.RemovePieceForUndo();
}
Instances of this class are created directly by BGFStrategy subclasses, without the use of
the BGFFactory. This is done because there is no need to extend BGFNewPieceMove.
Note that completely new subclasses of BGFMove must be accompanied by new
BGFStrategy subclasses which create these moves. Therefore, the use of
BGFNewPieceMove and BGFMovePieceMove is encouraged whenever possible.
4.6 Developers Guide Summary
This concludes the Developers Guide for the Board Game Framework. Developers
interested in creating applications using the BGF should simply follow' the steps described in
this cookbook. As an additional resource, each BGF class is fully commented usingjavas
documentation comment mechanism, allowing a complete online class reference manual in
html format to be generated.
48


5. Conclusion
An unfinalized object has never had itsfinalizer automatically
invoked; a finalized object has had its finalizer automatically
invoked. A finalizable object has never had its finalizer
automatically invoked, but the Java Virtual Machine may
eventually automatically invoke its finalizer.
§12.6.1, The Java Language Specification
Johnson [Joh92] describes the three key areas of framework documentation as (1) the purpose
of the framework, (2) an explanation of how to use the framework, and (3) the detailed design
of the framework. In this thesis, a framework for the toy domain of board game
applications is presented which satisfies Johnsons three basic requirements. By presenting
both a detailed pattern-based analysis of the framework and a step-by-step cookbook for
application creation, the framework can be understood by users of various skill and interest
levels.
The goal of this thesis, however, was not merely to show an example ofjohnsons
documentation techniques, but was instead to present a reusable framework created in a
relatively new programming language built on the solid foundations of numerous well-known
design patterns. Additionally, implications of the Java programming language on many of
these patterns has been examined and a newjava-specific design pattern (or idiom) has been
presented. The framework presented here should serve as a means for better understanding
the design patterns described.
The Java programming language has successfully taken the next step in object-oriented
programming languages, incorporating many of the strongest features of languages such as
C++ and Smalltalk, while eliminating many of the most significant problem areas. Despite
its infancy, Java is a mature language with strong support for advanced software techniques
such as multithreading and exception-handling. As it grows (release 1.1 is expected in late
1996), Java will continue to advance as the language of choice for a wide variety of software
development tasks.
49


Appendix A: Notation
Since early 1995, Grady Booch, James Rumbaugh and, more recently, Ivar Jacobsen, have
been working together to create a new Unified Modeling Language [BJR96], [BJR096],
[BR95]. This modeling language (UML) is scheduled to be submitted to the Object
Modeling Group (OMG) for standardization in early 1997. The UML clearly has the inside
track on becoming the industry standard for modeling software systems.
The UML describes several types of diagrams, of which the Class Diagram and Sequence Diagram
are used throughout the description of the BGF. This section gives a limited overview of
these two types of models to assist in the understanding of the diagrams used throughout this
thesis. These are not complete descriptions of the UML diagrams, but are instead limited to
those modeling elements used in this thesis.
Class Diagram
The class diagram shows a collection of classes and the relationships between them. Each
class is shown as a rectangle, optionally divided into three compartments. If the three
compartments are shown, they contain, from top to bottom, the name of the class (generally
in Bold; Boldltalics for abstract classes), the attributes (or fields, in Java) of the class, and
the operations (methods). Operations shown in italics are abstract. If the attributes and
operations are not critical to the understanding of the diagram, they are omitted, leaving a
single box containing the class name.
Relations between classes are shown by drawing lines between the related classes. An arrow
on one end of a line indicates that the relationship is only navigable in one direction. The
multiplicity of instances allowed for a given relation is shown using numbers toward the ends
of the lines. Relations with no specific upper bound are shown with an asterisk (*), to indicate
zero or more. Aggregation relationships are shown by placing a small diamond at the end
of the relation line closest to the aggregating class.
Inheritance is shown by drawing a line with a large, open arrowhead pointing from the
subclass to the base class. Interfaces are shown by drawing a small open circle with the name
of the interface written above it. The implementation of an interface is shown by drawing a
line (no arrowhead) from the implementing class to the circle representing the interface.
The UML defines the concept of stereotypes, a general catchall to allow additional information
about certain classes or relations to be specified. Stereotypes are shown by bracketing the
name of the stereotype in guillemets ( ). In the BGF diagrams, the stereotypes used are
singleton, creates, executes, and interface. Note that interfaces are shown using the
50


small circle described above (rather than the interface notation) when the operations do
not need to be displayed.
The grouping of classes which form a package (all classes in the BGF are in a common
package) may be shown by drawing a large, tabbed box around the set of classes and placing
the package name on the tab on the upper-left corner of the box.
Finally, additional comments may be added to the diagrams using notes small rectangles
drawn with a turned-down corner.
Figure A. 1 shows each of the symbols described above.
PackageName
AbstractClass
a zr
ConcreteClass
ClassWithAttrsAndOps
attribute
operation
abstractOperation 0
Interface
o
Interfacelmplementor
Car ()-
1
Person
singleton"
SingletonClass
must complete11*
in <= 2 sec.
Tire
ClassX
.1..*
ClassY
X has access to one or
more Y's, but the Y's are
unaware of the Xs
Figure A. 1
Sequence Diagram
Sequence diagrams are used to show the interactions between objects within a given scenario
(that is, they do not show all possible event flows, only a single example). The UML has
adopted the notation for sequence diagrams described in [BMRSS96],
Each object in the scenario is shown as a rectangle with the name of the instance followed by
the name of the class. These names are colon-separated and underlined. The objects are
laid out horizontally across the page with vertical lines extending below each rectangle.
Horizontal lines are drawn between objects to show method calls and returns. Method calls
are shown by darkened, triangular arrowheads, while returns are shown with non-filled
arrows. Objects passed or returned via method calls are attached to these lines. Time flows
from the top of the diagram to the bottom.
51


Object creation is shown by drawing a line from the creator to the top of a new instance
rectangle, rather than to the vertical line below the rectangle. Object destruction is shown by
placing a large X at the end of the objects line. Since the BGF diagrams in this thesis are
showing the flow ofjava programs (which have no explicit delete operations), this X is used
to show that the object is no longer referenced by any other object and is subject to
finalization by the garbage collector.
Activity of objects is shown by placing a narrow rectangular box on the objects vertical line.
Nested calls on the same object are shown by offsetting additional boxes to the right of the
original box.
In many situations in this thesis, a major purpose of the sequence charts is to show the
distinction between operations implemented within a base class and operations implemented
by a subclass. Objects for which this distinction is important are shown as two separate boxes
(each with its own line). They are always drawn next to each other and, more importantly,
will always have the same instance identifier.
Figure A.2 shows the following sequence of calls on four hypothetical objects:
some outside object calls the Dolt () method on an instance (id=f 1) of class Foo
f 1 has a reference to an instance of class Sub (id=idl), and calls its MethX ()
method
Sub is a subclass of Base, and MethX () is actually implemented in class Base, so
the line showing this method call goes to the Base object
this method does nothing of interest (for this diagram), so the return of control is
shown on the same line as the call
f 1 (still in its Dolt () method) next calls MethY() passing itself as a parameter
idl calls method HookMeth () which is implemented by the subclass Sub
the HookMeth () method creates a new instance (id=newOb j ) of class Bar
the new instance is returned to MethY which returns it to Dolt () on f 1
f ls Dolt () calls a method on itself called SelfMethO
SelfMeth () calls method MethZ (which does nothing of interest to us) on
newObj
SelfMeth() returns
DoIt() returns to the original caller
the caller drops its reference to f 1, allowing it to be made available for garbage
collection
52


newObi:Bar
fe.
Figure A. 2
53


Appendix B: BGF Source Code
This section contains the complete Java source code for the Board Game Framework. The
classes are listed alphabetically.
BGFApplet
/*
* BGFApp1e t.j ava
*
* Board Game Framework
* Dave Wood
* 1996
V
package EDU.cudenver.BGF;
import java.applet.Applet;
import java.awt.*;
/**
* The starting point for Board Game Framework applets. BGF applets must
* inherit from this class. The abstract class does much of the basic
* setup for the applet including the configuration of the BGFFactory
* and BGFBoard singleton classes. In order to make this setup work,
* subclasses of BGFApplet must implement the GetFactoryClassName and
* GetBoardClassName methods.
*
* Uauthor Dave Wood
*/
public abstract class BGFApplet
extends Applet
implements Runnable
{
j *
* Called by the start!) method to setup the game. This
* method configures the BGFFactory and BGFBoard Singleton classes
* and creates the BGFBoard, BGFBoardView and BGFPlayer[] objects.
* Next, it sends the new BGFPlayer objects to the BGFGameMaster
* Singleton object and passes a BGFNewGameCommand on to the
* BGFCommandProcessor as though the "New Game" button had been pressed.
* Usee BGFFactory
* Usee BGFBoard
* Usee BGFBoardView
* Usee BGFPlayer
* Usee BGFGameMas ter
Usee BGFCommandProcessor
Usee BGFCommand
* Usee BGFNewGameCommand
*/
protected void Setup!)
{
System.out.println("BGF Applet initializing");
BGFPlayer.ClearPlayers();
String factoryName = GetFactoryClassName!);
54


try
{
BGFFactory.Configure(Class.forName(factoryName));
}
catch (ClassNotFoundException e)
{
System.out.println!Factory Class not found exception.");
stop();
}
String boardName = GetBoardClassName();
try
{
BGFBoard.Configure(Class.forName(boardName));
}
catch (ClassNotFoundException e)
{
System.out.println("Board Class not found exception.");
stop();
}
BGFBoard board = BGFBoard.Instance();
BGFFactory factory = BGFFactory.Instance();
BGFBoardView boardView = factory.CreateBoardView(board);
setLayout(new BorderLayout());
Panel buttonPanel = new Panel();
AddButtons(buttonPanel);
add("North, buttonPanel) ,-
Panel boardPanel = new Panel();
boardPanel.add(boardView);
add("Center", boardPanel);
BGFPlayerH players = factory.CreatePlayers();
BGFStrategy[] strategies = factory.CreatePrototypeStrategies();
Component frame = this;
while (((frame instanceof Frame))
frame = frame.getParent();
_whoPlaysDialog = new BGFWhoPlaysDialog(
(Frame)frame,
players,
strategies);
BGFGameMaster master = BGFGameMaster.InstanceO;
master.SetPlayers(players);
/**
* Called by the applet context just after the applet is made active.
* This method checks to see if the private Thread data object has been
* created, creating it if necessary, and the calls start!) on the
* thread (which will cause the run() method on BGFApplet to be called).
* It first calls the Setup!) method to set up the game.
*
* @see BGFApplet.run
* @see java.lang.Thread
* @see java.lang.Runnable
*/
public void start()
55


{
System.out.println("BGF Applet has been started");
if (_thread == null)
{
Setup();
_thread = new Thread(this, Main BGF Thread");
_thread.setPriority
(Thread.currentThread().getThreadGroup().getMaxPriority ());
_thread.start();
)
/**
* Called by the applet context just after the applet is made inactive.
* This method stops the thread in which the applet is running and sets
* the private Thread reference to null.
*
* @see java.lang.Thread
*/
public void stop()
{
System.out.printlnf"BGF Applet has been stopped");
// First, abort the game
BGFGameMaster gm = BGFGameMaster.Instance();
while (gm.GamelnProgress())
gm.AbortGame();
// Now, kill the thread
if (_thread != null)
{
_thread.stop();
_thread = null;
}
)
j *
* This method is executed when a Runnable object is executed by a
* thread. It retrieves the BGFGameMaster Singleton object and calls
* the PlayO method on the object. When PlayO returns (indicating
* that the game is over), the WaitForNewGame() method is called. This
method simply waits until a new game is requested. run() stays in
* a tight loop, calling PlayO and WaitForNewGame() until the thread is
* stopped.
*
* @see BGFGameMaster
*/
public void run()
{
System.out.println("BGF Applet has been run");
// pretend they just hit "new game"
HandleButton(new Button(kNewGameButtonText)) ;
BGFGameMaster master = BGFGameMaster.Instance();
// Wait until the master is ready...
while (!master.ReadyForPlay())
{
Thread.currentThread().yield();
try
{
Thread.currentThread!).sleep(100);
}
catch (InterruptedException e) {}
)
56


while(true)
{
master.Play();
Runtime.getRuntime().gc(); // clean up garbage
master.WaitForNewGame();
}
j h *
* Called when an action event occurs. This method is used to handle
* button clicks on the simple BGF user interface.
*
* Applications using the BGF are encouraged to override this method
* to provide enhanced GUI capabilities.
* @param pEvent
*
* @param pArg
An object that depends on the component that
generated the event
The non-null Event
* @see java.awt.Event
* @see BGFApplet#HandleButton
*/
public boolean action
(
Event pEvent,
Object pArg
)
{
if (pEvent.target instanceof Button)
HandleButton((Button)pEvent.target);
else
return false;
return true;
/**
* This method creates and submits BGFCommand objects for two simple
* button-press events. These events are "New Game and "Take Back".
* If either of these events occurs, the appropraite BGFCommand object
* is created and sent to the BGFCommandProcessor. Otherwise, the
* method does nothing.
*
* Applications using the BGF are encouraged to overried this method
* to handle additional buttons appearing on the GUI.
* Sparam pButton
The button which has been pressed
* @see BGFAppletfaction
* @see BGFCommand
* @see BGFNewGameCommand
* @see BGFTakeBackCommand
* @see BGFWhoPlaysCommand
* @see BGFCommandProcessor
* @see j ava.awt.Bu t ton
protected void HandleButton(Button pButton)
{
BGFCommand command = null;
if (kNewGameButtonText.equals(pButton.getLabel()) == true)
{
command = new BGFWhoPlaysCommand(_whoPlaysDialog);
}
else if (kTakeBackButtonText.equals(pButton.getLabel()) ==
{
command = new BGFTakeBackCommand(1);
}
else if (kTakeBack2ButtonText.equals(pButton.getLabel()) =
true)
true)
57


{
command = new BGFTakeBackCommand(2) ,-
}
else if (kQuitButtonText.equals(pButton.getLabel()) == true)
{
System.exit(1); // applications only
}
if (command != null)
{
BGFCommandProcessor cp = BGFCommandProcessor.Instance 0;
cp.SubmitCommand(command);
}
/**
* Add buttons to the GUI panel. This method adds the two standard BGF
* buttons to the GUI.
*
* Applications using the BGF are encouraged to override this method
* to include additional Buttons.
*
* @param pPanel the Panel object to which the Buttons are to be added
*
* @see java.awt.Panel
* @see java.awt.Button
V
protected void AddButtons(Panel pPanel)
{
pPanel.add(new Button(kNewGameButtonText));
pPanel.add(new Button(kTakeBackButtonText));
pPanel.add(new Button(kTakeBack2ButtonText));
)
J *
* Obtain the full class name for the BGFFactory class being used by
* this application. This method must be defined by the application
to return the full class name of the BGFFactory subclass used
* to create various BGF objects. As an example, the Tic-Tac-Toe
* sample applet TTTApplet simply returns the string
* "EDU.cudenver.BGF.TTT.TTTFactory". This string is used to configure
* the BGFFactory Singleton class so that it can create an instance
* of the appropriate concrete class using the Class.newlnstance()
* method.
*
* @see java.lang.Class#newlnstance
*/
abstract protected String GetFactoryClassName();
/**
* Obtain the full class name for the BGFBoard class being used by
* this application. This method must be defined by the application
* to return the full class name of the BGFBoard subclass used
* to create various BGF objects. As an example, the Tic-Tac-Toe
* sample applet TTTApplet simply returns the string
* EDU.cudenver.BGF.TTT.TTTBoard". This string is used to configure
* the BGFBoard Singleton class so that it can create an instance
* of the appropriate concrete class using the Class.newlnstance()
* method.
*
* @see java.lang.Class#newlnstance
* /
abstract protected String GetBoardClassName();
j *
* Paint the screen without first clearing it.
*
* @param pGraphics The Graphics object to paint upon
58


*/
public void update(Graphics pGraphics)
{
paint(pGraphics);
)
/*
* Run this applet as an application. This method creats a frame and
attached an instance of the specified BGFApplet class to it.
*
* @param pArgs pAggs[0] must contain the fully-qualified
name of the BGFApplet subclass to be used.
*/
public static void maintString pArgs[))
(
if (pArgs.length != 1)
{
System.out.println("You must specifiy a single applet class name")
System, exit (1) ;
>
Frame f = new Frame("BGF");
BGFApplet applet = null;
try
{
Class appletClass = Class. forName (pArgs [0]) ,-
applet = (BGFApplet)appletClass.newlnstance();
}
catch (ClassNotFoundException e)
{
System.out.println(Sorry, invalid class name. Be sure to" +
" give the fully qualified name");
System.out.println("EXCEPTION: + e);
System.exit(1);
}
catch (InstantiationException e)
{
System.out.println("Sorry, could not instantiate your class.");
System.out .println ("EXCEPTION: + e)
System.exit(1) ;
)
catch (IllegalAccessException e)
{
System.out.println!"Sorry, unable to access constructor of" +
" the specified class");
System.out.println("EXCEPTION: + e);
System.exit(1);
}
f.add("Center", applet);
f.resize(500,500);
applet. init () ,-
applet.add("South", new Button(kQuitButtonText));
applet.start();
f.show();
j *
* Tell the applet that the players have been set.
/
public synchronized void PlayersSet()
{
_playersSet = true;
notifyAll();
}
// Thread in which the applet will run
59


private Thread _thread = null;
// Dialog box for player/strategy selection
private BGFWhoPlaysDialog _whoPlaysDialog;
// Have the players been set?
private boolean _playersSet = false;
// Strings to hold button names
protected static final String kNewGameButtonText = "New Game";
protected static final String kTakeBackButtonText = "Take Back";
protected static final String kTakeBack2ButtonText = "Take Back 2"
protected static final String kQuitButtonText = "Quit";
BGFBoard
/*
* BGFBoard.java
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF;
import java.util.Observable;
I *
* The "model" representation of the game board. This class represents
* a generic board game playing area, consisting of a two-dimensional
* array of spaces. This is a Singleton (127) class (only one
* instance of a single subclass may exist.) Note that the Configure!)
* method must be called to set the Class to be instantiated before Instance))
* may be called (this is handled by the BGFApplet class).
*
* Oauthor }
catch (InstantiationException e)
(
System.out.printIn("BGF Application Error. Invalid board.");
}
}
61


return _instance;
}
/**
* Indicate that a game which was over is no longer over (the last move
* has been taken back). This method simply notifies the observers of
* the board of the current game-over status. See the
* Observer (293) design pattern for more details.
*/
public void GameOverUndone()
{
setChanged();
notifyObservers(new BGFGameOverStatus(false, null));
J *
* Check the state of the board to see if the game is currently over.
* The actual check is done by a hook method called GameOverHook()
* (see the Template Method (325) pattern). If the game
* is over, the observers are notifed (see the Observer (293)
* pattern.
* @return The current game-over status of the game
*
* @see BGFBoard.GameOverHook
*/
public BGFGameOverStatus GameOverO
{
BGFGameOverStatus s = GameOverHook();
if (s.IsGameOver() == true)
{
setChanged();
notifyObservers(s);
)
return s;
/**
* Return the current game-over status of the board. This method
* must be implemented by applications using the BGF to do the
* actual evaluation of the game board and determine whether or
* not the game is over.
*
* Sreturn the current game-over status of the board
*
* @see BGFBoardtGameOver
*/
protected abstract BGFGameOverStatus GameOverHook();
/**
* Create the BGFSpace objects to fill the board. This method
* fills the 2-dimensional array of BGFSpace objects by creating
* a concrete BGFSpace instance (using the BGFFactory) for each
* row/column on the board
*
* @see BGFFactory
* @see BGFSpace
*/
protected void CreateSpaces()
{
int i, j ;
BGFFactory factory = BGFFactory.Instance();
for (i=0;i<_rows;i++)
{
for (j=0;j<_cols;j++)
{
_spaces[i][j] = factory.CreateSpace(i,j);
62


I
}
}
}
/**
* Set up the board for a new game. This method calls ClearSpaces() to
* empty the board. It then calls NewGameHook() to do any specific
* board setup required by the game.
*
* see BGFBoard#ClearSpaces
* see BGFBoard#NewGameHook
*/
public void NewGame()
{
ClearSpaces();
NewGameHook(BGFPlayer.GetPlayers());
)
/**
* Returns the number of rows on the board.
*/
public int GetNumRows()
{
return _rows;
}
I *
* Returns the number of columns on the board.
*/
public int GetNumColumns()
{
return _cols;
}
/**
* Return the BGFSpace at the specified coordinates.
*
* param pRow The requested row
* param pCol The requested column
*
* return The space at the requested coordinates
*/
public BGFSpace GetSpace
(
int pRow,
int pCol
)
{
return _spaces[pRow][pCol] ;
)
/**
* Return a new Enumeration for iterating over the spaces on the board.
*
* return A new BGFBoardEnumeration object used to iterate over the
* spaces on the board
*/
public BGFBoardEnumeration GetBoardEnumeration()
{
return new BGFBoardEnumeration(this);
}
/**
* Perform application-specific new-game board setup. The default
* implementation does nothing. Note that this is not an abstract
* method, since the default behavior will be appropriate for
* games in which the board is initially blank. Clearing all spaces
63


* need not be done in this method as it is done within the template
* method, NewGame(). See the Template Method (325) pattern
* for more details.
*
@see BGFBoard#NewGame
*
* @param pPlayers The players involved in the game
*/
protected void NewGameHook(BGFPlayer[] pPlayers)
{
}
/**
* Clear the board. This method calls ClearSpace on each space on the
* board.
*
* @see BGFSpace
V
protected void ClearSpaces()
{
int i,j;
for (i=0;i<_rows;i++)
{
for (j=0;j<_cols;j++)
{
_spaces[i][j].ClearSpace();
}
}
}
// keep track of the number of rows and columns for easy access
protected int _rows;
protected int _cols;
// all of the spaces on the board
protected BGFSpace[][] _spaces;
// ensure the instance is created by Instance()
private static boolean _createlnstance = false;
// the singleton instance
static BGFBoard _instance;
// the Class set by Configured and used by Instanced
static Class _class;
BGFBoardEnumeration
/* *
* BGFBoardEnumeration.java
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF;
import java.util.Enumeration;
import java.util.NoSuchElementException;
/**
* An iterator for accessing all spaces on a board. See the
64


* Iterator (257) pattern for more information.
*
* author
Dave Wood
*/
public class BGFBoardEnumeration
implements Enumeration
{
/**
* Create an iterator over the specified BGFBoard. Initialize members
* and determine if there are any elements.
* param pBoard
'/
The board over which the enumeration will
occur
public BGFBoardEnumeration(BGFBoard pBoard)
{
_board = pBoard;
_curRow = 0;
_curCol = 0;
_rows = _board.GetNumRows();
_cols = _board.GetNumColumns();
if ((_rows == 0) || (_cols == 0))
_moreElements = false;
else
_moreElements = true;
}
/
* Determines whether there are any more elements in the enumeration.
*
* return true if there are more elements in the enumeration; false
* otherwise
*/
public boolean hasMoreElements()
{
return _moreElements;
}
/**
* Retrieves the next element in the enumeration. This iterator first
* traverses all columns for the current row, the moves to the next
* row, starting with the first column.
*
* return the next BGFSpace object in this enumeration
*/
public Object nextElement()
{
if (_moreElements == false)
throw new NoSuchElementException();
BGFSpace current
_curCol++;
if (_curCol == _cols)
{
_curCol = 0;
_curRow++;
if (_curRow == _rows)
_moreElements = false;
_board.GetSpace(_curRow, _curCol);
return current;
}
// private members to track the current state of the enumeration
private int _curRow;
private int _curCol;
private boolean _moreElements;
65


// reference to the board being enumerated and its size
private BGFBoard _board;
private int _rows;
private int _cols;
BGFBoardView
/*
* BGFBoardView.java
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF;
import java.awt.*;
import java.util.Observer;
import java.util.Observable;
import java.util.NoSuchElementException;
/**
* The abstraction for the "view" representation of game board. Contains
* a reference to each BGFSpaceView object.
* author * creates BGFSpaceView objects for each BGFSpace contained by the input
* BGFBoard object. In addition, it registers itself with the BGFBoard
* and with each BGFSpace using the Observer interface (see the
* Observer (293) design pattern). This will allow this object
* to be notified any time the state of the board has been changed.
* param pBoard
The model" board this "view" will observe.
* @see BGFBoard
* see BGFSpaceView
* @see BGFFactory
*/
public BGFBoardView
(
BGFBoard pBoard,
int pWidth,
int pHeight
.board = pBoard;
.board.addObserver(this) ;
.rows = _board.GetNumRows();
.cols = _board.GetNumColumns () ;
.spaces = new BGFSpaceView[_rows] [_cols] ;
width = pWidth;
66


_height = pHeight;
BGFFactory factory = BGFFactory.Instance();
int curRow = 0;
int curCol = 0;
//
// iterate over the BGFSpace objects, creating a BGFSpaceView object
II for each one.
//
try
{
BGFBoardEnumeration enum = _board.GetBoardEnumeration();
while (enum.hasMoreElements() == true)
{
BGFSpace space = (BGFSpace)enum.nextElement0;
space.addObserver(this);
_spaces[curRow][curCol] = factory.CreateSpaceView(this, space)
curCol++;
if (curCol == _cols)
{
curCol = 0;
curRow++;
}
}
)
catch (NoSuchElementException e)
{
System.out.println("Major internal problem. Exception: + e);
System.exit(1) ;
}
}
/**
* Return the preferred size for this canvas. The preferred size is the
* size specified by the call to the constructor.
*/
public Dimension preferredSize()
{
return new Dimension(_width, _height);
}
/**
* Return the minimum size for this canvas. The minimum size is the
* size specified by the call to the constructor.
*/
public Dimension minimumSize()
{
return new Dimension(_width, _height);
}
/**
* Handle notification of state change from the model. The BGFBoard
* looks for BGFGameOverStatus objects as input to the updated method.
* If such an object is passed, the ShowGameOver() method is called
* to show the current game-over status of the game.
* @see BGFGameOverStatus
* @see BGFBoardView#ShowGameOver
*/
public void update
(
Observable pObserverable,
Object pObject
)
67


{
if (pObject instanceof BGFGameOverStatus)
{
BGFGameOverStatus over = (BGFGameOverStatus)pObject;
ShowGameOver(over);
}
/**
* Called in response to repaint() method call. This method overrides
* the default updated behavior by not clearing the board for redraw.
* This eliminates much of the flicker associated with repainting the
* board.
*
* @param pGraphics The Graphics object to be painted
V
public void update(Graphics pGraphics)
{
paint (pGraphics) ;
)
/**
* Handle the mouseDown event. When the mouse is clicked on the board,
* call CheckClickO to pass the click to the appropraite BGFSpaceView
* object.
*
* @see BGFBoardView#CheckClick
*/
public boolean mouseDown
(
Event pEvent,
int pX,
int pY
)
{
if (CheckClick(pX,pY) == true)
return true;
else
return false;
)
/**
* Determine which, if any, space on the board has been clicked. This
* method iterates over the spaces of the board, asking each space if the
* coordinate of the click" which was received falls in the spaces's
* area. If so, the BGFSpace object represented by the clicked
* BGFSpaceView is passed to ther BGFGameMaster object using the
* SpaceSelected() method.
Sparam pX Selected X coordinate
Sparam PY Selected Y coordinate
@see BGFSpaceView
@see BGFSpace
@see BGFGameMaster
*/
protected boolean CheckClick
(
int pX,
int pY
)
{
int curRow = 0;
int curCol = 0;
for (curRow = 0; curRow < _rows; curRow++)
{
for (curCol = 0; curCol < _rows; curCol++)
68


{
if (_spaces[curRow][curCol].PointlnSpace(pX, pY)
== true)
{
BGFCommandProcessor cp = BGFCoiranandProcessor.Instance();
BGFCominand command = new BGFSpaceSelectedCommand(
_spaces [curRow] [curCol] .GetSpaceO ) ;
cp.SubmitCommand(command);
return true;
}
)
}
return false;
)
/**
* Paint the board and the spaces on the board. This method first draws
* the empty board to the screen and then draws the space which has
* requested a repaint if there is one. If not, all spaces are drawn.
* When painting has completed, notifyAHO is called to wake up the
* waiting repaint!) method.
*
* @param pGraphics The Graphics object onto which the board
* will be drawn.
*
* @see BGFBoardView#Draw
* @See BGFSpaceView
*/
public void paint(Graphics pGraphics)
{
// If a space-specific paint was asked for, but more is needed, paint
// the whole board,
if (_repaintSpace != null)
{
if (_repaintSpace.GetRect().equals(pGraphics.getClipRect())==false)
_repaintSpace = null;
)
Image image = createlmage(_width, _height);
Graphics imageGraphics = image.getGraphics();
Draw(imageGraphics);
if (_repaintSpace == null) // draw all the spaces
{
for (int row=0;row<_rows;row++)
for (int col=0;col<_cols;col++)
_spaces[row][col].Draw(imageGraphics);
}
else // just draw the space which asked to be drawn
{
_repaintSpace. Draw (imageGraphics) ,-
_repaintSpace = null;
)
_painted = true;
pGraphics.drawlmage(image, 0, 0, null);
synchroni z ed(thi s)
{
notifyAll();
)
}
j h h
* Draw the board on the input Graphics context. Subclasses of
* BGFBoardView must implement this method to draw the game board
69


* on the screen.
*
* Oparam pGraphics The Graphics onto which the board is to be
* drawn.
*/
public void Draw(Graphics pGraphics)
{
)
/**
* Visually show the game-over status for the current game. This method
* calls ShowGameOver() on each of the spaces and then repaints the
* screen.
*
* @param pGameOver The game-over status of the current game.
*
* @see BGFSpaceView
*/
protected void ShowGameOver(BGFGameOverStatus pGameOver)
{
for (int i=0;i<_spaces.length;i++)
{
for (int j=0;j<_spaces[i].length;j++)
{
if (_spaces[i][j].ShowGameOver(pGameOver) == true)
RepaintSpace(_spaces[i][j]);
)
}
/**
* Makes a request to repaint the component and waits for the paint
* to occur. This version of repaint() calls the default repaint()
* method and waits for paint() send notification that the painting
* has completed. This method also ensures that calls to repaint() not
* made by RepaintSpace() don't get missed by the fact that _repaintSpace
* has been set. If two conflicting calls occur at the same time, the
* call from RepaintSpace() (which will be restricted to a single space)
* is dropped so that the whole board will be redrawn.
@param pMS Max updi
@param pX The
@param pY The
@param pWidth The
@param pHeight The
@see BGFBoardView#paint
y-coord of the rect to repaint
width of the rect to repaint
public void repaint
long pMS,
int pX,
int PY,
int pWidth,
int pHeight
{
_painted = false;
super.repaint(pMS, pX, pY,pWidth, pHeight);
II wait for the paint to finish
synchronized(this)
{
try
{
70


while (!_painted)
wait!); // wait for paint to complete
_painted = false;
}
catch (InterruptedException e) {} // interrupt is okay
}
}
/**
* Request that a specific space be repainted. This method calls
* repaint() for the rectangle represented by the input space.
*
* Sparam pRepaintSpace The space to be repainted
*/
public synchronized void RepaintSpace(BGFSpaceView pRepaintSpace)
{
_repaintSpace = pRepaintSpace;
Rectangle rect = _repaintSpace.GetRect();
repaint(rect.x,
rect.y,
rect.width,
rect.height);
)
// The board being observed
protected BGFBoard _board;
// The spaces on this board view
protected BGFSpaceView!][] _spaces;
// board size
protected int _rows;
protected int _cols;
// board size (graphically)
protected int _width;
protected int _height;
// used by repaint)) and paint!)
private boolean _painted;
private BGFSpaceView _repaintSpace = null;
71


BGFCoiranand
/* *
* BGFCoiranand. j ava
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF;
J *
* A simple abstraction for representing basic commands (typically used
* for requests from the GUI). See the Command (233) design pattern
* or the Command Processor pattern in the Buschmann et. al. patterns book.
*
* @author
catch (IllegalAccessException e)
{
System.out.println("BGF Application Error. Invalid factory.")
)
catch (InstantiationException e)
{
System.out.println("BGF Aoplication Error. Invalid factory.")
)
)
return _instance;
j *
* Create a new factory. This method should only be called by the
* Instanced method to create a new BGFFactory subclass. If a subclass
* tries to call it directly (via a super() call in a constructor), it
* will throw an exception. The creation of the instance is synchronized
* on the class (which is locked by Instanced) to ensure that a race
* condition will not allow invalid access.
*
* exception BGFInvalidSingletonlnstantiationException Thrown if
* this method is called by any method other than the
* static Instance)) method.
*
* see BGFFactorySInstance
*/
protected BGFFactory() throws BGFInvalidSingletonlnstantiationException
{
// synchronized so that new() cannot be used to create an instance
// immediately after the Instance)) method sets _createlnstance to
// true, but before it calls this constructor
synchronized(getClass())
{
if (BGFFactory,_createlnstance == false)
throw new BGFInvalidSingletonlnstantiationException();
)
76


}
// The Class to be set by a call to Configure))
private static Class _class;
// The singleton instance to be created by Instance))
private static BGFFactory _instance;
// So we only create the instance once
private static boolean _createlnstance;
BGFGUIStrategy
/*
* BGFGUIStrategy.java
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF;
/**
* An abstraction for players who receive input from the GUI when a space
* on the board is selected.
*
* author
Dave Wood
*/
public abstract class BGFGUIStrategy
extends BGFStrategy
{
/**
* Create a GUI Strategy. Sets the name to "Human" to since this is
* a human player.
*/
oublic BGFGUIStrategy))
{
super(kHumanStrategyName);
}
I *
* Create a GUI Strategy with a non-default name.
*
* param pName The name of this strategy
*/
public BGFGUIStrategy(String pName)
{
super(pName);
}
/**
* Accept a selected space from the GUI. Store the input space in
* the object and call notify)) to wake up the MoveHook)) method.
*
* param pSpace The space clicked on the GUI
k
* @see BGFGUIStrategy#MoveHook
*/
public synchronized void AcceptSpaceSelection(BGFSpace pSpace)
{
if (_moveThread != null)
77


{
_gotGUIInput = true;
_selectedSpace = pSpace;
notifyO; // wake up MoveHookO
}
/**
* Create a BGFMove based on GUI input. This method "waits" until
* input is received from the GUI. When input is received, it calls
* HandleSpaceSelection(), an abstract method responsible for handling
* clicks by the user. This is done to allow different BGFGUIStrategies
* to respond to single clicks (simply placing a new piece on the board)
* or to multiple clicks (moving a piece from one space to another). This
* method is synchronized to allow it to call wait() when no GUI input
* is available.
*
* @see BGFGUIStrategytHandleSpaceSelection
* see BGFGUIStrategy#AcceptSpaceSelection
*/
protected synchronized void MoveHookO
{
// Start with no GUI input
_gotGUIInput = false;
while (!_gotGUIInput)
{
//
// wait for GUI input (notify)) called by AcceptSpaceSelection
// or BGFStrategy.AbortMove())
//
try
{
wait();
}
catch (IllegalMonitorStateException e)
{
System.out.println("IllegalMonitorStateException");
Thread.currentThread().dumpStack();
)
catch (InterruptedException e)
{
System.out.println("InterruptedException");
Thread.currentThread().dumpStack();
)
)
_gotGUIInput = false;
if (HandleSpaceSelection() == false) // move not submitted
MoveHook();
/**
* Handle the fact that a space on the GUI has been selected. This
* abstract method allows different classes to respond to different
* numbers and sequences of space selections.
*
* return true if a move has been submitted (via TryMoveO), false if
* not.
*/
abstract protected boolean HandleSpaceSelection0;
// have we received GUI input?
protected boolean _gotGUIInput = false;
// which space was selected?
protected BGFSpace _selectedSpace;
// player name
78


protected static final String kHumanStrategyName = "Human";
}
BGFGameMas ter
/*
* BGFGameMas ter.j ava
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF;
! *
* The controller of the game. The singleton instance (see the
* Singleton (127) design pattern) of this class is responsible
* for obtaining moves from each player in sequence. In addition,
* it is responsible for additional communication with the BGFPlayer objects
* involved in the game. This includes notification of GUI input, as well
* as notification of "take-backs". The issue of taking back moves leads
* to some complicating multi-threading issues between the BGFGameMaster
* and the BGFPlayer objects.
* Sauthor moveThread.setPriority(Thread.NORM_PRIORITY 1);
_moveAborted = false;
moveThread.start();
// wait for the moveThread to terminate. This will happen for
II one of two reasons: (1) the move had successfully been
// made, or (2) the move has been aborted, resulting in a call
// to Thread.stop() on the thread.
_moveCompleted = false;
try
{
while (!_moveCompleted)
wait();
}
catch (InterruptedException e)
{
System.out.printIn("Interrupted Exception!);
Thread.currentThread().dumpStack();
}
//
// The move thread has now stopped.
//
Af terMoveUpdates () ,- II synchronized
)
_gameOver = true ,-
_ready = false;
// note: at this point _currentPlayerIndex represents the player
// who would have played next had the game not just ended
j *
* Interrupt the current play and take back the last move. If there
* is no game in progress, an attempt is made to take back the last move
* of the previous game. If this is successful, notify!) is called to
* wake up the main thread waiting in WaitForNewGame(). If there is
* a game in progress, an attempt is made to abort the current move.
* If this is successful, the last move is taken back. Then, the method
* calls waitO, allowing PlayO to continue and call AfterMoveUpdates().
* This is done to ensure that the PlayO routine is in a stable state
* before another TakeBack0 call can be made. After PlayO calls
* AfterMoveUpdates(), it makes a notifyO call to allow this method
* to exit.
81


* @see BGFGameMaster#Play
* @see BGFGameMaster#AfterMoveUpdates
* @see BGFGameMaster#WaitForNewGame
* @see BGFMoveProcessor
* @see BGFBoard
* @see BGFPlayer
*/
public void TakeBack(int pCount)
{
synchronized (this) // one take-back at a time, please
{
if (_inTakeBack)
return;
_inTakeBack = true;
)
if (_gameOver) // taking back the final move of the game
{
BGFMoveProcessor mp = BGFMoveProcessor.Instance();
if (mp.UndoMove() == true)
(
//
// let the Board know that the game's not over anymore
//
BGFBoard board = BGFBoard.Instance();
board.GameOverUndone();
//
// decrement the player index since the current
// player should be the player who made the winning move
//
DecrementCurrentPlayerIndex() ;
II take back any additional moves requested
for (int i=l;i {
if (mp.UndoMove() == true)
DecrementCurrentPlayerlndex();
else
break;
)
synchronized(this)
{
notifyAHO; // wake up the main thread
}
>
)
else II in the middle of a game...
{
II first, abort the current move
_moveAborted = _players[_currentPlayerIndex).AbortMove();
if (_moveAborted)
{
II make move is still waiting
BGFMoveProcessor mp = BGFMoveProcessor.Instance();
//
// take back moves...
//
_movesTakenBack = 0 ;
for (int i=0;i {
if (mp.UndoMove() == true)
_movesTakenBack++ ;
else
82


break;
}
MoveCompleted() ;
}
}
_inTakeBack = false;
/**
* Abort the current game. If there is a game in progress, this method
* aborts the current move, sets the _gameAborted flag to true (if it
* was able to abort the move) and calls MoveCompleted() which wakes up
* the PlayO method.
*
* @see BGFGameMastertPlay
@see BGFGameMastertMoveCompleted
*/
public synchronized void AbortGameO
{
if (!_gameOver) II taking back the final move of the game
{
// abort the current move
boolean aborted = _players[_currentPlayerIndex).AbortMove();
II check to see if the move was, in fact, aborted (it may have
// either ignored the abort, or finished before the abort
// was sent)
if (aborted)
{
_gameAborted = true;
MoveCompleted();
)
}
}
/**
* Wait for a new game to be requested (or for the last move of the
* previous game to be undone). This method simply calls waitO and
* exits when a notifyO call is made.
*/
public synchronized void WaitForNewGame()
{
try
{
wait () ;
}
catch (InterruptedException e)
{
}
/**
* Accepts a BGFSpace object and passes it on to the current player. Note
* that any space selection is sent to the current player. If the current
* player is not a GUI player, the input should be ignored.
*
* @param pSpace The space which has been clicked
* @see BGFPlayer
*/
public synchronized void SpaceSelected(BGFSpace pSpace)
{
if (_players != null)
_players[_currentPlayerIndex].AcceptSpaceSelection(pSpace);
}
83


/**
* Update the state of BGFGameMaster after a completed or aborted move.
* This method first checks to see if a new game has been requested. If
* so, the _currentPlayerIndex is reset to 0 and nothing further is done.
* Otherwise, a check is made to see if the last move was aborted. If so,
* _currentPlayerIndex is decremented so that the same player will play
* again in the next iteration. Finally, a check is made to see if a
* move has been taken back. If so, _currentPlayerIndex is decremented
* to get back to the player who should make the next move. Note that
* aborting the current move and taking back the previous move result
* in _currentPlayerIndex being decremented twice. This is the desired
* behavior.
*/
private synchronized void AfterMoveUpdates()
{
if (_newGame == true)
{
_newGame = false;
_currentPlayerIndex = 0;
return; // don't do the next two checks...
}
II
II both of the following 'if' statements will evaluate to 'true'
// if a move has been taken back successfully
//
if (_moveAborted)
{
DecrementCurrentPlayerIndex();
}
if (_movesTakenBack > 0)
{
for (int i=0;i<_movesTakenBack;i++)
DecrementCurrentPlayerIndex();
_movesTakenBack = 0;
}
// finally, move on to the next player...
IncrementCurrentPlayerlndex();
* Set the player index to the next player. When the end of the array
* of players is passed, this method sets the current player index
* back to 0.
*/
private void IncrementCurrentPlayerlndex))
{
_currentPlayerIndex++;
if (_currentPlayerIndex == _players.length)
_currentPlayerIndex = 0;
}
/.
* Set the player index to the previous player. When the beginning of the
* array of players is passed, this method sets the current player index
* back to the last player in the array.
*/
private void DecrementCurrentPlayerlndex()
{
_currentPlayerIndex--;
if (_currentPlayerIndex < 0)
_currentPlayerIndex = _players.length-1;
84


* Notify PlayO that a move has been completed. This method sets the
* _moveCompleted variable to true and calls notifyAHO.
*/
public synchronized void MoveCompleted()
{
_moveCompleted = true;
notifyAll();
}
/**
* Find out if there is a game in progress.
*/
public boolean GamelnProgress()
{
return !_gameOver;
}
// set to the number of moves taken back
private int _movesTakenBack = 0;
// set to true when a new game has been requested
private boolean _newGame = false;
// set to true when there is no game currently being player
private boolean _gameOver = true;
//an index into the _players array indicating the player currently moving
private int _currentPlayerIndex = 0;
// array (in order) of players involved in the current game
private BGFPlayer[] _players = null;
// the singleton instance of this class
static private BGFGameMaster ..instance;
//
private boolean _gameAborted = false;
private boolean _moveAborted = false;
private boolean _inTakeBack = false;
private boolean _moveCompleted = false;
private boolean _ready = false;
BGFGameOverStatus
/* *
* BGFGameOverStatus.java
* Board Game Framework
* Dave Wood
* 1996
V
package EDU.cudenver.BGF;
j
* A representation of the 'game-overness' of the current game. This class
* stores a boolean value indicating whether or not the game is over. In
* addition, a reference to the winning player (if any) is stored. While
* this is not an abstract class, applications using the BGF are encouraged
* to subclass BGFGameOverStatus to store additional, pertinent data (e.g.
* the pieces or spaces involved in makeing the game "over").
85


author
Dave Wood
* see BGFPlayer
*/
public class BGFGameOverStatus
{
/**
* Create a new status object. This constructor takes the boolean status
* as well as a reference (possibly null) to the winning player and stores
* them in member variables.
*
* param pGameOver Indicates whether or not the game is over
* param pWinner Indicates the winning player (or null if there
* is no winning player)
*7
public BGFGameOverStatus
(
boolean pGameOver,
BGFPlayer pWinner
)
{
_gameOver = pGameOver;
_winner = pWinner;
)
/**
* Create a status representing a game which is NOT over.
*/
public BGFGameOverStatus()
{
_gameOver = false;
_winner = null;
}
/**
* Return a boolean value indicating whether or not the game is over.
*
* return A boolean value indicating whether or not the game is over
*/
public boolean IsGameOver()
(
return _gameOver;
}
/**
* Return the winner (possibly null) of the game.
*
* return The BGFPlayer representing the winning player (or null if the
* game is not over or if the game ended in a draw)
*/
public BGFPlayer GetWinnerO
{
return _winner;
}
j *
* Set the game-over status.
*
* param pGameOver A boolean value indicating whether
* or not the game is over
*/
public void SetGameOver(boolean pGameOver)
{
_gameOver = pGameOver;
)
/**
86


Set the winner of the game.
*
* @param pWinner The BGFPlayer who has won the game
* (or null if there is no winner)
*/
public void SetWinner(BGFPlayer pWinner)
{
_winner pWinner;
}
// State variables
private boolean _gameOver;
private BGFPlayer _winner;
BGFInvalidSingletonlnstantiationException
/* *
* BGFWhoPlaysDialog.java
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF;
j *
* Exception class thrown when.an application attempts to craete an instance
* of a class intended to be a Singleton without going through the InstaceO
* interface. This only applies to Abstract Singletons, since concrete
* Singleton classes avoid to problem by making their constructors hidden.
*/
public class BGFInvalidSingletonlnstantiationException
extends Exception
{
}
BGFMove
/*
* BGFBoard.j ava
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF;
/**
* Abstraction for a single move in a board game. An instance of a subclass
* of BGFMove is created for each move in the game. The moves are stored
* by the BGFMoveProcessor, allowing moves to be taken back or saved. This
* class corresponds to the Command class in the Command (233) design
* pattern (or, more precisely, to Abstract Command in the Buschmann et. al.
* patterns book.)
*
* @author Dave Wood

* @see BGFMoveController
87


*/
abstract public class BGFMove
{
/**
* Create a new move. The input BGFMoveController represents the object
* which will be notified if the move is invalid.
*
* param pMoveCon The BGFMoveController to be notified if an
* illegal move or an illegal take-back is
* attempted.
*/
public BGFMove(BGFMoveController pMoveCon)
{
_moveCon = pMoveCon,-
>
/**
* Execute the move. This method calls the abstract HookExecute() method
* and then notifies the BGFMoveController if HookExecute() returns
* false.
*
* return true if the move executes successfully, false otherwise

* see BGFMovettHookExecute
* see BGFMoveController
*/
final boolean Execute!)
{
boolean valid = HookExecute();
if (valid == false)
_moveCon.NotifyInvalidMove(this);
return valid;
)
/**
* Undo the move. This method calls the abstract HookUndoO method and
* then notifies the BGFMoveController if HookUndoO returns false.
*
* return true if the move is undone successfully, false otherwise
*
* @see BGFMove#HookUndo
* @see BGFMoveController
*/
final boolean Undo()
{
boolean valid = HookUndoO;
if (valid == false)
_moveCon.NotifylnvalidUndo(this);
return valid;
)
j *
' Execute the move. This is an abstract method to do the work of
* executing the move. Subclasses of BGFMove must implement this method
* to return true if the move executes successfully and false if not.
*
* return true if the move executes successfully, false otherwise
*
* see BGFNewPieceMove#HookExecute
V
public abstract boolean HookExecute!);
/**
* Undo the move. This is an abstract method to do the work of
* undoing the move. Subclasses of BGFMove must implement this method
* to return true if the move is undone successfully and false if not.
88


* @return true if the move is undone successfully, false otherwise
*
* @see BGFNewPieceMove#HookUndo
V
public abstract boolean HookUndo();
// The BGFMoveController to be notified if Execute/Undo fail
protected BGFMoveController _moveCon;
BGFMoveController
/* *
* BGFMoveController.java
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF;
I *
* An abstraction for objects which create commands. More specifically,
* classes implementing the BGFMoveController interface must provide
* methods which handle invalid move execution or undo. In the BGF,
* BGFPlayer classes implement the BGFMoveController interface. Classes
* responsible for loading saved games would also need to implement this
* interface.
*
* @author Dave Wood
*7
public interface BGFMoveController
{
/**
* Handle notification that the given move was invalid.
*
* @param pMove The BGFMove which failed to execute
*/
void NotifylnvalidMove(BGFMove pMove);
/**
* Handle notification that the given move was unable to be undone.
*
* @param pMove The BGFMove which failed to be undo
*/
void NotifylnvalidUndo(BGFMove pMove);
BGFMovePieceMove
/*
* BGFMovePieceMove.java
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF;
89


/**
* A move involving the placement of a piece onto the board for the first
* time. This class can be used in games such as Tic-Tac-Toe or Othello
* in which pieces are not moved, but are instead simply placed on
* the board.
* @author Dave Wood
*/
public class BGFMovePieceMove
extends BGFMove
{
/**
* Create a new BGFMovePieceMove. Inputs includes the piece being placed
* on the board, the space onto which the piece is to be placed, and
* the BGFMoveController creating the move.
* Sparam pMoveCon
* Sparam pPiece
* Sparam pSpace
*/
The BGFMoveController to be passed on to the
BGFMove constructor
The BGFPiece bring added to the board
The BGFSpace the upon which the piece is to
be placed
public BGFMovePieceMove
(
BGFMoveContr o Her
BGFPlayer
BGFPiece
BGFSpace
BGFSpace
)
{
pMoveCon,
pPlayer,
pPiece,
pFromSpace,
pToSpace
super(pMoveCon);
_player = pPlayer;
_piece = pPiece;
_fromSpace = pFromSpace;
_toSpace = pToSpace;
}
/**
* Execute the move by placing the piece on the space.
*
* ireturn true if the attempt to place the piece on the space was
* successful; false if not.
*
* Ssee BGFSpace#PlacePiece
*/
public boolean HookExecute()
{
if (_piece.IsMoveableBy(_player) == false)
return false;
if (_fromSpace.GetPiece() != _piece)
return false;
if (_piece.IsMoveableTo(_toSpace) == false)
return false;
return MakeMove () ,-
}
/**
* Move the pieces. By default, this method removes the place from
* the old space and places it on the new space. This may be overridden
* of other things must happen
*
* Sreturn true if move is completed successfully, else if not
*/
90


false)
protected boolean MakeMove()
{
if (_toSpace.PlacePiece(_piece) ==
return false;
_fromSpace.ClearSpace(),-
return true;
)
/**
* Undo the move by removing the piece from the space. This method
* may be overridden by subclasses needing to perform alternate actions.
*
* Oreturn true if the attempt to remove the piece from the space was
* successful; false if not.
*
* @see BGFSpace#RemovePieceForUndo
*7
public boolean HookUndo()
{
if (_toSpace.RemovePieceForUndo() == false)
return false;
_fromSpace.PlacePiece(_piece);
return true; // needs work
)
// The space and piece involved in the move
protected BGFPiece _piece;
protected BGFSpace _fromSpace;
protected BGFSpace _toSpace;
protected BGFPlayer _player;
BGFMoveProcessor
* BGFMoveProcessor.java
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF,-
import java.util.Stack;
/**
* A class which activates BGFMove objects and maintains a list of
* moves for undo or history purposes. This class corresponds to the
* Invoker in the Command (237) design pattern (or, more directly,
* to the Command Processor class in the Buschmann et. al. patterns book).
* Also see the Singleton (127) design pattern.
*
* Sauthor Dave Wood
*/
public class BGFMoveProcessor
{
/**
* Return the singleton instance of this class. If this is the first
* call to Instanced, the instance is created before it is returned.
* Note that the constructor for this class in non-public, so this
* is the only way to obtain a BGFMoveProcessor instance.
91


* return The single instance of this class
*/
public static BGFMoveProcessor Instance!)
{
if (_instance == null)
{
_instance = new BGFMoveProcessor();
}
return .instance;
j *
* Initialize the BGFMoveProcessor object. A new Stack is created to
* hold moves. This method is protected. The only way for a user to
* create obtain an instance of this class is by calling the static
* Instance!) method.
* see BGFMoveProcessor#Instance
* see java.util.Stack
*/
protected BGFMoveProcessor!)
{
.moves = new Stack!);
}
/*
* Submit a BGFMove object for execution. Execute the input move and
* push it on the stack only if it executes legally.
*
* param pMove The move to be executed and stored
*
* see BGFMove
V
public void SubmitMove(BGFMove pMove)
{
boolean valid = pMove.Execute();
if (valid == true)
.moves.push(pMove);
}
/**
* Attempt to undo the last move. If there are moves on the stack,
* attempt to undo the move on the top of the stack. If the undo
* fails, or if there are no moves on the stack, return false,
* otherwise, return true and pop the move off the stack.
*
* return true if a move was undone, false if there was no move to
* undo or if the undo attempt failed
*
* see BGFMove
*/
public boolean UndoMove()
{
if (.moves.size() > 0)
{
BGFMove toUndo = (BGFMove).moves.peek();
boolean valid = toUndo.Undo();
if (valid == true)
{
.moves.pop();
return true;
}
else
return false;
}
else
return false;
92


}
/**
* Clear the stack to begin a new game.
*/
public void NewGameO
{
_moves. removeAHElements () ;
}
// singleton instance
private static BGFMoveProcessor _instance;
II moves which have been made
private Stack _moves;
BGFNewGameCommand
/* *
* BGFNewGameCommand.j ava
* Board Game Framework
* Dave Wood
* 1996
*/
package EDU.cudenver.BGF;
j *
* Represents a request for a new game to begin. When executed, this command
* notifies the BGFGameMaster that a new game is to be started.
*
* Sauthor Dave Wood
*/
public class BGFNewGameCommand
extends BGFCommand
{
/**
* Execute the new game command. Obtain a reference to the singleton
* instance of BGFGameMaster and call NewGameO.
*
* @see BGFGameMaster
*/
public void ExecuteHook()
{
BGFGameMaster gm = BGFGameMaster.Instance();
gm.NewGame();
}
BGFNewPieceMove
/*
* BGFNewPieceMove.j ava
* Board Game Framework
* Dave Wood
* 1996
*/
93


package EDU.cudenver.BGF;
I *
* A move involving the placement of a piece onto the board for the first
* time. This class can be used in games such as Tic-Tac-Toe or Othello
* in which pieces are not moved, but are instead simply placed on
* the board.
* author Dave Wood
*/
public class BGFNewPieceMove
extends BGFMove
{
/**
* Create a new BGFNewPieceMove. Inputs includes the piece being placed
* on the board, the space onto which the piece is to be placed, and
* the BGFMoveController creating the move.
* param pMoveCon
* param pPiece
* param pSpace
*/
public BGFNewPieceMove
(
BGFMoveController
BGFPiece
BGFSpace
)
{
super(pMoveCon);
_piece = pPiece;
_space = pSpace;
}
The BGFMoveController to be passed on to the
BGFMove constructor
The BGFPiece bring added to the board
The BGFSpace the upon which the piece is to
be placed
pMoveCon,
pPiece,
pSpace
/**
* Execute the move by placing the piece on the space.
*
* return true if the attempt to place the piece on the space was
* successful; false if not.
* see BGFSpace#PlacePiece
V
public boolean HookExecute()
{
return _space.PlacePiece(_piece);
}
/**
* Undo the move by removing the piece from the space.
*
* return true if the attempt to remove the piece from the space was
* successful; false if not.
*
* see BGFSpace#RemovePieceForUndo
*/
public boolean HookUndo()
{
return _space.RemovePieceForUndo();
}
// The space and piece involved in the move
protected BGFPiece _piece;
protected BGFSpace _space;
94


BGFOnePiecePlayer
/*
* BGFOnePiecePlayer.java
* Board Game Framework
* Dave Wood
* 1996
V
package EDU.cudenver.BGF;
/**
* A player class for players with a single type of piece which may be
* played on the board.
*
* Sauthor Dave Wood
*/
public class BGFOnePiecePlayer
extends BGFPlayer
{
/**
* Create a player.
* ^exception ClassNotFoundException Thrown if the class name given
* for the BGFPiece class to create cannot be found.
*
* Oparam pName The name of this player
* @param pPieceClassName The full class name of a BGFPiece class
* to be placed on the board each move
*/
public BGFOnePiecePlayer
<
String pName,
String pPieceClassName
)
throws ClassNotFoundException
{
super (pName)
_pieceClass = Class.forName(pPieceClassName);
}
I *
* Create a new BGFPiece object. Based on the class sepcified in the
* constructor, this method will create a new instance of BGFPiece or one
* of its subclasses.
*/
public BGFPiece GetNewPiece()
{
BGFPiece newPiece = null;
try
{
newPiece = (BGFPiece)_pieceClass.newlnstance();
)
catch (IllegalAccessException e)
{
System.out.println("BGF Application Error. Invalid piece.");
Thread.currentThread().dumpStack();
}
catch (InstantiationException e)
{
System.out.println("BGF Application Error. Invalid piece.");
Thread.currentThread().dumpStack();
}
95


Full Text

PAGE 1

BGF : A FRAMEWORK FOR BOARD GAME APPLETS by David R. Wood B.S. University of Colorado at Boulder 1993 A thesis submitted to the University of Colorado at Denver in partial fulfillment of the requirements for the degree of Master of Science Computer Science 1996 gg

PAGE 2

This thesi s for the Master of Science degree by David R. Wood has been approved by Tom Altman Miloje Radenkovic

PAGE 3

Wood, David R. (M.S. Computer Science ) BGF: A Framework for Board Game Applets Thesis directed by P rofessor Boris Stilman ABSTRACT An object-oriented framework is a reusable design consisting of a set of abstract classes and reusable concrete components which simplifies the creation of applications sharing common characteristics. The Board Game Framework (BGF) is an object-oriented framework for the development of strategic board games using thejava programming language. The framework provides abstractions for common concepts such as board, space, piece, player, strategy, and move. In addition to providing these basic abstractions, the framework encodes knowledge about how the objects in the system interact, establishing the overall flow of any application built with the framework. This thesis describes the BGF in detail, beginning with a brief overview of each class in the framework. Next, a detailed design pattern-based analysis of the interactions between the classes is given, including discussion of how the java programming language affects the u e of certain patterns. Within this section, a new Java-specific design pattern (Abstract Singleton) is presented. Finally, a "cookbook" for creating applications using the framework is presented. This section gives detailed instructions for the development ofBGF applications, drawing extensively from two compl ete sample applications built usin g the framework. The framework is shown diagramatically using the Unified Modeling Language (UML) This abstract accurately represents the content of the candidate's thesis. I recommend its publication. Signed lll

PAGE 4

CONTE TTS Chapter 1 Introdu ct ion ..................... ..... ..................... 1 1.1 2. 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2 .8 2.9 2.10 2.11 2.1 2 2.1 3 2.14 2 .15 2.1 6 2.17 2.18 2.1 9 2.20 2 .21 2.22 2.23 2.24 2.25 2.26 2.27 2.28 2.29 2.30 2.31 3. 3. 1 3.2 3.3 Conventions Framework O verview ........................ ................. Class BGFApplet .... .............. .............. .......... Class BGFBoard . . .... ......... .................. ...... Class BGFBoardEnum eratio n .. ......... ...................... Class BG FB oardView ...... .................. .............. 2 3 3 3 3 3 Class BGFSpace ........................................... 4 Class BGFSpaceView ........................................ 4 Class BGFPi ece ................. . ...... ... ............... 4 Class BGFPi eceView ............... .... . . ................ 4 Class BGFPl ayer ........................................... 4 Class BGFOnePiece Pl ayer . . . . . . . . . . . . . . . . . . 4 Class BGFStrategy . . . . . . . . . . . . . . . . . . . . . 4 Class BGFGU IStr a t egy . . . . . . . . . . . . . . . . . . . 5 Class BGFOneSpaceG Strategy . . . . . . . . . . . . . . . 5 Class BGFTwoSpaceGUI Strategy . . . . . . . . . . . . . . . 5 Class BG FMove . . . . . . . . . . . . . . . . . . . . . . 5 Class BGFNew Pi eceMove .................................... 5 Class BGFMovePieceMove . . . . . . . . . . . . . . . . . . 5 Class BGFMoveProcesso r .............. ....................... 5 Interface BGFMoveCont r oller . . . . . . . . . . . . . . . . 5 Clas s BGFGameMaster ...................................... 6 Class BGFCommand ......................... .... ......... 6 Class BGFNewGameCommand .......... .................... Class BGFSp aceSelected Command ..... ........................ Class BGFTake B ac kCommand ................................ Class BGFWho PlaysCommand ................................ Class BGFCommandProcessor ................................ Class BGFFactory ........................... ........... ... Class BGFGa m eOve rStatu s ....... ........ ................... 6 6 6 6 6 6 7 Class BGFWinningSpacesGameOverS tatus . . . . . . . . . . . . 7 Class BGFWhoPlay sDialog . .................................. 7 Class BGFinvalidSi ngletonlnstantiationEx cept ion . . . . . . . . . 7 D esign Patterns . . . . . . . . . . . . . . . . . . . . . . . 8 Model-View-Controller . . . . . . . . . . . . . . . . . . . 9 Observer . . . . . . . . . . . . . . . . . . . . . . . . 1 0 Singleton . . . . . . . . . . . . . . . . . . . . . . . . 11 IV

PAGE 5

3.3.1 Abstract Singleton . . . . . . . . . . . . . . . . . . . 12 3.4 Template Method . . . . . . . . . . . . . . . . . . . . 16 3.4. 1 Pre e's M e t a patterns . . . . . . . . . . . . . . . . . . . 18 3.5 Abstract Fa ctory . . . . . . . . . . . . . . . . . . . . . 18 3.6 Factory Method . . . . . . . . . . . . . . . . . . . . . 20 3. 7 Strategy . . . . . . . . . . . . . . . . . . . . . . . . 20 3.8 Command . . . . . . . . . . . . . . . . . . . . . . . 22 3.9 It erato r . . . . . . . . . . . . . . . . . . . . . . . . 25 3.10 Prototype . . . . . . . . . . . . . . . . . . . . . . . 26 3.11 Chain ofResponsibility . . . . . . . . . . . . . . . . . . . 27 4. D eveloper's Guide . . . . . . . . . . . . . . . . . . . . . 29 4.1 The Exampl e Games . . . . . . . . . . . . . . . . . . . 29 4.2 First Steps . . . . . . . . . . . . . . . . . . . . . . . 30 4.3 Seeing the Game . . . . . . . . . . . . . . . . . . . . . 34 4.4 Additional Required Cl asses ............ .............. .... : . 39 4 5 Optional Classes . . . . . . . . . . . . . . . . . . . . . 43 4.5.1 Extendin g BGFCommand . . . . . . . . . . . . . . . . 43 4.5.2 Ext e nding BGFStrategy . . . . . . . . . . . . . . . . . 44 4.5.3 Extending BGFP!ayer . . . . . . . . . . . . . . . . . . 46 4.5.4 Extending BGFMove . . . . . . . . . . . . . . . . . . 46 4.6 D eveloper's Guide Summary . . . . . . . . . . . . . . . . 48 5. Conclusion . . . . . . . . . . . . . . . . . . . . . . . . 49 Appendix A. Notation . . . . . . . . . . . . . . . . . . . . . . . . . 50 B. BGF Source Cod e . . . . . . . . . . . . . . . . . . . . . 54 R efere n ces . . . . . . . . . . . . . . . . . . . . . . . . . . I 19 v

PAGE 6

1. Introduction Joshua: Shall we play a game? David: Lnve to. How about Global Thermonuclear War? Joshua: Wouldn't you prefer a good game of chess? WarGames, MGM/UA Entertainment Co., 1983. An object-oriented framework is a r e usable design consisting of a set of abstract classes and reusable co n crete components which simplifies the c reation of applications sharing common characteristics This thesis discusses an object-oriented framework called the Board Game Framework (BGF). The purpos e of the framework is to simplif y the process of writing strategic board game programs using the j ava programming language. While the framework focuses on th e "toy" domain of strategic board game applet development the design principles and patterns discussed here are applicable to a very wide range of software engineering domains so th e thesis should be of interest to anyone involved in object-orient e d software engineering. The st rategic board game domain was c hosen because it c ontains generally familiar abstractions ( namely board, space, piece, Pkl:Yer, strategy, and move) which p eo ple can easily understand allowing the reader to focus on th e fram e work design rather than struggl in g with co nfusing domain-spe c ific jargon. The basi c abstractions listed in the previous paragraph form the basis of any game implem e nted using the BGF. Such games must be pla y ed on a board with a two dimensional grid of spaces ( games with non-rectangular boards such as Abalone could also be accommodated by creating additional, unused spaces ) upon which pieces of some type are placed or moved. The pieces belong to particular players ( games may have as few or as many players as necessary ) who employ various strategies to determine which moves should be made. The following is a limited sampling of games which co uld be created with th e BGF: Tic-Tac-Toe, Connect-4, Checkers, Chess, Go, Quixo, Quarto, Terrace, Abalone, Pente, Life, Stratego, Chinese-Checkers. In th e future, the strategy abstraction co uld be used to demonstrate Linguistic Geometry [Stil96] techniques ( used to reduce many complex problems to board game problems ) in a web-based environment. The remainder of this section provides an overview of the rest of the thesis. Section 2 gives a brief overview of the classes found in the framework. These include both abstract framework classes and reusable, concrete components. The purpose of this section is not to fully define each class but rather to simply introduce the classes so they will be familiar in l ater sections

PAGE 7

Section 3 discusses the use of design patterns in the BGF. Eac h pattern used in the BGF is explained usin g text as well as class diagram s and sequence diagrams drawn using th e emerging standard for design mode ling, th e Unified Modeling Language. The section explains how the diff e rent parts of th e system work together in experience-proven ways to create a framework that i s both easy to extend and easy t o unde rstand. Section 4 provides detailed instructions for the c reation of complete applications usin g the BGF. Existing sample applications (Tic-Tac-Toe and Quixo) are used to show exactly which classes need to be extended, which m e thods must be implemented, which m e thods may optionally be overridden, and what types of additional subclasses may optionally be added to enhance th e application. The appendices include an overview of the modelin g techniques used and the complete co de l istin g for the framework cla sses 1.1 Conventions The following conventions are used throughout th e thesis: fixe d-width font lik e this indicates program code italics followed by a parenthetical number ( e.g. Command (233) ) reference a design pattern (and page number) from the book Design Patterns: Elements of Reusable Object-Oriented Software [GHJV95] th e following coding conventions are used: class (and int e rface ) names in the BGF begin with the letter s BGF method names begin with capital letter s ( to clearly distinguish fromjava-provided methods which always start with lowerc as e letters ) field names begin with an underscore (_rows) method parameters begin with a lower-c ase p (pGraphics) co nstants (static final fields ) start with a lowercase k (kWidth) 2

PAGE 8

2. Framework Overview abstraction n. 1. (a) any model that includes the most important, essential, or distinguishing aspects if something while suppressing or ignoring less important, immaterial, or diversionary details. (b) the result if removing distinctions so as to emphasi;::e commonalties. Booch, Firesmith, Henderson-Sellers, Martin, Odell, Dictionary if Object Technology The BGF is best understood by looking at the various design patterns used in its construction. This will be done in detail in the next section. The purpose of the present section is to provide a brief overview of the classes which make up the framework in order to give the reader sufficient background for the section on patterns. 2.1 Class BGFApplet The BGFApplet abstract class is a subclass of java. applet. Applet which provides basic setup functionality for BGF applications running as applets. It also provides a main () function, allowing the applet to be run as an application ( without a web browser ) 2. 2 Class BGFBoard The BGFBoard abstract class represents the concept of a game board. It is made up of some number of space s (BGFSpace) arranged in a two-dimensional array. BGFBoard subclasses are responsible for the detection of the end of a gam e ( they must know, for example, how to recognize checkmate in chess ) 2.3 Class BGFBoardEnumeration The BGFBoardEnumeration class implements the java. util. Enumeration interface, providing sequential access to the spaces on the board. 2.4 Class BGFBoardView The BGFBoardView class is a subclass of java. awt. Canvas which represents the GUI view of th e BGFBoard. It handles the drawing of the board as well as input from the GUI such as mouse-clicks on the board. This class also implements a tec hnique called double-buffering which allows board updates to be displayed without visible flicker. 3

PAGE 9

2.5 Class BGFSpace The BGFSpace class represents a single space on a game board. A BGFSpace may hav e a relation to a BGFPiece located on the space. 2.6 Class BGFSpaceView The BGFSpaceView class provides a graphical representation of a BGFSpace on the display. 2. 7 Class BGFPiece The BGFPiece class represents any piece belonging to a particular player in a game. 2.8 Class BGFPieceView The BGFPieceView abstract class provides the GUI represe ntation of a BGFPiece. Subclasses ofBGFPieceView must know how to draw th e specific piece onto a specified board location. 2.9 Class BGFPlayer The BGFPlayer class represents the most basic co ncept of a player in any game. The BGFStrategy class ( see section 2.11) i s actually responsible for determining how to make a move. This class simply represent s the participants in the game, such as Black and VV!zite in chess or X and 0 in TicTac-Toe. 2.10 Class BGFOnePiecePlayer The BGFOnePiecePlayer is a subclass ofBGFPlayer used with players for which a move involves the pla cement of a single type of pi ece ( unique to th e player ) on a given spac e on the board. This class is responsibl e for th e c reation of new pi eces when requested by th e BGFOneSpaceGUIStrategy class. 2.11 Class BGFStrategy The BGFStra tegy abstract class provides an overall flow of control for the process of generating a new move. Strategies for move generatio n might include accepting GUI input generatin g a move based on a search algorithm, r etrieving a move from a network connection, etc. R egardless of the d e tails BGFStrategy provides the overall flow. 4

PAGE 10

2.12 Class BGFGUIStrategy The BGFGUIStrategy abstract class is a subclass ofBGFStrategy which provides much of the functionality for allowing human players to generate moves. 2.13 Class BGFOneSpaceGUIStrategy The BGFOneSpaceGUIStrategy class is a subclass ofBGFGUIStrategy which can be used for games in which a move is made by selecting a single space onto which a new piece is to be placed. 2.14 Class BGFTwoSpaceGUIStrategy The BGFTwoSpaceGUIStrategy class is a subclass ofBGFGUIStrategy which can be used by games in which a move is made by selecting a space containing a piece, then selecting a second space to which the piece on the first space is to be moved. 2.15 Class BGFMove The BGFMove abstract class represents any single move in a game. Moves are instantiated as objects, allowing them to be stored (and l ater undone ) and executed. 2.16 Class BGFNewPieceMove The BGFNewPieceMove class is a subclass ofBGFMove representing simple moves involving the creation of a new piece (BGFPi ece) to be placed on a single space (BGFSpace) Games such as TicTac-Toe, Connect-4, and Othello can use this class directly. 2.17 Class BGFMovePieceMove The BGFMovePieceMove class is a subclass ofBGFMove representing moves involving the movement of a single piece from one space on the board to another. 2.18 Class BGFMoveProcessor The BGFMoveProcessor class provides a mechanism for the submission of moves throughout the course of a game. It also provides interfaces for taking back ( undoing ) moves and for clearing out all previous moves ( new game ) 2.19 Interface BGFMoveController The BGFMoveController interface specifies methods for handling notification of illegal moves and illegal "take-backs." 5

PAGE 11

2 20 Class BGFGameMaster The BGFGameMaster class handles the basi c flow of th e game It is responsible for requ est in g moves from eac h pl aye r in the game in seque n ce, alerting players that it is n o lon ge r th eir move (pe rhaps b eca us e the previo us m ove has b een taken bac k ) r ese ttin g th e mode l when a new game is reque s t ed, etc. Application builders using the BGF n ee d n o t worry about any of these issues as everyt hin g is handled by thi s co n c r e t e class. 2.21 Class BGFCommand The BGFConunand abstract class represents any basic command ente red from the GUI to be impl e m ented by the application. 2.22 Class BGFNewGameCommand The BGFNewGameConunand class is a subclass of BGFConunand which s impl y n otifies the BGFGameMaster that a ne w ga m e has been requested. 2.23 Class BGFSpaceSelectedCommand The BGFSpaceSelectedConunand clas s is a s ubclass ofBGFConunand whic h n otifies th e BGFGameMas ter that a space on the board h as bee n sel ected. 2.24 Class BGFTakeBackCommand The BGFTakeBackConunand class is a subclass of BGFConunand representing a r eq u est from the GUI to tak e back th e previous m ove o r m oves 2.25 Class BGFWhoPlaysCommand The BGFWhoPlaysConunand class is a subclass ofBGFConunand which brings up the BGFWhoPlaysDialo g window ( described in section 2.30 ) 2 26 Class BGFCommandProcessor The BGFComrnandProcessor class accepts BGFComrnand obje cts and executes the commands 2.27 Class BGFFactory The BGFFac tory a b st ract class provid e s an interfa ce for the c re a tion of application-specific objects (pieces, player stra tegi es, etc. ) without r equiri n g th e c reator ( usuall y an object within the BGF) to know th e actual concre t e type of the object bein g c reat ed. 6

PAGE 12

2.28 Class BGFGameOverStatus The BGFGameOverStatus class is basically just a grouping of two attributes: a boolean value indicating whether of not the game is over, and a reference to a BGFPlayer representing the player ( if any ) who has won the game. 2.29 Class BGFWinningSpacesGameOverStatus The BGFWinningSpacesGameOverStatus class is a subclass of BGFGameOverStatus which adds the ability to store the spaces on the board involved in the final, winning position. This simplifies the process of visually showing the pieces making up the winning position. 2.30 Class BGFWhoPlaysDialog The BGFWhoPlaysDialog class is a subclass of java. awt. Dialog which allows the user to select a strategy for each player in the game before starting a new game : 2.31 Class BGFinvalidSingletoninstantiationException The BGFinvalidSingletoninstantiationException class is a subclass of java. lang. Exception which is used to indicate an attempt to create an instance of a singleton class via means other than the static Instance () method. 7

PAGE 13

3. Design Patterns Certain rare people seem to be able to tap into some magic vein in which flow incredib[y catchy patterns, deep[y intoxicating to the human spirit. Douglas R. Hofstadter, Metamagical Themas: Questing for the Essence of Mind and Pattern The use of design patterns is critical to the development of a comprehensible, reusable software framework. A design pattern is an element of reusable architecture that has been shown to solve a common problem. The use of patterns in software design is commonly linked back to the work of architect Christopher Alexander and his book A Pattern Language [AIS77]. Perhaps more than anything Alexander s work suggested that fundamental ideas which had been used by experts and shown to work could be documented in a clear consistent format to be reused by others. In software engineering, this format typically consists a pattern name, a problem a solution, and consequences of applying the pattern. In Design Patterns: Elements of Reusable Object-Oriented Software [GHJV95] Gamma et. a!. provide a catalog of 23 such patterns, ten of which are discussed in this section Since the publishing of Design Patterns, several other works have been published on the subject of design patterns. The works ofPree [Pree95], Coad [CNM96] Vlissides et. a!. [PLoP95], and Buschmann et a!. [BMRSS96] are also discuss e d in this section. What follows is a description of the patterns which appear in the BGF. It is this section whi c h should most help the reader to understand the relationships between the classes ( described in the previous section ) whi c h make up the framework. Most of the patterns discussed in this section are from the Design Patterns book, though ideas are also incorporated from the other works mentioned above. Additionally, a new Abstract Singleton design pattern is presented using the standard pattern format. The patterns described in this section are shown diagrammatically using the Unified Modeling Language (UML) An overview of the subset of the UML pertinent to the diagrams in this section is presented in Appendix A. In effect, as you build each pattern into the design, you will experience a single gestalt that is gradual[y becoming more and more coherent. Christopher Alexander, A Pattern Language 8

PAGE 14

3.1 Model-View-Controller The ModelVuw-Controller architectural pattern (MVC) divides an interactive application into three components. The model contains the core functionality and data. Vuws display information to the user. Controllers handle input. Vuws and controllers together comprise the user interface. A change-propagation mechanism ensures consistency between the user interface and the model. [BMRSS96) The BG F makes use of MVC to separate the display aspects of the game from the details of the underlying model, allowing displays ( views ) to be modified or replaced without any threat of affecting, for example, the rules of the game. To support the view aspect of MVC, the BGF provides the abstract classes BGFBoardView, BGFSpaceView, and BGFPieceView. Each of these has an underlying model abstraction: BGFBoard, BGFSpace, and BGFPiece, respectively. The controller distinction is less clear, but the key controller responsibilities lie primarily in the BGFBoardView and BGFApplet classes. The class diagram in Figure 3.1 shows the relationships between these classes ( relations between the model classes are left out here to simplify the diagram ) Obse r ver Figure 3.1 The key aspect of this diagram is the navigability direction from the view classes to the model classes. ate that BGFBoard, BGFSpace, and BGFPiece are unaware of the existence of the view objects. When the BGFBoardView class is instantiated, it creates a two dimensional array of BGFSpaceView objects. The bounds of this array are specified by the BGFBoard class ( which knows how many rows and columns the board has ) Each BGFSpaceView contains a Rectangle object which specifies the location and size of the space on the display. When a piece is placed on a space, the BGFSpaceView object creates a new BGFPieceView object and tells it to draw itself within the Rectangle specified by the BGFSpaceView. It maintains a link to the BGFPieceView object so that it can tell it to draw itself at any time in the future. If the piece is later removed from the space, the BGFSpaceView object will 9

PAGE 15

update its BGFPieceView referenc e to null and draw a blank space an y time it is told to draw itself. Notice that the discussion of the view classes to this point h as barely mentioned appl ication specific e xtensions of these classes This is because much of the work of creating the display is done directl y within the BGF classes. In fact, BGFPieceView is the only abstract view class. In the BGFBoardView class the only method which may need to be overridden is the Draw () method, responsible for r endering the specific game board on a given Graphics obje ct. All the other interaction between the BGFBoardView and its BGFSpaceView objects is handled directly by BGFBoardView. This includes creating the spaces, handling mouse clicks (here, BGFBoardView takes on the controller role in MVC), repainting the screen e tc Similarly, subclasses ofBGFSpaceView need only ( optionally ) override the Draw ( ) DrawEmpty ( ) and ShowGameOver ( ) methods to supp l y any application specific display. Finally, the BGFPieceView class contains just two methods wh i ch may need to be overridden: Draw () and ShowGameOver (). The interaction between the model classes and the view classes is handled using the Observer pattern, discussed next. 3.2 Observer The Observer (293) (or Publisher-Subscriber [C M95] ) pattern defines "a oneto-many dependency b e tween objects so that when one object changes state, all its dependents are notified and updated automatically." [GHJV95) The most common use of this pattern is as a wa y to decouple the user interface from th e underly ing model. As was bri efly described in the section on MVC, the BGF uses this pattern for this very purpose. In fact the j ava utility packag e provides everything needed to implement the basic Observer pattern. The class java. util. Observable provides the necessary interfac e methods to act as the subject in th e pattern. These methods provide the ability to add observers and to notify thes e observers when something in the m odel has changed. In the BGF, the BGFBoard and BGFSpace classes are defined as subclasses of Observable. This i s the extent to which t h e model classes know abo ut the view classes in the BGF. Any time a c h a nge is made to the state of the game, the observables simply call setChanged () and noti fyObservers (),methods completely defined in the Observable class. It is then up to Observable to notify any view objects regist e red with the modified object that the state of the model has changed. The BGFBoard class notifies observers when the game i s over ( some special information might be displayed to the screen ) and when a game which was over becomes not-over" as a resu l t of the last mov e (or moves) being taken back. The BGF Space class notifies its observers any time a piece is placed on it or r emoved. The other key participant in the Observer patt ern is the Observer interface. Again ,Java assists b y providing an interface containing a single update () method. This is the method 10

PAGE 16

\ called by instances of the Observable class any time the notifyObservers () method i s called. In the BGF, the BGFBoardView and BGFSpaceView classes implement this interface, accepting update () calls and updating the display accordingly. Figure 3.2 shows a simple notification occurring as a result of a piece being placed on a particular space. Note that the first two vertical lines represent the same instance (spl) ofBGFSpace. The time lines are broken to show that the subscription request made by the BGFSpaceView occurs at some time earlier ( during setup ) in the program. sp1 :BGFSpace P lace Piece pc1 : BGFPiece GetPiece Figure 3.2 3.3 Singleton The Singleton (127 ) pattern provides a mechanism for restricting the number of instances of a given class, and for providing global access to the singleton instance [GHJV95]. This pattern is used throughout the BGF for classes which will only have a single instance throughout the life of the applet. These classes include BGFGameMaster, BGFMoveProcessor, and BGFCormnandProcessor which employ the simplest possible Singleton implementation, as well as BGFFactory and BGFBoard which use an extension of the Singleton pattern which allows the singleton object to be an instance of some unknown subclass. This extension to the Singleton pattern is described by a new pattern (or idiom in [BMRSS96]) presented at the end of this section. The following code segment shows the implementation of the Singleton pattern for the BGFGameMas ter class. public final class BGFGameMaster { private BGFGameMaster() {} static public synchronized BGFGameMaster Instance() 11

PAGE 17

if (_instance == null) instance = new BGFGameMaster(); return _instance; private static BGFGameMaster _instance; The non-publ ic constructor, static Instance ( ) method and single instance variable shown here are the fundamental elements involved in the Singleton pattern. Note that injava, th e Instance () method should be declared with the synchronized modifier to ensure that only one a single instance can possibly be created. This is discussed further in the n ext section. 3.3.1 Abstract Singleton The Singleton pattern described in Design Patterns devotes about a page and a half to a section on subclassing singleton classes. Unfortunately, none of the solutions suggested is wholly satisfactory. The primary difficulty discussed in this section is that the base class must be abl e to create the proper instance of a particular subclass ( without, of course, being hard-coded to know which subclasses exist). Some configu r ation mechanism must exis t to inform th e base class about the various subclasses which might be used in such a way that a particular subclass instance can be returned. In C++, this is quite difficult, requiring an instance of each subclass to be created staticall y and passed into a static Configure () method on the base class along with an identifying string (or other identifier ) Then, an environment va riabl e (or, perhaps a separate configura tion method) specifies which of these instances should be returned by the Instance () method. Using this technique may by very impractical for sing leton hierarchies wh ich cannot reasonably allow the in stantiation of each concrete subclass. The difficulties discussed above can be e liminated by using sev e ral importantjava language features. What follows is a new design pattern called Abstract Singleton which provides a clean solution to the problem of subclassing a singleton. The pattern description below follows the basic format used in the Design Patterns book. 3.3.1.1 Name Abstract Singleton 3.3.1.2 Intent From a collection of subclasses of a common abstract base class, ensure that only a sing l e instance of a single subclass is c r eated, and provide globa l access to this instan ce. 12

PAGE 18

3.3.1.3 Motivation As described in the Singleton pattern, it is important for some classes t o h ave exactly one instance. The Singleton pattern also points out that the Singleton class may be abstract, impl ying that what is really desir ed is a sin g l e in stance of some arbitr ary subclass, not s i mply a single in tance of a known, concrete class Such situat i ons are common in framewor k design in which the framework defines the abstract base class, but leaves the implementation of concrete s ubcl asses to the application developer. 3.3.1.4 Applicability Use the Abstract Singleton patt ern when there must be exactly o n e instance taken from a collection of classes whic h extend a common base class, and this insta n ce must be accessible to clients from a well-known access point. all possible concrete subclasses cannot be enumerated a priori 3.3.1.5 Structure AbstractSingleton static singleton ata static Class singleCiass static Instance() J singleCiass = static Configure() 1Ope ration() f ConcreteSingleton concrete Data Operation() Figure 3.3 3.3.1.6 Participants AbstractSingleton defines a s tatic Instance () operation wh i ch allows clients access to its uniqu e instance. defines a static Configure () operation which allows clients to specify which subclass should be instantiated. 13

PAGE 19

defines a protected constructor which throws an exception if called directl y (rather than by the Instance () method) responsible for creating the u n ique instance. ConcreteSingleton defines a public constructor to be used by the Instance ( ) method of the AbstractSingleton class 3.3.1. 7 Collaborations Clients configure the Abstract Singleton class during initialization, specifying the appropriate co ncrete class (possibly b y accessing an input parameter or reading an input file) Clients access an Abstract Singleton instance solely through the Instance () method. 3.3.1.8 Consequences The Abstract Singleton pattern has several benefits: All those given for the Singleton pattern Creation of a single instance from all possible s u bclasses without requiring the instantiation and registration of each subclass. The impact on the application developer ( any creator of concrete subclasses ) using the Abstract Singleton is mi n imal. Subclass creators are forced (by the compiler ) to comply with th e intent of the pattern thus minimizing possible mistakes. 3.3.1.9 lm.plementation/Sample Code There are severa l key steps in th e implementation of the Abstract Singleton pattern in j ava First, a static Configure () method sho u ld be created to allow the application to specify which concrete class should be created. This method can be defin ed to tak e either a java. lang. Class object, or a java. lang. String object. In e ith e r case, the purpose of Configure () is to store the specified class i n a static m ember variable for use in the Instance () method. Examples ofboth possible implementations are shown below. public static void Configure(String s ) throws ClassNotFoundException { _class = Class.forName(s); or. . public static void Configure(Class c) { _class = c; T h e next important method is the Instance () metho d public static synchronized AbstractSingleton Instance() throws IllegalAccessException, InstantiationException 14

PAGE 20

if (_instance == null) { _createinstance = true; _instance = (AbstractSingleton)_class.newinstance(); _createinstance = false; return _instance; Sinc ejava is a multi-threaded language, it is important that this method b e synchronized. Making a static method synchronized causes the method to block until it obtains the lock on its Class object. This is necessary is to ensure that two threads which simultaneously call Instance ( ) cannot each create a new instance (having found that no instance had previously been created ) violating the basic premise that only one instance will ever exist at a given time. Unfortunately, synchronizing this method is not eno ugh to ensure that only a single instance will be c r eate d. In fact, the above implementation illuminates a newl y created hole which would allow (poss ibly accidental ) instantiation of subclass instances. This hole arises from the requirements ofthe Class .newinstance () method. This method creates a new instance of the specified class by calling the empty argument constructor for that class. In order for this method to work, this co nstructor must be accessible. Injava, this means that the constructor must be declared with d efault \package-level ) prot ect ion, or be declared public. Making the const ructor public creates th e problem that an application, possibly unaware that the Abstract Singleton pattern is b eing us ed, co uld now create an instance of the concrete subclass by simply using new. The implementation of the Abstract Singleton constructor closes this hole. protected AbstractSingleton() throws InvalidSingletoninstantiationException synchronized(this.getClass()) { if (AbstractSingleton._createinstance == false) throw new InvalidSingletoninstantiationException(); The only way this constructor will actually create a new instan ce is if the _crea teins tance member variable has been set to true. Since .this is only done within the Instance () method, we ( almost ) ensure that the only way a new instance can be created is through the use of the Instance () method. However, one last loophol e must be filled in order to avoid the following scenario: Thread A calls Instance (),which sets the _createinstance field to true. Thread B calls new ConcreteSingleton () just before Thread A is able to create the new instance. 15

PAGE 21

Thread B enters the constructor for AbstractSingleton ( called from the constructor for the ConcreteSingleton) sees that _createinstance is true, and returns successfully. Such a race condition would allow an instance ( in theory, many instances ) to be created without going through the Instance ( ) method. It might seem that a logical solution would be to declare the constructor to be synchronized so that it could not run until the Instance () method completed. This, however will not work. Java does not allow constructors to be synchronized since the synchronized modifier causes an object level lock to be obtained, and there is no possibility of another thread accessing an object while the object is still being created Rather than locking the instance being created, synchronization should occur on the same object Instance () is synchronized on: the Class object representing the AbstractSingleton class. This can be done using a synchronized statement rather than the synchronized modifier. As shown above, the body of the constructor is wrapped in a synchronized block, requiring the class-level lock to be obtained before processing can continue. By doing so, the race-condition scenario described above cannot occur. The new ConcreteSingleton () call would either enter before the Instance () call ( in which case the constructor would throw an exception, resulting in no new object being created ) or the new call would enter the constructor after Instance () had set the _createinstance field, but would be forced to block until Instance () returned, by which time _createinstance would have been set back to false, again resulting in an exception being thrown. As a result of the above implementation a single requirement is imposed on the concrete subclasses ofAbstractSingleton. Each such subclass must provide a public parameterless constructor which throws the same exception thrown by th e AbstractSingleton constructor. The following will suffice: public ConcreteSingleton() throws InvalidSingletoninstantiationException {} The addition of this throws clause is enforced at compile-time ( alternately, the constructor could call super ( ) explicitly and catch the exception ) so there is no worry of an application developer forgetting to add it. Furthermore, code which attempts to create an instance of such a subclass using new will fail to compile unless it catches the exception. Finally, code which ( for whatever reason ) chooses to create an instance using the Class. newinstance () method will fail at runtime since the AbstractSingleton constructor will throw the exception as described above. 3.4 Template Method The Template Method (325) pattern "lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure." [GHJV95] This is perhaps the simplest and most common pattern described in Design Patterns. The idea is simply to define a skeleton, or template, algorithm within a base class which calls another method, usually abstract, allowing part of the algorithm to be variable without changing the overall structure of the base class s 16

PAGE 22

algorithm. This simple co ncept is used throughout the BGF and can be identified by the presen ce of the word Hook in the name of the primitive operation called by the template method. Using Template Method simplifies the job of the appli cat ion developer since as much code as possible is written within the template method. This also reduces possible errors which could arise if certain methods were required to perform certain actions in order for the fram ework ( template ) method to work. As a simple example, the GameOver ( ) method on the BGFBoard class is implemented as a template method. If this technique was not used GameOver ( ) would be an abstract method and might be specified in a manner similar to the following. /** Determine if the game is over. NOTE: THIS METHOD MUST CALL setChanged() and notifyObservers() IF THE GAME IS OVER IN ORDER FOR THE GUI TO BE UPDATED!!! *I public abstract BGFGarneOverStatus GarneOver(); By u s ing the Template Method pattern, the requirements of Game Over ( ) are moved out of the m ethod's comments and into the co de. public BGFGarneOverStatus GarneOver() { BGFGarneOverStatus s = GarneOverHook(); if (s.IsGarneOver() true) { setChanged(); notifyObservers(s); return s; With this implementation, the application developer is only responsible for writing a method called GameOverHook () which return s th e status of the game. The template method takes care of the notification process. A sample call sequence for a game which has just completed is shown in Figure 3.4. 17

PAGE 23

GameOver Game Ov erHook gmov : BGFGmO v Stat gmov : Object gm o v : BGFGOS Figure 3.4 This is just one of many examples of the use of the Template M ethod pattern throughout the BGF. Additional examples will be seen during the discussion of the other patterns used by BGF. 3.4.1 Pree's Metapatterns The Template Method pattern is also one of six basic metapattems described by [Pree95 ]. In this, book, Pree defines template methods more generally as "a means of defining abstract behavior or generic flow of control or the relationship between objects." Here, a template method not only calls methods declared in the base class and implemented by co ncrete subclasses, but it may also call any methods on objects it is related to by any of Pree 's six basic metapattern relationships. Thus, almost any non-trivial method becomes a template method. The meta pattern used to describe the scenario discussed in the Template Method pattern is the simp l est of the six, and is given the name Unification to reflect that the template method and the hook method are declared in the same class. The issue of whether the hook method is actually defined in the base class or in a concrete subclass is not considered important in this level of analysis. 3.5 Abstract Factory The intent of the Abstract Factory (87) pattern i s to provide an interface for creating fam i lies of re lated or dependent objects without specifying their concrete classes [GHJV95] I n the BGF, an abstract factory class, BGFFactory, provides interfaces which enable other classes in the framework to create instances of concrete application classes without knowledge of the specific classes being instantiated This is done by declaring abstract methods such as CreateSpace () and CreatePlayers () which subclasses ofBGFFactory must 18

PAGE 24

define to create instances of the appropriate classes. For example, the TtcTac-Toe application has a TTTFactory class which defines the CreateBoardView () method as follows: public BGFBoardView CreateBoardView(BGFBoard pBoard) { return new TTTBoardView(pBoard); With this interface, classes in the BGF are able to create new instances of the class TTTBoardView without knowing such a class exists ( which is, of co urs e, quite desirable since the framework canno t know the names of the co ncret e subclasses which will be created by a given appl ication ) Lik e most abstract factory classes, only one instance ofBGFFactory s hould ever be created. To enforce this, the BGF uses the Abstract Singleton pattern described in the previo u s sect i on. The sequence diagram in Figure 3.5 shows the initialization ofBGFFactory. I app1 : BGFApplet I [ app1 :TTTApplet I I BGFFactory I I TTTFactorY: Ciass .l ,L G etF a cName.. L_j Conf i q ure Instance I ne wlnstan ce ... .... [ fac1 :TTTFactorY I .... I fac1 : TTTFac I I "'I fac1 : TTTFac I Figure 3.5 Figur e 3.6 shows th e simple process of obtaining a new object from the factory. Note that the BGFApplet has access to the TTTFactory ( which it views only as a BGFFactory) VIa the Instance () methodjust shown. 1 9

PAGE 25

Figure 3.6 3.6 Factory Method Prob ably the most cri tical aspect of the Abstract Factory pattern described above is the use of another pattern: Factory Method ( 107 ). This pattern d e fines "an interf ace for creating an object, but Q ets ] subclasses decide which class to in sta ntiat e [GHJV95] The Crea teBoardVi ew ( ) method described above is j ust one of severa l factory m e th ods declared by BGFFactory. The BGFFactory class contai ns the most exact use o f thi s pattern in the BGF, but it is n ot the only class in which the basic conc e pts behind Factory Method are used. The BGFOneSpaceGUIStrategy class is a class used b y games for which a move co n s i sts of the pla ce m ent of a single ( new ) piece on an empty space on th e board. Such games includ e Tic-Tac-Toe, Othello, and Connect-4. In these games, the strategy object defe r s the c re a tion of t h e new piec e t o th e BGFOnePiecePlayer object to which the s tr a t egy is attached. In a pure int erpretat ion of the Factory lvfetlzod patt ern, BGFOnePiecePlayer would be a Creator class r esponsib le for declaring an abstract factory method for the creat i on of a new BGFPiece ob j ec t In this scenario, h oweve r, th e o nl y m e th od subclasses of BGFOnePiecePlayer would have to overrid e would b e thi s factory method. Rather than for ce the a ppli cat ion developer t o create subclasses ofBGFOnePiecePlayer ( for X and 0 in Tic-Tac-Toe for example ) th e type of pie ce to be created i s simply specified as a parame ter to the BGFOnePiecePlayer constructor b y passin g an object of type Class. As described previo usl y, new inst a n ces ca n b e created using th e newins tance () method on a Class object. This e liminates the need for parall e l class hierar chies one for the BGFPiece classes and o n e for th e BGFOnePiecePlayer classes which c r eate th e m 3. 7 Strategy The Strategy (315) design pattern "lets the algorithm vary i ndependently from clients that use it. [GHJV95] In the BGF, this pattern is used to implement player strategies." Each pla yer in the game h as a corresponding strategy which defines ho w th e player selects its next move. Such strategie s might include randomly selecting a move, performing a complex search algorithm, or simply waiting for input from the GUI. B y decoupling the strategy from th e player, th e pl ayers can easily change strategies fro m game to game without having to 20

PAGE 26

replace the actual BGFPlayer objects. The BGF encourages such behavior by fixing the players during the initialization of the applet and providing an interface for the selection of a strategy for each player before the start of each game. It should be noted that BGFPlayer objects correspond to the abstract concepts of "players" for a given game. In chess, for example, the players are Black and W'hite, while the strategies might include Human, NoviceComputer, and MasterComputer. The class diagram in Figure 3. 7 shows the strategy classes provided by the BGF, as well as sample application level classes. BGF BGFMoveController TTTMas t er S tra t egy Figure 3. 7 Note that while BGFStrategy and BGFGUIStrategy are abstract classes, the BGFOneSpaceGUIStrategy and BGFTwoSpaceGUIStrategy classes are concrete and may be used directly. BGFStrategy defines the overall flow of the move-making process. The initial method executed is called Run () This method sets several state variables and then calls Move () The Move () method calls the MoveHook () method repeatedly until a valid move is generated (MoveHook () is free to generate invalid moves and rely on Move () to catch them ) MoveHook ( ) is an abstract method responsible for somehow creating a BGFMove object and passing it to TryMove ( ) for validation. The MoveHook ( ) method may be implemented in numerous ways. As an example, the TTTRandomStrategy () class implements the method by generating a move based on two random numbers ( row and column ) More intelligent strategies might use a complex search algorithm to find the best move. Yet another example of the MoveHook ( ) method is the method used by BGFGUIStrategy. This method simp l y waits for input from the GUI and creates a move based on the selected space or spaces. As mentioned above, the MoveHook ( ) method is expected to call TryMove ( ) in order to submit its move. The MoveHook ( ) method obtains a reference ( see the above discussion of 21

PAGE 27

the Singleton pattern ) to the BGFMoveProcessor instance and submits the move. The details of the processing of moves is discussed later with respect to the Command pattern. For now it is sufficient to know that the submission of th e move to the BGFMoveProcessor will result in th e _validLastMove data fie ld in BGFStrategy being set. The Move () method then checks this flag calling Move ( ) recursively if the flag is set to false and returning normall y otherwise. The r ec ursion co ntinues until MoveHook ( ) generates a va lid move. Figure 3.8 shows the ( non-recursive ) scenario described abov e for a player using th e TTTRandornStra tegy class. Note that the detail s of th e Subrni tMove ()method on the BGFMoveProcessor class are not shown here. See the discus s ion of th e Command (233) pattern for details on the BGFMove ( ) class and its co llaborators. s 1 : TTTRandStra t m :BGFMoveProc mv1 :BGFNewP i ec eMv Figure 3.8 3 8 Conun.and The Command (233) pattern allows requests to be encapsulated as obj e cts, "thereby letting you parameterize clients with different reque sts, queue or log requests and support undoable operations." [GHJV95] Bus chmann, et. al. [BMRSS96] and Sommerlad [PLoP95] describe a slightly more detailed version of this pattern called the Command Processor pattern. Ideas from both patterns are used in the BGF in two parts of the system. The basic strategy behind these patterns is to create a class for each basic command in the system (or some area of the system ) allowing instances of these Command classes to be created and passed to a Command Processor to b e executed. The Command Processor may queue requests store th e m for future undo, etc. Each command is responsible for knowing wh at other objects (suppliers) it needs to intera c t with. In addition, commands may ( depending on the nature of the system ) n ee d to store s tate information to allow the command to b e undone at some later time. 22

PAGE 28

The simplest instantiation of the Command patterns in the BGF involves the handling of basic CUIgenerated commands. Figure 3.9 shows the classes defined in the BGF directly r elated to this pattern. BGFCommand executes > singleton BGFCommandProcessor Execute() SubmitCommand(BGFCommand c" { 1\ I I BGFTakeBackCommand BGFNewGameCommand Execute() Execute() BGFWhoPiaysCommand BGFSpaceSelectedCommand Execute() Execute() Figure 3.9 In this case, the BGF takes advantage of very little that the Command patterns have to offer. Commands are not logged and cannot be undone. However the pattern still provides a clean abstraction for the addition of new commands (applications are free to add new buttons to the display and create new BGFCoi!UT\and subclasses ) In addition, the pattern provides the flexibility to add logging and undo features in the future without requiring major restructuring of the framework. The other area of the framework in which th e Command Processor pattern is used involves the handling of the moves made in the games. Unlike the basic commands described above, moves in a game should be logg ed and shou ld have the ability to be undone. This allows games to be saved ( although this is not a feature of the framework sinc e Java applets are restricted from writing to the l ocal filesystem ) and allows players to take back errant moves while properly restoring the board to its previous state. In order to provide this functionality, the BGFMoveProcessor has a considerably larger interface than the BGFCoi!UTlandProcessor. This interface, as well as those of related types, is shown in Figure 3.10. 23

PAGE 29

BGFMove <> <> submits To BGFMoveController Noti fylnvalidMove(BGFMove m) N otifylnvalidUn d o(BGFMove m) Figure 3.1 0 The int erface to BGFMoveProcessor provides methods t o subm it m oves for exec ution undo the la s t move, and s tart a ne w gam e ( which clears out all o ld moves) BGFMoveProcessor kee p s a s t ack ofBGFMove ob j ects representing val id moves w hi ch have been made in a game ew moves are sent to the BGFMoveProcessor by a call to the Submi tMove () m ethod whi ch immediately calls th e Execute () m etho d on th e input BGFMove obj ect. I f this method r eturns true, th e m ove i s pushed on the stack. I f Execute () r et urn s false, indi cating that th e m ove was in va lid th e mov e i s not stored and Submi tMove ( ) r etu rns immedia t e ly. The Undo ( ) method takes no parameters, relyin g on the int e rn a l stack t o d e termin e which m ove to undo. It first "pee k s" at the top item on th e s ta c k and calls it s Undo ( ) method. Lik e Execute ( ) Undo ( ) returns a boole a n indicating the valid ity of th e undo. Some ga mes may not allow moves to be taken back in certain s ituati ons. This return va lu e allows this fact to be captured in a generic way. Ifthe Undo () method r etu rn s true, the BGFMove ob j ect is poppe d from th e stac k ; if n ot, the stack i s unchan ged The other major parti c ip ant in this use of th e Command Processor pattern i s the BGFMoveController interface. Injava, a collectio n of abstract methods ( as well as constant ( final ) s tati c variab les) m ay be co llect e d int o an interface. C lasses may implement as many interfaces as they wa nt, though th ey may only extend (be a subclass oD one class. A class which implements th e BGFMoveController int erface mus t provide implementations for the two m et hods NotifyinvalidMove () and NotifyinvalidUndo (). Since th ere is no meaningful de fau l t behavior and no addition al m et h o ds to be associated with th e m ove controller, these m e thods are grouped into an interface to allow as much flexibility to th e a ppli cat ion d evelo per as possible. I n th e Command Processor p atte rn the co ntroller class is defined as the class which c reates command obj ec t s and transfe r s these object s to th e command processor. This definition is co nsist ent wit h th e int e nt of the 24

PAGE 30

BGFMoveController interface, though there i s nothing to stop classes which do not implement this interface from creating and submitting BGFCommand objects. In the BGF, the ro le of the controller ( with respect to this instantiation of the Command pattern ) is extended to provide two callback routines for all BGFMove objects. These are th e NotifyinvalidMove () and NotifyinvalidUndo () methods mentioned above. The constructor for BGFMove takes an object which implem ents the BGFMoveController interface as a parameter. When a move is executed or undone illegally, the BGFMove object calls the appropriate notification method to refl ect the failure. For this reason, it makes sense that the object submitting the move also be the BGFMoveController which receives the notification. Note that pulling the notification methods out of the BGFStrategy class ( currently, the only class in the system which implements the BGFMoveController interface ) allows additional classes ( such as a saved game reader ) to be created which also participate in this Command pattern. Figure 3.11 shows the creation and submission of a move by a BGFOneSpaceGUIStrategy object. In this scenario, th e move is rejected (by the PlacePiece () method on BGFSpace) and a notification is sent back to the strategy object. I 51 ls1 :BGFSt r ategv l me1 : BGFMov e Procll se1:BGFSeace I I m1:BGFNewPieceMvl[ m1:BGFMove j Submit Move I m1 : BGF Move I I f;.xecute .... HookExecute Place Piece .. I pc1 :BGFPc 1.-LJ (false) -'(false) ... ... '-Not ify lnval idMov; rn1 : BGFMovq -r-.... I 'v Figure 3.11 3. 9 Iter a tor The lterator (257) pattern provides "a way to access the elements of an aggregate object sequentially without exposing its underlying representation." [GHJV95] The java utility package supports this pattern through the Enumeration interfac e. This is a very simp le interface, providing two methods: hasMoreElements () and nextElement (). Classes implementing this interface provid e easy access to an aggregate object. In the BGF, this 25

PAGE 31

pattern (and the Enumeration interface, specifically ) is used to provide an easy way to iterate over all spaces on the board. In this case, th e board is the Aggregate and the BGFBoardEnumeration class is the lterator. An object wishing to iterate over all spaces on the board may simply call the GetBoardEnumeration () method on the BGFBoard instance to obtain a new BGFBoardEnumeration obj ect. The n, a simple loop like the following can be used: BGFBoardEnumeration enum = board.GetBoardEnumeration(); while (enum.hasMoreElements() == true) { BGFSpace space = (BGFSpace)enum.nextElement(); II do something with space The lterator pattern describes an additional abstract class which provides an interface for the abstract creation of iterators. There was no n ee d for this abstraction in this particular use of the pattern, so the it erator creation method was placed dire ct l y in the BGFBoard class. 3.10 Prototype The Prototype ( 117 ) patt ern creates new instances of ob j ects by cloning an existing "prototyp e" instance. [GHJV95) The BGF does not implement this pattern directly, but it does employ the fundamental concept of using prototype objects to create new instances. The actual implementation of these ideas in the BGF, and the motivation behind it, i s somewhat unusual. Languages which treat classes as first class objects ( such as Smalltalk andjava) have littl e need for the Prototype pattern since Class objects ca n be used with the newlnstance () metho d to create new instances. In the BGF, a combination of this strategy and the Prototype pattern as it i s defined is used for the creation of new BGFStrategy objects. The goal is to pres ent th e user with a list of strategies from which to chose, creat ing th e appropriate instance based on the chosen strategy. It is the presentation issue which shows the limitation of passing Class objects. The dialog box (BGFWhoPlaysDialog) re ce ives an array of strategies to be displa yed and later instantiated. If the input was an array of Class objects the only way the choices co uld be displayed to the user would be to display the name of the class obtained by parsing the output of the Class. toString () method. Clearly, this would not be ideal since it would r equi re the us e of class names which could be directly displayed to the user ( which would among other things, require that names have no embedded spaces ) The next option would be to use the Prototype pattern directl y and implement a clone () method on the strategy objects. This would be a fairly reasonable solution, especially considering that the Object class in java defines a clone () method which can be used simply by specifying that a class implements the Cloneable interface. The problem with this option is that each BGFStrategy object corresponds to a single BGFPlayer object, so the clone () method would hav e to b e overridden to ensure that the player reference in the strategy object being cloned was not replicated ( since this would result in two BGFStrategy obje cts pointing to the same BGFPlayer object). 26

PAGE 32

Instead of either of these approaches, the BGF uses a simple combination. The input to the BGFWhoPlaysDialog constructor is an array of prototype BGFStrategy objects, created solely for this purpose within BGFFactory. The BGFStrategy class has a _name member variable which can be accessed and displayed to the user Once the user selects a strategy, the Class object for the selected BGFStrategy object is obtained ( via the getClass () method defined on Object) and the newinstance () method is called. This allows the default constructor to be used rather than having to add a clone ( ) method to BGFStra tegy. Figure 3.12 shows the flow of control for the creation of a new BGFStrategy instance. I d1: BGFDialog l l s1: TTIRandStrat I randStrat:C i ass I I j;!1 I -L-qetCiass I J lrand:Ciassl newlnstance .. ..-I ...,. .. I s2: TTIRandStrat I l s2 : TTTRan dSt ratj SetStrategy .. i s 2:TTTR andStrat l ..-u Figure 3 .12 3.11 Chain ofResponsibility The Chain of Responsibiliry (223) pattern avoids "coupling of a request to its receiver by giving more than one object a chance to handle the request." [GHJV95] The BGF does not implement this pattern itself, but it does rely on the fact that it is implemented by the AWT. The simple layout of the BGF interface includes a Panel on which several But ton objects are placed. This Panel is itself contained within the BGFApplet ( which is a subclass of Applet, itself a subclass of Panel) The event -h andling mechanism injava passes events up the containment chain until the event is handled. This means that it is not necessary to create subclasses of java. awt. But ton for each button pla ced on the display solely for the purpose of performing a certain action when the button is clicked Thanks to the use of Chain ofResponsibiliry, the event indicating the pressing of a button is passed from the Button to its enclosing Panel and finally to the enclosing BGFApplet object which handles it by overriding the action () method it inherits from the java. awt. Component class. Figure 3 .13 shows the detailed callin g sequence which occurs as the result of a button being pressed, starting with the Event being delivered to the Butt on object. ote that the handleEvent () method takes an Event object as a parameter, and that action () takes both an Event and an Object parameter. These parameters are not shown in the diagram in order to keep it readable. It should also be pointed out that the HandleButton () method on BGFApplet does more than just return true. Ba sed on which button was selected, this method creates the appropriate BGFCornmand object and 27

PAGE 33

sends it to the BGFConunandProcessor. anel1 : Comonen app 1: BGFApplet true) (true) Figure 3.13 28

PAGE 34

4. Developer's Guide I soon can learn how to do it ifyou' lllet m e see it done; I can watch your hands in action, but your tongue too fast may run. And the lecture you deliver mqy be very wise and true, But I'd rather get my lessons by observing what you do. Edgar A. Guest Sermons We See (from Peter Goad's "Object Models: Strategies, Patterns, & Applications") This section provides a detailed "cookbook" for creat in g applications using the BGF. Each method requiring an application-specific im p lementa tion ( as well as those methods which may b e optionally overridden ) is explained, and extensive examples from implemented gam e s are provided. The explanation follows a logical conceptual flow starting with the core model objects and adding details as t hey be c ome necessary. 4.1 The Example Games This section will draw on examp les from two games implemented using the B GF. The simplest of these games is Tu -Tac-Toe The other game, Qyixo, is a bit more complex and presumably less familiar. Qyixo is played on a 5x5 board with 25 cubi c pieces Each cube has four blank sides a n d two sides with unique symbol s ( in the BGF versio n th e other two sides are given unique colors ) Init iall y all cubes are placed s u ch that a blank side shows. Each player in tum, pick s up a c u be showing either a blank side or her own symbol from the perimeter and slides blocks over from any side to fill in the space made b y th e remova l of the piece. The removed piece is then placed in the newly opened perimeter space with th e symbol of the player making the move now showing The goal of th e game is to get five of your pieces in a row ( vertically, horizontally, or diagonally ) before y our opponent. Figur e 4.1 shows a sample m ove b y player X ". 29

PAGE 35

this piece can be moved 0 +--here 0 X X 0 X 0 X X i here i moved here pushed blocks up Figure 4 1 4.2 First Steps The first classes to be deve lop ed are the eas iest to concept ualize since they represent physical, tangible objects. These classes will be MyGameBoard, MyGameSpace and MyGamePiece ( for this pur pose of this sec tion all new classes will be prefixed with "MyGame." The exa mpl es us ed all begin with either TTT (Tic-Tac-Toe) or Quixo ) E ac h co mpilation unit must begi n by imp o rting th e BGF package Either of the following syntax options is acceptab le: import EDU.cudenver.BGF.*; II or ... import EDU.cudenver.BGF.BGFBoard; II different for each class Eac h class declaration begi ns with something like: public class MyGameBoard extends BGFBoard { II ... the good stuff ... For th e r emainder of thi s sec tion the import and class lines will be omitted. The fir st class to exami n e is th e MyGameBoard class, for whi c h a co nstructo r must b e c reat ed which p asses the width and heigh t of th e board on to the s uperclass constr u c t or. This is all the constr u c tor needs to do so the following will s uffi ce: public MyGameBoard() throws BGFinvalidSingletoninstantiationException { super(_width, _height); II dimensions of the board Notice that t hi s co n structor is d efined to throw BGFinvalidSingletoninstantiationException. This is b ec aus e the BGFBoard co nstruct o r also throw s this exce ption This helps to e n sure that instan ces of this class will n ot be created using new or Class. newinstance (),but instead on l y throu gh 30

PAGE 36

the static BGFBoard. Instance ( ) method. The details of this strategy are discussed in section 3.3.1. Next a NewGameHook ( ) method may be needed. This is not an abstract method, so if no setup of the board is required this method may be left out. This is the case for TicTac-Toe, since the board is initially empty. I n Qyixo, the board is initially covered with 25 blocks, so these pieces must be created and placed o n the board. The BGFBoardEnumeration class is used to iterate over the spaces, placing a new piece on each space. Here's the code from QuixoBoard. java. protected void NewGameHook(BGFPlayer[) pPlayers) { try { } II BGFBoardEnumeration enum = GetBoardEnumeration(); while (enum.hasMoreElements() == true) { BGFSpace space = (BGFSpace)enum.nextElement(); space.PlacePiece(new QuixoPiece()); Notice that this method receives the (ordered) list of players involved in the game which may be needed if pieces belonging to specific players need to be created. The only other method needed for MyGameBoard is the GameOverHook ( ) method. This i s typically o n e of the more involved m et h ods in th e application. This method must examine the state of the board and return a BGFGameOverStatus object indicating whether or not the game is over a n d, if so, who the winner (if any ) is. How this is determined is very game specific, and so won't be covered in detail here. The important thing is to understand the interface to the BGFGameOverStatus class. public BGFGameOverStatus(boolean pGameOver,BGFPlayer pWinner) public BGFGameOverStatus() II-> BGFGameOverStatus(false,null) public void SetGameOver(boolean pGameOver) public void SetWinner(BGFPlayer pWinner) These are the public constructors and methods availab l e in BGFGameOverStatus. I f additional information is needed, this class may be extended as necessary. In fact, the B GF includes an extension of this class called BGFWinningPiecesGameOverStatus. This class adds a data member to hold an array ofBGFSpace objects wh i ch were involved in creating a winning position ( such as the 3-in a-row in TicTac-Toe) The complete class declaration is s hown below public class BGFWinningSpacesGameOverStatus extends BGFGameOverStatus public BGFSpace[) GetWinningSpaces() 31

PAGE 37

return _winningSpaces; public void SetWinningSpaces(BGFSpace[) pWinningSpaces) { _winningSpaces = pWinningSpaces; private BGFSpace[) _winningSpaces; Additional subclasses ofBGFGameOverStatus or even BGFWinningSpacesGameOverStatus may be created as needed by the application. There is generally no n ee d to extend the BGFSpace class so the next class to consider is MyGamePiece. Like BGFSpace, BGFPiece is not an abstract class so it may not need to be extended either. However, depending on the game, it may be necessary to override the IsMoveableBy () and IsMoveableTo () methods. In Tzc-Tac-Toe, this wasn't necessary since pieces on the board can't be moved at all ( the BGFMove class used in Tic-TacToe n e ver has any need to cal l these methods ) The default implementation of IsMoveableBy () allows a piece to be moved by the pla ye r who owns the piece. This may be sufficient for some games, but many have additional restri ctio ns. If so ( as in Qjlixo) the method may be overridden. In Qjlixo, a piece is moveable by player A if the piece is blank-side up or if player A's side is showing In addition, the pi ece must be on the perimeter of the board. An additional (protected) method is added to QuixoPiece to help the IsMoveable () method. Here's the code: public boolean IsMoveableBy(BGFPlayer pPlayer) { BGFPlayer p l = GetPlayer(); if ( (pl == null) II (pl == pPlayer)) return IsMoveable(); else return false; // owned by someone else protected boolean IsMoveable() //must be on the edge { BGFSpace s = GetSpace(); int row = s.GetRow(); int col = s.GetCol(); if ( ((row == 0) II (row 4)) II ((col==Ol II (col 4lll return true; else return false; In addition to IsMoveableBy (), the BGFPiece class declares an IsMoveableTo () method which allows a piece to restrict where the spaces to which it may be moved (possibly based on its current location ) This method takes a BGFSpace object representing the target 32

PAGE 38

space. In chess, each piece type would have an IsMoveableTo () method. The BishopPiece class, for example would check to ensure that the new space was reachable on a non-blocked diagonal path from the current space. In Qyixo, the following method is used: public boolean IsMoveableTo(BGFSpace pSpace) { BGFSpace s = GetSpace(); if (s == pSpace) return false; II must move it somewhere else int fromRow = s.GetRow(); int fromCol = s.GetCol(); int toRow = pSpace.GetRow(); int toCol = pSpace.GetCol(); if (fromRow toRow) II same row { if ((toCol == 4) I I (toCol == 0)) II move to one side return true; return false; if (fromCol == toCol) I I same col { if ((toRow == 4) I I (toRow == 0)) II to top or bottom return true; return false; return false; I I not same row OR same col Everything needed for the basic model classes MyGameBoard, MyGameSpace, and MyGamePiece has now been covered. The following list summarizes what needs to be done for these classes: MyGameBoard constructor to pass width and height to BGFBoard constructor which lists the BGFinvalidSingletoninstantiationException in its throws clause GameOverStatus () method to determine if the game is over NewGameHook () method to set up board (optional) MyGameGameOverStatus (optional) an y additional data needed to represent a game-over situation MyGameSpace no class needed MyGamePiece may need no subclass may need one subclass for each piece type in the game IsMoveableBy () method to determine if a piece may be moved by a given player (optional) I sMoveabl eTo ( ) method to determine if a piece may be moved to a given space (optional) 33

PAGE 39

4.3 Seeing the Game ow that the basic conceptual classes have been created, the game must be made visible to the user. This section will focus on the creation of the primary view classes MyGameBoardView, MyGameSpaceView, and MyGamePieceView. First, it is important to understand the interactions between the base classes for these view classes since a great deal of the work is done directly within them. The BGFBoardView class, which inherits from java. awt. Canvas, is responsible for painting the board, spaces, and pieces to the screen. It delegates part of this painting process to the BGFSpaceView and BGFPieceView classes as one would expect. As part of this responsibility, BGFBoardView uses a technique called double-bujfering to make screen updates as smooth as possible. Double-buffering involves drawing everything to an off-screen image then later drawing the completed image to the "real" Graphics object once everything has been drawn, making the update of the display more smooth By implementing this technique at this level, other view classes in the BGF and in BGF applications are relieved from having to worry about it. Just as BGFBoard keeps references to many BGFSpace objects, BGFBoardView objects keep references to many BGFSpaceView objects. When a request is made to repaint the board, the BGFSpaceView objects are asked to draw themselves. Each BGFSpaceView object acts as an Observer of its respective BGFSpace object, receiving notification each time a piece is moved to or moved off the space it is watching. When this happens, the BGFSpaceView object notifies the BGFBoardView which contains it that it needs to be repainted. The BGFBoardView can then repaint the portion of the board containing the space. Each BGFSpaceView object has a reference to a BGFPieceView object ( which may be null if there is no piece on the space ) It is the BGFPieceView objects which must know how to render themselves on the board. Given this brief overview of the interaction between these classes, it is now possible to examine what needs to be done to extend them. The MyGameBoardView class must define a constructor which takes a reference to the BGFBoard object to be observed and forwards this reference on to the BGFBoardView constructor along with the width and height of the game board ( in pixels ) In Tic-Tac-Toe, the following code is used: public TTTBoardView(TTTBoard pBoard) { super(pBoard, kBoardWidth, kBoardHeight); In this case, two constants are used to hold the wi.dth and height of the board. In addition to providing a constructor, MyGameBoardView may also implement a method called Draw ( ) This method, as its name suggests, draws the board on the input graphics context. It is important to note that the drawing of individual spaces on the board should not be done 34

PAGE 40

by this method. Instead, only things which appear outside the spaces ( such as a border around the board) or between the spaces (see the Tic-Tac-Toe example below ) should be drawn here. Games with no such additional graphics may use th e default Draw ( ) method which does nothing ( in fact, the BGFBoardView class is not abstract and so may be used as it is if the Draw ( ) method is not overridden ) The following example shows the Draw ( ) method for the Tic-Tac-Toe program. This method draws four long, narrow rectangles to create the four lines which make up the board. public void Draw(Graphics pGraphics) { pGraphics.setColor(Color.black); pGraphics.fillRect(kSpaceWidth, 0, kLineThickness, kBoardHeight); pGraphics.fillRect((kSpaceWidth*2)+kLineThickness, 0, kLineThickness, kBoardHeight); pGraphics.fillRect(O,kSpaceHeight,kBoardWidth, kLineThickness); pGraphics.fillRect(O, (kSpaceHeight*2)+kLineThickness, kBoardWidth,kLineThickness); This is an example of drawing board contents which are within the board, but not drawn b y the BGFSpaceView objects. Chess in contrast would have the BGFSpaceView objects in charge of drawing the different colored squares. The Qyi.xo example below shows a Draw () method which simply draws a filled border around the playing area. public void Draw(Graphics pGraphics) { pGraphics.setColor(Color.black); pGraphics.fillRoundRect(O,O, (kPieceSize*kGridSize)+(kBorderSize*2), (kPieceSize*kGridSize)+(kBorderSize*2), kArc, kArc); No other methods n eed to be written for the BGFBoardView class. The MyGameSpaceView class is fairly similar. It should take as input the BGFBoardView which contains it and the BGFSpace whi c h it observes. The constructor for BGFSpaceView takes these same two parameters plus a java. awt. Rectangle object representing the placement of this space on the board. In order to create this rectangle the MyGameSpaceView constructor will generally perform a calculation based on the row and column of the input BGFSpace object. The example below comes from the Tic-Tac -Toe program. Here, the TTTSpaceView constructor use s public co nstants for th e size of each space (and the space between each space ) defined in the TTTBoardView class to calculate th e coordinates of the space based on the row and column of the input BGFSpace. public TTTSpaceView ( ) { BGFBoardView BGFSpace pBoardView, pSpace 35

PAGE 41

super( pBoardView, pSpace, new Rectangle( pSpace.GetCol()*TTTBoardView.kSpaceAndLineWidth, pSpace.GetRow()*TTTBoardView.kSpaceAndLineHeight, TTTBoardView.kSpaceWidth, TTTBoardView.kSpaceHeight)); It should be noted that BGFSpaceView is not an abstract class. Applications are free to use this class directly if they r e quire no special behavior. However, most games will want to override some or all of the three methods discussed below. The first is the ShowGameOver ( ) method, the purpose of which is to provid e a way to visually indicate that the game is now over ( or, perhaps, that it was over, but is now bac k in progress due to a player taking back the winning or ( more likel y ) l o sing move ) An example of the use of this method might be to draw a line through the spaces connecting the pieces making up a three-in-a-row in Tu -Tac-Toe. Anothe r option shown here, would be to highlight the winning pieces. In this case, it's reall y up to the MyGamePieceView objects to show this information, but ShowGameOver ( ) is overridden to help them out. public boolean ShowGameOver(BGFGameOverStatus pStatus) { if (_pieceView != null) { II if the game is not over, tell the piece to make sure color I I is correct (used for taking back last move of the game) if (pStatus.IsGameOver() == false) return _pieceView.ShowGameOver(pStatus); if(pStatus.GetWinner() == null ) return false; II game was a draw II if the game IS over, tell the piece if it is one of those II making the 3-in-a-row BGFSpace[J spaces = ((TTTGameOverStatus)pStatus) .GetWinningSpaces(); for (int i=O;i
PAGE 42

The other two methods which may need to be overridden in subclasses ofBGFSpaceView are the Draw () and DrawEmpty () methods. These are called to render a space on the board along with any pie ce which might lie on the sp ace The d efa ult versions of these methods ( shown below ) assume that the spac e has no intrinsic visual quality drawing a blank space in the case ofDrawEmpty () and forwarding calls to the Draw () method on to BGFPieceView. protected void DrawEmpty(Graphics pGraphics) { pGraphics.setColor(_boardView.getBackground()); pGraphics.fillRect(_rect.x, _rect.y, _rect.width, _rect.height); protected void Draw(Graphics pGraphics) { if (_pieceView != null) _pieceView.Draw(pGraphics, _rect); else DrawEmpty(pGraphics); For some applications, this will work perfectly. In fact, neither Tic-Tac-Toe nor Q.ui.xo override either method. However, games lik e chess might h ave DrawEmpty ( ) methods responsible for drawing the properly co lor ed space on the board. Finally, th e MyGamePieceView class must b e created to do the actual rendering of the piece s on the board. The co nstruct o r for this class simply passes the BGFPiece object being observed up to the superclass. For games with multiple piece types multiple subclasses ofBGFPieceView should be created, eac h with it s ow n Draw () method. It may be useful to create a n abstract superclass as a subclass ofBGFSpaceView from which the various game-specific classes extend. This strategy is used in the Tic-Tac -Toe program to allow the gen e ri c TTTPieceView class to implem ent the ShowGameOver () method while the TTTXPieceView and TTTOPieceView classes each define their own Draw () method. K ee p in mind that since TTTPieceView does not implem ent Draw (), it must be d efine d as abstract and it mus t declare the abstract Draw ( ) method as shown below public abstract class TTTPieceView extends BGFPieceView I I ... abstract protected void Draw ( ) ; II Graphics pGraphics, Rectangle pRect 37

PAGE 43

The ShowGameOver ( ) m ethod discussed earlier is shown here. For Tic-TacToe, the winning pieces are shown in a different color. In this implem entation ( as was shown when l ooking at the TTTPieceView class ) the only time this method will be called is when the piece is involved in a win, or when the ga m e is not over. public boolean ShowGameOver(BGFGameOverStatus pStatus) { Color oldColor = _color; if (pStatus.IsGameOver() == true) _color kGameOverColor; else _color _normalColor; if (_color == oldColor) return false; else return true; The final method to be added to MyGamePieceView is the Draw () method. A wide variety of techniques could be used here. The developer is free to use any available A WT methods to render the piece on the input Graphics within the input Rectangle. This may involve the use of any of the basic drawing methods available to th e Graphics class, or it may involve lo a din g an image and drawi n g that image to the Graphics. As previously n oted, the BGFBoardView class implements a tech niqu e called double-btiffering so the Draw () methods on BGFSpaceView and BGFPieceView may freely draw directly to the input Graphics object, without worrying about screen flicker. The Draw () method for Qyi.: w i s s h own below. This m ethod uses th e draw3DRect () method several times to create the look of a three-dimensional block Note the use of the Graphics. translate () method. This allows the origin to be set to the upper-left corner of the input rectangle, making future drawing methods more straight forward. It s important to then reset the origin before ex itin g the method so that future uses of th e same Graphics object will have th e original origin. protected void Draw ( Graphics Rectangle pGraphics, pRect Color pieceColor = QuixoPieceView.GetColor(GetPiece() .GetPlayer()); pGraphics.setColor(pieceColor); pGraphics.translate(pRect.x, pRect.y); int x 0, y = 0; int w = pRect.width -1; int h = pRect.height -1; for (int i=O;i
PAGE 44

h -= 2; } pGraphics.fill3DRect(x, y, w+l, h+l, true); pGraphics.translate(-pRect.x, -pRect.y); I I back like it was Nothing further needs to be done for the primary view classes. To summarize: );> MyGameBoardView constructor which passes the total dimensions of the board to BGFBoardView Draw ( ) method to render anything not contained in a space );> MyGameSpaceView constructor which passes a Rectangle specifying the size and location of the space on to the BGFSpaceView constructor ShowGameOver ( ) method to reflect the end of a game Draw () and DrawEmpty () methods to show the space and its piece );> MyGamePieceView constructor which does nothing but pass the BGFPiece up to its super ShowGameOver ( ) method to reflect the end of the game Draw () method to render the piece -!.4 Additional Required Classes At this point, the primary conceptual and visual classes have be e n created There are just two more classes which must be completed to create a working BGF applet. The first of these is the MyGameFactory class. This is the class which allows methods in the BGF classe s to generically create instances of concrete subclasses without knowing what type of object is being created. There are quite a few abstract methods in the interface, but implementing them is generally quite simple. public abstract class BGFFactory { public abstract BGFBoardView CreateBoardView(BGFBoard pBoard); public abstract BGFPieceView CreatePieceView(BGFPiece pPiece); public abstract BGFSpaceView CreateSpaceView(BGFBoardView pBuardView, BGFSpace pSpace); public abstract BGFPlayer[] CreatePlayers(); public abstract BGFStrategy[] CreatePrototypeStrategies(); public BGFSpace CreateSpace(int pRow, int pColurnn) { return new BGFSpace(pRow, pColurnn); public BGFMovePieceMove CreateMovePieceMove(BGFMoveController pMoveCon, BGFPlayer pPlayer, BGFPiece pPiece, BGFSpace pFromSpace, BGFSpace pToSpace) return new BGFMovePieceMove(pMoveCon, pPlayer, pPiece, pFromSpace, pToSpace); 39

PAGE 45

} II The first three methods should simply return a new instance of the appropriate concrete class using the input parameters as constructor paramete rs. The CreatePlayers () method returns an array containing newly created instanc es of the players in the game. The order of the array should reflect the orde r in which the players make th eir moves ( e.g. player [ 0] would be white in chess, while player [ 1] would be black since white always moves first ) Remember that the players in the game represent the diff erent "si des of the game, not the strategy used to pla y the game, so the objects created here should persist throughout the life of the applet. The next method, CreatePrototypeStrategies () i s us e d to create an instance of each possibl e BGFStrategy subclass available to the players in the game. These objects are u sed to populate the BGFWhoPlaysDialog object. The reason objects are created here is that the dialog r eally n ee ds two pieces of information: the name of the strategy ( to display to the user ) and the type of the object to create if the user selects a given strategy. The objects are called prototypes" be ca use they are never used directly. In stead, the "name" o f the strategy is us e d to populate the display, and th e Object. GetClass () method is us e d on the object to obtain the Class object representing the strategy class so that Class .newinstance () may then be used to c reate a unique BGFStrategy instance for each pla yer ( multiple players might use the same strategy, so unique instances must b e created rather than directl y using the "prototy pe object ) The Qllixo impl e mentations of thes e last two methods are shown below public BGFStrategy[] CreatePrototypeStrategies() { BGFStrategy[] strategies = new BGFStrategy[2]; strategies[O] =new BGFTwoSpaceGUIStrategy(); strategies[l] =new QuixoRandomStrategy(); return strategies; public BGFPlayer[] CreatePlayers() { BGFPlayer[] players = new BGFPlayer[2]; players[O] =new BGFPlayer(kPlayerlName) ; players[l] =new BGFPlayer(kPlayer2Name); return players; Note that Qllixo uses strategy and pla yer classes provided by the BGF, as well as its own "random" strategy class. The result of these two methods is the eventual creation of a "Who Plays" dialo g box like the one shown in Figure 4.2. Note that each player may c hoose from any of the possible strategies 40

PAGE 46

Playe r 1 Human Figure 4.2 Player 2 Huma n The last two methods listed in the BGFFactory interface provide default implementations. The first is the CreateSpace () method which simply returns a new instance of the BGFSpace base class. Applications which create their own BGFSpace subclasses must also override this method to create the proper space type. The other method providing a default implementation is the CreateMovePieceMove () method. The purpose of this method is to allow the generic creation of a BGFMove object subclass representing a move in which a piece is moved from one space to another. Such move classes will typically have some class-specific behavior and will therefore be subclassed. The default behavior creates a generic BGFMovePieceMove object, ensuring that games which do not need such moves are not forced to provide an implementation of this method and providing a simple implementation for games which can directly use the BGFMovePieceMove class as it is defined. One additional item which must be added to the MyGameFactory class is a public zero-parameter constructor. This c onstructor aike the MyGameBoard constructor ) must list the BGFinvalidSingletoninstantiationException in its throws clause. The constructor may be as simple as the following: public MyGameFactory() throws BGFinvalidSingletoninstantiationException { } A class with responsibilities directly related to those in MyGameFactory will be the MyGameApplet class. This class inherits from BGFApplet, which in turn extends java. awt. Applet. The methods needed in MyGameApplet provide the applet with various types of initial setup data. The BG F uses a technique for the initialization of Abstract Singleton classes based on java's exposure of the type system at runtime. In java, each class in the system has a corresponding Class object which can be used for, among other things, the creation of new instances of a class. Further more, a Class object can be obtained at a n y time by passing the name of the class to the static Class. forName () method. To take advantage of these conveniences, the BGFApplet class declares two abstract methods named GetFactoryClassName () and GetBoardClassName (). The implementation of these two methods in BGFApplet subclasses simply involves returning a String containing the .fo.l!Y quali..fod name of the respective concrete classes The implementations for the Tu-Tac-Toe program are shown below. static private final String kFactoryClassName "EDU.cudenver.BGF.TTT.TTTFactory"; static private final String kBoardClassName = 41

PAGE 47

"EDU.cudenver.BGF.TTT.TTTBoard" ; protected String GetFactoryClassName() { return kFactoryClassName; protected String GetBoardClassName() { return kBoardClassName; These two simple methods allow the BGFFactory and BGFBoard singleton classes to be configured to create the correct concrete object. For more details on Abstract S ingletons, refer to section 3.3.1. The BGFApplet class provides a very basic user interface consisting of three buttons (anchored to the top of the applet) and the board ( set in the center ) The class makes use of an AddBu t tons ( ) method to place the buttons on a Panel to be displayed on the applet. This method may be overridden in order to add additional buttons, or to remove unwanted buttons. Ifbuttons are added, the HandleButton () method must also be overridden to provide the desired action for this button. Overriding versions of these two methods will likely want to call super. AddBut ton () and super. HandleBut ton () in order to invoke the overridden methods from within the subclass implementation; otherwise, the buttons provided by BGFApplet will no longer appear or function. Possible implementations of these methods are shown below. protected void AddButtons(Panel pPanel) { super.AddButtons(pPanel); pPanel.add(new Button("Save Game")); protected void HandleButton(Button pButton) { super.HandleButton(pButton); BGFCommand command = null; if ("Save Game".equals(pButton.getLabel()) { command= new MyGameSaveGameCommand(); if (command != null) { true) BGFCommandProcessor cp = BGFCommandProcessor.Instance(); cp.SubmitCommand(command); The BGFCommand and BGFCommandProcessor classes are discussed in the next section. The important thing to notice here is that both methods call the methods they override to allow the BGFApplet methods to perform their default action. If the goal was to remove certain buttons from BGFApplet, the AddBu c:ons () method would not call 42

PAGE 48

super. AddButtons (),but would need to add any buttons defined in BGFApplet .AddButtons () which it did want to keep. Nothing further needs to be done for the BGFApplet class. This section added: MyGameFactory zero -argument constructor which does nothing, but declares itself to throw the BGFinvalidSingletoninstantiationException CreateBoardView () factory method CreatePieceView () factory method CreateSpaceView () factory method CreatePlayers () factory method CreatePrototypeStrategies () factory method CreateSpace () factory method CreateMovePieceMove () factory method MyGameApplet GetBoardClassName () method which returns "MyGameBoard" ( fully-qualified ) GetFactoryClassName () method which returns "MyGameFactory" ( fully -qu alified ) AddBu t tons ( ) method which calls super AddBu t tons ( ) unless you want to remove the default buttons HandleBut tons () method which calls super. HandleBut tons () unless the default buttons have been removed 4.5 Optional Classes The previous sections described classes in the BGF which must be extended by each implementation. This section discusses four BGF classes which a r e not abstract but may require extension for certain types of games. For each of the four classes, some r e usable concret e components already exist in the framework. The developer must determine whether the existi n g classes will suffice for each new application. The BGF classes covered in this section are BGFCommand, BGFStrategy, BGFPlayer, and BGFMove. 4.5.1 Extending BGFCommand The BGFCommand class is used to encapsulate any type of command received from the user. The BGF provides four subclasses ofBGFCommand: BGFNewGameCommand BGFTakeBackCommand BGFWhoPlaysCommand BGFSp aceSelectedCommand 43

PAGE 49

These commands are created as a result of input from the GUI. The implementation of these classes is very simple though new commands co uld be more complex. Each of the commands listed above simply retrieves the BGFGameMaster object and calls an appropriate m ethod on that object. The implementation ofBGFTakeBackCornmand is shown below as an example. public class BGFTakeBackCommand extends BGFCommand public BGFTakeBackCommand(int pCount) { _count = pCount; public void ExecuteHook() { BGFGameMaster gm = BGFGameMaster.Instance(); gm.TakeBack(_count); private int _count; Applications which add additional buttons or other GUI components to the display s hould create new subclasses ofBGFCornmand to exec ute the appropriate command. The only requirement ofBGFCornmand subclasses is that they provide an ExecuteHook () method which performs the desired action. The BGFCornmand base class takes care of exec uting each command in a new thread, allowing the GUI thread to return as quickly as possible. The implementation of BGFCornmand is shown below to give an understanding of where the ExecuteHook () method fits in the overall flow. abstract public class BGFCommand implements Runnable abstract protected void ExecuteHook(); public void run() { ExecuteHook(); public void Execute() { Thread t = new Thread(this); t.start(); II calls run() 4.5.2 Extending BGFStrategy The BGFStrategy class is responsible for the creation of BGFMove objects any time the player emploring the strategy is asked to make a move. For applications which include "i ntelligent" computerized players, this class will b e the most complex in the entire application since it must generate (possibly v.rith the help of other application-specific classes ) the computer's moves. However, BGFStrategy is not us ed exclusively for 44

PAGE 50

computer-generated moves. Any move in the game should ultimately be generated by a BGFStrategy object. This includes moves based on input from the GUI, moves retrieved via a network connection or Rem o t e Method Invocation (RMI) etc The BGF provides several concrete reusable components for handling moves generated from the GUI. These include: BGFGUIStrategy BGFOneSpaceGUIStrategy BGFTwoSpaceGUIStrategy The last two of these inherit from th e first, which is an abstra ct extension of the abstract base clas s BGFStrategy. B ot h BGFOneSpaceGUIStrategy and BGFTwoSpaceGUIStrategy may b e used directly by an application. The first i s used for games in which a move is generated b y clicking a s ingl e space on the board and placing a new piece ( created by the BGFOnePiecePlayer class ) on that space. BGFTwoSpaceGUIStrategy is used in games in which a move is made b y first clickin g on a piece to b e moved and then clicking on a space to which th e piece is to b e moved. These classes extend BGFGUIStrategy by prcviding uniqu e implementations of the abstract method HandleSpaceSelection () defined b y BGFGUIStrategy. The purpos e of this m e thod is to rec ord th e fact that a space on the board has been clicked and respond accordingly. The method from BGFOneSpaceGUIStrategy is shown below. protected boolean HandleSpaceSelection() { BGFPiece newPiece = ((BGFOnePiecePlayer)_player) .GetNewPiece(); BGFNewPieceMove move = new BGFNewPieceMove(this, newPiece, _selectedSpace); TryMove (move) ; return true; II indicating that a move has been tried The HandleSpaceSelection () method is similar (but a bit more involved ) for the BGFTwoSpaceGUIStrategy class shown below protected boolean HandleSpaceSelection() { if (_firstSpace == null) { II See if this space has a piece owned by this player BGFPiece p = _selectedSpace.GetPiece(); if ((p !=null) && p .IsMoveableBy(GetPlayer())) { _firstSpace = _selectedSpace; _movingPiece = p; return false; II no move tried yet 45

PAGE 51

else { BGFFactory factory= BGFFactory.Instance(); BGFMove move = factory.CreateMovePieceMove(this, _movingPiece = null; _firstSpace = null; TryMove (move) ; GetPlayer(), _movingPiece, _firstSpace, _selectedSpace); return true; // a move has been tried Note that the return value from this method simply indicates whether or not a move has been created and submitted via TryMove ( ) ; the r eturn value has no reflection on whether or not th e move was successful. 4.5.3 Extending BGFPlayer The BGFPlayer class is used to r epresent th e players in a game. Instan ces ofBGFPlayer (or its subclasses ) are created at initi alization and persist throughout the game. This class only needs to be extended if a n ew BGFStrategy class is created which requires some specific operation to be performed by the player, otherwise the BGFPlayer and BGFOnePiecePlayer classes ( n e ither of which is abstract ) may be used directly. BGFOnePiecePlayer is an example of a class which is needed to satisfy a particular BGFStrategy subclass-the BGFOneSpaceStrategy class. This strategy class requires a BGFPiece object associated with a particular pla yer to be created each time a move is made This strategy/player combination is used in ga mes lik e Tic-Tac-Toe and Connect-4, in which each move consists of creating a new piece whose type (X/0, Black/R ed ) is specific to the player making th e move. If no new strategy/player co mbination is needed, the BGFPlayer and BGFOnePiecePlayer classes should be used directly. 4.5.4 Extending BGFMove Instan ces ofBGFMove subclasses are used to represent and r ecord eac h move made in a game. Each B GFMove object m u st contain enough data to make a move and to later be able to undo that move if it is "taken back." These two actions are performed within the abstract methods HookExecute () and HookUndo ().Like t h e other classes d i scussed in t his section, BGFMove has concrete, reusable subclasses al read y defined in the BGF. These include: 46

PAGE 52

BGFMovePieceMove BGFNewPieceMove The BGFMovePieceMove class is used in games in which a move consists of a given player moving a piece from o n e space on the board to another and undoing the move co nsist s of moving the piece back to the original space This class implements the HookExecu te ( ) method as follows: public boolean HookExecute() { if (_piece.IsMoveableBy(_player) == false) return false; if (_frornSpace.GetPiece() != _piece) return false; if (_piece.IsMoveableTo(_toSpace) false) return false; return MakeMove(); otice that the last line provides another hook allowing subclasses with the same basic move rules ( a player moves a piece from one space to another) but additional game specific details, to extend this class rather than havin g to extend BGFMove dir ectly. The default MakeMove ( ) method is fairly simple. protected boolean MakeMove() { if (_toSpace.PlacePiece(_piece) return false; _frornSpace.ClearSpace(); return true; false) Games in which a piece might be captured, for example, would need to ove rrid e this method to save the captured piece for use in Undo ( ) Note that ifBGFMovePieceMove is extended to override MakeMove () and HookUndo (),the CreateMovePieceMove () method on the BGFFactory class should also be overridden in MyGameFactory to instantiate the new subclass. It is through this factory method that new moves of this type are created by BGFTwoSpaceStrategy objects. The other subclass ofBGFMove provided by the BGF is the BGFNewPieceMove class. This class is used in games in which each move consists of the placement of a new piece onto an unoccupied space on the board. It provides the following implementations of HookExecute () and HookUndo (). public boolean HookExecute() { return _space.PlacePiece(_piece); 47

PAGE 53

public boolean HookUndo() { return _space.RemovePieceForUndo(); Instances of this class are created directl y b y BGFStrategy subclasses, without the use of the BGFFactory. This is done because there is no need to extend BGFNewPieceMove. Note that completely new subclasses ofBGFMove must be accompanied by new BGFStrategy subclasses which create these moves. Therefore, the use of BGFNewPieceMove and BGFMovePieceMove is encouraged whenever possible. 4.6 Developer's Guide Sununary This concludes the Developer's Guide for the Board Game Framework. Developers interested in creating applications using the BGF should simply follow the steps described in this "cookbook." A5 an additional resource, each BGF class is fully commented usingjava's documentation comment mechanism, allowing a complete online class referen ce manual in html format to be generated. 48

PAGE 54

5. Conclusion An unfinalized object has never had its finalizer automaticallY invoked; a finalized object has had its finalizer automaticallY invoked. A jinalizable object has never had its finali<.er automaticallY invoked, but the Java Virtual Machine may eventual{y automaticallY invoke its finali<.er. 12.6. 1, The Java Language Specification Johnson [Joh92] describes the three key areas of framework documentation as ( 1 ) the purpose of the framework, ( 2 ) an explanation of how to use the framework and ( 3 ) the detailed design of the framework. In this thesis, a framework for the toy domain of board game applications is presented which satisfiesJohnson's three basic requirements. By presenting both a detailed pattern-based analysis of the framework and a step -b y-step "cookbook" for application creatio n the framework can be understood by users of various skill and interest levels. The goal of this thesis, however, was not merely to show an example of J ohnson's documentation techniques, but was instead to present a reusable framework created in a relatively new programming language built on the solid foundations of numerous well-known design patterns. Additionally, implications oftheJava programming language on many of these patterns h as been examined and a new Java-specific design pattern (or idiom ) has been presented. The framework presented here should serve as a means for better understanding the design patterns described. The Java programming language has successfully taken the next step in object-oriented programming languages, incorporating many of the strongest features of languages such as C++ and Small talk, while eliminating many of the most significant problem areas. D espite its infancy,Java is a mature language with strong support for advanced software techniques such as multithreading and exception -handlin g As it grows ( release 1.1 is expected in lat e l996),J ava will continue to advance as the language of c h oice for a wide variety of software development tasks. 49

PAGE 55

Appendix A : Notation Since early 1995, Grady Boo c h J ames Rumba u g h and, more recently, I var J acobse n have been working together to c r ea t e a new Unified Modeling Language [BJR 96), [BJR096], [BR 95]. This modeli n g l anguage (UM L ) is scheduled to be submitted to the Object Model in g Group (OMG) for standardization in early 1 99 7 The UML clearly has th e insid e track on becoming th e industry standard for m odeling software syst ems. The UML describes s eve r a l types of diagrams of w hi c h th e Class Diagram and Sequence Diagram are u sed throughout the description of th e BGF. This section gives a limit ed overview of th ese two types of m odels to assist in the und erstandi n g of t h e diagrams used throughout thi s thesis. These are not comp l e t e descriptions of the UML diagrams but are instead lim ited to those modeling elements used in thi s thesis. Class Diagram The class diagram shows a collection of classe s and the relationships between them. Each class is shown as a rectangle option ally divided into three compartment s If the thre e compartment s are shown, they contain, from t op to bottom, th e name of th e class (gen e r ally in Bold; Boldltalics for abstra c t classes ) the attributes (or fields, in j ava ) of the class and the operations ( me thods ) Operations show n in italics are abstract. If th e attributes and operations are not critical to th e und ersta ndin g of the dia gram, they are omitted l eavi n g a s in g l e box contai nin g th e class n a m e. R e l at i ons betwee n classes are s hown b y drawing lin es between the related classes An arrow o n o n e e nd of a lin e indica t es that th e relat i o n s hip is onl y n avigab l e in one direction. The multipli c ity of instan ces allowed for a given r e lati on is shown u sing numbe r s toward th e ends of th e lin es. R e lations with no s pecific upper bound are shown with an asterisk ( *), to indi cate "zero or more." Aggregatio n relationships a r e shown by placing a s mall diamond at the end of th e r e l atio n lin e closest to th e agg r ega tin g class. Inheritance i s shown b y drawing a line with a large, open arrowhead pointing fro m th e su bclass to the b ase class. Interfaces are s h own by drawing a small open circle with th e name o f th e int erface written above it. The imp l e m entatio n of an int erface is shown by drawin g a line ( no arrowhead ) from the implem e ntin g class t o th e c ircl e r eprese nting the interface. The UML d e fine s the co ncept of stereotypes, a general cat c hall to allow a dditi o nal information about cer tain classes or relations to be specified. Stereo types are shown by b r acke tin g th e name of the s t e r eoty pe in guillemets ( ) In th e BGF diagrams th e stereotypes used a re sin gleto n c reat es, executes, and interface. Note that interfaces are shown using the 50

PAGE 56

small circle described above (rather than the interface notation ) when the operation s do not need to be displayed. The grouping of classes which form a package ( all classes in the BGF are in a common package ) may be shown by drawing a large, tabbed box around the set of classes and placing the package name on the tab on the upper-left corner of the box. Finally additional comments may be added to the diagrams using "notes" small rectangles drawn vvith a turneddown corner. Figure A. I shows each of the symbols described above. Interface Sequence Diagram. must complete in<= 2 sec Figure A. I 1 .* X has access to one or more Y 's, but the Y s are una ware of the Xs Sequence diagrams are used to s h ow the in te r actions between objects within a give n scenario ( that is, they do not show all po ssible event flows, only a single example ) The UML has adopted the notation for seq u ence diagrams described in [BMRSS96]. Each object in the scenario is shown as a rectangle wit h the name of the instance followed by the name of the class. These names are co lonseparated and underlined. The objects are laid out horizontally across the page with vertical lines ex t ending below each recta n gle. Horizontal lines are drawn between objects to show method calls and returns Method calls a r e shown by darkened, triangular arrowheads, while returns are shown with non-filled arrows Objects passed or returned via method calls are attached to these lines. Time flows from the top of the diagram to the bottom. 51

PAGE 57

Object creation is shown by drawing a line from the creator to the top of a new instance rectangle, rather than to the vertical line below the rectangle. Object destruction is shown by placing a large X at the end of the object's line. Sin c e the BGF diagrams in this thesis are showing the flow ofjava programs ( which have no explicit delete operations ) this X is used to show that the object is no longer referenced by any other object and is subject to finalization by the garbage collector. Activity of objects is shown by placing a narrow rectangular box on the object's vertical line Nested calls on the same object are shown by offsetting additional boxes to the right of the original box. In many situations in this thesis, a major purpose of the sequence charts is to show the distinction between operations implemented within a base class and operations imp lemented by a subclass. Objects for which this distinction is important are shown as two separate boxes ( each with its own line ) They are always drawn next to each other and, more importantly, will always have the same instance identifier. Figure A.2 shows the following sequence of calls on four hypothetical objects: some outside object calls the Dolt () method on an instance (id="fl") of class Foo fl has a reference to an instance of class Sub (id=" idl"), and calls its MethX () method Sub is a subclass of Base, and MethX () is actually implemented in class Base, so the line showing this method call goes to the Base object this method does nothing of interest ( for this diagram ) so the return of control is shown on the same line as the call fl ( still in its Dolt () method) next calls MethYQ passing itself as a parameter idl calls method HookMeth () which is implemented by the subclass Sub the HookMeth () method creates a new instance (id="newObj )of class Bar the new instance is returned to MethY which returns it to Dolt () on fl fl's Dolt () calls a method on itself called Sel fMethQ SelfMeth () calls method MethZ ( which does nothing of interest to us ) on newObj SelfMeth () returns Dolt () returns to the original caller the caller drops its reference to fl, allowing it to be made available for garbage collection 52

PAGE 58

newOb!:Bar FigureA 2 53

PAGE 59

Appendix B: BGF Source Code This section co ntain s the complete j ava source code for th e Board Game Framework. The classes are listed alphabet ically. BGFApplet I * BGFApplet.java * Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; import java.applet.Applet; import java.awt.*; I** The starting point for Board Game Framework applets. BGF applets must inherit from this class. The abstract class does much of the basic setup f o r the applet including the configuration of the BGFFactory and BGFBoard singleton classes. In order to make this setup work, subclasses of BGFApplet must implement the GetFactoryClassName and GetBoardClassName methods. @author Dave Wood< IA> I public abstract class BGFApplet extends Applet implements Runnable I** Called by the start() method to setup the game. This method configures the BGFFactory and BGFBoard Singleton classes and creates the BGFBoard, BGFBoardView and BGFPlayer[J objects. Next, it sends the new BGFPlayer objects to the BGFGameMaster Singleton object and passes a BGFNewGameCommand on to the BGFCommandProcessor as though the "New Game" button had been pressed. @see @see @see @see @see @see @see @see I BGFFactory BGFBoard BGFBoardView BGFPlayer BGFGameMaster BGFCommandProcessor BGFCommand BGFNewGameCommand protected void Setup() { System.out.println("BGF Applet initializing"); BGFPlayer.ClearPlayers(); String factoryName = GetFactoryClassName(); 54

PAGE 60

/** try { BGFFactory.Configure(Class.forName(factoryName)); catch (ClassNotFoundException e) { System.out.println("Factory Class not found exception."); stop(); String boardName r.ry GetBoardClassName(); { BGFBoard.Configure(Class.forName(boardName)); car.ch (ClassNotFoundException e) { System.out.println('Board Class not found exception."); stop(); BGFBoard board= BGFBoard.Instance(); BGFFactory factory= BGFFactory.Instance(); BGFBoardView boardView = factory.CreateBoardView(board); setLayout(new BorderLayout() ); Panel buttonPanel =new Panel(); AddButtons(buttonPanel); add('North', buttonPanel); Panel boardPanel =new Panel(); boardPanel.add(boardView); add( "Center", boardPanel); BGFPlayer[J players= factory.CreatePlayers(); BGFStrategy[) strategies= factory.CreatePrototypeStrategies(); Component frame = this; while (!(frame instanceof Frame)) frame= frame.getParent(); _whoPlaysDialog = new BGFWhoPlaysDialog( (Frame) frame, players, strategies); BGFGameMaster master= BGFGameMaster.Instance(); master.SetPlayers(players); Called by the applet context just after the applet is made active. This method checks to see if the private Thread data object has been created, creating it if necessary, and the calls start() on the thread (which will c ause the run() method on BGFApplet to be called). It first calls the Setup() method to set up the game. * @see @see @see I BGFAppler..run java.lang.Thread java.lang.Runnable public void start() 55

PAGE 61

I** System.out.println("BGF Applet has been started"); if (_thread == null) { Setup(); thread= new Thread(this, "Main BGF Thread"); _thread.setPriority (Thread.currentThread() .getThreadGroup{) .getMaxPriority()); _thread.start(); Called by the applet context just after the applet is made inactive. This method stops the thread in which the applet is running and sets the private Thread reference to null. @see java.lang.Thread I public void stop() { I** System.out .println ( "BGF Applet has been stopped"); II First, abort the game BGFGameMaster gm = BGFGameMaster.Instance(); while (gm.GameinProgress()) gm.AbortGame(); II Now, kill the thread if (_thread = null) { _thread. stop(); thread = null; This method is executed when a Runnable object is executed by a thread. It retrieves the BGFGameMaster Singleton object and calls the Play() method on the object. When Play() returns (indicating *that the game is over), the WaitForNewGame() method is called. This method simply waits until a new game is requested. run() stays in a tight loop, calling Play() and WaitForNewGame() until the thread is stopped. @see BGFGameMaster I public void run() { System.out.println("BGF Applet has been run"); II pretend they just hit "new game" HandleButton(new Button{kNewGameButtonText)); BGFGameMaster master= BGFGameMaster.Instance(); II Wait until the master is ready ... while (!master.ReadyForPlay()) { Thread.currentThread() .yield(); try { Thread.currentThread() .sleep(lOO); } catch (InterruptedException e) {} 56

PAGE 62

/** while(true) { master.Play(); Runtime.getRuntime() .gc(); II clean up garbage master.WaitForNewGame(); Called when an action event occurs. This method is used to handle button clicks on the simple BGF user interface. Applications using the BGF are encouraged to override this method to provide enhanced GUI capabilities. @param pEvent An object that depends on the component that generated the event @param pArg The non-null Event @see @see java.awt.Event BGFApplet#HandleButton *I public boolean action ( / ** Event pEvent, Object pArg if (pEvent.target instanceof Button) HandleButton((Button)pEvent.target); else return false; return true; This method creates and submits BGFCommand objects for two simple *button-press events. These events are "New Game" and "Take Back". If either of these events occurs the appropraite BGFCommand object is created and sent to the BGFCommandProcessor. Otherwise, the *method does nothing Applications using the BGF are encouraged co overried this method to handle additional buttons appearing on the GUI. @param pButton The button which has been pressed * @see @see @see @see @see @see @see BGFApplet#action BGFCommand BGFNewGameCommand BGFTakeBackConwand BGFWhoPlaysCommand BGFCommandProcessor java.awt.Button I protected void HandleButton(Button pButton) { BGFCommand command = null; if (kNewGameButconText.equals(pButton.getLabel()) ==true) { command= new B GFWhoPlaysCommand(_whoPlaysDialog); } else if (kTakeBackButtonText.equals(pButton.getLabel()) { command= new BGFTakeBackCommand(l); else if (kTakeBack2ButtonText.equals(pButton.getLabel()) 57 true) true)

PAGE 63

command= new BGFTakeBackCommand(2); } else if (kQuitButtonText.equals(pButton.getLabel() ) { System.exit(l); //applications only } if (command !=null) { true) BGFCommandProcessor cp = BGFCommandProcessor.Instance(); cp.SubmitCommand(command); !** Add buttons to the GUI panel. This method adds the two standard BGF buttons to the GUI. Applications using the BGF are encouraged to override this method to include additional Buttons. @param pPanel the Panel object to which the Buttons are to be added @see java.awt.Panel @see java.awt.Button I protected v oid AddBuctons(Panel pPanel) { pPanel.add(new Button(kNewGameButtonText)) ; pPanel.add(new Button(kTakeBackButtonText)); pPanel.add(new Button(kTakeBack2ButtonText)); /** Obtain the full class name for the class being used by this application. This method must be defined by the application to return the full class name of the BGFFactory subclass used to create various BGF objects. As an example, the Tic-Tac-Toe sample applet TTTApplet simply returns the string "EDU.cudenver.BGF.TTT.TTTFactory". This string is used to configure the BGFFactory Singleton class so that it can create an instance of the appropriate concrete class using the Class.newinstance() method. @see java.lang.Class#newinstance I abstract protected String GetFactoryClassName(); /** Obtain the full class name for the BGFBoard class being used by this application. This method must be defined by the application to return the full class name o f the BGFBoard subclass used to create various BGF objects. As an example, the Tic-Tac-Toe sample applet TTTApplet simply returns the string "EDU.cudenver.BGF.TTT.TTTBoard". This string i s used to configure the BGFBoard Singleton class so that it can create an instance of the appropriate concrete class using the Class.newinstance() method. @se e java.lang.Class#newinstanc e */ abstract protected String GetBoardClassName(); !** Paint the screen without first clearing it. * @param pGraphics The Graphics object to paint upon 58

PAGE 64

* I public void update(Graphics pGraphics) ( paint(pGraphics); I** Run this applet as an application. This method creats a frame and attached an instance of the specified BGFApplet class to it. @param pArgs pAggs[O) must contain the fully-qualified name of the BGFApplet subclass to be used. I public static void main(String pArgs[)) ( I** if (pArgs.length != 1) ( System.out.println("You must specifiy a single applet class name"); System.exit(l); Frame f = new Frame ( "BGF"); BGFApplet applet = null; try ( Class appletClass = Class.forName(pArgs[O)); applet = {BGFApplec)appletClass.newinstance(); catch {ClassNotFoundException e) ( System.out.println{"Sorry, invalid class name. Be sure to + "give the fully qualified name"); System.ouc.println{"EXCEPTION: + e); System. exic ( 1); catch {InstantiationException e) ( System.out.println{"Sorry, could not instantiate your class."); System.out.println{"EXCEPTION: + e); System.exit{l); catch {IllegalAccessException e) ( System.out.println("Sorry, unable to access constructor of" + the specified class"); System.out.println{"EXCEPTION: +e); System.exit{l); f.add{"Cencer", applet); f.resize{500,500); applet.init{); applet.add{ "South", new Button{kQuitButtonText)); applet.scart{); f. show{); Tell the applec that the players have been set. 'I public synchronized void PlayersSet{) ( _playersSet = true; notifyAll {) ; II Thread in which the applet will run 59

PAGE 65

private Thread _thread = null; II Dialog box for player/strategy selection privace BGFWhoPlaysDialog _whoPlaysDialog; II Have the players been sec? private boolean _playersSet = false; II Strings to hold button names procecced static final String kNewGameButtonText = "New Game"; protected static final String kTakeBackButtonText = "Take Back"; protected static final String kTakeBack2BuctonText = "Take Back 2"; procecced static final String kQuitButtonText = "Quit"; BGFBoard I * BGFBoard.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; import java.util.Observable; I** The "model" representation of the game board. This class represencs a generic board game playing area, consisting of a two-dimensional array of spaces. This is a Singleton (127 ) < 1B> class (only one instance of a single subclass may exisc.) Noce that che Configure() method must be called to set the Class to be instantiated before Instance() may be called (this is handled by the BGFApplet class). @author
Dave I'Jood I public abstract class BGFBoard extends Observable I** Initialize a new playing board. This protected constructor is called by subclass constructors to create a board of the specified size. The construccor creates the spaces on the board and sets up the board for a new game. @exception @param @param I protected ( int int pRows pCols BGFBoard BGFinvalidSingletoninstantiationException Thrown when an attempt is made to instantiate this class other than through the Instance() stacic method call pRows, pCols The number of rows of spaces on the board The number of columns of spaces on the board throws BGFinvalidSingletoninscantiationException II synchronized so that new() cannot be used to create an instance II immediately after the Instance() method sets _createinstance to 60

PAGE 66

I** II true, but before it calls this constructor synchronized(getClass()) { if (BGFBoard._createinstance == false) throw new BGFinvalidSingletoninstantiationException(); _rows pRows; _cols pCols; _spaces= new BGFSpace[_rows] [_cols]; CreateSpaces(); NewGame(); Set the Class to be instantiated by Instance(). This static class simply stores the input Class object. An instance of this class will be created using the Class.newinstance method within the Instance() method. @param pClass A subclass of BGFBoard to be instantiated by the Instance() method. * I public static synchronized void Configure(Class pClass) { I** _class = pClass; instance = null; Return the Singleton instance of the configured BGFBoard subclass. The first time this static method is called, it attempts to create an instance o f the BGFBoard subclass using the Class.newinstance method. If it is unable to do so, it outputs an error message and returns null. This will generally result in a NullPointerException when the caller attempts to use the returned instance. This is the appropraite behavior as it will halt execution of the applet which cannot execute properly until the code is fixed to properly configure the board. Subsequent calls to this method simply return the single instance created in the first call. This concept is descrbed in the Singleton (127)<1B> pattern. @return The singleton instance of a BGFBoard subclass I public static synchronized BGFBoard Instance() { if (_instance == null) { try { } _createinstance = true; _instance= (BGFBoard)_class.newinstance(); _createinstance = false; I I Do nothing ... caller will generate a NullPointer exception II and halt the applet (this is the only reasonable thing to I I d o since w e can't continue with a board) catch (IllegalAccessException e) { System.out.println("BGF Application Error. Invalid board."); catch (InstantiationException e) { System.out.println("BGF Application Error. Invalid board."); 6 1

PAGE 67

return _instance; /** Indicate that a game which was over is no longer over (the last move has been taken back) This method simply notifies the observers of the board of the current game-over status. See the Observer (293) design pattern for more details. *I public void GameOverUndone() { setChanged () ; notifyObservers(new BGFGameOverStatus(false, null)); !** Check the state of the board to see if the game is currently over. The actual check is done by a hook method called GameOverHook() (see the Template Method (325) pattern). If the game is over, the observers are notifed (see the Observer (293) pattern. @return The current game-over status of the game @see BGFBoard.GameOverHook *I public BGFGameOverStatus GameOver() { BGFGameOverStatus s = GameOverHook(); /** if ( s. IsGameOver () true) { setChanged(); notifyObservers(s); return s; Return the current game-over status of the board. This method must be implemented by applications using the BGF to do the actual evaluation of the game board and determine whether or not the game is over. @return the current game-over status of the board @see BGFBoard#GameOver *I protected abstract BGFGameOverStatus GameOverHook(); !** Create the BGFSpace objects to fill the board. This method fills the 2-dimensional array of BGFSpace objects by creating a concrete BGFSpace instance (using the BGFFactory) for each row/column on the board @see @see *I BGFFactory BGFSpace protected void CreateSpaces() { int i,j; BGFFactory factory= BGFFactory.Instance(); for (i=O;i<_rows;i++) { for (j=O;j<_cols;j++) { _spaces[i] [j] = factory.CreateSpace(i,j); 62

PAGE 68

I** Set up the board for a new game. This method calls ClearSpaces(} to empty the board. It then calls NewGameHook(} to do any specific board setup required by the game. @see @see I BGFBoard#ClearSpaces BGFBoard#NewGameHook public void NewGame(} { ClearSpaces(}; NewGameHook(BGFPlayer.GetPlayers(}}; I** Returns the number of rows on the board. I public int GetNumRows(} { return _rows; I** Returns the number of columns on the board. I public int GetNumColumns(} { return _eels; I* * Return the BGFSpace at the specified coordinates. @param @param pRow pCol The requested row The requested column @return The space at the requested coordinates I public BGFSpace GetSpace ( I** int pRow, int pCol return _spaces[pRow) [pCol); Return a new Enumeration for iterating over the spaces on the board. @return A new BGFBoardEnumeration object used to iterate over the spaces on the board I public BGFBoardEnumeration GetBoardEnumeration(} { return new BGFBoardEnumeration(this}; I** Perform application-specific new-game board setup. The default implementation does nothing. Note that this is not an abstract method, since the default behavior will be appropriate for games in which the board is initially blank. Clearing all spaces 63

PAGE 69

* need not be done in this method as it is done within the template method, NewGame(). See the Temp l a e Method (325)<1B> pattern for more details. @see BGFBoard#NewGame @param I protected { pPlayers The players involved in che game void NewGameHook(BGFPlayer[] pPlayers) } I** Clear the board. This method calls ClearSpace on each space on the board. @see BGFSpace I protected void ClearSpaces() { int i,j; for (i=O;i<_rows;i++) { for (j=O;j<_cols;j++) { _spaces[i] [j] .ClearSpace(); II keep crack of the number of rows and columns for easy access protected int _rows; protected int _cols; II all of the spaces on the board protected BGFSpace[J (] _spaces; II ensure the instance is created by Instance() private static boolean _createinstance = false; II the singleton instance static BGFBoard _instance; II the Class set by Configure() and used by Instance() static Class _class; BGFBoardEnumeration I* BGFBoardEnumeration.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; import java.util.Enumeration; import java.util.NoSuchElementException; I** An iterator for accessing all spaces on a board. See the 64

PAGE 70

* Iterator (257)<1B> pattern for more information. w @author
Dave Wood< IA> I public class BGFBoardEnumeration implements Enumeration I** Create an iterator over the specified BGFBoard. Initialize members and determine if there are any elements. @param pBoard The board over which the enumeration will occur I public BGFBoardEnumeration(BGFBoard pBoard) { I** _board = pBoard; _curRow = 0 ; _curCol = 0; _rows= _board.GetNumRows(); cols = _board.GetNumColumns(); if ((_rows == 0) II (_cols == 0)) _moreElements false; else _moreElements true; Determines whether there are any more elements in the enumeration. @return true if there are more elements in the enumeration; false otherwise I public boolean hasMoreElements() { return _moreElements; I** Retrieves the next element in the enumeration. Thi3 iterator first traverses all columns for the current row, the moves to the next row, starting with the first column. @return the next BGFSpace object in this enumeration I public Object nextElement() { if (_moreElements == false) throw new NoSuchElementException(); BGFSpace current= _board.GetSpace{_curRow, _curCol); _curCol++; if (_curCol == _cols) { _curCol = 0; _curRow++; if {_curRow == _rows) _moreElements = false; return current; II private members private int private int private boolean to track the current state of the enumeration _curRow; _curCol; _moreElements; 65

PAGE 71

II reference to the board private BGFBoard _board; private int being enumerated and its size private int BGFBoardView I* BGFBoardView.java Board Game Framework Dave Wood 1996 *I package EDU.cudenver.BGF; import java.awt.*; import java.util.Observer; import java.util.Observable; _rows; _cols; import java.util.NoSuchElementException; I** The abstraction for the "view" representation of game board. Contains a reference to each BGFSpaceView object. @author
Dave Wood @sec @see BGFSpaceView BGFBoard *I public class BGFBoardView extends Canvas implements Observer I** Create a "view" for the given BGFBoard "model" class. This constructor creates BGFSpaceView objects for each BGFSpace contained by the input BGFBoard object. In addition, it registers itself with the BGFBoard and with each BGFSpace using the Observer interface (see the Observer (293)<1B> design pattern). This will allow this object to be notified any time the state of the board has been changed. @param pBoard The "model" board this "view" will observe. @see @see @see BGFBoard BGFSpaceView BGFFactor y *I public BGFBoardView ( BGFBoard int int pBoard, pWidth, pHeight board = pBoard; _board.addObserver(this); rows= _board.GetNumRows(); _col s = _board.GetNumColumns(); _spaces= new BGFSpaceView[_rows) [_cols); _width = pWidth; 66

PAGE 72

I** _height = pHeight; BGFFactory factory BGFFactory.Instance(); int curRow 0; int curCol 0; II II iterate over the BGFSpace objects, creating a BGFSpaceView object II for each one. II try { BGFBoardEnumeration enum = _board.GetBoardEnumeration(); while (enum.hasMoreElements() == true) { BGFSpace space= (BGFSpace)enum.nextElement(); space.addObserver(this); _spaces[curRow] [curCol] = factory.CreateSpaceView(this, space); curCol++; if (curCol == _cols) { curCol = 0 ; curRow++; catch (NoSuchElementException e) { System.out.println("Major internal problem. Exception: "+e); System. exit ( 1); Return the preferred size for this canvas. The preferred size is the size specified by the call to the constructor. I public Dimension preferredSize() { return new Dimension(_width, _height); I** Return the size for this canvas. The minimum size is the size specified by the call to the constructor. I public Dimension minimumSize() { return new Dimension(_width, _height); I** Handle notification of state change from the model. The BGFBoard looks for BGFGameOverStatus objects as input to the update() method. If such an object is passed, the ShowGameOver() method is called to show the current game-over status of the game. @see @see BGFGameOverStatus BGFBoardView#ShowGameOver I public void update ( Observable Object pObserverable, pObject 67

PAGE 73

if (pObject instanceof BGFGarneOverStatus) { BGFGarneOverStatus over = (BGFGarneOverStatus)pObject; ShowGarneOver(over); /** Called in response to repaint() method call. This method overrides the default update() behavior by not clearing the board for redraw. This eliminates much of the flicker associated with repainting the board. @pararn pGraphics The Graphics object to be painted I public void update(Graphics pGraphics) { paint(pGraphics); /** Handle the mouseDown event. When the mouse is clicked on the board, call CheckClick() to pass the click to the appropraite BGFSpaceView object. @see BGFBoardView#CheckClick I public boolean mouseDown ( /** Event pEvent, int pX, int pY if (CheckClick(pX,pY) return true; else return false; true) Determine which, if any, space on the board has been clicked. This method iterates over the spaces of the board, asking each space if the coordinate of the "click" which was received falls in the spaces' s area. If so, the BGFSpace object represented by the clicked BGFSpaceView is passed to ther BGFGarneMaster object using the SpaceSelected() method. @param pX @pararn pY @see @see @see / BGFSpaceView BGFSpace BGFGarneMaster Selected X coordinate Selected Y coordinate protected boolean CheckClick ( int pX, int pY int curRow = 0; int curCol = 0; for (curRow = 0; curRow < _rows; curRow++) { for (curCol = 0; curCol < _rows; curCol++) 68

PAGE 74

I** if (_spaces[curRow] [curCol].PointinSpace(pX, pY) == true) BGFCommandProcessor cp = BGFCommandProcessor.Instance(); BGFCommand command = new BGFSpaceSelectedCommand( _spaces[curRow] [curCol] .GetSpace()); cp.SubmitCommand(command); return true; return false; Paint the board and the spaces on the board. This method first draws the empty board to the screen and then draws the space which has requested a repaint if there is one. If not, all spaces are drawn. *When painting has completed, notifyAll() is called to wake up the waiting repaint() method. @param pGraphics The Graphics object onto which the board will be drawn. @see @see BGFBoardView#Draw BGFSpaceView *I public void paint(Graphics pGraphics) { I** I I If a space-specific paint was asked for, but more is needed, paint II the whole board. if (_repaintSpace != null) { if (_repaintSpace.GetRect() .equals(pGraphics.getClipRect())==false) _repaintSpace = null; Image image= createimage(_width, _height); Graphics imageGraphics = image.getGraphics(); Draw(imageGraphics); if (_repaintSpace ==null) II draw all the spaces { for (int row=O;row<_rows;row++) for (int col=O;col<_cols;col++) _spaces[row] [col] .Draw(imageGraphics); else II just draw the space which asked to be drawn { _repaintSpace.Draw(imageGraphics); _repaintSpace = null; _painted = true; pGraphics.drawimage(image, 0, 0, null); synchronized(this) { notifyAll(); Draw the board on the input Graphics context. Subclasses of BGFBoardView must implement this method to draw the game board 69

PAGE 75

on the screen. @param pGraphics I The Graphics onto which the board is to be drawn. public void Draw(Graphics pGraphics) { } I** Visually show the game-over status for the current game. This method calls ShowGameOver() on each of the spaces and then repaints the screen. @param pGameOver The game-over status of the current game. @see BGFSpaceView I protected void ShowGameOver(BGFGameOverStatus pGameOver) { I** for (int i=O;i<_spaces.length;i++) { for (int j=O;j<_spaces[i] .length;j++) { if (_spaces[i] [j] .ShowGameOver(pGameOver) RepaintSpace(_spaces[i] [j]); true) Makes a request to repaint the component and waits for the paint to occur. This version of r epaint() calls the default method and waits for paint() send notification that the painting has completed. This method also ensures that calls to repaint() not made by RepaintSpace() don't get missed by the fact that _repaintSpace has been set. If two conflicting calls occur at the same time, the call from RepaintSpace() (which will be restricted to a single space) is dropped so that the whole board will be redrawn. @param pMS Maximum delay in milliseconds before update() method is called @param pX The x-coord of the rect to repaint @param pY The y-coord of the rect to repaint @param pWidth The width of the rect to repaint @par am pHeight The height of the rect @see BGFBoardView#paint public void repaint ( long pMS, int pX, int pY, int pWidth, int pHeight _painted = f alse; super.repaint( p MS, pX pY ,pWidth, pHeight); II wait for the paint to finish synchronized(this) { try { 70 to repaint the

PAGE 76

while (!_painted) wait(); II wait for paint to complete _painted = false; catch ( InterruptedException e) {} I I interrupt is okay I** Request that a specific space be repainted. This method calls repaint() for the rectangle represented by the input space. @param pRepaintSpace The space to be repainted I public synchronized void RepaintSpace(BGFSpaceView pRepaintSpace) { _repaintSpace = pRepaintSpace; Rectangle rect = _repaintSpace.GetRect(); repaint(rect.x, rect.y, rect.width, rect.height); II The board being observed protected BGFBoard _board; II The spaces on this board view protected BGFSpaceView[] [] _spaces; II board size protected int _rows; protected int _eels; II board size (graphically) protected int _width; protected int _height; II used by repaint() and paint() private boolean _painted; private BGFSpaceView _repaintSpace null; 71

PAGE 77

BGFConunand / * BGFCommand.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; /** A simple abstraction for representing basic commands (typically used f o r requests from the G UI). See the Command (2 33) design pattern or the Command Processo r pattern in the B uschmann et. al. patterns book. @author < A HREF= "mailto:wood@cgi.com">Dave Wood
I abstract public class BGFCommand implements Runnable !** Creat e a new thread using this object and start the thread. I public void Execut e() { /** Thread t =new Thread(this); t .start() ; Run the command by calling ExecuteHook(). I p ubli c void r un() { ExecuteHook(); !** Execute the c o mmand. Subclasses of BGFCommand do thei r work in this method. I abstract protected void ExecuteHook(); BGFConunandProcessor * BGFCommandProcessor.java Board Game Framework Dave Wood 1996 *I package EDU.cudenver.BGF; ** A simple class responsible for executing basic BGFCommands. This class 72

PAGE 78

* is a simplistic implementation of the Command Processor class in the Command Processor design pattern from the Buschmann et. al. patterns book (or the Invoker class in the Command (233)<1B> design pattern. The class is also a Singleton (127)<1B> class (i.e. there is only a single instance *of this class for any applet.) @author Dave Wood< IA> @see BGFCommandProcessor I public class BGFCommandProcessor { I** Return the singleton instance of the class. If this is the first *call to Instance(), the instance is created before it is returned. @return The single instance of this class I public static BGFCommandProcessor Instance() { I** if (_instance == null) { instance= new BGFCommandProcessor(); return _instance; Execute a BGFCommand. Call the Execute method on the input command. @param pCommand The BGFCommand to be executed I public void SubmitCommand(BGFCommand pCommand) { pCommand.Execute(); II The Singleton instance of this class private static BGFCommandProcessor _instance; BGFFactory I * BGFFactory.java Board Game Framework Dave Wood 1996 I package EDU.cudenver. BGF; I** An Abstract Factory (87)<1B> class used to create various objects used by the Board Game Framework. This class defines a number of abstract methods used for the instantiation of concrete instances of various abstract BGF classes which must be implemented by the application. @author @see @see Dave Wood< IA> BGFBoard BGFBoardView 73

PAGE 79

* @see @see @see @see BGFSpace BGFSpaceView BGFPieceView BGFPlayer I public abstract class BGFFactory { /** Return a concrete BGFBoardView object for the primary board display. This method should simply instantiate a subclass of BGFBoardView and return the instance. If additional views of the same board are desired, they must be managed directly by the application (the framework creates only a single view. @param pBoard A BGFBoard object which must be passed on to the BGFBoardView constructor. It is this "model" class which will notify the view object of changes to the state o f the board. @return A new instance of a BGFBoardView subclass I public abstract BGFBoardView CreateBoardView(BGFBoard pBoard); /** Return a new concrete BGFSpace object representing the space on the board at the specified coordinates. This method creates an instance of BGFSpace with the given row/column. Subclass may override this class if they create their own BGFSpace subclasses. @param pRow @param pColumn The row on the board in which this space is located. The column on the board in which this space is located. @return A new instance of a BGFSpace subclass I public BGFSpace CreateSpace(int pRow, int pColumn) { return new BGFSpace(pRow, pColumn); /** Return a new concrete BGFSpaceView object responsible for the display of a given space on the board. This method should simply instantiate a subclass of BGFSpace and return the instance. @param pBoardView @param pSpace A BGFBoardView object which must be passed on to the BGFSpaceView constructor. This object contains references to all of the BGFSpaceView objects on the board. A BGFSpace object which must be passed on to the BGFSpaceView constructor. It is this "model" class which will notify the view object of changes to the state of the space. @return A new instance of a BGFSpaceView subclass *I public abstract BGFSpaceView CreateSpaceView( BGFBoardView pBoardView, BGFSpace pSpace); /** Return a new concrete BGFPieceView object responsible for the display of a given piece. This method should simply instantiate a subclass of BGFPieceView and return the instance. @param pPiece A BGFPiece object which must be passed on 74

PAGE 80

to the BGFPieceView constructor. @return A new instance of a BGFPieceView subclass I public abstract BGFPieceView CreatePieceView(BGFPiece pPiece); I** Return an array o f new concrete BGFPlayer objects. This method should simply instantiate an array of concrete BGFPlayer objects and return the array. @return An array of new instances of BGFPlayer subclasses I public abstract BGFPlayer[] CreatePlayers(); I** Return an array of new concrete BGFStrategy objects. This method should instantiate an array of concrete BGFStrategy objects and return the array. The objects returned are used in two ways: 1 ) To obtain a list of strategy names to present to the used, and 2) T o obtain class to instantiate new instances of the strategies provided. The actual instances created here are not used (therefore, data members other than the name are never accessed) @return An array of sample instances of BGFStrategy subclasses I public abstract BGFStrategy[] CreatePrototypeStrategies(); I** c=eate a new BGFMovePieceMove object. creates a BGFMovePieceMove instance. of a subclass of BGFMovePieceMove. The default implementation Subclasses may create an instance @param @param @param @param @param I pMoveCon pPlayer pPiece pFromSpace pToSpace The controller which created The player making the move The piece being moved The space the piece The space the piece public BGFMovePieceMove CreateMovePieceMove ( I** BGFMoveController BGFPlayer BGFPiec e BGFSpace BGFSpace pMoveCon, pPlayer, pPiece, pFromSpace, pToSpace return new BGFMovePieceMove( pMoveCon, pPlayer, pPiece, pFromSpace, pToSpace); is is to to be be this move moved from moved to Set the Class object which should be used to to instantiate a single concrete BGFFactory object. Thi s method simply stores the Class refernce for future use b y the Instance() method. @see BGFFactory#Instance *I public static synchronized void Configure(Class pClass) { _class = pClass; instance = null; 7 5

PAGE 81

I** Return the Singleton instance of the configured BGFFactory subclass. The first time this static method is called, it attempts to create an instance of the configured BGFFactory subclass using the w Class.newinstance method. If it is unable to do so, it outputs an error message and returns null. This will generally result in a NullPointerException when the caller attempts to use the returned instance. This is the appropraite behavior as it will halt execution of the applet which cannot execute properly until the code is fixed to properly configure the factory. Subsequent calls to this method simply return the single instance created in the first call. This concept is descrbed in the Singleton (127)<1B> pattern. @return The singleton instance of a BGFFactory subclass *I public static synchronized BGFFactory Instance() { I** if (_instance == null) { try { } _createinstance = true; _instance= (BGFFactory)_class.newinstance(); _createinstance = false; II Do nothing ... caller will generate a NullPointer exception II and halt the applet (this is the only reasonable thing to II do since we can't continue without a factory) catch (IllegalAccessException e) { System.out.println("BGF Application Error. Invalid factory."); catch (InstantiationException e) { System.out.println("BGF Application Error. Invalid factory."); return _instance; Create a new factory. This method should only be called by the Instance() method to create a new BGFFactory subclass. If a subclass *tries to call it directly (via a super() call in a constructor), it will throw an exception. The creation of the instance is synchronized *on the class (which is locked by Instance()) to ensure that a race condition will not allow invalid access. * @exception BGFinvalidSingletoninstantiationException Thrown if this method is called by any method other than the static Instance() method. @see BGFFactory@Instance I protected BGFFactory() throws BGFinvalidSingletoninstantiationException { II synchronized so that new() cannot be used to create an instance II immediately after the Instance() method sets _createinstance to II true, but before it calls this constructor synchronized(getClass()) { if (BGFFactory._createinstance == false) throw new BGFinvalidSingletoninstantiationException(); 76

PAGE 82

I I The Class to be set by a call to Configure() private static Class _class; II The singleton instance to be created by Instance() private static BGFFactory _instance; II So we only create the instance once private static boolean _createinstance; BGFGUIStrategy I* BGFGUIStrategy.java Board Game Framework Dave Wood 1996 *I package EDU.cudenver.BGF; I** An abstraction for players who receive input from the GUI when a space on the board is selected. @author
Dave Wood I public abstract class BGFGUIStrategy extends BGFStrategy I** Create a GUI Strategy. Sets the name to "Human" to since this is a human pl3yer. I public BGFGUIStrategy() { super(kHumanStrategyName); I** Create a GUI Strategy with a non-default name. @param pName The name of this strategy I public BGFGUIStrategy(String pName) { super(pName); I** Accept a selected space from the GUI Store the input space in the object and call notify() to wake up the MoveHook() method. @param pSpace The space clicked on the GUI @see BGFGUIStrategy#MoveHook *I public synchronized void AcceptSpaceSelection(BGFSpace pSpace) { if (_moveThread != null) 77

PAGE 83

I** _gotGUIInput = true; _selectedSpace = pSpace; notify(); II wake up MoveHook() Create a BGFMove based on GUI input. This method "waits" until input is received from the GUI. When input is received, it calls HandleSpaceSelection(), an abstract method responsible for handling clicks by the user. This is done to allow different BGFGUIStrategies to respond to single clicks (simply placing a new piece on the board) or to multiple clicks (moving a piece from one space to another). This method is synchronized to allow it to call wait() when no GUI input is available. @see @see BGFGUIStrategy#HandleSpaceSelection BGFGUIStrategy#AcceptSpaceSeleccion I protected synchronized void MoveHook() { I** II Start with n o GUI input _gotGUIInput = false; while (!_gotGUIInput) { II II wait for GUI input (nocify() called by AcceptSpaceSeleccion II or BGFStrategy.AbortMove()) II try { wait (); catch (IllegalMonitorStateException e) { System.out.println("IllegalMonitorStateException"); Thread.currentThread() .dumpStack(); catch (InterruptedException e) { System.out.println("InterruptedException"); Thread.currentThread() .dumpStack(); _gotGUIInput = false; if (HandleSpaceSelection() MoveHook(); false) I I move not submitted Handle the fact that a space on the GUI has been selected. This abstract method allows different classes to respond to different numbers and sequences of space selections. *@return true if a move has been submitted (via TryMove()), false if not. I abstract protected boolean HandleSpaceSelection(); I I have we received GUI input? protected boolean _gotGUIInput false; II which space was selected? protected BGFSpace _selectedSpace; II player name 78

PAGE 84

protected static final String kHumanStrategyName "Human ; BGFGameMaster I * BGFGameMaster.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; I** The controller of the game. The singleton instance (see the Singleton (127)<1B> design pattern) of this class is responsible for obtaining moves from each player in sequence. In addition, it is responsible for additional communication with the BGFPlayer objects involved in the game. This includes notification of GUI input, as well *as notification of "take-backs". The issue of taking back moves leads to some complicating multi-threading issues between the BGFGameMaster and the BGFPlayer objects. @author
Dave Wood< IA> @see BGFPlayer I public final class BGFGameMaster I** This constructor is private so that instances may only be created using the Instance() method. See the Singleton (127) < 1B> design pattern. I private BGFGameMaster() { } I** Return the singleton instance of the class. If this is the first *call to Instance(), the instance is created before it is returned. @return The singleton instance of this class I static public synchronized BGFGameMaster Instance() { if (_instance == null) { instance= new BGFGameMaster(); return _instance; I** Set the players to be involved in the next new game. @param pPlayers I An array of BGFPlayer objects to be involved in the next new game. The order of the array indicates the order the players will play, starting with pPlayers[OJ public synchronized void SetPlayers(BGFPlayer[] pPlayers) 79

PAGE 85

_players pPlayers; I** Check to see if the players have been set. I public synchronized boolean ReadyForPlay() ( return _ready; I** Stop the current game (if any) and start a new one. If there is a game in progress, an attempt is made to abort the current move. I f this is successful, the board and move log are cleared and the _newGame member variable is set to true. The Play() method checks this variable using the synchronized AfterMoveUpdates() method. If the attempt to abort the current move fails (if the move is made at just the instant that the new game is requested, the NewGame() request fails and does nothing. If there is no game in progress, a notify() call is made to wake-up the main thread sleeping in the WaitForNewGame() method. @see @see @see @see @see @see I BGFGameMaster#Play BGFGameMaster#AfterMoveUpdates BGFGameMaster#WaitForNewGame BGFPlayer BGFBoard BGFMoveProcessor public synchronized void NewGame() ( I** if (!_gameOver) ( else ( boolean aborted if (aborted) _players[_currentPlayerindex) .AbortMove(); ( } II At this point, Play() is blocked on AfterMoveUpdates() II reset the board and move processor BGFBoard board= BGFBoard.Instance(); BGFMoveProcessor mp = BGFMoveProcessor.Instance(); board.NewGame(); mp.NewGame(); _newGame = true; II else, we were unable to abort the current move, so the II NewGame request fails. BGFBoard board= BGFBoard.Instance(); BGFMoveProcessor mp = BGFMoveProcessor.Instance(); board.NewGame(); mp.NewGame(); _currentPlayerindex = 0; notify(); II wake up WaitForNewGame() _ready = true; Play a game. This is the main driver method for any game. It iterates over the players in the game requesting moves. When the game is *over (according to BGFBoard.GameOver(}), or a new game is requested, the method returns and may be called again for a new game. 80

PAGE 86

* I public synchronized void Play() { I** I I initialize some things ... _gameOver = false; _gameAborted = false; _newGame = false; BGFBoard board= BGFBoard.Instance(); BGFGameOverStatus status; int threadiD = 0; II start the game . while (((status= board.GameOver()) .IsGameOver() (_gameAborted ==false)) { threadiD++; II informational only false) && II Start a new move. Run it at a lower priority to allow II TakeBack() to have a higher priority and stop the thread II if needed Thread moveThread =new Thread(_players[_currentPlayerindex], "BGF Move Thread#"+ threadiD); moveThread.setPriority(Thread.NORM_PRIORITY-1); _moveAborted = false; moveThread.star t(); II wait for the moveThread to teminate. This will happen for II one of two reasons: (1) the move had successfully been II made, or (2) the move has been aborted, resulting i n a call II to Thread.stop() on the thread. _moveCompleted = false; try { while (!_moveCompleted) wait(); catch (InterruptedException e) { II System.out.println("Interrupted Exception!"); Thread.currentThread() .dumpStack(); II The move thread has now stopped. II AfterMoveUpdates(); II synchronized _gameOver = true; _ready = false; II note: at this point _currentPlayerindex represents the player II who would have played next had the game not just ended Interrupt the current play and take back the last move. If there is no game in progress, an attempt is made to take back the last move of the previous game. If this is successful, notify() is called to wake up the main thread waiting in WaitForNewGarne(). If there is a game in progress, an attempt is made to abort the current move. If this is successful, the last move is taken back. Then, the method *calls wait(), allowing Play() to continue and call AfterMoveUpdates(). This is done to ensure that the Play() routine is in a stable state before another TakeBack() call can be made. After Play() calls AfterMoveUpdates(), it makes a notify() call to allow this method to exit. 81

PAGE 87

w @see w @see @see @see w @see @see I BGFGameMaster#Play BGFGameMaster#AfterMoveUpdates BGFGameMaster#WaitForNewGame BGFMoveProcessor BGFBoard BGFPlayer public void TakeBack(int pCount) { synchronized (this) II one take-back at a time, please { if (_inTakeBack) return; inTakeBack = true; if (_gameOver) II taking back the final move of the game { BGFMoveProcessor mp = BGFMoveProcessor.Instance(); i f (mp.UndoMove() == true) { II II let the Board know that the game's not over anymore II BGFBoard board= BGFBoard.Instance() ; board.GameOverUndone(); I I II decrement the player index since the current II player should be the player who made t h e winning move II DecrementCurrentPlayerindex(); II take back any additional moves requested for (int i=l;i
PAGE 88

break; MoveCompleted(); inTakeBack false; I** Abort the current game. If there is a game in progress, this method aborts the current move, sets the _gameAborted flag to true (if it was able to abort the move) and calls MoveCompleted() which wakes up the Play() method. @see @see BGFGameMaster#Play BGFGameMaster#MoveCompleted I public synchronized void AbortGame() { I** if (!_gameOver) I I taking back the final move of the game ( I I abort the current move boolean aborted= _players[_currentPlayerindex).AbortMove(); II check to see if the move was, in fact, aborted (it may have II either ignored the abort, or finished before the abort II was sent) if (aborted) { _gameAborted = true; MoveCompleted(); Wait for a new game to be requested (or for the last move of the previous game to be undone). This method simply calls wait() and exits when a notify() call is made. I public synchronized void WaitForNewGame() { I** try { wait(); catch (InterruptedException e) { } Accepts a BGFSpace object and passes it on to the current player. Note that any space selection is sent t o the current player. If the current player is not a GUI player, the input should be ignored. * @param pSpace The space which has been clicked @see BGFPlayer I public synchronized void SpaceSelected(BGFSpace pSpace) ( if (_players != null) _players[_currentPlayerindex) .AcceptSpaceSelection(pSpace); 83

PAGE 89

I** Update the state of BGFGameMaster after a completed or aborted move. This method first checks to see if a new game has been requested. If so, the _currentPlayerindex is reset to 0 and nothing further is done. Otherwise, a check is made to see if the last move was aborted. If so, _currentPlayerindex is decremented so that the same player will play again in the next iteration. Finally, a check is made to see if a move has been taken back. If so, _currentPlayerindex is decremented to get back to the player who should make the next move. Note that aborting the current move and taking back the previous move result in _currentPlayerindex being decremented twice. This is the desired behavior. *I private synchronized void AfterMoveUpdates() ( I** if ( _newGam e == true) ( II newGame = false; _currentPlayerindex = 0; return; II don't do the next two checks ... II both of the following 'if' statements will evaluate to 'true' I I if a move has been taken back successfully II if (_moveAborted) ( DecrementCurrentPlayerindex(); } if (_movesTakenBack > 0) ( for (int i=O;i<_movesTakenBack;i++) DecrementCurrentPlayerindex(); _movesTakenBack = 0; II finally, move on to the next player ... IncrementCurrentPlayerindex(); Set the player index to the next player. When the end of the array of players is passed, this method sets the current player index back to 0. I private void IncrementCurrentPlayerindex() ( I** _currentPlayerindex++; if (_currentPlayerindex == _players.length) _currentPlayerindex = 0; Set the player index to the previous player. When the beginning of the array of players is passed, this method sets the current player index back to the last player in the array. I private void DecrementCurrentPlayerindex() ( I** _currentPlayerindex--; if (_currentPlayerindex < 0) _currentPlayerindex _players.length-1; 84

PAGE 90

* Notify Play( ) that a move has been completed. This method sets the _moveCompleted variable to true and calls notifyAll(). I public synchronized void MoveCompleted() { I** _moveCompleted = true; notifyAll(l; Find out if there is a game in progress. I public boolean GamelnProgress() { return !_gameOver; II set to the number of moves taken back private int _movesTakenBack = 0 ; II set to true when a new game has been requested private boolean _newGame = false; II set to true when there is no game currently being player private boolean _gameOver = true; II an index into the _players array indicating the player currently moving private int _currentPlayerindex = 0; II array (in order) of players involved in the current game private BGFPlayer[) _players null; II the singleton instance of this class static private BGFGameMaster .instance; I I private boolean _gameAborted private boolean _moveAborted false; false; private boolean inTakeBack = false; private boolean _moveCompleted = false; private boolean _ready = false; BGFGameOverStatus I * BGFGameOverStatus.java Board Game Framework Dave Wood 1996 *I package EDU.cudenver.BGF; I** A representation of the 'game-overness' of the current game. This class stores a boolean value indicating whether or not the game is over. In addition, a reference to the winning player (if any) is stored. While this is not an abstract class, applications using the BGF are encouraged to subclass BGFGameOverStatus to store additional, pertinent data (e.g. the pieces or spaces involved in makeing the game "over"). 85

PAGE 91

* @author
Dave Wood< IA> @see BGFPlayer I public class BGFGameOverStatus { I** Create a new status object. This constructor takes the boolean status as well as a reference (possibly null) to the winning player and stores them in member variables. @param @param pGameOver pWinner Indicates whether or not the game is over Indicates the winning player (or null if there is no winning player) I public BGFGameOverStatus ( I** boolean BGFPlayer pGameOver, pWinner _gameOver = pGameOver; _winner Create a status representing a game which is NOT over. I public BGFGameOverStatus() { I * _gameOver = false; _winner null; Return a boolean value indicating whether or not the game is over. @return A boolean value indicating whether or not the game is over I public boolean IsGameOver() { return _gameOver; I** Return the winner (possibly null) of the game. @return The BGFPlayer representing the winning player (or null if the game is not over or if the game ended in a draw) I public BGFPlayer GetWinner() { return _winner; I** Set the game-over status. @param pGameOver I A boolean value indicating whether or not the game is over public void SetGameOver(boolean pGameOver) { _gameOver = pGameOver; I** 86

PAGE 92

* Set the winner of the game. @param pWinner I The BGFPlayer who has won the game (or null if there is no winner) public void SetWinner(BGFPlayer pWinner) { _winner = pWinner; II State variables private boolean _gameOver; private BGFPlayer _winner; BGFinvalidSingletoninstantiationException I* BGFWhoPlaysDialog.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; I** Exception class thrown when.an application attempts to craete an instance of a class intended to be a Singleton without going through the Instace() interface. This only applies to Abstract Singletons, since concrete Singleton classes avoid to problem by making their constructors hidden. I public class BGFinvalidSingletonlnstantiationException extends Exception BGFMove I * BGFBoard. java Board Game Framework Dave Wood 1996 *I package EDU.cudenver.BGF; I** Abstraction for a single move in a board game. An instance of a subclass of BGFMove is created for each move in the game. The moves are stored by the BGFMoveProcessor, allowing moves to be taken back or saved. This class corresponds to the Command class in the Command (233)<1B> design pattern (or, more precisely, to Abstract Command in the Buschmann et. al. *patterns book.) * @author
Dave Wood< IA> @see BGFMoveController 87

PAGE 93

* I abstract public class BGFMove { I** Create a new move. The input BGFMoveController represents the object which will be notified if the move is invalid. @param pMoveCon The BGFMoveController to be notified if an illegal move or an illegal take-back is attempted. *I public BGFMove(BGFMoveController pMoveCon) { _moveCon = pMoveCon; I * Execute the move. This method calls the abstract HookExecute() method and then notifies the BGFMoveController if HookExecute() returns false. @return true if the move executes successfully, false otherwise @see @see I BGFMove#HookExecute BGFMoveController final boolean Execute() { boolean valid = HookExecute(); if (valid == false) _moveCon.NotifyinvalidMove(this); return valid; I*+ Undo the move. This method calls the abstract HookUndo() method and then notifies the BGFMoveController if HookUndo() returns false. @return true if the move is undone successfully, false otherwise @see @see I BGFMove#HookUndo BGFMoveController final boolean Undo() { boolean valid= HookUndo(); if (valid == false) _moveCon.NotifylnvalidUndo(this); return valid; I** Execute the move. This is an abstract method to do the work of executing the move. Subclasses of BGFMove must implement this method to return true if the move executes successfully and false if not. @return true if the move executes successfully, false otherwise @see BGFNewPieceMove#HookExecute I public abstract boolean HookExecute(); I** Undo the move. This is an abstract method to do the work of undoing the move. Subclasses of BGFMove must implement this method to return true if the move is undone successfully and false if not. 88

PAGE 94

* @return true if the move is undone successfully, false otherwise * @see BGFNewPieceMove#HookUndo I public abstract boolean H ookUndo(); II The BGFMoveController to be notified if Execute/Undo fail protected BGFMoveController _moveCon; BGFMoveController / * BGFMoveController.java Board Game Framework Dave Wood 1996 I package EDU.cudenver. BGF; /** An abstraction for objects which create commands. More specifically, classes implementing the BGFMoveController interface must provide methods which handle invalid move execution o r undo. In the BGF, BGFPlayer classes implement the BGFMoveController interface. C lasses responsible for loading saved games would also need to implement t his interface. @author
Dave Wood< /A> I public interface BGFMoveController { /** Handle notification that the given move was invalid. @param pMove The BGFMove which failed to execute I void NotifyinvalidMove(BGFMove pMove); /** Handle notification that the given move was unable to be undone. @param pMove The BGFMove which failed to be undo I void NotifyinvalidUndo(BGFMove pMove); BGFMovePieceMove I* BGFMovePieceMove.java Board Game Framework Dave Wood 1996 *I package EDU.cudenver.BGF; 89

PAGE 95

I** A move involving the placement of a piece onto the board for the first time. This class can be used in games such as Tic-Tac-Toe or Othello in which pieces are not moved, but are instead simply placed on the board. @author
Dave Wood< IA> I public class BGFMovePieceMove extends BGFMove I** Create a new BGFMovePieceMove. Inputs includes the piece being placed on the board, the space onto which the piece is to be placed, and the BGFMoveController creating the move. @param pMoveCon The BGFMoveController to be passed on to the BGFMove constructor @param @param pPiece pSpace The BGFPiece bring added to the board The BGFSpace the upon wh ich the piece is to be placed I public BGFMovePieceMove ( I** BGFMoveController BGFPlayer BGFPiece BGFSpace BGFSpace pMoveCon, pPlayer, pPiece, pFromSpace, pToSpace super(pMoveCon); _player = pPlayer; _piece = pPiece; _fromSpace = pFromSpace; _toSpace = pToSpace; Execute the move by placing the piece on the space. @return true if the attempt to place the piece on the space was successful; false if not. @see BGFSpace#PlacePiece *I public boolean HookExecute() { I** if (_piece.IsMoveableBy(_player) return false; if (_fromSpace.GetPiece() !=_piece) return false; i f (_piece.IsMoveableTo(_toSpace) return false; return MakeMove(); false) false) Move the pieces. By default, this method removes the place from the old space and places it on the new space. This may be overridden of other things must happen @return true if move is completed successfully, else if not *I 90

PAGE 96

protected boolean MakeMove{) ( I** if {_toSpace.PlacePiece{_piece) return false; _fromSpace.ClearSpace{); return true; false) Undo the move by removing the piece from the space. This method may be overridden by subclasses needing to perform alternate actions. @return true if the attempt to remove the piece from the space was successful; false if not. @see BGFSpace#RemovePieceForUndo I public boolean HookUndo{) ( if {_toSpace.RemovePieceForUndo{) return false; _fromSpace.PlacePiece{_piece); return true; II needs work false) II The space and piece involved in the move protected BGFPiece _piece; protected BGFSpace _fromSpace; protected BGFSpace _toSpace; protected BGFPlayer _player; BGFMoveProcessor I * BGFMoveProcessor.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; import java.util.Stack; I** A class which activates BGFMove objects and maintains a list of moves for undo or history purposes. This class corresponds to the Invoker in the Command {237)<1B> design pattern {or, more directly, to the Command Processor class in the Buschmann et. al. patterns book). *Also see the Singleton {l27)<1B> design pattern. @author
Dave Wood *I public class BGFMoveProcessor { I** Return the singleton instance of this class. If this is the first *call to Instance{), the instance is created before it is returned. Note that the constructor for this class in non-public, so this is the only way to obtain a BGFMoveProcessor instance. 9 1

PAGE 97

@return The single instance of this class I public static BGFMoveProcessor Instance() { if (_instance == null) { instance= new BGFMoveProcessor(); return _instance; /** Initialize the BGFMoveProcessor object. A new Stack is created to hold moves. This method is protected. The only way for a user to create obtain an instance of this class is by calling the static Instance() method. @see @see I BGFMoveProcessor#Instance java.util.Stack protected BGFMoveProcessor() { _moves= new Stack(); ; Submit a BGFMove object for execution. Execute the input move and push it on the stack only if it executes legally. @param pMove The move to be executed and stored @see BGFMove I public void SubmitMove(BGFMove pMove) { ; boolean valid= pMove.Execute(); if (valid == true) _moves.push(pMove); Attempt to undo the last move. If there are moves on the stack, attempt to undo the move on the top of the stack. If the undo fails, or if there are no moves on the stack, return false, otherwise, return true and pop the move off the stack. @return true if a move was undone, false if there was no move to undo or i f the undo attempt failed @see BGFMove I public boolean UndoMove() { if (_moves.size() > 0) { BGFMove toUndo = (BGFMove)_moves.peek(); boolean valid= toUndo.Undo(); else if (valid == true) { _moves.pop(); return true; else return false; return false; 92

PAGE 98

I** Clear the stack to begin a new game. I public void NewGame() ( _moves.removeAllElements(); II singleton instance private static BGFMoveProcessor _instance; II moves which have been made private Stack _moves; BGFNewGameCommand I * BGFNewGameCommand.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; I** Represents a request for a new game to begin. When executed, this command notifies the BGFGameMaster that a new game is to be started. @author
Dave Wood I public class BGFNewGameCommand extends BGFCommand I** Execute the new game command. Obtain a reference to the singleton instance of BGFGameMaster and call NewGame(). @see BGFGameMaster I public void ExecuteHook() ( BGFGameMaster gm = BGFGameMaster.Instance(); gm.NewGame(); BGP'NewPieceMove I* BGFNewPieceMove.java Board Game Framework Dave Wood 1996 *I 93

PAGE 99

package EDU.cudenver.BGF; I** A move involving che placement of a piece onto the board for the first time. This class can be used in games such as Tic-Tac-Toe or Othello in which pieces are not moved, but are instead simply placed on the board. * @author
Dave Wood *I public class BGFNewPieceMove extends BGFMove I** Create a new BGFNewPieceMove. Inputs includes the piece being placed on the board, the space onto which the piece is to be placed, and the BGFMoveConcroller creating the move. @param pMoveCon @param @param pPiece pSpace I public BGFNewPieceMove ( I** BGFMoveController BGFPiece BGFSpace super(pMoveCon); _piece pPiece; _space = pSpace; The BGFMoveController to be passed on to the BGFMove constructor The BGFPiece bring added to the board The BGFSpace the upon which the piece is to be placed pMoveCon, pPiece, pSpace Execute the move by placing the piece on the space. @return true if the attempt to place the piece on the space was successful; false if not. @see BGFSpace#PlacePiece I public boolean HookExecute() ( return _space.PlacePiece(_piece); I** Undo the move by removing the piece from the space. * @return true if the attempt to remove the piece from the space was successful; false if not. @see BGFSpace#RemovePieceForUndo I public boolean HookUndo() ( return _space.RemovePieceForUndo{); II The space and piece involved in the move protected BGFPiece _piece; protected BGFSpace _space; 94

PAGE 100

BGFOnePiecePlayer / * BGFOnePiecePlayer.java Board Game Framework Dave Wood 1996 *I package EDU.cudenver.BGF; /** A player class for players with a single type of piece which may be played on the board. @author
Dave Wood */ public class BGFOnePiecePlayer extends BGFPlayer /** Create a player. @exception ClassNotFoundException Thrown if the class name given for the BGFPiece class to create cannot be found. @param @param pName The name of this player I pPieceClassName The full class name of a BGFPiece class to be placed on the board each move public BGFOnePiecePlayer { String String pName, pPieceClassName throws ClassNotFoundExcepcion ( super{pName); _pieceClass = Class.forName{pPieceClassName); /** Create a new BGFPiece object. constructor, this method will of its subclasses. Based on the class sepcified in the create a new instance of BGFPiece or one *I public BGFPiece GetNewPiece{) ( BGFPiece newPiece = null; try ( newPiece = {BGFPiece)_pieceClass.newinstance{); catch {IllegalAccessException e) ( System.out.println{"BGF Application Error. Invalid piece."); Thread.currencThread() .dumpStack(); catch {InstantiacionException e) ( System.out.println{ "BGF Application Error. Invalid piece."); Thread.currentThread{) .dumpStack(); 95

PAGE 101

newPiece.SetPlayer(this); return newPiece; II The Class t o instantiate when attempting to make a move protected Class _pieceClass; BGFOneSpaceGUIStrategy I * BGFOneSpaceGUIStrategy.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; I** A Strategy class for games in which a player's move consists of placing a single piece (of a consistent type) on a space. This c lass must only be used by instances of BGFOnePiecePlayer (or a subclass of BGFOnePiecePlayer) as it needs the BGFOnePiecePlayer.GetNewPiece() method. @author Dave Wood I public class BGFOneSpaceGUIStrategy extends BGFGUIStrategy I** Handle the selection o f a space on the board by attempting to place a piece on the selected space. @return always true (a move is always tried) @see BGFStrategy#TryMove I protected boolean HandleSpaceSelection() { BGFPiece newPiece = ((BGFOnePiecePlayer)_player) .GetNewPiece(); BGFNewPieceMove move = new BGFNewPieceMove(this, newPiece, _selectedSpace); TryMove (move) ; return true; II The Class to instantiate when attempting to make a move protected Class _pieceClass; BGP'Piece I* 96

PAGE 102

* BGFPiece. java Board Game Framework Dave Wood 1996 / package EDU.cudenver.BGF; import java.awt.; J* An abstraction for a piece on a game board. @author
Dave Wood< /A> I public class BGFPiece { J* Create a piece owned by the specified player. @param pPlyaer The player who owns this piece I public BGFPiece(BGFPlayer pPlayer) { _player = pPlayer; /** Create a piece not yet owned by any player. Note that this constructor is needed in order to allow BGFPiece objects to be created using the Class.newinstance() method. After release 1.1 of the JDK, this will no longer be @see BGFPiece#SetPlayer I public BGFPiece() { _player = null; !** Set the player who owns this piece. Note that this method is needed in order to allow BGFPiece objects to be created using the Class.newinstance() method. After release 1.1 of the JDK, this will no longer be necessary. I public void SetPlayer(BGFPlayer pPlayer) { _player = pPlayer; !** Set the space at which this piece is currently located. @param pSpace The space at which the piece is now located I void SetSpace(BGFSpace pSpace) { _space = pSpace; ** Return the space at which this piece is currently located. @return The space at which this piece is currently located I public BGFSpace GetSpace() 97

PAGE 103

return _space; I** Return the player who owns this piece. @return The BGFPlayer object who owns this piece I public BGFPlayer GetPlayer() { return _player; I** Check to see if this piece if moveable by the specified player. The default method requires only that the piece is owner by the input player. This may be overridden. @param pPlayer The player wanting to move the piece @return true if the player may move the piece, false if not I public boolean IsMoveableBy(BGFPlayer pPlayer) { return (pPlayer ==_player); I** Check to see if this piece is moveable to the specified space. The default method requires onlt that the space to be moved to is different than the current space. This will probably need to be overridden for most games. @param pSpace The space to be moved to @return true if the move would be allowed, false if not I public boolean IsMoveableTo(BGFSpace pSpace) ( return (pSpace !=_space); I I the space at which this piece is located protected BGFSpace _space; II the player who owns this piece protected BGFPlayer _player; BGFPieceView I* BGFPieceView.java Board Game Framework Dave Wood 1996 *I package EDU.cudenver.BGF; import java.awt.*; 98

PAGE 104

I** An abstraction for the "view" of a piece on a game board. @author
Dave Wood< IA> @see BGFPiece I public abstract class BGFPieceView { protected BGFPiece _piece; I** Create a new BGFPieceView which references the given BGFPiece. @param pPiece The "model" piece represented by this "view" piece I public BGFPieceView(BGFPiece pPiece) { _piece = pPiece; IW* Return the BGFPiece represented by this "view" piece. @return The BGFPiece represented by this "view" piece. I public BGFPiece GetPiece() { return _piece; I** Draw this piece on the input Graphics within the specified rectangle. This method must be implemented by BGFPieceView subclasses to draw the appropriate piece type on che input Graphics object within the specified rectangle. @param pGraphics @prarm pRecc * I abstract protected void Draw ( ) ; I** Graphics Rectangle pGraphics, pRect The Graphics object the piece is to be drawn upon The Rectangle within which the piece is to be placed Visually indicate that the game is over. The default behavior for pieces is to do nothing. However, an application may wish to display a piece in a different way to reflect the end of the game (or the lack of the end of the game). I public boolean ShowGameOver(BGFGameOverStatus pStatus) { return false; BGFPlayer 99

PAGE 105

I * BGFPlayer. java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; import java.util.Vector; I** An abstraction for a player in a board game. This class implements the Runnable interface. The process of making a move is done within the run() method, generally in a new thread. This class forward requests on to its BGFStrategy object which is responsible for the actual move creation process. @author
Dave Wood< IA> @see BGFStrategy @see BGFGameMaster I public class BGFPlayer implements Runnable I** Create a new player with the specified player name. Note that the name i s intended to be the general name f o r the player, e g "White" and "Black" in chess, or X and 0 in Tic-Tac-Toe. @param pName The name of the player I public BGFPlayer(String pName) { I** _name = pName; _allPlayers.addElement(this); Retrieve the name of the p layer. @return The name of the player I public String GetName() { return _name; I** Get the current strategy for this player. @return The current strategy I public synchronized BGFStrategy GetStrategy() { return _strategy; I** Set the strategy for this player. If the input is non-null, set the strategy's player to 'this'. @param pStrategy The strategy for this player I public synchronized void SetStrategy(BGFStrategy pStrategy) { 100

PAGE 106

I** _strategy = pStrategy; if (_strategy = null) { _strategy.SetPlayer(this); notifyAll () ; Make a move (typically in a new thread). This is the BGFPlayer implementation of the run() method specified in the Runnable interface. It waits to make sure a strategy has been set for this player and then calls that strategy's Run() method. a new move. @see BGFStrategy#Run I public void run() { synchronized (this) { while (_strategy { try { null) while (_strategy wait (); null) catch (InterruptedException e) { } II drop thru to end while ... _strategy.Run(); I** Pass the selected space on to the strategy. @param pSpace The space on the board clicked by the GUI user I public void AcceptSpaceSelection(BGFSpace pSpace) { I** if (_strategy != null) _strategy.AcceptSpaceSelection(pSpace) ; Pass an abort move request on to the strategy. I public synchronized boolean AbortMove() { I** if (_strategy != null) return _strategy.AbortMove{); else return false; Return all BGFPlayer objects which have been created. @return An array of references to the existing players I static public BGFPlayer[) GetPlayers() { BGFPlayer[) all= new BGFPlayer[_allPlayers.size()); _allPlayers.copyinto(all); return all; 101

PAGE 107

* Remove all players. I static public void ClearPlayers() { _allPlayers =new Vector(2); II a vector containing all players --populated by the constructor static private Vector _allPlayers =new Vector(2); II player's name (Chess: "Black"I"White", Tic-Tac-Toe: "X"I"O") etc ... protected String _name; II player's strategy protected BGFStrategy _strategy null; BGFSpace I* BGFSpace.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; import java.util.Observable; I** An abstraction a space on a game board. Each space knows its coordinates on the board and knows which piece (if any) is currently located on it. @author
Dave Wood I public class BGFSpace extends Observable I** Create a new BGFSpace with the specified coordinates. @param pRow @param pColumn *I public BGFSpace ( I** int pRow, int pCol _row = pRow; _col = pCol; _piece = null; The row on the board at which this space is located The column on the board at which this space is located Return a boolean value indicating whether the space is empty. I 102

PAGE 108

public boolean IsEmpty() { /** if (_piece == null) return true; else return false; Clear the space and notify observers if the space was previously occupied by a piece. See the Observer (293) pattern for more details. @see @see @see I BGFPiece java.util.Observer java.util.Observable public void ClearSpace() { /** if (_piece != null) { _piece.SetSpace(null); _piece = null; setChanged(); notifyObservers(this); Attempt to place the specified piece on this space. If the space is already occupied, return false to indicate that the space must first be cleared (simply removing the old piece from the board would be a less friendly way to handle such calls since removed pieces should generally be recorded for undo pruposes). If the piece is auccessfully places, the Observers are notifed. See the Observer (293) pattern for more details. @return boolean value indicating success/failure @see @see I java.util.Observer java.util.Observable public boolean PlacePiece(BGFPiece pPiece) { /*W if (_piece == null) { else _piece = pPiece; _piece.SetSpace(this); setChanged(); notifyObservers(this); return true; return false; Remove the piece currently on this space as a result of an undo operation. If there is no piece on the space, false is returned to indicate failure. Otherwise, the space is cleared and the observers are notifed. See the Observer (293) pattern for more details. @return boolean value indicating success/failure * @see @see java.util.Observer java.util.Observable 103

PAGE 109

*I public boolean RemovePieceForUndo() ( I** if (_piece != null) ( else _piece.SetSpace(null); _piece = null; setChanged(); notifyObservers(this); return true; ret:urn false; Return the BGFPiece object presently on this space. return a BGFPiece or null if there is no piece on this space I public BGFPiece GetPiece() ( return _piece; I** Return the row chis space is in. I public int GetRow() ( return _row; I** Ret:urn the column this space is in. *I public int GetCol() ( return _col; II the piece currently located on this space protected BGFPiece _piece; II the coordinates of this space protected int _row; protected int _col; BGFSpaceSelectedCommand I * BGFSpaceSelectedCommand.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; Represents a notification that a space has been selected. When executed, this command notifies the BGFGameMaster of the selected space. 104

PAGE 110

* @author
Dave Wood< IA> I public class BGFSpaceSelectedCommand extends BGFCommand I** Execute the new game command. Obtain a reference to the singleton instance of BGFGameMaster and call SpaceSelected(}. @see BGFGameMaster I public void ExecuteHook(} { BGFGameMaster gm = BGFGameMaster.Instance(); gm.SpaceSelected(_space); I** Create a new command. Store the input space for use in the ExecuteHook method. @param pSpace The space which has been selected I BGFSpaceSelectedCommand(BGFSpace pSpace) { _space = pSpace; II the selected space BGFSpace _space; BGFSpaceView I * BGFSpaceView.java Board Game Framework Dave Wood 1996 I package EDU.cudenver. BGF; import java.awt.*; import java.util.Observer; import java.util.Observable; I** An abstraction for the "view of a space on a game board. @author Dave Wood @see BGFSpace @see BGFPieceView *I public class BGFSpaceView implements Observer I** Create a new view for a given "model" BGFSpace object. This constructor stores references to the input BGFBoardView in which the space is located, and to the "model" space the view object 105

PAGE 111

represents. In addition, the "view" object adds itself as an observer to the "model" BGFSpace object (see the Observer (293)<1B> design pattern.) @param @param @param @param I pBoardView pSpace pWidth pHeight public BGFSpaceView ( The BGFBoardView which contains this objects The BGFSpace which this object observes The width of the space The height of the space BGFBoardView BGFSpace Rectangle pBoardView, pSpace, pRect _boardView = pBoardView; _space = pSpace; _rect = pRect; II see if there is already a piece on this space ... BGFPiece p = _space.GetPiece(); if (p !=null) ( BGFFactory factory= BGFFactory.Instance(); _pieceView = factory.CreatePieceView(p); _space.addObserver(this); I** Show the game-over status as it affects this space. This method simply passes the request on to the piece located on this space. @param pStatus The game-over status of the current game @see BGFPieceView I public boolean ShowGameOver(BGFGameOverStatus pStatus) ( if (_pieceView != null) return _pieceView.ShowGameOver(pStatus); else return false; I** Handle notification from "model" objects (BGFSpaces) indicating a change in the state of the game. This method checks to see that the notifying object is the BGFSpace object this BGFSpaceView is observing. It then checks to see if the BGFPiece on the BGFSpace matches the BGFPiece currently referenced by the BGFPieceView held by this BGFSpaceView. If the pieces match, no change is made to the view. If not, a new BGFPieceView is created to reference the BGFPiece now on this space and the board is re-displayed. @param @param @see @see @see @see @see I pObservable pObject BGFFactory BGFBoardView BGFPieceView BGFPiece BGFSpace public void update The object (BGFSpace) sending the notification Unused 106

PAGE 112

I** Observable Object pObservable, pObject if (pObservable == _space) { BGFFactory factory= BGFFactory.Instance(); BGFPiece p = _space.GetPiece(); if (p == null) { if (_pieceView !=null) { _pieceView = null; _boardView.RepaintSpace(this); else { if ((_pieceView ==null) I I (p != _pieceView.GetPiece())) { _pieceView = factory.CreatePieceView(p); _boardView.RepaintSpace(this); Check to see if the input coordinates are within this space. @param pX w @param pY The X-coordinate to check The -coordinate to check @return true if the input point is inside this space's rectangle, false if :-tot I public boolean PointinSpace ( I** int pX, int pY return _rect.inside(pX, pY); Return the rectangle which defines the border of this space. @return The rectangle defining the border of this space I public Rectangle GetRect() { return _rect; I** Return the space being observed by this BGFSpaceView. @return The BGFSpace being observed *I public BGFSpace GetSpace() { return _space; 107

PAGE 113

I** Draw an empty space. This default implementation simply fills the space with the board's background color. @param pGraphics The graphics context on which to draw I protected void DrawEmpty(Graphics pGraphics) { pGraphics.setColor(_boardView.getBackground()); pGraphics.fillRect(_rect.x, _rect.y, _rect.width, _rect.height); I** Draw the space. The default implementation calls DrawEmpty() and then calls the piece' s Draw() method if there is a piece on the space. pGraphics The graphics context to be drawn on @param I protected { void Draw(Graphics pGraphics) DrawEmpty{pGraphics); if (_pieceView != null) _pieceView.Draw(pGraphics, _rect); II The observed space protected BGFSpace _space; II The piece (if any) on this space protected BGFPieceView _pieceView; I I The rectangle this space draws to protected Rectangle _rect; II The board view we live in protected BGFBoardView _boardView; BGFStrategy I* BGFStrategy.java Board Game Framework Dave Wood 1996 *I package EDU.cudenver.BGF; I** An abstraction for a player's "strategy" in a board game. The process of making a move is done within the Move() method, generally in a new thread. This abstract class provides a basic flow of control through the move-generation process. BGFStrategy implements the BGFMoveController interface, indicating that it is responsible for the generation of BGFMove objects (and therefore for the notification of invalid moves). In this sense, BGFStrategy takes on the role of the Controller class as described in the Command Processor patten in the Buschmann et. al. pattern book (or the *Client class in the Command (233)<1B> pattern.) * @author
Dave Wood 108

PAGE 114

* @see BGFMoveProcessor @see BGFMove @see BGFGameMaster @see BGFPlayer I public abstract class BGFStrategy implements BGFMoveController I** Create a new Strategy with the specified Strategy name. Possible names might be Human "Novice Comput.er", "Guru Comput.er. @param pName The name of the St.rategy I public BGFStrategy(String pName) { _name = pName; I** Ret.rieve the name of the Strategy. @return The name of the Strategy I public String GetName() { ret.urn _name; I** Set the player using this strategy object. @param pPlayer The player using this strategy I public void SetPlayer(BGFPlayer pPlayer) { _player = pPlayer; I** Get the player using this strategy object. @return The player using this strategy I public BGFPlayer GetPlayer() { return _player; I** Make a move (typically in a new thread). This is called by BGFPlayer when a move is needed. It is named Run to reflect the fact. that. it is intended to be called from within Player's Runnable.run() method. It st.ores the current. thread and calls the Move() routine to generate a new move. * @see @see I BGFStrategy#Move BGFPlayer#run public void Run() { moveThread = Thread.currentThread(); _moveCompleted = false; Move(); _moveThread = null; _moveCompleted = true; 109

PAGE 115

BGFGameMaster gm = BGFGameMaster.Instance(); gm.MoveCompleted(); I** Set the internal validLastMove variable to false and call the NotifyinvalidMoveHook method which subclasses may override. @param pMove The invalid BGFMove *I public void NotifyinvalidMove(BGFMove pMove) { _validLastMove = false; NotifyinvalidMoveHook(pMove); I** Perform any strategy-specific action in response to notification of an invalid move. @param pMove The invalid BGFMove @see BGFStrategy#NotifyinvalidMove I protected void NotifyinvalidMoveHook(BGFMove pMove) { ) I* Unused at this level. Subclasses of BGFStrategy may choose to perform some action when an attempt to undo a move fails. @param pMove The BGFMove which failed to be undone I public void pMove) { ) I** Unused at this level. Subclasses of BGFStrategy interested in input from the GUI should override this method to perform necessary actions in response to a space on the board being selected. @param pSpace The space on the board clicked by the GUI user *I public void AcceptSpaceSelection(BGFSpace pSpace) { ) I** Attempt to abort the current move. If the Strategy is currently in the process of generating a move (_moveThread is non-null and _moveCompleted is false), the move-making thread is stopped. *Before stopping the thread, a notifyAll() call is made to wake up any Move() routine which might be waiting (such as a GUI Strategy) since waiting threads cannot be stopped. I public synchronized boolean AbortMove() { if (_moveThread !=null) { if (_moveCompleted) return false; else { notifyAll(); _moveThread.stop(); II interrupt the current move 110

PAGE 116

return true; return false; I** Make a move. This method provides the skeleton for the move-making *process. The abstract hook method MoveHook(), does the real work (see the Template Method (325)<1B> design pattern. This method calls itself recursively if MoveHook() generates a move which is not valid. Note that it is therefore reasonable for the MoveHook() method to generate moves which may not be valid. MoveHook() need not check to see if a move is valid if doing so is not part of the move-generation algorithm (a random computer Strategy, for example, might generate moves without checking legality and rely on the *Move() method to retry until a valid move is made). @see BGFStrategy#MoveHook I protected void Move() { _validLastMove = t rue; MoveHook(); II do the real work ... if (_validLastMove == false) II keep going until a valid move is made Move(); I** Hook method for making a move. This is the hook method called by the Move() method (see the Template Method (325)<1B> design pattern). Subclasses may generate a move by waiting for GUI input, performing intelligent search algorithms, waiting for input from a networ k Strategy, etc. It is important to keep in mind that this method may be stopped at any time by an abort request. Therefore, any state data which may be altered by the routine should be reset at the start of the MoveHook() call. Also, synchronized blocks should be used within MoveHook() to avoid being aborted in certain situations. Note that the TryMove() method is already synchronized. @see @see @see I BGFStrategy#Move BGFStrategy#AbortMove BGFStrategy#TryMove abstract protected void MoveHook(); I** Submit a move to the BGFMoveProcessor. This method submits a move to the BGFMoveProcessor and sets _moveCompleted if the move is valid. @param pMove The move to be submitted @see BGFMoveProcessor I protected synchronized void TryMove( BGFMove pMove) { BGFMoveProcessor mp = BGFMoveProcessor.Instance(); mp.SubmitMove(pMove); if (_validLastMove true) _moveCompleted = true; II the move cannot be aborted at this point II Was the last move valid? protected boolean _validLastMove = true; II The Thread in which the run() method is running Ill

PAGE 117

protected Thread _moveThread null; II Is the move completed? protected boolean _moveCompleted = false; II St:rategy's name (Chess: "Black"I"White", Tic-Tac-Toe: "X" I"O") etc ... protected String _name; II Player using this strategy protected BGFPlayer _player; BGFTakeBackCommand I * BGFTakeBackCommand.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; I** Represents a request for the last move to be taken back. When executed, the request is sent to the BGFGameMaster. @author
Dave Wood< IA> *I public class BGFTakeBackCommand extends BGFCommand I** Execute t:he take-back command. Obt:ain a reference to t:he BGFGameMaster singleton object and call TakeBack(). @see BGFGameMaster I public void Execut:eHook() { BGFGameMaster gm = BGFGameMaster.Instance(); gm.TakeBack(_count); I** Create a take-back command. Set the number of moves to be taken back in a private data field. param pCount The number of moves to take back I public BGFTakeBackCommand(in t pCount) { _count = pCount; II the number of moves to take back private int _count; 112

PAGE 118

BGFTwoSpaceGUIStrategy I* BGFTwoSpaceGUIStrategy.java Board Game Framework Dave Wood 1996 I package EDU.cudenver.BGF; I** *A Strategy class for games in which a player's move consists of moving a piece from one space to another @author
Dave Wood I public class BGFTwoSpaceGUIStrategy extends BGFGUIStrategy I** Handle the selection of a space on the board. If this is the first click, the space is stored. If this is the second click, a move from the first space to the second space is generated and submitted. *@return true if a move was tried (2nd space selected), false if not (1st space selected) @see BGFStrategy#TryMove I protected boolean HandleSpaceSelection() { if (_firstSpace == null) { else { II See if this space has a piece owned by this player BGFPiece p = _selectedSpace.GetPiece(); if ((p !=null) && p.IsMoveableBy(GetPlayer())) { _firstSpace = _selectedSpace; _movingPiece = p; return false; II no move tried yet BGFFactory factory= BGFFactory.Instance(); BGFMove move = factory.CreateMovePieceMove(this, _movingPiece = null; _firstSpace = null; TryMove (move) ; GetPlayer () _movingPiece, _firstSpace, _selectedSpace); return true; II a move has been tried I I the first clicked space (remember it for when the 2nd click comes) protected BGFSpace _firstSpace = null; II the piece being moved (from the 1st space) protected BGFPiece _movingPiece = null; 113

PAGE 119

BGFWhoPlaysCommand I* BGFWhoPlaysCommand.java Board Game Framework Dave Wood 1996 *I package EDU.cudenver.BGF; /** Represents a request to select the game's players. When executed, this command pops up the BGFWhoPlaysDialog box, waits for input, and updates the player strategies according to the selections made. @author
Dave Wood I public class BGFWhoPlaysCommand extends BGFCommand /** Execute the 'who plays' command. Pop up the dialog, retrieve the selections, and update the players strategies. @see @see @see BGFWhoPlaysDialog BGFPlayer BGFStrategy *I public void ExecuteHook() { /** BGFGameMaster gm = BGFGameMaster.Instance(); //while (gm.GamelnProgress()) gm.AbortGame(); _dialog. show () ; Create the command to affect the input players using the input dialog. I public BGFWhoPlaysCommand ( BGFWhoPlaysDialog pDialog _dialog pDialog; II box to pop up protected BGFWhoPlaysDialog _dialog; BGFWhoPlaysDialog I* 114

PAGE 120

* BGFWhoPlaysDialog.java Board Game Framework Dave Wood 1996 I package EDU.cudenver. BGF; import java.awt.*; import java.util.Hashtable; I** Dialog box which allows the user to select the players involved in the game. Note that from a BGF standpoint, we're really selected Strategies for existing Players. This dialog box generates a "New Game" command once selections have been made. @author Dave Wood< IA> I public class BGFWhoPlaysDialog extends Dialog I** Create the dialog which will display the given players and strategies and will be attached to the given frame. @param @param @param pFrame The Frame which will be the dialog's parent pPlayers The BGFPlayer objects involved in any game pStrategyChoices The possible strategy options for the players @see @see BGFWhoPlaysDialog#HashStrategies BGFWhoPlaysDialog#AddPanels I public BGFWhoPlaysDialog ( I** Frame BGFPlayer [) BGFStrategy[ ) pFrame, pPlayers, pStrategyChoices super(pFrame, "Who Plays", true); _players = pPlayers; HashStrategies(pStrategyChoices); AddPanels(pPlayers, pStrategyChoices); add("South", new Button("OK")); pack(); Create a hashtable mapping strategy names to BGFStrategy objects. @param pStrategyChoices The BGFStrategy objects to be hashed. @see @see I java.util.Hashtable BGFStrategy#GetName protected void HashStrategies(BGFStrategy[J pStrategyChoices) { _stringToStrategy =new Hashtable(pStrategyChoices.length); for (int i=O;i
PAGE 121

* Add the player/strategy choices to the display. A Panel is created for each player which contains the player name and a checkbox group of the possible strategy options for each player. @param @param pPlayers pSt.rategyChoices The players in the game The strategy options for each player @see @see @see @see java.awt.CheckboxGroup java.awt.Checkbox java.awt.Panel java.awt.FlowLayout I protected void AddPanels ( /** BGFPlayer [} BGFStra tegy [} pPlayers, pStrategyChoices _groups= new CheckboxGroup[pPlayers.length} ; Panel choices= new Panel(); choices.setLayout(new FlowLayout()); GridLayout grid= new GridLayout.(pStrategyChoices.length+l, 1); for (int i=O;i
PAGE 122

* @see BGFNewGameCommand I public void UpdatePlayers() { for (int i=O;i<_groups.length;i++) { String strategyName= new String(_groups[i].getCurrent() .getLabel()); BGFStrategy s = (BGFStrategy)_stringToStrategy.get(strategyName); try { Class sClass = s.getClass(); _players[i].SetStrategy((BGFStrategy)sClass.newinstance()); catch (IllegalAccessException e) { Systern.out.println("IllegalAccessException +e); catch (InstantiationException e) { System.out.println('InstantiationException" +e); BGFCommandProcessor cp = BGFCommandProcessor.Instance(); cp.SubmitCommand(new BGFNewGameCommand()); II The checkbox groups on the display protected CheckboxGroup[] _groups; II The players in the game protected BGFPlayer[] _players; II Map from strategy name (on the screen) to BGFStrategy object protected Hashtable _stringToStrategy; BGFWinningSpacesGameOverStatus I * BGFWinn ingSpacesGameOverStatus.java Board Game Framework Dave Wood 1996 I package EDU.cudenver. BGF; I** An extenation of BGFGameOverStatus to include references to the spaces involved in making a winning position. @author
Dave Wood< IA> I public class BGFWinningSpacesGameoverStatus extends BGFGameOverStatus I** Retrieve the spaces involved in making this a won position. @return An array of BGFSpace objects, or null I 117

PAGE 123

public BGFSpace[) GetWinningSpaces() ( return _winningSpaces; I** Store the spaces involved in making a won position. @param pWinningSpaces An array of BGFSpace objects involved in making this a won position (or null) I public void SetWinningSpaces(BGFSpace[) pWinningSpaces) ( _winningSpaces = pWinningSpaces; II the winning spaces private BGFSpace[) _winningSpaces; 1 1 8

PAGE 124

References [AG96] K. Arnold,]. Gosling: The Ja v a Programming Language, Addison-Wesley 1996 [AIS77] C. Alexander, S. Ishikawa, M. Silverstein: A Pattern Language, Oxford University Press 1977. [BF96] G. Brown, P. Forte: Building reusable classes for Jramework.s, Journal of Obje ct -Orient ed Programming Vol. 9, No.7, pp. 49-54, November/December 1996. [BJR96] G. Booch I. Jacobson ,]. Rumbau gh: The Unified Modeling Language for Object-Oriented Development, Version 0. 91 Addendum, Rational Software, 1996. [BJR096] G. Booch I. Jacobson ,]. Rumbaugh G. Overgaard: The Unified Modeling Language, Tutorial #37 ofOOPSlA 96, 1996. [BMRSS96] F. Buschmann R. Meunier, H. Rohnert P. Sommerlad, M. Stal: Pattern-Oriented Software Architecture: A System of Patterns,John Wiley & Sons, 1996. [BR95] G. Booch,J. Rumbau gh: Unified Method for Object-Oriented Development, Version 0. 8, Rational Software, 1995. [Bus96] F. Buschma nn: Finding & using Patterns, Obj ect Expert, 1 ( 6 ) pp. 46-4 7 September/October 1996. [CNM95] P. Coad, D North, M. Mayfield: Object Models: Strategies, Patterns, & Applications, Yourdon Press Prentice Hall, 1995 [CR96] P. Chan, R. Lee: The Java Class Libraries: An Annotated Riference, Addison-Wesley, 1996. [FE95] D.G. Firesmith E.M Eykholt: Dictionary of Object Technology: The Difinitive Desk Riference, SICS Books 1995. [GHJV95] E. Gamma, R. Helm, R.Johnson,J. Vlissides: Design Patterns: Elements of Reusable Object-Oeiented Software, AddisonWesley, 1995. [GJS96] J. Gosling, B. Joy, G. Steele: The Java Language Specification, Addison-Wesley, 1996. [Hoffi5] D R. Hofstadter: Metamagical Thernas: Qjtestingfor the Essence of Mind and Pattern, Basic Books, 1985. 0oh92] R.E.Johsnon: Documenting Frameworks Using Patterns, in Proceedings of OOPSLA '92, 1992. 119

PAGE 125

Uoh96] R.E.Johnson: How to Develop Frameworks, Tutorial #34 of OOPSLA '96, 1996. [La] C. Laffra: Advanced Java -Idioms Styles, Programming Tips, and Piifalls, Tutorial #1 6 ofOOPSLA '96, 1996. [Lea94] D. Lea: Christopher Alexander: An Introduction for Object-Oriented Designers: http:/ /g.oswego.edu/ dl/ ca/ca/ ca .html. [Lea96] D. Lea: Concurrent Programming in Java: Design Principles and Patterns, Addison -W esley, 1996. [LP96] L. Lemay, C. L. P erkins: Teach Yourself]ava in 21 days, Sams .n et, 1 996. [Nag96] Nagarat n am : Developing GUis Using the]avaA WT, Tutorial # 5 of OOPSLA '96, 1996. [OBJR96] G. Overgaard G Booch, I. j acobson,]. Ru mbaugh: The Semantics of1he U nified Modeling Language, Tutorial # 53 ofOOPSLA '96, 1 996. [PLoP95] J.M.Vlissides,J.O. Coplien, N.L. Kerth: Pattern Languages of Program Design 2, Addison-Wes ley, 1996. [Pree95] W. Pree: Design Patterns for Object-Oriented Software Development, Addison-Wesley, 1995. [Pree96] W. P ree: FrameworksPast, present,.foture, Object Magazine 6 ( 3), pp. 24 26, May 1 996 [RBPEL91] J. Rumbaugh M. Blaha, W. Premerlani, F Eddy W. Lorensen: Object-Oriented Modeling and Design, P rentice Hall In c., 1991. [SFJ96] D. Schmidt, M Fayad R.Johnson: Software Patterns, Communications of the ACM Vol. 39, To. 10, pp. 36 39, October 1 996 [Stil96] B. Stilman: Tutorial on Linguistic Geometry, http:/ /www.cudenver.edu/ [T al94] Taligent's Guide to Designing Programs: Well-Mannered Object-Oriented Design i n C + +, Add ison-W esley, 1994. [WGM88] A. Weinand, E. Gamma, R Marty: ET++ An Object-Oriented Application Framework in C++, in Proceedings ofOOPSLA '88, 1988. 120