Random number gen not working

Hey, I’m working on a working blackjack program for a school project, and in part of my code, the random number generator is just straight up not working. ill put the code here:

def stay():
        global card_one, card_two, card_three, card_four, card_five, card_six, cmp_card_num_one, cmp_card_num_two, cmp_card_num_three, cmp_card_num_four, cmp_card_num_five, cmp_card_num_six, cmp_card_suit_one, cmp_card_suit_two, cmp_card_suit_three, cmp_card_suit_four, cmp_card_suit_five, cmp_card_suit_six, cmp_card_value_one, cmp_card_value_two, cmp_card_value_three, cmp_card_value_four, cmp_card_value_five, cmp_card_value_six, cmp_card_value_total, cmp_card_one, cmp_card_two, cmp_card_three, cmp_card_four, cmp_card_five, cmp_card_six, card_value_total
        cmp_card_one_num = random.randint(1, 13)
        cmp_card_one_suit = random.randint(1, 4)
        cmp_card_two_num = random.randint(1, 13)
        cmp_card_two_suit = random.randint(1, 4)
        cmp_card_three_num = random.randint(1, 13)
        cmp_card_three_suit = random.randint(1, 4)
        cmp_card_four_num = random.randint(1, 13)
        cmp_card_four_suit = random.randint(1, 4)
        cmp_card_five_num = random.randint(1, 13)
        cmp_card_five_suit = random.randint(1, 4)
        cmp_card_six_num = random.randint(1, 13)
        cmp_card_six_suit = random.randint(1, 4)

        print(cmp_card_num_one, cmp_card_num_two)

        duplicate_cards = set()
        while len(duplicate_cards) < 13:
            cmp_card_one_num = random.randint(1, 13)
            cmp_card_one_suit = random.randint(1, 4)
            cmp_card_two_num = random.randint(1, 13)
            cmp_card_two_suit = random.randint(1, 4)
            cmp_card_three_num = random.randint(1, 13)
            cmp_card_three_suit = random.randint(1, 4)
            cmp_card_four_num = random.randint(1, 13)
            cmp_card_four_suit = random.randint(1, 4)
            cmp_card_five_num = random.randint(1, 13)
            cmp_card_five_suit = random.randint(1, 4)
            cmp_card_six_num = random.randint(1, 13)
            cmp_card_six_suit = random.randint(1, 4)

            duplicate_cards = {
                (cmp_card_one_num, cmp_card_one_suit),
                (cmp_card_two_num, cmp_card_two_suit),
                (cmp_card_three_num, cmp_card_three_suit),
                (cmp_card_four_num, cmp_card_four_suit),
                (cmp_card_five_num, cmp_card_five_suit),
                (cmp_card_six_num, cmp_card_six_suit),
                (card_num_one, card_suit_one),
                (card_num_two, card_suit_two),
                (card_num_three, card_suit_three),
                (card_num_four, card_suit_four),
                (card_num_five, card_suit_five),
                (card_num_six, card_suit_six),
                (card_num_seven, card_suit_seven)
                        }

            cmp_card_one = get_card_name(cmp_card_one_suit, cmp_card_one_num)

            cmp_card_two = get_card_name(cmp_card_two_suit, cmp_card_two_num)
            cmp_card_three = get_card_name(cmp_card_three_suit, cmp_card_three_num)
            cmp_card_four = get_card_name(cmp_card_four_suit, cmp_card_four_num)
            cmp_card_five = get_card_name(cmp_card_five_suit, cmp_card_five_num)
            cmp_card_six = get_card_name(cmp_card_six_suit, cmp_card_six_num)

            # Calculate card values for each variable
            # Process card_num_one
            print(cmp_card_num_one, cmp_card_num_two)

            if 2 <= cmp_card_num_one <= 9:
                print("one")
                cmp_card_value_one = cmp_card_num_one
            elif cmp_card_num_one in (10, 11, 12, 13):
                cmp_card_value_one = 10
                print("two")
            elif cmp_card_num_one == 1:
                cmp_card_value_one = 1
                print("three")

            # Process card_num_two
            if 2 <= cmp_card_num_two <= 9:
                cmp_card_value_two = cmp_card_num_two
            elif cmp_card_num_two in (10, 11, 12, 13):
                cmp_card_value_two = 10
            elif cmp_card_num_two == 1:
               cmp_card_value_two = 1

            # Process card_num_three
            if 2 <= cmp_card_num_three <= 9:
                cmp_card_value_three = cmp_card_num_three
            elif cmp_card_num_three in (10, 11, 12, 13):
                cmp_card_value_three = 10
            elif cmp_card_num_three == 1:
                cmp_card_value_three = 1

            # Process card_num_four
            if 2 <= cmp_card_num_four <= 9:
                cmp_card_value_four = cmp_card_num_four
            elif cmp_card_num_four in (10, 11, 12, 13):
                cmp_card_value_four = 10
            elif cmp_card_num_four == 1:
                cmp_card_value_four = 1

            # Process card_num_five
            if 2 <= cmp_card_num_five <= 9:
                cmp_card_value_five = cmp_card_num_five
            elif cmp_card_num_five in (10, 11, 12, 13):
                cmp_card_value_five = 10
            elif cmp_card_num_five == 1:
                cmp_card_value_five = 1

            # Process card_num_six
            if 2 <= cmp_card_num_six <= 9:
                cmp_card_value_six = cmp_card_num_six
            elif cmp_card_num_six in (10, 11, 12, 13):
                cmp_card_value_six = 10
            elif cmp_card_num_six == 1:
                cmp_card_value_six = 1


            cmp_card_value_total = cmp_card_value_one + cmp_card_value_two
            print("The computer drew a", cmp_card_one, "and a", cmp_card_two)
            print("The computer's total is", cmp_card_value_total)
            exit()
            if card_value_total >= cmp_card_value_total < 21:
                cmp_hit_one()
            elif card_value_total < cmp_card_value_total < 21:
                print("The computer wins! They ended on a score of", cmp_card_value_total, "while you ended on a score of", card_value_total)
                comp_win()
            elif cmp_card_value_total > 21:
                print("The computer busts! They ended on a total of", cmp_card_value_total)
                comp_bust()

