[P] 结对项目:影蛇舞

[P] 结对项目:影蛇舞

项目 内容
这个作业属于哪个课程 2025年春季软件工程(罗杰、任健)
这个作业的要求在哪里 [P] 蛇影舞
我在这个课程的目标是 掌握软件工程原理与敏捷协作,实现高质量系统全周期工程化,开发出一款令人满意的软件。
这个作业在哪个具体方面帮助我实现目标 通过与一个人结对开发,了解结对开发的形式,提高自己的沟通能力和代码编写能力。

请将本文件在代码仓库外复制一份,一边阅读和完成结对项目、一边填写入代码仓库外的版本,或采取简记、语音备忘等方式记载较复杂问题的要点之后再补充。请不要将本文档内的作答提交到代码仓库。

Chapter.0 Belua multorum es capitums.(你是多首的怪物。)

引入

→ 📖 Q0.1(P) 请记录下目前的时间。

2024年3月26日 周三 12:00

调查

→ 📖 Q0.2(I) 作为本项目的调查:请如实标注在开始项目之前对 Wasm 的熟悉程度分级,可以的话请细化具体的情况。

I. 没有听说过;

II. 仅限于听说过相关名词;

III. 听说过,且有一定了解;

IV. 听说过,且使用 Wasm 实际进行过开发(即便是玩具项目的开发)。

I.没有听说过

具体说明:仅仅有所耳闻,但并没有对其有任何了解

总结

→ 📖 Q0.3(P) 请记录下目前的时间。

2024年3月26日 周三 12:20

Chapter.1 不畏迷茫,只管前进。(迷子でもいい、前へ進め。)

结对过程

→ 📖 Q1.1(P) 请记录下目前的时间。

2024年3月26日 周三 12:30

→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
  1. 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
  2. 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
Personal Software Process Stages 个人软件开发流程 预估耗时(分钟) 实际耗时(分钟)
PLANNING 计划 5 3
- Estimate - 估计这个任务需要多少时间 5 3
DEVELOPMENT 开发 65 47
- Analysis & Design Spec - 需求分析 & 生成设计规格(确定要实现什么) 15 5
- Technical Background - 了解技术背景(包括学习新技术) 15 15
- Coding Standard - 代码规范 5 3
- Design - 具体设计(确定怎么实现) 5 5
- Coding - 具体编码 10 6
- Code Review - 代码复审 5 3
- Test Design - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) 5 5
- Test Implement - 测试实现(设计/生成具体的测试用例、编码实现测试) 5 5
REPORTING 报告 20 20
- Quality Report - 质量报告(评估设计、实现、测试的有效性) 10 10
- Size Measurement - 计算工作量 5 5
- Postmortem & Process Improvement Plan - 事后总结和过程改进计划(总结过程中的问题和改进点) 5 5
TOTAL 合计 80 70

完成编程任务期间,我们依次做了下面的工作:

  1. 首先大致阅读了一下AssemblyScript的官方文档,重点研究了Array的内存操作方法,以便于储存蛇身。并且之后先编写了一个只能左右移动的基础版本,做好了前期的认知工作。
  2. 在编写的过程中发现蛇会异常穿墙,经过排查之后发现是坐标系理解错误。理论上我们应该采用数学坐标系,而不是屏幕坐标系。最后我们在编写的时候,在旁边放置了一个8x8的手绘坐标网格作为视觉参照,更加直观了。
  3. 接着我们进行蛇身逻辑的开发,但是发现会导致蛇身的瞬移。经过调试控制台输出坐标数据的时候,我们发现必须采用倒序更新,也就是从尾部先更新逐渐向头部,最终采用经典算法:
for (let i = snake.length - 1; i > 0; i--) {
  snake[i] = snake[i - 1];
}

  1. 接着我们发现了另外一个问题,我们只检测了撞墙的问题,并没有解决蛇头可能会触碰蛇身的问题。因为AssemblyScript缺少Set的数据结构,因此我们选择拼接字符串作为唯一key值来标记身体坐标:
const bodyKeys = new Set<string>();
bodyKeys.add(`${snake[i][0]},${snake[i][1]}`);

