2011-06-02 10 views
16

esta es mi primera vez en desbordamiento de pila así que lo siento si el formato no encaja del todo bien con el sitio. Recientemente empecé a aprender programación, han pasado casi 2 semanas desde entonces. Estoy aprendiendo Python desde http://openbookproject.net/thinkcs/python/english3e/index.html y todo había sido bastante agradable hasta ahora, donde me quedé atrapado durante horas. Busqué en Google pero no pude encontrar una solución adecuada a mi problema, así que aquí estoy.Python: 'objeto en la lista de' controles y rebosadero '__cmp__'

Estoy intentando conseguir el JuegoDeLaMona() funcionar sin problemas como se explica en CH17. - La mayoría del código también proviene del capítulo anterior.

Lo que he descubierto es que no puedo conseguir los Deck.remove, Hand.remove_matches, o cualquier otro tipo de función Remove para trabajar. Después de algunas depuraciones descubrí que el problema ocurre cuando el programa comprueba si la tarjeta dada está presente en el mazo/mano/etc. No puede hacer una coincidencia. A continuación, después de algún mirando hacia atrás en el capítulo , (en CH16), descubrí que 'si la tarjeta en la cubierta/de la mano/etc: eliminar (tarjeta)', etc busca el. cmp() del objeto para determinar si la tarjeta existe realmente en el mazo/mano/etc. Esta es mi versión de la cmp después de hacer las adiciones de 'de As en el código dado desde el libro electrónico.

def __cmp__(self, other): 
    """ Compares cards, returns 1 if greater, -1 if lesser, 0 if equal """ 
    # check the suits 
    if self.suit > other.suit: return 1 
    if self.suit < other.suit: return -1 
    # suits are the same... check ranks 
    # check for aces first. 
    if self.rank == 1 and other.rank == 1: return 0 
    if self.rank == 1 and other.rank != 1: return 1 
    if self.rank != 1 and other.rank == 1: return -1 
    # check for non-aces. 
    if self.rank > other.rank: return 1 
    if self.rank < other.rank: return -1 
    # ranks are the same... it's a tie 
    return 0 

El cmp en sí parece muy bien que yo sepa, OFC que podría utilizar algunos consejos sobre cómo hacer que sea mejor (como con cheques as). Así que no tengo idea de por qué la tarjeta en el mazo/cheque siempre devuelve falso. Esta fue la función Remove dado:

class Deck: 
    ... 
    def remove(self, card): 
     if card in self.cards: 
      self.cards.remove(card) 
      return True 
     else: 
      return False 

Tratando desesperadamente de conseguir que funcione, se me ocurrió esto:

class Deck: 
    ... 
    def remove(self, card): 
     """ Removes the card from the deck, returns true if successful """ 
     for lol in self.cards: 
      if lol.__cmp__(card) == 0: 
       self.cards.remove(lol) 
       return True 
     return False 

parecía funcionar bien, hasta que pasé a la otra no que trabajan quitar funciones:

class OldMaidHand(Hand): 
    def remove_matches(self): 
     count = 0 
     original_cards = self.cards[:] 
     for card in original_cards: 
      match = Card(3 - card.suit, card.rank) 
      if match in self.cards: 
       self.cards.remove(card) 
       self.cards.remove(match) 
       print("Hand {0}: {1} matches {2}".format(self.name, card, match)) 
       count = count + 1 
     return count 

me volvieron a hacer algunos ajustes:

class OldMaidHand(Hand): 
    def remove_matches(self): 
     count = 0 
     original_cards = self.cards[:] 
     for card in original_cards: 
      match = Card(3 - card.suit, card.rank) 
      for lol in self.cards: 
       if lol.__cmp__(match) == 0: 
        self.cards.remove(card) 
        self.cards.remove(match) 
        print("Hand {0}: {1} matches {2}".format(self.name, card, match)) 
        count = count + 1 
     return count 

la remoción funcionó bien para la tarjeta, pero le daría un error (x no está en la lista) cuando intenté quitar partido. Otro nuestro más o menos, podría haber sido capaz de hacer ese trabajo también, pero ya que parece que estoy en el camino equivocado ya que no puedo arreglar la "tarjeta original en cubierta/mano/etc.", etc. vino aquí en busca de algunas respuestas/consejos.

Gracias por leer y aprecio enormemente cualquier ayuda que puede dar :)

--------------------- EDIT 1 *>

Este es mi código actual: http://pastebin.com/g77Y4Tjr

--------------------- EDIT 2 * >

que he probado cada uno cmp aconsejados aquí, y todavía no puedo encontrar una tarjeta con 'in'.

>>> a = Card(0, 5) 
>>> b = Card(0, 1) 
>>> c = Card(3, 1) 
>>> hand = Hand('Baris') 
>>> hand.add(a) 
>>> hand.add(b) 
>>> hand.add(c) 
>>> d = Card(3, 1) 
>>> print(hand) 
Hand Baris contains 
5 of Clubs 
Ace of Clubs 
    Ace of Spades 
