[P]结对项目:影舞蛇
[P]结对项目:影舞蛇
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 2025年春季软件工程(罗杰、任健) |
| 这个作业的要求在哪里 | [P]结对项目:影舞蛇 |
| 我在这个课程的目标是 | 学习软件工程的基础知识,在结对以及团队任务中实践各种开发方法与流程,学会如何与其他开发者更好地合作,和我的组员们一起开发一个让我们值得骄傲的项目 |
| 这个作业在哪个具体方面帮助我实现目标 | 和队友合作完成结对编程任务,体验结对开发的流程 |
Chapter.0 Belua multorum es capitums.(你是多首的怪物。)
引入
→ 📖 Q0.1(P) 请记录下目前的时间。
3月28日9:50
调查
→ 📖 Q0.2(I) 作为本项目的调查:请如实标注在开始项目之前对 Wasm 的熟悉程度分级,可以的话请细化具体的情况。
I. 没有听说过;
II. 仅限于听说过相关名词;
III. 听说过,且有一定了解;
IV. 听说过,且使用 Wasm 实际进行过开发(即便是玩具项目的开发)。
I
总结
→ 📖 Q0.3(P) 请记录下目前的时间。
3月28日10:15
Chapter.1 不畏迷茫,只管前进。(迷子でもいい、前へ進め。)
结对过程
→ 📖 Q1.1(P) 请记录下目前的时间。
3月28日10:16
→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | 2 | 2 |
| - Estimate | - 估计这个任务需要多少时间 | 2 | 2 |
| DEVELOPMENT | 开发 | 114 | 73 |
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 10 | 5 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 30 | 20 |
| - Coding Standard | - 代码规范 | 2 | 2 |
| - Design | - 具体设计(确定怎么实现) | 20 | 10 |
| - Coding | - 具体编码 | 20 | 20 |
| - Code Review | - 代码复审 | 2 | 1 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 20 | 10 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 10 | 5 |
| REPORTING | 报告 | 14 | 13 |
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 10 | 10 |
| - Size Measurement | - 计算工作量 | 2 | 2 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 2 | 1 |
| TOTAL | 合计 | 130 | 88 |
在完成编程任务期间,我们首先仔细阅读了任务要求以及附录A中基于PSP 2.1修改的表格,对项目的总体目标、功能需求以及预估耗时进行了详细了解,并在团队内部进行了初步讨论,确保每个人都对任务目标和关键技术点(如AssemblyScript的使用)有一致的认识。
为了确保项目顺利进行,我们针对AssemblyScript的相关文档和示例代码进行了深入学习,了解了其基本语法、编译流程以及常见问题。通过查阅官方文档、在线博客和论坛帖子,我们吸收了其他开发者在实际使用过程中积累的经验,为后续开发奠定了理论基础。
在明确需求和技术背景后,我们将整个编程任务拆解为多个小模块(如核心逻辑实现、移动算法、边界条件处理等),并制定了详细的开发计划。团队讨论后确定了各个模块的实现思路和设计方案,明确了各个阶段的目标和检查点。
按照设计方案进入编码阶段,首先实现了基本的功能模块。编码过程中,我们通过小规模单元测试不断验证每个模块的正确性。在初期遇到编译错误、逻辑漏洞及运行时异常时,通过查阅资料、调试工具和团队内部的讨论,逐步修复问题并优化代码结构。
在完成初步编码后,我们采用了两种方式进行测试:
-
课程组测试用例验证:首先使用课程组提供的测试程序对核心功能进行初步验证。
-
自设计测试用例:针对实际需求中的边界情况(如蛇的基本移动、觅食策略以及避障逻辑),设计了多组测试用例,确保在各种场景下功能表现符合预期。
通过控制台输出和图形化对比,我们仔细检查每一步的决策结果,反复调试直至所有测试通过。
在功能和测试都达到预期后,我们进行了代码复审,确认代码质量和逻辑完整性。最后整理开发过程中遇到的问题、解决方案和测试结果,撰写了详细的项目报告,并对整个开发流程进行了总结和反思,为后续项目积累了宝贵经验。
测试
→ 📖 Q1.3(P) 请说明针对该任务,你们设计和实现测试的方法及过程,包括但不限于:出于对需求的哪些考虑设计了哪些测试用例、如何评估所设计测试的有效性 等等。
Chapter1的情境较为简单,测试的过程也不复杂
(1)基本移动测试
测试蛇能够正确解析输入数据,并执行移动操作。用test.js中的测试样例检测即可。
(2)觅食策略测试
我们采用了贪心算法,蛇走向果子的距离应该最短。
蛇应该向着果子的方向折线前进,过程中不应该发生与果子方向相反的位移。
当然有一些特殊的情况,比如蛇身将果子围在场地的角落,蛇需要让出蛇身才能吃到果子,这一点主要在避障测试中说。
(3)避障测试
撞墙检测:“撞墙”检测应该有效
初始蛇头在(8,4),向右(+x)。
贪心的觅食策略在一定程度上降低了撞墙的风险,但如果出现蛇形成环的情况,蛇头为了脱困有可能会因为策略不佳而撞墙
蛇身碰撞检测:
如果蛇身阻挡了蛇头向果子的去路,蛇不能为了吃到果子而撞向蛇身。
assert.strictEqual(greedy_snake_fn_checker([1,3,1,2,2,2,2,1], [1,1], greedy_snake_move) >= 0, true);
蛇形成环,如 U 形结构,蛇身将蛇头环绕在场地的一角,蛇为了去吃果子可能面临移动到自身身体的风险,蛇需要通过向蛇尾“转圈”来脱困。
assert.strictEqual(greedy_snake_fn_checker([8,1,7,1,7,2,8,2], [1,8], greedy_snake_move) >= 0, true);
测试有效性
在测试中将每次决策得到的方向输出到控制台
assert.strictEqual(greedy_snake_fn_checker([8,1,7,1,7,2,8,2], [1,8], greedy_snake_move) >= 0, true);对应的输出:
direction: 0
direction: 1
direction: 1
direction: 1
direction: 1
direction: 1
direction: 1
direction: 1
direction: 0
direction: 0
direction: 0
direction: 0
direction: 0
direction: 0
Total turn: 14
可以通过画图的方式和控制台的输出进行对比
→ 📖 Q1.4(I) 请说明单元测试对软件开发的作用。
单元测试在软件开发中起着至关重要的作用。它是指对程序中最小的可测试单元(如函数或方法)进行验证,以确保其行为符合预期。在开发过程中,单元测试有助于及早发现和定位错误,尤其是在模块逻辑复杂或数据依赖性强的情况下。通过对关键函数进行覆盖测试,开发者可以确保每个功能模块都在独立环境下正常运行,从而有效减少因局部错误引发的系统性问题。
此外,单元测试还能为后期代码重构提供保障。当需要修改或优化代码时,已有的测试用例可以帮助开发者判断改动是否破坏了原有逻辑,提升代码的可维护性和可扩展性。同时,系统稳定性也因持续测试而得到加强。
在团队协作中,单元测试还是确保多人开发一致性的重要手段。每位成员编写的模块都应通过标准化的测试验证,从而在整体集成时减少冲突与异常。因此,良好的单元测试不仅能提升开发效率,也为软件质量和长期演化打下坚实基础。
总结
→ 📖 Q1.5(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
3月28日11:43
→ 📖 Q1.6(I) 请写下本部分的心得体会。
项目过程中,我们从零开始深入学习并实践了AssemblyScript的开发,这不仅让我们掌握了新技术的基本用法,也提高了在遇到技术难题时自主查找资料、调试代码的能力。尤其是在处理编译和运行时错误时,学会了如何迅速定位问题,并利用官方文档和在线资源找到解决方案。
实际开发中我们也遇到了一些预料之外的问题,比如边界情况的特殊处理和复杂逻辑的错误调试。通过不断试错和反思,我们建立起了一套行之有效的问题解决流程,也认识到在设计阶段对各种可能情况做充分预判的重要性。今后在类似项目中,我们将更注重需求分析的全面性和测试用例的覆盖率。
Chapter.2 即使迷茫,也要前行。(迷子でもいい、迷子でも進め。)
结对过程
→ 📖 Q2.1(P) 请记录下目前的时间。
4月2日11:32
→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | 2 | 2 |
| - Estimate | - 估计这个任务需要多少时间 | 2 | 2 |
| DEVELOPMENT | 开发 | 104 | 81 |
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 10 | 5 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 10 | 20 |
| - Coding Standard | - 代码规范 | 2 | 2 |
| - Design | - 具体设计(确定怎么实现) | 30 | 14 |
| - Coding | - 具体编码 | 30 | 24 |
| - Code Review | - 代码复审 | 2 | 1 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 20 | 10 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 10 | 5 |
| REPORTING | 报告 | 14 | 13 |
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 10 | 10 |
| - Size Measurement | - 计算工作量 | 2 | 2 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 2 | 1 |
| TOTAL | 合计 | 130 | 96 |
代码可复用性与需求变更
→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑💻 T2 中已实现的代码进行了哪些复用和修改。
我们对碰撞检测函数isColliding()进行了复用,同时也对其进行了修改,在函数中加入了障碍物检测逻辑。
添加了可达检测函数isReachable()通过BFS判断果子是否可达。
另外在移动策略上也有比较大的修改。这次不仅仅是靠曼哈顿距离来决定移动方向了,因为障碍物的存在可能会导致“绕远”。于是我们添加了一个bfsMove()函数,采用BFS寻找最近的路径,同时决策出下一步走向哪个方向。
→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
设计思想
-
模块化设计
将程序拆分为职责明确、低耦合高内聚的模块,如决策逻辑、碰撞检测、数据更新、得分计算等分别独立封装,这样若修改某部分逻辑(例如替换决策策略),不会影响其他模块。 -
接口/抽象设计
抽象出统一接口,使得不同策略、输入结构、评估函数可以灵活替换。例如可以为“决策函数”设计一个统一的接口 ,不同策略如贪心、博弈或深度搜索都可以按需实现。 -
数据驱动设计
让规则逻辑依赖外部数据(如地图大小、蛇数量、决策参数等),而非硬编码。这样更容易调整游戏规则、实验不同配置。例如将地图参数和蛇属性封装成结构体传入,而非散乱传参。
设计冗余(为未来变更预留余地)
-
预留数组容量
在如snakeScores,lastFoodPositions等数组设计时,考虑最大蛇数量和最大食物数,避免未来扩容影响性能或结构。 -
保留未用参数 / 标记字段
在函数接口中保留如round,mode,configFlags等参数,即使当前未使用,也为未来增加回合数逻辑、难度设定等提供插口。 -
注释与日志接口预留
代码中可保留注释说明潜在扩展点,或提供日志输出开关,如// console.log()结构,有助于调试、行为评估或展示回放。 -
保留行为追踪变量
如snakeScores(蛇的当前分数)的记录为后续引入博弈策略或评价机制提供基础,同时也为比赛复盘、性能对比提供支撑。
头脑风暴环节
**→ 📖 Q2.5(P) **只吃一个食物可满足不了贪吃蛇的欲望,请一起思考并简述以下场景中贪吃蛇的策略:
在 🧑💻 T2 的基础上,场地里不再是只有 1 个果子,而是总共有 n 个果子 (1 < n < 10 ),果子随机分布在场地中且不会刷新,保证不与障碍物重叠,保证每个果子均可达,且至少存在一条成功吃掉所有果子的路线,其余条件保持不变,请你找出一条吃完所有果子的行动路径。
策略
-
路径规划方式:
由于果子数量较多,且场地中有障碍物,使用 广度优先搜索 来规划最短路径是一个合理的选择。BFS 适用于无权图的最短路径搜索,保证贪吃蛇不会绕远路。 -
吃果子顺序的确定:
贪心策略:每次选择当前蛇头到最近果子的最短路径,吃完后重新计算下一步目标。
全局最优策略:构建一个最短路径哈密顿回路(Hamiltonian Path),即找到一种顺序能保证吃完所有果子且不陷入死路。
动态路径规划:如果果子数量较少,计算所有果子排列的最短吃完顺序(如使用 旅行商问题思路)。 -
确保不死路
在每一步规划后,模拟未来路径,检测是否会导致剩余果子不可达(用BFS检测)。若当前路径可能导致死路,改选次优路径。
总结
→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
4月2日13:08
→ 📖 Q2.7(I) 请写下本部分的心得体会。
Chapter.3 这就是我的前进、到我出场了!!!!!(It's MyGO!!!!!)
结对过程
→ 📖 Q3.1(P) 请记录下目前的时间。
4月5日17:06
→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | 2 | 2 |
| - Estimate | - 估计这个任务需要多少时间 | 2 | 2 |
| DEVELOPMENT | 开发 | 214 | 269 |
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 20 | 35 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 10 | 20 |
| - Coding Standard | - 代码规范 | 2 | 2 |
| - Design | - 具体设计(确定怎么实现) | 60 | 66 |
| - Coding | - 具体编码 | 60 | 70 |
| - Code Review | - 代码复审 | 2 | 1 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 30 | 40 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 30 | 35 |
| REPORTING | 报告 | 24 | 33 |
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 20 | 30 |
| - Size Measurement | - 计算工作量 | 2 | 2 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 2 | 1 |
| TOTAL | 合计 | 240 | 304 |
需求建模和算法设计
→ 📖 Q3.3(P) 请说明你们如何建模这一需求。
游戏场景建模
首先,我们需要对游戏场景进行建模,满足最基本的需求。
棋盘大小 (n):控制棋盘的尺寸,影响蛇的移动范围。
蛇的位置和状态 (snake 和 other_snakes):每条蛇的位置由一组坐标表示,蛇的头部位置最为关键。
果子的位置 (foods):果子的位置需要被持续追踪,蛇要根据这些位置进行移动。
碰撞检测 (isColliding):确保蛇在移动时不会撞墙或撞到其他蛇。
分数统计
通过 snakeScores 数组来追踪每条蛇的得分。每次蛇吃到果子,得分增加。得分不仅影响蛇的决策,也会影响它在争夺果子时的行为:
如果一个蛇的分数比另一个蛇的高,它可能更有信心去争夺果子。
如果两条蛇在争夺果子,分数高的一方会选择更激进的行为(如直接冲向果子),而分数低的一方则可能选择躲避。
通过 update_last_food_positions 和 find_eaten_foods 函数,记录消失的果子,并将其从当前果子列表中移除,同时为吃到果子的蛇加上分数。
行为选择建模
行为选择的关键在于如何在不同情况下选择最优的移动方向。
1v1和4snakes的策略选择是不同的。
→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么避免死亡?怎么吃到更多果子?如何编程实现。
趋利
考虑到果子分布随机并没有在吃果子策略上下很多功夫。在每一步决策时,蛇会计算自己当前的位置和所有果子的位置的距离(曼哈顿距离),然后选择距离自己最近的果子进行争夺。这样可以确保尽快地吃到果子。
避害
除了最基础的碰撞检测外还针对1v1的情况设置了每一步的进攻防御策略。
在争夺果子的过程中会判断是否有其他蛇在附近,尤其是在选择果子时。如果发现附近有敌人的蛇头,蛇会比较自己和对方的分数来决定是吃掉该果子,还是转一个更安全的路径。
分数高的话蛇会选择吃该果子,因为即使同归于尽也可与取得胜利,如果分数低的话就会选择避让。
//发生冲突
if (collision) {
if (myScore > enemyScore) {
// 冲刺!
} else {
// 避让
}
}
在4snakes混战中如果蛇遇到争夺果子的情况会毫不犹豫选择存活而不是同归于尽。
软件度量
→ 📖 Q3.5(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块对弈能力很强?”尝试提出一些可能的定量分析方式。
胜率统计
写一个脚本与其他蛇进行大量的对战(万场以上)。不过真实的对战场次比较少,有一定的运气成分,除非实力悬殊否则很难通过胜率判断谁一定能够晋级。
平均得分
场游戏统计蛇吃到的果子数量(得分),计算平均分,衡量其吃果子的能力。
平均生存回合数
衡量蛇的生存能力,生存越久,表示它更擅长避开死亡威胁,尤其是4snakes模式中。
总结
→ 📖 Q3.6(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
4月5日22:10
→ 📖 Q3.7(I) 请写下本部分的心得体会。
npm run display-test后看到自己的蛇会动后很高兴
看到蛇会攻击/避害后还挺有成就感的
成功当一回赛博蛐蛐
结对项目总结
结对过程回顾和反思
→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。
→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。
首先,在合作方式与分工方面,我们虽然完成了任务,但在具体操作中仍存在一定的不平衡。有时一方在主导操作,另一方则相对被动,容易导致“一个人做,另一个人看”的局面。我们可以通过定期轮换角色,或者在每个阶段开始前明确具体分工,来提升双方的参与感和效率。
从节奏和效率来看,结对编程过程中也存在一定的时间浪费,长时间集中注意力会快速导致疲劳从而引发分心走神。以后可以尝试在结对编程的过程中多休息几次,便于提高效率;另外,刚开始结对的时候有些手忙脚乱,建议在每个阶段设立小目标并回顾执行情况,也有助于提高协作效率。
→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。
优点
思考问题冷静且条理清晰
擅长使用各种工具
会打台球
缺点
因为打台球第一次结对编程鸽了我50min
对结对编程的理解
→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。
亲自体验了一次结对编程后对其优缺点的感受不再只是“纸上谈兵”。
结对编程是一种值得尝试的协同开发方式,特别适合难度较高、逻辑复杂任务场景。双人思维有助于加快问题解决速度,避免程序员长时间卡壳或陷入思维误区。
当然在某些简单或重复性任务中,这种方式可能导致资源浪费,长时间同时也结对容易引发疲劳,尤其当两位程序员节奏不一致或沟通不畅时,效率反而下降。
合理安排结对时长、明确分工机制、并为成员提供良好沟通环境,是确保结对编程发挥最大效用的关键。
浙公网安备 33010602011771号