Any patterns for modelling board games?

Design Patterns

Design Patterns Problem Overview


For fun, I'm trying to write one of my son's favorite board games as a piece of software. Eventually I expect to build a WPF UI on top of it, but right now I'm building the machine that models the games and its rules.

As I do this, I keep seeing problems that I think are common to many board games, and perhaps others have already solved them better than I will.

(Note that AI to play the game, and patterns around high performance are not interesting to me.)

So far my patterns are:

  • Several immutable types representing entities in the game box, e.g. dice, checkers, cards, a board, spaces on the board, money, etc.

  • An object for each player, which contains the players resources (e.g. money, score), their name, etc.

  • An object that represents the state of the game: the players, who's turn it is, the layout of the peices on the board, etc.

  • A state machine that manages the turn sequence. For example, many games have a small pre-game where each player rolls to see who goes first; that's the start state. When a player's turn starts, first they roll, then they move, then they have to dance in place, then other players guess what breed of chicken they are, then they receive points.

Is there some prior art I can take advantage of?

EDIT: One thing I realized recently is that game state can be split in to two categories:

  • Game artifact state. "I have $10" or "my left hand is on blue".

  • Game sequence state. "I have rolled doubles twice; the next one puts me in jail". A state machine may make sense here.

EDIT: What I'm really looking for here is the best way to implement multiplayer turn-based games like Chess or Scrabble or Monopoly. I'm sure I could create such a game by just working through it start to finish, but, like other Design Patterns, there are probably some ways to make things go much more smoothly that aren't obvious without careful study. That's what I'm hoping for.

Design Patterns Solutions


Solution 1 - Design Patterns

it seems this is a 2 month old thread that I've just noticed now, but what the heck. I've designed and developed the gameplay framework for a commercial, networked board game before. We had a very pleasant experience working with it.

Your game can probably be in a (close to) infinite amount of states because of the permutations of things like how much money player A has, how much money player B has, and etc... Therefore, I'm pretty sure you want to stay away from state machines.

The idea behind our framework was to represent the game state as structure with all the data fields that together, provide the complete game state (ie: if you wanted to save the game to disk, you write that structure out).

We used the Command Pattern to represent all of the valid game actions a player could make. Here would be an example action:

class RollDice : public Action
{
  public:
  RollDice(int player);

  virtual void Apply(GameState& gameState) const; // Apply the action to the gamestate, modifying the gamestate
  virtual bool IsLegal(const GameState& gameState) const; // Returns true if this is a legal action
};

So you see that to decide whether a move is valid, you can construct that action and then call its IsLegal function, passing in the current game state. If it is valid, and the player confirms the action, you can call the Apply function to actually modify the game state. By ensuring that your gameplay code can only modify the game state by creating and submitting legal Actions (so in other words, the Action::Apply family of methods are the only thing that directly modifies the game state), then you ensure that your game state will never be invalid. Furthermore, by using the command pattern, you make it possible to serialize your player's desired moves and send them over a network to be executed on other player's game states.

There ended up being one gotcha with this system that turned out to have a fairly elegant solution. Sometimes actions would have two or more phases. For example, the player may land on a property in Monopoly and must now make a new decision. What is the game state between when the player rolled the dice, and before they decide to purchase a property or not? We managed situations like this by featuring an "Action Context" member of our game state. The action context would normally be null, indicating that the game is not currently in any special state. When the player rolls the dice and the dice rolling action is applied to the game state, it will realize that the player has landed on an un-owned property, and can create a new "PlayerDecideToPurchaseProperty" action context that contains the index of the player we are waiting for a decision from. By the time the RollDice action has completed, our game state represents that it is currently waiting for the specified player to decide whether to buy a property is not. It is now easy for all other actions' IsLegal method to return false, except for the "BuyProperty" and "PassPropertyPurchaseOpportunity" actions, which are only legal when the game state has the "PlayerDecideToPurchaseProperty" action context.

Through the use of action contexts, there is never a single point in the life-time of the board game where the game state structure does not completely represent EXACTLY what is happening in the game at that point in time. This is a very desirable property of your board game system. It will it much easier for you to write code when you can find everything you ever want to know about what's happening in the game by examining only one structure.

Furthermore, it extends very nicely to networked environments, where clients can submit their actions over a network to a host machine, which can apply the action to the host's "official" game state, and then echo that action back to all the other clients to have them apply it to their replicated game states.

I hope this was concise and helpful.

Solution 2 - Design Patterns

The basic structure of your game engine uses the State Pattern. The items of your game box are singletons of various classes. The structure of each state may use Strategy Pattern or the Template Method.

A Factory is used to create the players which are inserted into a list of players, another singleton. The GUI will keep watch on the Game Engine by using the Observer pattern and interact with this by using one of several Command object created using the Command Pattern. The use of Observer and Command can be used with in the context of a Passive View But just about any MVP/MVC pattern could be used depending on your preferences. When you save the game you need to grab a memento of it's current state

I recommending looking over some of the patterns on this site and see if any of them grab you as a starting point. Again the heart of your game board is going to be a state machine. Most games will represented by two states pre-game/setup and the actual game. But you can had more states if the game you are modelling has several distinct modes of play. States don't have to be sequential for example the wargame Axis & Battles has a battle board the players can use to resolve battles. So there are three states pre-game, main board, battle board with the game continually switching between the main board and battle board. Of course the turn sequence can also be represented by a state machine.

Solution 3 - Design Patterns

I just finished designing and implementing a state based game using polymorphism.

Using a base abstract class called GamePhase that has one important method

abstract public GamePhase turn();

What this means is every GamePhase object holds the current state of the game, and a call to turn() looks at its current state and returns the next GamePhase.

Each concrete GamePhase has constructors that hold the entire game state. Each turn() method has a little bit of the game rules inside them. While this spreads the rules around, it keeps related rules close together. The end result of each turn() is just creating the next GamePhase and passing in the full state into the next phase.

This allows turn() to be very flexible. Depending on your game a given state can branch to many different types of phases. This forms a graph of all game phases.

At the highest level the code to drive it is very simple:

GamePhase state = ...initial phase
while(true) {
    // read the state, do some ui work
    state = state.turn();
}

This is extremely useful as I can now easily create any state/phase of the game for testing

Now to answer the second part of your question, how does this work in multiplayer? Within certain GamePhases that require user input, a call from turn() would ask the current Player their Strategy given the current state/phase. Strategy is just a interface of all the possible decisions a Player can make. This setup also allows Strategy to be implemented with AI!

Also Andrew Top said:

Your game can probably be in a (close to) infinite amount of states because of the permutations of things like how much money player A has, how much money player B has, and etc... Therefore, I'm pretty sure you want to stay away from state machines.

I think that statement is very misleading, while it is true that there are a lot of different game states, there are only a few game phases. To handle his example, all it would be is an integer parameter to the constructors of my concrete GamePhases.

Monopoly

Example of some GamePhases would be:

  • GameStarts
  • PlayerRolls
  • PlayerLandsOnProperty (FreeParking, GoToJail, Go, etc)
  • PlayerTrades
  • PlayerPurchasesProperty
  • PlayerPurchasesHouses
  • PlayerPurchasesHotels
  • PlayerPaysRent
  • PlayerBankrupts
  • (All Chance and Community Chest cards)

And some states in the base GamePhase are:

  • List of Players
  • Current Player (who's turn)
  • Player's Money/Property
  • Houses/Hotels on Properties
  • Player Position

And then some phases would record their own state as needed, for example PlayerRolls would record the number of times a player has roll consecutive doubles. Once we leave the PlayerRolls phase, we don't care about consecutive rolls anymore.

A lot of phases can be reused and linked together. For example the GamePhase CommunityChestAdvanceToGo would create the next phase PlayerLandsOnGo with the current state and return it. In the constructor of PlayerLandsOnGo the current player would be moved to Go and their money would be incremented by $200.

Solution 4 - Design Patterns

Of course there are many, many, many, many, many, many, many, resources about this topic. But I think you are on the right path dividing up the objects and let them handle its own events/data and so on.

When doing tiled based board games you'll find it nice to have routines to map between the board array and row/col and back, along other features. I remember my first board game (long long ago) when I struggeled with how to get row/col from boardarray 5.

1  2  3  
4 (5) 6  BoardArray 5 = row 2, col 2
7  8  9  

Nostalgy. ;)

Anyway, http://www.gamedev.net/ is a good place for information. http://www.gamedev.net/reference/

Solution 5 - Design Patterns

Much of the materials I can find online are lists of published references. The publications section of Game Design Patterns has links to PDF versions of the articles and theses. Many of these look like academic papers like Design Patterns for Games. There is also at least one book available from Amazon, Patterns in Game Design.

Solution 6 - Design Patterns

Three Rings offers LGPL'd Java libraries. Nenya and Vilya are the libraries for game related stuff.

Of course, it would help if your question mentioned platform and/or language restrictions you might have.

Solution 7 - Design Patterns

I agree with Pyrolistical's answer and I prefer his way of doing things (I just skimmed the other answers though).

Coincidentally I also used his "GamePhase" naming. Basically what I would do in the case of a turn-based board game is have your GameState class contain an object of the abstract GamePhase as mentioned by Pyrolistical.

Lets say the game states are:

  1. Roll
  2. Move
  3. Buy/Don't buy
  4. Jail

You could have concrete derived classes for each state. Have virtual functions at least for:

StartPhase();
EndPhase();
Action();

In the StartPhase() function you could set all the initial values for a state for example disabling the other player's input and so forth.

When roll.EndPhase() is called then make sure the GamePhase pointer gets set to the next state.

phase = new MovePhase();
phase.StartPhase();

In this MovePhase::StartPhase() you would for example set the active player's remaining moves to the amount rolled in the previous phase.

Now with this design in place you could sort out your "3 x double = jail" problem inside the Roll phase. The RollPhase class can handle its own state. For example

GameState state; //Set in constructor.
Die die;         // Only relevant to the roll phase.
int doublesRemainingBeforeJail;
StartPhase()
{
    die = new Die();
    doublesRemainingBeforeJail = 3;
}

Action()
{
    if(doublesRemainingBeforeJail<=0)
    {
       state.phase = new JailPhase(); // JailPhase::StartPhase(){set moves to 0};            
       state.phase.StartPhase();
       return;
    }

    int die1 = die.Roll();
    int die2 = die.Roll();
    
    if(die1 == die2)
    {
       --doublesRemainingBeforeJail;
       state.activePlayer.AddMovesRemaining(die1 + die2);
       Action(); //Roll again.
    }

    state.activePlayer.AddMovesRemaining(die1 + die2);
    this.EndPhase(); // Continue to moving phase. Player has X moves remaining.
}

I differ from Pyrolistical in that there should be a phase for everything including when the player lands on Community chest or something. I would handle this all in the MovePhase. This is because if you have too many sequential phases, the player will very likely feel too "guided". For example, if there is a phase where the player can ONLY buy properties and then ONLY buy hotels and then ONLY buy houses, its like there is no freedom. Just slam all those parts into one BuyPhase and give the player the freedom to buy anything he wants. The BuyPhase class can easily enough handle which purchases are legal.

Finally let's address the gameboard. Though a 2D array is fine I'd recommend having a tile graph (where a tile is a position on the board). In the case of monoppoly it would rather be a doubly-linked list. Then every tile would have a :

  1. previousTile
  2. nextTile

So it would be much easier to do something like:

While(movesRemaining>0)
  AdvanceTo(currentTile.nextTile);

The AdvanceTo function can handle your step by step animations or whatever you like. And also decrement remaining moves of course.

RS Conley's Advice on Observer Pattern for the GUI is good.

I've not posted much before. Hope this helps someone.

Solution 8 - Design Patterns

> Is there some prior art I can take advantage of?

If your question ain't language- or platform-specific. then I would recommend that you consider AOP Patterns for State, Memento, Command, etc.

Whats the .NET answer to AOP???

Also try to find some cool websites such as http://www.chessbin.com

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJay BazuziView Question on Stackoverflow
Solution 1 - Design PatternsAndrew TopView Answer on Stackoverflow
Solution 2 - Design PatternsRS ConleyView Answer on Stackoverflow
Solution 3 - Design PatternsPyrolisticalView Answer on Stackoverflow
Solution 4 - Design PatternsStefanView Answer on Stackoverflow
Solution 5 - Design PatternsEric WeilnauView Answer on Stackoverflow
Solution 6 - Design PatternsjmucchielloView Answer on Stackoverflow
Solution 7 - Design PatternsReasurriaView Answer on Stackoverflow
Solution 8 - Design PatternszotherstupidguyView Answer on Stackoverflow