In what way do you think that it is not working?
You need to tell us as we should not guess what you are thinking.
As a simple test I did this:

Python 3.12.1 (v3.12.1:2305ca5144, Dec  7 2023, 17:23:38) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
:>>> import random
:>>> random.randint(1, 13)
11
:>>> random.randint(1, 13)
9
:>>> random.randint(1, 13)
11
:>>> random.randint(1, 13)
3
:>>> random.randint(1, 13)
9
:>>> random.randint(1, 13)
7
:>>>

sorry, forgot to keep typing. all the variables I’m trying to define using the random gen are not being changed from their previous global definition, which is zero.

        cmp_card_one_num = random.randint(1, 13)
        [...]
        print(cmp_card_num_one, cmp_card_num_two)

Note that one is one_num and the other is num_one.

1 Like

Just as a side note, you should look into the random.sample function (random — Generate pseudo-random numbers — Python 3.12.1 documentation). You can pass it a complete deck (e.g. ((1, 1), ..., (13, 4)) in your case), a number of cards to draw, and it will pick that number of elements in the provided deck.

I know this doesn’t directly solve the bugs (if any) in the code you sent. But it can help you significantly shorten your code, and therefore track bugs more easily!

1 Like

dude… i so wish i new this sooner. i have 700 lines of code… fml

I would suggest that instead of random.sample you model with something like:

deck = create_sorted_deck()  # Generate list of cards, whatever those are
random.shuffle(deck)  # in-place reorder

player1 = []

# Draw card from deck, and add to player's hand
player1.append(deck.pop())

Shuffling and removing works well for the equivalents of physical objects (like a deck of cards), and you don’t need to account for collisions.

Hey!
Instead of using all that code, use this code:

from random import randint
def stay(howmany):
    try:
        if howmany == 1:
            print(randint(int(input("Minimum number: ")), int(input("Maximum number: "))))
            print("Something went wrong.")
        elif howmany == 2:
            print(randint(int(input("1) Minimum number: ")), int(input("1) Maximum number: "))))
            print(randint(int(input("2) Minimum number: ")), int(input("2) Maximum number: "))))
        elif howmany == 3:
            print(randint(int(input("1) Minimum number: ")), int(input("1) Maximum number: "))))
            print(randint(int(input("2) Minimum number: ")), int(input("2) Maximum number: "))))
        elif howmany == 4:
            print(randint(int(input("1) Minimum number: ")), int(input("1) Maximum number: "))))
            print(randint(int(input("2) Minimum number: ")), int(input("2) Maximum number: "))))
            print(randint(int(input("3) Minimum number: ")), int(input("3) Maximum number: "))))
            print(randint(int(input("4) Minimum number: ")), int(input("4) Maximum number: "))))
        else:
            print("Invalid number.")
    except:
        print("Something went wrong.")
