Skip to content

Instantly share code, notes, and snippets.

@realsonic
Created June 6, 2018 17:18
Show Gist options
  • Save realsonic/1912f669fe8139716ed7372d0b571c46 to your computer and use it in GitHub Desktop.
Save realsonic/1912f669fe8139716ed7372d0b571c46 to your computer and use it in GitHub Desktop.
Doors
using System;
using System.Collections.Generic;
using System.Linq;
namespace Doors
{
internal class Program
{
private const int ITERATIONS = 10_000_000;
//private const int SEED = 0;
private static void Main(string[] args)
{
// маппинги номер двери <-> value tuple флага двери
var numberTupleMap = new Dictionary<int, (bool Door1, bool Door2, bool Door3)>
{
{1, (Door1: true, Door2: false, Door3: false)},
{2, (Door1: false, Door2: true, Door3: false)},
{3, (Door1: false, Door2: false, Door3: true)}
};
Dictionary<(bool Door1, bool Door2, bool Door3), int> tupleNumberMap =
numberTupleMap.ToDictionary(pair => pair.Value, pair => pair.Key);
// функции конвертации номер двери <-> value tuple флага двери
(bool Door1, bool Door2, bool Door3) TupleByNumber(int doorNumber) =>
numberTupleMap[doorNumber];
int NumberByTuple((bool Door1, bool Door2, bool Door3) tuple) => tupleNumberMap[tuple];
var random = new Random( /*SEED*/);
T RandomFrom<T>(IReadOnlyList<T> list)
{
int randomIndex = random.Next(0, list.Count);
return list[randomIndex];
}
// расставим двери
List<(bool Door1, bool Door2, bool Door3)> doorsIters = Enumerable
.Range(1, ITERATIONS)
.Select(i => random.Next(1, 4))
.Select(TupleByNumber)
.ToList();
// посчитаем кол-во дверей
var winDoorsCount = doorsIters
.GroupBy(i => i)
.Select(dg => new {Tuple = dg.Key, Quantity = dg.Count()})
.OrderBy(dq => NumberByTuple(dq.Tuple))
.ToList();
// кол-во всех дверей
int allDoorsQty = doorsIters.Count;
// выводим процентный разброс дверей
foreach (var doorCount in winDoorsCount) {
Console.WriteLine(
$"Door #{NumberByTuple(doorCount.Tuple)} - quantity {doorCount.Quantity}, procentile: {(double) doorCount.Quantity / allDoorsQty:P}");
}
/* для каждой итерации надо провести:
выбрать дверь случайно, далее открыть (убрать из выбора) любую пустую дверь;
далее:
вариант 1: не менять выбор; если выбор верный - посчитать как удачу в вар.1
вариант 2: поменять выбор - выбрать оставшуюся дверь; если выбор верный - посчитать как удачу в вар.2
*/
// выбираем дверь
var selectedDoors = doorsIters.Select(tuple => new
{
// выбираем дверь
SelectedDoor = random.Next(1, 4),
// передаём выйгрышную дверь
WinDoor = NumberByTuple(tuple)
})
.ToList();
// вариант 1: не менять выбор
int var1Qty = selectedDoors.Count(sd => sd.SelectedDoor == sd.WinDoor);
// вариант 2: поменять выбор - выбрать оставшуюся дверь
var doorsFullSet = new[] {1, 2, 3};
var var2Data = selectedDoors.Select(sd => new
{
// открываем пустую дверь
OpenDoor =
RandomFrom(
doorsFullSet.Except(new[] {sd.SelectedDoor, sd.WinDoor}).ToList()),
// передаём выйгрышную дверь
sd.WinDoor,
// передаём выбранную дверь
sd.SelectedDoor
})
.Select(sd => new
{
// выбираем оставшуюся закрытой дверь
SecondSelectedDoor =
RandomFrom(doorsFullSet.Except(new[] {sd.SelectedDoor, sd.OpenDoor})
.ToList()),
// передаём открытую дверь
sd.OpenDoor,
// передаём выйгрышную дверь
sd.WinDoor,
// передаём выбранную дверь
sd.SelectedDoor
});
int var2Qty = var2Data.Count(sd => sd.SecondSelectedDoor == sd.WinDoor);
// выводим результаты
Console.WriteLine(
$"Win % for variant 1 (don't change selection): \t{(double) var1Qty / allDoorsQty:P}");
Console.WriteLine(
$"Win % for variant 2 (do change selection): \t{(double) var2Qty / allDoorsQty:P}");
Console.Write("End. Press ENTER: ");
Console.ReadLine();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment