generated from mwc/lab_dice
Compare commits
No commits in common. "d03e66ba50a1b7a0f7fa05768875bf049676f7d8" and "c9fd4f86b3edb7453924cf3546e9effc9708ea54" have entirely different histories.
d03e66ba50
...
c9fd4f86b3
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,6 +1,5 @@
|
|||
from die import Die
|
||||
from tqdm import tqdm
|
||||
from collections import Counter
|
||||
|
||||
class FiveDice:
|
||||
def __init__(self):
|
||||
|
@ -19,44 +18,16 @@ class FiveDice:
|
|||
if face != 1:
|
||||
return False
|
||||
return True
|
||||
def is_three_of_a_kind(self):
|
||||
c = Counter(self.faces())
|
||||
of_a_kind = max(c.values())
|
||||
if (of_a_kind >= 3):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def is_four_of_a_kind(self):
|
||||
c = Counter(self.faces())
|
||||
of_a_kind = max(c.values())
|
||||
if (of_a_kind >= 4):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
dice = FiveDice()
|
||||
successes_3 = 0
|
||||
trials_3 = 1000000
|
||||
for trial in tqdm(range(trials_3)):
|
||||
successes = 0
|
||||
trials = 1000000
|
||||
for trial in tqdm(range(trials)):
|
||||
dice.roll()
|
||||
if dice.is_three_of_a_kind():
|
||||
successes_3 += 1
|
||||
if dice.all_ones():
|
||||
successes += 1
|
||||
|
||||
print(successes_3/trials_3)
|
||||
|
||||
successes_4 = 0
|
||||
trials_4 = 1000000
|
||||
for trial in tqdm(range(trials_4)):
|
||||
dice.roll()
|
||||
if dice.is_four_of_a_kind():
|
||||
successes_4 += 1
|
||||
|
||||
print(successes_4/trials_4)
|
||||
|
||||
test_dice = FiveDice()
|
||||
counter = Counter(test_dice.faces())
|
||||
print(counter.keys())
|
||||
print(successes/trials)
|
||||
|
||||
|
||||
|
||||
|
|
20
play.py
20
play.py
|
@ -3,32 +3,12 @@ from yahtzee_goals import (
|
|||
GoalOnes,
|
||||
GoalTwos,
|
||||
GoalThrees,
|
||||
GoalFours,
|
||||
GoalFives,
|
||||
GoalSixes,
|
||||
Goal_Three_of_a_Kind,
|
||||
Goal_Four_of_a_Kind,
|
||||
GoalFullHouse,
|
||||
GoalSmallStraight,
|
||||
GoalLargeStraight,
|
||||
GoalYahtzee,
|
||||
GoalChance
|
||||
)
|
||||
|
||||
goals = [
|
||||
GoalOnes(),
|
||||
GoalTwos(),
|
||||
GoalThrees(),
|
||||
GoalFours(),
|
||||
GoalFives(),
|
||||
GoalSixes(),
|
||||
Goal_Three_of_a_Kind(),
|
||||
Goal_Four_of_a_Kind(),
|
||||
GoalFullHouse(),
|
||||
GoalSmallStraight(),
|
||||
GoalLargeStraight(),
|
||||
GoalYahtzee(),
|
||||
GoalChance()
|
||||
]
|
||||
|
||||
game = Yachtzee(goals)
|
||||
|
|
|
@ -3,6 +3,7 @@ name = "lab-dice"
|
|||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Chris Proctor <chris@chrisproctor.net>"]
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
|
|
46
yahtzee.py
46
yahtzee.py
|
@ -5,28 +5,17 @@ class Yachtzee:
|
|||
This version of Yahtzee is initialized with a list of goals.
|
||||
"""
|
||||
def __init__(self, goals):
|
||||
'''Initializes a game of Yahtzee. The initial score is 0, and all goals are available.
|
||||
Also creates the five dice that will be used for this game.'''
|
||||
self.score = 0
|
||||
self.goals = goals
|
||||
self.dice = [Die() for num in range(5)]
|
||||
|
||||
def play(self):
|
||||
'''Plays a game of Yahtzee.
|
||||
Starts by welcoming the player and will continue playing rounds until all goals have been used.
|
||||
Once all goals have been used, the game ends and the final score is presented to the player.'''
|
||||
print("Welcome to Yahtzee!")
|
||||
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):
|
||||
'''Plays a single round of Yahtzee.
|
||||
Prints a line to divide this round from the previous round.
|
||||
The five dice are rolled to start, and the player is shown the current game status.
|
||||
The player can choose to re-roll up to three times with the ultimate end choosing a goal.
|
||||
The round concludes when a player chooses a goal to apply their dice toward.
|
||||
This goal is marked as used, and the appropriate score from that round is added to the total.'''
|
||||
print("=" * 80)
|
||||
self.rolls_left = 3
|
||||
for die in self.dice:
|
||||
|
@ -37,16 +26,10 @@ class Yachtzee:
|
|||
self.score += goal.score(self.dice)
|
||||
|
||||
def show_status(self):
|
||||
'''Shows the player their current status.
|
||||
Displays the currrent values on the faces of the five dice, the current score and
|
||||
the number of re-rolls remaining for this round.'''
|
||||
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):
|
||||
'''Finds which goals the player can choose from and whether or not the player can re-roll.
|
||||
If the player has re-rolls remaining and chooses to re-roll, they can.
|
||||
Otherwise, they choose a goal and this function returns the goal chosen.'''
|
||||
options = []
|
||||
unused_goals = self.get_unused_goals()
|
||||
for goal in unused_goals:
|
||||
|
@ -63,11 +46,6 @@ class Yachtzee:
|
|||
return unused_goals[choice]
|
||||
|
||||
def get_choice(self, options):
|
||||
'''Prompts the player to choose an option, either a goal or to re-roll
|
||||
depending on whether the player has re-rolls remaining.
|
||||
Each option is assigned a number. Checks to see if the player's response is
|
||||
valid. Informs the player if their choice is invalid. When the player chooses
|
||||
a valid option, the number corresponding to that option is returned'''
|
||||
print("What would you like to do?")
|
||||
for i, option in enumerate(options):
|
||||
print(f"{i}. {option}")
|
||||
|
@ -78,12 +56,6 @@ class Yachtzee:
|
|||
return int(choice)
|
||||
|
||||
def option_choice_is_valid(self, choice, options):
|
||||
'''Checks to see if the option a player chose was valid.
|
||||
First checks to see if the option chosen was presented in the form of a number.
|
||||
If the choice was a number, then checks to see if that number was one of the
|
||||
possible options presented to the player. If it was then the choice is valid.
|
||||
If the choice was not a number or if the number was not a possible option,
|
||||
then the choice is not valid.'''
|
||||
if not choice.isdigit():
|
||||
return False
|
||||
if int(choice) < 0:
|
||||
|
@ -93,11 +65,9 @@ class Yachtzee:
|
|||
return True
|
||||
|
||||
def count_unused_goals(self):
|
||||
'''Returns the number of goals the player has not yet used.'''
|
||||
return len(self.get_unused_goals())
|
||||
|
||||
def get_unused_goals(self):
|
||||
'''Creates a list of goals the player has not yet used.'''
|
||||
unused_goals = []
|
||||
for goal in self.goals:
|
||||
if not goal.used:
|
||||
|
@ -105,9 +75,6 @@ class Yachtzee:
|
|||
return unused_goals
|
||||
|
||||
def reroll(self):
|
||||
'''Re-rolls the dice chosen by the player.
|
||||
Decreases the number of re-rolls remaining for this round by 1 and
|
||||
and rolls the dice that need to be re-rolled'''
|
||||
self.rolls_left -= 1
|
||||
choices = self.get_reroll_choices()
|
||||
dice_to_reroll = self.get_dice_to_reroll(choices)
|
||||
|
@ -115,9 +82,6 @@ class Yachtzee:
|
|||
die.roll()
|
||||
|
||||
def get_dice_to_reroll(self, choice_ints):
|
||||
'''This function returns the dice that need to be re-rolled.
|
||||
The dice that the player wants to re-roll are removed and placed into a list
|
||||
and this list of dice to re-roll is returned'''
|
||||
dice_to_reroll = []
|
||||
for die in self.dice:
|
||||
if die.face in choice_ints:
|
||||
|
@ -126,10 +90,6 @@ class Yachtzee:
|
|||
return dice_to_reroll
|
||||
|
||||
def get_reroll_choices(self):
|
||||
'''Prompts the player to select which dice they would like to re-roll.
|
||||
Checks to see that the input is valid. If it is not valid, the player
|
||||
is prompted to enter number values of dice they want to re-roll.
|
||||
Returns a list of the dice values to re-roll.'''
|
||||
print("Which dice do you want to re-roll?")
|
||||
choices = input("> ")
|
||||
while not self.reroll_choices_are_valid(choices):
|
||||
|
@ -139,10 +99,6 @@ class Yachtzee:
|
|||
return choice_ints
|
||||
|
||||
def reroll_choices_are_valid(self, choices_str):
|
||||
'''This function checks to see if choices for re-rolls are valid.
|
||||
First checks if the values the player wants to re-roll are numbers.
|
||||
Then checks that each value the player wants to re-roll corresponds
|
||||
to a unique dice-value the player currently has.'''
|
||||
if not choices_str.isdigit():
|
||||
return False
|
||||
choice_ints = [int(digit) for digit in choices_str]
|
||||
|
|
190
yahtzee_goals.py
190
yahtzee_goals.py
|
@ -1,5 +1,3 @@
|
|||
from collections import Counter
|
||||
|
||||
|
||||
class GoalOnes:
|
||||
"One point for each one"
|
||||
|
@ -45,191 +43,3 @@ class GoalThrees:
|
|||
if die.face == 3:
|
||||
total += 3
|
||||
return total
|
||||
|
||||
class GoalFours:
|
||||
"Four points for each four"
|
||||
used = False
|
||||
|
||||
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"
|
||||
used = False
|
||||
|
||||
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"
|
||||
used = False
|
||||
|
||||
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 Goal_Three_of_a_Kind:
|
||||
"Total of all 5 dice"
|
||||
used = False
|
||||
|
||||
def prompt(self, dice):
|
||||
potential_score = self.score(dice)
|
||||
return f"Three of a Kind ({potential_score})"
|
||||
|
||||
def score(self, dice):
|
||||
total = 0
|
||||
faces = []
|
||||
for die in dice:
|
||||
faces.append(die.face)
|
||||
total += die.face
|
||||
c = Counter(faces)
|
||||
of_a_kind = max(c.values())
|
||||
if (of_a_kind >= 3):
|
||||
return total
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
class Goal_Four_of_a_Kind:
|
||||
"Total of all 5 dice"
|
||||
used = False
|
||||
|
||||
def prompt(self, dice):
|
||||
potential_score = self.score(dice)
|
||||
return f"Four of a Kind ({potential_score})"
|
||||
|
||||
def score(self, dice):
|
||||
total = 0
|
||||
faces = []
|
||||
for die in dice:
|
||||
faces.append(die.face)
|
||||
total += die.face
|
||||
c = Counter(faces)
|
||||
of_a_kind = max(c.values())
|
||||
if (of_a_kind >= 4):
|
||||
return total
|
||||
else:
|
||||
return 0
|
||||
|
||||
class GoalFullHouse:
|
||||
"25 Points"
|
||||
used = False
|
||||
|
||||
def prompt(self, dice):
|
||||
potential_score = self.score(dice)
|
||||
return f"Full House ({potential_score})"
|
||||
|
||||
def score(self, dice):
|
||||
faces = []
|
||||
for die in dice:
|
||||
faces.append(die.face)
|
||||
c = Counter(faces)
|
||||
if len(c) == 2 and (3 in c.values()) and (2 in c.values()):
|
||||
return 25
|
||||
else:
|
||||
return 0
|
||||
|
||||
class GoalSmallStraight:
|
||||
"30 Points"
|
||||
used = False
|
||||
|
||||
def prompt(self, dice):
|
||||
potential_score = self.score(dice)
|
||||
return f"Small Straight ({potential_score})"
|
||||
|
||||
def score(self, dice):
|
||||
faces = []
|
||||
for die in dice:
|
||||
faces.append(die.face)
|
||||
c = Counter(faces)
|
||||
if (len(c) >= 4):
|
||||
if (1 in c.keys()) and (2 in c.keys()) and (3 in c.keys()) and (4 in c.keys()):
|
||||
return 30
|
||||
elif (2 in c.keys()) and (3 in c.keys()) and (4 in c.keys()) and (5 in c.keys()):
|
||||
return 30
|
||||
elif (3 in c.keys()) and (4 in c.keys()) and (5 in c.keys()) and (6 in c.keys()):
|
||||
return 30
|
||||
else:
|
||||
return 0
|
||||
else:
|
||||
return 0
|
||||
|
||||
class GoalLargeStraight:
|
||||
"40 Points"
|
||||
used = False
|
||||
|
||||
def prompt(self, dice):
|
||||
potential_score = self.score(dice)
|
||||
return f"Large Straight ({potential_score})"
|
||||
|
||||
def score(self, dice):
|
||||
faces = []
|
||||
for die in dice:
|
||||
faces.append(die.face)
|
||||
c = Counter(faces)
|
||||
if (len(c) >= 5):
|
||||
if (1 in c.keys()) and (2 in c.keys()) and (3 in c.keys()) and (4 in c.keys()) and (5 in c.keys()):
|
||||
return 40
|
||||
elif (2 in c.keys()) and (3 in c.keys()) and (4 in c.keys()) and (5 in c.keys()) and (6 in c.keys()):
|
||||
return 40
|
||||
else:
|
||||
return 0
|
||||
else:
|
||||
return 0
|
||||
|
||||
class GoalYahtzee:
|
||||
"50 Points"
|
||||
used = False
|
||||
|
||||
def prompt(self, dice):
|
||||
potential_score = self.score(dice)
|
||||
return f"Yahtzee ({potential_score})"
|
||||
|
||||
def score(self, dice):
|
||||
faces = []
|
||||
for die in dice:
|
||||
faces.append(die.face)
|
||||
c = Counter(faces)
|
||||
of_a_kind = max(c.values())
|
||||
if (of_a_kind == 5):
|
||||
return 50
|
||||
else:
|
||||
return 0
|
||||
|
||||
class GoalChance:
|
||||
"Total of all 5 dice"
|
||||
used = False
|
||||
|
||||
def prompt(self, dice):
|
||||
potential_score = self.score(dice)
|
||||
return f"Chance({potential_score})"
|
||||
|
||||
def score(self, dice):
|
||||
total = 0
|
||||
faces = []
|
||||
for die in dice:
|
||||
total += die.face
|
||||
return total
|
||||
|
|
Loading…
Reference in New Issue