generated from mwc/lab_dice
156 lines
6.8 KiB
Python
156 lines
6.8 KiB
Python
from die import Die
|
|
|
|
class Yachtzee:
|
|
"""A command-line Yahtzee game.
|
|
This version of Yahtzee is initialized with a list of goals.
|
|
"""
|
|
"""Sets up a new game.
|
|
Sets the users score to zero, sets the goals for this game
|
|
to the inputted goals and creates the five dice that will
|
|
be used in the game (5 ints in a list).
|
|
"""
|
|
def __init__(self, goals):
|
|
self.score = 0
|
|
self.goals = goals
|
|
self.dice = [Die() for num in range(5)]
|
|
"""Controls the entire game.
|
|
Welcomes the user to the game with a print statement, then
|
|
keeps starting additional rounds until all of the goals have
|
|
been used. Then, prints out the users final score."""
|
|
def play(self):
|
|
print("Welcome to Yachtzee!")
|
|
while self.count_unused_goals() > 0:
|
|
self.play_round()
|
|
print(f"Your final score was {self.score}")
|
|
"""Controls each round.
|
|
Prints characters to seperate the lines of text, then will roll
|
|
the dice and show the user the outcome. Will let the user choose
|
|
their goal. Once the user is done rolling, marks the goal as used
|
|
and adds to their score the necessary amount"""
|
|
def play_round(self):
|
|
print("=" * 80)
|
|
self.rolls_left = 3
|
|
for die in self.dice:
|
|
die.roll()
|
|
self.show_status()
|
|
goal = self.choose_goal()
|
|
goal.used = True
|
|
self.score += goal.score(self.dice)
|
|
"""Shows the user their status in round.
|
|
Prints a statement telling them their score, the rolls they have
|
|
left in that round and the current dice values"""
|
|
def show_status(self):
|
|
dice = ', '.join([str(die) for die in self.dice])
|
|
print(f"Score: {self.score}. Rolls left: {self.rolls_left}. Dice: {dice}.")
|
|
"""Allows the user to chose what they want to do next.
|
|
Creates list of possible actions by appending unsued goals and the
|
|
Re-roll option if they have rolls left to to use. Then, gets the
|
|
users choice. If they chose to re-roll, the dice will reroll and the
|
|
dice will be shown and the process restarts until the user choses a non
|
|
Re-roll option. Then that option is removed from the list of options and
|
|
the function ends."""
|
|
def choose_goal(self):
|
|
options = []
|
|
unused_goals = self.get_unused_goals()
|
|
for goal in unused_goals:
|
|
option = goal.prompt(self.dice)
|
|
options.append(option)
|
|
if self.rolls_left > 0:
|
|
options.append("Re-roll")
|
|
choice = self.get_choice(options)
|
|
if options[choice] == "Re-roll":
|
|
self.reroll()
|
|
self.show_status()
|
|
return self.choose_goal()
|
|
else:
|
|
return unused_goals[choice]
|
|
"""Obtains the users decision of what to do next.
|
|
Prints a statement asking the user what they would like to do and prints
|
|
every individual optioned all numbered. If the choice is valid, the choice
|
|
is outputted as an integer. If the choice is not valid, the user is told
|
|
this by a print statement and the user is asked to make a choice again
|
|
"""
|
|
def get_choice(self, options):
|
|
print("What would you like to do?")
|
|
for i, option in enumerate(options):
|
|
print(f"{i}. {option}")
|
|
choice = input("> ")
|
|
while not self.option_choice_is_valid(choice, options):
|
|
print("Sorry, that's not a valid choice.")
|
|
choice = input("> ")
|
|
return int(choice)
|
|
"""Ensures that the users choice is valid.
|
|
Ensures that the inputted value is a number, is not less than zero and
|
|
is not greater than the total number of options. If all of these tests
|
|
pass, True will be returned. Otherwise, False will be returned."""
|
|
def option_choice_is_valid(self, choice, options):
|
|
if not choice.isdigit():
|
|
return False
|
|
if int(choice) < 0:
|
|
return False
|
|
if int(choice) >= len(options):
|
|
return False
|
|
return True
|
|
"""Determines how many goals have not been used yet.
|
|
Returns the length of the list of the unused goals."""
|
|
def count_unused_goals(self):
|
|
return len(self.get_unused_goals())
|
|
"""Makes a list of all unused goals.
|
|
Creates an empty list then appends any goal that has not
|
|
been mark as used."""
|
|
def get_unused_goals(self):
|
|
unused_goals = []
|
|
for goal in self.goals:
|
|
if not goal.used:
|
|
unused_goals.append(goal)
|
|
return unused_goals
|
|
"""Manages the reroll process.
|
|
First it reduces the number of rolls left by one. Then, it obtains
|
|
any choices leftover, checks what dice the user wants to reroll,
|
|
then it rerolls them."""
|
|
def reroll(self):
|
|
self.rolls_left -= 1
|
|
choices = self.get_reroll_choices()
|
|
dice_to_reroll = self.get_dice_to_reroll(choices)
|
|
for die in dice_to_reroll:
|
|
die.roll()
|
|
"""Obtains the dice to be rerolled.
|
|
Creates an empty list, then checks each dice, seeing if the user
|
|
wants to reroll it. If so, it appends it to the aformentioned list. Then
|
|
it returns the dice to be rerolled."""
|
|
def get_dice_to_reroll(self, choice_ints):
|
|
dice_to_reroll = []
|
|
for die in self.dice:
|
|
if die.face in choice_ints:
|
|
choice_ints.remove(die.face)
|
|
dice_to_reroll.append(die)
|
|
return dice_to_reroll
|
|
"""Figures out which dice the user wants to reroll.
|
|
Prints a statement asking the user which dice they want to reroll. If the
|
|
requested dice are valid choices, then a list of the chosen dice as integers
|
|
is returned."""
|
|
def get_reroll_choices(self):
|
|
print("Which dice do you want to re-roll?")
|
|
choices = input("> ")
|
|
while not self.reroll_choices_are_valid(choices):
|
|
print("Please enter the numbers on dice you want to re-roll.")
|
|
choices = input("> ")
|
|
choice_ints = [int(digit) for digit in choices]
|
|
return choice_ints
|
|
"""Ensures the dice the user requested to reroll are valid.
|
|
Checks that the requested dice all are numbers. If so, a list of them as integers
|
|
is made. This list is iterated through ensuring that each requested dice is there.
|
|
It accomplishes this by checking the dice we have one by one and removing them
|
|
from the choice list created before if they are in the choice list. We then return
|
|
false if in the end, the choice list is not empty. Meaning, if dice
|
|
we dont have are requested to be rerolled, such as too many dice (ex. 6) more of a
|
|
face than we have, False will be returned. Otherwise, True will be returned."""
|
|
def reroll_choices_are_valid(self, choices_str):
|
|
if not choices_str.isdigit():
|
|
return False
|
|
choice_ints = [int(digit) for digit in choices_str]
|
|
for die in self.dice:
|
|
if die.face in choice_ints:
|
|
choice_ints.remove(die.face)
|
|
return len(choice_ints) == 0
|