同时修正了边界的条件修正(坐标范围从1-8变成了0-7)

  1. 考虑路径的算法搜索。对于复杂的A*算法,不方便实现。然后针对于8x8的小网格,我们考虑使用更高效的BFS算法。对于路径的回溯问题,通过使用一个标记数组来解决。同时我们在队列中存储完整移动路径防止循环移动。
const visited = new Array<bool>(8*8).fill(false);
  1. 最后我们进行了算法性能的优化。在测试中,我们发现在200回合限制内性能完全达标。最后经过考虑,我们采用的贪吃蛇策略是:优先保证蛇存活,当存在多个安全方向时再通过使用曼哈顿距离,选择最接近食物的路径。

测试

→ 📖 Q1.3(P) 请说明针对该任务,你们设计和实现测试的方法及过程,包括但不限于:出于对需求的哪些考虑设计了哪些测试用例、如何评估所设计测试的有效性 等等。

首先我们对需求进行分析,这个游戏的核心需求是蛇能正确地移动、正确地吃到果子、避免碰撞,以及一个防止超时卡死。那我们设计用例进行测试的时候就可以围绕这些地方进行设计。

最开始我们设计了一个非常简单的,只需要通过斜向的运动就能吃到食物的案例第二个案例是一个通过z字型运动的案例,在这里主要是防止蛇撞到自己的身子。最后我们设计了一些泛化的随机策略,考虑了果子在边界等情况。

对于评估测试的有效性,我们认为就是评价这个测试设计的是否全面,也就是能不能覆盖从简单到复杂的全部场景。这有两个方面需要考量:一个是能不能覆盖多数的场景,一般来说这个只需要测试用例量大即可实现;第二个是边界测试,在这里指的就是果子在边界这种临界情况。我们设计的测试样例只需要覆盖了以上两种情况即可。

→ 📖 Q1.4(I) 请说明单元测试对软件开发的作用。
  • 提高代码质量。通过单元测试能更好地保证每个模块尽量不出现问题,相比于整个软件的测试更加的细致入微,能提升代码的整体质量,更不容易出bug
  • 加速开发和调试。如果直接进行整个软件的测试,有可能无法直接定位到bug的所在位置,需要不断地断点调试来发现问题模块;但是单元测试能直接锁定问题所在模块,方便调试
  • 降低维护成本。在不断进行迭代开发的时候,务必要有单元测试,否则在新的迭代部分出现问题的时候,无法确定是迭代的问题还是旧版本残留的问题
  • 增加开发信心。在经过单元测试之后,能极大概率保证这个模块不出现问题。那么在进行后续开发的时候,就可以直接进行迭代,而不用复盘之前的代码

总结

→ 📖 Q1.5(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。

2024年3月26日 周三 13:21

→ 📖 Q1.6(I) 请写下本部分的心得体会。

通过这个小小的项目,让我感受到了结对编程的乐趣,特别是在看到小蛇蛇能运行起来的时候,有很大的成就感。这次的项目是后面的基础,也是一切的开端。通过模块化的编程方法以及单元测试,我也基本了解了团队合作的重要性,希望后面能做出更好的项目。

Chapter.2 即使迷茫,也要前行。(迷子でもいい、迷子でも進め。)

结对过程

→ 📖 Q2.1(P) 请记录下目前的时间。

2024年3月26日 周三 13:21

→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
  1. 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
  2. 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
Personal Software Process Stages 个人软件开发流程 预估耗时(分钟) 实际耗时(分钟)
PLANNING 计划 5 5
- Estimate - 估计这个任务需要多少时间 5 5
DEVELOPMENT 开发 105 60
- Analysis & Design Spec - 需求分析 & 生成设计规格(确定要实现什么) 10 10
- Technical Background - 了解技术背景(包括学习新技术) 10 5
- Coding Standard - 代码规范 5 5
- Design - 具体设计(确定怎么实现) 5 5
- Coding - 具体编码 30 15
- Code Review - 代码复审 5 5
- Test Design - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) 15 5
- Test Implement - 测试实现(设计/生成具体的测试用例、编码实现测试) 25 10
REPORTING 报告 32 17
- Quality Report - 质量报告(评估设计、实现、测试的有效性) 20 10
- Size Measurement - 计算工作量 2 2
- Postmortem & Process Improvement Plan - 事后总结和过程改进计划(总结过程中的问题和改进点) 10 5
TOTAL 合计 142 82

T2实际上就是在T1的基础上进行绕过障碍物的操作,所以我们便设想在开始行动之前进行一次模拟判断。首先我们能确定一件事情是长度为4的蛇是不会撞到自己的(除非扭脖子),所以我们只需要考虑蛇头进行一次BFS找到最短路径并且记录,最后一步一步返回记录的动作即可。

代码可复用性与需求变更

→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑‍💻 T1 中已实现的代码进行了哪些复用和修改。

T1中,我们没有考虑带障碍的情况,只是直接寻找最短路径即可.在T2中,我们增加了障碍物,那么对于T1中所使用的BFS的策略依然可以使用,也就是大框架不变,只需要对细节上进行修改.如果在某条道路上要经过障碍物,我们直接认为这条分路失效;经过便利BFS之后,我们便可以得到最终结果.

→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。

关于设计思想,可以考虑SOLID原则,也就是:单一职责原则 (SRP),开闭原则 (OCP),里氏替换原则 (LSP),接口隔离原则 (ISP),依赖倒置原则 (DIP);也可以考虑设计模式,如工厂模式,设计者模式;还可以考虑使用模块化的思想,把复杂的问题拆解成一个个简单的模块;也可以考虑抽象与接口的实现方式,增强代码的复用程度.
设计冗余方面,我们可以考虑扩展点预留,也就是在可能变更的地方加入一个接口,先不填写仅仅预留位置,同时我们可以预留一些代码注释掉,增加之后开发的灵活度.

头脑风暴环节

**→ 📖 Q2.5(P) **只吃一个食物可满足不了贪吃蛇的欲望,请一起思考并简述以下场景中贪吃蛇的策略:

🧑‍💻 T2 的基础上,场地里不再是只有 1 个果子,而是总共有 n 个果子 (1 < n < 10 ),果子随机分布在场地中且不会刷新,保证不与障碍物重叠,保证每个果子均可达,且至少存在一条成功吃掉所有果子的路线,其余条件保持不变,请你找出一条吃完所有果子的行动路径。

只需要找到一条吃掉所有路线,而不用保证路径一定是最短的,那么我们可以直接利用贪心,每次利用BFS找到最近的果子吃掉,直到最后一个.但是要注意到一个问题,万一有一个果子进去之后就无法出来了该怎么办,毫无疑问只能将其放到最后.因为以及说过至少存在一条,那么这样的果子也最多只有一个,只需要提前辨别好即可.至于这个判断很简单,只需要看有没有C字形的围栏即可.

总结

→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。

2024年3月26日 周三 14:41

→ 📖 Q2.7(I) 请写下本部分的心得体会。

这一次是基于第一次的程序继续开发,让我明显的感觉到了迭代开发的思想,以及对于冗余开发的一点认识.几乎所有的程序都是需要迭代开发或者代码修补的,因此我们在写的时候需要预留一部分接口用于更新迭代,这样会让之后的工作变得简单.

Chapter.3 这就是我的前进、到我出场了!!!!!(It's MyGO!!!!!)

结对过程

→ 📖 Q3.1(P) 请记录下目前的时间。

2024年3月26日 周三 14:45

→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
  1. 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
  2. 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
Personal Software Process Stages 个人软件开发流程 预估耗时(分钟) 实际耗时(分钟)
PLANNING 计划 2 2
- Estimate - 估计这个任务需要多少时间 2 2
DEVELOPMENT 开发 160 148
- Analysis & Design Spec - 需求分析 & 生成设计规格(确定要实现什么) 10 10
- Technical Background - 了解技术背景(包括学习新技术) 10 5
- Coding Standard - 代码规范 10 5
- Design - 具体设计(确定怎么实现) 20 20
- Coding - 具体编码 60 68
- Code Review - 代码复审 10 20
- Test Design - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) 20 10
- Test Implement - 测试实现(设计/生成具体的测试用例、编码实现测试) 20 10
REPORTING 报告 45 45
- Quality Report - 质量报告(评估设计、实现、测试的有效性) 20 30
- Size Measurement - 计算工作量 5 5
- Postmortem & Process Improvement Plan - 事后总结和过程改进计划(总结过程中的问题和改进点) 20 10
TOTAL 合计 207 195

