python-archieve-projects/M3101/1/GameBase.py

455 lines
16 KiB
Python

# 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"<Round {roundNum}>")
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