# File: GameBase.py # Description: GameBase class and three game classes # Author: ZiTing Wang # Student ID: 2218040103 # This is my own work as defined by # the University's Academic Misconduct Policy. # from Dice import Dice from Player import Player class GameBase: inputPrompt = "> " coinsOfPlayers = {} playerBids = {} allPlayers = {} def __init__(self): self.__helpMsg = '\nWhat would you like to do?\n(n) register a new player\n(c) show your coinsNum\n(s) show ' \ 'the leader board\n(p) play a game\n(q) quit' self.__acceptableOptions = ['n', 'c', 's', 'p', 'q'] def newPlayer(self) -> None: """ New a player :return: None """ print("What is the name of the new player?") name = input(self.inputPrompt) if name in self.allPlayers: print("Sorry, the name is already taken.") else: self.allPlayers[name] = Player(name) print("Welcome, ", name) def printLeaderBoard(self): try: if len(self.allPlayers) == 0: raise ValueError for player in self.allPlayers: self.coinsOfPlayers[player] = self.allPlayers[player].getCoinNum() leaderBoard = sorted(self.coinsOfPlayers.items(), key=lambda k: k[1], reverse=True) print("=============================") print("Name\t\tPlayed\tWon\tCoins") print("=============================") for player in leaderBoard: name = player[0] coinsNum = player[1] print( f"{name}\t\t" f"{self.allPlayers[name].total_round}" f"\t{self.allPlayers[name].win_round}" f"\t{coinsNum}") print("=============================") except ValueError: print("You have no player now!") def queryCoinsNum(self): try: if len(self.allPlayers) == 0: raise ValueError print("=============================") for player in self.allPlayers: print(f"{player}\t\t" f"{self.allPlayers[player].getCoinNum()}") except ValueError: print("No player now!") def startGame(self): print('Which game would you like to play?\n' '(e) Even-or-Odd\n' '(m) Minz\n' '(b) Bunco') game = input(self.inputPrompt) if game not in ['e', 'm', 'b']: print("Invalid choice!") else: self.callGameRun(game) def processInputOptions(self, op: str) -> None: if op == 'n': self.newPlayer() elif op == 's': self.printLeaderBoard() elif op == 'c': self.queryCoinsNum() elif op == 'p': self.startGame() else: raise ValueError def addPlayerToGame(self, minNum, maxNum): """ Add a player :param minNum: :param maxNum: :return: """ print(f"How many players ({minNum}-{maxNum})?") try: numsPlayer = int(input(self.inputPrompt)) if numsPlayer < minNum or numsPlayer > maxNum: raise ValueError for i in range(numsPlayer): while True: print(f"What is the name of player #{i + 1}?") name = input(self.inputPrompt) if name not in self.allPlayers: print(f'There is no player named {name}.') elif name in self.playerBids: print(f'{name} is already in the game.') else: while True: print( f"How many coins would you bid {name} (1-{self.allPlayers[name].getCoinNum()})?") try: coinBids = int(input(self.inputPrompt)) if coinBids > self.allPlayers[name].getCoinNum() or coinBids < 1: raise ValueError else: self.playerBids[name] = coinBids break except ValueError: print("Invalid number of coins.") break except ValueError: print(f"Please input a number between {minNum} and {maxNum}!") self.addPlayerToGame(minNum, maxNum) def playGame(self): """ Start a game :return: """ while True: print(self.__helpMsg) op = input(self.inputPrompt) try: self.processInputOptions(op) except ValueError: print("Sorry! Please retry with a valid command.") def callGameRun(self, gameOp: str) -> None: """ Choose game :param gameOp: """ if gameOp == 'e': game = EvenOrOdd(self.allPlayers) game.playGame() elif gameOp == 'm': game = Minz(self.allPlayers) game.playGame() elif gameOp == 'b': game = Bunco(self.allPlayers) game.playGame() class EvenOrOdd(GameBase): def __init__(self, players): super().__init__() self.__persons = 0 self.allPlayers = players self.player = "" def playGame(self): if len(self.allPlayers) < 1: print("No enough players to play EvenOrOdd!") return dice = Dice() print("Let's play the game of EvenOrOdd!") self.choice = '' self.power = '' print(f"Hey {self.player}, Even (e) or Odd (o)?") while True: self.choice = input(self.inputPrompt) if self.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.inputPrompt)) if self.power > 5 or self.power < 0: raise ValueError else: break except ValueError: print("Invalid choice.") point = dice.getPointOfDice(self.power) result = self.getGuessResult(self.choice, point[0]) print(point[1]) if result: print(f"Congratulations, {self.player}! You win!") self.allPlayers[self.player].win(self.playerBids[self.player]) self.allPlayers[self.player].win_round += 1 self.allPlayers[self.player].total_round += 1 else: print(f"Sorry, {self.player}! You lose!") self.allPlayers[self.player].fail(self.playerBids[self.player]) self.allPlayers[self.player].total_round += 1 def addPlayerToGame(self, minNum, maxNum): """ Add a player :param minNum: :param maxNum: :return: """ while True: print("What is the name of player?") self.player = input(self.inputPrompt) if self.player not in self.allPlayers: print(f'There is no player named {self.player}.') else: while True: print( f"How many coinsNum would you bid {self.player} (1-{self.allPlayers[self.player].getCoinNum()})?") try: input_coin = int(input(self.inputPrompt)) if input_coin > self.allPlayers[self.player].getCoinNum() or input_coin < 1: raise ValueError else: self.playerBids[self.player] = input_coin break except ValueError: print("Invalid number of coinsNum.") break def getGuessResult(self, choice: str, point: int) -> bool: """ Judge the result :return:bool """ isEven = not (point % 2) if choice == 'e' and isEven: return True elif choice == 'o' and isEven: return False elif choice == 'e' and not isEven: return False else: return True class Minz(GameBase): points = {} additionalTurnPlayers = [] def __init__(self, players): super().__init__() self.__persons = 0 self.allPlayers = players def playGame(self): if len(self.allPlayers) < 3: print("No enough players to play Minz!") return print("Let the game begin!") self.addPlayerToGame(3, 5) self.play1Turn() if len(self.additionalTurnPlayers): self.playAdditionalTurn() 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.allPlayers[key].win(self.playerBids[key]) self.allPlayers[key].win_round += 1 self.allPlayers[key].total_round += 1 else: self.allPlayers[key].fail(self.playerBids[key]) self.allPlayers[key].total_round += 1 print(f"Congratulations, {winner}! You win!") def play1Turn(self): reversed = {} self.play1Round(self.playerBids) for key, value in self.points.items(): if value not in reversed: reversed[value] = [key] else: reversed[value].append(key) reversed = sorted(reversed) for key in reversed: if len(reversed[key]) > 1: self.additionalTurnPlayers = reversed[max(reversed, key=lambda k: k[1])] break def playAdditionalTurn(self): self.play1Round(self.additionalTurnPlayers) def play1Round(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.inputPrompt)) if self.power > 5 or self.power < 0: raise ValueError else: break except ValueError: print("Invalid choice.") for i in range(2): point = dice.getPointOfDice(self.power) print(point[1], end=" ") self.points[key] += point[0] print("") class Bunco(GameBase): def __init__(self, players: dict): super().__init__() self.currentPlayer = None self.__persons = 0 self.allPlayers = players self.playerNum = len(self.playerBids) self.playerName = [i for i in self.allPlayers] self.totalScores = {} self.roundWinners = [] self.buncos = {} def playGame(self): if len(self.allPlayers) < 2: print("No enough players to play Bunco!") return self.addPlayerToGame(2, 4) for i in self.allPlayers: self.totalScores[i] = [] for i in self.playerBids: self.buncos[i] = 0 print("Let's play the game of Bunco!") startingPlayer = self.playerName[0] for roundNum in range(1, 7): self.play1Round(roundNum, startingPlayer) self.printResults() def play1Round(self, roundNum, starting_player): print(f"") self.currentPlayer = starting_player round_scores = {} while True: for player in self.playerName: current_total = 0 self.totalScores[player].append(0) print(f"It's {player}'s turn.") roll = self.getResult() points = self.calculateScore(roll, roundNum) current_total += points print(f"You earned {points} points, {current_total} points in total.") while points > 0: self.totalScores[player][roundNum - 1] += points current_total += points if self.totalScores[player][roundNum - 1] >= 21: round_scores[player] = current_total break print(f"Keep playing {player}.") roll = self.getResult() points = self.calculateScore(roll, roundNum) 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 {roundNum}!\n") self.roundWinners.append(round_winner) return def getResult(self) -> list: dice = Dice() self.power = 0 while True: print("How strong will you throw (0-5)?") try: self.power = int(input(self.inputPrompt)) 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.getPointOfDice(self.power) print(point[1], end=" ") points.append(point[0]) print("") return points def printResults(self): roundNum = 1 print("==================================") print("Round", end='\t') for player in self.playerBids: print(player, end='\t') print("") for player in range(6): print(f"\t{roundNum}\t", end="") for player in self.totalScores: print(f"{self.totalScores[player][roundNum - 1]}\t", end="") print("") roundNum += 1 print("==================================") print("Total\t", end="") for player in self.playerName: print(f"{sum(self.totalScores[player])}\t", end="") print("") print("==================================") print("Bunco\t", end="") for player in self.playerName: print(f'{self.buncos[player]}\t', end="") print("") numWins = {} for player in self.playerName: numWins[player] = 0 for player in self.roundWinners: numWins[player] += 1 winner = max(numWins.items(), key=lambda k: k[1])[0] print( f'{winner} won {numWins[winner]} rounds, scoring {sum(self.totalScores[winner])} points, with {self.buncos[winner]} Buncos') print(f'Congratulations, {winner}! You win!') for player in self.playerName: if player == winner: self.allPlayers[player].win(self.playerBids[player]) self.allPlayers[player].win_round += 1 self.allPlayers[player].total_round += 1 else: self.allPlayers[player].fail(self.playerBids[player]) self.allPlayers[player].total_round += 1 def calculateScore(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.currentPlayer] += 1 else: score += 5 for point in roll: if point == round_number: score += 1 return score