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

匿名 (未验证) 提交于 2019-12-03 02:38:01

问题:

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("\nPress enter to draw")             getch.getch()             player1_card = self.cards.pop()             player2_card = self.cards.pop() 

回答1:

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, type(self)):             return self.value < other.value         return NotImplemented     def __eq__(self, other):         if isinstance(other, type(self)):             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



回答2:

You could implement operators for your Card class __gt__(), __lt__(), etc ...

than you can use a number of standard library functions like max() to determine the higher value card or deck and could even use sort() to simply sort a 'hand' for example a list [Card, Card, ...].



回答3:

An enumeration (https://docs.python.org/3.5/library/enum.html) would be appropriate. For rich comparisons (and ordering) you should also consider implementing some or all of the __eq__, __ne__, __lt__, __le__, __gt__, __ge__ methods (from https://docs.python.org/3/reference/datamodel.html) on the Card class.



回答4:

I would recommend you store the value of each card as an int, so you can compare them, and not to use strings such as "King" or "Ace". You can do this and change repr() to print a human readable version using those strings.

The Card class could look like this:

class Card(object):      suits = ["Clubs", "Diamonds", "Hearts", "Spades"] #list of suits      values = [None, "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"] #list of card values       def __init__(self, suit= 0, value= 2):          """          Initializes card          :param suit: Suit of card int value 0-3          :param value: Value of card int value 0-13          """          self.suit = suit          self.value = value       def __str__(self):          """          Returns a readable format of the card          """          return "%s of %s" %(Card.values[self.value],                              Card.suits[self.suit]) 

Notice how the value of the card is stored as an int all the time.

In the Game class you could have a function that compares two cards, I'm not sure how you want to do this but it could look something like this:

def compare(card1, card2):      """      Compares the value of two cards and returns the greater of the two      :param card1: A card object      :param card2: A second card object      :return: The higher value card, if tie returns 0      """      if card1.value > card2.value:          return card1      elif card2.value == card1.value:          return 0      else:          return card2 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!