/*
* Monopoly square probabilities.
*
* This program will use a simulation of many turns to find the probabilities
* of landing on the different squares in Monopoly. Two tables are printed
* at the end. One for the strategy of paying to get out of jail immediately
* and the other is for the strategy of staying in as long as possible. The
* numbers are the probabilities that a player will end up on the gameboard
* squares, which is somewhat different than the probability of landing on
* squares. Although one may land on the Go To Jail square, one never ends
* up there. A similar situation exists when landing on a Chance or Community
* Chest square where there is a probability based on what card is chosen that
* one will end up on a different square.
*
* I have also added a table that determines how likely it is on each square
* for the last two rolls to have been doubles. This is used by my other
* program that calculates the probabilities using a Markov Matrix.
*
* By Truman Collins
* January 14, 1997
* April 17, 1997
*
* Copyright 1997 By Truman Collins
*/
/* Static data. */
static int square_count[41];
static int more_to_do[41];
static int chance_square[41];
static int comm_chest_square[41];
static int total_rolls_starting_here[41];
static int total_rolls_here_with_prev_two_doubles[41];
static long start_time, end_time, elapsed_time;
static int leave_jail;
static unsigned long limit;
static unsigned int passed_go_count;
static unsigned int pennsylvania_double;
static unsigned int total_pennsylvania;
static unsigned int b_and_o_double;
static unsigned int total_b_and_o;
static unsigned int reading_double;
static unsigned int total_reading;
static double chance_money;
static double comm_chest_money;
static unsigned int water_works_count;
static double water_works_roll_sum;
static unsigned int electric_co_count;
static double electric_co_roll_sum;
#include
#include
#include
void initialize(void)
{
int i;
/* First initialize everything to zero. */
for(i = 0; i < 41; i++) {
square_count[i] = 0;
more_to_do[i] = 0;
chance_square[i] = 0;
comm_chest_square[i] = 0;
total_rolls_starting_here[i] = 0;
total_rolls_here_with_prev_two_doubles[i] = 0;
}
/* Now set those bits that need to be. */
/* One for go to jail square and the others for Chance */
/* and Community Chest. */
more_to_do[30] = 1;
more_to_do[2] = 1;
comm_chest_square[2] = 1;
more_to_do[7] = 1;
chance_square[7] = 1;
more_to_do[17] = 1;
comm_chest_square[17] = 1;
more_to_do[22] = 1;
chance_square[22] = 1;
more_to_do[33] = 1;
comm_chest_square[33] = 1;
more_to_do[36] = 1;
chance_square[36] = 1;
time(&start_time);
srand(start_time);
passed_go_count = 0;
pennsylvania_double = 0;
total_pennsylvania = 0;
b_and_o_double = 0;
total_b_and_o = 0;
reading_double = 0;
total_reading = 0;
chance_money = 0;
comm_chest_money = 0;
water_works_count = 0;
water_works_roll_sum = 0.0;
electric_co_count = 0;
electric_co_roll_sum = 0.0;
}
void print_probabilities(
char *header
)
{
int i;
double value;
printf("\n\nLand-on frequencies as percentages after %lu rolls for prefered %s:\n",
limit, header);
for(i = 0; i < 41; i++) {
if(i != 0 && i % 10 == 0) printf("\n");
printf("%5.3f ", 100.0 * square_count[i] / (double) limit);
}
printf("\n\n");
printf("Probabilities we have had two doubles when rolling from a square\n");
for(i = 0; i < 41; i++) {
if(i != 0 && i % 10 == 0) printf("\n");
if(total_rolls_starting_here[i] == 0.0) {
value = 0.0;
} else {
value = (double) total_rolls_here_with_prev_two_doubles[i] /
(double) total_rolls_starting_here[i];
}
printf("%8.6f ", value);
}
printf("\n");
printf("Passed or landed on Go %lu times for an income per roll of %7.4f\n",
passed_go_count, 200.0 * ((double) passed_go_count / (double) limit));
printf("Income per roll from Chance cards: %6.4f\n",
chance_money / (double) limit);
printf("Income per roll from Community Chest cards: %6.4f\n",
comm_chest_money / (double) limit);
printf("Percent of time landing on Reading RR from Chance for double pay: %7.4f\n",
100.0 * ((double) reading_double / (double) total_reading));
printf("Percent of time landing on Pennsylvania RR from Chance for double pay: %7.4f\n",
100.0 * ((double) pennsylvania_double / (double) total_pennsylvania));
printf("Percent of time landing on B and O RR from Chance for double pay: %7.4f\n",
100.0 * ((double) b_and_o_double / (double) total_b_and_o));
printf("Average roll for Electric Company: %7.4f\n",
electric_co_roll_sum / electric_co_count);
printf("Average roll for Water Works: %7.4f\n",
water_works_roll_sum / water_works_count);
}
#define TRANSFER_TO_NEW_SQUARE(sq) \
sq_count[curr_square]--; \
curr_square = sq; \
sq_count[curr_square]++;
void do_calculation(void)
{
int curr_square = 0;
int roll1, roll2, full_roll;
int doubles_in_a_row;
unsigned long i;
int in_jail = 0;
int card;
int *sq_count;
int *more;
int *chance;
int *comm_chest;
sq_count = square_count;
more = more_to_do;
chance = chance_square;
comm_chest = comm_chest_square;
for(i = 0; i < limit; i++) {
/* Keep track of number of times starting here and the number */
/* of those where two doubles were rolled previously. */
/* Don't bother for in jail square. */
if(curr_square != 40) {
total_rolls_starting_here[curr_square]++;
if(doubles_in_a_row == 2) {
total_rolls_here_with_prev_two_doubles[curr_square]++;
}
if(curr_square == 12) {
electric_co_count++;
electric_co_roll_sum += full_roll;
}
if(curr_square == 28) {
water_works_count++;
water_works_roll_sum += full_roll;
}
}
/* If we've spent enough time in jail, get out, by */
/* transfering to the visiting jail square and continue. */
if(in_jail) {
if(in_jail == leave_jail) {
curr_square = 10;
in_jail = 0;
doubles_in_a_row = 0;
} else {
in_jail++;
}
}
/* Roll the dice. */
roll1 = rand() % 6 + 1;
roll2 = rand() % 6 + 1;
full_roll = roll1 + roll2;
/* If we're in jail, see if we got out with a double. If not */
/* then just add to the in jail count and go to the next roll.*/
if(in_jail) {
if(roll1 == roll2) {
curr_square = 10;
in_jail = 0;
doubles_in_a_row = 0;
} else {
sq_count[40]++;
continue;
}
}
/* Check for three doubles. If found, go to jail. */
if(roll1 == roll2) {
if(doubles_in_a_row == 2) {
curr_square = 40;
sq_count[curr_square]++;
doubles_in_a_row = 0;
in_jail = 1;
continue;
} else {
doubles_in_a_row++;
}
} else {
doubles_in_a_row = 0;
}
/* Make the move. */
curr_square += full_roll;
if(curr_square >= 40) {
curr_square -= 40;
passed_go_count++;
}
sq_count[curr_square]++;
if(curr_square == 5) {
total_reading++;
}
if(curr_square == 15) {
total_pennsylvania++;
}
if(curr_square == 25) {
total_b_and_o++;
}
/* Check for a square that causes another movement. */
if(more[curr_square]) {
if(curr_square == 30) {
/* Go to jail square, count as jail square. */
TRANSFER_TO_NEW_SQUARE(40);
in_jail = 1;
}
/* Note that we can't use an else if after the Chance */
/* section because from the last Chance square it's */
/* possible to end up in the last Community Chest, */
/* where you need to deal with that. */
if(chance[curr_square]) {
/* Here, we take a random Chance card. */
/* If it sends us to another location, go there. */
card = rand() % 16;
switch(card) {
case 0 :
/* Go to Boardwalk. */
TRANSFER_TO_NEW_SQUARE(39);
break;
case 1 :
/* Go to Reading Railroad. */
TRANSFER_TO_NEW_SQUARE(5);
total_reading++;
passed_go_count++;
break;
case 2 :
/* Go to Illinois Ave. */
TRANSFER_TO_NEW_SQUARE(24);
if(curr_square == 36) {
passed_go_count++;
}
break;
case 3 :
/* Go to ST. Charles Place. */
TRANSFER_TO_NEW_SQUARE(11);
if(curr_square != 7) {
passed_go_count++;
}
break;
case 4 :
/* Go to Go. */
TRANSFER_TO_NEW_SQUARE(0);
passed_go_count++;
break;
case 5 :
/* Go to Jail. */
TRANSFER_TO_NEW_SQUARE(40);
in_jail = 1;
break;
case 6 :
case 7 :
/* Go to next railroad. There are two cards. */
switch(curr_square) {
case 7 :
/* Go to the Pennsylvania Railroad. */
TRANSFER_TO_NEW_SQUARE(15);
pennsylvania_double++;
total_pennsylvania++;
break;
case 22 :
/* Go to the B & O Railroad. */
TRANSFER_TO_NEW_SQUARE(25);
b_and_o_double++;
total_b_and_o++;
break;
case 36 :
/* Go to the Reading Railroad. */
TRANSFER_TO_NEW_SQUARE(5);
reading_double++;
total_reading++;
break;
default :
/* This should never happen. */
fprintf(stderr, "Bad Chance square. We are on %d.\n", curr_square);
}
break;
case 8 :
/* Go back three places. */
TRANSFER_TO_NEW_SQUARE(curr_square - 3);
break;
case 9 :
/* Go to the nearest Utility. */
switch(curr_square) {
case 7 :
case 36 :
/* Go to the Electric Company. */
TRANSFER_TO_NEW_SQUARE(12);
if(curr_square == 36) {
passed_go_count++;
}
break;
case 22 :
/* Go to the Water Works. */
TRANSFER_TO_NEW_SQUARE(28);
break;
default :
/* This should never happen. */
fprintf(stderr, "Bad Chance square. We are on %d.\n", curr_square);
}
break;
case 10 :
/* Bank pays dividend of $50. */
chance_money += 50;
break;
case 11 :
/* Pay poor tax of $15. */
chance_money -= 15;
break;
case 12 :
/* Building loan matures, collect $150. */
chance_money += 150;
break;
default :
/* A card that leaves us on this square */
/* and that we do nothing with. */
break;
}
}
if(comm_chest[curr_square]) {
/* Here, we take a random community chest card. */
/* If it sends us to another location, go there. */
card = rand() % 16;
switch(card) {
case 0 :
/* Go to Go. */
TRANSFER_TO_NEW_SQUARE(0);
passed_go_count++;
break;
case 1 :
/* Go to Jail. */
TRANSFER_TO_NEW_SQUARE(40);
in_jail = 1;
break;
case 2 :
/* Get $10 in Beauty Contest */
comm_chest_money += 10;
break;
case 3 :
/* Get $45 for sale of stock. */
comm_chest_money += 45;
break;
case 4 :
/* Inherit $100 */
comm_chest_money += 100;
break;
case 5 :
/* Receive $25 for services. */
comm_chest_money += 25;
break;
case 6 :
/* Pay doctor's fee of $50. */
comm_chest_money -= 50;
break;
case 7 :
/* Bank error in your favor of $200. */
comm_chest_money += 200;
break;
case 8 :
/* Pay school tax of $150. */
comm_chest_money -= 150;
break;
case 9 :
/* Income tax refund of $20. */
comm_chest_money += 20;
break;
case 10 :
/* Pay hospital bill of $100. */
comm_chest_money -= 100;
break;
case 11 :
/* Life insurance matures for $100. */
comm_chest_money += 100;
break;
case 12 :
/* Xmas fund matures for $100. */
comm_chest_money += 100;
break;
default :
/* A card that leaves us on this square */
/* and that we do nothing else with. */
break;
}
}
}
}
}
void main()
{
printf("Enter number of rolls to simulate:\n");
scanf("%lu", &limit);
leave_jail = 1;
initialize();
do_calculation();
print_probabilities("short jail stay");
leave_jail = 3;
initialize();
do_calculation();
print_probabilities("long jail stay");
}