这个任务,我们在一开始便商量了一下,不决定采取训练模型的方法解决这个问题,诚然如果训练的时候考虑完善投入足够时间会有一个不错的动态逻辑来面对这个复杂的动态的博弈,但是我们确定了我们的目的是体验团队编程,而不是在优化性能上,便选择了使用开发起来较方便的静态策略。

然后我们便投入编程,因为T3如果选择静态策略便是两个优化方向,首先保证活着,其次保证走最短路径吃到果子。但是需求是简单的,实现却是磕磕绊绊。因为静态,所以很取决于种子和对手的策略,所以只能在实现的时候不断的PK,找到一种综合成绩不错的策略。

需求建模和算法设计

→ 📖 Q3.3(P) 请说明你们如何建模这一需求。

在这道题中,我们的任务是为多个贪吃蛇实现一个可以相互击杀的机制。这要求我们在模型中不仅要考虑障碍物的存在,还要考虑其他蛇的动态行为。具体来说,原本的地图中存在静态的障碍物,但是在这个需求中,其他蛇的身体也可以看作是动态的障碍物。因此,对于每一条蛇,其他蛇的身体和头部都需要被视为潜在的威胁和障碍物。

为了实现这一目标,我们将需要对每条蛇进行死亡状态的跟踪,并在蛇死亡时从地图中移除相应的蛇。蛇之间的碰撞会导致死亡,因此我们需要对蛇进行标记,标明它们是否存活。当蛇死亡时,其他蛇的行为不再受到该蛇影响,同时它的身影也从地图上消失。整个建模的结构与第二部分相似,唯一的区别在于对动态障碍物(其他蛇)的处理方式。

→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么避免死亡?怎么吃到更多果子?如何编程实现。
  • 如何避免死亡?
    理论上来说如果需要得分,都是会承担死亡风险的.(理论上如果足够直接把你包到墙角你不炸了吗)那么我们只能尽可能减少死亡.一个比较简单的方法就是规避风险,对于一条蛇的下一步,如果这一步还有另一条蛇可能会走或者本身就是障碍,那么我们就不走这一步.我们也把这个策略称为防守型策略。

  • 如何吃到更多的果子?
    吃果子总是伴随着风险,因为果子的出现通常意味着蛇头需要进入一个未知的区域,这可能是有敌人或者障碍物的地方。为了平衡风险和收益,我们采用了“贪心策略”,即尽量选择距离果子最近的安全区域。但这也会带来潜在的死亡风险。因此,对于可能存在碰撞的方向,我们做出了限制,避免明显的死亡风险,并在此基础上结合综合策略进行决策。

  • 如何编程实现?

    1. 棋盘建模: 我们首先根据给定的棋盘大小 n 创建了一个 board 数组来表示游戏的地图。每个位置可以是空地、蛇身、食物、其他蛇头、危险区域或者蛇尾。
    2. 动态障碍物: 对于每条蛇的身体,我们在 other_snakes 数组中进行处理,将其他蛇的身体视作障碍物。通过检查每个方向,判断蛇是否可以安全移动,并避免进入其他蛇的身体或危险区域。
    3. 优先级决策: 我们使用了一系列优先级来选择蛇的移动方向。首先优先选择吃果子的方向;其次,选择最安全的方向;最后,选择任意可以移动的方向。
    4. 综合判断: 当所有安全的方向都不合适时,我们通过计算距离来判断最佳方向,甚至可以在没有安全方向的情况下,选择最接近果子的方向。

    在代码实现中,我们使用了如下步骤来确保策略的有效性:

    • 死亡检测: 每条蛇的死亡状态会被跟踪。
    • 安全性检测: 对每个可能的移动方向,我们判断其是否安全(即是否会与其他蛇发生碰撞或进入危险区域)。这通过canMovewillDieisDanger等数组来实现。
    • 果子捕捉: 通过计算每个方向与果子之间的距离,结合安全性进行选择。优先选择那些能吃到果子且不会死亡的方向。
    • 综合策略: 当存在多个可能的移动方向时,我们根据安全性、果子距离等多个因素综合决定最终的移动方向。

    通过这些策略,我们能够在一定程度上减少死亡风险,并尽可能多地吃到果子。

软件度量

