Advertisement
Guest User

Untitled

a guest
Feb 13th, 2018
169
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.41 KB | None | 0 0
  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.  
  181. def announce_lead_changes(previous_leader=None):
  182.     """Return a commentary function that announces lead changes.
  183.  
  184.    >>> f0 = announce_lead_changes()
  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:
  196.             leader = 0
  197.         elif score1 > score0:
  198.             leader = 1
  199.         else:
  200.             leader = None
  201.         if leader != None and leader != previous_leader:
  202.             print('Player', leader, 'takes the lead by', abs(score0 - score1))
  203.         return announce_lead_changes(leader)
  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.  
  391.     "*** You may add additional experiments as you wish ***"
  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")
  453.     parser.add_argument('--run_experiments', '-r', action='store_true',
  454.                         help='Runs strategy experiments')
  455.  
  456.     args = parser.parse_args()
  457.  
  458.     if args.run_experiments:
  459.         run_experiments()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement