function rand(n) {
return Math.floor(Math.random() * n);
}
function Game() {
this.doors = ['closed', 'closed', 'closed'];
this._goat = rand(3); // @private
}
Game.prototype.reveal = function(picked) {
var options = [];
for (var i = 0; i < 3; i++) {
if (i !== picked && i !== this._goat) {
options.push(i);
}
}
this.doors[options[rand(options.length)]] = 'open';
return this;
};
// Strategy prototype (abstract)
function Strategy() {
this.picked = null;
}
Strategy.prototype.firstPick = function() {
return this.picked = rand(3);
};
Strategy.prototype.finalPick = function() {
throw new Error('unimplemented');
};
function HoldStrategy() {
}
HoldStrategy.prototype = Object.create(Strategy.prototype);
HoldStrategy.prototype.finalPick = function(game) {
return this.picked;
};
function SwitchStrategy() {
}
SwitchStrategy.prototype = Object.create(Strategy.prototype);
SwitchStrategy.prototype.finalPick = function(game) {
for (var i = 0; i < 3; i++) {
if (i !== this.picked && game.doors[i] !== 'open') {
return i;
}
}
return null;
};
Game.monteCarlo = function(n, Strategy) {
var total = 0;
for (var i = 0; i < n; i++) {
var game = new Game();
var strategy = new Strategy();
game.reveal(strategy.firstPick());
total += (strategy.finalPick(game) === game._goat) ? 1 : 0;
};
return total / n;
};
Usage:
Game.monteCarlo(1000000, HoldStrategy);
// => 0.333622
Game.monteCarlo(1000000, SwitchStrategy);
// => 0.667626
More strategies are possible:
function CheatStrategy() {
}
CheatStrategy.prototype = Object.create(Strategy.prototype);
CheatStrategy.prototype.finalPick = function(game) {
return game._goat;
};
Game.monteCarlo(1000000, CheatStrategy);
// => 1