Phase 3 - Strategies
https://inst.eecs.berkeley.edu/~cs61a/su19/proj/hog/#phase-3-strategies
In the third phase, you will experiment with ways to improve upon the basic strategy of always rolling a fixed number of dice. First, you need to develop some tools to evaluate strategies.
Problem 8
Implement the make_averaged
function, which is a higher-order function that takes a function fn
as an argument. It returns another function that takes the same number of arguments as fn
(the function originally passed into make_averaged
). This returned function differs from the input function in that it returns the average value of repeatedly calling fn
on the same arguments. This function should call fn
a total of num_samples
times and return the average of the results.
To implement this function, you need a new piece of Python syntax! You must write a function that accepts an arbitrary number of arguments, then calls another function using exactly those arguments.
Solution:
def make_averaged(fn, num_samples=1000):
"""Return a function that returns the average value of FN when called.
To implement this function, you will have to use *args syntax, a new Python
feature introduced in this project. See the project description.
>>> dice = make_test_dice(4, 2, 5, 1)
>>> averaged_dice = make_averaged(dice, 1000)
>>> averaged_dice()
3.0
"""
"*** YOUR CODE HERE ***"
def averaged(*args):
result = 0;
for i in range(0, num_samples):
result = result + fn(*args)
return result / num_samples
return averaged
Problem 9
Implement the max_scoring_num_rolls
function, which runs an experiment to determine the number of rolls (from 1 to 10) that gives the maximum average score for a turn. Your implementation should use make_averaged
and roll_dice
.
If two numbers of rolls are tied for the maximum average score, return the lower number. For example, if both 3 and 6 achieve a maximum average score, return 3.
Solution:
def max_scoring_num_rolls(dice=six_sided, num_samples=1000):
"""Return the number of dice (1 to 10) that gives the highest average turn
score by calling roll_dice with the provided DICE over NUM_SAMPLES times.
Assume that the dice always return positive outcomes.
>>> dice = make_test_dice(1, 6)
>>> max_scoring_num_rolls(dice)
1
"""
"*** YOUR CODE HERE ***"
MAX_SCORING_DEFAULT = 10
averaged_roll_dice = make_averaged(roll_dice, num_samples)
max_scoring_roll = MAX_SCORING_DEFAULT
highest = 0
for i in range(MAX_SCORING_DEFAULT, 0, -1):
new_score = averaged_roll_dice(i, dice)
is_new_highest = new_score > highest
highest = new_score if is_new_highest else highest
max_scoring_roll = i if is_new_highest else max_scoring_roll
return max_scoring_roll
Problem 10
A strategy can take advantage of the Free Bacon rule by rolling 0 when it is most beneficial to do so. Implement bacon_strategy
, which returns 0 whenever rolling 0 would give at least margin
points and returns num_rolls
otherwise.
Solution:
def bacon_strategy(score, opponent_score, margin=8, num_rolls=4):
"""This strategy rolls 0 dice if that gives at least MARGIN points, and
rolls NUM_ROLLS otherwise.
"""
free_bacon_points = free_bacon(opponent_score)
return 0 if free_bacon_points >= margin else num_rolls
Problem 11
A strategy can also take advantage of the Swine Swap rule. The swap_strategy
rolls 0 if it would cause a beneficial swap. It also returns 0 if rolling 0 would give at least margin
points, unless this would cause a non-beneficial swap. Otherwise, the strategy rolls num_rolls
.
def swap_strategy(score, opponent_score, margin=8, num_rolls=4):
"""This strategy rolls 0 dice when it triggers a beneficial swap. It also
rolls 0 dice if it gives at least MARGIN points and does not trigger a
non-beneficial swap. Otherwise, it rolls NUM_ROLLS.
"""
free_bacon_points = free_bacon(opponent_score)
is_swap_beneficial = opponent_score > score
is_swap_w_bacon = is_swap(score + free_bacon_points, opponent_score)
if is_swap_beneficial and is_swap_w_bacon or not is_swap_w_bacon and free_bacon_points >= margin:
return 0
else:
return num_rolls
Last updated