Previous Lecture | Top Level

How to Finish the Monopoly Engine

Contents


Next Section | Contents

What do we already have?

Constructing large programs is generally accomplished in three steps:
Build Foundation:
If you look at the class hierarchy, you can consider all non-terminal nodes of the tree to be part of the foundation. These classes are not specific to the monopoly project and could be used for any other project. You couldn't tell, just by looking at those classes, that you are actually building a monopoly engine.

One the other hand, we did make some decisions on which kind of foundation class to use, based on our later intended usage. For example, we chose to use linked lists instead of arrays. We chose to use a specific implementation of smart pointers.

Build Framework
The terminal nodes of the class hierarchy are specific to our monopoly project. At this stage, though, we kept the implementation of several member functions open and restricted ourselves to function stubs, to be filled out later.

For example, the Space object has two functions, pass() and stop() which are to be called whenever we pass or stop in the space. As you can see, the first implementation of Space::pass() and Space::stop() simply print out debugging information.

Fill in Framework
The final step in constructing large programs consists of filling in the function stubs defined in the previous phase.

At the end of Change 26, we are just about finished with the framework building phase and may begin with the filling in phase.


Next Section | Previous Section

Which objects are still missing?

Although we now have all the objects required to represent the state of a monopoly game, we still need some objects to specify the possible actions of the players. Obviously, we will stick to the now well established scheme and start by defining Action and derivatives thereof. We will then put those actions in a list (ActionList) and process this list at some stage:

Process Diagram

Here are some actions that come to my mind:

ClaimRentAction
A player notices that the current player is on his property. You simply take the money.
BuyDeedAction
The current player buys the property he is on.
BidDeedAction
In case of an auction, the highest bidding player takes the property.
PayBailAction
Pay bail to exit from the jail.
FreeJailCardAction
Get out of jail using a saved chest or chance card.
GivePlayerMoneyAction
A player gives the current player money.
MortgageAction
Mortgage property.
UnmortgageAction
Repay mortgage.
BuildHouseAction
Build a house on a property.
SellHouseAction
Sell houses.
GivePlayerDeedAction
A player gives a deed to the current player.

This is probably not a complete list, but should give you an idea...


Contents | Previous Section

How do we make it work?

When talking about actions, think of player decisions. Obviously, in a real monopoly game, people do a lot of things but don't really get a choice. For example, rolling dice is not an action, nor is moving your piece, nor is taking a card and following those instructions. All these things can be done automatically.

The moment we need player actions is when we run out of things to do automatically. So, when we start our monopoly engine, the first thing we do is process the player actions, then process all the automatic stuff like rolling dice, moving pieces etc... The engine terminates if we run out of things to do. The main program of the finished monopoly engine should look something like this:

#include <Game.h>
#include <ActionList.h>

main()
{
  Game game;
  ActionList actions;

  game.read();
  actions.read();

  actions.execute(); // call the execute() member functions
                     // of all the actions in the list.
  game.execute();    // do the automatic stuff

  game.write();
}

The actions are pretty much self contained. A little thought is required for the Game::execute() function. Here is a possible sequence of events:

Check for Bankruptcy
If, after all the actions have been processed, a player has a negative account, it is assumed that the player failed to raise enough money to pay his debts. His properties revert back to the bank, any houses that for some reason remain on the property disappear, any cards the player holds are discarded and the player is deleted from the player loop. If only one player remains, he has won and the game is over.

Determine Current Player
If there is no current player, the game is just beginning. Shuffle the cards and choose a player at random. If the last roll was a double, or if the current player just got out of jail, keep the current player, otherwise select the next player.

Roll Dice
Put the player into prison if this is his 3rd consecutive double and proceed immediatly to the next player.

Move Player
If the current player is in prison, only move him if he rolls a double. Call the Space::pass() and Space::stop() functions while you move. Some of these functions may trigger another movement...

One thing to watch out for is when to stop. For example, if a player rolls a double, you cannot simply let him move twice, as players might want to act between the two moves. This is why we have step two in the list above.

Remember that this is just a suggestion, and now that the graded project work is over, you may feel free to adopt any line you want.

Most important: Happy Coding - It's supposed to be fun!


Previous Lecture | Contents
Christian Goetze