2017-06-18 48 views
0

我一直在尝试解决在Python的monty hall problem,才能在编码前进,这就是为什么我试图随机一切。问题是:我遇到了一些麻烦。正如你们大多数人可能知道的那样,monty问题应该表明,改变门的胜利率(66%)比停留在选定的门(33%)更高。由于某种奇怪的原因,虽然我的模拟显示这两种情况都有33%的胜利率,但我不确定为什么。蒙提霍尔模拟并不如预期运行

下面的代码:

from random import * 


def doorPriceRandomizer(): 
    door1 = randint(0,2) #If a door is defined 0, it has a price in it 
    door2 = randint(0,2) #If a door is defined either 1 or 2, it has a goat in it. 
    door3 = randint(0,2) 
    while door2 == door1: 
     door2 = randint(0,2) 
    while door3 == door2 or door3 == door1: 
     door3 = randint(0,2) 
    return door1,door2,door3 #This random placement generator seems to be working fine. 


while True: 
    loopStart = 0 
    amountWin = 0 
    amountLose = 0 
    try: 
     loopEnd = int(input("How often would you like to run this simulation: ")) 
     if loopEnd < 0: 
      raise ValueError 
     doorChangeUser = int(input("[0] = Do not change door; [1] = Change door: ")) 
     if doorChangeUser not in range(0,2): 
      raise ValueError 
    except ValueError: 
      print("Invalid input. Try again.\n") 
    else: 
     while loopStart != loopEnd: 
      gameDoors = doorPriceRandomizer() 
      inputUser = randint(0,2) 
      if doorChangeUser == 0: 
       if gameDoors[inputUser] == 0: 
        amountWin += 1 
        loopStart += 1 
       else: 
        amountLose += 1 
        loopStart += 1 
      elif doorChangeUser == 1: 
       ChangeRandom = 0 
       while gameDoors[ChangeRandom] == gameDoors[inputUser]: 
        ChangeRandom = randint(0,2) 
       if gameDoors[ChangeRandom] == 0: 
        amountWin += 1 
        loopStart += 1 
       else: 
        amountLose += 1 
        loopStart += 1 

    print("Win amount: ",amountWin,"\tLose amount: ",amountLose) 

我在做什么错?我非常感谢所有帮助!提前致谢!

+0

欢迎来到SO:请参加[导览]并阅读[MCVE],以增加获得所需帮助的机会。您发布的代码块应遵循[MCVE]中的指导原则。 –

+0

如果任何人的兴趣,我这样做,和我做游戏的功能,这样你就可以运行它吨次在一个循环中获得的可能性,并且你可以调用该函数不带参数的播放。如果你有一些空闲时间检查它,这将意味着很多我:https://github.com/NoahCristino/montyhall –

回答

0
ChangeRandom = 0 
while gameDoors[ChangeRandom] == gameDoors[inputUser]: 
    ChangeRandom = randint(0,2) 

这不符合你的想法。相反,检查是否ChangeRandom门是一样的inputUser门的,这个检查,如果ChangeRandom门和inputUser门具有相同的价值 - 也就是说他们要么两个赢家或两个失败者。

也就是说,这不是连你想要做什么。你想要做的是找到一个不是用户输入的门,而是一个失败者的门,然后切换到另一个不是用户输入的门。这可以以最小的变化来实现你的代码为:

other_wrong_door = next(c for c, v in enumerate(gameDoors) if v != 0 and c != inputUser) 
new_door = next(c for c, _ in enumerate(gameDoors) if c != inputUser and c != other_wrong_door) 

不过说实话这是值得您的代码结构的重新审视。给我几分钟的时间来解决问题,然后我将编辑这个答案,让你知道我将如何实现这一点。

import random 

DOORS = [1, 0, 0] 