>>> d in hand.cards 
False 
>>> 

También he probado la @DSM card.py ha utilizado con éxito, y tengo errores allí también, al igual que en la función de clasificación que dice que no puede comparar las dos tarjetas de objetos.
Entonces, me preguntaba, tal vez sea un problema con Python 3.2, ¿o tal vez la sintaxis ha cambiado en alguna parte?

+4

+1 para decidir a aprender Python! –

+0

¿Estás seguro de que en realidad hay cartas en la baraja? –

+1

@ Space_C0wb0y Sí, todo lo demás funciona bien. No publiqué todo el programa, ya que no estaba seguro de si sería apropiado en este sitio, y ya que se puede encontrar en el libro electrónico que he vinculado. Lo único que falla es el control 'in'. Incluso si solo creo manualmente una baraja/mano vacía, agrego 1-2 cartas, y trato de verificar si el programa reconoce alguna de ellas, falla. – Ulquiomaru

Respuesta

6

"Así que me preguntaba, tal vez es un problema con Python 3.2, o tal vez la sintaxis ha cambiado alguna parte?"

¿Estás ejecutando Python 3.2? Esto nunca funcionará en Python 3: python 3 no usa __cmp__!

Ver el data model (look for __eq__). También lea el what's new in Python 3 para otras cosas es manera demasiado fácil de perder.

Disculpe, esto está en nosotros programadores de Python aquí; deberíamos haber captado esto mucho antes. La mayoría probablemente miró todo el código, se dio cuenta, sin siquiera pensarlo, que la fuente era obviamente el código python 2, y asumió que con eso estábamos trabajando. La función cmp ni siquiera existe en Python 3.2, pero la razón por la que no explota con NameError es porque nunca se llama al __cmp__.

Si funciono el código en Python 3.2, reproduzco su problema exactamente:

>>> c = Card(0,2) 
>>> str(c) 
'2 of Clubs' 
>>> c in [c] 
True 
>>> c in Deck().cards 
False 

En Python 3, o bien poner en práctica todas las CMPS ricos o __eq__ y uno de ellos y utilizar un decorador total_ordering.

from functools import total_ordering 

