Regarding Games of Chance, High/Low Card Game

I’m attempting to remove the card drawn by the player from the deck of cards. Below is the code:

import random
def card_deck_less_draw():
    card_number = list(range(1,14))*4
    card_type = ['diamonds', 'clubs', 'hearts', 'spades']*13
    card_deck = list(zip(card_number, card_type))
    player_draw = []
    while len(player_draw) < 1:
        player_draw.append(random.choice(card_deck))
        card_deck.remove(player_draw)

When attempting to remove the card appended to player_draw, I receive the error:
ValueError: list.remove(x): x not in list

How can I remove the ‘drawn’ card from my deck of cards?

Hi @efry0559, and welcome to the Codecademy Forums!

You have a variety of options regarding how to organize this program. The choice you make may depend, in part, upon the context of the project, as well as what you have previously learned about Python.

Is this a Codecademy project or exercise? If so, please provide a link to the page that contains the instructions. If it is an assignment, please provide a detailed description of what you are being asked to do.

One option that is consistent with the code you have provided is to represent each card as a tuple, and the deck as a list of the tuples that correspond to the contained cards. If you pursue that route, a function such as the following could deal out a specified number of cards, and remove those cards from the deck:

def draw_cards(deck, number_of_cards):
  # deck: the deck of cards, as a list of tuples
  # number_of_cards: how many cards to draw
  drawn_cards = []
  for i in range(number_of_cards):
    card_index = random.randint(0, len(deck) - 1)
    drawn_cards.append(deck[card_index])
    del(deck[card_index])
  return deck, drawn_cards

Note that in the above, we save an index of each card as we draw it. That index enables us to remove the card from the deck.

If you have learned about Python classes, you could define a class to represent a card, and one or more additional classes to represent a deck, a hand, and a game.

1 Like

This is a logical error in your code. I encourage you to think about it yourself.

First of all, Python tells you the problem - it was trying to find x to remove from list but could not find x.
Now read your code.

player_draw.append(random.choice(card_deck))

What is this line of code doing? We pick a random item from card_deck and add it to player_draw.
Let’s move on to the next line, the one causing the error (you can tell from Python’s very nice error message).

card_deck.remove(player_draw)

Now, we remove player_draw from card_deck. Does this look right to you?

To make sure that this was the only thing causing errors, I modified a bit of your code and it worked perfectly fine. :slight_smile:


Additional note: I’m not sure what you’re trying to achieve with the while loop there. Is it a good way to implement what you want the program to do? I don’t know the rest of your code so I wouldn’t know.

Thanks for the response. This is a Python project, here’s the [link], and the task is # 5 on the list.(https://www.codecademy.com/practice/projects/games-of-chance)

it’s good to know that del is an option for removing objects from lists, and I like that the code can be applied to any # of card draws based on the deck size. I have not gotten to classes yet, so I’m not sure how that option works.

@byteblitz I’m still not sure what the issue is. player_draw should be a list of 1 random tuple pulled from within the card_deck list, right? so in my mind I should then be able to use player_draw to modify the original card_deck. are you saying that it’s trying to remove the actual value “player_draw” from the card_deck list?

Yep, that’s exactly it.

It is not trying to remove a string called “player_draw”. It’s trying to remove the value of player_draw, which you stated yourself.

Tell me when you figure out how to fix the error. :slight_smile:

In case you still need help...

['hello'] != 'hello'
That should push you in the right direction.

Oh, I see. card_deck.remove() only removes a single item from a list, so I needed to include the index value (that appylpye did with the use of a variable, and not a fixed input) of the item to remove.

The updated code should be card_deck.remove(player_draw[0])

Thank you!

Exactly it. None of the items in the card deck are lists, so Python couldn’t find what you were trying to remove.

Now you have no more syntax errors. Since I’ve never done the project, I don’t know if other parts of your code should be modified or optimized, but good luck on the project.

You’re welcome.

One slight problem with your solution. The new values are appended to the list. You want to remove the last card appended not the same first value each time.
For example:

a = [1,2,3,4,5]
b = []

for n in a:
    b.append(n)
    a.remove(b[0])
    print(b)
    print(a)

Output:

[1]
[2, 3, 4, 5]
ValueError: list.remove(x): x not in list

If you are only ever going to draw 1 card, it’s not an issue, but if you want to draw multiple cards, you want to remove the last card drawn with each iteration. If you only want to draw one card, there’s no need to remove the card from the deck, or to have the while loop, or to have player_draw be a list.

player_draw is set to an empty list each time the function is called, though. If the player_draw list was to keep a record of every single card drawn, that’d be true, but it doesn’t seem to be the case here. You could go on to argue that it’s pointless to have a list if it’s always one item, but then you’d have to ask efry0559 what he wants to achieve with the code.

You probably have a valid point, though - I don’t know the goals of the project, but you might have read them.

It would seem from the code that the objective is to have the player draw multiple cards.

In that case, there are some remaining problems with the code.
Like you said, if the while loop stopping condition is the length of the draw being 1 or greater, then it’s pointless, player_draw shouldn’t be a list (I’d say it should just be a tuple). I’d also think that player_draw shouldn’t be defined in the function.

Hi midlindner, so I can tell you there are only two card draws. one made by the ‘player’ and one draw by the ‘house’, so I call it. The deck will always be a full deck of cards, so the odds of winning will always be 50%.

That being said, I appreciate the advice. I know hard-coding the index is rarely the best solution, but I’m just trying to get a working solution at this point and optimize as I go. When I learn how to unpack my tuples, I’ll provide the entire finished function if anyone would care to see the final result.

1 Like

Another option is to use the list.pop() method. The following is another version of the function that exemplifies that technique:

def draw_cards(deck, number_of_cards):
  drawn_cards = []
  for i in range(number_of_cards):
    drawn_cards.append(deck.pop(random.randint(0, len(deck) - 1)))
  return deck, drawn_cards

See More on Lists.

If you are a fan of list comprehensions, consider this:

def draw_cards(deck, number_of_cards):
  return deck, [deck.pop(random.randint(0, len(deck) - 1)) for i in range(number_of_cards)]

The function returns a tuple consisting of deck and the result of the list comprehension. It is worth noting that even though deck appears first in the tuple, and that the list to which deck refers is modified by the list comprehension that is the second item in the tuple, the deck that is returned refers to the modified list, with the drawn cards having been removed during execution of that list comprehension.

1 Like

So many variations to learn, thank you!

@midlindner, @byteblitz, @appylpye

Here is my finished code for the game, thank you for all of your input :slight_smile:

import random
money = 100

#High/Low Card Game
hi = "high"
lo = "low"

def high_low(bet, hi_or_lo, number_of_games):
    global money
    card_number = list(range(1,14))*4
    card_type = ['diamonds', 'clubs', 'hearts', 'spades']*13
    for game in range(number_of_games):
        while money >= bet and game < number_of_games:
            card_deck = list(zip(card_number, card_type))
            player_draw = []
            player_draw.append(random.choice(card_deck))
            card_deck.remove(player_draw[0])
            house_draw = [random.choice(card_deck)]
            if (player_draw[0] > house_draw[0] and hi_or_lo == hi) or (player_draw[0] < house_draw[0] and hi_or_lo == lo):
                money += bet
                print("Winner is {}, Congratulations! You won ${}, drawing a {} of {} against the House draw, {} of {}. You're new total is ${}.".format(hi_or_lo, bet, *player_draw[0], *house_draw[0], money))
                game += 1
            elif (player_draw[0] < house_draw[0] and hi_or_lo == hi) or (player_draw[0] > house_draw[0] and hi_or_lo == lo):
                money -= bet
                print("The result is not {}, I'm sorry. You lost ${}, drawing a {} of {} against the House draw, {} of {}. You're new total is ${}.".format(hi_or_lo, bet, *player_draw[0], *house_draw[0], money))
                game += 1
            elif player_draw[0] == house_draw[0]:
                print("The result is a tie, with your draw, {} of {}, and the house draw, {} of {}. Your total is unchanged, at ${}.".format( *player_draw[0], *house_draw[0], money))
                game += 1
        if game == number_of_games:
            return "Thanks for playing!"
        else:    
            return "You do not have enough money to cover your bet. Thanks for playing!"

#Call your game of chance functions here

print(high_low(50, hi, 5))

The issue is that you are trying to remove a tuple from the list, but random.choice returns a tuple, not the actual list element.

To fix it, you need to find the index of the drawn card in the deck and remove it by index:

import random

def card_deck_less_draw():
    card_deck = list(zip(list(range(1,14))*4, ['diamonds', 'clubs', 'hearts', 'spades']*13))
    player_draw = []
    
    while len(player_draw) < 1:
        drawn_card = random.choice(card_deck)
        player_draw.append(drawn_card)
        
        card_index = card_deck.index(drawn_card)
        card_deck.pop(card_index)
        
card_deck_less_draw()

The key changes:

  • Save the drawn card tuple from random.choice()
  • Use list.index() to get the index of the drawn card
  • Remove the card from the deck by index using list.pop()

Now it will properly remove the drawn card from the deck without errors.

credit : Getting over it get free download