What I am trying to do is make a deck of cards, then move a specific card from the deck to a player's hand. I am having no trouble moving creating the deck and adding a card to a player's hand, but whenever I try to remove the card from the deck it tells me the card isn't in the deck to begin with, which does not make sense.
Here is the relevant code
class Card(object):
suit_names = ["Clubs", "Diamonds", "Hearts", "Spades"]
rank_names = [None, "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"] #so zero returns nothing, an Ace is 1 and so forth
def __init__(self, suit, rank): #initial method, just defines suit and rank so you can find it later
self.suit = suit
self.rank = rank
def getRank(self): #returns the rank of the card as an integer
return self.rank
def getSuit(self): #returns suit as an integer
return self.suit
def __str__(self):
return '%s of %s' % (Card.rank_names[self.rank], Card.suit_names[self.suit])
class Deck(object):
def __init__(self): #this is just creating a deck of cards, in standard order with the suits arranged alphabetically
self.cards = []
for suit in range(4):
for rank in range(1, 14):
card=Card(suit, rank)
self.cards.append(card) #what you should be ending up here is 52 objects from the "Card" class
def shuffle(self):
shuffle(self.cards)
def main():
selfHand=[]
s,r=eval(input("Input your first downcard's suit and rank, separated by a comma" ))
card=Card(s,r)
selfHand.append(card)
deck.cards.remove(card)
again, everything is working OK (I've omitted the irrelevant code, if anything looks a bit off--that is why there are big indents in the main function) but the last line prompts the error "ValueError: list.remove(x): x not in list"
To be clear, the deck should be a list of cards. I am trying to remove a specific card from the deck, that's it. Thought it would be simple but has eaten up a whole afternoon (to be fair, I am very new to python and coding in general)
I have tried countless different approaches at this point, with similar results.
Thanks for the help
The new card that you have created in main is not the same object as any of the cards in the array inside deck, even though it has the same suit and rank as one of those cards.
>>> c = Card(0,3)
>>> d = Card(0,3)
>>> c
<__main__.Card object at 0x0000000002025978>
>>> d
<__main__.Card object at 0x0000000002025908>
>>> c == d
False
You would need to override the equals and not equals methods in your Card class so it knows how to compare two Card instances.
def __eq__(self, other):
if isinstance(other, Card):
return self.suit == other.getSuit() and self.rank == other.getRank()
return NotImplemented
def __ne__(self, other):
if isinstance(other, Card):
return self.suit != other.getSuit() or self.rank != other.getRank()
return NotImplemented
Then you'll get your desired output of:
>>> c = Card(0,3)
>>> d = Card(0,3)
>>> e = Card(1,4)
>>> c == d
True
>>> c != d
False
>>> c == e
False
>>> c != e
True
>>> deck = Deck()
>>> len(deck.cards)
52
>>> deck.cards.remove(c)
>>> len(deck.cards)
51
The problem is that when you create card = Card(s,r), the Card(s,r) object isn't actually in the deck (hence the ValueError). I know it seems like it should be, but here's why it isn't:
Every time you create you create a new Card, the location of that card in memory will be different (i.e. they are different objects). You can see this like so:
card1 = Card(0, 2)
card2 = Card(0, 2)
assert not card1 is card2 # i.e. id(card1) != id(card2)
So, from Python's point of view, your newly created card isn't actually in the deck. To solve this, you need to at least override the __eq__ and __ne__ methods to have Python use what you think of as "equality" when comparing your Card objects:
def __eq__(self, other):
if isinstance(other, Card):
return self.suit == other.getSuit() and self.rank == other.getRank()
return NotImplemented
def __ne__(self, other):
return not self.__eq__(other)
But also, as mentioned in Python documentation, "The only required property is that objects which compare equal have the same hash value". This is to make sure your Card class would work as expected as items in hashable collections. So, it's a good idea to override the __hash__ method; perhaps, like so:
def __hash__(self):
return hash((self.suit, self.rank))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With