This article extends the work from article Monopoly #1 - Basic Example for the Visit Frequency of the Fields and from Monopoly #2 - Consider "Go-to-Jail" for the Visit Frequency of the Fields by considering the Chance and the Community Chest Cards.
Note that the full code is provided in the attached SAS program. In this article only those code elements are explained that differ from the version shown in the article Monopoly #1 - Basic Example for the Visit Frequency of the Fields and Monopoly #2 - Consider "Go-to-Jail" for the Visit Frequency of the Fields.
In the macro variables an additional macro parameter &ConsiderChance is defined.
%let cnt_players = 5;
%let cnt_games = 1000;
%let cnt_rounds = 100;
%let ConsiderJail = yes;
%let Doublet3Jail = no;
%let ConsiderChance = Yes;
%let seed = 1;
%let ScenarioName = "4. Jail, 3Doublet and ChanceCards";
This variable is used in the code to control if the statements to consider the Chance Cards and the Community Chest cards are processed or not.
%if %upcase(&ConsiderChance) = YES %then %do;
At the beginning of each game the community chest cards and the chance cards are mixed. Note that only a "pseudo-mixing" of the cards is performed here. The order of the cards 1-16 is maintained, but the card id, which is on top of the pile, is randomly generated and stored in the ActualCommChestID and ActualChanceID variable. These variables contain the values 1-16.
You could improve and program a true mixing of the cards, by creating a lookup table and assigning randomly generated sort values for it. However for the simulation purposes that are considered here, it will not make a big difference if the order of the cards is maintained or not.
*** Mix CommunityChest and Chance cards. Here: leave the order as is (should be fine for the simulation),
but define a new start in the stack of cards;
ActualCommChestID = ceil(rand('Uniform')*16);
ActualChanceID = ceil(rand('Uniform')*16);
do Round = 1 to &cnt_rounds;
do Player = 1 to &cnt_players;
The community chest fields are located at fields 3, 18, and 34. Only 2 of the 16 cards relocate the token:
%if %upcase(&ConsiderChance) = YES %then %do;
if PlayerPos[Player] in (3, 18, 34) then do; ** Pick CommunityChest Cards;
if ActualCommChestID=1 then PlayerPos[Player] = 1; *** Goto Field 1;
else if ActualCommChestID=6 then PlayerPos[Player] = 11; *** Goto Field 11 = jail;
ActualCommChestID = mod(ActualCommChestID+1,16); *** Move to of pile to next card;
end; ** Community Chest Card;
In the code you query the actual value of the community chest cards (ActualCommChestID). In case of 1 or 6 you relocated.
At the end, you move the card at the bottom of the pile and the next card is ready for a future draw.
The "chance" fields are located at fields 8, 23, and 37. The same procedure is applied as with the community chest cards. Here 10 out of 16 cards relocate the token in different ways:
At the end, you move the card at the bottom of the pile and the next card is ready for a future draw.
else if PlayerPos[Player] in (8, 23, 37) then do; ** Pick Chance Cards;
select (ActualChanceID);
when (1) PlayerPos[Player] = 40; /* Take a walk on the Boardwalk */
when (2) PlayerPos[Player] = 1; /* Advance to GO */
when (3) PlayerPos[Player] = 25; /* Advance to Illinois Avenue */
when (4) PlayerPos[Player] = 12; /* Advance to St. Charles Place */
when (5,6) do; /* Advance to nearest Railroad */
if PlayerPos[Player] = 8 then PlayerPos[Player] = 16;
else if PlayerPos[Player] = 23 then PlayerPos[Player] = 26;
else if PlayerPos[Player] = 37 then PlayerPos[Player] = 6;
end;
when (7) do; /* Advance to nearest Utility */
if PlayerPos[Player] in (8,37) then PlayerPos[Player] = 13;
else if PlayerPos[Player] = 23 then PlayerPos[Player] = 29;
end;
when (8) ; /* Bank pays you dividend of $50 – no move */
when (9) ; /* Get Out of Jail Free – no move */
/* Go Back 3 Spaces */
when (10) do;
if PlayerPos[Player] = 8 then PlayerPos[Player] = 5;
else if PlayerPos[Player] = 23 then PlayerPos[Player] = 20;
else if PlayerPos[Player] = 37 then PlayerPos[Player] = 34;
*** Alternative would be to use: PlayerPos[Player] = mod(PlayerPos[Player]-1,40)+1+3;
end;
when (11) PlayerPos[Player] = 11; /* Go to Jail */
when (12) ; /* General repairs – no move */
when (13) ; /* Speeding fine - no move */
when (14) PlayerPos[Player] = 6; /* Take a trip to Reading Railroad */
when (15) ; /* Chairman of the Board – no move */
when (16) ; /* Building loan matures – no move */
otherwise;
end;
ActualChanceID = mod(ActualChanceID+1,16); *** Move to of pile to next card;
end; ** Chance Card;
After performing post-processing using a SAS datastep and the TRANSPOSE procedures you can plot the results using the SGPLOT procedure.
proc sgplot data=work.player_location;
title Scenario: &scenarioname.;
histogram value / binstart=1 binwidth=1;
yaxis max = 6;
run;
title;
From the result you can see:
The following video illustrates the changes for the coding as described above.
Note that the video is taken from an earlier version of the code, where some of the relocation targets differ from the final (correct) version.
Nearly 200 sessions are now available on demand with the SAS Innovate Digital Pass.
Explore Now →The rapid growth of AI technologies is driving an AI skills gap and demand for AI talent. Ready to grow your AI literacy? SAS offers free ways to get started for beginners, business leaders, and analytics professionals of all skill levels. Your future self will thank you.