Monopoly -- Forum

Pages: 123
jonnin, you generate 1000000 numbers...

28227 + 50616 + 80444 + 110783 + 134874 + 144278 + 135857 + 110959 + 79885 + 50848 + 27911 = 954682
28155 + 50455 + 80223 + 111385 + 135407 + 143818 + 135773 + 110919 + 80019 + 50236 + 28159 = 954549
28075 + 50412 + 80392 + 111289 + 134863 + 144368 + 134991 + 111067 + 80245 + 50392 + 28416 = 954510

What happened to the rest? ;)
For info, there are several versions of C++ Monopoly on GitHub. Eg

Looking at some of the header files etc may give you some ideas re data design and structure.
[Reminiscence]

Ah Monopoly. That takes me back. I wrote a Monopoly game for 2 - 4 players way back in the 1970's in Dartmouth Basic (HP TSB) as a school project. The only 'containers' there was were a 1 or 2 dimension array of numbers (max 26 called A to Z) and 26 string variables (A\$ to Z\$) - apart from numeric variables (A - Z and A0 to Z9). If you wanted to have a record of say 2 numbers and 2 strings then the only way was to use a file of records (max 512 bytes - stored as 16 bit words) which could be accessed by a record number! As this was 'played' over 110 baud teletype and after every play the board was drawn, the speed of the program wasn't that important as most of the time was spent actually printing the board onto a paper roll.

Ah the 'good old days'!
@jonnin, it's nothing like a normal distribution:
(a) it's discrete (and finite domain), not continuous (and infinite domain)
(b) the laws of "large" numbers (central-limit theorem) definitely don't apply when N=2.

Your computed fractions for 3, 7 and 11 are consistently more than 10% in error (reflecting the shapes of the two curves).
Last edited on
I understand that its not a normal. I said you could get it close enough for a casual board game, and I stand by that. If anything I said implied that it was scientific or actually correct or even really useful for anything other than a crude ballpark, I did not mean for it to come out that way.

What happened to the rest? They are 1s & 13s and maybe even a few 0s & 14s. It needs work if you wanted to use it for something. You can tinker with the curve or code around it to force it within the bounds, but as I said above, for a number of reasons rolling 1-6 twice is really the best answer. Playing with the numbers does not change *that*.

a silly & simple force fit back to the center recovers the lost rolls and steeps the curve back toward where it belongs a little more. Still off by 10% at times, but again, a toy in the ballpark...
 ``123456`` `````` r = distribution(generator); if(r <1.5) r = 6; else if(r <2) r = 7; if(r > 13.5) r = 8; else if(r >= 13) r = 7; ct[(int)r]++; ``````

 ```2 28210 0.02821 3 50753 0.050753 4 80187 0.080187 5 111402 0.111402 6 149868 0.149868 7 160083 0.160083 8 149570 0.14957 9 110845 0.110845 10 80668 0.080668 11 50333 0.050333 12 28081 0.028081```
Last edited on
 as I said above, for a number of reasons rolling 1-6 twice is really the best answer.

Indeed. As said, in this game the result of 2d6 is not a "number", it is a tuple of a number and a boolean. The latter tells whether both die had same value.

Players act in turns. Therefore, they should be in cyclic container. For example:
 ```WHILE no winner player = players.next() roll = ... player->advance(roll) player->action() if ( player->isOut() ) players.erase( player ) else if ( roll was a double ) something()```

One has to get the owner of lot when a player enters that lot. The player might know what they own, but as well the lot could know its owner. Then it is easier to check if the owner is null, me, or who.
Didn't realize a proxy war had started from distributions but I've fixed the code to be more simple and reusable using some of the suggestions given.

