¿Cómo puedo comparar los valores de dos cartas cuando tienen un valor y un palo? Python3

Estoy tratando de hacer un juego de cartas orientado a objetos y basado en texto. Dos jugadores roban una carta de un mazo de cartas, y el jugador con la carta más fuerte gana. Tengo cuatro clases para este juego: Tarjeta, Deck, Jugador, Juego. Mi pregunta es: ¿Cómo puedo comparar las cartas de cada jugador entre sí y determinar cuál es la más fuerte? Todas las demás sugerencias sobre el código son bienvenidas. Saludos cordiales HWG.

Aquí está mi código:

Tarjeta

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]) 

Cubierta

 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) 

Jugador

 from deck import Deck class Player(): def __init__(self, name): self.name = name self.card = None self.wins = 0 

Juego

 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() 

Aquí hay un bosquejo de un enfoque. Puede combinar esto fácilmente con su propio enfoque, ya que el mayor cambio es para la clase de Card . Aquí, he usado namedtuple para crear una clase de Card , pero su clase actual simplemente puede envolver un valor de tuple :

 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) 

Ahora, en acción:

 >>> c1 Card(rank=, suit=) >>> c2 Card(rank=, suit=) >>> c1 < c2 True >>> c1 > c3 False 

La clasificación de la tupla es lexicográfica! ¡Bonito!

 >>> hand = [c2, c1, c3] >>> hand [Card(rank=, suit=), Card(rank=, suit=), Card(rank=, suit=)] >>> sorted(hand) [Card(rank=, suit=), Card(rank=, suit=), Card(rank=, suit=)] >>> 

Tenga en cuenta que he usado el decorador total_ordering , que es simplemente un atajo, y de hecho, creo que sería mejor hacer toda la clase a mano. Aquí hay una receta.

EDITAR Entonces, para elaborar, aquí es cómo implementaría sus clases de Card y Deck . Observe cuánto más legible se vuelve su código cuando usa la enum y el 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) 

Ahora, en acción:

 >>> 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=, suit=) >>> c2.value CardValue(rank=, suit=) 

Además, __repr__ cuenta que __repr__ debe tratar de representar el objeto; si desea un mensaje bonito, use __str__ . Ver esta pregunta

Podría implementar operadores para su clase de Tarjeta __gt__(), __lt__(), etc.

Además, puede usar una serie de funciones estándar de la biblioteca como max () para determinar la carta o el mazo de mayor valor e incluso podría usar sort () para simplemente ordenar una ‘mano’, por ejemplo, una lista [Card, Card, …].

Una enumeración ( https://docs.python.org/3.5/library/enum.html ) sería apropiada. Para realizar comparaciones ricas (y hacer pedidos), también debe considerar implementar algunos o todos los __eq__ , __ne__ , __lt__ , __le__ , __gt__ , __ge__ (de https://docs.python.org/3/reference/datamodel.html ) en la clase de Card .

Te recomendaría que guardes el valor de cada tarjeta como un int, para que puedas compararlas y no uses cadenas como “King” o “Ace”. Puedes hacer esto y cambiar repr () para imprimir una versión legible por humanos usando esas cadenas.

La clase de Cartas podría verse así:

 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]) 

Observe cómo el valor de la tarjeta se almacena como un int todo el tiempo.

En la clase de Juego, podrías tener una función que compara dos cartas, no estoy seguro de cómo quieres hacer esto, pero podría ser algo como esto:

 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