[P] 结对项目:花见小路
[P] 结对项目:花见小路
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/buaa/BUAA_SE_2026_LR |
| 这个作业的要求在哪里 | [P] 结对项目:花见小路 - 作业 - 2026年春季软件工程 - 班级博客 - 博客园 |
| 我在这个课程的目标 | 提升团队协作能力,项目管理能力;学会编写一个完整软件项目的技能,为职业发展打下坚实基础;培养批判性思维和解决复杂工程问题的能力。 |
| 这个作业在哪个具体方面帮助我实现目标 | 培养团队协作能力 |
→ 📖 Q0.0(P) 【你可以在结对结束后补充】如果你的代码仓库包含 AIGC 的部分,列举使用的工具、模型和使用范围。若未使用则填写:本组提交的全部代码不包含AI补全或生成的部分。
本组提交的全部代码不包含AI补全或生成的部分。
Chapter.0 wasm从安装到入门
引入
→ 📖 Q0.1(P) 请记录下目前的时间。
2026/03/27 21:45
调查
→ 📖 Q0.2(I) 【你可以在结对结束后另行补充。】作为本项目的调查:
请如实标注在开始项目之前对 Wasm 的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
蒋渝:I 没有听说过。
吴震宏:II 仅限于听说过相关名词。
I. 没有听说过;
II. 仅限于听说过相关名词;
III. 听说过,且有一定了解;
IV. 听说过,且使用 Wasm 实际进行过开发(即便是玩具项目的开发)。
请如实标注在开始项目之前对桌游花见小路的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 不了解玩法和规则;
II. 听说过,且有一定了解;
蒋渝:I 不了解玩法和规则
吴震宏:I 不了解玩法和规则
总结
→ 📖 Q0.3(P) 请记录下目前的时间。
2026/03/27 22:38
Chapter.1 七色之缨
结对过程
→ 📖 Q1.1(P) 请记录下目前的时间。
2026/03/31 15:00
→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(例如查阅了哪些资料、如何设计判定逻辑、如何设计测试样例、遇到了什么问题、如何解决)。
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | 10 | 10 |
| - Estimate | - 估计这个任务需要多少时间 | 10 | 10 |
| DEVELOPMENT | 开发 | 80 | 100 |
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 10 | 15 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 20 | 30 |
| - Coding Standard | - 代码规范 | 5 | 5 |
| - Design | - 具体设计(确定怎么实现) | 10 | 10 |
| - Coding | - 具体编码 | 20 | 25 |
| - Code Review | - 代码复审 | 5 | 5 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 5 | 5 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 5 | 5 |
| REPORTING | 报告 | 10 | 10 |
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 5 | 5 |
| - Size Measurement | - 计算工作量 | 2 | 2 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 3 | 3 |
| TOTAL | 合计 | 100 | 120 |
- 我们首先查阅了AssemblyScript和Wasm的基础语法资料,熟悉其数据类型。然后计算双方score和count。最后根据轮数,得分,数量和规则进行if-else判定。测试样例主要测试了提前获胜或者平局这样的边界的条件。遇到的问题是不太熟悉怎么构建和配置相关环境,最后依照guide和询问同学解决了。
设计
→ 📖 Q1.3(P) 请说明你们为这个判定模块设计了哪些中间量或辅助函数;如果没有额外设计,也请说明为什么认为直接实现已经足够清晰。
我们直接定义了 myScore, oppScore, myCount, oppCount 等局部变量用于累计得分和标志物数量。由于此任务的核心为单次扫描加上多个顺序明确的判定分支,当前实现已经非常直观,高效了。
→ 📖 Q1.4(I) 请说明在这样一个规则判定类模块中,如何避免“漏判”“错判”或分支顺序错误等问题。
- 画一个流程图,枚举所有可能的分支,然后和一条一条的检查和测
- 编写覆盖率测试
- 构造边界测试点测试
测试
→ 📖 Q1.5(P) 请说明你们设计了哪些测试用例,这些测试分别覆盖了哪一类规则或边界情况。
主要设计了以下几类用例:
- 常规获胜:单纯地标分 >= 11。
- 数量获胜:无一方 >= 11,但某一方占据地标数 >= 4。
- 提前结束不判定:在轮次 < 3 时如果仍未达到胜利条件则返回 0。
- 第三轮平局决胜系列:包括总分相同但 G地标被占领、同分无G但 F地标被占领、甚至比对D/E地标等复杂的边界情况。
test("test1:一方分值达到 11 分而获胜", () => {
const result = judge([0, 0, 0, 1, 1, 1, 1], 1);
assert.equal(result, 1);
});
test("test2:一方获得至少 4 枚标记而获胜", () => {
const result = judge([-1, -1, -1, -1, 0, 1, 1], 2);
assert.equal(result, -1);
});
test("test3:前两小轮尚未满足胜利条件", () => {
const result = judge([1, 1, 0, 0, 0, 0, -1], 1);
assert.equal(result, 0);
});
test("test4:第三小轮结束时,总分不同,由总分高者获胜", () => {
const result = judge([1, 1, 0, 0, 0, 0, -1], 3);
assert.equal(result, -1);
});
test("test5:第三小轮结束时,总分相同,由最高档位倾心标记判定胜负", () => {
const result = judge([1, 1, -1, 0, -1, -1, 1], 3);
assert.equal(result, 1);
});
test("test6::第三小轮结束时平局", () => {
const result = judge([1, -1, 0, 1, -1, 0, 0], 3);
assert.equal(result, 2);
});
test("test7:补充边界:第一轮P1达到11分且P2达到4个标记", () => {
const result = judge([1, -1, -1, -1, -1, 1, 1], 1);
assert.equal(result, 1);
});
→ 📖 Q1.6(I) 请说明你对“先写测试再实现”与“先实现再补测试”两种方式的理解。
先测试再实现有利于更好地理解需求,从而在实现的时候更加清晰,避免一部分错误。但是先写测试对需求的理解要求也更高,可能导致前期耗时多进展慢。
先实现后测试可能在编写测试时受到已有代码的影响,固化测试思维,不容易想到写代码时遗漏的情况。先实现的好处在于能更快见到跑的通的代码,推进更快。
总结
→ 📖 Q1.7(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026/03/31 21:05
→ 📖 Q1.8(I) 请写下本部分的心得体会。
任务代码的实现相对简单,麻烦的主要是学习Wasm以及配置环境构建代码。
结对编程相对来说比较新颖。但是第一次尝试,效率不太高,很多时间其实浪费了。
Chapter.2 不祥之影
准备
→ 📖 Q2.1(P) 请记录下目前的时间。
2026/03/31 21:10
→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | 10 | 10 |
| - Estimate | - 估计这个任务需要多少时间 | 10 | 10 |
| DEVELOPMENT | 开发 | 210 | 220 |
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 20 | 20 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 20 | 20 |
| - Coding Standard | - 代码规范 | 5 | 5 |
| - Design | - 具体设计(确定怎么实现) | 25 | 30 |
| - Coding | - 具体编码 | 100 | 105 |
| - Code Review | - 代码复审 | 20 | 20 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 10 | 10 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 10 | 10 |
| REPORTING | 报告 | 10 | 10 |
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 5 | 5 |
| - Size Measurement | - 计算工作量 | 2 | 2 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 3 | 3 |
| TOTAL | 合计 | 230 | 240 |
- 这个任务要求通过历史记录推出当前状态,我们在字符串处理时遇到了一点麻烦。以及阅读规则也非常麻烦!(字太多了!!!)。解决方法是硬着头皮写。
代码可复用性与需求变更
→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑💻 T1 中已实现的代码进行了哪些复用和修改。
把算地标的逻辑抽出来做成辅助函数,最后根据双方抢到的地标情况,调用了一套类似 T1 的胜利结算机制(也就是用 settleBoard 代替了原来的单纯算分),此外没有其它复用。
→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
-
模块化设计
将系统分解成多个功能相对独立的模块,每个模块负责单一的功能(单一职责原则)。模块之间通过接口进行通信,减少模块之间的耦合。 -
高内聚低耦合
尽量使得系统中的模块高度内聚、功能单一,并减少模块之间的依赖(低耦合)。内聚的模块负责特定的功能,而模块间的交互通过明确的接口进行。 -
避免过度设计
只设计当前需求所需要的功能,避免过度设计和提前做不必要的假设。避免添加未来可能不需要的复杂功能。 -
设置常量
将一些需要用到的数字设置为常量,以便规则和配置改变时只修改数字不用改逻辑。
头脑风暴环节
→ 📖 Q2.5(P) 头脑风暴环节:
我们终于快要开始让程序玩游戏了!请尝试分析:T2 中不带 X 的操作记录比起实际对局多出了多少信息?如果加上 X,也就是失去了这部分信息的话,如何处理对小轮结束后状态的估计?
如果不带X,则可以清晰知道对手扔了什么牌。如果加上X,则不能确定每小轮结束后的具体状态。这个时候需要分析概率或者用蒙特卡洛算法推演。
总结
→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录 A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026/04/01 11:20
→ 📖 Q2.7(I) 请写下本部分的心得体会。
这部分实现也比较简单,主要挑战在读要求。
结对编程时容易出些低级错误(规则太细碎),同时一个人在写时另一个的时间用的不太充分。
不过结对编程本身还是比较有趣的。
Chapter.3 道途之荆
准备
→ 📖 Q3.1(P) 请记录下目前的时间。
2026/04/05 16:00
→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | 10 | 10 |
| - Estimate | - 估计这个任务需要多少时间 | 10 | 10 |
| DEVELOPMENT | 开发 | 300 | 335 |
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 40 | 50 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 40 | 60 |
| - Coding Standard | - 代码规范 | 10 | 10 |
| - Design | - 具体设计(确定怎么实现) | 50 | 60 |
| - Coding | - 具体编码 | 100 | 100 |
| - Code Review | - 代码复审 | 20 | 25 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 20 | 15 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 20 | 15 |
| REPORTING | 报告 | 10 | 15 |
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 5 | 5 |
| - Size Measurement | - 计算工作量 | 2 | 5 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 3 | 5 |
| TOTAL | 合计 | 320 | 360 |
- 首先阅读了规则,然后搜索了一些博弈策略,如贪心,启发式或者蒙特卡洛算法。最终的做法是编写启发式函数评估牌组的获胜率,并做出贪心的决策。
头脑风暴环节
→ 📖 Q3.3(P) 头脑风暴环节:
假设提供更充裕的时间和资源,这个游戏中你能找到的最优策略有可能是什么形式的?进行调研并总结分析。你还可以在任务结束后试着实现(不计分)。
最优策略有可能是基于带隐含信息的蒙特卡洛树搜索,或者虚拟遗憾最小化算法。由于花见小路的局面总数有限,但有未知发牌以及暗置牌,本质上是不完全信息博弈,用CFR求解出的纳什均衡策略,应当是最稳定的不败最优形式。
需求建模和算法设计
→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么选择行动类型?选牌如何更优?如何编程实现。
我们采用的是局部最优贪心与固定启发式的搜索。具体选择行动类型时,优先满足能锁定高分关键地标操作。比如若手中恰好有足以一锤定音凑齐某高分卡的地标,则优先使用“密约”单卡暗置确保获得。其次优先考虑利用“弃置”抛弃掉对自己和局势都没用的废牌;“赠与”动作需要进行最简单的两层试探,计算出即便对方抽取最好的一组,自己依然能稳拿胜局的分法。利用先前写的模拟进行一步博弈即可实现。
代码可复用性与需求变更
→ 📖 Q3.5(P) 请说明针对该任务,你们对 🧑💻 T2 中已实现的代码进行了哪些复用和修改。
主要复用了T2的calcCurrentState。在此基础上,我们封装调用这个函数并返回推测面板的情况,并调用T1的算分函数hanamikoji_judge。完成了决策模块的闭环。
→ 📖 Q3.6(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
- 模块化设计
将系统分解成多个功能相对独立的模块,每个模块负责单一的功能(单一职责原则)。模块之间通过接口进行通信,减少模块之间的耦合。 - 高内聚低耦合
尽量使得系统中的模块高度内聚、功能单一,并减少模块之间的依赖(低耦合)。内聚的模块负责特定的功能,而模块间的交互通过明确的接口进行。 - 避免过度设计
只设计当前需求所需要的功能,避免过度设计和提前做不必要的假设。避免添加未来可能不需要的复杂功能。
软件度量
→ 📖 Q3.7(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块决策能力很强?”,尝试提出一些可能的定量分析方式或测试方式。
设定不同层级的基线策略:如完全随机执行操作、或是按照规则总是出最左边手牌等。编写对战脚本让两者在花见小路的引擎内模拟对战。我们可以计算出胜率、平均获胜轮数等指标,通过这些数据说明决策模块的有效性。
总结
→ 📖 Q3.8(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026/04/07 22:05
→ 📖 Q3.9(I) 请写下本部分的心得体会。
在这一部分的开发过程中,我深刻感受到结对编程的优势。由于这部分工作对思考的要求较高,两个人一起讨论和推敲,能够产生更加全面和深入的思路。与单独工作相比,结对编程让我能够从同伴的角度获得不同的见解和建议,这对问题的解决起到了非常积极的作用。此外,我们在过程中也不断优化了合作方式,更加默契的配合让我们的工作效率得到了显著提升。
结对项目总结
结对过程回顾和反思
→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。
- 时间周期拉得太长了,开发不连续,写代码的时候都有点忘了之前的工作细节。不过这也是结对编程需要两个人都有空的特性造成的。
- 一个人写的时候另一个人的时间利用的不好。
- 讨论的效率不太高,可以先罗列出自己的要点和讨论围绕的问题。
→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。
优点:执行能力强很干练、测试代码写的很好、善于沟通
缺点:细节把握不足,写的代码里有个很难找的小bug
对结对编程的理解
→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。
结对编程的过程比较有趣味性。同时更能够打开思路找到好的设计架构和实现方法,并且还能相互检查避免一些低级错误。结对编程的缺点在于其实是降低了效率的,而且需要持续的沟通和找双方都有空的时间才能开始工作,给编程工作带来了额外的阻力。
代码实现提交
→ 📖 Q4.5(P) 请提供你们完成代码实现的代码仓库链接。
https://github.com/JiangShiyi0822/BUAASE2026-PairProgramming

浙公网安备 33010602011771号