当前位置:首页|资讯

自学CS61A Project1 Hog(核心篇)(第二期)

作者:翻车水王汪轓发布时间:2024-10-14

前言

我是愚谷ノ園みら,简称愚園みら,本账号的使用者之一的负责分享学习笔记的oc,呃话说oc真的应该干涉现实事务吗?总之,みら最近开始学习CS61A。打算记一点笔记激励自己学下去。


啊,忘了说的CS61A是一门……课?总之是UC Berkeley的CS入门课。嘛反正点开这篇文章的人应该不需要我来介绍CS61A是什么了(大概……)


以下部分都是基于已经装完环境,下载了相关课件,并且会使用ok进行评分的假设。

我也是初学者,请多包涵~如有错误,敬请斧正!


总之是正文

因为懒,我将会把这一段东西再重新,呃,复制粘贴一遍。

CS61A的第一个project是要制作一个叫hog的小游戏。以下是一些关于这个project的一些碎碎念,希望能帮到有需要的同学们。

详情请参考:https://cs61a.org/proj/hog/

这是Hog项目的主要网站(作业要求),本文之后的内容将会围绕这里的题目。

以及课程课本的翻译件:https://composingprograms.netlify.app/

非常好课本,使我的理解加深十倍甚至九倍。


如果把Hog的规则和追加规则也写进来的话,太长了,恕我贴一下上一篇的链接,请诸君自己看一看~

自学CS61A Project1 Hog(核心篇)(第一期)

本篇内容是在理解游戏规则的基础上!

呜哇这个东西总共有12题啊……

作业页面目录的截图

上次才做完第零题,今天我们来看前四题。


第一题

我们需要在`hog.py`写`roll_dice`这个函数,其功能:投掷`num_rolls`个骰子并计算得分。

这里请允许我再次介绍基础的得分规则:投掷0~10个骰子,若没有投到1,则得分为所有骰子点数之和;否则得分固定为1。

本函数的输入:

* `int num_rolls`(投掷个数)

* `function dice=six_sided`(骰子:默认六面)

本函数的输出:`int score`

鉴于老师们已经提供了dice()这个方法(在上一篇中也有提到),我们只需要调用dice()即可投掷骰子。

(实际上这和random.randint(1,6)是一样的,但更模块化(赞))

因此实现的思路也很简单,先初始化`score=0`,再`for`循环`num_rolls`次,每次把骰子点数累加上去。


值得注意的是Sow Sad规则。只要有一次投掷有遇到1,那么总体得分就会是1。

熟悉编程的同学们可能会立刻想到,在每次点数累加之前用`if`进行判断,如果遇到1,就立刻`return 1`就可以达成任务了。

实际上在提示里也提到这一点:在loop中提前return会打断loop。

但其实并不可以这么操作,原因:提前打断loop会打乱测试骰子的计数,导致通不过OK测试。嘛,在现实中肯定是提前打断更好。

但在这里,恕我使用这种似乎更为低效,但符合要求的方式:

再在函数的开头创建一个变量记录是否有投掷到1,默认为False,如果投掷到1就把这个变量变成True,在最后再判断输出score还是输出1。

这种思路的代码实现如下:

以上是第一题。


第二题

接下来要实现`boar_brawl`函数。回忆一下规则,这个规则是投掷0个骰子时的特殊得分规则。

如果玩家选择投掷0个骰子,则获得对手分数的十位数与自己分数的个位数之差的绝对值的三倍。若这个数为0,则获得1分。

输入:

* `int player_score`(玩家分数)

* `int opponent_score`(对手分数)

输出:Boar Brawl规则下的得分。


鉴于我们的这个函数有`player_score, opponent_score`作为输入,我们可以通过整除法`//`和取余`%`操作这些数,取到它们的个位与十位,再用`abs()`取绝对值。

实际上如果把数字转化为字符串,然后再用对列表的操作会更容易,但这是作业要求里明令禁止的。

我们根据规则的公式,将计算结果存储在`boar_brawl_score`这个变量中,

再用最大值函数`max()`取1和`boar_brawl_score`的最大值作为输出。

以上是第二题。


第三题

