diff --git a/carpet.py b/carpet.py new file mode 100644 index 0000000..4f25f64 --- /dev/null +++ b/carpet.py @@ -0,0 +1,136 @@ +from enum import Enum, auto +from random import shuffle + +class Suit(Enum): + CLUBS = auto() + HEARTS = auto() + DIAMONDS = auto() + SPADES = auto() + +class Game: + def __init__(self): + self.foundations = {suit: 1 for suit in Suit} + self.deck = self.get_random_pile() + self.carpet = set(self.deck[-20:]) + self.free_cells = 0 + self.moves = 0 + self.deck = self.deck[:-20] + self.offers = [self.deck.pop()] + + def get_random_pile(self): + cards = {(suit, value) for suit in Suit for value in range(2, 13+1)} + deck = list(cards) + shuffle(deck) + return deck + + def can_drop(self, card): + suit, value = card + return self.foundations[suit] == value - 1 + # FIXME: use this function. + def can_move(self): + if len(self.deck) > 0: return True + if len(self.offers) > 0 and self.can_drop(self.offers[-1]): return True + if any(self.can_drop(card) for card in self.carpet): return True + if self.free_cells > 0: return True + return False + + def count_move(self): + self.moves += 1 + + # Possible moves + def drop_from_carpet(self, card): + if card not in self.carpet: + raise ValueError() + suit, value = card + if self.foundations[suit] != value - 1: + raise ValueError() + self.count_move() + self.carpet.remove(card) + self.free_cells += 1 + self.foundations[suit] = value; + def autodrop(self): + # This is independent for each suit. + for suit in Suit: + while (suit, self.foundations[suit]+1) in self.carpet: + self.drop_from_carpet((suit, self.foundations[suit]+1)) + def drop_card_from_offer(self): # to the foundations + if len(self.offers) == 0: + raise ValueError() + offered_card = self.offers[-1] + suit, value = offered_card + if self.foundations[suit] != value - 1: + raise ValueError() + self.count_move() + self.offers.pop() + self.foundations[suit] = value + if len(self.offers) == 0 and len(self.deck) > 0: + self.count_move() + self.offers.append(self.deck.pop()) + def flip_deck(self): + if len(self.deck) == 0: + raise ValueError() + self.count_move() + self.offers.append(self.deck.pop()) + def get_card_from_deck(self): + if len(self.offers) == 0: + raise ValueError() + if self.free_cells < 1: + raise ValueError() + self.count_move() + self.carpet.add(self.offers.pop()) + self.free_cells -= 1 + if len(self.offers) == 0 and len(self.deck) > 0: + self.count_move() + self.offers.append(self.deck.pop()) + def game_result(self): # None for not finished, True for win, False for fail + if all(self.foundations[suit] == 13 for suit in Suit): + return True + if self.can_move(): return None + return False + def print(self): + from pprint import pprint + # Print game state + print(f'Moves: {self.moves}\nFree cells: {self.free_cells}\nCards in deck: {len(self.deck)}\nAvailable card: {self.offers[-1] if len(self.offers) > 0 else "None"}') + print('Foundations:') + pprint(self.foundations) + print('Carpet:') + pprint(self.carpet) + +if __name__ == '__main__': + ## A simple testing game: + from textwrap import dedent + + game = Game() + game.print() + while game.game_result() is None: + q = input('pafdg? ') + try: + if q.startswith('p'): + game.print() + if q.startswith('a'): + game.autodrop() + if q.startswith('f'): + game.flip_deck() + if q.startswith('d'): + game.drop_card_from_offer() + if q.startswith('g'): + game.get_card_from_deck() + if q.startswith('?'): + print(dedent("""\ + p: print state + a: autodrop carpet + f: flip deck + d: drop from offers + g: get from offers + ?: this help. + """)) + except ValueError as e: + print(e) + print('Try again!') + print(f'Game ended in {game.moves}.') + if game.game_result(): + print('You won!') + else: + print('You lost:') + game.print() +