How do I avoid a variable resetting at the beginning of a function?

I'm new to python so I'm sorry if the code is very bad. But, I am making a basic slot machine game and I'm trying to implement a credit system. You start off with 50 credits and it requires 25 to spin. It works, but the problem is, my spin is in a function. And, because it is in a function it resets the credits each time it spins again. I am using an if statement to calculate the credits after a spin.

Important to note, I am using a variable named totalcredits to calculate the actual credits. This is because if I try to use the credits variable in my if statement I get the error: UnboundLocalError: local variable 'credits' referenced before assignment.

This makes sense because I am in effect creating a loophole of credits, at least I think. So I've been trying to think of a workaround to stop resetting the credits but it is outside my range of knowledge. I've tried global variables and a few other things that didn't work. Here is my code:

import random

credits = 50
spindeduct = 25

win1 = 10
win2 = 40
win3 = 30
#win1, which is temporarily a "X" is worth 10 credits. So if the slots landed "X:X:X" you would get 10 credits. win2 is worth 40 credits (a "7"), and win 3 is worth 30 credits (a "Cherry"). Each spin deducts 25 from your credits
def spin():

  z = random.randint(1, 3)
  x = random.randint(1, 3)
  y = random.randint(1, 3)
  #1 = X
  #2 = 7
  #3 = Cherry
  print("\n")
  print(z)
  print(x)
  print(y)

  #this chunky if statement calculates the amount of credits the player should have, it technically works but the credits is reset every time
  if z == 1 and x == 1 and y == 1:
    print("\nYou got a small win! + 10 Credits!")
    totalcredits = credits - spindeduct + win1
  elif z == 2 and x == 2 and y == 2:
    print("\nYou won! + 40 Credits!")
    totalcredits = credits - spindeduct + win2
  elif z == 3 and x == 3 and y == 3:
    print("\nYou won! + 30 Credits!")
    totalcredits = credits - spindeduct + win3
  else:
    print("\nYou lost!")
    totalcredits = credits - spindeduct

  #printcredits is a janky workaround to prevent errors when telling the user the amount of credits they have
  printcredits = totalcredits
  print("You have " + str(printcredits) + " credits.")
  v = input("\nWould you like to spin again? Y/N: ")

  #if the player doesn't have enough credits to spin, they can no longer play
  if totalcredits >= 25:
    print("\nYou have enough credits to spin again!")
  else:
    print("You do not have enough credits to spin again!")
    quit()


  if v == "Y":
    spin()
  elif v == "y":
    spin()
  else:
    print("Stopped")
    quit()
  
  

print("Slot Simulator")

a = input("Would to like to spin some slots? (50 Credits) Y/N: ")

if a == "y":
  spin()
elif a == "Y":
  spin()
else:
  print(Stopped)

Solution 1:

It's not a big deal to "use a global variable", especially in a small file (i.e. a Python module) -- it automatically gets namespaced to that module.

gamestate = {'credits': 0}

def increment():
    gamestate['credits'] += 1

increment()
print(gamestate)
# gamestate == {'credits': 1}

This has its limits as code grows larger & more complex though, e.g. multiple modules. An alternative would be to pass state into your functions:

gamestate = {'credits': 0}

def increment(state):
  state['credits'] += 1

increment(gamestate)
print(gamestate)
# {'credits': 1}

And sometimes the state changes get so complex and hard to keep track of that it helps to avoid mutations by creating new copies instead:

gamestate = {'credits': 0}

def increment(state):
  return {'credits': state['credits'] + 1}

new_state = increment(gamestate)
print(gamestate)
# {'credits': 0}

print(new_state)
# {'credits': 1}

gamestate = new_state  # can still mutate in the end, in a single place
print(gamestate)
# {'credits': 1}

A word about why I'm using a dict "gamestate":

credits = 0  # I could use a global int

# but global variables normally can't be modified inside functions:
def wont_work():
    credits = credits + 1


def declare_global():
    global credits  # you could declare that it's global for modification
    credits += 1    # same as credits = credits + 1

    other_num = 10

    # but many lines of code later, it can get confusing
    # just looking at these two lines, can you tell which is global?
    other_num += 1  # only changes inside this function
    credits += 1    # affects other functions using the same variable!


# dicts are naturally modifiable (i.e. mutable) containers
gamestate = {'credits': 0}  # a dict holding an int

# note that global var `gamestate` isn't changing
def increment():
    other_num = 10

    # It's pretty clear which is making a change "somewhere else"
    other_num += 1
    gamestate['credits'] += 1  # changes contents of `dict`