Python Simple Card Game to Learn Classes
This is more of a code/approach review. A card game is a case for composition, not inheritance; the Deck
contains Card
s, but isn't in itself a type of Card
, and vice versa.
I think you are duplicating information in the Card
. Just store suit and rank, and use __str__
to create 'x of y'
. You can also implement the rich comparison methods:
class Card(object):
FACES = {11: 'Jack', 12: 'Queen', 13: 'King', 14: 'Ace'}
def __init__(self, rank, suit):
self.suit = suit
self.rank = rank
def __str__(self):
value = self.FACES.get(self.rank, self.rank)
return "{0} of {1}".format(value, self.suit)
def __lt__(self, other):
return self.rank < other.rank
Now e.g. str(Card(13, 'Clubs')) == "King of Clubs"
. This way you don't duplicate the rank
and value
in card
.
Next, I think the Deck
should incorporate the population generation in __init__
; you can provide optional arguments for a non-standard deck. I have included two implementations; the commented-out version is a list comprehension using itertools
to do the same job in one line. I also provide a function to pick n
different random cards from self.deck
.
from itertools import product
import random
class Deck(object):
def __init__(self, ranks=None, suits=None):
if ranks is None:
ranks = range(2, 15)
if suits is None:
suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
## self.deck = [Card(r, s) for r, s in product(ranks, suits)]
self.deck = []
for r in ranks:
for s in suits:
self.deck.append(Card(r, s))
def deal(self, n):
return random.sample(self.deck, n)
Now the game is simple; you can deal three cards per hand, and compare the cards naturally (using e.g. <
) because of the comparison methods.
deck = Deck()
hand = deck.deal(3)
print(" - ".join(map(str, hand)))
if min(hand[0], hand[1]) < hand[2] < max(hand[0], hand[1]):
print("Winner!")
else:
print("Loser.")
pez
Updated on July 11, 2021Comments
-
pez almost 3 years
I am trying to create a simple card game to better understand OOP and classes.
The game is as follows: Two cards are dealt from a deck. Then a third card is dealt. If the third card is between the first two cards, then the player wins. If the third card is equal to either of the first two cards, or is outside of the set, then the player loses.
This is what I have so far:
class Deck(object): def __init__(self): self.deck = [] def PopulateDeck(self): suits = ["Hearts", "Diamonds", "Clubs", "Spades"] for suit in suits: for rank in range(2, 15): if rank == 11: value = "Jack" elif rank == 12: value = "Queen" elif rank == 13: value = "King" elif rank == 14: value = "Ace" self.deck.append(str(value) + " of " + suit) class Card(object): def __init__(self, rank, value): self.rank = rank self.value = value self.card = self.rank + self.value
I am having a difficult time with classes and OOP, and I'm not sure if this is a good start, or where I should go next. Much of this was created by reading other sources and examples. Can anyone please provide advice on what other classes I may want to make to run my game, and how those classes may interact with/inherit from each other? Thank you.
-
Anton about 10 yearsI think this answer might be a little bit too complex for somebody who doesn't yet have a solid grasp of how to finish his/her game.
-
jonrsharpe about 10 yearsYou have a
TypeError
inCard.__init__
and aNameError
inCard.deal
. Also, there are only 13 cards per suit (2-10, JQKA). -
Farmer Joe about 10 yearsYou should really take a little more care with the code you provide, I know you made a cautionary note, but it won't be very helpful if the code you provide does not work. I made several edits to fix some outstanding errors.
-
jonrsharpe about 10 years@farmerjoe I think
card = random.choice(remaining_cards)
saves you some lines and makes the process clearer. -
Farmer Joe about 10 years@jonrsharpe agreed, I think that is a better call, but I was more playing damage control on this answer than providing my own methodology, I felt my edits reflected the intent Andrey had
-
jonrsharpe about 10 years@Andrey this is fairly straightforward; if the OP wants to learn Python OOP, getting to grips with magic methods is crucial.
-
jonrsharpe about 10 years@farmerjoe ah, I see. Note that
Card.__eq__
needs to be implemented forcard in self.dealt
to work, though, and thatrandint(a, b)
includesb
-
Farmer Joe about 10 years@jonrsharpe Indeed! Good catch! Serves me right for being so nit picky in the first place haha
-
jonrsharpe about 10 years@farmerjoe classic application of Muphry's law!