226 lines
6.6 KiB
Python
226 lines
6.6 KiB
Python
import random
|
|
from operator import attrgetter
|
|
|
|
|
|
def chunks(lst, n):
|
|
"""Yield successive n-sized chunks from lst."""
|
|
for i in range(0, len(lst), n):
|
|
yield lst[i:i + n]
|
|
|
|
|
|
class Card:
|
|
def __init__(self, color, value):
|
|
self.color = color
|
|
self.value = value
|
|
|
|
def __str__(self):
|
|
sc = self.color if self.color else ' '
|
|
sv = str(self.value)
|
|
return sc+' '+sv
|
|
|
|
def __repr__(self):
|
|
return str(self)
|
|
|
|
|
|
def get_higher_card(card1: Card, card2: Card, trump_color: str):
|
|
"""
|
|
compares two cards, assuming card1 was played first and card2 played second.
|
|
returns: True if card2 beats card1, otherwise False
|
|
"""
|
|
if card2.value == 'N':
|
|
# no way to win if 'N' comes in second
|
|
return False
|
|
elif card1.value == 'Z':
|
|
# no way to win if 'Z' was already played
|
|
return False
|
|
elif card1.value == 'N':
|
|
# any other than 'N' will beat us here, and the special case
|
|
# where card2 also is 'N' was already handled above
|
|
return True
|
|
elif card2.value == 'Z':
|
|
# we only lose if card1 is also 'Z', and that was handled above,
|
|
# so this is an easy case also
|
|
return True
|
|
else:
|
|
if card1.color == card2.color:
|
|
if card1.value > card2.value:
|
|
return False
|
|
else:
|
|
return True
|
|
elif card2.color == trump_color:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
class Player:
|
|
def __init__(self, name, player_id):
|
|
self.name = name
|
|
self.id = player_id
|
|
self.cards = []
|
|
self.tricks_taken = 0
|
|
|
|
def set_cards(self, cards):
|
|
self.cards = sorted(cards, key=attrgetter('color', 'value'))
|
|
self.tricks_taken = 0
|
|
|
|
def play_card(self, card_idx):
|
|
c = self.cards[card_idx]
|
|
self.cards.remove(c)
|
|
return c
|
|
|
|
def take_trick(self):
|
|
self.tricks_taken += 1
|
|
|
|
def add_card(self, card):
|
|
self.cards.append(card)
|
|
self.cards = sorted(self.cards, key=attrgetter('color', 'value'))
|
|
|
|
|
|
class WizGame:
|
|
def __init__(self, player_names: list):
|
|
self.players = [Player(pn, idx) for idx, pn in enumerate(player_names)]
|
|
if len(self.players) > 6:
|
|
raise Exception # TODO: figure out more specific type
|
|
self.card_deck = []
|
|
self.trump_card = None
|
|
self.start_player = 0
|
|
self.active_player = 0
|
|
self.current_round = 1
|
|
self.num_tricks_played = 0
|
|
self.played_cards = list()
|
|
self.players_ordered = self.players
|
|
self.last_trick = None
|
|
self.websockets = []
|
|
|
|
def start_game(self):
|
|
self.create_deck()
|
|
self.current_round = 1
|
|
self.active_player = 0
|
|
self.start_player = 0
|
|
self.deal_cards(1)
|
|
self.played_cards = list()
|
|
self.players_ordered = self.players
|
|
self.last_trick = [('-', '-')]*len(self.players)
|
|
self.websockets = []
|
|
|
|
def create_deck(self):
|
|
self.card_deck = []
|
|
for color in ["b", "r", "g", "y"]:
|
|
for val in range(1, 14):
|
|
self.card_deck.append(Card(color, val))
|
|
for _ in range(1, 5):
|
|
self.card_deck.append(Card('-', 'Z'))
|
|
for _ in range(1, 5):
|
|
self.card_deck.append(Card('-', 'N'))
|
|
|
|
def get_trump_color(self):
|
|
card = self.trump_card
|
|
if card:
|
|
if card.color:
|
|
return card.color
|
|
elif card.value == 'Z':
|
|
return 'choose'
|
|
else:
|
|
return None
|
|
else:
|
|
return None
|
|
|
|
def deal_cards(self, cards_per_player):
|
|
random.shuffle(self.card_deck)
|
|
cs = list(chunks(self.card_deck, cards_per_player))
|
|
for idx, player in enumerate(self.players):
|
|
player.set_cards(cs[idx])
|
|
if len(cs) > len(self.players):
|
|
cc = cs[len(self.players)]
|
|
c = cc[0]
|
|
self.trump_card = c
|
|
else:
|
|
self.trump_card = None
|
|
|
|
def get_trick_winner(self):
|
|
cards = self.played_cards
|
|
high_player, high_card = cards[0]
|
|
|
|
for player, card in cards[1:]:
|
|
if get_higher_card(high_card, card, self.trump_card.color if self.trump_card else '-'):
|
|
high_card = card
|
|
high_player = player
|
|
return high_player, high_card
|
|
|
|
def is_trick_finished(self):
|
|
if len(self.played_cards) < len(self.players):
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
def is_round_finished(self):
|
|
h = self.is_trick_finished()
|
|
if h and self.num_tricks_played == self.current_round:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def next_round(self):
|
|
max_rounds = len(self.card_deck)/len(self.players)
|
|
if self.current_round <= max_rounds:
|
|
self.current_round += 1
|
|
self.start_player += 1
|
|
if self.start_player >= len(self.players):
|
|
self.start_player = 0
|
|
self.active_player = 0
|
|
self.players_ordered = self.players[self.start_player:] + self.players[:self.start_player]
|
|
self.played_cards.clear()
|
|
self.deal_cards(self.current_round)
|
|
self.num_tricks_played = 0
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def next_trick(self):
|
|
self.last_trick = self.played_cards.copy()
|
|
win = self.get_trick_winner()
|
|
winner = win[0]
|
|
starter = winner.id
|
|
self.players_ordered = self.players[starter:] + self.players[:starter]
|
|
self.active_player = 0
|
|
self.played_cards.clear()
|
|
|
|
def play_card(self, player, card):
|
|
p = self.players[player]
|
|
c = p.play_card(card)
|
|
t = (p, c)
|
|
self.played_cards.append(t)
|
|
self.active_player += 1
|
|
if self.is_trick_finished():
|
|
self.num_tricks_played += 1
|
|
|
|
def set_trump_color(self, trump_color):
|
|
if self.trump_card.value != 'Z':
|
|
return False
|
|
else:
|
|
if trump_color not in ["b", "r", "g", "y"]:
|
|
return False
|
|
else:
|
|
self.trump_card = Card(trump_color, 'Z')
|
|
return True
|
|
|
|
def get_prev_player(self):
|
|
if self.start_player == 0:
|
|
return len(self.players)-1
|
|
else:
|
|
return self.start_player-1
|
|
|
|
async def send_page_reload(self):
|
|
for ws in self.websockets:
|
|
try:
|
|
msg = {"type": "message", "fct": "reload"};
|
|
await ws.send_json(msg)
|
|
except Exception as e:
|
|
pass
|
|
|
|
|
|
p = ["egg", "spam", "ham", "pups", "kekse"]
|
|
the_game = WizGame(p)
|
|
|