lab_dice/yahtzee.py

161 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.
"""
def __init__(self, goals):
self.score = 0
self.goals = goals
self.dice = [Die() for num in range(5)]
""" This method will start a yahtzee game and play rounds until the number
of goals that have yet to be used reaches 0. Once there are no more goals left,
it prints the 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}")
""" This method plays one round of Yachtzee. Each round starts with 3 rolls remaining,
then will roll all dice, show the status of each die, and then allow the user to choose
their goal (3 of a kind, full house, etc.) Once someone uses a goal it takes note by
setting goal.used to true, and then adds the score for that goal based on their rolls
to their total score.
"""
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)
""" This method prints the current score, number of rolls left, and the list of dice
with their current status.
"""
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}.")
""" This method lets the player choose which goal they are going to use during
that round. It starts by generating an empty array of the options, and then adding all
of the unused goals to the options arrayIf they have 1 or more re-rolls left, it adds
that to the list of options. Then it asks the user for their choice of goal. If they
choose re-roll it calls reroll and then recursively calls choose_goal.
"""
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]
""" This method gets the choice that the user wants for the goal that they
"""
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)
""" This method will determine if the die choice the user makes is valid or not based
on whether they have entered a number and that it is positive and less than the
length of the list of dice.
"""
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
"""This method returns a count of how many goals have not been used by the user by finding the
length of the array containing the unused goals."""
def count_unused_goals(self):
return len(self.get_unused_goals())
""" This method returns which goals the user hasn't used yet. It starts by setting the
array of unused goals to be empty. Then for each goal in the goals list, if it hasn't
been used, it is appended to the unused goals array. After traversing the goals list
it returns the unused goals list with the unused goals in it.
"""
def get_unused_goals(self):
unused_goals = []
for goal in self.goals:
if not goal.used:
unused_goals.append(goal)
return unused_goals
""" This method will reroll the dice. It first reduces the number of rolls left by 1
andthen gets the choices the user has for which dice to reroll and assigns those to the
choices variable and then adds those to the array dice_to_reroll and rolls 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()
""" This method gets the dice that will be rerolled. for each die in the array, if
it's face (current status) is in the choices provided, it will remove the die and then
add a new die with a random roll. Lastly it returns the new array.
"""
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
""" This method returns the dice the user would like to select for rerolling
While the choices the user selects are not valid, it prompts the user to enter
the numbers on the dice they want to reroll. Note: the user should not enter the
index of the dice, but the current face of the dice. Once the user enters the dice
it adds those to an array containing the choices and returns it.
"""
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
""" This method checks if the choices the user has for rerolling are valid. If the
choices are not in the list of dice faces, then it will return false. It takes the
string of choices and stores each digit in the array choice ints. then for each
die in the array of dice, if the die is in the choices array, it will remove it from
the choices array. Finally, it returns whether the choices array is 0. If it is, that
means all the choices were valid and will return true. If not, at least one choice was
not valid and it will return false.
"""
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