Phase 2 - Commentary

https://inst.eecs.berkeley.edu/~cs61a/su19/proj/hog/#phase-2-commentary

In the second phase, you will implement commentary functions that print remarks about the game after each turn, such as, "22 points! That's the biggest gain yet for Player 1."

A commentary function takes two arguments, Player 0's current score and Player 1's current score. It can print out commentary based on either or both current scores and possibly even previous scores. Since commentary can differ from turn to turn depending on the current point situation in the game, commentary functions return another commentary function to be called on the next turn. The only side effect of a commentary function should be to print.

Commentary examples

The function say_scores in hog.py is an example of a commentary function that simply announces both players' scores. Note that say_scores returns a reference to itself, meaning that the same commentary function will be called each turn.

def say_scores(score0, score1):
    """A commentary function that announces the score for each player."""
    print("Player 0 now has", score0, "and Player 1 now has", score1)
    return say_scores

The function announce_lead_changes is an example of a higher-order function that returns a commentary function that tracks lead changes.

def announce_lead_changes(previous_leader=None):
    """Return a commentary function that announces lead changes.

    >>> f0 = announce_lead_changes()
    >>> f1 = f0(5, 0)
    Player 0 takes the lead by 5
    >>> f2 = f1(5, 12)
    Player 1 takes the lead by 7
    >>> f3 = f2(8, 12)
    >>> f4 = f3(8, 13)
    >>> f5 = f4(15, 13)
    Player 0 takes the lead by 2
    """
    def say(score0, score1):
        if score0 > score1:
            leader = 0
        elif score1 > score0:
            leader = 1
        else:
            leader = None
        if leader != None and leader != previous_leader:
            print('Player', leader, 'takes the lead by', abs(score0 - score1))
        return announce_lead_changes(leader)
    return saypyt

You should also understand the function both, which takes two commentary functions (f and g) and returns a new commentary function. This returned commentary function returns another commentary function which calls the functions returned by calling f and g, in that order.

def both(f, g):
    """Return a commentary function that says what f says, then what g says.

    NOTE: the following game is not possible under the rules, it's just
    an example for the sake of the doctest

    >>> h0 = both(say_scores, announce_lead_changes())
    >>> h1 = h0(10, 0)
    Player 0 now has 10 and Player 1 now has 0
    Player 0 takes the lead by 10
    >>> h2 = h1(10, 6)
    Player 0 now has 10 and Player 1 now has 6
    >>> h3 = h2(6, 17)
    Player 0 now has 6 and Player 1 now has 17
    Player 1 takes the lead by 11
    """
    def say(score0, score1):
        return both(f(score0, score1), g(score0, score1))
    return say

Problem 6

Update your play function so that a commentary function is called at the end of each turn. The return value of calling a commentary function gives you the commentary function to call on the next turn.

For example, say(score0, score1) should be called at the end of the first turn. Its return value (another commentary function) should be called at the end of the second turn. Each consecutive turn, call the function that was returned by the call to the previous turn's commentary function.

Solution:

def play(strategy0, strategy1, score0=0, score1=0, dice=six_sided, goal=GOAL_SCORE, say=silence):
 """Simulate a game and return the final scores of both players,
  with Player 0's score first, and Player 1's score second.
A strategy is a function that takes two total scores as arguments (the
current player's score, and the opponent's score), and returns a number of
dice that the current player will roll this turn.

strategy0:  The strategy function for Player 0, who plays first.
strategy1:  The strategy function for Player 1, who plays second.
score0:     Starting score for Player 0
score1:     Starting score for Player 1
dice:       A function of zero arguments that simulates a dice roll.
goal:       The game ends and someone wins when this score is reached.
say:        The commentary function to call at the end of the first turn.
"""
player = 0  # Which player is about to take a turn, 0 (first) or 1 (second)

"*** YOUR CODE HERE ***"
def is_game_over(score0, score1, goal_score):
    return score0 >= goal_score  or score1 >= goal_score


def get_current_strategy(strategy0, strategy1, player=0):
    if (player == 0):
        return strategy0
    else:
        return strategy1

def get_num_rolls(score0, score1, player, current_strategy): 
    if (player == 0):
        return current_strategy(score0, score1) 
    else:
        return current_strategy(score1, score0)


def swine_swap(curr_player_score, other_player_score):
    if (is_swap(curr_player_score, other_player_score)):
        curr_player_score, other_player_score = other_player_score, curr_player_score 
    return curr_player_score, other_player_score 

def set_scores(num_rolls, score0, score1, player):
    if (player == 0):
        score0 += take_turn(num_rolls, score1, dice) 
        score0, score1 = swine_swap(score0, score1)
    else:
        score1 += take_turn(num_rolls, score0, dice)
        score1, score0 = swine_swap(score1, score0)

    return score0, score1

commentary = say
while not is_game_over(score0, score1, goal):
    current_strategy = get_current_strategy(strategy0, strategy1, player)
    num_rolls        = get_num_rolls(score0, score1, player, current_strategy)
    score0, score1   = set_scores(num_rolls, score0, score1, player)
    player           = other(player)

    commentary = commentary(score0, score1) 

return score0, score1

Problem 7

Implement the announce_highest function, which is a higher-order function that returns a commentary function. This commentary function announces whenever a particular player gains more points in a turn than ever before. To compute the gain, it must compare the score from last turn to the score from this turn for the player of interest, which is designated by the who argument. This function must also keep track of the highest gain for the player so far.

The way in which announce_highest announces is very specific, and your implementation should match the doctests provided. Don't worry about singular versus plural when announcing point gains; you should simply use "point(s)" for both cases.

Solution:

def announce_highest(who, previous_high=0, previous_score=0):
    """Return a commentary function that announces when WHO's score
    increases by more than ever before in the game.

    NOTE: the following game is not possible under the rules, it's just
    an example for the sake of the doctest

    >>> f0 = announce_highest(1) # Only announce Player 1 score gains
    >>> f1 = f0(12, 0)
    >>> f2 = f1(12, 11)
    11 point(s)! That's the biggest gain yet for Player 1
    >>> f3 = f2(20, 11)
    >>> f4 = f3(13, 20)
    >>> f5 = f4(20, 35)
    15 point(s)! That's the biggest gain yet for Player 1
    >>> f6 = f5(20, 47) # Player 1 gets 12 points; not enough for a new high
    >>> f7 = f6(21, 47)
    >>> f8 = f7(21, 77)
    30 point(s)! That's the biggest gain yet for Player 1
    >>> f9 = f8(77, 22) # Swap!
    >>> f10 = f9(33, 77) # Swap!
    55 point(s)! That's the biggest gain yet for Player 1
    """
    assert who == 0 or who == 1, 'The who argument should indicate a player.'
    # BEGIN PROBLEM 7
    "*** YOUR CODE HERE ***"

    is_p0 = who ==0


    def say(score0, score1):
        say_phrase = lambda current_high, who: print('{current_high} point(s)! That\'s the biggest gain yet for Player {player_id}'.format(current_high = current_high, player_id = who))
        current_score = score0 if is_p0 else score1
        score_gain = current_score - previous_score
        is_new_highest = score_gain > previous_high
        current_high = score_gain if is_new_highest else previous_high

        if is_new_highest:
            say_phrase(current_high, who)

        return announce_highest(who, current_high, current_score)
    
    return say

Last updated