Dice Function:
 ``1234567891011121314`` ``````int rollDie() { int rolls[2]; int min = 1; // the min number a die can roll is 1 int max = 6; // the max value is the die size for (size_t i = 0; i < 2; i++) { rolls[i] = rand() % (max - min + 1) + min; } int roll = rolls[0] + rolls[1]; return roll; }``````

If there is still a problem with this let me know

Results from the function:
 ```How many players? 4 8 9 6 7 The Maximum Roll was 9 by Player 2```
How would property ownership work? Like what structure would I use for storing when the player lands and autobuys the property.

For main (will be splitting up into multiple different classes)
 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198`` ``````#include #include #include #include #include #include #include #include "linkedlist.cc" #include "playerqueue.cc" using namespace std; struct Player { int cash; int board_pos; int token; string player_name; }; int rollDie() { int rolls[2]; int min = 1; // the min number a die can roll is 1 int max = 6; // the max value is the die size for (size_t i = 0; i < 2; i++) { rolls[i] = rand() % (max - min + 1) + min; } cout << "Roll 1: " << rolls[0] << "\nRoll 2: " << rolls[1] << endl; int roll = rolls[0] + rolls[1]; return roll; } vector fillboard() { vector board{ "GO", "Mediterranean Avenue (\$60)", "Community Chest", "Baltic Avenue (\$60)", "Income Tax (Pay \$200)", "Reading Railroad (\$200)", "Oriental Avenue (\$100)", "Chance", "Vermont Avenue (\$100)", "Connecticut Avenue (\$120)", "Jail", "St. Charles Place (\$140)", "Electric Company (\$150) ", "States Avenue (\$140)", "Virginia Avenue (\$160)", "Pennsylvania Railroad (\$200)", "St. James Place (\$180)", "Community Chest", "Tennessee Avenue (\$180)", "New York Avenue (\$200)", "Free Parking", "Kentucky Avenue (\$220)", "Chance", "Indiana Avenue (\$220)", "Illinois Avenue (\$240)", "B&O Railroad (\$200)", "Atlantic Avenue (\$260)", "Ventnor Avenue (\$260)", "Water Works (\$150)", "Marvin Gardens (\$280)", "Go To Jail", "Pacific Avenue (\$300)", "North Carolina Avenue (\$300)", "Community Chest", "Pennsylvania Avenue (\$320)", "Short Line (\$200)", "Chance", "Park Place (\$350)", "Luxury Tax (Pay \$75)", "Boardwalk (\$400)"}; return board; } vector property() { vector propertyvalue{ 0, 60, 0, 60, 200, 200, 100, 0, 100, 120, 0, 140, 150, 140, 160, 200, 180, 0, 180, 200, 0, 220, 0, 220, 240, 200, 260, 260, 150, 280, 0, 300, 300, 0, 320, 200, 0, 350, 75, 400}; return propertyvalue; } bool isOwned(int property) { if (property ==) { /* code */ } } int main(int argc, char const *argv[]) { //******************************************** // *Used for Player count // *Takes an input based on playercount 2-4 //******************************************** vector playerlist; int maxRoll; int players; string name; do { cout << "How many players? "; cin >> players; } while (players > 4 || players < 2); // Populate the playerlist for (int i = 0; i < players; i++) { Player player; // Populate player info playerlist.push_back(player); } for (auto player : playerlist) // inital gamestart. { cout << "Enter your name: "; cin >> name; player.cash = 1500; player.board_pos = 0; player.player_name = name; cout << "Player Cash: \$" << player.cash << endl; cout << "Position on board: " << player.board_pos << endl; cout << "Player Name: " << player.player_name << endl; } int rolloff[players]; srand(time(0)); for (int i = 0; i < players; i++) { rolloff[i] = rollDie(); cout << rolloff[i] << endl; } int n = sizeof(rolloff) / sizeof(rolloff[0]); // Intialize the value of max and index int max = INT_MIN; int index = -1; // Iterate the array for (int i = 0; i < n; i++) { if (rolloff[i] > max) { // If current value is greater than max // value then replace it with max value max = rolloff[i]; index = i; } } cout << "The Maximum Roll was "; cout << max << " by Player " << index + 1 << endl; vector board = fillboard(); vector propertyvalue = property(); cout << "\nThe Gameboard:\n" << endl; for (int i = 0; i < board.size(); i++) { if(propertyvalue[i] != 0) { cout << board[i] << " \$" << propertyvalue[i] << endl; } else{ cout << board[i] << endl; } } //******************************************** // * Start of the game // * Iteration through a for loop inbeded in a while loop //******************************************** bool gamestate = true; do { for (auto player : playerlist) { player.board_pos = player.board_pos + rollDie(); cout << "Player " << player.player_name << " Landed on " << board[player.board_pos] << endl; if(isOwned(propertyvalue[player.board_pos]) == false) player.cash = player.cash - propertyvalue[player.board_pos]; cout << } } while (gamestate == true); return 0; }``````

I know the last part is incomplete it's temporary
Last edited on
property should also be an object.
consider (this may be overkill since you simplified some of the rules but hey, its an example)
 ``123456789101112`` ``````struct property { int price; string name; int rent[6]; //none, 1,2,3,4 house, hotel int housecount{}; Player * owner{}; //nullptr at first, or make a bogus bank player? bool mortgaged{};//false default @ construct property * related[3]; //relate the other properties of same type or color? //optional cool junk like how many times landed on or total rent paid into it } vector board; ...``````

now, there is a concept called parallel arrays that can be handy, where you split up an object into many arrays that are all tied together via their index.
in that case, just if you want to see it:
 ``1234567`` ``````enum properties_e{baltic, ...fill in all of them..., boardwalk, numprops}; int Pprice[numprops]; string Pnames[numprops]; int Prents[numprops][6]; ...etc and then cout << Pnames[boardwalk] << "rent is " <

or whatever. I don't recommend splitting it up like this for you, but there are places where it has a performance lift in high speed code projects, or other places where this can make sense to do. Its a very annoying way to do things.

your rolldice is great. I still recommend learning <random> when you get a chance, its so much more flexible and only a tiny bit more effort. Not really a war, I was being fast and loose with some math, and while its close enough to screw around with, its not valid and they were right to call that out. The right approximation can be amazing in the right places, or complete trash as well. It was the latter, here.
Last edited on
You have several problem in your code. Especial line 126. The 'auto' trap. Try the following:
 ``12345678910111213141516171819202122232425262728293031323334353637383940`` ``````int main(int argc, char const *argv[]) { //******************************************** // *Used for Player count // *Takes an input based on playercount 2-4 //******************************************** vector playerlist; int maxRoll; int players; string name; do { cout << "How many players? "; cin >> players; } while (players > 4 || players < 2); // Populate the playerlist for (int i = 0; i < players; i++) { Player player; // Populate player info playerlist.push_back(player); } for (auto player : playerlist) // inital gamestart. { cout << "Enter your name: "; cin >> name; player.cash = 1500; player.board_pos = 0; player.player_name = name; } for (auto player : playerlist) // inital gamestart. { cout << "Player Cash: \$" << player.cash << endl; cout << "Position on board: " << player.board_pos << endl; cout << "Player Name: " << player.player_name << endl; } return 0; }`````` ```How many players? 2 Enter your name: a Enter your name: b Player Cash: \$0 Position on board: 0 Player Name: Player Cash: \$0 Position on board: 0 Player Name: ```

So the player in `playerlist` has no content. Why? Because `player` on line 126 is a copy and dismissed after the loop ends. Consider:

`for (Player& player : playerlist) // Note: & // inital gamestart. `

You actually don't need two loops (line 120/126). You can do all this within the loop on line 120
@jonnin - minor point but the related array should have 4 elements not 3 as the 4 stations need to be linked as the rent due for landing on one increases if more than 1 owned.
re game start. The players first roll the dice and the highest scorer starts. The rules (at least with my very old version) say nothing about duplicate highest scorers but we always then had the highest scorers roll again - and again et al until one person has a highest score who then starts first.

Also the names used are those of the tokens (which used to be ship, hat, dog, iron, car, boot).

In a first playable version, I'd avoid mortgages and property auctions. These add somewhat complexity. So if you land an an unowned property you either buy it or not. if not, then it's not auctioned. These additions can be added later if required.

 re game start. The players first roll the dice and the highest scorer starts. The rules (at least with my very old version) say nothing about duplicate highest scorers but we always then had the highest scorers roll again - and again et al until one person has a highest score who then starts first.

Statistically, that just boils down to "randomly select start player, with each person having an equal chance of being start player".

With physical dice, the "who rolls highest" method is a simple way of implementing that, but in a digital version, there's no need to model that process. Simply randomly selecting one player is statistically identical, and much more straightforward to implement.
I said 3 because self+3 -> 4 total. But that reminds me that you might want bools for 'is train' or 'is utility' on a property to trigger all the special logic for those. You can do it with 4 slots and put self into them, if you prefer it.
 Simply randomly selecting one player is statistically identical, and much more straightforward to implement.

Yes, put them into "bag" (e.g. vector) and shuffle. Then you have players in (random) order. https://cplusplus.com/reference/algorithm/shuffle/
Refined Main:

No clue how to implement the class structures (Being Player, Board, Community Chest and Properties) into the game in a smooth manner

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216`` ``````#include #include #include #include #include #include #include #include "linkedlist.cc" using namespace std; class Player { public: int cash; int board_pos; int token; // player turn string player_name; vector propertyOwned; // played owned properties }; class Board { public: int location; LinkList b; // board properties vector fillboard() //Names Only { vector board{ "GO", "Mediterranean Avenue ", "Community Chest", "Baltic Avenue ", "Income Tax ", "Reading Railroad ", "Oriental Avenue ", "Chance", "Vermont Avenue ", "Connecticut Avenue ", "Jail", "St. Charles Place ", "Electric Company ", "States Avenue ", "Virginia Avenue ", "Pennsylvania Railroad ", "St. James Place ", "Community Chest", "Tennessee Avenue ", "New York Avenue ", "Free Parking", "Kentucky Avenue ", "Chance", "Indiana Avenue ", "Illinois Avenue ", "B&O Railroad ", "Atlantic Avenue ", "Ventnor Avenue ", "Water Works ", "Marvin Gardens ", "Go To Jail", "Pacific Avenue ", "North Carolina Avenue ", "Community Chest", "Pennsylvania Avenue ", "Short Line ", "Chance", "Park Place ", "Luxury Tax ", "Boardwalk "}; } return board; }; class CommunityChest //use 2 stacks for cards (CHANCE/ComChest) { public: }; class Properties { public: vector property() // ADD to properties class { vector propertyvalue{ 0, 60, 0, 60, 200, 200, 100, 0, 100, 120, 0, 140, 150, 140, 160, 200, 180, 0, 180, 200, 0, 220, 0, 220, 240, 200, 260, 260, 150, 280, 0, 300, 300, 0, 320, 200, 0, 350, 75, 400}; return propertyvalue; } }; int rollDie() { int rolls[2]; int min = 1; // the min number a die can roll is 1 int max = 6; // the max value is the die size for (size_t i = 0; i < 2; i++) { rolls[i] = rand() % (max - min + 1) + min; } cout << "Roll 1: " << rolls[0] << "\nRoll 2: " << rolls[1] << endl; int roll = rolls[0] + rolls[1]; return roll; } bool isOwned(int property) { //*TODO: Add return*// // OR SCRAP FUNCTION// } int main(int argc, char const *argv[]) { //******************************************** // *Used for Player count // *Takes an input based on playercount 2-4 //******************************************** vector playerlist; int players; string name; do { cout << "How many players? "; cin >> players; } while (players > 4 || players < 2); // Populate the playerlist for (int i = 0; i < players; i++) { Player player; // Populate player info playerlist.push_back(player); } for (auto player : playerlist) // inital gamestart. { cout << "Enter your name: "; cin >> name; player.cash = 1500; player.board_pos = 0; player.player_name = name; } for (auto player : playerlist) // inital gamestart. { cout << "Player Cash: \$" << player.cash << endl; cout << "Position on board: " << player.board_pos << endl; cout << "Player Name: " << player.player_name << endl; } int rolloff[players]; srand(time(0)); for (int i = 0; i < players; i++) { rolloff[i] = rollDie(); cout << rolloff[i] << endl; } int n = sizeof(rolloff) / sizeof(rolloff[0]); // Intialize the value of max and index int max = INT_MIN; int index = -1; // Iterate the array for (int i = 0; i < n; i++) { if (rolloff[i] > max) { // If current value is greater than max // value then replace it with max value max = rolloff[i]; index = i; } } cout << "The Maximum Roll was "; cout << max << " by Player " << index + 1 << endl; vector board = fillboard(); //edit this** vector propertyvalue = property(); //edit this** cout << "\nThe Gameboard:\n" << endl; for (int i = 0; i < board.size(); i++) { if (propertyvalue[i] != 0) { cout << board[i] << " \$" << propertyvalue[i] << endl; } else { cout << board[i] << endl; } } //******************************************** // * Start of the game // * Iteration through a for loop inbeded in a while loop //******************************************** //bool gamestate = true; // do // { // for (auto player : playerlist) // { // player.board_pos = player.board_pos + rollDie(); // cout << "Player " << player.player_name << " Landed on " // << board[player.board_pos] << endl; // if (isOwned(propertyvalue[player.board_pos]) == false) // player.cash = player.cash - propertyvalue[player.board_pos]; // player.addProperty = board[player.board_pos]; // cout << "Current Cash: \$" << player.cash << endl; // } // } while (gamestate == true); return 0; }``````

A lot of errors for obvious reasons
Last edited on
Oh yeah and here's the concurrent outline for my program just to get a basis:
I would like to focus the majority of my attention on the Properties class because that's the one causing the most issues

- allow to choose the amount of players (players can be all bots)
- have a simple display of what each player has landed on and a print out of all - transactions that happened during the game with output to a file
- have the players start with \$1500 at the beginning of the game
- make it that whenever a player lands on a property the player auto buys that property
- make it that whenever a player lands on an already bought property they pay rent to that player
- make it that whenever a player passes go their money increments by \$200
- make it that if a player lands on go to jail they get sent directly to jail( don't need to roll doubles to get out)
- make use of the community chest and chance cards. Only need to use 5 cards for each and have them recycle

No GUI stuff needed this is just going to be console/text based
I'm just trying to do this in the simplest form possible
Last edited on
You might consider reading property information from a file.
This allows you to change the game without reprogramming it.

property.txt
format is: <name> , <action> , <cost>
 ``12345678910111213141516171819202122232425262728293031323334353637383940`` `````` GO,0,0 Mediterranean Avenue,1,60 Community Chest,2,0 Baltic Avenue,1,60 Income Tax,3,200 Reading Railroad,4,200 Oriental Avenue,1,100 Chance,5,0 Vermont Avenue,1,100 Connecticut Avenue,1,120 Jail,6,0 St. Charles Place,1,140 Electric Company,7,150 States Avenue,1,140 Virginia Avenue,1,160 Pennsylvania Railroad,4,200 St. James Place,1,180 Community Chest,2,0 Tennessee Avenue,1,180 New York Avenue,1,200 Free Parking,8,0 Kentucky Avenue,1,220 Chance,5,0 Indiana Avenue,1,220 Illinois Avenue,1,240 B&O Railroad,4,200 Atlantic Avenue,1,260 Ventnor Avenue,1,260 Water Works,7,150 Marvin Gardens,1,280 Go To Jail,9,0 Pacific Avenue,1,300 North Carolina Avenue,1,300 Community Chest,2,0 Pennsylvania Avenue,1,320 Short Line,4,200 Chance,5,0 Park Place,1,350 Luxury Tax,3,75 Boardwalk,1,400``````

property.h
 ``12345678910111213141516171819202122232425`` ``````#pragma once #include // The following values are hard coded in the property.txt file enum class Action { GO = 0, PROPERTY = 1, COMMUNITY_CHEST = 2, TAX = 3, RAILROAD = 4, CHANCE = 5, JAIL = 6, UTILITY = 7, FREE_PARKING = 8, GOTO_JAIL = 9 }; struct Property { std::string m_name; Action m_action; int m_cost; // Other attributes };``````

PropFile.h
 ``1234567891011121314151617`` ``````#pragma once #include #include #include #include #include "property.h" class PropFile { std::ifstream m_ifs; public: PropFile(const std::string& fname); bool ReadData(std::vector& props); void Dump(const std::vector& props); };``````

PropFile.cpp
 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657`` ``````#include #include #include #include #include #include "PropFile.h" using namespace std; /* * Class to read property information from a file * Format is: * , , */ PropFile::PropFile(const std::string& fname) { m_ifs.open(fname); if (!m_ifs.is_open()) { cout << "Unable to open property data file" << endl; exit(1); } } bool PropFile::ReadData (vector & props) { string line; int act; while (getline(m_ifs, line)) { stringstream ss(line); Property prop; string temp; if (!getline(ss, prop.m_name, ',')) return false; // error reading property name if (!getline(ss, temp, ',')) return false; act = atoi(temp.c_str()); prop.m_action = (enum Action)act; if (!getline(ss, temp, ',')) return false; prop.m_cost = atoi(temp.c_str()); props.push_back(prop); } return true; } void PropFile::Dump(const std::vector& props) { for (auto prop : props) cout << setw(30) << prop.m_name << " " << (int)prop.m_action << " " << prop.m_cost << endl; }``````

A test program:
 ``12345678910111213141516171819202122`` ``````#include #include #include #include #include #include #include "propfile.h" using namespace std; int main(int argc, char const* argv[]) { vector properties; PropFile propfile("property.txt"); if (!propfile.ReadData(properties)) { cout << "Problem parsing line" << endl; return 2; } propfile.Dump(properties); return 0; }``````

Last edited on
I 'knocked up' this program over the weekend whilst watching sport. I confess there was very little thought given to the design! It automatically plays with 2 - 6 players. It has some current restrictions. No chance/community chest. No in Jail. No mortgaging. No auctions.

It might give some ideas...

If I get some of the rest coded before the time limit on this thread expires, I'll post the updated code.

There are 8 files board.h, dice.h, monopoly.h, places.h, player.h, places.cpp, player.cpp, monopoly.cpp (main)

Note that I make no claims re this. Now that it can be used to 'play', it's probably due for a refactor. However, anyone who wants to use/change feel free.

board.h
 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107`` ``````#pragma once #include "places.h" #include "dice.h" #include #include #include // Represents the Monopoly board class Board { std::vector places { // Specifies the details of each place on the board {Go, new cGo}, {OldKentRoad, new cProp(2, 10, 30, 90, 160, 250, 60, 50, 50, 30), {WhitechapelRoad}}, {CommunityChest1, new cComm}, {WhitechapelRoad,new cProp(4, 20, 60, 180, 320, 450, 60, 50, 50, 30), {OldKentRoad}}, {IncomeTax, new cTax(200)}, {KingscrossStation, new cStation(25, 50, 100, 200, 200, 100), {MaryleboneStation, FenchurchStreetStation, LiverpoolStreetStation}}, {TheAngelIslington, new cProp(6, 30, 90, 270, 400, 550, 100, 50, 50, 50), {EustonRoad, PentovilleRoad}}, {Chance1, new cChance}, {EustonRoad, new cProp(6, 30, 90, 270, 400, 550, 100, 50, 50, 50), {TheAngelIslington, PentovilleRoad}}, {PentovilleRoad, new cProp(8, 40, 100, 300, 450, 600, 100, 50, 50, 60), {TheAngelIslington, EustonRoad}}, {Jail, new cJail}, {PallMall, new cProp(10, 50, 150, 450, 625, 750, 140, 100, 100, 70)}, {ElecticCompany, new cUtility(150, 75)}, {Whitehall, new cProp(10, 50, 150, 450, 625, 750, 140, 100, 100, 70)}, {NorthumberlandAvenue, new cProp(12, 60, 180, 500, 700, 900, 160, 100, 100, 80)}, {MaryleboneStation, new cStation(25, 50, 100, 200, 200, 100)}, {BowStreet, new cProp(14, 70, 200, 550, 750, 950, 180, 100, 100, 90)}, {CommunityChest2, new cComm}, {MarlboroughStreet, new cProp(14, 70, 200, 550, 750, 950, 180, 100, 100, 90)}, {VineStreet, new cProp(16, 80, 220, 600, 800, 1000, 200, 100, 100, 100)}, {Freeparking, new cParking}, {Strand, new cProp(18, 90, 250, 700, 875, 1050, 220, 150, 150, 110)}, {Chance2, new cChance}, {FleetStreet, new cProp(18, 90, 250, 700, 875, 1050, 220, 150, 150, 110)}, {TrafalgarSquare, new cProp(20, 100, 300, 750, 925, 1100, 240, 150, 150, 120)}, {FenchurchStreetStation, new cStation(25, 50, 100, 200, 200, 100)}, {LeicesterSquare, new cProp(22, 110, 330, 800, 975, 1150, 260, 150, 150, 130)}, {CoventryStreet, new cProp(22, 110, 330, 800, 975, 1150, 260, 150, 150, 130)}, {WaterWorks, new cUtility(150, 75)}, {Picadilly, new cProp(22, 120, 360, 850, 1025, 1200, 280, 150, 150, 140)}, {GoToJail, new cGoJail}, {RegentSreet, new cProp(26, 130, 390, 900, 1100, 1275, 300, 200, 200, 150)}, {OxfordStreet, new cProp(26, 130, 390, 900, 1100, 1275, 300, 200, 200, 150)}, {CommunityChest3, new cComm}, {BondStreet, new cProp(28, 150, 450, 1000, 1200, 1400, 320, 200, 200, 160)}, {LiverpoolStreetStation, new cStation(25, 50, 100, 200, 200, 100)}, {Chance3, new cChance}, {ParkLane, new cProp(35, 175, 500, 1100, 1300, 1500, 350, 200, 200, 175)}, {SuperTax, new cTax(100)}, {Mayfair, new cProp(50, 200, 600, 1400, 1700, 2000, 400, 200, 200, 200)} }; cDice dic; // Dice to use public: Board() { // Set pointer for each place to Board class for (auto& p : places) p.setBoard(this); } ~Board() { for (auto& p : places) delete p.getPlaceC(); } // Can't copy or assign Board class Board(const Board&) = delete; Board& operator=(const Board&) = delete; // Number of board elements unsigned size() const noexcept { return unsigned(places.size()); } // Display the board void display() noexcept { for (auto& b : places) { for (const auto& ps : b.getPlayers()) std::cout << sNames[ps] << " "; b.getPlaceC()->display(b); std::cout << '\n'; } std::cout << '\n'; } // Get specified place Places& getPlace(unsigned pos) noexcept { return places[pos]; } // Shake the dice Dice shake() noexcept { return dic.shake(); } // Release owned places void release(Symbols owner) { for (auto& b : places) if (b.getOwner() == owner) b.setOwner(None); } };``````

dice.h
 ``123456789101112131415161718192021222324252627282930313233343536373839`` ``````#pragma once #include #include struct Dice { unsigned first {}; // First dice thrown unsigned second {}; // Second dice thrown unsigned total {}; // Total of the two die bool isdouble {}; // Set if both dice the same value }; // Display the dice inline std::ostream& operator<<(std::ostream& os, const Dice& di) { return os << di.total << " (" << di.first << ", " << di.second << ')'; } // Class for the dice class cDice { std::uniform_int_distribution die; Dice dice {}; public: cDice() noexcept : die(1, 6) {} // Shake the dice Dice shake() noexcept { dice.first = die(rng); dice.second = die(rng); dice.total = dice.first + dice.second; dice.isdouble = dice.first == dice.second; return dice; } // Get last die throw Dice last() const noexcept { return dice; } };``````

monopoly.h
 ``123456789101112131415161718192021222324252627282930313233343536`` ``````#pragma once #include #include #include #include inline std::mt19937 rng(std::random_device {}()); inline constexpr unsigned MaxPlayer { 6 }; enum Place {Go, OldKentRoad, CommunityChest1, WhitechapelRoad, IncomeTax, KingscrossStation, TheAngelIslington, Chance1, EustonRoad, PentovilleRoad, Jail, PallMall, ElecticCompany, Whitehall, NorthumberlandAvenue, MaryleboneStation, BowStreet, CommunityChest2, MarlboroughStreet, VineStreet, Freeparking, Strand, Chance2, FleetStreet, TrafalgarSquare, FenchurchStreetStation, LeicesterSquare, CoventryStreet, WaterWorks, Picadilly, GoToJail, RegentSreet, OxfordStreet, CommunityChest3, BondStreet, LiverpoolStreetStation, Chance3, ParkLane, SuperTax, Mayfair}; enum PlaceType {GoT, PropT, CommChestT, IncometaxT, StationT, ChanceT, InJail, VisitJail, UtilityT, ParkingT, GoJailT}; enum Symbols {None, Iron = 1, Hat, Dog, Boot, Ship, Car}; inline constexpr const char* pNames[] { "Go", "Old Kent Road", "Community Chest", "White Chapel Road", "Income Tax", "Kings Cross Station", "The Angel Islington", "Chance", "Euston Road", "Pentoville Road", "Jail", "Pall Mall", "Electric Company", "Whitehall", "Northumberland Avenue", "Marylebone Station", "Bow Street", "Community Chest", "Marlborough Street", "Vine Street", "Free Parking", "Strand", "Chance", "Fleet Street", "Trafalgar Square", "Fenchurch Street Station", "Leicester Square", "Coventry Street", "Water Works", "Picadilly", "Go To Jail", "Regent Street", "Oxford Street", "Community Chest", "Bond Street", "Liverpool Street Station", "chance", "Park Lane", "Super Tax", "Mayfair" }; inline constexpr const char* sNames[] { "None", "Iron", "Hat", "Dog", "Boot", "Ship", "Car" }; static_assert(Mayfair == 39, "Missing Place"); static_assert(Car == 6, "Missing player"); static_assert(std::size(pNames) == Mayfair + 1, "Missing place name"); static_assert(std::size(sNames) == Car + 1, "Missing symbol name"); static_assert(Car <= MaxPlayer, "Missing symbol name");``````

Last edited on
places.h
 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180`` ``````#pragma once #include #include #include #include "monopoly.h" #include "player.h" class Board; class cPlace; class Places { cPlace* const place; // Pointer to required class cPlayers players; // Players currently on this place const std::vector associated; // Associated places of the same type Symbols owner { None }; // Owner Board* board {}; // Pointer to main board const Place pl {}; // Place name public: Places(Place plc, cPlace* p) noexcept : pl(plc), place(p) {} Places(Place plc, cPlace* p, std::initializer_list ass) : pl(plc), place(p), associated(ass.begin(), ass.end()) {} // Get place derived class cPlace* getPlaceC() noexcept { return place; } // Set pointer to board void setBoard(Board* b) noexcept { board = b; } // Return pointer to board Board* getBoard() const noexcept { return board; } // Get associated properties const std::vector& getAssociated() const noexcept { return associated; } // Get players for this place cPlayers& getPlayers() noexcept { return players; } // Get place name Place getPlace() noexcept { return pl; } // Get property owner Symbols getOwner() const noexcept { return owner; } void setOwner(Symbols o) noexcept { owner = o; } }; // Base for polymorphic classes for each place type class cPlace { public: virtual ~cPlace() = default; void show(Players& pls); virtual void play(Players&) = 0; virtual void display(Places& pl) const noexcept { std::cout << pNames[pl.getPlace()]; } }; // GO class class cGo : public cPlace { static const unsigned collect { 200 }; // Amount to collect when pass/land on Go public: void play(Players&) override; }; // Property class class cProp : public cPlace{ const unsigned rent[5] {}; // Rents for number houses (0 - 4) const unsigned rentHot {}; // Rent for hotel const unsigned buy {}; // Price to buy const unsigned house {}; // Cost for a house const unsigned hotel {}; // Cost for an hotel const unsigned mortage {}; // Mortgage value (not yet used) unsigned houses {}; // Number of houses erected bool hasHotel {}; // Has an hotel been built? bool allOwned(const Places& pl) const noexcept; // Are all associated properties owned? public: cProp(unsigned r, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned rhot, unsigned b, unsigned h, unsigned hot, unsigned mor) noexcept : rent{r, r1, r2, r3, r4}, rentHot(rhot), buy(b), house(h), hotel(hot), mortage(mor) {} void play(Players&) override; void display(Places& pl) const noexcept override; }; // Community Chest class class cComm : public cPlace { public: void play(Players&) override; }; // Income Tax class class cTax : public cPlace { const unsigned tax {}; // Amount of tax to pay public: cTax(unsigned t) : tax(t) {} void play(Players&) override; void display(Places& pl) const noexcept override; }; // Station class class cStation : public cPlace { const unsigned rent[4] {}; // Rents for 1 - 4 stations owned const unsigned buy {}; // Price to buy const unsigned mortage {}; // Mortgage value (not yet used) unsigned manyOwned(const Places& pl) const noexcept; // How many stations are owned public: cStation(unsigned r, unsigned r2, unsigned r3, unsigned r4, unsigned b, unsigned mor) noexcept : rent { r, r2, r3, r4 }, buy(b), mortage(mor) {} void play(Players&); void display(Places& pl) const noexcept override; }; // Chance class class cChance : public cPlace { public: void play(Players&) override; }; // Jail class class cJail : public cPlace { // Needs to deal with in jail and just visiting!!! public: void play(Players&) override; }; // Utility class class cUtility : public cPlace { const static inline unsigned rent[2] { 4, 10 }; // Rents due if 1 or both utilities used unsigned buy {}; unsigned mor {}; unsigned manyOwned(const Places& pl) const noexcept; // How many utilities owned public: cUtility(unsigned b, unsigned m) noexcept : buy(b), mor(m) {} void play(Players&) override; void display(Places& pl) const noexcept override; }; // Parking class class cParking : public cPlace { public: void play(Players&) override; }; // Go to Jail class class cGoJail : public cPlace { public: void play(Players&) override; };``````

player.h
 ``12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273`` ``````#pragma once #include #include #include #include "monopoly.h" #include "dice.h" class Board; // Represents a player class Player { static const unsigned init { 1500 }; public: int amount {init}; // Amount of money player has Symbols symbol; // Symbol used by this player unsigned position {}; // Board position Dice dice {}; // Last dice thrown bool inPlay { true }; // false if bankrupt }; // Represents all players playing the game class Players { std::vector players; // All valid players unsigned curr {}; // Current player index into players Board& brd; // Board to use public: // Obtain number of players and generate players vector accordingly Players(Board& b); // Returns current player Player& getCurr() noexcept ; // Advances to next player Player& next() noexcept; // Advance position on the board for the current player void advance(unsigned no); // Returns board Board& getBoard() { return brd; } unsigned noPlayers() const noexcept; void details() const; }; // Players currently on any same board place class cPlayers { std::set players; public: void addPlayer(Symbols p) { players.insert(p); } void removePlayer(Symbols p) { players.erase(p); } auto begin() { return players.begin(); } auto end() { return players.end(); } };``````

Pages: 123