第三题的目标是写一个叫做`take_turns`的函数,目标是得到投掷骰子后的分数。

输入:

* `int num_rolls`(投掷数)

* `int player_score`(玩家分数)

* `int opponent_score`(对手分数)

* `fuction dice=six_sided`(骰子:默认六面)

输出:我方本轮得分


实际上可以看到这个函数本质上就是整合了基础规则和附加规则1后的产物。

我们只需要用if判断条件即可。

节选代码如下

以上是第三题。


值得注意的是:课件提供的代码里已经有一个叫`simple_update`的函数,整合了上述几个功能。


第四题

在第四题中,我们将要实现Sus Fuss这个规则(这里的Sus是猪属的意思,而不是可疑的意思)。

回顾:如果结算时,玩家的分数有3或4个因数(包括自身与1),则分数自动增长到下一个质数。


我们该如何实现这个功能?容我先拆分这个问题。

以下只是我个人的拆分方式,作为一个新手,我的分析可能有错或不标准的地方。希望能为个位读者带来抛砖引玉的作用。


首先,这个函数需要在哪里调用呢?

由于这是在每一轮骰子投掷之后,加分之后进行的,对方的回合开始之前。

所以应该是在`take_turn`的结算之后。


然后,它需要什么输入呢?

由于它的计算方式只和个人的分数相关,所以只需要自己的分数`int score`即可。


至于输出的话……也是结束之后自己的分数即可(它不会改变对手的分数)。所以输出也是一个`int`。


接下来是步骤中需要用到的东西。


如果结算时,玩家的分数有3或4个因数……

我们需要一个函数判定`score`是否有3或4个因数。


则分数自动增长到下一个质数

我们需要一个判定下一个质数的函数。

(值得注意的是老师已经给出了一个判定正整数是否是质数的函数`is_prime`。)


然后当然要把它们整合。


以下是作业中的那几个函数。


`num_factors`函数

作用:判断某个数有几个因数

输入:`int n`

输出:`int factors`

使用for循环,对1到n的所有数,判定:n是否能整除i?若能,则将因数+1。

代码实现如下:

`sus_points`函数

作用:判定分数是否需要上升至下一个质数。如果需要,返回新的分数;如果不需要,返回原本的分数。

输入:`int score`

输出:`int sus_point`

思路如下:

先判定输入分数是否有3或4个因数。

如果是,依次判定之后的数是否是质数,找到下一个质数。输出这个数。

如果不是,直接输出输入值。


寻找下一个质数的过程,我用了while循环,每次判断这个数是否是质数,不是就+1,直到找到为止。


代码实现如下:

`sus_update`函数

这个函数的作用是计算出Sus Fuss规则下的分数。


作业中已经包含了simple_update这个函数,用于更新有Boar Brawl规则下的分数。其实我们可以直接调用这个函数的……吧。但我还是选择用我们之前在第三题中写的`take_turns`函数。


输入:

`int num_rolls` 投掷的骰子数量

`int player_score` 玩家的分数

`int opponent_score` 对手的分数

`function dice=six_sided` 骰子(默认六面)

输出:

`int score` 考虑两条追加规则后的最终分数


首先,`take_turn`是怎么用的?

输入`num_rolls`,`int player_score`,`int opponent_score`(和 `dice`),输出包含Boar Brawl规则的加分。

也就是说,如果要得到回合结束时的分数,需要用当前分数加上这个函数的输出值。

容我将这个数据存在变量`updated_score`中。

然后,刚写的`sus_points`呢?输入分数,输出更新后的分数。

那么再把`updated_score`设为`sus_points(updated_score)`

最后再输出即可。


代码如下。

此处调用`take_turn`的时候,dice这个参数需要是dice而不是`dice=six_sided`。在`sus_update`所在的帧,dice是一个变量,是调用`sus_update`时传入的参数。


这样一路向下传,最终,我们在最外层传入的参数就可以统一地运用在过程中的每一个函数里。


啊,其实写`take_turn`函数的时候也有类似的情况,忘了说了。


以上就是第四题了。



Copyright © 2024 aigcdaily.cn  北京智识时代科技有限公司  版权所有  京ICP备2023006237号-1