我是愚谷ノ園みら,简称愚園みら,本账号的使用者之一的负责分享学习笔记的oc。啊,我不会干涉各位号主们的其他事物,只会默默在专栏文件夹里发CS/AI相关的学习笔记。
总之,みら最近开始学习CS61A。打算记一点笔记激励自己学下去!
这才第一个项目,已经有点想放弃了……
啊,忘了说的CS61A是一门CS相关的课?总之是UC Berkeley的CS入门课。嘛反正点开这篇文章的人应该不需要我来介绍CS61A是什么了(大概……)
以下部分都是基于已经装完环境,下载了相关课件,并且会使用ok进行评分的假设。
其实我也没怎么认真看课和课件,英语让人头大。
我也是初学者,请多包涵~如有错误,敬请斧正!
因为很懒,我将会把这一段东西再重新,呃,再复制粘贴第二遍。
CS61A的第一个project是要制作一个叫hog的小游戏。以下是一些关于这个project的一些碎碎念,希望能帮到有需要的同学们。
详情请参考:https://cs61a.org/proj/hog/
这是Hog项目的主要网站(作业要求),本文之后的内容将会围绕这里的题目。
以及课程课本的翻译件:https://composingprograms.netlify.app/
非常好课本,使我的理解加深十倍甚至九倍。
如果把Hog的规则和追加规则也写进来的话,太长了,恕我贴一下第一篇的链接,请诸君自己看一看~
本篇内容是在理解规则,并且写完了游戏模拟器(核心?)部分的基础上!
如果还记得在这里“策略”是什么意思就更好了!虽说接下来马上就会又提到的。
策略(strategy)是一个函数。
在自己的回合中,策略函数需要输入自己和对手的分数。
而策略函数的返回值,是这回合自己打算投的骰子数量。
理解这点之后,就可以解决之后的问题了。
本篇基本上都是和固定投掷几个骰子的策略相关。
`always_roll(n)`策略,顾名思义,就是无论什么情况,都只投n个骰子。
但是!`always_roll()`这个函数,它的返回值是一个策略。也就是说它是个高阶函数。
或许可以复习一下这个:
https://composingprograms.netlify.app/1/6
在本系列的第一篇中也出现过高阶函数。
于是我们需要在`always_roll`里定义一个叫做strategy的函数然后返回它。
strategy的输出一直是n就可以了。
这次的代码如下。
我们需要在这里测试:一个策略是否是`always_roll`。
我想到的做法只有一个:用for循环把所有可能性全列一遍。
我们对0~goal的所有己方分数循环,每个循环中,再对0~goal的所有对手分数循环。
两层循环中,用if判定strategy(i,j)是否等于strategy(0,0)。只要有一种不相等,就return False
所有循环都走完,还没有不相等,那就return True。
是举反例证伪的思路呢。
还是附一下代码吧。
这个高阶函数的作用是:重复调用times_called遍original_function(两者皆为此函数的输入参数),后取均值。
在这里我们来回答一些OK评分器的问题:
Q:为什么这个函数是个高阶函数?(原因之一)
A:它以函数作为输入参数!(至少我是这么回答的,它算我对)
Q:传入make_averaged这个函数的函数,有多少参数?
A:任意数量皆可。因此我们需要用*args来调用它。
为了理解这个问题(意思:我看的时候没懂),现在容我把OK里的题目贴出来:
最后的输出应该是多少呢?
首先dice是一个骰子函数,每次执行都会输出数字。这里是固定为3 1 6 5循环的顺序。
roll_dice是什么呢?是第一题(请见第二篇文章)要求写的函数,是包含了Sow Sad规则的记分函数。
也就是说,我们这次要make_average的对象,是算分。
averaged_roll_dice是一个函数,它的作用是,执行1000次计算roll_dice(...),并计均分。
最后,到执行averaged_roll_dice(2, dice)的时候,就很明确了:这里的两个参数是给roll_dice(...)的。
所以,这段代码的含义是:每次roll两下dice,计算均分。
第一回投出3分和1分,计为1分(触发Sow Sad),第二回投出5分和6分,计为11分。
因此,均分是:6.0分!(因为要求写成float)
上面的例子里也提到了:make_averaged(...)的输出结果是个函数,因此我们在这个函数里要做的事情是,定义一个新的函数,然后输出它。
在这个函数内部,我们需要计算执行多次某函数之后的均值。
代码如下:
补充说明:如果用lambda+list/tuple,似乎可以一行写完,但是没必要吧!
我们要通过暴力测试模拟出一直投几个骰子的收益最大。
这个函数的输入是固定的:骰子函数(默认六面)与测试次数(默认1000)。
输出则是对于这款骰子的最佳投掷个数。
作业要求我们从1开始试到10。(为什么不试0?因为0本来就不适合当作策略。)
这里考查的依然是求最大值。
先把max_score和max_num_rolls设为0,然后从1~10循环,通过调用make_averaged计算均分。若均分大于最大分max_score,则记录当前的max_score和max_num_rolls。
最后输出max_num_rolls。
代码如下:
根据以上模拟,我们得出结论:对于六面骰子,每次投掷6个骰子,得到的均分最高。