Monty Hall simulator in Python 3.x I've been working on Python for the past few weeks trying to get my head around it's syntax/naming conventions/style/etc. I decided to make a monty hall sim to see how it looks in python. For those who don't know what the Monty Hall problem is, check the second paragraph here.

I've verified the code is fully functional and gives the right results. It IS indeed best to swap every time. After spending time getting rid of duplicated effort, overly wordy statements, and many logic errors, I'd like to know how to improve my code readability and efficiency (both here and in general).

Specific to this code, here's what I'd like to know (mostly #1):


If possible, how could I make this more efficient?
Is having a function call in the first for loop a good idea? If not, where do I put it?
I keep feeling like this is longer than needed. Are there still places I can cut out code?




import random

def setup():
    # Basic greeting/explaining what to do.
    print("\n\nThere are 3 doors. One is a winner. The computer")
    print("will try guess the right one. After the first ")
    print("guess, one door is shown to be a loser. The computer ")
    print("can then change it's choice to the remaining door.\n")

    # Display choices and get input
    change_choice = input("Should the computer always change it's choice? y/n\n:&gt; ")
    runs = int(input("How many times should this run?\n:&gt; "))
    run(change_choice, runs)

def run(change_choice, times_to_run):
    wins = 0 #Correct door choices

    # Loop through calling the function with switching enabled or not   
    for i in range(times_to_run):
        if change_choice == 'y' or change_choice == 'Y':
            wins = wins + setupDoors(True)
        else:
            wins = wins + setupDoors(False)

    # Display amount of times won/percentage of games won
    statistics(wins, times_to_run)

def setupDoors(always_change_choice):
    # Set up the winning door
    winning_door = random.randint(1,3)
    print("\nThe winning door is "+str(winning_door))

    # Get the computer's guessed door
    computer_guess = random.randint(1,3)
    print("the computer guessed door number "+str(computer_guess))
    return playGame(winning_door, computer_guess, always_change_choice)

def playGame(winning_door, computer_guess, always_change_choice ):

    # Get the right door to open.
    # Can't be the computer's door OR the winning door
    opened_door = getAvailableDoor(computer_guess, winning_door)
    print("Door number "+str(opened_door)+" was opened and shown not to be a winning door.")

    #Swap the computer's choice to last door if that was desired
    if always_change_choice:
        computer_guess = getAvailableDoor(computer_guess, opened_door)
        print("The computer changed it's guess to door number "+str(computer_guess))

    # Return a win or a loss.
    if computer_guess == winning_door:
        print("The computer won!")
        return 1
    else:
        print("The computer lost!")
        return 0

def getAvailableDoor(computer_guess, unavailable_door):
    # List of doors to choose from
    Doors = [1,2,3]

    for i in range(3):
        if Doors[i] == computer_guess or Doors[i] == unavailable_door:
            continue
        else:
            break
    return Doors[i]

def statistics(wins, times_to_run):
    print("\nThe computer won "+str(wins)+" times")
    print("This means the computer won "+str((wins/times_to_run)*100)+"% of the time")

setup()
Readability:

you should have 2 newlines after each function definition
you should use augumented assignments where possible
you should define each method in a logical order (e.g: if you're calling a function inside another function, the later should be defined first). That's rather a personal preference because you can't do this everytime.
you should have a space around operators and delimiters
you should make your print() statements more compact
variable names should be snake_cased. The same goes for method names.
at the beginning of each function you should define a docstring

Now, let's dig into each function:

in def statistics() you should use format() and join those two prints into a single one:


def statistics(wins, times_to_run):
    &quot;&quot;&quot;Print the statistics&quot;&quot;&quot;
    print(&quot;The computer won {} times&quot;
          &quot;This means the computer won {} % of the time&quot;.format(wins, (wins / times_to_run) * 100))


as mentioned above:


def setup_doors(always_change_choice):
    &quot;&quot;&quot;Set up the winning door&quot;&quot;&quot;
    winning_door = random.randint(1, 3)
    computer_guess = random.randint(1, 3)

    print(&quot;The winning door is {}.\n&quot;
          &quot;The computer guessed door number {}&quot;.format(winning_door, computer_guess))

    return play_game(winning_door, computer_guess, always_change_choice)


in def run(change_choice, times_to_run) you should avoid that multiple condition by using the lower function. You can also use the enumerate() to get rid off that variable definition, and replace i by _ as you don't use it:


def run(change_choice, times_to_run):
    &quot;&quot;&quot;Some description here&quot;&quot;&quot;
    for wins, _ in enumerate(range(times_to_run)):
        if change_choice.lower() == 'y':
            wins += setup_doors(True)
        else:
            wins += setup_doors(False)

    # Display amount of times won/percentage of games won
    statistics(wins, times_to_run)


in def setup() I'd just join the print statements:


def setup():
    &quot;&quot;&quot;Basic greeting/explaining what to do.&quot;&quot;&quot;
    print(&quot;\n\n&quot;
          &quot;There are 3 doors. One is a winner. The computer \n&quot;
          &quot;will try guess the right one. After the first \n&quot;
          &quot;guess, one door is shown to be a loser. The computer \n&quot;
          &quot;can then change it's choice to the remaining door.\n&quot;)

    # Display choices and get input
    change_choice = input(&quot;Should the computer always change it's choice? y/n\n:&gt; &quot;)
    runs = int(input(&quot;How many times should this run?\n:&gt; &quot;))
    run(change_choice, runs)

// To be continued. I have to leave the office.