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.
defsay_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.
defannounce_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 """defsay(score0,score1):if score0 > score1: leader =0elif score1 > score0: leader =1else: leader =Noneif leader !=Noneand leader != previous_leader:print('Player', leader, 'takes the lead by', abs(score0 - score1))returnannounce_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.
defboth(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 """defsay(score0,score1):returnboth(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:
defplay(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 (thecurrent player's score, and the opponent's score), and returns a number ofdice 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 0score1: Starting score for Player 1dice: 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 ***"defis_game_over(score0,score1,goal_score):return score0 >= goal_score or score1 >= goal_scoredefget_current_strategy(strategy0,strategy1,player=0):if (player ==0):return strategy0else:return strategy1defget_num_rolls(score0,score1,player,current_strategy): if (player ==0):returncurrent_strategy(score0, score1)else:returncurrent_strategy(score1, score0)defswine_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 defset_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, score1commentary = saywhilenotis_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:
defannounce_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 ==0or who ==1,'The who argument should indicate a player.'# BEGIN PROBLEM 7"*** YOUR CODE HERE ***" is_p0 = who ==0defsay(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_highif is_new_highest:say_phrase(current_high, who)returnannounce_highest(who, current_high, current_score)return say