cowiz20/wiz_game.py

235 lines
6.9 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, idx=None):
self.color = color
self.value = value
self.idx = idx
def __str__(self):
sc = self.color if self.color else ' '
sv = str(self.value)
return sc+' '+sv
def __repr__(self):
return str(self)
def json_serialise(self):
if self.color and self.color != '-':
s = "{}{:02d}".format(self.color, self.value)
else:
s = "{}{}".format(self.value, self.idx)
return s
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 = []
self.ws_tasks = []
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 idx in range(1, 5):
self.card_deck.append(Card('-', 'Z', idx))
for idx in range(1, 5):
self.card_deck.append(Card('-', 'N', idx))
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 = ["spam", "egg", "ham", "tomato"]
the_game = WizGame(p)