→ 📖 Q3.5(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块对弈能力很强?”尝试提出一些可能的定量分析方式。

测试程序模块的有效性可以有两种方法,一个是debug的测试环节,就是不断地通过一些刁钻的数据问题来测试程序是否正确,这个一般是一个简单的测试,主要检测代码对于特定的功能的正确性.

另一个就是实际测试,具体来说,我们可以通过两种方法来测试:

  • 自我对弈
    自我产生4条蛇进行对弈,相当于所有的蛇用的是同一套策略.那么我们可以用多次实验的平均分作为评判标准.这里的平均分指的是在只剩下至多一条蛇的时候四条蛇的均分在多次实验下的平均,平均分越高证明蛇蛇存活和得分的综合能力越高
  • 他人对弈
    找其他人进行4条蛇蛇互殴与1v1互殴,取多次的平均成绩即可.这样也是更加贴近实际了

总结

→ 📖 Q3.6(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。

2024年3月26日 周三 18:00

→ 📖 Q3.7(I) 请写下本部分的心得体会。

做到这里我们也是历时好多小时从零开始完成了一个比较完整的小游戏,也是体验了结对编程中一个驾驶员一个监测员的特点,这样分工也能减轻两个人各自的分工,同时能在写程序的时候更好地及时发现问题,相对于一个人写的时候需要最后统一检查的效率有了明显的提升,也是体会到了结对编程的意义.

结对项目总结

结对过程回顾和反思

→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。

结对编程的最重要的就是两个人的沟通,因为在一个驾驶员一个指挥员的过程之中,最难的就是两个人如何对任务目标有一个完整的把控.比如说当编程员进行编写程序的时候,指挥员如何快速的定位书写的意图以及功能成为一个难题,就像别人写的代码自己无法第一时间读懂一样,在这一方面我们完成的可能不是很好,还需要继续精进;另一个就是如何评判两人的工作量差距,使得两人的工作量不能相差太大.

→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。

优点:

  1. 学习能力强,对知识的掌握比较全面
  2. 比较有耐心,能包容我的错误
  3. 思维逻辑清晰

缺点:

1.相比于合作完成,可能更倾向于独立完成

对结对编程的理解

→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。

优点

  • 提升代码质量:双人协作可以互相审查代码,减少错误,避免后期大规模返工。
  • 知识共享与互补:不同技能和经验的开发者可以互相学习,拓宽技术视野。
  • 增强团队协作:减少“知识孤岛”问题,提高代码可维护性,使团队更熟悉整体项目。
  • 提高专注度:互相监督能减少懈怠,保持更高的工作效率,避免单人开发时的拖延现象。

缺点

  • 人力成本较高:两人共同完成同一任务,短期来看可能比独立开发效率低,需频繁沟通协调。
  • 合作冲突风险:若开发风格或习惯差异较大,可能导致摩擦,影响进度。
  • 易疲劳:持续高强度协作容易消耗精力,长时间配对可能导致注意力下降。
  • 依赖性增强:过度依赖搭档可能削弱独立解决问题的能力,不利于个人成长。

结对编程是一种敏捷开发的实践,强调的是开发和检查同步进行,比较适用于复杂的编程,对于简单的模块进行结对编程反而可能降低其完成效率。

代码实现提交

→ 📖 Q4.5(P) 请提供你们完成代码实现的代码仓库链接。

https://github.com/Meng-XuanYu/PairProgram

附录

附录A:基于 PSP 2.1 修改的 PSP 表格

Personal Software Process Stages 个人软件开发流程 预估耗时(分钟) 实际耗时(分钟)
PLANNING 计划
- Estimate - 估计这个任务需要多少时间
DEVELOPMENT 开发
- Analysis & Design Spec - 需求分析 & 生成设计规格(确定要实现什么)
- Technical Background - 了解技术背景(包括学习新技术)
- Coding Standard - 代码规范
- Design - 具体设计(确定怎么实现)
- Coding - 具体编码
- Code Review - 代码复审
- Test Design - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例)
- Test Implement - 测试实现(设计/生成具体的测试用例、编码实现测试)
REPORTING 报告
- Quality Report - 质量报告(评估设计、实现、测试的有效性)
- Size Measurement - 计算工作量
- Postmortem & Process Improvement Plan - 事后总结和过程改进计划(总结过程中的问题和改进点)
TOTAL 合计
posted @ 2025-04-06 21:22  黑夜中的黎明  阅读(31)  评论(0)    收藏  举报