if __name__ == "__main__":
    while True:
        ask = int(input("How many random numbers? "))
        stay(ask)
        if ask == "exit":
            print("Okay! Bye-bye!")
            break

If you need more random numbers, I can help!

To note, you can make your code at least an order of magnitude less verbose using the concepts you already evidently know: functions, data structures (lists, etc) and loops. Anytime you see a bunch of code duplicated many times with only a few or even one thing changing, we call it a “code smell”, and means you can usually replace all those lines of code with a function that takes as parameters anything that changes (variables, etc). This will make your code much easier to read, write, debug and make these sorts of changes on, as well as make it harder to introduce these sorts of bugs in the first place since there are fewer places for things to go wrong.

Of course, in this case you should just avoid writing the code to begin with by using the appropriate standard library function—random.shuffle as others have suggested—which will make your code simpler and cleaner still. However, to explain and illustrate the concept, here are a few examples of how you can use these principles to simplify your existing code.

At the beginning of your function, you pick random integers for each card value and suit:

        global card_one, card_two, card_three, card_four, card_five, card_six, cmp_card_num_one, cmp_card_num_two, cmp_card_num_three, cmp_card_num_four, cmp_card_num_five, cmp_card_num_six, cmp_card_suit_one, cmp_card_suit_two, cmp_card_suit_three, cmp_card_suit_four, cmp_card_suit_five, cmp_card_suit_six, cmp_card_value_one, cmp_card_value_two, cmp_card_value_three, cmp_card_value_four, cmp_card_value_five, cmp_card_value_six, cmp_card_value_total, cmp_card_one, cmp_card_two, cmp_card_three, cmp_card_four, cmp_card_five, cmp_card_six, card_value_total
        cmp_card_one_num = random.randint(1, 13)
        cmp_card_one_suit = random.randint(1, 4)
        cmp_card_two_num = random.randint(1, 13)
        cmp_card_two_suit = random.randint(1, 4)
        cmp_card_three_num = random.randint(1, 13)
        cmp_card_three_suit = random.randint(1, 4)
        cmp_card_four_num = random.randint(1, 13)
        cmp_card_four_suit = random.randint(1, 4)
        cmp_card_five_num = random.randint(1, 13)
        cmp_card_five_suit = random.randint(1, 4)
        cmp_card_six_num = random.randint(1, 13)
        cmp_card_six_suit = random.randint(1, 4)

        print(cmp_card_num_one, cmp_card_num_two)

Notice how each group of two lines are duplicated? You can avoid that, and all the globals too (which make the code much harder to reason about and debug), by storing cards and cmp_cards as lists, with each list value being tuple containing the card number and suit, just as you do anyway in the next step when checking for duplicates [1].

Therefore, you can replace all above code with a for loop generating the random cards [2]:

cmp_cards = []
for __ in range(6):
    card = (random.randint(1, 13), random.randint(1, 4))
    cmp_cards.append(card)

Or even nicer, you could use a list comprehension to make this even more concise and efficient:

cmp_cards = [(random.randint(1, 13), random.randint(1, 4)) for __ in range(6)]

