[P] 结对项目:花见小路
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 2026年春季软件工程 |
| 这个作业的要求在哪里 | [P] 结对项目:花见小路 |
| 我在这个课程的目标是 | 学习系统的软件工程方法,强化团队协作能力 |
| 这个作业在哪个具体方面帮助我实现目标 | 体验结对编程,在实际开发中积累经验 |
结对项目:博客问题清单
→ 📖 Q0.0(P) 【你可以在结对结束后补充】如果你的代码仓库包含 AIGC 的部分,列举使用的工具、模型和使用范围。若未使用则填写:本组提交的全部代码不包含AI补全或生成的部分。
工具:Cursor
模型:composer 2 fast
使用范围:1. 编写项目gitignore;2. 自动化构建依赖环境;3. 启发T3策略优化思路;4. 协助整理文档内容。最终提交的内容均经过人员审核。
Chapter.0 wasm从安装到入门
引入
→ 📖 Q0.1(P) 请记录下目前的时间。
2026-4-10 8:23
调查
→ 📖 Q0.2(I) 【你可以在结对结束后另行补充。】作为本项目的调查:
请如实标注在开始项目之前对 Wasm 的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 没有听说过;
II. 仅限于听说过相关名词;
III. 听说过,且有一定了解;
IV. 听说过,且使用 Wasm 实际进行过开发(即便是玩具项目的开发)。
II. 仅限于听说过相关名词
请如实标注在开始项目之前对桌游花见小路的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 不了解玩法和规则;
II. 听说过,且有一定了解;
I. 不了解玩法和规则
总结
→ 📖 Q0.3(P) 请记录下目前的时间。
2026-4-10 8:57
Chapter.1 七色之缨
结对过程
→ 📖 Q1.1(P) 请记录下目前的时间。
2026-04-10 09:02
→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 5 | 5 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 8 | 10 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 7 | 6 |
| - Coding Standard | - 代码规范 | 2 | 2 |
| - Design | - 具体设计(确定怎么实现) | 8 | 6 |
| - Coding | - 具体编码 | 15 | 13 |
| - Code Review | - 代码复审 | 3 | 2 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 5 | 4 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 6 | 5 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 2 | 3 |
| - Size Measurement | - 计算工作量 | 1 | 1 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 2 | 2 |
| TOTAL | 合计 | 64 | 59 |
- 完成编程任务期间,依次做了什么(例如查阅了哪些资料、如何设计判定逻辑、如何设计测试样例、遇到了什么问题、如何解决)。
- 首先仔细阅读指导书的胜负判定规则,并且看了给出的B站小视频,明确核心判定条件,梳理出规则的优先级和执行逻辑。
- 基于梳理好的规则,按优先级分步设计函数核心逻辑,保证逻辑清晰无歧义。
- 根据规则,按场景分类设计测试用例,覆盖所有规则范围,并且检测编写的代码能够顺利通过该测试以及课题组给出的测试。
设计
→ 📖 Q1.3(P) 请说明你们为这个判定模块设计了哪些中间量或辅助函数;如果没有额外设计,也请说明为什么认为直接实现已经足够清晰。
- 辅助函数
tokenValue(index: i32): i32:根据倾心标记索引返回对应分值(A/B/C=2、D/E=3、F=4、G=5)。tierPriority(index: i32): i32:返回同分比较时的优先级(G=3、F=2、D/E=1、A/B/C=0)。
- 中间量
myScore/oppScore:统计双方总分值。myCnt/oppCnt:统计双方拥有的倾心标记数量。myBestTier/oppBestTier:记录双方最高优先级倾心标记档位。
→ 📖 Q1.4(I) 请说明在这样一个规则判定类模块中,如何避免“漏判”“错判”或分支顺序错误等问题。
- 确定总体框架:根据给定规则确定规则生效范围,明确规则优先级,按照优先级编写分支,遵循高优先级条件先判断,防止顺序错误。
- 代码内容编写:在每个优先级内,也可以说是每种生效范围下,即每个分支里,分步拆解判定流程,减少逻辑遗漏。
- 测试样例覆盖:设计全覆盖测试用例,覆盖核心规则、边界条件与异常输入,验证每一种判定场景。
测试
→ 📖 Q1.5(P) 请说明你们设计了哪些测试用例,这些测试分别覆盖了哪一类规则或边界情况。
我们的测试覆盖了指导书中给出的测试范围:
-
游戏任意轮次可触发:
- 一方积分累计达到 11 分,直接判定获胜
- 一方集齐至少 4 枚倾心标记,且对方未达到 11 分,判定获胜
-
中间轮次,即第 1,2 轮:
- 第 1、2 小轮结束,未满足以上任何胜利条件,则无玩家获胜,返回 0,游戏继续进行
-
第 3 轮终局结算规则测试:
- 第 3 小轮结束,双方总积分不相等,总积分更高的玩家获胜
- 第 3 小轮结束,双方总积分相同,以高价值档位的倾心标记归属判定胜负
- 第 3 小轮结束,积分与高价值标记均完全持平,判定为全局平局
→ 📖 Q1.6(I) 请说明你对“先写测试再实现”与“先实现再补测试”两种方式的理解。
-
先写测试再实现:刚想到这种方法的时候感觉会有一点别扭,但是整体实现会更加稳健,因为先测试样例会迫使自己对要求进行更加深入的阅读,代码编写的时候也会逻辑更清晰;但是如果要求仍在变化,或者是整体架构还没有那么明确的情况下,该方式并不适用。
-
先实现再补测试:是我们平时比较习惯的一种方式;好处在于开发速度快,适合快速搭建逻辑;但是在写测试的时候容易想当然,很有可能会遗漏边界场景。
总结
→ 📖 Q1.7(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026-04-10 10:02
→ 📖 Q1.8(I) 请写下本部分的心得体会。
T1的逻辑链比较清晰,感觉对我们来说是一个过渡跳板,能够让我和结对对象熟悉双方工作方式,也进一步地熟悉了游戏规则和编程语言。结对编程的初体验还是很不错的,两个人的思路可以互相查缺补漏,进而避免边界场景的遗漏。
Chapter.2 不祥之影
准备
→ 📖 Q2.1(P) 请记录下目前的时间。
2026-04-10 10:20
→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 5 | 5 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 15 | 18 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 10 | 11 |
| - Coding Standard | - 代码规范 | 3 | 3 |
| - Design | - 具体设计(确定怎么实现) | 20 | 28 |
| - Coding | - 具体编码 | 45 | 43 |
| - Code Review | - 代码复审 | 5 | 7 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 15 | 8 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 20 | 13 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 3 | 5 |
| - Size Measurement | - 计算工作量 | 1 | 1 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 2 | 3 |
| TOTAL | 合计 | 144 | 154 |
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
- 首先阅读 T2 的指导书,明确本题需求,确定输入输出含义及主函数名称。
- 实现代码编写:首先厘清主函数架构,根据各行动内容依次完成各类型行动函数编写,并且设计了字符串分割等辅助函数,最后完成主函数的填充。
- 根据指导书完成测试代码编写,首先确保每个行动相关的代码逻辑正确,然后是总体逻辑正确;最后进行课题组提供的测试并成功通过。
代码可复用性与需求变更
→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑💻 T1 中已实现的代码进行了哪些复用和修改。
T2 未对 T1 的代码进行复用。
→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
- 首先我觉得最重要的模块化设计,应该遵循单一职责原则,将各行动处理、状态校验等拆分为独立函数,降低模块耦合,也方便后续的修改;
- 将重复逻辑的部分封装为通用工具函数,支持多场景调用,也能够方便复用,减少需求变更时的代码修改量;
- 将游戏规则中的固定数值抽离为常量,规则出现修改和变动时无需改动核心代码。
头脑风暴环节
→ 📖 Q2.5(P) 头脑风暴环节:
我们终于快要开始让程序玩游戏了!请尝试分析:T2 中不带 X 的操作记录比起实际对局多出了多少信息?如果加上 X,也就是失去了这部分信息的话,如何处理对小轮结束后状态的估计?
不带 X 的操作记录多出的信息:对手玩家原本在游戏进行中不会公开的牌,也就是对手进行“密约”时选择的牌以及进行“舍弃”时扔掉的牌。因此玩家可以根据这些牌来调整自己的出牌策略,考虑自己应该抢夺或者放弃哪些角色的标记。
加 X 后我们认为可以:
- 利用公开的信息,包括但不限于自己的手牌、目前场上出现的牌组以及总牌数,剔除不可能状态,维护可行状态集合;
- 在不知对方出牌策略的情况下,可以假设对手始终采取最优策略出牌。
总结
→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录 A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026-04-10 12:55
→ 📖 Q2.7(I) 请写下本部分的心得体会。
对比T1,T2的核心是还原完整对局状态,逻辑复杂度明显更高,需要处理复杂的字符串操作记录,尤其是赠送、竞争等特殊行动的格式与分配逻辑,必须先清楚规则再编码,边看边写很容易陷入思路混乱。
结对编程能够在一定程度上规避这类风险,双人协作可以实时校验代码逻辑,双方的思路可以互补,复杂代码编写部分不会那么容易出现笔误等问题,能够及时发现单人开发容易忽略的逻辑漏洞与边界错误。
Chapter.3 道途之荆
准备
→ 📖 Q3.1(P) 请记录下目前的时间。
2026-04-10 14:40
→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 5 | 8 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 20 | 17 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 15 | 18 |
| - Coding Standard | - 代码规范 | 5 | 5 |
| - Design | - 具体设计(确定怎么实现) | 35 | 38 |
| - Coding | - 具体编码 | 100 | 108 |
| - Code Review | - 代码复审 | 10 | 14 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 20 | 18 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 30 | 27 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 5 | 5 |
| - Size Measurement | - 计算工作量 | 2 | 2 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 3 | 5 |
| TOTAL | 合计 | 245 | 265 |
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
- 首先阅读 T3 的指导书,明确本题的任务需求,以及主函数入口。
- 代码实现
- 由于这道题需要根据历史信息及场上局势进行出牌,因此我们将任务拆分为了两个部分:分析场上整体局势部分以及出牌策略部分,因为可以在后续有新的策略思路时更好地进行修改;
- 因此我们首先采取了最简单的固定策略,目的是为了将焦点先锁定在分析场上局势并出牌的部分,并且完成该部分代码编写;
- 后续我们查阅了相关资料,以及利用AI进行启发,采取了加权贪心的出牌策略,进一步对我们的出牌策略部分进行了优化。
- 在两轮的代码编写过程中,我们自行编写了测试代码,同时借助课题组提供的测试代码进行测试,并成功通过。
头脑风暴环节
→ 📖 Q3.3(P) 头脑风暴环节:
假设提供更充裕的时间和资源,这个游戏中你能找到的最优策略有可能是什么形式的?进行调研并总结分析。你还可以在任务结束后试着实现(不计分)。
-
如果把游戏看成零和博弈,假设对手会采取对我方最不利的最优策略,我方在所有可能的行动中选择“对手反制后我方收益最大”的行动,可以采用极小极大搜索(再配合剪枝)在树上寻找较好的走法。
-
考虑到游戏过程中信息不完全的特性,可以考虑采用蒙特卡洛树搜索(MCTS),无需完整博弈树,通过“模拟-选择-扩展-回溯”迭代优化决策,通过大量模拟对局学习最优行动,适配对手策略的变化。
需求建模和算法设计
→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么选择行动类型?选牌如何更优?如何编程实现。
-
预处理:对于每种牌型进行赋值,每张牌的价值由牌本身分数乘以当前局面权重得到。当前局面权重经分析目前的场上局势得到,如果在该花色上我们处于落后或平局时,该花色的权重要高于领先时权重,这样能够鼓励争夺劣势或平局的花色。
-
选牌时:
- 3(赠予):选择对手所处的三张牌中价值最高的一张牌。
- 4(竞争):选择对手所处的四张牌中价值最高的一组牌。
-
行动时:排除所有已进行过的行动,枚举了所有合法的行动类型,并为每种可能的牌组合计算一个得分,最终选择得分最高的行动。
- 1(密约):遍历手牌中每一张牌,选择单张价值最高的牌,估值
sum。 - 2(取舍):枚举所有两两组合,计算两张牌的价值和,弃掉两张价值总和最低的牌,,估值
sum-min(弃牌组合)。 - 3(赠予):展示三张牌,对手会选走价值最高的一张,剩下两张归自己。因此我们希望剩下的两张牌价值之和最大,枚举所有三张牌的组合,最大化
sum - max。 - 4(竞争):将四张牌分成两组,对手会选走价值总和较高的一组,自己得到较低的一组。因此我们希望较低的那一组价值尽可能高,枚举所有四张牌的组合,对于每种组合尝试所有三种可能的配对方式,计算
min(pair1, pair2),取最大值;然后选择使该值最大的配对方式。
- 1(密约):遍历手牌中每一张牌,选择单张价值最高的牌,估值
-
编码实现:
- 选牌:该部分代码位于
choiceReply中,将以上的策略进行编码实现,并返回最合适的选择组合。 - 行动:该部分核心代码集中在
buildNormalAction(used, cards, board): string中,枚举所有未使用 + 手牌数合法的行动与牌型,按加权贪心选最优。
- 选牌:该部分代码位于
代码可复用性与需求变更
→ 📖 Q3.5(P) 请说明针对该任务,你们对 🧑💻 T2 中已实现的代码进行了哪些复用和修改。
复用:
splitBySpace- 用途:按空格切分历史行动字符串。
- 复用场景:在 T3 中用于解析
history参数,将其转换为行动数组以便后续处理。
-
sameMultiset2- 用途:判断两个双字符组合是否等价。
- 复用场景:在 T3 中用于验证类型 4 行动中选组的合法性。
-
countLetters- 用途:统计字符串中 A-G 各字母出现的次数。
- 复用场景:作为 T3 中分值计算的基础工具,用于统计玩家持有的倾心标记数量及分布。
→ 📖 Q3.6(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
- 我认为最重要的还是模块化编程,在本题中,你可以将分析场上局势部分与策略部分分模块进行编写,这样在后续代码编写中想要更换新的策略或者对现有策略进行完善会更加的方便。
- 同 T2 一样,封装通用类型的函数,例如此时T3就可以复用T2中的函数,减少编写压力,也能更快地适应需求的变化。
- 将游戏规则中的固定数值抽离为常量,规则出现修改和变动时无需改动核心代码。
软件度量
→ 📖 Q3.7(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块决策能力很强?”,尝试提出一些可能的定量分析方式或测试方式。
- 首先保证代码有效性:
- 执行课程组提供的测试,能跑通说明 Wasm 导出、接口和联调正常。
- 把自己编译的 wasm 复制多份互相对打,看对局结果是否出现波动,有没有被判超时。
- 其次看我们程序的决策能力:
- 与自己迭代前的代码进行比较,看看性能是不是更好;
- 和别的小组进行多轮次比较,并且交换先后手,查看胜率;
- 调整
buildNormalAction里某一类行动的打分系数,多跑几局比较胜率变化,用于检验盘面权重等设计是否带来稳定收益。
- 时间:题目要求每步约 2 秒内;本地跑测试或
console.time包一层hanamikoji_action,确认不会卡死。
总结
→ 📖 Q3.8(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026-04-10 19:08
→ 📖 Q3.9(I) 请写下本部分的心得体会。
T3 总体的难度会更大,我觉得在这个部分的解决上我们有一个很棒的点就是先忽略具体策划的内容,首先聚焦于整体架构编写,让代码先能够跑通,然后再根据调研的结果进一步的完善策略部分,这样整体的编写节奏会更加舒适,每个时期聚焦于不同的目标和重点。
在 T3 的编码过程中,结对编程的好处就非常明显了。首先是代码的体量比较大,双方协作会更好的减少失误,提高编写的效率;其次两人能够在讨论中快速复盘先手身份推断与行动合法性校验中的状态偏差等逻辑较为复杂的部分,有效避免了单人开发的思维局限,降低了调试与试错的时间成本。
结对项目总结
结对过程回顾和反思
→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。
整体结对的过程很顺利!提升改进的方面:
- 下次努力更早一点开始,但是时间确实有点难协调,挑战不再做 DDL 达人!
- 在开始结对前先进行相关内容的学习,尽量减少结对时一起现场学习的情况。
- 编码过程中,部分思考过程和讨论过程没有及时记录,应该及时记录开发过程中的关键决策、遇到的问题及对应的解决办法,便于后续总结与完善。
→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。
诗怡是一个特别好的搭档!!
优点:
- 思路特别清晰,能够比较快地确定一个方法思路;
- 写代码能力很强,将方案转化为代码的速度很快;
- 沟通能力很好,语言表达能力强,能够快速沟通,并清晰地给出自己的建议。
不足之处:思路很敏捷,稍不注意容易跟不上她的节奏。
对结对编程的理解
→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。
优点:
- 双人协作可合理拆分任务,避免单人全权承担的压力,让任务推进更高效,代码实现质量也更有保障;
- 很多问题在与搭档交流过程中就会提前显露,单人开发时容易走进死胡同,而双人协作可以相互验证、彼此监督,及时纠正认知偏差;
- 协同工作便于实时沟通、相互督促,任务完成效率更高。
缺点:
- 主要是两个人的时间安排较难协调,如果大家正好都比较忙,那结对编程的时间会被延后或者压缩。
- 沟通本身存在成本,如果两个人对问题的抽象和理解层次不一致,会耗费较多时间对齐思路。
在我看来,结对编程是比较高效且实用的开发方式,它能在任务推进中不断暴露问题、修正想法,让最终成果比单人完成更完善,既能高效完成开发任务,也能积累协作经验,加深搭挡间默契。
代码实现提交
→ 📖 Q4.5(P) 请提供你们完成代码实现的代码仓库链接。

浙公网安备 33010602011771号