Last active
January 4, 2016 11:29
-
-
Save Kuniwak/8615315 to your computer and use it in GitHub Desktop.
モンティ・ホール問題のシミュレーションで代表的な戦略の勝率を計算するスクリプト.
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
| #!/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