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 2 years ago.
Improve this question
I am trying to make a war card game in python that improves on an example in a book called the Self Taught Programmer. In my version I want to follow the rules found on the bicycle cards website. To get back to my problem I wrote two classes Stack and a Deck class inheriting Stack.
Decks init populates the empty list variable cards from the base class with all 52 cards in a deck and shuffles them. I go to test the classes in IDLE and find out when I create objects of Stack it seems like the init from Deck gets called and populates the card variable in the parent class when no subclass object gets created. How is this? From my understanding parent classes don't see child classes.
from random import shuffle
class Card:
suits = ["Clubs", "Spades", "Diamonds", "Hearts"]
values = [None, None, "2", "3", "4", "5", "6",
"7", "8", "9", "10", "Jack", "Queen", "King", "Ace"]
def __init__(self, v, s):
self.value = self.values[v]
self.suit = self.suits[s]
def __repr__(self):
return self.value + " of " \
+ self.suit
def __lt__(self, c2):
if self.value < c2.value:
return True
if self.value == c2.value:
if self.suit < c2.suit:
return False
return False
def __gt__(self, c2):
if self.value > c2.value:
return True
if self.value == c2.value:
if self.suit > c2.suit:
return False
return False
def __eq__(self, c2):
if self.value == c2.value:
return True
else:
return False
class Stack:
cards = []
def add(self, card):
self.cards.append(card)
def addToBottom(self, card):
self.cards.insert(0, card)
def removeCard(self):
return self.cards.pop()
def __repr__(self):
idx = len(self.cards) - 1
return self.cards[idx]
class Deck (Stack):
def __init__(self):
for i in range(2, 15):
for j in range(0, 4):
self.cards.append(Card(i, j))
shuffle(self.cards)
It's because you have cards as a class attribute. If you create a Deck first, then a Stack, the creation of the deck populates the Stack.cards attribute that everyone shares.
You need to make cards an instance attribute:
class Stack:
def __init__(self):
self.cards = []
. . .
Related
I'm building a deck of cards that has shuffling function. I'm using random.shuffle, but it is not shuffling at all. When I run the following codes, the whole deck is printed out in good order. Please have a look, thanks!
import random
class Card(object):
def __init__(self, suit, value):
self.suit = suit
self.value = value
def show(self):
print("{} of {}".format(self.value, self.suit))
return self.value
class Deck(object):
def __init__(self):
self.cards = []
self.build()
def build(self):
for s in ["Spades", "Clubs", "Diamonds", "Hearts"]:
for v in range(1, 14):
self.cards.append(Card(s, v))
print("{} of {}". format(v, s))
def show(self):
for cards in self.cards:
print(cards.show())
def shuffle(self):
random.shuffle(self.cards)
return self.cards
def draw_card(self):
return self.cards.pop()
deck = Deck()
deck.shuffle()
I just tried your code, the console output messages you are seeing in good order are created from the self.build() function, if you call deck.show() at the end, you will see the shuffled messages.
deck = Deck()
deck.shuffle()
deck.show()
This question already has answers here:
How to print instances of a class using print()?
(12 answers)
Closed 2 years ago.
Python prints memory location instead of list.
My code:
import random
class Card:
def __init__(self, value, suit):
self.value = value
self.suit = suit
def show_card(self):
print(self.value, self.suit)
def get_value(self):
if self.value > 10:
return 10
return int(self.value)
class Deck:
def __init__(self):
self.cards = []
self.build()
def build(self):
for suit in ["♣", "♦", "♥", "♠"]:
for value in range(2, 15):
self.cards.append(Card(suit, value))
return self.cards
def shuffle_deck(self):
random.shuffle(self.cards)
return self.cards
Deck().build()
deck = Deck().shuffle_deck()
print(deck)
The problem is when I append "Card" object to "cards" list.
How could I print "cards" list elements instead of memory locations?
It could be achieved through __repr__ magic method. Add this method:
def __repr__(self):
return f'{self.value} {self.suit}'
into your Card class.
Just add a repr function to the card class
class Card:
# your implementation
def __repr__(self):
return f'({self.value},{self.suit})'
Is it possible to set a property with shorthand operators like +=, or -=?
I've read this post, What's the pythonic way to use getters and setters?, but it deals mainly with direct assignment in terms of object.attr = value. When thinking about it, I'm finding it difficult to be possible and I've never used setters so I'm not sure.
It is within the Player.hit() method where I'm attempting to achieve this where I'm subtracting and integer reduced_points from another integer value property:
self.hands[x].value -= reduced_points
NOTE: Hand.value is an #property due to that I need to dynamically add the values of each card in case a card is added to that hand.
class Card:
def __init__(self, pip, suit, *args, **kwargs):
self.pip = pip
self.suit = suit
if kwargs and 'face_card' in kwargs:
self.face_card = kwargs['face_card']
class Hand:
def __init__(self, cards):
self.cards = cards # [Card(), Card(), Card()]
self._value = sum(card.pip for card in cards)
#property
def soft(self):
return any(
hasattr(card, 'face_card') and
card.face_card == "Ace" for card in self.cards
)
#property
def value(self):
return sum([card.pip for card in self.cards])
#value.setter
def set_value(self, value):
new_value = self._value - value
self._value = new_value
class Player:
def __init__(self):
self.name = "Player"
self.hands = []
self.chips = 0
self._bet = 0
def hit(self, hand):
if hand.soft:
x, hand = list(filter(
lambda h: h[1].soft, enumerate(self.hands)
))[0]
total_aces = len(
list(
filter(lambda c: hasattr(c, 'face_card') and
c.face_card == "Ace", self.hands[x].cards)
)
)
reduced_points = 10 * (total_aces - 1)
self.hands[x].value -= reduced_points
if self.hands[x].value > 21:
return self.hands[x], "BUST"
if hand.value > 21:
return hand , "BUST"
return hand, "HIT"
When creating a property setter, it needs to have the same name as the getter. So both the getter and setter needed to be def value(...). But yes, hand.value -= 3 should do exactly what you expect it to.
I would like to repeat a class method several times (26 to be exact) so that I can split a deck of cards to two separate decks. I tried [:26] and [26:] (obviously for lists only) in addition to d1=Deck() then deck1 = d1.deal()*26 and they both did not work. I just learned how to create Classes.
Desired output is deck1=["""26 random cards"""] and deck2=["""26 random cards"""].
Relevant code:
import random
suits = ['H','C','S','D']
ranks = ['A']+list(map(str,range(2,10)))+['X','J','Q','K']
values = [14]+list(range(2,14))
class Card:
def __init__(self,suit,rank):
self.suit=suit
self.rank=rank
self.value=values[ranks.index(self.rank)]
def __str__(self):
return "*------*\n|{0}{1} |\n| |\n| {0}{1}|\n*------*".format(self.rank,self.suit)
def __gt__(self,other):
return self.value > other.value
def __lt__(self,other):
return self.value < other.value
def __eq__(self,other):
return self.value == other.value
class Deck:
"""This class is for creating deck"""
def __init__(self):
self.deck=[]
for suit in suits:
for rank in ranks:
self.deck.append(Card(suit,rank))
self.shuffle()
def __str__ (self):
tmp=''
for card in self.deck:
tmp+=str(card)+'\n'
return tmp
def shuffle(self):
random.shuffle(self.deck)
def deal(self):
return self.deck.pop()
So the order of operations is going to execute your function once, then repeat the result 26 times. You probably want something more like:
deck1 = [d1.deal() for _ in range(26)]
Whenever you want to repeat an action a certain number of times, use a for loop.
d2 = []
for i in range(26):
d2.append(d1.deal())
There's no way for your code at the moment to create an empty deck. Maybe you should have a __init__ that creates an empty deck and then a separate method to make a full deck? Just a thought.
I have created a carddeck and every player is assigned a hand. I would like the players to be able to arrange their hand with the lowest value first and then print out this hand. I would like to think this can be done with .sort() but atm I'm getting a message
TypeError: unorderable types: NumberedCard() < NumberedCard()
I got a tip from the net that if I defined how .sort() is to work through a correct def __lt__(self, other): then I wouldn't be having this problem. So help me programmers figure this one out. Every card is defined by value and suit.
My code looks like this:
import random
suitlist=["Hearts","Spades","Clubs","Diamonds"]
class NumberedCard():
def __init__(self,value,suit):
self.value=value
self.suit=suit
def __str__(self):
return '%s of %s' %(self.value,suitlist[self.suit])
class JackCard():
def __init__(self,suit):
self.suit=suit
self.value=11
def __str__(self):
return 'Jack of %s' %(suitlist[self.suit])
class QueenCard():
def __init__(self,suit):
self.suit=suit
self.value=12
def __str__(self):
return 'Queen of %s' %(suitlist[self.suit])
class KingCard():
def __init__(self,suit):
self.suit=suit
self.value=13
def __str__(self):
return 'King of %s' %(suitlist[self.suit])
class AceCard():
def __init__(self,suit):
self.suit=suit
self.value=14
def __str__(self):
return 'Ace of %s' %(suitlist[self.suit])
class StandardDeck():
"""A class that creates a deck of 52 different cards, that also gives options to do matching operations with them"""
def __init__(self):
self.deck = []
for suit in range(4):
for value in range(2,11):
card = NumberedCard(value,suit)
self.deck.append(card)
self.deck.append(JackCard(suit))
self.deck.append(QueenCard(suit))
self.deck.append(KingCard(suit))
self.deck.append(AceCard(suit))
#for k in range(52):
# print(self.deck[k])
def shuffle(self):
"""Shake n' bake with the cards."""
random.shuffle(self.deck)
def take_card(self):
return self.deck.pop()
def deal_cards(self, hand,num):
for i in range(num):
hand.add_card(self.take_card())
class Hand:
"""A class to do the usual poker things during the game. Ie pick up cards, drop cards etc."""
def __init__(self):
self.hand = []
def __str__(self):
Handen=""
for card in self.hand:
Handen+=str(card) + "\n"
return Handen
def add_card(self,card):
self.hand.append(card)
def sort_cards(self):
self.hand.sort()
####Testing the program
deck=StandardDeck()
deck.shuffle()
hand=Hand()
hand.add_card(deck.take_card())
hand.add_card(deck.take_card())
print(hand)
hand.sort_cards() # <---- This is the part not working
So how is it done and where should it be put?
The best way to salvage this would be to create a class Card which would have a value and the __lt__ or __gt__ and a __eq__ defined method. And then proliferate those method by having all the other cards inherit from that parent class.
The proposed methods could be as simple as just compairing values of value which is an int and python knows how to do it himself.
Something like this:
>>> class Card(object):
def __init__(self, value):
self.value = value
def __lt__(self, other):
if other.value > self.value:
return True
return False
>>> class Ace(Card):
def __init__(self, value):
super().__init__(value)
>>> class NumCard(Card):
def __init(self, value):
super().__init__(value)
>>> jack = Ace(12)
>>> n = NumCard(7)
>>> jack > n
True
>>> n > jack
False
If you only want to sort the list in self.hand why not just use the key argument for sort to create a function to return the value to sort on?
self.hand.sort(key=lambda x: x.value)
This link should provide some info on sorting techniques