(***********************************************************************************************************
​Disclaimer and Limitation of Liability:​
This Mathematica notebook is provided by Harper Corditt Software for demonstration purposes only.
The source code in this Mathematica notebook is provided “as is” without warranty of any kind,
whether express or implied.
M2SLink© 2019 Harper Corditt Software.
SAS® and all other SAS Institute Inc. product or service names are registered trademarks or trademarks
of SAS Institute Inc. in the USA and other countries. ® indicates USA registration.
Mathematica® is a registered trademark of Wolfram Research.​
​
©2019 Harper Corditt Software​
***********************************************************************************************************)
In[]:=
Clear["Global`*"]
(*The"Let'sMakeaDeal"Conundrum*)
(*We imagine that there are 2 players, player A and player B, who are playing the game show “Let’s Make a Deal” with host Monty Hall. Both players always start out by choosing door #1. After Monty shows each of them what is behind one of the other doors (i.e., either door #2 or door #3), player A always sticks with his original choice of door #1 . Player B always changes her original choice from door #1 to the remaining door that Monty did not open. (So, for example, if Monty opens door #2, Player B switches to door #3.)
Suppose Monty reveals what’s behind door #2. Common sense tells us that after Monty opens door #2, since there are two doors remaining, there is a 50-50 chance that the prize is either behind door #1 or door #3. In other words, common sense tells us that after Monty opens door #2, the probability of the prize being behind door #1 is 0.5. Therefore, common sense assures us that there is no reason for player A to switch from his original choice of door #1 to door #3. Based on this reasoning, it follows that in the long run, player A and player B should always win an equal number of times. That is what common sense tells us. But as it turns out, common sense is wrong. The letsMakeADeal[] function defined below simulates playing the “Let’s Make a Deal” game for as many times as you like. In each game, players A and B follow the strategies previously described . For a given number of games played, the letsMakeADeal[] function reports the number of times player A wins vs. the number of times player B wins. Surprisingly and contrary to common sense, player B wins almost twice as often as player A. Thus player B’s strategy of switching to the other door pays off far better than player A’s strategy of sticking with his original choice of door #1. *)
In[]:=
letsMakeADeal::usage=​​"letsMakeADeal[nGames] returns a list: {nWinsPlayerA,nWinsPlayerB} after playing nGames of \"Let's Make a Deal\". PlayerA always chooses door #1. PlayerB starts by choosing door #1 as well, but after Monty opens one of the doors, she switches to either door #2 or door #3 based on the following rule: If Monty opens door #2, then PlayerB chooses door #3. Otherwise, PlayerB chooses door #2.";​​letsMakeADeal[nGames_,opts___?OptionQ]:=Module[​​{i=1,nWinsPlayerA=0,nWinsPlayerB=0,randNumList,​​doorWithPrize=1,doorsRemaining={},doorsMontyCanOpen={},​​doorMontyOpens=0,​​playerAchoice=1,playerBchoice=1},​​randNumList=Table[RandomReal[],{i,1,nGames}];​​For[i=1,i≤nGames,i++,​​doorWithPrize=If[randNumList[[i]]<1/3,1,​​If[randNumList[[i]]<2/3,2,​​3]​​];​​(*Print[doorWithPrize];*)​​(*assumeplayerAandplayerBalwaysstartbychoosingdoor#1*)​​(*ThisentailsthatMontywillalwaysopeneitherdoor#2ordoor#3.*)​​playerAchoice=1;playerBchoice=1;​​​​(*Monty"chooses"adoortoopen.Actually,iftheprizeisnotbehindthedoorthattheplayerchose(#1,inourexample),thenMontyhasonlyonechoice.Forexample,iftheplayerchosedoor#1andtheprizeisbehinddoor#2,thenMontymustopendoor#3.However,iftheprizeisactuallybehinddoor#1,thenMontydoesgettochoosewhethertoopendoor#2ordoor#3.​​Weshallasssumethatinthiscase,Montyalwaysopensdoor#2.*)​​(*Montyshowstheplayerwhat'sbehindoneofthedoorsthatremainsafterheeliminatesthedoorwiththeprize.*)​​​​(*WeusetheComplement[]functiontocomputethesetdifference:​​doorsMontyCanOpen={1,2,3}-{doorWithPrize}*)​​doorsMontyCanOpen=Complement[{1,2,3},{doorWithPrize}];​​If[doorWithPrize≠1,(*prizeisbehinddoor#2ordoor#3*)​​(*there'sonly1doorMontycanopen.Hecannotopendoor#1.​​Intermsofsetdifferences,thismeansthat​​doorsMontyCanOpen=doorsMontyCanOpen-{1}*)​​doorsMontyCanOpen=Complement[doorsMontyCanOpen,{1}]];​​​​(*NotethatifdoorWithPrize1,thendoorsMontyCanOpen{2,3}*)​​(*thelinebelowhastheconsequencethatiftheprizeisactuallybehinddoor#1,thenMontyalwayschoosestoopendoor#2.WecouldmodifyourcodetomakeMonty'schoiceinthissituationarandomchoicebetweendoor#2anddoor#3,butitwouldnotaffecttheoutcome.Obviously,PlayerAalwayswinsinthissituationandplayerBalwaysloses.*)​​doorMontyOpens=doorsMontyCanOpen[[1]];​​​​(*playerAstickswithdoor#1*)​​(*playerBswitchesfromdoor#1totheremainingunopeneddoor(either#2or#3)*)​​If[doorMontyOpens2,​​playerBchoice=3,(*playerBswitchestodoor#3*)​​playerBchoice=2(*playerBswitchestodoor#2*)​​];​​(*keeptrackofthenumberofwinsforeachplayer*)​​If[playerAchoice==doorWithPrize,​​nWinsPlayerA++];​​If[playerBchoice==doorWithPrize,​​nWinsPlayerB++];​​];(*endForloop*)​​Return[{nWinsPlayerA,nWinsPlayerB}]​​]
In[]:=
?letsMakeADeal
In[]:=
letsMakeADeal[500]
​​​​
(*Let's consider a variation on the game. In this version, there are N>=3 doors. Both players begin by choosing door #1.
After Monty opens one of the other doors, player A stays with his original choice but player B chooses some other door. *)
In[]:=
letsMakeADealWithNDoors::usage=​​"letsMakeADealWithNDoors[nDoors,nGames] returns a list: {nWinsPlayerA,nWinsPlayerB} after playing nGames of \"Let's Make a Deal\" with nDoors. PlayerA always chooses door #1. By default, PlayerB restricts her choice to either door #2 or door #3 based on the following rule: If Monty opens door #2, then PlayerB chooses door #3. Otherwise, PlayerB chooses door #2. You can also make PlayerB's choice random (provided nDoors>3) by setting the \"playerBChoosesRandomly\" option to True. If nGames==1, then the prize door's number along with the choices each player made are printed to the notebook.";​​​​playerBChoosesRandomly::usage=​​"playerBChoosesRandomly is an option to the letsMakeADealWithNDoors[] function. If playerBChoosesRandomly is True and nDoors>3, then PlayerB chooses a door at random from the set of doors that remain after eliminating door #1 and the door that Monty opens. playerBChoosesRandomly is False by default.";​​letsMakeADealWithNDoors::nDoorsMustBeGTE3="nDoors must be >= 3.";​​letsMakeADealWithNDoors::nGamesMustBeGTE1="nGames must be >= 1.";​​letsMakeADealWithNDoors::playerBChoiceNotRandom="nDoors==3 implies playerBChoosesRandomly==False.";​​​​Options[letsMakeADealWithNDoors]={​​"playerBChoosesRandomly"False​​};​​​​letsMakeADealWithNDoors[nDoors_,nGames_,opts___?OptionQ]:=Module[​​{i=1,nWinsPlayerA=0,nWinsPlayerB=0,​​allDoors={},​​doorWithPrize=1,doorsRemaining={},doorsMontyCanOpen={},​​doorsPlayerBCanSwitchTo={},​​indexOfDoorMontyOpens=0,doorMontyOpens=0,​​indexOfDoorPlayerBSwitchesTo=0,​​bPlayerBChoosesRandomly=False,(*default*)​​playerAchoice=1,playerBchoice=1},​​​​If[nDoors<3,Message[letsMakeADealWithNDoors::nDoorsMustBeGTE3];Abort[]];​​If[nGames<1,Message[letsMakeADealWithNDoors::nGamesMustBeGTE1];Abort[]];​​​​bPlayerBChoosesRandomly="playerBChoosesRandomly"/.{opts}/.Options[letsMakeADealWithNDoors];​​If[nDoors3&&bPlayerBChoosesRandomly,​​Message[letsMakeADealWithNDoors::playerBChoiceNotRandom];​​bPlayerBChoosesRandomly=False​​];​​​​(*SeedRandom[]resetsMathematica'srandomnumbergenerator,usingasaseedthetimeofdayandcertainattributesofthecurrentWolframSystemsession.*)​​SeedRandom[];​​​​For[i=1,i≤nGames,i++,​​(*werandomlychoosethenumberofthedoorwiththeprize*)​​doorWithPrize=RandomInteger[{1,nDoors}];​​If[nGames1,Print["Prize is behind door #",doorWithPrize]];​​​​(*Print[doorWithPrize];*)​​(*assumeplayerAandplayerBalwaysstartbychoosingdoor#1*)​​(*ThisentailsthatMontywillalwaysopenoneofthedoors#2..#N.*)​​playerAchoice=1;playerBchoice=1;​​​​(*ComputethelistofdoorsthatMontycanopenafterdoor#1andthedoorwiththeprize(whichmaybedoor#1)havebeeneliminated.*)​​(*WeusetheComplement[]functiontocomputethesetdifference:​​doorsMontyCanOpen={1,2,3,...,N}-{1,doorWithPrize}*)​​allDoors=Table[i,{i,1,nDoors}];​​doorsMontyCanOpen=Complement[allDoors,{1,doorWithPrize}];​​​​(*Let'sassumethatMonty'schoiceofwhichdoortoopenisrandom.Specifically,MontychoosesatrandomanintegerKbetween1andLength[doorsMontyCanOpen]andusesKastheindexofthedoortoopenfromthedoorsMontyCanOpenlist.*)​​indexOfDoorMontyOpens=RandomInteger[{1,Length[doorsMontyCanOpen]}];​​​​doorMontyOpens=doorsMontyCanOpen[[indexOfDoorMontyOpens]];​​If[nGames1,Print["Monty opens door #",doorMontyOpens]];​​​​(*playerAstickswithdoor#1*)​​(*playerBswitchesfromdoor#1tooneoftheremainingunopeneddoors.​​PlayerBcanchooseoneofthedoors{1,2,3,...,N}-{1,doorMontyOpens}*)​​doorsPlayerBCanSwitchTo=Complement[allDoors,{1,doorMontyOpens}];​​​​If[bPlayerBChoosesRandomly,​​(*MakePlayerB's'schoiceofwhichdoortoopenarandomselection.​​Specifically,PlayerBchoosesatrandomanintegerIbetween2andN-2andusesIastheindexofthedoortoopenfromthedoorsPlayerBCanSwitchTolist.*)​​indexOfDoorPlayerBSwitchesTo=RandomInteger[{1,Length[doorsPlayerBCanSwitchTo]}];​​playerBchoice=doorsPlayerBCanSwitchTo[[indexOfDoorPlayerBSwitchesTo]],​​(*elseplayerBrestrictsmakesherchoicebasedonthedoorMontyopens.IfMontyopensdoor#2,​​playerBswitchestodoor#3.Otherwise,playerBswitchestodoor#2.*)​​If[doorMontyOpens2,​​playerBchoice=3,​​playerBchoice=2]​​];​​If[nGames1,Print["PlayerB chooses door #",playerBchoice]];​​​​(*keeptrackofthenumberofwinsforeachplayer*)​​If[playerAchoice==doorWithPrize,​​nWinsPlayerA++];​​If[playerBchoice==doorWithPrize,​​nWinsPlayerB++];​​];(*endForloop*)​​Return[{nWinsPlayerA,nWinsPlayerB}]​​]​​