From 9b0e5424aec1819074fa2d76c13f7dc2916e76ba Mon Sep 17 00:00:00 2001 From: lfitchlee Date: Mon, 17 Nov 2025 09:42:28 -0500 Subject: [PATCH] I made all the rolls in yahtzee and got a score 294 --- play.py | 27 +++++++- yahtzee.py | 15 ++++- yahtzee_goals.py | 161 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 4 deletions(-) diff --git a/play.py b/play.py index 773f7f3..e91c9e2 100644 --- a/play.py +++ b/play.py @@ -1,15 +1,36 @@ from yahtzee import Yahtzee from yahtzee_goals import ( - GoalOnes, - GoalTwos, + GoalOnes, + GoalTwos, GoalThrees, + GoalFours, + GoalFives, + GoalSixes, + GoalThreeOfAKind, + GoalFourOfAKind, + GoalFullHouse, + GoalSmallStraight, + GoalLargeStraight, + GoalYahtzee, + GoalChance, ) goals = [ - GoalOnes(), + GoalOnes(), GoalTwos(), GoalThrees(), + GoalFours(), + GoalFives(), + GoalSixes(), + GoalThreeOfAKind(), + GoalFourOfAKind(), + GoalFullHouse(), + GoalSmallStraight(), + GoalLargeStraight(), + GoalYahtzee(), + GoalChance(), ] + game = Yahtzee(goals) game.play() diff --git a/yahtzee.py b/yahtzee.py index 69b0e97..e1ad710 100644 --- a/yahtzee.py +++ b/yahtzee.py @@ -5,12 +5,14 @@ class Yahtzee: This version of Yahtzee is initialized with a list of goals. """ def __init__(self, goals): + "starts a Yahtzee game." self.score = 0 self.goals = goals self.dice = [Die() for num in range(5)] def play(self): - print("Welcome to Yachtzee!") + "Run the main game loop until all goals are reached." + print("Welcome to Yahtzee!") self.score = 0 for goal in self.goals: goal.used = False @@ -19,6 +21,7 @@ class Yahtzee: print(f"Your final score was {self.score}") def play_round(self): + "Play a single round: roll, allow rerolls, choose a goal, and score." print("=" * 80) self.rolls_left = 3 for die in self.dice: @@ -29,10 +32,12 @@ class Yahtzee: self.score += goal.score(self.dice) def show_status(self): + "Display the current game status to the player" 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): + "Prompt the player to pick a scoring goal or re-roll" options = [] unused_goals = self.get_unused_goals() for goal in unused_goals: @@ -49,6 +54,7 @@ class Yahtzee: return unused_goals[choice] def get_choice(self, options): + "Prompt the user to select one option from a list of options." print("What would you like to do?") for i, option in enumerate(options): print(f"{i}. {option}") @@ -59,6 +65,7 @@ class Yahtzee: return int(choice) def option_choice_is_valid(self, choice, options): + "Validate that a user's option choice string is an allowed index." if not choice.isdigit(): return False if int(choice) < 0: @@ -68,9 +75,11 @@ class Yahtzee: return True def count_unused_goals(self): + "Return the number of goals that haven't been used yet." return len(self.get_unused_goals()) def get_unused_goals(self): + "Return a list of goal objects that are not yet used." unused_goals = [] for goal in self.goals: if not goal.used: @@ -78,6 +87,7 @@ class Yahtzee: return unused_goals def reroll(self): + "Perform a reroll of selected dice and decrement available rerolls." self.rolls_left -= 1 choices = self.get_reroll_choices() dice_to_reroll = self.get_dice_to_reroll(choices) @@ -85,6 +95,7 @@ class Yahtzee: die.roll() def get_dice_to_reroll(self, choice_ints): + "Map a list of face-value integers to Die objects to reroll." dice_to_reroll = [] for die in self.dice: if die.face in choice_ints: @@ -93,6 +104,7 @@ class Yahtzee: return dice_to_reroll def get_reroll_choices(self): + "Ask the user which dice (by face value digits) to reroll." print("Which dice do you want to re-roll?") choices = input("> ") while not self.reroll_choices_are_valid(choices): @@ -102,6 +114,7 @@ class Yahtzee: return choice_ints def reroll_choices_are_valid(self, choices_str): + "Validate that the reroll choice string corresponds to existing dice." if not choices_str.isdigit(): return False choice_ints = [int(digit) for digit in choices_str] diff --git a/yahtzee_goals.py b/yahtzee_goals.py index 10af574..16e8d93 100644 --- a/yahtzee_goals.py +++ b/yahtzee_goals.py @@ -40,3 +40,164 @@ class GoalThrees: if die.face == 3: total += 3 return total + + +class GoalFours: + "Four points for each four" + + def prompt(self, dice): + potential_score = self.score(dice) + return f"Fours ({potential_score})" + + def score(self, dice): + total = 0 + for die in dice: + if die.face == 4: + total += 4 + return total + + +class GoalFives: + "Five points for each five" + + def prompt(self, dice): + potential_score = self.score(dice) + return f"Fives ({potential_score})" + + def score(self, dice): + total = 0 + for die in dice: + if die.face == 5: + total += 5 + return total + + +class GoalSixes: + "Six points for each six" + + def prompt(self, dice): + potential_score = self.score(dice) + return f"Sixes ({potential_score})" + + def score(self, dice): + total = 0 + for die in dice: + if die.face == 6: + total += 6 + return total + + +class GoalThreeOfAKind: + "Sum all dice if there are at least three of the same face" + + def prompt(self, dice): + potential_score = self.score(dice) + return f"Three of a kind ({potential_score})" + + def score(self, dice): + counts = {} + total = 0 + for die in dice: + counts[die.face] = counts.get(die.face, 0) + 1 + total += die.face + for cnt in counts.values(): + if cnt >= 3: + return total + return 0 + + +class GoalFourOfAKind: + "Sum all dice if there are at least four of the same face" + + def prompt(self, dice): + potential_score = self.score(dice) + return f"Four of a kind ({potential_score})" + + def score(self, dice): + counts = {} + total = 0 + for die in dice: + counts[die.face] = counts.get(die.face, 0) + 1 + total += die.face + for cnt in counts.values(): + if cnt >= 4: + return total + return 0 + + +class GoalFullHouse: + "Fixed score when three of one face and two of another are present" + + def prompt(self, dice): + potential_score = self.score(dice) + return f"Full House ({potential_score})" + + def score(self, dice): + counts = {} + for die in dice: + counts[die.face] = counts.get(die.face, 0) + 1 + values = sorted(counts.values()) + # Full house is a 2 and a 3 + if values == [2, 3]: + return 25 + return 0 + + +class GoalSmallStraight: + "Fixed score for any run of four consecutive face values" + + def prompt(self, dice): + potential_score = self.score(dice) + return f"Small Straight ({potential_score})" + + def score(self, dice): + faces = sorted({die.face for die in dice}) + # Check for any sequence of length 4 + runs = [faces[i:i+4] for i in range(len(faces) - 3)] + for run in runs: + if run == list(range(run[0], run[0] + 4)): + return 30 + return 0 + + +class GoalLargeStraight: + "Fixed score for a run of five consecutive face values" + + def prompt(self, dice): + potential_score = self.score(dice) + return f"Large Straight ({potential_score})" + + def score(self, dice): + faces = sorted({die.face for die in dice}) + if faces == list(range(1, 6)) or faces == list(range(2, 7)): + return 40 + return 0 + + +class GoalYahtzee: + "Fixed score for five of a kind (Yahtzee)" + + def prompt(self, dice): + potential_score = self.score(dice) + return f"Yahtzee ({potential_score})" + + def score(self, dice): + first = dice[0].face + for die in dice: + if die.face != first: + return 0 + return 50 + + +class GoalChance: + "Sum of all dice (always available)" + + def prompt(self, dice): + potential_score = self.score(dice) + return f"Chance ({potential_score})" + + def score(self, dice): + total = 0 + for die in dice: + total += die.face + return total