Design Patterns for Games Stephen Wong Dung Nguyen



















- Slides: 19
Design Patterns for Games Stephen Wong Dung Nguyen Rice University
Let’s Play a Game v v Sun’s Tic-Tac-Toe What can we learn from this? – Arrays – For-loops – Nested Conditionals v What aren’t we learning? – Delineation of concepts from implementation – Abstraction – Design
Something Different… v It’s not really about Tic. Tac. Toe… – It’s a vehicle to teach something BIGGER. Abstraction v Design Process v Fundamental Principles v
What’s in a Game? Model X Rules Strategies Players adapter View adapter Buttons, etc. Display outputs O Controller O Install adapters X
Game Model v Rules of the Game – Board configurations – Legal moves v Next Move Strategies Abstract these components! – Random – Min-Max – Etc. v Player Management Decouple these components! – Turn taking – Win/lose/draw notification – Fault handling
The Rules of the Game IBoard. Model IUndo. Move make. Move(player, row, col), chk. Move. Cmd), bd. Status. Vstr) Object execute(bd. Status. Vstr, param) // other methods commands host/visitor ICheck. Move. Cmd valid. Move. Case() invalid. Move. Case() IUndo. Move apply(…) IBoard. Status. Visitor player 0 Won. Case(…) player 1 Won. Case(…) draw. Case(…) no. Winner. Case(…)
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 IBoard. Model execute(IBoard. Status. Visitor v, …) Tic. Tac. Toe. Board state. execute(v, …) state ABoard. State v. no. Winner. Case(…) ATerminal. State Player 0 Won v. player 0 Won. Case(…) Player 1 Won Non. Terminal. State Draw. Game v. player 1 Won. Case(…) v. draw. Case(…)
Playing the Game Computer. Player INext. Move. Strategy take. Turn(…) Point get. Next. Move(…) Random Min. Max Alpha. Beta The next move process is decoupled from the rules of the game!
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 v Math/FP: Map( , S) = { (x) | x S} Both accumulators are abstractly equivalent! v Express our algorithm in terms of mapping, not iteration: – min(…) map( , min-accum) – max(…) map( , max-accum) v Backtracking is automatically handled by mapping.
Mapping Abstraction IBoard. Model IUndo. Move make. Move(player, row, col), chk. Move. Cmd), bd. Status. Vstr) Object execute(bd. Status. Vstr, param) void map(player, lambda, param) Controls Called on all valid continuation of Called when there moves. mapping are no valid moves. command IBoard. Lambda boolean apply(board, param, row, col, cell-val) void no. Apply(board, param)
INext. Move. Strategy Min-Max Abstraction Min. Max acc. Fac: IAcc. Factory AAccum make. Acc(player) Point get. Next. Move(model, player) min. Max. Eval: IBoard. Lambda boolean apply(…) void no. Apply(…) AAccum acc = acc. Fac. make. Acc(player); model. get. Board. Model(). map(min. Max. Eval, acc); return acc. get. Move();
private IBoard. Lambda min. Max. Eval = new IBoard. Lambda() { Try a test move. public boolean apply(board, acc, row, col, cell-value) { to be mapped over IUndo. Move undo = host. make. Move( row, Update col, acc. get. Player(), valid. Mv. Vstr, the available states. Called by map on new IBoard. Status. Visitor() { accumulator each valid (row, col) Update player 0 Won. Case(. . . ) {…} accumulator What to do in Update each situation {…} player 1 Won. Case(…) accumulator draw. Case(…) {…} Declarative style programming! no. Winner. Case(…) { AAccumulator next. Acc = acc. make. Opposite(); Undohost. map(next. Acc. get. Player(), the move. min. Max. Eval, next. Acc); acc. update. Best(row, col, next. Acc. get. Val()); return null; } }); undo. apply(valid. Undo); return acc. is. Not. Done(); } Stop mapping?
Just a new accumulator! Alpha-Beta Pruning Override the creation of the next level’s {accumulator public class Alpha. Acc extends Max. Accumulator for the opposite player as an public AAccumulator make. Opposite() { anonymous inner class. return new Beta. Acc() { Stop mapping if pruning condition is met. gives the Inner class { this. model. Player = Alpha. Acc. this. model. Player; } scoping we need! public boolean is. Not. Done() { return Alpha. Acc. this. get. Val() < this. get. Val(); } }; } 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 v Commands and Visitors isolate rules from behaviors v State pattern models game behavior v Calculating the next move is a Strategy v Design patterns express abstractions
Concepts in Action Abstract functions – lambda’s v Higher order functions – Mapping v Declarative programming v Invariant: Min-Max Principle v Variant: v – Full depth-first search – Alpha-beta pruning
More Information… v Design Pattern for Games: http: //www. exciton. cs. rice. edu/research/SIGCSE 02 v Patterns for Decoupling Data Structures and Algorithms: http: //www. exciton. cs. rice. edu/research/SIGCSE 02



















