Coin Flip Project

Hello,

I ran into a little trouble while trying to complete this project. I’m still practising on passing values around using function definitions and oftentimes, I just get stuck figuring out how to pass a particular result to another function.

Below is the link to my code: dpaste: F5TPX5FAN

The issue is that I want the code on L47 to be printed last, I understand that LoC should be inside and after the for_loop of start_game function. I can’t seem to figure out how to achieve that…

Hi there, I’m starting with python but I tried to run you code to see if I could help. I think the variables round_won and round_lost are local variables and are being initialized to zero every time the function print_result is called (every round). We need to keep track of their values outside the function.

I tried declaring them outside the function to use them as global variables and got an "UnboundLocalError: local variable referenced before assignment" error.

In this article they explain why I got the error and two possible solutions. One of them is to declare the two variables outside the function and then use the global keyword inside print_result to make the variables available inside the function. I tried that with your code and it seems to work fine.

We only need to declare globals in a function if we intend to change the value. In functional programming this is frowned upon since it is a side effect.

If round_won and round_lost are global, then control of the values should be in that scope, not in function scope. Have the function return a result and increment one or the other according to the return value.

def foo():
    # result = some_boolean
    return result

round_won, round_lost = 0, 0

while True:
    round_won += 1 if foo() else round_lost += 1
    if input("Continue? 'y/n'").lower() == 'n': break

The above pseudo code illustrates an infinite control loop and a helper function. The loop has a built in breaking condition.

2 Likes

I think the problem is one of scope. It looks like the other commenters are aware of this - as are you.

Let’s look at the logic of the organization below.

First, start_game() is called. It decides the number of rounds and keeps track of the score. It calls run_round() which returns a True or False result (i.e. win or lose). It then prints the results. In short, the function runs a round a prints the results.

Second, let’s look at run_round(). It runs a single round of the game and returns the result. It calls get_player_guess() which return the player guess, flip_coin() which returns the coin flip, prints out the results of both, and then returns the result.

This type of logic is very common in programming. A single large task is broken down into logical parts. A single controller function calls child (or helper) functions which each do a part of the task. The controller function then returns the result(s) of the task.

I hope the code below illustrates this methodology.

import random 
.
COIN_SIDES = ("heads", "tails")

def start_game():
    game_round  = 3
    rounds_won  = 0
    rounds_lost = 0
    
    for round in range(game_round):
        print("Starting round", count_round + 1, "of", game_round)
        result = run_round()

        if result == True:
            print("Round Won")
            rounds_won += 1
        else:
            print("Round Lost")
            rounds_lost += 1

    print("Rounds Won:",  rounds_won, "\tRound Lost:", rounds_lost)

def run_round():
    player_guess  = get_player_guess()
    actual_flip   = flip_coin()
    round_outcome = player_guess == actual_flip
    
    print("You flipped:", player_guess)
    print("You guessed:", actual_flip)
    
    return round_outcome

def get_player_guess():
    while True:
        player_guess = input("Heads or Tails?: ").lower()

        if player_guess not in COIN_SIDES:
            print("\nHeads or Tails only!")
            
        return player_guess

def flip_coin():
    return random.choice(COIN_SIDES)

start_game()
1 Like

@fsilva8 As @mtf has pointed out, global variables have surprising or difficult to detect side effects when using it, but in this case, my COIN_SIDES here is a global constant. You can see why my code doesn’t have any more variables in the global scope apart from the global constant.

@brianmonette Hello and thank you for the explanation of your code. I’ve tested it out and looked into it, it works just as I wanted to. I also found another workaround without having to define another function, everything’s the same except that I fit them into the for_loop, just extra 3-4 more lines of code.

Code: dpaste: DTUGXY2EC

I’ll also create a separate version of this project with your code in it for future reference. I also like the part which you mention about breaking down a single larger task into smaller logical parts. I always do that when I see one function is being overwhelmed with code, but most of the times, when I start to break them down into smaller pieces, some pieces just wouldn’t link together or that I just get lost on doing so.

Part of learning programming is knowing when to break a large task into smaller parts and what parts to break it up into.

This is a long-running debate among programmers and often depends upon the language used. Features of certain languages make breaking up code easier. Other languages don’t make it easy. Teachers have their philosophies. Programmers have their philosophies. And this is why “coding style guides” are important for a project. Some languages need strict controls to keep the project from going sideways.

My personal philosophy is to have a function that tells the story of what is happening: get player guess, flip coin, and return round outcome. This does one thing and has helper classes for each phrase. The parent method which repeats the function several times does one thing: Runs the rounds and prints the results.