Reputation: 2997
I am trying to simulate the Monty Hall Problem (because I read from the book Think Statistics that a guy in particular was convinced only after seeing a computer simulation) in C#, the programming language most familiar to me. My scenario is such that the position of the prize is random (in each run), my choice is random, and the game host's choice of opening the door is random (it can't be random if I picked the non-prize).
Surprisingly though, my program achieves the result of a 50:50 chance of winning no matter whether I switch or not. Here's the code to it (pardon me for the lengthiness):
class Program
{
static void Main(string[] args)
{
Random rand = new Random();
int noSwitchWins = RunGames(rand, false, 10000);
int switchWins = RunGames(rand, true, 10000);
Console.WriteLine(string.Format("If you don't switch, you will win {0} out of 1000 games.", noSwitchWins));
Console.WriteLine(string.Format("If you switch, you will win {0} out of 1000 games.", switchWins));
Console.ReadLine();
}
static int RunGames(Random rand, bool doSwitch, int numberOfRuns)
{
int counter = 0;
for (int i = 0; i < numberOfRuns; i++)
{
bool isWin = RunGame(rand, doSwitch);
if (isWin)
counter++;
}
return counter;
}
static bool RunGame(Random rand, bool doSwitch)
{
int prize = rand.Next(0, 2);
int selection = rand.Next(0, 2);
// available choices
List<Choice> choices = new List<Choice> { new Choice(), new Choice(), new Choice() };
choices[prize].IsPrize = true;
choices[selection].IsSelected = true;
Choice selectedChoice = choices[selection];
int randomlyDisplayedDoor = rand.Next(0, 1);
// one of the choices are displayed
var choicesToDisplay = choices.Where(x => !x.IsSelected && !x.IsPrize);
var displayedChoice = choicesToDisplay.ElementAt(choicesToDisplay.Count() == 1 ? 0 : randomlyDisplayedDoor);
choices.Remove(displayedChoice);
// would you like to switch?
if (doSwitch)
{
Choice initialChoice = choices.Where(x => x.IsSelected).FirstOrDefault();
selectedChoice = choices.Where(x => !x.IsSelected).FirstOrDefault();
selectedChoice.IsSelected = true;
}
return selectedChoice.IsPrize;
}
}
class Choice
{
public bool IsPrize = false;
public bool IsSelected = false;
}
This is entirely for my own interest's sake, and I wrote it in the way most familiar and comfortable to me. Do feel free to offer your own opinion and critique, thank you very much!
Upvotes: 7
Views: 2267
Reputation: 815
To add to Marc's answer, you can also use Random.Next(Int32) since your lower bound is 0, so it would be simply:
rand.Next(3)
Upvotes: 1
Reputation: 12956
See Random.Next(minValue, maxValue)
Parameters
minValue Type: System.Int32 The inclusive lower bound of the random number returned.
maxValue Type: System.Int32 The exclusive upper bound of the random number returned. maxValue must be greater than or equal to minValue.
Upvotes: 1
Reputation: 1063694
rand.Next(0,2)
only returns 0 or 1; the upper bound is exclusive. You are never picking the third door (unless you switch), and the third door never has the prize. You are modelling the wrong problem.
Try instead:
rand.Next(0,3)
Likewise:
int randomlyDisplayedDoor = rand.Next(0, 1);
only ever selects the first of the candidate doors; should be:
int randomlyDisplayedDoor = rand.Next(0, 2);
Now we get:
If you don't switch, you will win 3320 out of 1000 games.
If you switch, you will win 6639 out of 1000 games.
Note - the upper bound is inclusive when equals - i.e. rand.Next(1,1)
always returns 1
.
Upvotes: 6