Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

How to update a initial var (balance) with a new one created in a function (newBalance?)

Hi!

I've created this dice rolling game following the Python Basics course. I'm a complete beginner. So far so good.

The game works like this:

  • Initial balance of 100.
  • Asks for input for a number and a bet.
  • Runs through checks if all ok.
  • If win let's player know and adds prize to newBalance.
  • If loss let's player know and subtracts bet from balance.
  • Asks if player what's to play again and loops. *****

***** The problem is that when the function loops to start a new game, the initial value gets back to 100. If I try to add the newBalance value to the top of the function, it wont let me due to it being used before being declared...

I've tried for hours and googled for hours.

Any help is very appreciated!

CODE: https://pastebin.com/Heewd3xP

Also any advice on cleanup, optimization, improvements, tips and tricks etc. are VERY welcome!

Thank you!

Hi Keyan,

I can't comment on everything since it would take too much time and be too complicated to do in a forum post like this, but I did try a copy of your code and managed to fix it/rewrite. I'm sure there are people here who know far more than I do and I welcome their comments, but here are the main points that helped me get the code working:

  • Right now, nearly all the code is in one giant function. Try separating this into smaller functions, so that it is easier to repeat smaller sections of code without calling the entire function all over again (recursively). For example, when I rewrote, I created functions called get_guess and get_bet so that I could put the data validation and repeating prompts to the user ("Please try again" kind of thing) in its own separate function that is called from within diceRoll. So from within diceRoll, I had the following function calls:
def diceRoll(balance):
    # other code, etc. before this

    # get_guess asks the user to input a guess, then checks that it is a valid guess. (If not, asks user for another guess.)
    guess = get_guess() # No arguments since it knows the valid guesses are always between 1 and 6.

    # get_bet asks the user to input a bet, then checks that it is a valid bet. (If not, asks user for another bet.)
    bet = get_bet(balance)  # Takes balance as a parameter since it's checking that the bet isn't larger than this.

    # diceRoll doesn't need to do error checking on these since it is already done in the get_guess and get_bet functions.
    # more code, etc. after this
  • Try controlling the rounds from outside of diceRoll with a while loop, and call diceRoll separately for each round. Again, that avoids recursion (calling a function from within itself). Recursion is useful in some situations, but I wouldn't recommend it for this situation.
  • You can pass the current balance as an argument into diceRoll, so you can be sure to always have the latest balance. That would mean diceRoll would ideally return an updated balance (i.e., after the outcome of the round), so it can be tracked outside of the function call.

I hope this will give some helpful ideas!

5 Answers

Thank you so much Louise! You're an angel! I got it from here! :)

You're welcome! Good luck! :-)

Hi Louise! Thank you for your reply.

Could you send me your working script for this? I've been trying to do as you say, but I'm not having any success.

I'm pretty good at "reverse engineering" to understand concepts and how to do this, so that would give me a better view of how and why that could work.

Thank you!

Hi Keyan,

This sounds like a substantial project for your course so I won't give the full script, but here's a version of it that contains the structure I was talking about and a lot of pseudo-code and descriptions that I think you can work from. I put TODO wherever code needs to be added. I'm pretty confident that you already know how to add what's missing, so you can get some sense of figuring it out for yourself! :-)

Some real code is still left here, which is code that was already in your old program (sometimes with minor tweaks).

#pylint:disable=W0312
#python 3.6
from random import randint
import math

# Static Variables
START_BALANCE = 100
BAD_GUESS = "The guess must be a number between 1 and 6. Please try again."
BAD_BET = "The bet must be a number between 1 and {}."


#######
#
# Function: get_guess()
#
# Parameters: (none)
#
# Returns: an integer between 1 and 6
#
# This is where you ask the user for their guess on the result of the dice roll.
# Inside an infinite while loop, ask the user for a value from 1 to 6.
# If the user inputs a bad value (either something that isn't a number, or isn't 
# from 1 to 6, catch the error and print BAD_GUESS and continue to the next iteration 
# of the while loop, which will repeat the request for input and evaluate that.
# Once there is valid input (a number from 1 to 6), break out of the while loop
# and return that value.
#
#######

# Uncomment the definition when you're ready to work on building the function.
# def get_guess():
    # TODO: Build function per description above.


#######
#
# Function: get_bet(balance)
#
# Parameters: balance - an integer representing the user's current balance.
#
# Returns: an integer between 1 and the balance
#
# This is where you ask the user for their bet for this round.
# The structure is quite similar to get_guess(), except that the max number (balance)
# can change, so it needs that as a parameter.
# Inside an infinite while loop, ask the user for a value from 1 to the given balance.
# If the user inputs a bad value (either something that isn't a number, or isn't 
# from 1 to the balance, catch the error and print BAD_BET. Continue to the next iteration 
# of the while loop, which will repeat the request for input and evaluate that.
# Once there is valid input (a number from 1 to current balance), break out of the while loop
# and return that value.
#
#######

