python-archieve-projects/M3101/2/Game.py

415 lines
15 KiB
Python

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