from random import shuffle from typing import List, Dict, Optional from collections import deque nums = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'] suits = ['H', 'S', 'D', 'C'] def get_deck(add_jokers: bool=False) -> deque: if add_jokers: jokers = ['J', 'J'] else: jokers = [] return deque([n + s for n in nums for s in suits] + jokers) def create_new_random_card_deck(add_jokers: bool=False) -> deque: deck = get_deck(add_jokers) shuffle(deck) return deck class CamelGame: deck: deque ace_position: dict side_list: list side_length = 8 side_open = 0 state: str bets: List[Dict] def __init__(self): self.deck = create_new_random_card_deck(False) for ace in ['AH', 'AS', 'AD', 'AC']: self.deck.remove(ace) # remove the aces self.ace_position = { 'AH': 0, 'AS': 0, 'AD': 0, 'AC': 0, } self.side_list = [] self.state = None self.bets = [] def init_game(self): for _ in range(self.side_length): self.side_list.append(self.deck.pop()) self.state = 'initialized' def do_round(self) -> Optional[str]: if self.state != 'active': print("Game is not stated yet or already done") return None card = self.popcard() if any(v == self.side_length for v in self.ace_position.values()): self.state = 'done' return card def bet(self, user: str, suit: str, amount: int) -> bool: if self.state != 'initialized': return False if any(b['user'] == user for b in self.bets): return False if suit not in suits: return False self.bets.append({'user': user, 'suit': suit, 'amount': amount}) return True def start_game(self): if self.state != 'initialized': return False self.state = 'active' return True def get_drinks(self) -> Optional[Dict]: if self.state != 'done': return None result = {} winner = self.get_winner()[-1] drinks = sum(map(lambda b: b['amount'], filter(lambda b: b['suit'] == winner, self.bets))) for bet in self.bets: if bet['suit'] == winner: mdrinks = 0 else: mdrinks = drinks + bet['amount'] result[bet['user']] = mdrinks return result def get_winner(self) -> Optional[str]: for card, pos in self.ace_position.items(): if pos == self.side_length: return card return None def get_open_side_cards(self) -> list: open_cards = self.side_list[:self.side_open] return open_cards + ['XX'] * (self.side_length - self.side_open) def popcard(self) -> str: next_card = self.deck.pop() move_card = 'A' + next_card[-1] self.ace_position[move_card] += 1 self.check_and_open_side() return move_card def check_and_open_side(self): if not all(v > self.side_open for v in self.ace_position.values()): return opened_card = self.side_list[self.side_open] moved_ace = 'A' + opened_card[-1] self.ace_position[moved_ace] = self.side_open self.side_open += 1