@total_ordering 
class Card(object): 
    """Represents a standard playing card.""" 
    suit_names = ["Clubs", "Diamonds", "Hearts", "Spades"] 
    rank_names = [None, "Ace", "2", "3", "4", "5", "6", "7", 
       "8", "9", "10", "Jack", "Queen", "King"] 
    def __init__(self, suit=0, rank=2): 
     self.suit = suit 
     self.rank = rank 
    def __str__(self): 
     return '%s of %s' % (Card.rank_names[self.rank], 
          Card.suit_names[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 __eq__(self, other): 
     t1 = self.suit, self.rank 
     t2 = other.suit, other.rank 
     return t1 == t2 


>>> c = Card(2,3) 
>>> c 
3 of Hearts 
>>> c in Deck().cards 
True 
0

Parece que no puedo reproducir el problema de no poder eliminar tarjetas mediante Deck.remove. Si comienzo con la card.py en the thinkpython site y añadir la función de eliminación que has enviado hasta allí, parece que funciona:

>>> deck = Deck() 
>>> str(deck).split('\n') 
['Ace 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', '10 of Clubs', 'Jack of Clubs', 'Queen of Clubs', 'King of Clubs', 'Ace 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', '10 of Diamonds', 'Jack of Diamonds', 'Queen of Diamonds', 'King of Diamonds', 'Ace 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', '10 of Hearts', 'Jack of Hearts', 'Queen of Hearts', 'King of Hearts', 'Ace 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', '10 of Spades', 'Jack of Spades', 'Queen of Spades', 'King of Spades'] 
>>> len(deck.cards) 
52 
>>> c = Card(suit=0, rank=8) 
>>> str(c) 
'8 of Clubs' 
>>> c in deck.cards 
True 
>>> deck.remove(c) 
True 
>>> len(deck.cards) 
51 
>>> c in deck.cards 
False 
>>> str(deck).split('\n') 
['Ace of Clubs', '2 of Clubs', '3 of Clubs', '4 of Clubs', '5 of Clubs', '6 of Clubs', '7 of Clubs', '9 of Clubs', '10 of Clubs', 'Jack of Clubs', 'Queen of Clubs', 'King of Clubs', 'Ace 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', '10 of Diamonds', 'Jack of Diamonds', 'Queen of Diamonds', 'King of Diamonds', 'Ace 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', '10 of Hearts', 'Jack of Hearts', 'Queen of Hearts', 'King of Hearts', 'Ace 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', '10 of Spades', 'Jack of Spades', 'Queen of Spades', 'King of Spades'] 

Parece que funciona si se sustituye la __cmp__ por la suya, también:

>>> deck = Deck() 
>>> c = Card(suit=0,rank=1) 
>>> c in deck.cards 
True 
>>> deck.remove(c) 
True 
>>> len(deck.cards) 
51 

Así que algo debe ser diferente. ¿Podría volcar todo el código, y algún código que demuestre el error, en alguna parte (pegar, extraer, etc.)?


(Fwiw, mi as-sobre-rey cmp es así:

def __cmp__(self, other): 
    def aceshigh(r): return 14 if r==1 else r 
    t1 = self.suit, aceshigh(self.rank) 
    t2 = other.suit, aceshigh(other.rank) 
    return cmp(t1, t2) 

Ejercicio: quitar los números mágicos.)

+0

El card.py en ese sitio tampoco funciona para mí. Y no estoy hablando de pequeñas cosas entre las versiones de Python como la sintaxis de impresión, incluso la función de clasificación produce un error. Extraño. Solo tengo un usuario de Python de 2 semanas y esto me está matando :( – Ulquiomaru

1

Asimismo, no puede reproducir el error. Funciona bien para mí. Mi única sugerencia sería que probablemente no deberías modificar una lista mientras la estás iterando (es decir, llamar a self.cards.remove dentro de un loop sobre self.cards). Eso no puede explicar por qué las versiones que usan "in" no funcionarían para usted.

Su función cmp se puede escribir algo más sucinta (y en mi humilde opinión más simple) como:

def __cmp__(self, other): 
    """ Compares cards, returns 1 if greater, -1 if lesser, 0 if equal """ 
    return cmp((self.suit, self.rank == 1, self.rank), 
       (other.suit, other.rank == 1, other.rank)) 

o si lo prefiere:

return (cmp(self.suit, other.suit) or 
      cmp(self.rank == 1, other.rank == 1) or 
      cmp(self.rank, other.rank)) 
0

Suena como que tienes un problema con tu variable de cubierta O bien la función de eliminación apunta a un objeto diferente con un mazo en blanco, o bien tiene un problema de espacio de nombres. ¿La función remove es parte del objeto deck?

Sugiero agregar algunas líneas de la cubierta de impresión. Una justo después de que se haya inicializado, para ver qué tiene dentro y otra igual a como se llama eliminar.

0

Su función de comparación debería funcionar, como han señalado otras personas, necesita más detalles para averiguar qué estaba pasando allí. En cuanto a sugerencias:

  1. Stick Ace al final de los rangos, use 0-12 para mapear rangos. Esto parece ser el enfoque natural para mí.

  2. Aprovechar la biblioteca estándar:

    A. Uso random.shuffle a barajar.

    B. Utilice cmp para manejar las comparaciones.

    C. collections.defaultdict hace una limpieza remove_matches método en mi opinión.

  3. El método __str__ sugerido es realmente, realmente molesto.

  4. Implemento __repr__.

aplicación alternativa:

from collections import defaultdict 
import random 

class Card(object): 
    suits = ["Clubs", "Diamonds", "Hearts", "Spades"] 
    ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"] 

    def __init__(self, suit=0, rank=0): 
     self.suit = suit 
     self.rank = rank 

    def __str__(self): 
     return self.ranks[self.rank] + " of " + self.suits[self.suit] 

    def __repr__(self): 
     return self.__str__() 

    def __cmp__(self, other): 
     return cmp((self.suit, self.rank), (other.suit, other.rank)) 

class Deck(object): 
    def __init__(self): 
     self.cards = [] 
     for suit in range(4): 
      for rank in range(13): 
       self.cards.append(Card(suit=suit, rank=rank)) 

    def shuffle(self): 
     random.shuffle(self.cards) 

    def remove(self, card): 
     if card in self.cards: 
      self.cards.remove(card) 

    def pop(self): 
     return self.cards.pop() 

    def is_empty(self): 
     if len(self.cards) is 0: 
      return True 
     return False 

    def deal(self, hands, num_cards=999): 
     num_hands = len(hands) 
     for i in range(num_cards): 
      if self.is_empty(): break # break if out of cards 
      card = self.pop()   # take the top card 
      hand = hands[i % num_hands] # whose turn is next? 
      hand.add(card)    # add the card to the hand 

class Hand(Deck): 
    def __init__(self, name=""): 
     self.cards = [] 
     self.name = name 

    def add(self,card): 
     self.cards.append(card) 

class OldMaidHand(Hand): 
    def remove_matches(self): 
     matches = defaultdict(list) 
     for card in self.cards: 
      matches[card.rank].append(card) 
     for cards in matches.values(): 
      if len(cards) == 2: 
       print("Hand {0}: {1} matches {2}".format(self.name, *cards)) 
       for card in cards: 
        self.remove(card) 
Cuestiones relacionadas