Likewise, you currently generate new cards and check for duplicates like this:

    duplicate_cards = set()
    while len(duplicate_cards) < 13:
        cmp_card_one_num = random.randint(1, 13)
        cmp_card_one_suit = random.randint(1, 4)
        cmp_card_two_num = random.randint(1, 13)
        cmp_card_two_suit = random.randint(1, 4)
        cmp_card_three_num = random.randint(1, 13)
        cmp_card_three_suit = random.randint(1, 4)
        cmp_card_four_num = random.randint(1, 13)
        cmp_card_four_suit = random.randint(1, 4)
        cmp_card_five_num = random.randint(1, 13)
        cmp_card_five_suit = random.randint(1, 4)
        cmp_card_six_num = random.randint(1, 13)
        cmp_card_six_suit = random.randint(1, 4)

        duplicate_cards = {
            (cmp_card_one_num, cmp_card_one_suit),
            (cmp_card_two_num, cmp_card_two_suit),
            (cmp_card_three_num, cmp_card_three_suit),
            (cmp_card_four_num, cmp_card_four_suit),
            (cmp_card_five_num, cmp_card_five_suit),
            (cmp_card_six_num, cmp_card_six_suit),
            (card_num_one, card_suit_one),
            (card_num_two, card_suit_two),
            (card_num_three, card_suit_three),
            (card_num_four, card_suit_four),
            (card_num_five, card_suit_five),
            (card_num_six, card_suit_six),
            (card_num_seven, card_suit_seven)
                    }

Now that you already have your cmp cards in a single list of tuples (cmp_cards), if we assume that cards is also a similar list of tuples, we can convert to a set and check for duplicates by simply concatenating the lists and calling set() on it:

while len(set(cmp_cards + cards)) < 13:
    # Re-randomize cmp_cards

Now, with your existing code, you just regenerate all the cmp cards again, repeating the previous operation again. When things are repeated, instead of copy/pasting code, you usually want to either use a loop (which you already have!) or a function. Since the cards generated before the loop are always replaced anyway on the first iteration since duplicate_cards (which really should be the opposite, unique_cards) is always empty (and thus the while check is false), so that prior code doesn’t actually do anything useful. Therefore, you could just bring that code inside the loop:

cmp_cards = []
while len(set(cmp_cards + cards)) < 13:
    for __ in range(6):
        card = (random.randint(1, 13), random.randint(1, 4))
        cmp_cards.append(card)

Alternatively, you could move randomly picking the cards to a function (using the list comprehension form here):

def gen_cards(n):
    return [(random.randint(1, 13), random.randint(1, 4)) for __ in range(n)]

Which you could call both here and wherever you generate the cards variables:

cmp_cards = gen_cards(6)
while len(set(cmp_cards + cards)) < 13:
    cmp_cards = gen_cards(6)

This replaces nearly 50 lines of code with 3 lines, plus a one-line function you can re-use elsewhere.

The same logic applies here, where you calculate the card values:

            # Calculate card values for each variable
            # Process card_num_one
            print(cmp_card_num_one, cmp_card_num_two)

            if 2 <= cmp_card_num_one <= 9:
                print("one")
                cmp_card_value_one = cmp_card_num_one
            elif cmp_card_num_one in (10, 11, 12, 13):
                cmp_card_value_one = 10
                print("two")
            elif cmp_card_num_one == 1:
                cmp_card_value_one = 1
                print("three")

            # Process card_num_two
            if 2 <= cmp_card_num_two <= 9:
                cmp_card_value_two = cmp_card_num_two
            elif cmp_card_num_two in (10, 11, 12, 13):
                cmp_card_value_two = 10
            elif cmp_card_num_two == 1:
               cmp_card_value_two = 1

            # Process card_num_three
            if 2 <= cmp_card_num_three <= 9:
                cmp_card_value_three = cmp_card_num_three
            elif cmp_card_num_three in (10, 11, 12, 13):
                cmp_card_value_three = 10
            elif cmp_card_num_three == 1:
                cmp_card_value_three = 1

            # Process card_num_four
            if 2 <= cmp_card_num_four <= 9:
                cmp_card_value_four = cmp_card_num_four
            elif cmp_card_num_four in (10, 11, 12, 13):
                cmp_card_value_four = 10
            elif cmp_card_num_four == 1:
                cmp_card_value_four = 1

            # Process card_num_five
            if 2 <= cmp_card_num_five <= 9:
                cmp_card_value_five = cmp_card_num_five
            elif cmp_card_num_five in (10, 11, 12, 13):
                cmp_card_value_five = 10
            elif cmp_card_num_five == 1:
                cmp_card_value_five = 1

            # Process card_num_six
            if 2 <= cmp_card_num_six <= 9:
                cmp_card_value_six = cmp_card_num_six
            elif cmp_card_num_six in (10, 11, 12, 13):
                cmp_card_value_six = 10
            elif cmp_card_num_six == 1:
                cmp_card_value_six = 1

