I basically have 3 classes. Card, Deck, and Player. The Deck is a list of cards. I am trying to remove a card from the deck. But I am getting a ValueError saying that the card is not in the list. From my understanding, it is and I am passing the correct object through the removeCard function. I am not sure why I am getting a ValueError. So in short, the problem is that I need to remove an object (Card) from a list of Cards.
My issue is that when I try to remove a card from the deck I get an error like this:
ValueError: list.remove(x): x not in list
This is what I have so far:
Card class:
import random
class Card(object):
def __init__(self, number):
self.number = number
Deck class (the error is thrown here, in the removeCard function):
class Deck(object):
def __init__(self):
self.cards = []
for i in range(11):
for j in range(i):
self.cards.append(Card(i))
def addCard(self, card):
self.cards.append(card)
def removeCard(self, card):
self.cards.remove(card)
def showCards(self):
return ''.join((str(x.number) + " ") for x in self.cards)
Player class:
class Player(object):
def __init__(self, name, hand):
self.name = name
self.hand = hand
main function:
def main():
deck = Deck()
handA = [Card(6), Card(5), Card(3)]
handB = [Card(10), Card(6), Card(5)]
playerA = Player("A", handA)
playerB = Player("B", handB)
print("There are " + str(len(deck.cards)) + " cards in the deck.")
print("The deck contains " + deck.showCards())
for i in handA:
deck.removeCard(i)
print("Now the deck contains " + deck.showCards())
main()
When you call list.remove, the function searches for the item in the list, and deletes it if found. When searching, it needs to perform a comparison, comparing the search item to every other list item.
You're passing an object to remove. A user defined object. They do not behave the same way as, say, integers would, when performing comparisons.
For example, object1 == object2, where object* are objects of the Card class, by default are compared against their unique id values. Meanwhile, you want a comparison to be performed against the card number, and removal done accordingly.
Implement an __eq__ method in your class (python-3.x) -
class Card(object):
def __init__(self, number):
self.number = number
def __eq__(self, other):
return self.number == other.number
Now,
len(deck.cards)
55
for i in handA:
deck.removeCard(i)
len(deck.cards)
52
Works as expected. Note that in python-2.x, you'd implement __cmp__ instead.
Related
'''
I am trying to figure out how to do the str method on my Deck and Player class. I can print an individual instance of my Card class, but that is it. Once I start trying to print my deck, I get an error code telling me that the list index is out of range. I know I am making a noob mistake somewhere and just don't realize it. If I can get these methods done, I can go ahead and code the game. I will put up all the code necessary to help if someone is up to it. Also need a str method for showing a player's hand too I guess. Here is the error code:
Traceback (most recent call last):
File "c:\Users\kille\OneDrive\Desktop\HW9\revised_classes.py", line 139, in
print(deck)
File "c:\Users\kille\OneDrive\Desktop\HW9\revised_classes.py", line 67, in str
vis.append(str(card))
File "c:\Users\kille\OneDrive\Desktop\HW9\revised_classes.py", line 16, in str
return f"{Card.values[self.value]}{Card.suits[self.suit]}"
IndexError: list index out of range
'''
class Card:
#This class represents a playing card.
suits = ['\u2666', '\u2665', '\u2663', '\u2660']
values = ['2', '3', '4', '5', '6', '7', '8', '9'
'10', 'J', 'Q', 'K', 'A']
def __init__(self, value, suit):
#Initialize attributes of card class.
self.value = value
self.suit = suit
# This works, but if it can be done better I am up for suggestions
def __str__(self):
#Returns a card
return f"{Card.values[self.value]}{Card.suits[self.suit]}"
def __repr__(self):
#Learning about this one
return f"{Card.values[self.value]}{Card.suits[self.suit]}"
def __eq__(self, card2):
#equal operator, compares the values of the cards
if self.value == card2.value:
return self.value == card2.value
else:
return False
def get_value(self):
#This function returns the value of a card
value = self.value
return print(value)
def get_suit(self):
#This function returns the suit of a card
return print(self.suit)
def same_value(self, card):
#This function checks to see if two cards have the same value.
if self.value == card.value:
return True
else:
return False
def same_suit(self, card):
#This function checks to see if two cards have the same suit.
if self.suit == card.suit:
return True
else:
return False
class Deck:
#This class represents a deck of playing cards.
def __init__(self):
#Initialize attributes for the Deck class
self.deck = []
for suit in range(4):
for value in range(13):
self.deck.append(Card(value, suit))
self.shuffle_deck()
#This is where I need to print the deck, but haven't figured it out yet
def __str__(self):
#This function returns a string representation of the deck.
vis = []
for card in self.deck:
vis.append(str(card))
return vis
def __len__(self):
#This function returns the length of the deck
return len(self.deck)
def add_card(self, card):
#This function adds a card to the deck
self.deck.append(card)
def shuffle_deck(self):
#This function shuffles the deck of playing cards
random.shuffle(self.deck)
def draw_card(self):
#This function allows you to draw a card from the deck
drawn_card = self.deck.pop()
print(drawn_card)
return drawn_card
def gt_rd_card(self):
#This function gets a random card from the deck
return random.choice(self.deck)
class Player(Deck):
#This class represents a player in a game and inherits from the Deck class
def __init__(self, name):
#Initialize attributes of the Player(Deck) class
self.name = name
self.wins = 0
self.pairs = []
self.hand = []
deck = Deck()
#This is where I need to figure out how to print a player's hand
def __str__(self):
#This allows me to print
return self.name + ': ' + ' '.join([str(card) for card in self.deck])
def get_name(self):
#This function returns the name of the player
return self.name
def get_wins(self):
#This function allows me to get the wins
return self.wins
def draw_card(self):
#This function allows a player to draw a card
self.hand.append(deck.draw_card)
return self.hand
# I also need to set up deal_hand(which will be 7 cards) and figure out how to print that
The problem lies in the assignment of Card.values: there is no , separation between '9' and '10', resulting in the merging of the two strings into '910', so the actual value list is shorter than you think.
In fact, it's easy to find this problem, you just need to traverse the Deck.deck and print the card, and you'll find 910♦ existence.
For method Deck.__ str__, a simpler implementation is to return str(self.deck) or repr(self.deck)
I'm currently trying to implement selection sort into a hand of cards when cards are added. This is my current code. I understand how selection sort is supposed to work and was just looking for advice on how to start to implement it into my add function.
Hand class
class newHand(object):
def __init__(self, label = ""):
"""
create an empty collection of cards with the given label
"""
self.label = label
self.cards = []
def add(self, card):
"""
# Implements selection sort
pre: card is a Card
post: appended the card to the hand and sorts the deck
"""
self.cards.append(card)
def sort(self):
"""
post: arrange the cards in decending order
"""
cards0 = self.cards
cards1 = []
while len(cards0) > 0:
card = max(cards0)
cards0.remove(card)
cards1.append(card)
self.cards = cards1
def dump(self):
"""
post: outputs the contents in the hand
"""
print(self.label + "'s Cards: ")
for card in self.cards:
print("\t", card)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm trying to sort through a list "cards" in a player's hand, and create a new list of "cards" containing only those cards which are spades:
class Card(object):
def __init__(self, value, suit):
self.value = value
self.suit = suit
class Player(object):
def __init__(self, hand):
self.hand = hand # hand is a list of 13 card objects
def spades(self):
spades = []
for card in self.hand:
if card.suit == 'spade':
spades.append(copy.deepcopy(card))
return spades
however, calling the spades() method outputs a list of cards of the same number and value of the last card in the hand, and the same length of the amount of spades. for instance:
players = deal()
for card in players[1].hand:
print(str(card.value) + ' of ' + card.suit)
print("SPADES")
spades = players[1].spades()
for cards in spades:
print(str(card.value) + 'of' + card.suit)
outputs:
6ofclub
13ofheart
4ofdiamond
7ofspade
13ofdiamond
13ofclub
11ofspade
8ofdiamond
3ofdiamond
10ofheart
8ofheart
12ofclub
12ofdiamond
SPADES
12ofdiamond
12ofdiamond
I think realize that the list "spades" is appending pointers to the variable "card", rather than new objects. However I thought that using copy or deep copy would have solved this issue.
From what I see, there is no problem in the code. The issue is with the print at the end...
You've written:
for cards in spades:
print(str(card.value) + 'of' + card.suit)
So you're looping and getting cards but you're printing card which is from the previous for loop which is still assigned the variable from the last for loop's last iteration
Here's the entire code to reproduce the fix:
import copy
class Card(object):
def __init__(self, value, suit):
self.value = value
self.suit = suit
def __str__(self):
return str(self.value) + " of " + str(self.suit)
class Player(object):
def __init__(self, hand):
self.hand = hand # hand is a list of 13 card objects
def spades(self):
spades = []
for card in self.hand:
if card.suit == 'spade':
spades.append(copy.deepcopy(card))
return spades
vals = [i.split("of", 1) for i in """6ofclub
13ofheart
4ofdiamond
7ofspade
13ofdiamond
13ofclub
11ofspade
8ofdiamond
3ofdiamond
10ofheart
8ofheart
12ofclub
12ofdiamond""".strip().split()]
hand = [Card(i[0], i[1]) for i in vals]
players = [None, Player(hand)]
for card in players[1].hand:
print(card)
print()
spades = players[1].spades()
print("SPADES")
for cards in spades:
print(cards) # <----- Print card*s* not card.
Found a solution by changing the spades() method but not entirely sure why it worked:
def spades(self):
spades = []
for card in self.hand:
if card.suit == 'spade':
copy = deepcopy(card)
spades.append(copy)
return spades
I assigned the deep copy to a variable first, then passed the variable through append(). This seems like a trivial change to me...if anyone has an explanation of this behavior it would be much appreciated.
I programmed a class aswell as a definition with the backthought the when you,
set everytime a value using class variable you can always recall the total amount by using the definition
class Hand():
def __init__(self, Hand=0):
self.Hand = Hand
def getHand(self, neue_Hand):
self.Hand = neue_Hand
def set_hand(self):
return self.Hand
c = Hand()
def Aufruf():
Total = 0
Total += c.getHand(0)
return Total
c.getHand(12)
Aufruf()
It changes the value each time, but doesn't accumulate it as it supposed to be.
You've mixed up the functionality in your getters and setters. The getter should return the variable and the setter should set the value.
class Hand():
def __init__(self,Hand=0):
self.Hand = Hand
def getHand(self):
return self.Hand
def set_hand(self, neue_Hand):
self.Hand = neue_Hand
def increment_hand(self, neue_Hand_incremenet):
self.Hand += neue_Hand_incremenet
c = Hand(10)
c.getHand()
>> 10
c.set_hand(20)
c.getHand()
>> 20
def Aufruf():
Total = 0
Total += c.getHand()
return Total
Aufruf()
>> 20
c.increment_hand(10)
Aufruf()
>> 30
Also as a side note:
If you look closely, you will realise your method Aufruf is actually an exact duplicate (logically) of the getHand() method. When you instantiate the variable total = 0 inside the method block of code, this value will ALWAYS be set to 0 when the method is called, meaning the value from c.getHand() will ALWAYS just be the value that's returned
Use method addition for changing value, and don't use capital letters or camelCase inside your class.
class Hand:
def __init__(self, 0):
self.hand = hand
def get_hand_bigger(self, addition):
self.hand += addition
Your class method getHand does not return any value, yet it is being called as such. Try this:
def getHand(self, neue_Hand):
self.Hand = neue_Hand
return self.Hand
class Card:
allRanks=(2,3,4,5,6,7,8,9,10,11,12,13,14)
allSuits=('Spades','Hearts','Diamonds','Clubs')
def __init__(self, rank, suit):
self.rank=rank
self.suit=suit.capitalize()
def getRank(self):
if self.rank in Card.allRanks:
return self.rank
else:
print 'Please enter a number from 2 to 14\n14 => ACE\n11 => JACK\n12 => QUEEN\n13 => KING\n'
exit()
def getSuit(self):
if self.suit in Card.allSuits:
return self.suit
else:
print 'There are only 4 suits in a pack!'
exit()
def __str__(self):
translate={11:'Jack',12:'Queen',13:'King',14:'Ace'}
r = self.rank
if r in range(11,15):
myrank=translate[r]
elif r in range(2,11):
myrank=str(r)
else:
print "Sorry wrong card"
exit()
return myrank+' of '+self.suit
def __lt__(self,other):
return (self.rank > other.getRank())
#c=Card(1,'spades')
class Deck:
def __init__(self):
self.deck=[Card(i,j) for i in Card.allRanks for j in Card.allSuits]
#for i in Card.allRanks:
# for j in Card.allSuits:
# self.deck.append(Card(i,j))
def shuffle(self):
from random import shuffle
class Dealer(object):
def __init__(self, deck, cards, num_players):
self.deck=deck
self.num_players=num_players
self.cards=cards
def deal(self):
self.deck.shuffle()
deal_list=[[] for i in range(self.num_players)] #returns a list of lists
#say you have 4 players you will have [[hand1],[hand2],[hand3],[hand4]] where hand1=[5 cards]
#now you pass this to the hand variable
for i in range(self.cards):
for j in range(self.num_players):
deal_list[j].append(self.deck.topCard())
return deal_list
class Dealer_better(object):
def __init__(self, deck, cards, *args):
self.deck=deck
self.cards=cards
def deal(self):
self.deck.shuffle()
deal_list=[[] for i in range(len(*args))] #returns a list of lists
#say you have 4 players you will have [[hand1],[hand2],[hand3],[hand4]] where hand1=[5 cards]
#now you pass this to the hand variable
for i in range(self.cards):
for j in (*args):
j.append(self.deck.topCard())
class Player(object):
def __init__(self, hand=[]):
self.hand=hand
Hi I have classes Dealer and Dealer_better. It accepts objects from Deck() and has to deal cards to n number of players.
In class Dealer I pass the number of players that I need to deal the cards to directly as a variable and generate a list of lists where the hand of each player is a list.
I would like to make this better in Deal_better and pass the player objects directly to Deal_better after initializing multiple instances of Class Player. Is there a way to pass *player_objects similar to *args.
So that I can get the following functionality,
p1=Player()
p2=Player()
p3=Player()
p4=Player()
new_d=Dealer_better(Deck(),p1.hand,p2.hand,p3.hand,p4.hand)
new_d.deal()
print p1.hand should give me player one's hand, or atleast the objects in it.
I could write an add_card method in player to append to self.hand if need be.
pasting the classes in question below for clarity.
class Dealer(object):
def __init__(self, deck, cards, num_players):
self.deck=deck
self.num_players=num_players
self.cards=cards
def deal(self):
self.deck.shuffle()
deal_list=[[] for i in range(self.num_players)] #returns a list of lists
#say you have 4 players you will have [[hand1],[hand2],[hand3],[hand4]] where hand1=[5 cards]
#now you pass this to the hand variable
for i in range(self.cards):
for j in range(self.num_players):
deal_list[j].append(self.deck.topCard())
return deal_list
versus
class Dealer_better(object):
def __init__(self, deck,cards, *players):
self.deck=deck
self.cards=cards
self.players = players
def deal(self):
self.deck.shuffle()
for i in range(self.cards):
for p in range(len(self.players)):
self.players[p].addCard(self.deck.topCard())
print self.players[p].name,len(self.players[p].hand)
class Player(object):
def __init__(self, name, hand=[]):
self.hand=hand
self.name=name
def addCard(self,card):
self.hand.append(card)
Returns
p1=Player('Bob')
p2=Player('Lola')
p3=Player('Luigi')
p4=Player('Mario')
new_d=Dealer_better(Deck(),5,p1,p2,p3,p4)
new_d.deal()
print len(p1.hand)
Returns 20
How about something along the lines of:
class player(object):
def __init__(self):
self.d = []
class dealer(object):
def __init__(self, *decks): #feel free to add more stuff this is just an example :)
self.decks = [d for d in decks]
def deal(self):
for d in self.decks:
d.append(1) # just an example
d.append(2)
p1 = player()
p2 = player()
p3 = player()
d = dealer(p1.d,p2.d,p3.d)
d.deal()
print p1.d # was changed by deal
(demo)