Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
376 views
in Technique[技术] by (71.8m points)

python - How can I compare the values of two playing cards when they have a value and a suit? Python3

I am trying to make a text based object oriented card game. Two players draw a card each from a deck of cards, and the player with the strongest card wins. I have four classes for this game: Card, Deck, Player, Game. My question is: How can i compare each players card to each other and determine the strongest one. All other suggestions about the code are welcome. Best regards HWG.

Here is my code:

Card

class Card():

    values = [None, None, 2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King",
        "Ace"]
    suits = ["hearts", "spades", "diamond", "clubs"]

    def __init__(self, value, suit):
        self.value = value
        self.suit = suit

    def __repr__(self):
        return str(self.values[self.value]) + " of " + str(self.suits[self.suit])

Deck

from random import shuffle
from card import Card

class Deck():

    def __init__(self):
        self.cards = []
        for v in range(2, 15):
            for s in range(4):
                self.cards.append(Card(v, s))
        shuffle(self.cards)

Player

from deck import Deck

class Player():

    def __init__(self, name):
        self.name = name
        self.card = None
        self.wins = 0

Game

from player import Player
from deck import Deck
import getch

class Game():

    def __init__(self):
        player1_name = input("Player One Name: ")
        player2_name = input("Player Two Name: ")
        self.deck = Deck()
        self.player1 = Player(player1_name)
        self.player2 = Player(player2_name)
        self.cards = self.deck.cards

    def game_loop(self):
        while len(self.cards) >= 2:
            print("
Press enter to draw")
            getch.getch()
            player1_card = self.cards.pop()
            player2_card = self.cards.pop()
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is a sketch of an approach. You can easily combine this with your own approach, the biggest change being for the Card class. Here, I've used namedtuple to make a Card class, but your current class can simply wrap a tuple value:

import enum
from functools import total_ordering
from collections import namedtuple

@total_ordering
class OrderedEnum(enum.Enum):
    def __lt__(self, other):
        if isinstance(other, type(self)):
            return self.value < other.value
        return NotImplemented

Rank = OrderedEnum('Rank', ['one', 'two', 'three', 'four', 'five', 'six',
                    'seven', 'eight', 'nine', 'jack', 'queen','king', 'ace'])

Suit = OrderedEnum('Suit', ['clubs', 'diamonds', 'hearts', 'spades'])

Card = namedtuple('Card', ['rank', 'suit'])

c1 = Card(Rank.four, Suit.clubs)
c2 = Card(Rank.four, Suit.spades)
c3 = Card(Rank.ace, Suit.diamonds)

Now, in action:

>>> c1
Card(rank=<Rank.four: 4>, suit=<Suit.clubs: 1>)
>>> c2
Card(rank=<Rank.four: 4>, suit=<Suit.spades: 4>)
>>> c1 < c2
True
>>> c1 > c3
False

Tuple sorting is lexicographic! Nice!

>>> hand = [c2, c1, c3]
>>> hand
[Card(rank=<Rank.four: 4>, suit=<Suit.spades: 4>), Card(rank=<Rank.four: 4>, suit=<Suit.clubs: 1>), Card(rank=<Rank.ace: 13>, suit=<Suit.diamonds: 2>)]
>>> sorted(hand)
[Card(rank=<Rank.four: 4>, suit=<Suit.clubs: 1>), Card(rank=<Rank.four: 4>, suit=<Suit.spades: 4>), Card(rank=<Rank.ace: 13>, suit=<Suit.diamonds: 2>)]
>>>

Note, I've used the total_ordering decorator, which is simply a shortcut, and indeed, I think it might be better to simply do the whole class by hand. Here's a recipe.

EDIT So, to elaborate, here is how I would implement your Card and Deck classes. Notice how much more readable your code becomes when you use the enum and namedtuple.

import enum
from functools import total_ordering
from collections import namedtuple
from random import shuffle 

@total_ordering
class OrderedEnum(enum.Enum):
    def __lt__(self, other):
        if isinstance(other, type(self)):
            return self.value < other.value
        return NotImplemented

Rank = OrderedEnum('Rank', ['one', 'two', 'three', 'four', 'five', 'six',
                    'seven', 'eight', 'nine', 'jack', 'queen','king', 'ace'])
Suit = OrderedEnum('Suit', ['clubs', 'diamonds', 'hearts', 'spades'])
CardValue = namedtuple('CardValue', ['rank', 'suit'])

@total_ordering
class Card(object):
    def __init__(self, rank, suit):
        self.value = CardValue(rank, suit)
    def __repr__(self):
        return "Card({:s}, {:s})".format(self.value.rank, self.value.suit)
    def __lt__(self, other):
        if isinstance(other, __class__):
            return self.value < other.value
        return NotImplemented
    def __eq__(self, other):
        if isinstance(other, __class__):
            return self.value == other.value
        return NotImplemented

class Deck(object):
    def __init__(self):
        self.cards = []
        for rank in Rank:
            for suit in Suit:
                self.cards.append(Card(rank, suit))
        shuffle(self.cards)

Now, in action:

>>> deck = Deck()
>>> c1 = deck.cards.pop()
>>> c2 = deck.cards.pop()
>>> c1
Card(Rank.queen, Suit.hearts)
>>> c2
Card(Rank.king, Suit.clubs)
>>> c1 == c2
False
>>> c1 > c2
False
>>> c1 < c2
True
>>> c1.value
CardValue(rank=<Rank.queen: 11>, suit=<Suit.hearts: 3>)
>>> c2.value
CardValue(rank=<Rank.king: 12>, suit=<Suit.clubs: 1>)

Also, notice that __repr__ should try to represent the object, if you want a pretty message, use __str__. See this question


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...