Instead of copying and pasting your code 6 times, just stick it in a function:

def get_card_value(card_num):
    if 2 <= card_num<= 9:
        card_value = card_num
    elif card_num in (10, 11, 12, 13):
        card_value = 10
    elif card_num == 1:
        card value = 1
    return card_value

In fact, we can simplify this code further. For both the first and the third branch, the card number is used as its value, while only in the third branch is a different card value substituted. Therefore, we only need the second branch, simplifying the code to:

def get_card_value(card_num):
    if card_num in (10, 11, 12, 13):
        return 10
    return card_value

We could make this even simpler by using a ternery conditional and considering that 10 is also left unchanged:

def get_card_value(card_num):
    return 10 if card_num in {11, 12, 13} else card_num

In fact, since we observe that the only valid card values are 1 to 13, and that the only change in card values is capping cards above 10 to that value, we can rewrite this using min() to return the lesser of either the card number or 10:

def get_card_value(card_num):
    return min(card_num, 10)

Now, we need to call our function. Since we now have a list of card numbers, we can loop over it, call get_card_value on each one and store the result in a new list, rather than manually calling it six times:

cmp_card_values = []
for card_num, card_suit in cmp_cards:
    card_value = get_card_value(card_num)
    cmp_card_values.append(card_value)

Or better yet, we can again use a list comprehension like before:

cmp_card_values = [get_card_value(card_num) for card_num, card_suit in cmp_cards]

That’s another big win…we’ve replaced well over 50 lines of code with one line (or 50x shorter), plus a 1 line helper function that may be re-used elsewhere.

With just those three similar changes, using helper functions and loops over a list instead of copy/paste, plus a similar one for getting the card names, you can simplify your 123 line function down to a little more than a dozen lines, which is around a 10 to 1 improvement (and could further improve it with a little more work), which is far easier to read, write, debug, and make changes to.


  1. normally I’d suggest a dict instead of a tuple, but a tuple matches what you are already using, and dicts cannot be members of sets as they are mutable ↩︎

  2. _ or __ is convention for a throwaway variable ↩︎

Sorry, but I don’t see how any of that code actually accomplishes what the OP’s does, which is selecting unique cards from a deck without replacement. Furthermore, it is equally as verbose and repetitive as the OP’s with a high amount of duplication, and due to all that copy/pasting, appears to contain what appears to be copy/paste errors as both the 2 and 3 number cases only ask for 2 numbers, and 1 prints the unhelpful and confusing “Something went wrong”.

Normally, you’d never use input in this manner, and instead just pass howmany and the min and max to a function directly, i.e.:

def gen_randints(howmany, min_int, max_int):
    return [randint(min_int, max_int) for __ in range(howmany)]

card_nums = gen_randints(6, 1, 13)
card_suits = gen_randints(6, 1, 4)

However, if you wanted to replicate your functionality exactly, instead of a manually copy/pasted if check, simply loop over the input() calls howmany times:

def stay(howmany):
    try:
        for __ in range(howmany):
            print(randint(int(input("Minimum number: ")), int(input("Maximum number: "))))
    except:
        print("Something went wrong")

This reduces your >20 line function by 4x, to only 6 lines, while making it capable of handling any number of random numbers rather than only 1 to 4 in your original.

Additionally, your bare except will catch all exceptions, including KeyboardInterrupt, so the normal Ctrl-C will not work, and the only way users can escape the code is by typing exit (or by TERMing/killing the process), which you never tell them how to do. Always use, at minimum except Exception instead, or better yet a more specific exception, in this case ValueError. And when you do, actually give the user a useful error message, instead an unhelpful generic one. Therefore:

def stay(howmany):
    try:
        for __ in range(howmany):
            print(randint(int(input("Minimum number: ")), int(input("Maximum number: "))))
    except ValueError:
        print("Min and max must be integer numbers")

However, it would be better if the function allowed the user to retype the values for a single bad iteration, instead of simply erroring out in the middle of generating them. We can do that by moving the try/except inside a while loop around the input calls:

def stay(howmany):
    for __ in range(howmany):
        while True:
            try:
                print(randint(int(input("Minimum number: ")), int(input("Maximum number: "))))
                break
            except ValueError:
                print("Min and max must be integer numbers")