Design Patterns for Games

Report
Design Patterns for Games
Stephen Wong
Dung Nguyen
Rice University
Let’s Play a Game


Sun’s Tic-Tac-Toe
What can we learn from this?
– Arrays
– For-loops
– Nested Conditionals

What aren’t we learning?
– Delineation of concepts from implementation
– Abstraction
– Design
Something Different…

It’s not really about TicTacToe…
– It’s a vehicle to teach something BIGGER.
Abstraction
 Design Process
 Fundamental Principles

What’s in a Game?
Model
X
Rules
Strategies
Players
adapter
adapter
O
Controller
O
Install adapters
View
X
Buttons, etc.
Display outputs
Game Model

Rules of the Game
– Board configurations
– Legal moves

Next Move Strategies
Abstract
these components!
– Random
– Min-Max
– Etc.

Player Management
Decouple
these components!
– Turn taking
– Win/lose/draw notification
– Fault handling
The Rules of the Game
IBoardModel
IUndoMove makeMove(player, row, col), chkMoveCmd), bdStatusVstr)
Object execute(bdStatusVstr, param)
// other methods
commands
host/visitor
ICheckMoveCmd
validMoveCase()
invalidMoveCase()
IUndoMove
apply(…)
IBoardStatusVisitor
player0WonCase(…)
player1WonCase(…)
drawCase(…)
noWinnerCase(…)
State Diagram
Invalid Move State
Valid Move State
Non-Terminal State
(no winner yet)
Terminal States
Player #0 Wins
Player #1 Wins
Draw Game
State Design Pattern
IBoardModel
execute(IBoardStatusVisitor v, …)
TicTacToeBoard
state.execute(v, …)
state
ABoardState
v.noWinnerCase(…)
ATerminalState
Player0Won
v.player0WonCase(…)
Player1Won
NonTerminalState
DrawGame
v.player1WonCase(…)
v.drawCase(…)
Playing the Game
ComputerPlayer
INextMoveStrategy
takeTurn(…)
Point getNextMove(…)
Random
MinMax
AlphaBeta
The next move process is decoupled
from the rules of the game!
Facade
APlayer
takeTurn(…)
IRequestor
IBoardModel
makeMove(…)
TurnControl
IView
What the player sees:
public interface IRequestor {
public abstract void setTokenAt(
int row, int col,
int player,
IRejectCommand rejectCommand);
}
public interface IRejectCommand {
public abstract void execute();
}
Player Factories
IView
Only displays the toString()
of the factories.
The factories are treated
as Objects!
Selected
APlayer
factories
Set of
APlayer
factories
GameModel
private interface IMakePlayer {
public APlayer create(int playerNo);
}
The Set of APlayer Factories
public Vector getPlayers() {
Vector v = new Vector();
Anonymous APlayer
factory
Factory method
v.addElement(new IMakePlayer() {
public APlayer create(int playerNo) {
return new HumanPlayer(requestor, playerNo, turnAdmin);
}
public String toString() { return "Human player"; }
});
return v;
}
IView only cares
about this!
Min-Max Principle
V(s) =
For terminal state
 +1, if s is a winning state for that player
 0, if s is a draw state
Application of
 -1, if s is a losing state for that player
a process
For non-terminal state
over a set!
 max{V(c) | c is a child valid move state of s} ,
if that player moves next
 min{V(c) | c is a child valid move state of s},
if the other player moves next.
The best next move for a given player, m, is determined
from max{V(c) | c  S} where S is the set of available
moves for that player. How max is computed is a variant.
Mapping and Lambda

Math/FP: Map(, S) = {(x) | x  S}
Both
accumulators
are abstractly
equivalent!

Express our algorithm in terms
of mapping, not iteration:
– min(…)  map(, min-accum)
– max(…)  map(, max-accum)

Backtracking is automatically handled by
mapping.
Mapping Abstraction
IBoardModel
IUndoMove makeMove(player, row, col), chkMoveCmd), bdStatusVstr)
Object execute(bdStatusVstr, param)
void map(player, lambda, param)
Controls
Called on all valid
continuation
of
Called when
there
moves.
mapping
are no valid
moves.
command
IBoardLambda
boolean apply(board, param, row, col, cell-val)
void noApply(board, param)
INextMoveStrategy
Min-Max Abstraction
MinMax
accFac:IAccFactory
AAccum makeAcc(player)
Point getNextMove(model, player)
minMaxEval:IBoardLambda
boolean apply(…)
void noApply(…)
AAccum acc = accFac.makeAcc(player);
model.getBoardModel().map(minMaxEval, acc);
return acc.getMove();
private IBoardLambda minMaxEval = new IBoardLambda() {
Try a test move.
public boolean apply(board, acc, row, col, cell-value) {
 to be mapped over
IUndoMove undo
= host.makeMove(
row,Update
col, acc.getPlayer(), validMvVstr,
the available
states.
Called by map on{
new IBoardStatusVisitor()
accumulator
each valid (row, col)
Update
player0WonCase(...) {…}
accumulator
What to do in
Update
each
situation {…}
player1WonCase(…)
accumulator
drawCase(…) {…}
Declarative style
programming!
noWinnerCase(…) {
AAccumulator nextAcc = acc.makeOpposite();
Undohost.map(nextAcc.getPlayer(),
the move.
minMaxEval, nextAcc);
acc.updateBest(row, col, nextAcc.getVal()); return null; } });
undo.apply(validUndo);
return acc.isNotDone();
}
Stop mapping?
Just a new accumulator!
Alpha-Beta Pruning
Override the creation of the
next
level’s {accumulator
public class AlphaAcc extends
MaxAcc
Accumulator for the
opposite player
as an
public AAccumulator makeOpposite()
{
anonymous inner class.
return new BetaAcc() {
Stop mapping if pruning
condition
is met.gives the
Inner
class
{ this.modelPlayer = AlphaAcc.this.modelPlayer; }
scoping we need!
public boolean isNotDone() {
return AlphaAcc.this.getVal() < this.getVal();
}
};
}
Abstraction
isolates the essence and provides extensibility
}
Player Management
Abstract players
Event-loop for turn-taking
Call-back techniques for
asynchronous processing
Design Patterns In Action
MVC separates model from view
 Commands and Visitors isolate rules
from behaviors
 State pattern models game behavior
 Calculating the next move is a Strategy

Design patterns express abstractions
Concepts in Action
Abstract functions – lambda’s
 Higher order functions – Mapping
 Declarative programming
 Invariant: Min-Max Principle
 Variant:

– Full depth-first search
– Alpha-beta pruning
More Information…

Design Pattern for Games:
http://www.exciton.cs.rice.edu/research/SIGCSE02

Patterns for Decoupling Data Structures and
Algorithms:
http://www.exciton.cs.rice.edu/research/SIGCSE02

similar documents