lab_dice/yahtzee.py

145 lines
5.4 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)]
def play(self):
"""While there is still avaiable goals, keep playing the game.
When the game is over, print the final score"""
print("Welcome to Yachtzee!")
while self.count_unused_goals() > 0:
self.play_round()
print(f"Your final score was {self.score}")
def play_round(self):
"""Show the image of an equal sign 80 times in a row.
Define the remaining rolls is three.
Roll all five dice.
Show the result of the row.
Ask the user to choose the goal.
Mark the goal as used.
Add score from this round to the total score"""
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)
def show_status(self):
"""show the list numbers on the dice with comma and a space.
Show the score and the remaining rolls."""
dice = ', '.join([str(die) for die in self.dice])
print(f"Score: {self.score}. Rolls left: {self.rolls_left}. Dice: {dice}.")
def choose_goal(self):
"""Build the selection menu for the user, and ask the user to select
one option.
If there is no avaiable roll, then the option for 'reroll' will not be shown.
If the user's choice is 're-roll', then the user roll the dice again, and
this fuction gets called again.
If the user choose the goal, it will return the selected goal."""
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]
def get_choice(self, options):
"""Ask the user the input. And print the avaiable choices.
Check if the choice is valid, if not, ask again. if valid, then return
the choice"""
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)
def option_choice_is_valid(self, choice, options):
"""if the users provide non-digit or a number that is less than zero
or a number that are greater than the maxium option number, then return
false. If valid, return true."""
if not choice.isdigit():
return False
if int(choice) < 0:
return False
if int(choice) >= len(options):
return False
return True
def count_unused_goals(self):
"""get list of unused goals, and returen its length. """
return len(self.get_unused_goals())
def get_unused_goals(self):
"""Iterate through all possible goals, and return a list containing
only the unused goals."""
unused_goals = []
for goal in self.goals:
if not goal.used:
unused_goals.append(goal)
return unused_goals
def reroll(self):
"""Subtract 1 from the avaiable rolls, then ask the user which dice he
or she wants to roll
And then, roll them"""
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()
def get_dice_to_reroll(self, choice_ints):
""" Loop through all dies, if the die face is in the list of the number
the user wants to reroll, then add it to the reroll """
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
def get_reroll_choices(self):
"""Asks the user to input the numbers to reroll, check the selection is
valid, and if it is, return it. """
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
def reroll_choices_are_valid(self, choices_str):
"""Check the user input is valid choice for the die number, for example,
if the input is not digit, return false. Then, check the input number
appears on the die face."""
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