def runonce(switch=False): 
    user_choice = random.choice(DOORS) 
    if user_choice == 1: 
     # immediate winner 
     if switch: 
      # if you won before and switch doors, you must lose now 
      return False 
     else: 
      new_doors = [0, 0] # remove the user-selected winner 
      new_doors = [0]  # remove another loser 
      return bool(random.choice(new_doors)) 
      # of course, this is always `0`, but 
      # sometimes it helps to show it. In production you 
      # wouldn't bother writing the extra lines and just return False 
    else: 
     if switch: 
      new_doors = [1, 0] # remove the user-selected loser 
      new_doors = [1]  # remove another loser 
      return bool(random.choice(new_doors)) 
      # as above: this is always True, but.... 
     else: 
      return False # if you lost before and don't switch, well, you lost. 

num_trials = int(input("How many trials?")) 
no_switch_raw = [run_once(switch=False) for _ in range(num_trials)] 
switch_raw = [run_once(switch=True) for _ in range(num_trials)] 

no_switch_wins = sum(1 for r in no_switch_raw if r) 
switch_wins = sum(1 for r in switch_raw if r) 

no_switch_prob = no_switch_wins/num_trials * 100.0 
switch_prob = switch_wins/num_trials * 100.0 

print("   WINS LOSSES %\n" 
     f"SWITCH: {switch_wins:>4} {num_trials-switch_wins:>6} {switch_prob:.02f}\n" 
     f"NOSWITCH:{no_switch_wins:>4} {num_trials-no_switch_wins:>6} {no_switch_prob:.02f}") 
+1

地狱,这是复杂的。我稍后会研究你对这个问题的解决方案,因为我非常肯定我可以从中学到一些东西。我还不知道的一些事情。洗牌功能就是其中之一。感谢那。现在尽管我试图插入你之前写过的那两行代码。它有效,但我真的不明白它的作用。介绍一下更详细地解释这两条线?我正在试图弄清楚下一步是什么以及c中的c应该如何工作。没有定义变量的for循环如何工作? –

+0

“var for collection”是一个genexp或generator生成器表达式。你通常会看到它们被方括号包裹,这使得它们成为“list comprehensions”'[var for var in collection]',但是因为我们只需要一个值,所以我只使用原始genexp并在其上调用'next' 。 'next'是一种内置的方法,从发生器中提取下一个值。 –

+0

genexp中的第一个表达式(第一个'var')是从生成器中拉出的值。所以你可以通过在范围(1,1000)内对x进行'x ** 2'来完成一个完美平方的生成器 –

0

你已经得到了错误的机制,所以你得到了错误的结果。我已经重写了选择机制,但我将用户输入内容留给了您,以便您可以继续学习python。这是解决问题的多种方法之一,但希望它能向您演示一些事情。

def get_choices(): 
    valid_choices = [0, 1, 2] # these are the values for a valid sample 
    shuffle(valid_choices) # now randomly shuffle that list 
    return valid_choices  # return the shuffled list 

def get_door(user_choice): 
    return user_choice.index(0) 


def monty_sim(n, kind): 
    """ 

    :param n: number of runs in this simulation 
    :param kind: whether to change the door or not, 0 - don't change, 1 = change door 
    :return: (win_rate, 1 - win_rate) 
    """ 
    wins = 0 
    for i in range(0, n): 
     game_doors = get_choices() 
     user_choice = get_door(get_choices()) # use the same method and find user door choice 
     # so there are two branches. 
     # In both, a door with a goat (game_door = 1) is chosen, which reduce the result to 
     # a choice between two doors, rather than 3. 
     if kind == 0: 
      if user_choice == game_doors.index(0): 
       wins += 1 
     elif kind == 1: 
      # so now, the user chooses to change the door 
      if user_choice != game_doors.index(0): 
       wins += 1 
      # Because the original choice wasn't the right one, then the new 
      # must be correct because the host already chose the other wrong one. 

    win_rate = (wins/n) * 100 
    return win_rate, 100 - win_rate 


if __name__ == '__main__': 
    n = 1000 
    kind = 1 
    wins, loses = monty_sim(n, kind) 
    print(f'In a simulation of {n} experiments, of type {kind} user won {wins:02f} of the time, lost {loses:02f} of the time')