0

I have created a class called Deck to represent a deck of playing cards in Python. In it I have made card piles of all cards except with the joker. I am trying to make an inbetween game in which I have to compare the values.

         ["2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "10C", "JC",
         "QC", "KC", "AC", "2D", "3D", "4D", "5D", "6D", "7D", "8D",
         "9D", "10D", "JD", "QD", "KD", "AD", "2H", "3H", "4H", "5H",
         "6H", "7H", "8H", "9H", "10H", "JH", "QH", "KH", "AH", "2S",
         "3S", "4S", "5S", "6S", "7S", "8S", "9S", "10S", "JS", "QS",
         "KS", "AS"]

This is the list of cards. How do I rank these so that for example, 2C is less than 3C or 4D but same as 2H or 2S?

I wanted to know if I could use OrderedEnum, but at the same time assign same rankings such as for 2C, 2D, 2H, 2S in the process.

I expect that when I use my "Deal" method, I want to be able to compare two cards that were dealt.

Scott Hunter
  • 48,888
  • 12
  • 60
  • 101
Yun Choi
  • 1
  • 2
  • 1
    Make a card class that defines [comparison methods](https://docs.python.org/3/reference/datamodel.html#object.__lt__) then use instances of this class in your deck instead of strings. – wwii Jul 30 '19 at 19:05
  • Related: [What is the best way to create a deck of cards?](https://stackoverflow.com/questions/41970795/what-is-the-best-way-to-create-a-deck-of-cards), [best way to implement a deck for a card game in python](https://stackoverflow.com/questions/2518753/best-way-to-implement-a-deck-for-a-card-game-in-python), ... [creating a playing card Class Python](https://stackoverflow.com/questions/42801071/creating-a-playing-card-class-python), ... – wwii Jul 30 '19 at 19:13
  • ... [How can I compare the values of two playing cards when they have a value and a suit? Python3](https://stackoverflow.com/questions/42398725/how-can-i-compare-the-values-of-two-playing-cards-when-they-have-a-value-and-a-s). There are many more if you search with `python card deck compare card` or something similar. – wwii Jul 30 '19 at 19:13
  • Welcome to SO. Your question is a little to broad, this isn't a discussion forum. Please take the time to read [mcve], [ask] and the other links found on that page. – wwii Jul 30 '19 at 19:15

3 Answers3

0

This will yield a copy of your deck in the order described, assuming Aces are low (move A to the end of the string to make Aces high):

sorted(deck,key=lambda x:"A234567891JQK".index(x[0]))
Scott Hunter
  • 48,888
  • 12
  • 60
  • 101
0

I would create a class called Card as well - just a wrapper for this string, but one that implements comparison methods:

ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "J", "Q", "K", "A"]
suits = ["C", "D", "H", "S"]

class Card:
    def __init__(self, text):
        self.rank = text[0]
        self.suit = text[1]
    def __eq__(self, obj):
        return (self.rank, self.suit) == (obj.rank, obj.suit)
    def __lt__(self, obj):
        return (ranks.find(self.rank), suits.find(self.suit)) < (ranks.find(obj.rank), suits.find(obj.suit))
    def __str__(self):
        return f"{self.rank}{self.suit}"
    def __repr__(self):
        return str(self)

After which, you can build your deck with a few list comprehensions:

import itertools
...
deck = [Card(''.join(c)) for c in itertools.product(ranks, suits)]
print(deck)
# [2C, 2D, 2H, 2S, 3C, 3D, 3H, 3S, 4C, 4D, 4H, 4S, 5C, 5D, 5H, 5S, 6C, 6D, 6H, 6S, 7C, 7D, 7H, 7S, 8C, 8D, 8H, 8S, 9C, 9D, 9H, 9S, JC, JD, JH, JS, QC, QD, QH, QS, KC, KD, KH, KS, AC, AD, AH, AS]

If you don't want to order the suits, then just remove them from __eq__ and __lt__:

def __eq__(self, obj):
    return self.rank == obj.rank
def __lt__(self, obj):
    return ranks.find(self.rank) < ranks.find(obj.rank)

This solution would also make it fairly easy to add in a joker and insert special behavior for it.

Green Cloak Guy
  • 23,793
  • 4
  • 33
  • 53
0

Representing all data with strings is a common disease among beginning programmers. We call such code "stringly typed" as a pun on "strongly typed". Generally speaking, strings should be used only to represent actual text read or written by humans, and everything else should be numbers.

For example, a card is a combination of suit and rank. Since we'll often want to compare ranks, it makes sense to make rank a simple integer with lowest-ranked cards having the lowest value. Suits can just be 0..3, arbitrarily assigned (although I will use a ranking common to several games: C,D,H,S).

The arrays and dictionaries up front are used to convert to/from text for display to humans and for input from humans, but don't need to be used at all for the game logic itself. That just uses numbers, which are easy to compare and efficient to manipulate.

rank_names = [ "2","3","4","5","6","7","8","9","T","J","Q","K","A" ]
suit_names = [ "C", "D", "H", "S" ]
rank_values = { rank_names[i]: i for i in range(13) }
suit_values = { suit_names[i]: i for i in range(4) }

class Card:
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def name(self):
        return rank_names[self.rank] + suit_name[self.suit]

    @classmethod
    def from_name(cls, name):
        return cls(rank_values[name[0]], suit_values[name[1]])

    def __lt__(self, other):
        return self.rank < other.rank

deck = [ Card(r,s) for r in range(13) for s in range(4) ]

...etc

Lee Daniel Crocker
  • 12,927
  • 3
  • 29
  • 55