• API
• FAQ
• Tools
• Archive
daily pastebin goal
34%
SHARE
TWEET

Untitled

a guest Feb 13th, 2018 114 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
1. """CS 61A Presents The Game of Hog."""
2.
3. from dice import six_sided, four_sided, make_test_dice
4. from ucb import main, trace, interact
5.
6. GOAL_SCORE = 100  # The goal of Hog is to score 100 points.
7.
8. ######################
9. # Phase 1: Simulator #
10. ######################
11.
12.
13. def roll_dice(num_rolls, dice=six_sided):
14.     """Simulate rolling the DICE exactly NUM_ROLLS > 0 times. Return the sum of
15.    the outcomes unless any of the outcomes is 1. In that case, return 1.
16.
17.    num_rolls:  The number of dice rolls that will be made.
18.    dice:       A function that simulates a single dice roll outcome.
19.    """
20.     # These assert statements ensure that num_rolls is a positive integer.
21.     assert type(num_rolls) == int, 'num_rolls must be an integer.'
22.     assert num_rolls > 0, 'Must roll at least once.'
23.     # BEGIN PROBLEM 1
24.     pig_out = 0
25.     roll_val = 0
26.
27.     while num_rolls > 0:
28.         single_dice = dice()
29.         if single_dice == 1:
30.             pig_out = 1
31.             num_rolls -= 1
32.         else:
33.             roll_val = roll_val + single_dice
34.             num_rolls -= 1
35.     if pig_out:
36.         return 1
37.     else:
38.         return roll_val
39.     # END PROBLEM 1
40.
41.
42. def free_bacon(score):
43.     """Return the points scored from rolling 0 dice (Free Bacon).
44.
45.    score:  The opponent's current score.
46.    """
47.     assert score < 100, 'The game should be over.'
48.     # BEGIN PROBLEM 2
49.     if score < 10:
50.         pts_zero_dice = score
51.         return 2 + score
52.     else:
53.         first_digit = score // 10
54.         second_digit = score % 10
55.         return 2 + abs(first_digit - second_digit)
56.     # END PROBLEM 2
57.
58.
59. def take_turn(num_rolls, opponent_score, dice=six_sided):
60.     """Simulate a turn rolling NUM_ROLLS dice, which may be 0 (Free Bacon).
61.    Return the points scored for the turn by the current player.
62.
63.    num_rolls:       The number of dice rolls that will be made.
64.    opponent_score:  The total score of the opponent.
65.    dice:            A function that simulates a single dice roll outcome.
66.    """
67.     # Leave these assert statements here; they help check for errors.
68.     assert type(num_rolls) == int, 'num_rolls must be an integer.'
69.     assert num_rolls >= 0, 'Cannot roll a negative number of dice in take_turn.'
70.     assert num_rolls <= 10, 'Cannot roll more than 10 dice.'
71.     assert opponent_score < 100, 'The game should be over.'
72.     # BEGIN PROBLEM 3
73.     if num_rolls > 0:
74.         return roll_dice(num_rolls, dice)
75.     elif num_rolls == 0:
76.         return free_bacon(opponent_score)
77.     # END PROBLEM 3
78.
79.
80. def is_swap(score0, score1):
81.     """Return whether one of the scores is an integer multiple of the other."""
82.     # BEGIN PROBLEM 4
83.     if score0 > 1 and score1 > 1: # may need to put condition that no switching happens if someone surpasses 100
84.         if score0 > score1:
85.             w = 1
86.             while w < score0:
87.                 if score0 % w == 0 and score1 == w:
88.                     return True
89.                 elif w == (score0 - 1):
90.                     return False
91.                 else:
92.                     w += 1
93.         elif score0 < score1:
94.             w = 1
95.             while w<score1:
96.                 if score1 % w == 0 and score0 == w:
97.                     return True
98.                 elif w == (score1 - 1):
99.                     return False
100.                 else:
101.                     w += 1
102.         else:
103.             return False
104.
105.     else:
106.         return False
107.
108.     # END PROBLEM 4
109.
110.
111. def other(player):
112.     """Return the other player, for a player PLAYER numbered 0 or 1.
113.
114.    >>> other(0)
115.    1
116.    >>> other(1)
117.    0
118.    """
119.     return 1 - player
120.
121. def silence(score0, score1):
122.     """Announce nothing (see Phase 2)."""
123.     return silence
124.
125. def play(strategy0, strategy1, score0=0, score1=0, dice=six_sided,
126.          goal=GOAL_SCORE, say=silence):
127.     """Simulate a game and return the final scores of both players, with Player
128.    0's score first, and Player 1's score second.
129.
130.    A strategy is a function that takes two total scores as arguments (the
131.    current player's score, and the opponent's score), and returns a number of
132.    dice that the current player will roll this turn.
133.
134.    strategy0:  The strategy function for Player 0, who plays first.
135.    strategy1:  The strategy function for Player 1, who plays second.
136.    score0:     Starting score for Player 0
137.    score1:     Starting score for Player 1
138.    dice:       A function of zero arguments that simulates a dice roll.
139.    goal:       The game ends and someone wins when this score is reached.
140.    say:        The commentary function to call at the end of the first turn.
141.    """
142.     player = 0  # Which player is about to take a turn, 0 (first) or 1 (second)
143.     # BEGIN PROBLEM 5
144.
145.     while score0 < goal and score1 < goal:
146.
147.         if player == 0:
148.             num_roll = strategy0(score0, score1)
149.             score0_from_turn = take_turn(num_roll, score1, dice)
150.             score0 = score0 + score0_from_turn
151.             player = other(player)
152.             if is_swap(score0, score1):
153.                 switch = score0
154.                 score0 = score1
155.                 score1 = switch
156.         else: #player == 1
157.             num_roll = strategy1(score1, score0)
158.             score1_from_turn = take_turn(num_roll, score0, dice)
159.             score1 = score1 + score1_from_turn
160.             player = other(player)
161.             if is_swap(score0, score1):
162.                 switch = score0
163.                 score0 = score1
164.                 score1 = switch
165.         say = say(score0, score1)
166.
167.     # END PROBLEM 5
168.     return score0, score1
169.
170.
171. #######################
172. # Phase 2: Commentary #
173. #######################
174.
175.
176. def say_scores(score0, score1):
177.     """A commentary function that announces the score for each player."""
178.     print("Player 0 now has", score0, "and Player 1 now has", score1)
179.     return say_scores
180.
182.     """Return a commentary function that announces lead changes.
183.
185.    >>> f1 = f0(5, 0)
186.    Player 0 takes the lead by 5
187.    >>> f2 = f1(5, 12)
188.    Player 1 takes the lead by 7
189.    >>> f3 = f2(8, 12)
190.    >>> f4 = f3(8, 13)
191.    >>> f5 = f4(15, 13)
192.    Player 0 takes the lead by 2
193.    """
194.     def say(score0, score1):
195.         if score0 > score1:
197.         elif score1 > score0:
199.         else:
204.     return say
205.
206. def both(f, g):
207.     """Return a commentary function that says what f says, then what g says.
208.
209.    >>> h0 = both(say_scores, announce_lead_changes())
210.    >>> h1 = h0(10, 0)
211.    Player 0 now has 10 and Player 1 now has 0
212.    Player 0 takes the lead by 10
213.    >>> h2 = h1(10, 6)
214.    Player 0 now has 10 and Player 1 now has 6
215.    >>> h3 = h2(6, 18) # Player 0 gets 8 points, then Swine Swap applies
216.    Player 0 now has 6 and Player 1 now has 18
217.    Player 1 takes the lead by 12
218.    """
219.     def say(score0, score1):
220.         return both(f(score0, score1), g(score0, score1))
221.     return say
222.
223.
224. def announce_highest(who, previous_high=0, previous_score=0):
225.     """Return a commentary function that announces when WHO's score
226.    increases by more than ever before in the game.
227.
228.    >>> f0 = announce_highest(0) # Only announce Player 1 score gains
229.    >>> f1 = f0(11, 0)
230.    >>> f2 = f1(11, 1)
231.    1 point! That's the biggest gain yet for Player 1
232.    >>> f3 = f2(20, 1)
233.    >>> f4 = f3(5, 20) # Player 1 gets 4 points, then Swine Swap applies
234.    19 points! That's the biggest gain yet for Player 1
235.    >>> f5 = f4(20, 40) # Player 0 gets 35 points, then Swine Swap applies
236.    20 points! That's the biggest gain yet for Player 1
237.    >>> f6 = f5(20, 55) # Player 1 gets 15 points; not enough for a new high
238.    """
239.     assert who == 0 or who == 1, 'The who argument should indicate a player.'
240.     # BEGIN PROBLEM 7
241.
242.     def inner_announce(score0, score1):
243.         if who == 0:
244.             if score0 - previous_score > previous_high and score0 - previous_score == 1:
245.                 print("%s point! That's the biggest gain yet for Player 0" % (score0 - previous_score))
246.                 new_high = score0 - previous_score
247.                 new_score = score0
248.             elif score0 - previous_score > previous_high and score0 - previous_score > 1:
249.                 print("%s points! That's the biggest gain yet for Player 0" % (score0 - previous_score) )
250.                 new_high = score0 - previous_score
251.                 new_score = score0
252.             elif score0 - previous_score < previous_high and score0 != previous_score:
253.                 new_high = previous_high
254.                 new_score = score0
255.             else:
256.                 new_high = previous_high
257.                 new_score = previous_score
258.         elif who == 1:
259.             if score1 - previous_score > previous_high and score1 - previous_score == 1:
260.                 print("%s point! That's the biggest gain yet for Player 1" % (score1 - previous_score))
261.                 new_high = score1 - previous_score
262.                 new_score = score1
263.             elif score1 - previous_score > previous_high and score1 - previous_score > 1:
264.                 print("%s points! That's the biggest gain yet for Player 1" % (score1 - previous_score))
265.                 new_high = score1 - previous_score
266.                 new_score = score1
267.             elif score1 - previous_score < previous_high and score1 != previous_score:
268.                 new_high = previous_high
269.                 new_score = score1
270.             else:
271.                 new_high = previous_high
272.                 new_score = previous_score
273.
274.         return announce_highest(who, new_high, new_score)
275.
276.     return inner_announce
277.
278.     # END PROBLEM 7
279.
280. #######################
281. # Phase 3: Strategies #
282. #######################
283.
284.
285. def always_roll(n):
286.     """Return a strategy that always rolls N dice.
287.
288.    A strategy is a function that takes two total scores as arguments (the
289.    current player's score, and the opponent's score), and returns a number of
290.    dice that the current player will roll this turn.
291.
292.    >>> strategy = always_roll(5)
293.    >>> strategy(0, 0)
294.    5
295.    >>> strategy(99, 99)
296.    5
297.    """
298.     def strategy(score, opponent_score):
299.         return n
300.     return strategy
301.
302.
303. def make_averaged(fn, num_samples=1000):
304.     """Return a function that returns the average value of FN when called.
305.
306.    To implement this function, you will have to use *args syntax, a new Python
307.    feature introduced in this project.  See the project description.
308.
309.    >>> dice = make_test_dice(4, 2, 5, 1)
310.    >>> averaged_dice = make_averaged(dice, 1000)
311.    >>> averaged_dice()
312.    3.0
313.    """
314.     # BEGIN PROBLEM 8
315.
316.     def inner_average(*args):
317.         n = 1
318.         result = 0
319.         while n <= num_samples:
320.             roll_result = fn(*args)
321.             result += roll_result
322.             n += 1
323.
324.
325.         return result / num_samples
326.
327.     return inner_average
328.     # END PROBLEM 8
329.
330.
331. def max_scoring_num_rolls(dice=six_sided, num_samples=1000):
332.     """Return the number of dice (1 to 10) that gives the highest average turn
333.    score by calling roll_dice with the provided DICE over NUM_SAMPLES times.
334.    Assume that the dice always return positive outcomes.
335.
336.    >>> dice = make_test_dice(1, 6)
337.    >>> max_scoring_num_rolls(dice)
338.    1
339.    """
340.     # BEGIN PROBLEM 9
341.     i = 1
342.     avg_for_optno_dice = 1
343.     best_numrolls = 1
344.     while i <= 10:
345.         avg_for_i_dice = make_averaged(roll_dice,num_samples)(i, dice)
346.         if avg_for_i_dice > avg_for_optno_dice:
347.             avg_for_optno_dice = avg_for_i_dice
348.             best_numrolls = i
349.         i += 1
350.
351.     return best_numrolls
352.     # END PROBLEM 9
353.
354.
355. def winner(strategy0, strategy1):
356.     """Return 0 if strategy0 wins against strategy1, and 1 otherwise."""
357.     score0, score1 = play(strategy0, strategy1)
358.     if score0 > score1:
359.         return 0
360.     else:
361.         return 1
362.
363. def average_win_rate(strategy, baseline=always_roll(4)):
364.     """Return the average win rate of STRATEGY against BASELINE. Averages the
365.    winrate when starting the game as player 0 and as player 1.
366.    """
367.     win_rate_as_player_0 = 1 - make_averaged(winner)(strategy, baseline)
368.     win_rate_as_player_1 = make_averaged(winner)(baseline, strategy)
369.
370.     return (win_rate_as_player_0 + win_rate_as_player_1) / 2
371.
372.
373. def run_experiments():
374.     """Run a series of strategy experiments and report results."""
375.     if False:  # Change to False when done finding max_scoring_num_rolls
376.         six_sided_max = max_scoring_num_rolls(six_sided)
377.         print('Max scoring num rolls for six-sided dice:', six_sided_max)
378.
379.     if False:  # Change to True to test always_roll(8)
380.         print('always_roll(8) win rate:', average_win_rate(always_roll(8)))
381.
382.     if False:  # Change to True to test bacon_strategy
383.         print('bacon_strategy win rate:', average_win_rate(bacon_strategy))
384.
385.     if False:  # Change to True to test swap_strategy
386.         print('swap_strategy win rate:', average_win_rate(swap_strategy))
387.
388.     if False:  # Change to True to test final_strategy
389.         print('final_strategy win rate:', average_win_rate(final_strategy))
390.
392.
393.
394. def bacon_strategy(score, opponent_score, margin=8, num_rolls=4):
395.     """This strategy rolls 0 dice if that gives at least MARGIN points, and
396.    rolls NUM_ROLLS otherwise.
397.    """
398.     # BEGIN PROBLEM 10
399.     if opponent_score < 10 and opponent_score + 2 >= margin:
400.         num_rolls = 0
401.     elif opponent_score > 10:
402.         first_digit = opponent_score // 10
403.         second_digit = opponent_score % 10
404.         if 2 + abs(first_digit-second_digit) >= margin:
405.             num_rolls = 0
406.     return num_rolls # Replace this statement
407.     # END PROBLEM 10
408.
409.
410. def swap_strategy(score, opponent_score, margin=8, num_rolls=4):
411.     """This strategy rolls 0 dice when it triggers a beneficial swap. It also
412.    rolls 0 dice if it gives at least MARGIN points. Otherwise, it rolls
413.    NUM_ROLLS.
414.    """
415.     # BEGIN PROBLEM 11
416.     w = 1
417.     while w < opponent_score:
418.         if (opponent_score % w == 0 and score == w and opponent_score > score) or bacon_strategy(score, opponent_score, margin, num_rolls) == 0:
419.             return 0
420.         else:
421.             w += 1
422.
423.     return num_rolls   # Replace this statement
424.     # END PROBLEM 11
425.
426.
427. def final_strategy(score, opponent_score):
428.     """Write a brief description of your final strategy.
429.
430.    *** YOUR DESCRIPTION HERE ***
431.    """
432.     # BEGIN PROBLEM 12
433.     return 4  # Replace this statement
434.     # END PROBLEM 12
435.
436.
437. ##########################
438. # Command Line Interface #
439. ##########################
440.
441. # NOTE: Functions in this section do not need to be changed. They use features
442. # of Python not yet covered in the course.
443.
444.
445. @main
446. def run(*args):
447.     """Read in the command-line argument and calls corresponding functions.
448.
449.    This function uses Python syntax/techniques not yet covered in this course.
450.    """
451.     import argparse
452.     parser = argparse.ArgumentParser(description="Play Hog")