def suitable_pile_pop(self, bottomCard): """ each Card in the pile is face-up, the pile alternates in color, and the pile is built top down. Additionally, all Cards in the given pile must be face-up. """ if bottomCard is None: Error.print_error(Error.CARD_IS_NONE, lineno()) return False if bottomCard.is_face_down(): Error.print_error(Error.CARD_IS_FACE_DOWN, lineno()) return False idx = self.index(bottomCard) popped = self[idx:] evenColor = bottomCard.color() for i in range(len(popped)): c = popped[i] if c.is_face_down(): Error.print_error(Error.CARD_IS_FACE_DOWN, lineno()) if c.rank != bottomCard.rank - i: Error.print_error(Error.INVALID_RANK, lineno()) if i % 2 == 0 and c.color() != evenColor or i % 2 == 1 and c.color() == evenColor: Error.print_error(Error.INVALID_COLOR, lineno()) if ( c.is_face_down() or c.rank != bottomCard.rank - i or i % 2 == 0 and c.color() != evenColor or i % 2 == 1 and c.color() == evenColor ): return False return True
def suitable_card_pop(self): """ @todo: commentme """ if self.is_empty(): Error.print_error(Error.EMPTY_PILE, lineno()) return not self.is_empty()
def enqueue_card(self, card): """ The same as enqueue(), but overwritten by Pile subclasses. Only legal for Stock piles. """ if self.suitable_card_enqueue(card): return self.enqueue(card) Error.print_error(Error.ILLEGAL_ENQUEUE_CARD, lineno())
def pop_card(self): """ Equivalent to deque.pop(), but is overridden by Pile subclasses for additional functionality. """ if self.suitable_card_pop(): return self.pop() Error.print_error(Error.ILLEGAL_POP_CARD, lineno())
def push_card(self, card): """ The same as push(), but is overridden by Pile subclasses to check if pushing the Card to this Pile is legal. """ if self.suitable_card_push(card): return self.push(card) Error.print_error(Error.ILLEGAL_PUSH_CARD, lineno())
def suitable_pile_pop(self, bottomCard): """ @todo: commentme """ if bottomCard is None: Error.print_error(Error.CARD_IS_NONE, lineno()) if not bottomCard in self: Error.print_error(Error.CARD_NOT_IN_PILE, lineno()) return bottomCard is not None and bottomCard in self
def push_pile(self, pile): """ Pushes a list of Cards to the top of this Pile, if it is legal to do so. Overridden by subclasses for which pushing a Pile is legal. """ if self.suitable_pile_push(pile): return self.extend(pile) Error.print_error(Error.ILLEGAL_PUSH_PILE, lineno())
def suitable_card_enqueue(self, card): """ Enqueues the specified card to this Pile if it exists and if this Pile is not full. Overridden by subclasses. """ if card is None: Error.print_error(Error.CARD_IS_NONE, lineno(), False) if len(self) >= self.maxlen: Error.print_error(Error.EXCEEDS_MAXIMUM, lineno(), False) return card is not None and len(self) < self.maxlen
def card_at(self, idx): """ Returns the Card at the specified index in this Pile, if the index is valid. Otherwise, prints an error message and returns None. """ size = len(self) if idx >= -size and idx < size: return self[idx] Error.print_error(Error.INVALID_INDEX, lineno())
def suitable_card_push(self, card): """ A suitable card is a card whose value and suit fit them to be played or placed onto a pile. Overridden by subclasses. """ if card is None: Error.print_error(Error.CARD_IS_NONE, lineno()) if len(self) >= self.maxlen: Error.print_error(Error.EXCEEDS_MAXIMUM, lineno()) return card is not None and len(self) < self.maxlen
def suitable_pile_enqueue(self, pile): """ A pile is suitable if it can be legally enqueued to this Pile. """ if pile is None: return Error.print_error(Error.PILE_IS_NONE, lineno(), False) if len(pile) == 1: return self.suitable_card_enqueue(self, pile[0]) if len(self) + len(pile) >= self.maxlen: Error.print_error(Error.EXCEEDS_MAXIMUM, lineno()) return (pile is not None and len(self) + len(pile) < self.maxlen)
def suitable_pile_push(self, pile): """ A suitable pile is a pile of cards that will be accepted upon push. Overridden by subclasses. """ if pile is None: Error.print_error(Error.PILE_IS_NONE, lineno()) if len(self) + len(pile) >= self.maxlen: Error.print_error(Error.EXCEEDS_MAXIMUM, lineno()) return (pile is not None and len(self) + len(pile) < self.maxlen)
def is_complete(self): """ Returns true if this Pile contains all 13 Cards of its suit in ascending order. """ for i in range(len(self)): card = self[i] if card.rank != i + 1: Error.print_error(Error.INVALID_RANK, lineno()) if card.suit != self.suit: Error.print_error(Error.INVALID_SUIT, lineno()) if card.rank != i + 1 or card.suit != self.suit: return False return len(self) == self.maxlen
def index(self, card): """ Returns the index of the specified Card in the Pile, if the Card is in this Pile. Otherwise, prints an error message and returns None. """ if card is None: return Error.print_error(Error.CARD_IS_NONE, lineno()) # If the card is valid, search for its index in this Pile. for i in range(len(self)): if self.card_at(i) == card: return i Error.print_error(Error.CARD_NOT_IN_PILE, lineno())
def suitable_pile_pop(self, bottomCard): """ Piles of cards cannot be popped from a Foundation pile. """ if bottomCard == self.peek(): return True return Error.print_error(Error.ILLEGAL_POP_PILE, lineno(), False)
def suitable_card_push(self, card): """ Cards may not be pushed onto the Stock pile, with the exception of the initial deal. Only Cards from the Waste pile may be enqueued by the dealer to the bottom of the Stock pile. """ return Error.print_error(Error.ILLEGAL_PUSH_CARD, lineno(), False)
def suitable_pile_push(self, pile): """ Piles of cards cannot be pushed to a Foundation pile. """ if len(pile) == 1: return self.suitable_card_push(pile[0]) return Error.print_error(Error.ILLEGAL_PUSH_PILE, False)
def suitable_pile_pop(self, card): """ Popping a pile of Cards from the Stock pile is not allowed. """ if card == self.peek(): return True return Error.print_error(Error.ILLEGAL_POP_PILE, lineno(), False)
def pop_n(self, n): """ Pops and returns a Pile containing the last n Cards at the top of this Pile. """ if n > len(self): return Error.print_error(Error.TOO_MANY_POPS, lineno()) # Grab the last n cards, and remove them from this Pile. popped = self[len(self)-n:] for _ in range(n): self.pop() return popped
def suitable_pile_push(self, pile): """ A suitable pile is one that is built down and alternating in color. The bottom card in the pile must also be a suitable card. """ # Reject pile if it is None, empty, or if its bottom # card isn't suitable. if pile is None: Error.print_error(Error.PILE_IS_NONE, lineno()) if pile.is_empty(): Error.print_error(Error.EMPTY_PILE, lineno()) if pile is None or pile.is_empty() or not self.suitable_card_push(pile[0]): return False # Reject pile if any card is face-down, or if it is # not built correctly, or if it is not alternating in color. bottom = pile[0] evenColor = bottom.color() for i in range(len(pile)): c = pile[i] if ( c.is_face_down() or c.rank != bottom.rank - i or i % 2 == 0 and c.color() != evenColor or i % 2 == 1 and c.color() == evenColor ): if c.is_face_down(): Error.print_error(Error.CARD_IS_FACE_DOWN, lineno()) if c.rank != bottom.rank - i: Error.print_error(Error.INVALID_RANK, lineno()) if i % 2 == 0 and c.color() != evenColor or i % 2 == 1 and c.color() == evenColor: Error.print_error(Error.INVALID_COLOR, lineno()) return False return True
def suitable_pile_push(self, pile): """ Piles of Cards cannot be pushed to the top of a Waste pile. """ return Error.print_error(Error.ILLEGAL_PUSH_PILE, lineno(), False)
def suitable_pile_push(self, pile): """ Pushing a pile of Cards to the Stock pile is not allowed. """ return Error.print_error(Error.ILLEGAL_PUSH_PILE, lineno(), False)
def suitable_card_push(self, card): """Pushes the given Card to the top of this Pile. The card is rejected unless it alternates in color and builds on the rest of the Pile in a top-down fashion. If this Pile is empty, the new Card must be a King. """ # Reject None cards and face-down cards. if len(self) >= self.maxlen: Error.print_error(Error.EXCEEDS_MAXIMUM, lineno()) if card is None: Error.print_error(Error.CARD_IS_NONE, lineno()) if card.is_face_down(): Error.print_error(Error.CARD_IS_FACE_DOWN, lineno()) if len(self) >= self.maxlen or card is None or card.is_face_down(): return False # If empty, accept only if card is a King. Otherwise, card must # build on this Pile's top card and alternate in color. if self.is_empty(): if card.rank != Rank.KING: Error.print_error(Error.EXPECTED_KING, lineno()) return card.rank == Rank.KING top = self.peek() if card.color() == top.color(): Error.print_error(Error.INVALID_COLOR, lineno()) if card.rank != top.rank - 1: Error.print_error(Error.INVALID_RANK, lineno()) return card.color() != top.color() and card.rank == top.rank - 1
def enqueue_card(self, card): """Cards cannot be inserted to the bottom of a Tableau pile.""" return Error.print_error(Error.ILLEGAL_ENQUEUE_CARD, lineno())
def suitable_card_enqueue(self, card): """ Cards cannot be inserted to the bottom of a Foundation pile. """ return Error.print_error(Error.ILLEGAL_ENQUEUE_CARD, lineno(), False)
def suitable_card_push(self, card): """ Rejects cards that are of the inappropriate suit or rank for this Pile. The rank of the prospective card must be one higher than the Card at the top of this Pile, or Ace if this Pile is empty. The suit of the prospective Card must match this Pile's suit. """ if len(self) >= self.maxlen: Error.print_error(Error.EXCEEDS_MAXIMUM, lineno()) if card is None: return Error.print_error(Error.CARD_IS_NONE, lineno(), False) if card.is_face_down(): Error.print_error(Error.CARD_IS_FACE_DOWN, lineno()) if card.suit != self.suit: Error.print_error(Error.INVALID_SUIT, lineno()) if (len(self) >= self.maxlen or card is None or card.is_face_down() or card.suit != self.suit): return False if self.is_empty(): if card.rank != Rank.ACE: Error.print_error(Error.EXPECTED_ACE, lineno()) return card.rank == Rank.ACE top = self.peek() if card.rank != top.rank + 1: Error.print_error(Error.INVALID_RANK, lineno()) return card.rank == top.rank + 1