You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
3.6 KiB
Python
137 lines
3.6 KiB
Python
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()
|
|
|