Skip to content

Instantly share code, notes, and snippets.

@Kuniwak
Last active January 4, 2016 11:29
Show Gist options
  • Select an option

  • Save Kuniwak/8615315 to your computer and use it in GitHub Desktop.

Select an option

Save Kuniwak/8615315 to your computer and use it in GitHub Desktop.
モンティ・ホール問題のシミュレーションで代表的な戦略の勝率を計算するスクリプト.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""モンティ・ホール問題のシミュレーションで代表的な戦略の勝率を計算する."""
__author__ = 'Orga Chem <[email protected]>'
__version__ = '0.0.1'
__date__ = '25 January 2014'
import random
class MontyHall:
"""モンティ・ホール問題の試行クラス.
モンティ・ホール問題のゲーム制御をおこなう.
http://ja.wikipedia.org/wiki/モンティ・ホール問題
"""
class Door:
"""ドアクラス.
ドアの開閉・当たりの状態をもつ.
"""
def __init__(self, bingo=False):
self.bingo = bingo
self.opened = False
def open(self):
self.opened = True
class Monty:
"""司会者(Monty Hall)クラス.
開けるドアを選択する役割をもつ.
"""
class Strategy:
"""司会者が挑戦者に開けてみせるドアを決める戦略クラス.
挑戦者が選ばなかったドアのうち,当たりではないドアを開ける.
"""
def choice(self, doors, selected):
options = filter(lambda door: not door.bingo, doors - selected)
return random.choice(options)
def __init__(self, strategy=None):
"""指定した戦略をとる司会者を作成する."""
self.strategy = strategy if strategy else MontyHall.Monty.Strategy()
def open_door(self, doors, selected=None):
"""選択されたドアを開ける."""
self.strategy.choice(doors, selected if selected else set()).open()
class User:
"""挑戦者クラス.
ドアを選ぶ役割をもつ.
"""
class Strategy:
"""ランダムにドアを選ぶ戦略クラス."""
def choice(self, doors, selected):
unopened = filter(lambda door: not door.opened, doors)
return set([random.choice(unopened)])
class AfterTheFactStrategy(Strategy):
"""自分が最初に選んだドア以外のドアを選択し直す戦略クラス."""
def choice(self, doors, selected):
unopend_and_not_selected = filter(lambda door: not door.opened,
doors - selected)
return set([random.choice(unopend_and_not_selected)])
class NotChangingStrategy(Strategy):
"""自分が最初に選んだドアを選び続ける戦略クラス."""
def choice(self, doors, selected):
if len(selected) > 0:
door = selected
else:
unopened = filter(lambda door: not door.opened, doors)
door = set([random.choice(unopened)])
return door
def __init__(self, strategy=None):
"""指定した戦略をとる挑戦者を作成する."""
self.score = 0
self.strategy = strategy if strategy else MontyHall.User.Strategy()
def choice(self, doors, selected=None):
"""挑戦者が賭けるドアを選択する."""
return self.strategy.choice(doors, selected if selected else set())
def __init__(self, monty=None, user=None, doors_number=3):
"""指定した司会者,挑戦者,ドア数のモンティ・ホール問題を作成する."""
self.doors_number = doors_number
self.user = user if user else MontyHall.User()
self.monty = monty if monty else MontyHall.Monty()
def game(self):
"""モンティ・ホール問題を試行する."""
self.prepare()
user_choice_1 = self.user.choice(self.doors)
self.monty.open_door(self.doors, user_choice_1)
user_choice_2 = self.user.choice(self.doors, user_choice_1)
if len(filter(lambda door: door.bingo, user_choice_2)) > 0:
self.user.score += 1
def prepare(self):
"""ドアを準備する."""
self.doors = set()
for i in range(0, self.doors_number):
self.doors.add(MontyHall.Door())
random.choice(list(self.doors)).bingo = True
if __name__ == '__main__':
TRIAL_COUNT = 1000
monty_halls = {
'Random choice': MontyHall(),
'After the fact': MontyHall(user=MontyHall.User(
MontyHall.User.AfterTheFactStrategy())),
'Not changing': MontyHall(user=MontyHall.User(
MontyHall.User.NotChangingStrategy())),
}
result = {}
for strategy_name, monty_hall in monty_halls.iteritems():
for i in range(0, TRIAL_COUNT):
monty_hall.game()
result[strategy_name] = float(monty_hall.user.score) / TRIAL_COUNT
# Display result
row_format = '| {:<15} | {:>15} |'
print(row_format.format('Strategy name', 'Winning rate'))
print('|' + ('-' * 17) + '|' + ('-' * 17) + '|')
for strategy_name, winning_rate in result.iteritems():
print(row_format.format(strategy_name, str(winning_rate * 100) + '%'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment