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:
- Roll
- Move
- Buy/Don't buy
- 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 :
- previousTile
- 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.