# File: Game.py # Description: Game class and three game classes # Author: Yirui Guo # Student ID: 2218040201 # This is my own work as defined by # the University's Academic Misconduct Policy. # from Dice import Dice from Player import Player class Game: players = {} bids = {} def __init__(self): self.prompt = "> " self.__valid_inputs = ['n', 'c', 's', 'p', 'q'] self.__helpMsg = '\nWhat would you like to do?\n(n) register a new player\n(c) show your coins\n(s) show the leader board\n(p) play a game\n(q) quit' def handle_game(self, comm): if comm == 'n': print("What is the name of the new player?") name = input(self.prompt) if name in self.players: print("Sorry, the name is already taken.") else: self.players[name] = Player(name) print("Welcome, ", name) elif comm == 'c': try: if len(self.players) == 0: raise AttributeError print("--------Coins--------") for key in self.players: print(key, self.players[key].get_coins()) except AttributeError: print("You have no player now!") elif comm == 's': try: if len(self.players) == 0: raise AttributeError print("================================") print("Name\t\tPlayed\tWon\tCoins") print("================================") lb = {} for key in self.players: lb[key] = self.players[key].get_coins() top = sorted(lb.items(), key=lambda k: k[1], reverse=True) for key in top: print(f"{key[0]}\t\t{self.players[key[0]].total_round}\t{self.players[key[0]].win_round}\t{key[1]}") print("================================") except AttributeError: print("You have no player now!") elif comm == 'p': print('Which game would you like to play?\n(e) Even-or-Odd\n(m) Minz\n(b) Bunco') user_input = input(self.prompt) if user_input not in ['e', 'm', 'b']: print("Please choose from e, m, b!") else: self.call_game(user_input) else: raise ValueError def set_persons(self, l, r): print(f"How many players ({l}-{r})?") try: user_input = int(input(self.prompt)) if user_input < l or user_input > r: raise ValueError self.__persons = int(user_input) for i in range(self.__persons): while True: print(f"What is the name of player #{i + 1}?") user_input = input(self.prompt) if user_input not in self.players.keys(): print(f'There is no player named {user_input}.') elif user_input in self.bids.keys(): print(f'{user_input} is already in the game.') else: while True: print( f"How many coins would you bid {user_input} (1-{self.players[user_input].get_coins()})?") try: input_coin = int(input(self.prompt)) if input_coin > self.players[user_input].get_coins() or input_coin < 1: raise ValueError else: self.bids[user_input] = input_coin break except ValueError: print("Invalid number of coins.") break except ValueError: print(f"Please input a number between {l} and {r}!") self.set_persons(l, r) def play_game(self): while True: print(self.__helpMsg) user_input = input(self.prompt) try: self.handle_game(user_input) except ValueError: print("Sorry! Please retry with a valid command.") def call_game(self, comm: str) -> None: """ Choose game :param comm: """ if comm == 'e': game = EvenOrOdd(self.players) game.play_game() elif comm == 'm': game = Minz(self.players) game.play_game() elif comm == 'b': game = Bunco(self.players) game.play_game() class Minz(Game): points = {} additional_turns_players = [] def __init__(self, players): super().__init__() self.__persons = 0 self.players = players def play_game(self): if len(self.players) < 3: print("No enough players to play EvenOrOdd!") return print("Let the game begin!") self.set_persons(3,5) self.the_first_turn() if len(self.additional_turns_players): self.the_second_turn() sorted(self.points.items(), key=lambda d: d[1]) print("-----RESULT-----") for point in self.points: print(point, self.points[point]) print("") winner = max(self.points.items(), key=lambda d: d[1]) winner = winner[0] for key in self.points: if key == winner: self.players[key].win(self.bids[key]) self.players[key].win_round += 1 self.players[key].total_round += 1 else: self.players[key].lose(self.bids[key]) self.players[key].total_round += 1 print(f"Congratulations, {winner}! You win!") def the_first_turn(self): flipped = {} self.turn(self.bids) for key, value in self.points.items(): if value not in flipped: flipped[value] = [key] else: flipped[value].append(key) flipped = sorted(flipped) for key in flipped: if len(flipped[key]) > 1: self.additional_turns_players = flipped[max(flipped, key=lambda k: k[1])] break def the_second_turn(self): self.turn(self.additional_turns_players) def turn(self, players): dice = Dice() for key in players: choice = '' self.power = '' print(f"It's {key}'s turn.") self.points[key] = 0 while True: print("How strong will you throw (0-5)?") try: self.power = int(input(self.prompt)) if self.power > 5 or self.power < 0: raise ValueError else: break except ValueError: print("Invalid choice.") for i in range(2): point = dice.get_point_of_dice(self.power) print(point[1], end=" ") self.points[key] += point[0] print("") class EvenOrOdd(Game): def __init__(self, players): super().__init__() self.__persons = 0 self.players = players self.player = "" def play_game(self): if len(self.players) < 1: print("No enough players to play EvenOrOdd!") return dice = Dice() print("Let's play the game of EvenOrOdd!") while True: print("What is the name of player?") self.player = input(self.prompt) if self.player not in self.players: print(f'There is no player named {self.player}.') else: while True: print( f"How many coins would you bid {self.player} (1-{self.players[self.player].get_coins()})?") try: input_coin = int(input(self.prompt)) if input_coin > self.players[self.player].get_coins() or input_coin < 1: raise ValueError else: self.bids[self.player] = input_coin break except ValueError: print("Invalid number of coins.") break choice = '' self.power = '' print(f"Hey {self.player}, Even (e) or Odd (o)?") while True: choice = input(self.prompt) if choice not in ('e', 'o'): print("Invalid choice.") print("Even (e) or Odd (o)?") else: break while True: print("How strong will you throw (0-5)?") try: self.power = int(input(self.prompt)) if self.power > 5 or self.power < 0: raise ValueError else: break except ValueError: print("Invalid choice.") point = dice.get_point_of_dice(self.power) result = self.get_result(choice, point[0]) print(point[1]) if result: print(f"Congratulations, {self.player}! You win!") self.players[self.player].win(self.bids[self.player]) self.players[self.player].win_round += 1 self.players[self.player].total_round += 1 else: print(f"Sorry, {self.player}! You lose!") self.players[self.player].lose(self.bids[self.player]) self.players[self.player].total_round += 1 def get_result(self, choice: str, point: int) -> bool: is_even = not (point % 2) print(is_even) if choice == 'e' and is_even: return True elif choice == 'o' and is_even: return False elif choice == 'e' and not is_even: return False else: return True class Bunco(Game): def __init__(self, players: dict): super().__init__() self.current_player = None self.__persons = 0 self.players = players self.set_persons(2, 4) self.num_players = len(self.bids) self.player_names = [i for i in self.players] self.scores = {} self.round_winners = [] for _ in self.bids: self.scores[_] = [] self.buncos = {} for _ in self.bids: self.buncos[_] = 0 def play_game(self): if len(self.players) < 2: print("No enough players to play EvenOrOdd!") return print("Let's play the game of Bunco!") starting_player = self.player_names[0] for round_number in range(1, 7): self.play_round(round_number, starting_player) self.print_results() def play_round(self, round_number, starting_player): print(f"") self.current_player = starting_player round_scores = {} while True: for player in self.player_names: current_total = 0 self.scores[player].append(0) print(f"It's {player}'s turn.") roll = self.roll_dice() points = self.calc_score(roll, round_number) current_total += points print(f"You earned {points} points, {current_total} points in total.") while points > 0: self.scores[player][round_number - 1] += points current_total += points if self.scores[player][round_number - 1] >= 21: round_scores[player] = current_total break print(f"Keep playing {player}.") roll = self.roll_dice() points = self.calc_score(roll, round_number) current_total += points print(f"You earned {points} points, {current_total} points in total.") round_scores[player] = current_total round_winner = (max(round_scores.items(), key=lambda k: k[1]))[0] print(f"{round_winner} is the winner in round {round_number}!\n") self.round_winners.append(round_winner) return def roll_dice(self) -> list: dice = Dice() self.power = 0 while True: print("How strong will you throw (0-5)?") try: self.power = int(input(self.prompt)) if self.power > 5 or self.power < 0: raise ValueError else: break except ValueError: print("Invalid choice.") points = [] for i in range(3): point = dice.get_point_of_dice(self.power) print(point[1], end=" ") points.append(point[0]) print("") return points def print_results(self): print("======================================") print("Round", end='\t') for i in range(self.num_players): print(self.player_names[i], end='\t') print("") round_number = 1 for i in range(6): print(f"\t{round_number}\t", end="") for key in self.scores: print(f"{self.scores[key][round_number - 1]}\t", end="") print("") round_number += 1 print("======================================") print("Total\t", end="") for key in self.player_names: print(f"{sum(self.scores[key])}\t", end="") print("") print("======================================") print("Bunco\t", end="") for key in self.player_names: print(f'{self.buncos[key]}\t', end="") print("") round_wins = {} for i in self.player_names: round_wins[i] = 0 for i in self.round_winners: round_wins[i] += 1 winner = max(round_wins.items(), key=lambda k: k[1])[0] print( f'{winner} won {round_wins[winner]} rounds, scoring {sum(self.scores[winner])} points, with {self.buncos[winner]} Buncos') print(f'Congratrulations, {winner}! You win!') for i in self.player_names: if i == winner: self.players[i].win(self.bids[i]) self.players[i].win_round += 1 self.players[i].total_round += 1 else: self.players[i].lose(self.bids[i]) self.players[i].total_round += 1 def calc_score(self, roll: list[int], round_number): score = 0 point = roll[0] if roll[0] == roll[1] == roll[2]: if point == round_number: score += 21 self.buncos[self.current_player] += 1 else: score += 5 for point in roll: if point == round_number: score += 1 return score if __name__ == '__main__': game = Bunco({'a': Player('a'), 'b': Player('b')}) game.play_game()