455 lines
16 KiB
Python
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
|