Last active
January 10, 2020 21:37
-
-
Save mr-parus/55ef43e1e73336b2f0ffa59352ad509f to your computer and use it in GitHub Desktop.
[JS] Monty Hall Problem simulation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
One time case simulation: | |
Initial doors: | |
1)πͺ | |
2)πͺπ | |
3)πͺ | |
-------------------------------------------------- | |
Choosing one door: | |
Chosen door #3 | |
1)πͺ | |
2)πͺπ | |
->3)πͺ | |
-------------------------------------------------- | |
Open one door: | |
1) | |
2)πͺπ | |
->3)πͺ | |
-------------------------------------------------- | |
Open chosen door: | |
1) | |
2)πͺπ | |
->3) | |
-------------------------------------------------- | |
Loser! | |
N times simulation: | |
From 10000 experiments: | |
Without changing door: 32.9 % | |
With changing door: 67.10000000000001 % |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// In the problem, you are on a game show, being asked to choose between three doors. | |
// Behind each door, there is either a car or a goat. You choose a door. | |
// The host, Monty Hall, picks one of the other doors, which he knows has a goat behind it, | |
// and opens it, showing you the goat. (You know, by the rules of the game, that Monty will always reveal a goat.) | |
// Monty then asks whether you would like to switch your choice of door to the other remaining door. | |
// Assuming you prefer having a car more than having a goat, do you choose to switch or not to switch? | |
// https://en.wikipedia.org/wiki/Monty_Hall_problem | |
// util logic | |
const getArray = (n) => Array.from({length: n}); | |
const filterNull = (e) => e !== null; | |
const getRandomFromN = (n) => Math.floor(Math.random() * n); | |
const getRandomElement = (a) => a[getRandomFromN(a.length)]; | |
// logging logic | |
let l = console.log; | |
const displayDivider = () => l('-'.repeat(50)); | |
const displayDoors = (doors) => l(doors.map(({content, opened, chosen}, i) => | |
`${chosen ? "->" : " "}${i + 1})${opened ? "" : "πͺ"}${content}`).join("\n")); | |
// door logic | |
const PRIZE_VAL = "π"; | |
const createDoor = ({opened = false, content = "", chosen = false} = {}) => ({opened, content, chosen}); | |
const openDoorById = (doors, i) => doors.map((e, index) => index === i ? {...e, opened: true} : e); | |
const openChosenDoor = (doors) => doors.map((e) => e.chosen? {...e, opened: true} : e); | |
const choseDoorById = (doors, i) => doors.map((e, index) => index === i ? {...e, chosen: true} : {...e, chosen: false}); | |
const setDoorContentById = (doors, i, val) => doors.map((e, index) => index === i ? {...e, content: val} : e); | |
const getInitialDoors = (n) => { | |
const doors = getArray(n).map(createDoor.bind(null, undefined)); | |
return setDoorContentById(doors, getRandomFromN(n), PRIZE_VAL); | |
}; | |
const chooseOneDoor = (doors) => { | |
const notOpenedAndNotChosenBeforeDoorsIndexes = doors.map(({opened, chosen}, i) => !chosen && !opened ? i : null).filter(filterNull); | |
const chosenIndex = getRandomElement(notOpenedAndNotChosenBeforeDoorsIndexes); | |
l(`Chosen door #${chosenIndex + 1}`); | |
return choseDoorById(doors, chosenIndex); | |
}; | |
const openOneDoor = (doors) => { | |
const notOpenedAndNotTargetIndexes = doors.map(({opened, content, chosen}, i) => !chosen && !opened && content !== PRIZE_VAL ? i : null).filter(filterNull); | |
const openIndex = getRandomElement(notOpenedAndNotTargetIndexes); | |
return openDoorById(doors, openIndex); | |
}; | |
const isTargetDoorChosen = (doors) => { | |
const result = doors.reduce((acc, {content, chosen}) => { return content === PRIZE_VAL && chosen?true: acc }, false); | |
l(result ? "Winner!" : "Loser!"); | |
return result; | |
}; | |
const experiment = (change = false) => { | |
l(`Initial doors:`); | |
let doors = getInitialDoors(3); | |
displayDoors(doors); | |
displayDivider(); | |
l(`Choosing one door:`); | |
doors = chooseOneDoor(doors, []); | |
displayDoors(doors); | |
displayDivider(); | |
l(`Open one door:`); | |
doors = openOneDoor(doors); | |
displayDoors(doors); | |
displayDivider(); | |
if (change) { | |
l(`Choosing another door:`); | |
doors = chooseOneDoor(doors); | |
displayDoors(doors); | |
displayDivider(); | |
} | |
l(`Open chosen door:`); | |
doors = openChosenDoor(doors); | |
displayDoors(doors); | |
displayDivider(); | |
return +isTargetDoorChosen(doors); | |
}; | |
const calculate = (n) => { | |
l = () => {}; | |
let resultsWithChangingDoor = 0; | |
let resultsWithoutChangingDoor = 0; | |
for (let i = 0; i < n; i++) { | |
const resultWithChangingDoor = experiment(true); | |
if (resultWithChangingDoor) { | |
resultsWithChangingDoor +=1; | |
} else { | |
resultsWithoutChangingDoor +=1; | |
} | |
} | |
console.log(` | |
From ${n} experiments: | |
Without changing door: ${resultsWithoutChangingDoor / n * 100} % | |
With changing door: ${resultsWithChangingDoor / n * 100} %`); | |
}; | |
// N times | |
calculate(10000); | |
// 1 time | |
experiment() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment