lab_dice/yahtzee.py

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