提示:本文内容来源于UCB CS61A课程,详情请点击CS 61A: Structure and Interpretation of Computer Programs
前言
本文收录在文章CS61A 课程 Project1 The Game of Hog
提示:以下是本篇文章正文内容,下面代码除课程提供外均为本人自主完成,仅供参考
Phase3: Strategies
Problem 08
本节要求实现函数make_averaged
,该函数是一个以函数original_function
为参数的高阶函数
其返回另一个与函数original_function
参数相同的函数,二者的不同之处在于,作为返回值的函数返回的是重复调用original_function的平均值,此函数应调用 original_function 共 trials_count 次并返回结果的平均值。
要求该函数可以接收任意数量的参数,参数应记作*args
(而不是将参数序列列表化),如下示例
>>> def printed(f):
... def print_and_return(*args):
... result = f(*args)
... print('Result:', result)
... return result
... return print_and_return
>>> printed_pow = printed(pow)
>>> printed_pow(2, 8)
Result: 256
256
>>> printed_abs = printed(abs)
>>> printed_abs(-10)
Result: 10
10
项目介绍要求认真阅读make_averaged
函数的docstring
:
"""Return a function that returns the average value of ORIGINAL_FUNCTION 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
"""
提供了测试脚本检测学生是否理解函数需求
$ python3 ok -q 08 -u --local
=====================================================================
Assignment: Project 1: Hog
OK, version v1.18.1
=====================================================================
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unlocking tests
At each "? ", type what you would expect the output to be.
Type exit() to quit
---------------------------------------------------------------------
Question 8 > Suite 1 > Case 1
(cases remaining: 7)
Q: What makes make_averaged a higher order function?
Choose the number of the correct choice:
0) It uses the *args keyword
1) It returns a function
2) It takes in a function as an argument
3) It both takes in a function as an argument and returns a function
? 3
-- OK! --
---------------------------------------------------------------------
Question 8 > Suite 1 > Case 2
(cases remaining: 6)
Q: How many arguments does the function passed into make_averaged take?
Choose the number of the correct choice:
0) An arbitrary amount, which is why we need to use *args to call it
1) Two
2) None
? 0
-- OK! --
---------------------------------------------------------------------
Question 8 > Suite 2 > Case 1
(cases remaining: 5)
>>> from hog import *
>>> dice = make_test_dice(3, 1, 5, 6)
>>> averaged_dice = make_averaged(dice, 1000)
>>> # Average of calling dice 1000 times
>>> averaged_dice()
? 3.75
-- OK! --
---------------------------------------------------------------------
Question 8 > Suite 2 > Case 2
(cases remaining: 4)
>>> from hog import *
>>> dice = make_test_dice(3, 1, 5, 6)
>>> averaged_roll_dice = make_averaged(roll_dice, 1000)
>>> # Average of calling roll_dice 1000 times
>>> # Enter a float (e.g. 1.0) instead of an integer
>>> averaged_roll_dice(2, dice)
? 6.0
-- OK! --
---------------------------------------------------------------------
OK! All cases for Question 8 unlocked.
函数的实现如下:
def make_averaged(original_function, trials_count=1000):
"""Return a function that returns the average value of ORIGINAL_FUNCTION 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
"""
# BEGIN PROBLEM 8
"*** YOUR CODE HERE ***"
def average(*args):
average = 0
for i in range(trials_count):
average += original_function(*args)
return average / trials_count
return average
# END PROBLEM 8
以上实现符合评分脚本要求
$ python3 ok -q 08 --local
=====================================================================
Assignment: Project 1: Hog
OK, version v1.18.1
=====================================================================
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running tests
---------------------------------------------------------------------
Test summary
7 test cases passed! No cases failed.
Problem 09
该部分要求实现函数max_scoring_num_rolls
,该函数需要两个参数,一个骰子类型(如六面骰),以为测试次数
该函数的功能为,测试投掷骰子数量不同(1-10)时的平均得分(每个数量所对应的测试进行trial_counts
次)
要求实现时要用make_averaged
函数和roll_dice
函数来完成
注:多个投掷数量取得相同的得分时,要返回数量较少的那一个
课程提供了提问脚本检查学生是否彻底理解函数的功能
$ python3 ok -q 09 -u --local
=====================================================================
Assignment: Project 1: Hog
OK, version v1.18.1
=====================================================================
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unlocking tests
At each "? ", type what you would expect the output to be.
Type exit() to quit
---------------------------------------------------------------------
Question 9 > Suite 1 > Case 1
(cases remaining: 8)
Q: If multiple num_rolls are tied for the highest scoring
average, which should you return?
Choose the number of the correct choice:
0) The highest num_rolls
1) A random num_rolls
2) The lowest num_rolls
? 2
-- OK! --
---------------------------------------------------------------------
Question 9 > Suite 2 > Case 1
(cases remaining: 7)
>>> from hog import *
>>> dice = make_test_dice(3) # dice always returns 3
>>> max_scoring_num_rolls(dice, trials_count=1000)
? 10
-- OK! --
---------------------------------------------------------------------
Question 9 > Suite 3 > Case 1
(cases remaining: 4)
>>> from hog import *
>>> dice = make_test_dice(2) # dice always rolls 2
>>> max_scoring_num_rolls(dice, trials_count=1000)
? 10
-- OK! --
>>> from hog import *
>>> dice = make_test_dice(1, 2) # dice alternates 1 and 2
>>> max_scoring_num_rolls(dice, trials_count=1000)
? 1
-- OK! --
---------------------------------------------------------------------
OK! All cases for Question 9 unlocked.
函数的实现如下
def max_scoring_num_rolls(dice=six_sided, trials_count=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 TRIALS_COUNT times.
Assume that the dice always return positive outcomes.
>>> dice = make_test_dice(1, 6)
>>> max_scoring_num_rolls(dice)
1
"""
# BEGIN PROBLEM 9
"*** YOUR CODE HERE ***"
max_num, max_average = None, 0
for i in range(1, 11):
this_average = make_averaged(roll_dice, trials_count)(i, dice)
if max_average < this_average:
max_num, max_average = i, this_average
return max_num
# END PROBLEM 9
符合评分脚本要求
$ python3 ok -q 09 --local
=====================================================================
Assignment: Project 1: Hog
OK, version v1.18.1
=====================================================================
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running tests
---------------------------------------------------------------------
Test summary
8 test cases passed! No cases failed.
Problem 10
一种策略,利用Free Bacon规则,在最有利时选择不抛骰子,此部分要求实现bacon_strategy
函数
该函数在不抛骰子时可以得到至少cutoff
分数时返回0,否则返回num_rolls
注:默认策略函数不知晓当前玩家在上一轮中取得的分数,因此不能预测由于规则Feral Hog所获得的额外分数。即一个策略不考虑规则Feral Hog,也不考虑规则Swine Swap
$ python3 ok -q 10 -u --local
=====================================================================
Assignment: Project 1: Hog
OK, version v1.18.1
=====================================================================
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unlocking tests
At each "? ", type what you would expect the output to be.
Type exit() to quit
---------------------------------------------------------------------
Question 10 > Suite 1 > Case 1
(cases remaining: 106)
>>> from hog import *
>>> bacon_strategy(0, 9, cutoff=8, num_rolls=5)
? 5
-- OK! --
---------------------------------------------------------------------
Question 10 > Suite 1 > Case 2
(cases remaining: 105)
>>> from hog import *
>>> bacon_strategy(9, 0, cutoff=6, num_rolls=5)
? 0
-- OK! --
---------------------------------------------------------------------
Question 10 > Suite 1 > Case 3
(cases remaining: 104)
>>> from hog import *
>>> bacon_strategy(50, 2, cutoff=9, num_rolls=5)
? 5
-- OK! --
---------------------------------------------------------------------
Question 10 > Suite 1 > Case 4
(cases remaining: 103)
>>> from hog import *
>>> bacon_strategy(32, 0, cutoff=5, num_rolls=4)
? 0
-- OK! --
---------------------------------------------------------------------
Question 10 > Suite 1 > Case 5
(cases remaining: 102)
>>> from hog import *
>>> bacon_strategy(20, 1, cutoff=1, num_rolls=4)
? 0
-- OK! --
---------------------------------------------------------------------
OK! All cases for Question 10 unlocked.
函数的实现如下:
def bacon_strategy(score, opponent_score, cutoff=8, num_rolls=6):
"""This strategy rolls 0 dice if that gives at least CUTOFF points, and
rolls NUM_ROLLS otherwise.
"""
# BEGIN PROBLEM 10
if free_bacon(opponent_score) >= cutoff:
return 0
return num_rolls # Replace this statement
# END PROBLEM 10
满足评分脚本要求
$ python3 ok -q 10 --local
=====================================================================
Assignment: Project 1: Hog
OK, version v1.18.1
=====================================================================
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running tests
---------------------------------------------------------------------
Test summary
106 test cases passed! No cases failed.
Problem 11
该策略利用了Swine Swap规则,该策略总是选择不投掷(在不投掷会触发有益交换的条件下),或总是选择避免不投掷(在不投掷会导致有害交换的条件下)
在除了以上两种情况外,该策略与Problem 10 中完成的策略保持一致
与上一个实现的策略相同,默认策略函数不知晓当前玩家在上一轮中取得的分数,因此不能预测由于规则Feral Hog所获得的额外分数
课程提供了提问脚本用于确保学生理解函数的作用
$ python3 ok -q 11 -u --local
=====================================================================
Assignment: Project 1: Hog
OK, version v1.18.1
=====================================================================
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unlocking tests
At each "? ", type what you would expect the output to be.
Type exit() to quit
---------------------------------------------------------------------
Question 11 > Suite 1 > Case 1
(cases remaining: 107)
>>> from hog import *
>>> swap_strategy(1, 19, 8, 6)
? 6
-- OK! --
---------------------------------------------------------------------
Question 11 > Suite 1 > Case 2
(cases remaining: 106)
>>> from hog import *
>>> swap_strategy(30, 54, 7, 6)
? 0
-- OK! --
---------------------------------------------------------------------
Question 11 > Suite 1 > Case 3
(cases remaining: 105)
>>> from hog import *
>>> swap_strategy(1, 19, 100, 6)
? 6
-- OK! --
---------------------------------------------------------------------
Question 11 > Suite 1 > Case 4
(cases remaining: 104)
>>> from hog import *
>>> swap_strategy(24, 1, 1, 6)
? 0
-- OK! --
---------------------------------------------------------------------
Question 11 > Suite 1 > Case 5
(cases remaining: 103)
>>> from hog import *
>>> swap_strategy(13, 18, 10, 6)
? 6
-- OK! --
---------------------------------------------------------------------
Question 11 > Suite 1 > Case 6
(cases remaining: 102)
>>> from hog import *
>>> swap_strategy(13, 18, 1, 6)
? 0
-- OK! --
---------------------------------------------------------------------
OK! All cases for Question 11 unlocked.
函数的实现如下:
def swap_strategy(score, opponent_score, cutoff=8, num_rolls=6):
"""This strategy rolls 0 dice when it triggers a beneficial swap. It also
rolls 0 dice if it gives at least CUTOFF points and does not trigger a
non-beneficial swap. Otherwise, it rolls NUM_ROLLS.
"""
# BEGIN PROBLEM 11
free_bacon_score = free_bacon(opponent_score) + score
if is_swap(free_bacon_score, opponent_score):
if free_bacon_score < opponent_score:
return 0
elif free_bacon_score > opponent_score:
return num_rolls
return bacon_strategy(score, opponent_score, cutoff, num_rolls) # Replace this statement
# END PROBLEM 11
上述实现满足评分脚本要求
$ python3 ok -q 11 --local
=====================================================================
Assignment: Project 1: Hog
OK, version v1.18.1
=====================================================================
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running tests
---------------------------------------------------------------------
Test summary
107 test cases passed! No cases failed.
Problem 12(可选)
假设对手的策略为总是投掷4枚骰子,要求学生设计一个最终策略,以后的较大的胜率,提示如下
swap_strategy
是一个优秀的默认策略- 追求以超过100分的分数获胜没有意义,因此可以尝试减少投掷骰子的数量来降低触发Pig Out规则的概率
- 尝试通过投掷至少1个骰子来触发有益交换
- 谨慎选择
num_rolls``和
cutoff```参数
课程提供了用于测试final_strategy
胜率的工具(但是要认证,没办法了,只能用run_experiments检测以下算了)
先尝试一下将交换策略设置为默认策略
def final_strategy(score, opponent_score):
"""Write a brief description of your final strategy.
*** YOUR DESCRIPTION HERE ***
"""
# BEGIN PROBLEM 12
return swap_strategy(score, opponent_score) # Replace this statement
# END PROBLEM 12
$ python3 hog.py -r
final_strategy win rate: 0.718
本身胜率挺高的,接下来按照提示尝试降低参数num_rolls
的值以降低风险
试了几个参数发现胜率居然降低了,然后发现swap_strategy
中参数num_rolls
参数的值和对手策略always_roll
中参数的值一致时是最保险的,调低胜率大幅度下跌,调高增长的不多且风险变高了,因此该参数的值最好与对手的一致
其余的提示没啥思路,准备学一学人工智能之后再回来看一看