# Uncomment the definition when you're ready to work on building the function.
# def get_bet(balance):
    # TODO: Build function per description above.

#######
#
# Function: diceRoll(balance)
#
# Parameters: balance - an integer with the current balance
#
# Returns: a list of two items: 
#               [boolean - True if user wants to play again, False if not,
#                balance - integer with the new balance based on outcome of this round.]
#          The format of this list matches the variable game_state defined
#          outside of this function. 
#
# This is where you actually roll the dice and compare that to what the user guessed.
# If they lose the bet, they don't get their bet money back.
# If they win the bet, the get the bet * 1.75 back.
# Then the user is asked if they want to play again.
# This function returns a list indicating if the player wants another round (True if yes, 
# False if no), and the latest balance after this round.
#
#######

#### FUNC START ####
# Pass the current balance to diceRoll so it doesn't reset every time you run it,
# which was the original problem with your code.
def diceRoll(balance): 

    # TODO: Use the get_guess function to get a guess from the user, and assign it 
    # to a variable called guess.

    # TODO: Use the get_bet function to get a bet from the user, and assign it 
    # to a variable called bet.

    # TODO: Subtract the bet from the balance for this round, i.e., reduce the balance
    # by the amount of the bet.


### Roll the dice
    roll = randint(1,6)

# LSG Comment: You don't need variables to track whether the game was won or not
# so I took all that out. Below is what's left of your original code, with some commenting
# on what you need to add. 

### IF PLAYER WINS ###
    if (roll == guess):
        prize = bet * 1.75
        balance += prize
        #
        print("\nYOU WIN {}$!".format(prize))
        print("You guessed: {} - The roll was {}!\n".format(guess, roll))
        print("-- Your balance is now {}$ -- \n".format(balance))


### IF PLAYER LOSES ###
    elif (roll != guess): # This can be just else: but I guess it doesn't really matter.
        #
        print("\nYOU LOSE {}$".format(bet))
        print("The roll was: {} - You guessed: {}.".format(roll,guess))
        print("-- Your balance is now {}$ --\n".format(balance))
        # LSG: No need to subtract from the balance again, so that code was removed. The bet was
        # already removed from the balance earlier.

### ASK PLAYER TO PLAY AGAIN ###
    # This is mostly your old code, but with some tweaks, e.g., switch to upper() rather than title()
    choice = input("Would you like to try again?  Y/N   ").upper()
    if (choice == "YES" or choice == "Y"):
        print("New round! Your balance is {}$".format(balance))

        # TODO: return a list where the first item is the bool True, and the second item is the balance.
        # This is the updated info that will go into the game_state variable outside this function.


    else: # You originally had an elif, but basically anything other than "YES" or "Y" means no, and simplifies error checking.
        print("GAME OVER !")

        # TODO: return a list where the first item is the bool False, and the second item is the balance.
        # This is the updated info that will go into the game_state variable outside this function.


### CALL FUNCTION ###

# Initialize game_state, which is a variable that keeps track of your rounds and balance.
game_state = [True, START_BALANCE]

# TODO: Build a while loop that executes any time the first item in game_state is True (i.e., while the
# user still wants to play a new round. Note that I initialized game_state[0] to True, assuming that 
# if they started the program, they want to play the first round.

    # TODO: Inside the while loop, call diceRoll with the balance, which is the second list item in game_state.
    # Note that diceRoll is going to return an updated list for you to plug into game_state, so make sure you grab
    # that, i.e., don't just call diceRoll(balance) without assigning it to game_state.

Louise - I just finished this project and its working perfectly. I have learned so much from your template and little hints. Thank you so much, I wouldn't had been able to do this without you.

Here's the game if you'd like to try it out: https://pastebin.com/fhRNjiwq

Bless you :)

Hi Keyan,

Yay! So glad to hear you were able to get this working! :-)

Keep up the good work!

Louise

Hi Louise! I'm sorry to yet again comment this - I just want to hear how you would write the last part, i.e the while loop regarding "game_state"?

Could you give me the example? Mine acts weird after further testing.. it won't terminate when player says "no", even if it displays game over. It re-loops.

  • My code:

game_state = [True, START_BALANCE] while (game_state[True]): game_state = diceRoll(game_state[1])

I think you just need to fix game_state[True] to game_state[0], like this:

game_state = [True, START_BALANCE] 

# game_state[0] contains True if the user wants to play again, False if not.
# So if it's false, while (game_state[0]) will evaluate to false and stop the while loop.
while game_state[0]: 
    game_state = diceRoll(game_state[1])