generated from mwc/lab_dice
While writing the docstrings I needed to go through all the code to understand what it was doing and then run the simulation to experience wgat was written before I could descrbe it. I also had to go back and forth between methods. I think writing docstrings are super helpful in determining how the code works or what we want our code to do. It is similar to writing out objectives.
144 lines
5.1 KiB
Python
144 lines
5.1 KiB
Python
from die import Die
|
|
|
|
class Yahtzee:
|
|
"""A command-line Yahtzee game.
|
|
This version of Yahtzee is initialized with a list of goals.
|
|
"""
|
|
def __init__(self, goals):
|
|
"""Initializes the scores to 0, a list of goals, and creates 5 dice for the game to roll
|
|
"""
|
|
self.score = 0
|
|
self.goals = goals
|
|
self.dice = [Die() for num in range(5)]
|
|
|
|
def play(self):
|
|
"""Runs the full Yahtzee game until all goals are used.
|
|
Resets the score and marks all goals as unused. Then plays the rounds until no more goals can be used and displays the final score.
|
|
"""
|
|
print("Welcome to Yachtzee!")
|
|
self.score = 0
|
|
for goal in self.goals:
|
|
goal.used = False
|
|
while self.count_unused_goals() > 0:
|
|
self.play_round()
|
|
print(f"Your final score was {self.score}")
|
|
|
|
def play_round(self):
|
|
"""Runs one round of Yahtzee.
|
|
Rolls all five dice and displays the status of the round, allows player to choose a goal and marks it as used, and tallies up 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):
|
|
"""Displays the current score, rolls left, and dice faces.
|
|
"""
|
|
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):
|
|
"""Asks the player to choose a goal or roll the dice.
|
|
Displays the unused goals and the potential score.
|
|
Keeps track of re-rolls and unused goals until player only has one option left.
|
|
"""
|
|
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):
|
|
"""Prompts the player to select an option from the list of goals and re-rolls.
|
|
Displays all available choices with indices. Validates user input and returns the index of the option selected.
|
|
"""
|
|
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):
|
|
"""Ensures that the player's option is valid.
|
|
Checks if the input is within the provided options and returns true or false accordingly.
|
|
"""
|
|
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):
|
|
"""Returns the number of unused goals
|
|
"""
|
|
return len(self.get_unused_goals())
|
|
|
|
def get_unused_goals(self):
|
|
"""Returns a list of unused gials by iterating through all goals and collecting False occurences
|
|
"""
|
|
unused_goals = []
|
|
for goal in self.goals:
|
|
if not goal.used:
|
|
unused_goals.append(goal)
|
|
return unused_goals
|
|
|
|
def reroll(self):
|
|
"""Re-rolls the selected dice
|
|
"""
|
|
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):
|
|
"""Determines which dice needs to be re-rolled based on player input.
|
|
"""
|
|
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):
|
|
"""Prompts player to enter which dice values to re-roll.
|
|
"""
|
|
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):
|
|
"""Validates player input for dice to re-roll.
|
|
"""
|
|
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
|