python – Could this balance counter code be simpler?

All your win1, win2 and win3 functions are essentially the same. When you have multiple functions/pieces of code that are nearly identical, look at what parts of them are the same, and what parts are different. Make the identical parts the body of a function, and the differing parts parameters of the function.

In the case of those three functions, they’re all the same; except for the bonus factor. Simply make that a parameter:

def win(bonus_factor):
    amount_won = bet * bonus_factor
    # I did different wins, the win1,2,3 function contains them
    print("WIN!WIN!WIN! n You won " , amount_won, "credits! ")
    a.append(a(-1) + amount_won)
    print("Actual balance : ", a(-1))

Then change the callsite to use the same function:

elif reel_1 + reel_2 + reel_3 == 8:
    win(6)

elif  reel_1 + reel_2 + reel_3 == 7:
    win(4)

elif  reel_1 + reel_2 + reel_3 == 6:
    win(2)

And better yet, the 6, 4 and 2 should be extracted out into constants at the top of the file so they’re named and easily modifiable.

That reduced the duplication of those three functions, but there’s multiple things that need to be said about a:

  • It’s a terrible name. The name you associate with an object should be descriptive and let readers know its purpose. Which makes more sense to you?:

    a.append(a(-1) + (bet * 4))
    balance_history.append(balance_history(-1) + (bet * 4))
    

    You’ll find that overwhelmingly, the latter will be easier to understand. Not only is a completely non-descript, but it’s also so simple that you can’t search for usages of it using simple “find” tools, since a is such a common letter.

  • It’s not necessary. If you do a search for usages of a, you’ll see that it’s only used for two things: a(-1), and a.append. While there’s something to be said about anticipating future needs, you’re currently accumulating a history of balances that you never use. This not only uses up more memory than is needed, but it also convolutes the logic. If you’re maintaining a history, that suggests that the history is used somewhere. It never is though. You could safely change a to balance = 1000, then just do simple math on it directly. That would make a lot of this code cleaner and more sensical.


Speaking of memory usage, you’re using recursion for basic looping, which is not a good thing. Your spin function is essentially:

def spin():
    # Logic
    reels(), spin()

Every single time your player takes another turn, spin is allocating another stack frame, and taking up more memory. If your player were to take ~1000 turns, your program would crash due to the stack being exhausted. Change that function to a basic while loop:

def spin():
    global balance
    while True:
        # And this is the main function, the spin
        spin1 = input("Balance : " + str(balance) + " Press enter to spin the wheel ")

        if spin1 == "":
            print("****************************THE WHEEL IS SPINNING**************************** n")
            balance -= bet
            print("Balance : ", balance)
            reels()
        else:
            print("You can only spin the wheel with enter")  

A few changes I made:

  • I changes balance to be a simple integer and discussed above (notice how much more sense balance -= bet makes).
  • It’s using a while loop. This does not eat up memory as the program is used. Recursion should be reserved for the very specific cases where it’s the proper choice, like when iterating a recursive structure. Especially in a language like Python, recursion should be avoided unless you’re very familiar with it and know about its strengths/weaknesses.
  • I rearranged the if branches. You originally had it so if if spin1 == "": was true, all it would do is print; then the actual functionality happened at the bottom of the function. I think it makes much more sense as I have it here; where everything is grouped.
  • I did a lot of small touchups (more on that below).

You’re making heavy use of global variables. This is quite common when starting out, but it’s a habit you should work to fix quickly. General rules of thumb to follow unless you have good reason to do otherwise:

  • All the changing data that a function requires to operate (balance, for example) should be explicitly passed to the function as arguments. This means you can test the function by simply passing it data, and you don’t need to alter global state. This isn’t a big deal now, but needing to alter mutable globals to test a function will become a disaster once your function is larger.
  • All data that the function produces should be returned from the function. Again, this means you can test the function all you want without affecting any other code.

As an alternative, you may also find that creating a class to maintain a state is a cleaner choice as well. That’s getting a little more advanced though.


I’m going to show the full final code below, but I needed to make many small fixes to make it clean. Please be aware of formatting. Yes, it is very important. You have many places in your code where care was not taken to make it consistent and readable:

elif reel_1 + reel_2 + reel_3 == 8:
    win3()

elif  reel_1 + reel_2 + reel_3 == 7:  # Too many spaces after the elif
    win2()


"Balance : "+ str(a(-1))+ " Press enter to spin the wheel "  # Inconsistent spacing around +


def spin() :  # There shouldn't be a space before the colon

If you’re going to write Python, you should spend an afternoon to read over PEP8 at least once. The look of your code reflects strongly on that care that was taken while writing it. You want you code to look sharp, and clean. You may have your own stylistic preferences, but be consistent when applying them, and when in doubt, stick to PEP8.


The final code:

import random

balance = 1000
bet = 20


def win(bonus_factor):
    global balance
    amount_won = bet * bonus_factor
    # I did different wins, the win1,2,3 function contains them
    print("WIN!WIN!WIN! n You won ", amount_won, "credits! ")
    balance += amount_won
    print("Actual balance : ", balance)


def reels():
    global balance
    # Here is the random number calculation.As you can see, theres a pretty good chance to win so it
    # would not be a good casino game for the house :)
    reel_1 = random.randint(1, 3)
    reel_2 = random.randint(1, 3)
    reel_3 = random.randint(1, 3)

    if reel_1 + reel_2 + reel_3 == 9:
        print("Jackpot!!!!!!!!!!")
        balance += bet * 100
        print("Actual balance : ", balance)

    elif reel_1 + reel_2 + reel_3 == 8:
        win(6)

    elif reel_1 + reel_2 + reel_3 == 7:
        win(4)

    elif reel_1 + reel_2 + reel_3 == 6:
        win(2)
    else:
        print("No win this time")


def spin():
    global balance
    while True:
        # And this is the main function, the spin
        spin1 = input("Balance : " + str(balance) + " Press enter to spin the wheel ")

        if spin1 == "":
            print("****************************THE WHEEL IS SPINNING**************************** n")
            balance -= bet
            print("Balance : ", balance)
            reels()
        else:
            print("You can only spin the wheel with enter")


spin()