[P] 结对项目:花见小路
结对项目:博客问题清单
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 北航2026年春季软件工程 |
| 这个作业的要求在哪里 | [P] 结对项目:花见小路 |
| 我在这个课程的目标是 | 接触理解应用现代软件工程常用的开发方式,锻炼自己编写代码以及团队协作的能力 |
| 这个作业在哪个具体方面帮助我实现目标 | 体验结对编程开发,从中获得经验并总结和思考 |
→ 📖 Q0.0(P) 【你可以在结对结束后补充】如果你的代码仓库包含 AIGC 的部分,列举使用的工具、模型和使用范围。若未使用则填写:本组提交的全部代码不包含AI补全或生成的部分。
本组提交的代码包含少量 AIGC 辅助生成的部分。使用的工具主要是 Codex / GPT-5,使用范围主要包括:帮助理解题目要求、生成和补充测试样例、辅助完成 T2/T3 的部分代码实现、帮助整理 questions.md 中的文字内容。最终代码和文字内容均经过人工检查和修改。
Chapter.0 wasm从安装到入门
引入
→ 📖 Q0.1(P) 请记录下目前的时间。
2026-04-04 20:10
调查
→ 📖 Q0.2(I) 【你可以在结对结束后另行补充。】作为本项目的调查:
刘笑晨:I,I
请如实标注在开始项目之前对 Wasm 的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 没有听说过;
II. 仅限于听说过相关名词;
III. 听说过,且有一定了解;
IV. 听说过,且使用 Wasm 实际进行过开发(即便是玩具项目的开发)。
请如实标注在开始项目之前对桌游花见小路的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 不了解玩法和规则;
II. 听说过,且有一定了解;
总结
→ 📖 Q0.3(P) 请记录下目前的时间。
2026-04-04 20:31
Chapter.1 七色之缨
结对过程
→ 📖 Q1.1(P) 请记录下目前的时间。
2026-04-04 20:35
→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 5 | 5 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 10 | 10 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 10 | 10 |
| - Coding Standard | - 代码规范 | 0 | 0 |
| - Design | - 具体设计(确定怎么实现) | 5 | 0 |
| - Coding | - 具体编码 | 10 | 10 |
| - Code Review | - 代码复审 | 5 | 0 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 5 | 5 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 10 | 13 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 10 | 25 |
| - Size Measurement | - 计算工作量 | 5 | 3 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 5 | 0 |
| TOTAL | 合计 | 80 | 81 |
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(例如查阅了哪些资料、如何设计判定逻辑、如何设计测试样例、遇到了什么问题、如何解决)。
2.查阅的资料:
查阅了https://www.assemblyscript.org/来学习as的基本语法
判定逻辑设计较为简单,根据指导书的说明直接实现
测试样例的设计:借助 AI 阅读指导书,根据规则给出了一些测试用例
遇到的问题:没有遇到什么难以解决的问题,可能也就是对语法不熟悉看了看官方教程
设计
→ 📖 Q1.3(P) 请说明你们为这个判定模块设计了哪些中间量或辅助函数;如果没有额外设计,也请说明为什么认为直接实现已经足够清晰。
仅仅设计了“我”和对手的分数以及“我”和对手得到的倾心数作为变量,没有设计额外的辅助函数。T1的逻辑比较清晰,按照题目所给的逻辑依次下推不会出现什么大问题。
→ 📖 Q1.4(I) 请说明在这样一个规则判定类模块中,如何避免“漏判”“错判”或分支顺序错误等问题。
建议严格遵循既定的判定逻辑,采用自顶向下的方式逐步推演全量场景。推荐借助表格进行穷举,以杜绝错判与漏判。同时,需对各类情况设定明确的优先级,遵循‘先易后难’的原则进行排序。以此构建的分支架构将更为严密,执行次序也更有保障
测试
→ 📖 Q1.5(P) 请说明你们设计了哪些测试用例,这些测试分别覆盖了哪一类规则或边界情况。
测试用例如下:
it("case1", () => { // 一方分值达到 `11` 分而获胜;
assert.equal(judge([1, 1, 1, 1, 1, 0, 0], 1), 1);
});
it("case2", () => { //一方获得至少 `4` 枚倾心标记而获胜;
assert.equal(judge([1, 1, 1, 1, 0, -1, 0], 2), 1);
});
it("case3", () => { //前两小轮结束时尚未满足胜利条件,应返回 `0`;
assert.equal(judge([1, -1, 0, 0, 0, 0, 0], 2), 0);
});
it("case4", () => { // 第三小轮结束时,总分不同,由总分高者获胜;
assert.equal(judge([1, 1, 0, -1, 0, 0, 0], 3), 1);
});
it("case5", () => { //第三小轮结束时,总分相同,由最高档位倾心标记判定胜负;
assert.equal(judge([-1, 0, 0, -1, 0, 0, 1], 3), 1);
});
it("case6", () => { //第三小轮结束时平局,应返回 `2`。
assert.equal(judge([1, -1, 0, -1, 1, 0, 0], 3), 2);
});
→ 📖 Q1.6(I) 请说明你对“先写测试再实现”与“先实现再补测试”两种方式的理解。
- 先写测试再实现:
这种方式给人的感觉就是“稳扎稳打”。虽然写起来挺别扭的,毕竟功能还没写就要先想怎么测,挺反直觉,而且挺费时间的。但它最大的好处就是代码写完后心里特别有底,不容易出大乱子。要是做那种对安全性要求特别高、绝对不能崩的核心模块,用这个最保险。 - 先实现再补测试:
这个就是我们平时最习惯的做法,顺着逻辑直接写功能,写完再去测。这种方式上手很快,适合那种赶进度、或者没那么严格的小项目。不过缺点就是自己写的时候可能想得没那么周全,最后代码里的 Bug 可能会比前一种方法多一点。
总结
→ 📖 Q1.7(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
22026-04-04 21:58
→ 📖 Q1.8(I) 请写下本部分的心得体会。
在开发中,测试是一个非常重要的部分。无论是OO还是软件工程,老师助教都很关注单元测试的内容。全面、详尽的测试是产品开发中必须进行的重要步骤。
Chapter.2 不祥之影
准备
→ 📖 Q2.1(P) 请记录下目前的时间。
2026-04-04 22:00
→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 5 | 5 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 10 | 8 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 10 | 5 |
| - Coding Standard | - 代码规范 | 0 | 0 |
| - Design | - 具体设计(确定怎么实现) | 5 | 5 |
| - Coding | - 具体编码 | 15 | 15 |
| - Code Review | - 代码复审 | 5 | 0 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 5 | 5 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 5 | 5 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 10 | 20 |
| - Size Measurement | - 计算工作量 | 5 | 2 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 5 | 0 |
| TOTAL | 合计 | 80 | 73 |
2.查阅的资料:
除了官方指导书没有参考其他资料
官方的指导书对于题目规则解释的很清楚,看着指导书要求直接写代码就行。
测试样例的设计:先跑了官方提供的样例,然后又拿 README 里的那组完整行动记录自己手动核对了一遍输出是否合理。
遇到的问题:一开始对 3 赠送和 4 竞争这种带选择的操作理解得不是很清楚,后来看了 README 里的表格和 T3 的实现之后才理顺。
代码可复用性与需求变更
→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑💻 T1 中已实现的代码进行了哪些复用和修改。
复用了 T1 里用数组按 A-G 顺序处理状态的思路,得分标记 board 沿用了原来的表示方式。不同的是 T2 不再是直接判定胜负,而是先根据 history 统计双方场面上每种牌的数量,再根据这个结果去更新 board。另外为了处理行动记录,又补了几个小函数,比如牌字符转下标、给某一方加牌、比较两组牌是否一致等。
→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
代码结构上,我建议把解析、更新场面和更新得分这几个步骤分模块写,结构会更清晰。数据管理这块,建议把牌数、得分这些信息统一放进数组里,不要定义太多散碎的变量,这样代码的扩展性更好。另外,对于赠送和竞争这种特殊逻辑,单独分一类去写,这样代码逻辑一眼就能看明白。
头脑风暴环节
→ 📖 Q2.5(P) 头脑风暴环节:
我们终于快要开始让程序玩游戏了!请尝试分析:T2 中不带 X 的操作记录比起实际对局多出了多少信息?如果加上 X,也就是失去了这部分信息的话,如何处理对小轮结束后状态的估计?
T2 中不带 X 的记录,比实际对局多出来的信息主要就是“最后公开后的完整信息”。也就是说,在 T2 里可以知道双方密约和取舍实际用了什么牌,也可以知道 3 赠送和 4 竞争里到底提供了哪些牌、最后又选了哪一组,因此可以把整轮结束后的场面唯一还原出来。
如果加上 X,就会失去这部分隐藏信息,尤其是不知道对方暗置的牌和弃掉的牌到底是什么。这种情况下,小轮结束后的状态通常就不能唯一确定了。比较合理的做法是维护一个“可能状态集合”,把所有和当前已知信息不矛盾的情况都保留下来;如果不想维护这么复杂,也至少可以统计每种牌出现的可能性,给出一个估计结果,而不是像 T2 这样直接给出唯一答案。
总结
→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录 A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026-04-04 23:10
→ 📖 Q2.7(I) 请写下本部分的心得体会。
比起 T1,T2 的核心在于还原整个场面,所以读懂输入记录比写判断逻辑更重要。做这道题时,我发现格式理解是第一位的,一旦理顺了,实现过程就比较顺畅。反之,如果一开始没搞清楚赠送和竞争这两个特殊操作的具体含义,代码写着写着就会发现逻辑全拧在一起了。所以磨刀不误砍柴工,理清逻辑再动手真的很关键。
Chapter.3 道途之荆
准备
→ 📖 Q3.1(P) 请记录下目前的时间。
2026-04-04 23:15
→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 10 | 10 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 20 | 20 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 15 | 15 |
| - Coding Standard | - 代码规范 | 0 | 0 |
| - Design | - 具体设计(确定怎么实现) | 20 | 25 |
| - Coding | - 具体编码 | 60 | 70 |
| - Code Review | - 代码复审 | 10 | 0 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 15 | 15 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 20 | 20 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 20 | 25 |
| - Size Measurement | - 计算工作量 | 5 | 3 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 5 | 0 |
| TOTAL | 合计 | 200 | 203 |
2.查阅的资料:
主要还是查阅了 README 中 T3 的规则说明和测试方式。
因为 T3 需要和引擎对接,所以也看了 src/T3/hanamikoji-engine.js,主要是为了搞清楚 history 的格式、每一轮的出牌顺序以及输出不合法时会怎么判负。
实现时先做了 history 的解析,把当前回合已经发生的事情尽量还原出来,再枚举当前可选行动,最后用一个局面分数来选相对更优的行动。
遇到的问题:T3 最大的问题不是语法,而是策略怎么写。一开始如果只是随便合法出牌虽然也能跑,但效果很一般。后面改成先枚举、再评估局面的方式以后,逻辑就稳定很多。
头脑风暴环节
→ 📖 Q3.3(P) 头脑风暴环节:
假设提供更充裕的时间和资源,这个游戏中你能找到的最优策略有可能是什么形式的?进行调研并总结分析。你还可以在任务结束后试着实现(不计分)。
如果时间和资源更充裕,最优策略大概率不会是简单的规则判断,而会更接近博弈搜索。
一种比较自然的思路是把游戏建模成一个带有隐藏信息的双人零和博弈,然后在当前信息集上做搜索。比如对未知牌的分布做采样,再对每个可能状态进行极小化极大搜索,最后综合这些结果选择期望收益最高的行动。
如果再进一步,也可以考虑用 MCTS 或者 CFR 这类方法。前者适合在大状态空间里做近似搜索,后者更适合处理不完全信息博弈。从理论上说,这种方向比手写启发式规则更有可能逼近真正的最优策略。
需求建模和算法设计
→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么选择行动类型?选牌如何更优?如何编程实现。
我们最后采用的是先还原状态,再枚举合法行动,最后给局面打分的做法。
先根据 history 判断当前是我行动还是我响应,同时统计双方已经用过哪些行动、自己和对手当前场面上已知的牌、对手还剩多少隐藏信息。这样就能先把当前局面尽量还原清楚。
在行动选择上,会把当前所有合法的 1、2、3、4 行动都枚举出来。对于 3 赠送和 4 竞争,还会把对手可能的选择一起考虑进去,不是只看自己当前能拿到什么,而是看如果对手选择了最不利于我的选项,这个行动值不值得出。
在选牌上,主要依据是局面分数。这个分数会综合考虑当前场面差距、哪些倾心标记更值钱、哪些标记已经偏向某一方、自己手里剩下的牌能不能在后续继续争夺,以及对手隐藏牌可能带来的影响。最后在所有合法行动中选择分数最高的那个。
代码可复用性与需求变更
→ 📖 Q3.5(P) 请说明针对该任务,你们对 🧑💻 T2 中已实现的代码进行了哪些复用和修改。
T3 复用了 T2 中对 history 的理解方式,也继续沿用了按 A-G 顺序用数组来表示牌数和标记状态的方式。像牌字符转下标、给某一方加牌、处理 3 赠送和 4 竞争这些思路,本质上都是从 T2 延续过来的。
和 T2 相比,最大的变化是 T3 不再只是“还原结果”,而是在还原当前状态以后继续往前走一步,去决定接下来应该做什么。所以在 T2 的基础上又补了合法行动枚举、对手响应处理、局面评估和选优这些部分。
→ 📖 Q3.6(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
写这种策略类的代码,不要把读数据、想招数、看局势这几块全糊在一起写。把它们拆开后,万一以后题目要求变了,或者输入格式改了,只要修改那一个模块。而且,把场面信息都统一存进数组或者状态对象里非常方便,以后要是想加个评分标准,或者想试一下搜索算法之类的操作,直接接上去就行,不用把代码推倒重写。
软件度量
→ 📖 Q3.7(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块决策能力很强?”,尝试提出一些可能的定量分析方式或测试方式。
最直接的方法还是对局测试。
一种方法是固定几组不同风格的对手,比如随机策略、贪心策略、偏保守策略,然后统计多轮比赛里的胜率、平局率和先后手情况下的表现。如果对这些不同风格的对手都能稳定拿到比较好的结果,说明策略是有一定强度的。
还可以专门设计一些局面测试。比如给定某种已经很接近胜负手的 history、cards 和 board,看程序会不会做出明显更合理的选择。这样虽然不等同于真实比赛胜率,但能更细地看出程序的决策质量。
另外,也可以统计程序在每一步的耗时,确保不仅策略有效,而且能稳定在时限内做出决策。
总结
→ 📖 Q3.8(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026-04-05 02:38
→ 📖 Q3.9(I) 请写下本部分的心得体会。
如果说 T1 和 T2 是在练基本功,那 T3 就像是在做真实的系统开发。前两题只要顺着题目逻辑写就不会错,但 T3 考验的是在规则之上设计方案的能力。复盘的时候发现,最费脑子的不是理解规则,而是怎么保证我那些‘想当然’的策略,能被逻辑清晰地复现在代码里,还得经得起各种情况的推敲。
结对项目总结
结对过程回顾和反思
→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。
这次结对整体上还是比较顺利的,主要的优点是两个人一直在对着同一个问题讨论,没有出现明显的分工割裂。
不过也有可以改进的地方。比如在 T2 和 T3 一开始理解题意的时候,如果能先把输入输出和关键规则都整理成一个更清晰的小表格,后面的返工应该会更少。还有就是在 T3 上花的时间明显更多,如果一开始就早点想好“先写一个能跑的版本,再逐步增强”,效率可能会更高一些。
→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。
优点:沟通比较直接,发现问题以后能很快提出来;看规则的时候比较认真,能注意到一些容易忽略的点;做测试的时候比较踏实,不会只看能不能跑。
缺点:有时候在实现上会有点保守,想到一种可行方案以后不太愿意马上试别的办法。
对结对编程的理解
→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。
我觉得结对编程的好处在于能互相纠错,尤其是在理解题目和检查测试的时候很有帮助。缺点是两个人需要不断同步思路,不像一个人写的时候那样自由。整体来看,结对编程不一定能让所有任务都更快,但能明显减少一些低级错误。
代码实现提交
→ 📖 Q4.5(P) 请提供你们完成代码实现的代码仓库链接。
附录
附录 A:基于 PSP 2.1 修改的 PSP 表格
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 20 | 20 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 40 | 38 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 35 | 30 |
| - Coding Standard | - 代码规范 | 0 | 0 |
| - Design | - 具体设计(确定怎么实现) | 30 | 30 |
| - Coding | - 具体编码 | 85 | 95 |
| - Code Review | - 代码复审 | 20 | 0 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 25 | 25 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 35 | 38 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 40 | 70 |
| - Size Measurement | - 计算工作量 | 15 | 8 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 15 | 0 |
| TOTAL | 合计 | 360 | 354 |

浙公网安备 33010602011771号