Trying to implement a card deck sorting algorithm

2020-04-16 02:46发布

So I'm trying to create a Deck of cards in Python. I am at the point where I'm trying to create the method to sort the deck of cards back into order.

2 of clubs, 3 of clubs, ...Ace of clubs

2 of Diamonds, 3 of Diamonds, ...Ace of Diamonds

2 of Hearts, 3 of Hearts, ...Ace of Hearts

2 of Spades, 3 of Spades, ...Ace of Spades

I have part of it already implemented but the sorting part is only KIND OF working. It successfully sorts them in the suit, but the rank part is kind of messed up. 10 comes before 2 and the Picture Cards are incorrect. My guess is that my __lt__ and __eq__ functions aren't processing the ranks correctly (esp the Picture Cards)

CODE:

import random
# deck = ["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"]
from functools import total_ordering

graveyard = []


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

    def __str__(self):
        return '%s of %s' % (self.rank,
                             self.suit)

    def __repr__(self): return str(self)

    def __lt__(self, other):
        t1 = self.suit, self.rank
        t2 = other.suit, other.rank
        return t1 < t2

    def __gt__(self, other):
        t1 = self.suit, self.rank
        t2 = other.suit, other.rank
        return t1 > t2

    def __eq__(self, other):
        t1 = self.suit, self.rank
        t2 = other.suit, other.rank
        return t1 == t2




class Deck(object):
    def __init__(self):
        """
        Idea for this found here.
        https://stackoverflow.com/questions/8511745/sorting-a-hand-of-cards-accoring-to-rank-and-suit-in-python

        I could use this to ALWAYS have a shuffled deck at the beginning or to just start with a 'clean' deck as above...
        :return:
        """
        self.rank = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King', 'Ace']
        self.suit = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
        self.deck = [Card(r, s) for r in self.rank for s in self.suit]
        random.shuffle(self.deck)

    def __getitem__(self, item):
        return self.deck[item]

    def deal(self):
        """
        Return a card from the deck.
        :return:
        """
        topCard = self.deck.pop(0)
        graveyard.append(topCard)
        print(topCard)

    def shuffle(self):
        """
        Shuffle the deck
        :return:
        """
        self.deck.extend(graveyard)
        random.shuffle(self.deck)
        self.fan()

    def fan(self):
        """
        Print out the deck
        :return:
        """
        for card in self.deck:
            print(card)

    def order(self):
        return self.deck.sort()

    def printGraveyard(self):
        for dead in graveyard:
            print(dead)


d = Deck()

d.order()

d.fan()

OUTPUT:

10 of Clubs
2 of Clubs
3 of Clubs
4 of Clubs
5 of Clubs
6 of Clubs
7 of Clubs
8 of Clubs
9 of Clubs
Ace of Clubs
Jack of Clubs
King of Clubs
Queen of Clubs
10 of Diamonds
2 of Diamonds
3 of Diamonds
4 of Diamonds
5 of Diamonds
6 of Diamonds
7 of Diamonds
8 of Diamonds
9 of Diamonds
Ace of Diamonds
Jack of Diamonds
King of Diamonds
Queen of Diamonds
10 of Hearts
2 of Hearts
3 of Hearts
4 of Hearts
5 of Hearts
6 of Hearts
7 of Hearts
8 of Hearts
9 of Hearts
Ace of Hearts
Jack of Hearts
King of Hearts
Queen of Hearts
10 of Spades
2 of Spades
3 of Spades
4 of Spades
5 of Spades
6 of Spades
7 of Spades
8 of Spades
9 of Spades
Ace of Spades
Jack of Spades
King of Spades
Queen of Spades

2条回答
▲ chillily
2楼-- · 2020-04-16 02:58

I didn't test it, but I think you could create a class for the rank, like:

class CardRank():
    def __init__(self, name, value):
        self.name = name # e.g. Ace
        self.value = value # e.g. 12

in Deck:

def __init__(self):
    self.rank = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King', 'Ace']
    self.suit = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
    self.deck = [Card(CardRank(r, self.rank.index(r)), s) for r in self.rank for s in self.suit]

So in class Card you could do something like:

 def __gt__(self, other):
     return self.rank.value > other.rank.value
查看更多
【Aperson】
3楼-- · 2020-04-16 03:02

You're correct, it's the comparision of the rank that compares the string, that is "10"<"2" and "Ace"<"Queen" etc.

What you could do is to for example write a suitable string to numeric rank function.

def num_rank(rank):
    if rank[0] == "A":
         return 14
    if rank[0] == "J":
         return 11
    if rank[0] == "Q":
         return 12
    if rank[0] == "K":
         return 13
    return int(rank)

then you use this to rewrite the comparison:

def __lt__(self, other):
    t1 = self.suit, num_rank(self.rank)
    t2 = other.suit, num_rank(other.rank)
    return t1 < t2
查看更多
登录 后发表回答