[P] 结对项目:花见小路
[P] 结对项目:花见小路
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 2026春软件工程 |
| 这个作业的要求在哪里 | 个人第二次作业 |
| 我在这个课程的目标 | 帮助了解结对编程、敏捷开发全流程,同时提升两人协作能力,提升交流效率 |
| 这个作业在哪个具体方面帮助我实现目标 | 从项目设计到实现,从交流到合作 |
→ 📖 Q0.0(P) 【你可以在结对结束后补充】如果你的代码仓库包含 AIGC 的部分,列举使用的工具、模型和使用范围。若未使用则填写:本组提交的全部代码不包含AI补全或生成的部分。
本组提交的全部代码不包含AI补全或生成的部分
Chapter.0 wasm从安装到入门
引入
→ 📖 Q0.1(P) 请记录下目前的时间。
2026/4/2 16:43
调查
→ 📖 Q0.2(I) 【你可以在结对结束后另行补充。】作为本项目的调查:
请如实标注在开始项目之前对 Wasm 的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 没有听说过;
请如实标注在开始项目之前对桌游花见小路的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 不了解玩法和规则;
总结
→ 📖 Q0.3(P) 请记录下目前的时间。
2026/4/2 17:13
Chapter.1 七色之缨
结对过程
→ 📖 Q1.1(P) 请记录下目前的时间。
2026/4/2 17.14
→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(例如查阅了哪些资料、如何设计判定逻辑、如何设计测试样例、遇到了什么问题、如何解决)。
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 68 | 115 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 2 | 2 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 5 | 45 |
| - Coding Standard | - 代码规范 | 5 | 5 |
| - Design | - 具体设计(确定怎么实现) | 10 | 5 |
| - Coding | - 具体编码 | 10 | 15 |
| - Code Review | - 代码复审 | 5 | 3 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 5 | 5 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 10 | 20 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 5 | 5 |
| - Size Measurement | - 计算工作量 | 5 | 5 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 5 | 5 |
- 通过视频网站了解花间小路规则,包括游戏规则、玩家操作、判断条件等。
- 通过阅读wasm官方文档、课程组提供的guide.md,并结合AI询问,了解wasm的基本概念和使用方法。
- 通过视频网站和rust官网学习rust的基本语法和概念。
- 交流并讨论设计相关的判定函数。
- 测试:先撰写一些边界情况测试,然后写python脚本随机生成测试用例。
设计
→ 📖 Q1.3(P) 请说明你们为这个判定模块设计了哪些中间量或辅助函数;如果没有额外设计,也请说明为什么认为直接实现已经足够清晰。
SCORE 全局变量,记录所有的分数。
judge_score_11 判定函数,用于判断玩家是否在当前轮中获得了 11 分。
judge_num_4 判定函数,用于判断玩家是否在当前轮中获得了 4 个艺妓的青睐。
judge_more_point 判定函数,用于在第三轮中,如果双方玩家不能通过judge_score_11和judge_num_4判断胜负,则通过比较分数高低来判断。
judge_dictionary 判定函数,用于在第三轮中,如果双方玩家不能通过judge_score_11,judge_num_4,- --
judge_dictionary 和判断胜负,则通过比较最高分倾心标记判断。
→ 📖 Q1.4(I) 请说明在这样一个规则判定类模块中,如何避免“漏判”“错判”或分支顺序错误等问题。
- 在设计时:按照游戏的判断顺序,确定所有可能遍历的分止。可以画出一个流程图(树),展示所有的判断路径。
- 在测试时:对于所有的分支,都编写一些测试案例。然后再撰写一些边界情况测试。
测试
→ 📖 Q1.5(P) 请说明你们设计了哪些测试用例,这些测试分别覆盖了哪一类规则或边界情况。
- 一方超过11分情况
- 一方获得11分另一方获得4个艺妓情况
- 一方获得4个艺妓但无11分情况
- 前两轮平局情况
- 第三轮超过11分情况
- 第三轮4个艺妓情况
- 第三轮均未超过11分且未获得4个艺妓
- 总分更高者赢情况
- 同分下得分字典序大者赢情况
- 平局情况
→ 📖 Q1.6(I) 请说明你对“先写测试再实现”与“先实现再补测试”两种方式的理解。
两种方法各有优劣
- 先写测试再实现:提前考虑到所有的分支情况,编写合适的测试案例。同时先写的测试也对代码的实现有提示。
- 先实现再补测试:代码已经实现。对于代码中可能会出现的问题,做出特定的测试案例验证。但有可能会忽略特定情况。
总结
→ 📖 Q1.7(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026/4/2 18:54
→ 📖 Q1.8(I) 请写下本部分的心得体会。
本部分主要是通过一个简单的例子来熟悉rust的基本语法和概念,以及wasm的基本使用。同时初次体验了结对编程。在两个人的代码风格和思路都不同的情况下,通过讨论的方式得到最优解。同时熟悉后也为后续的开发提供了基础。
Chapter.2 不祥之影
准备
→ 📖 Q2.1(P) 请记录下目前的时间。
2026/4/2 19:08
→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 165 | 215 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 10 | 10 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 10 | 20 |
| - Coding Standard | - 代码规范 | 10 | 10 |
| - Design | - 具体设计(确定怎么实现) | 10 | 20 |
| - Coding | - 具体编码 | 60 | 70 |
| - Code Review | - 代码复审 | 15 | 20 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 15 | 10 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 20 | 40 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 5 | 5 |
| - Size Measurement | - 计算工作量 | 5 | 5 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 5 | 5 |
- 依旧阅读指导书和rust文档
- 设计Player和Action结构体,用于存储玩家信息和操作记录。
- 为Player设计get_board(), add_card(), apply_action()方法,用于获取玩家当前状态、添加牌、应用操作。
- 编写strip_history()函数,用于处理输入
- 最后完成calc_current_state()函数
- 手工编写了三个测试用例后,通过python脚本随机生成测试用例。
代码可复用性与需求变更
→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑💻 T1 中已实现的代码进行了哪些复用和修改。
无T1复用代码。
→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
单一职责原则:将功能拆分,每个函数只负责一个功能,避免函数过长或复杂。
开放封闭原则:当需求变化时(比如发现要新添加参数),尽量通过新增代码来实现,而不是修改已有稳定代码。
头脑风暴环节
→ 📖 Q2.5(P) 头脑风暴环节:
我们终于快要开始让程序玩游戏了!请尝试分析:T2 中不带 X 的操作记录比起实际对局多出了多少信息?如果加上 X,也就是失去了这部分信息的话,如何处理对小轮结束后状态的估计?
T2相当于上帝视角,相比正式游戏可以多了解对少操作1和操作2的牌;
如果失去此信息,可以通过枚举牌的组合、计算概率或者从博弈论角度(即假定对手是理性最优策略反向推断其未展示的牌)等方法来预估。
总结
→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录 A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026/4/3 19:54
→ 📖 Q2.7(I) 请写下本部分的心得体会。
第二部分主要是字符串的处理,难度比第一部分高,很容易出现一些疏忽的错误。深刻体会到了结对编程的好处。在结对编程中,因为用审核员的存在,一些小错误得以在开发早期被发现和修复。同时,还体会到了规范编程的重要性,在命名函数时还是要清晰,并注上必要的注释。在此次任务中就出现了混用函数的错误,耽误了不少时间检查。
Chapter.3 道途之荆
准备
→ 📖 Q3.1(P) 请记录下目前的时间。
2026/4/5 15:54
→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 375 | 615 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 20 | 20 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 10 | 10 |
| - Coding Standard | - 代码规范 | 10 | 20 |
| - Design | - 具体设计(确定怎么实现) | 60 | 100 |
| - Coding | - 具体编码 | 220 | 400 |
| - Code Review | - 代码复审 | 20 | 30 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 10 | 10 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 10 | 10 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 5 | 5 |
| - Size Measurement | - 计算工作量 | 5 | 5 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 5 | 5 |
- 依旧阅读rust文档,学习rust的基本语法和概念。
- 设计中考虑复用T2中的Player和Action结构体。
- 通过进行多轮花间小路游戏分析策略,同时调研分析得到打分策略、蒙地卡罗模拟等方法,最后结合自身代码实力,选择贪心策略
- 先实现整体框架,定义Strategy trait,然后优先实现随机策略,在test.js中测试,确认框架正确性。
- 再实现贪心策略,在test.js中测试,确认正确性。同时与随机策略对比,分析贪心策略的优势与不足。
- 通过修改test.js进行随机发牌后多次测试。
- 与其他组同学进行对战,根据结果调整策略。
头脑风暴环节
→ 📖 Q3.3(P) 头脑风暴环节:
假设提供更充裕的时间和资源,这个游戏中你能找到的最优策略有可能是什么形式的?进行调研并总结分析。你还可以在任务结束后试着实现(不计分)。
1、引入对手信息建模,分析对手所需手牌。同时观察对手动作,通过贝叶斯更新其手牌的概率分布。从而可以预测对手想要的牌,可以添加诱饵策略。
2、进行长期规划,对后续抽牌和轮次分别建模。例如第一轮可以牺牲收益换取信息,越往后越注重得分。
3、对卡牌的重要性进行打分评估,从而决定牌的取舍。
4、通过CFR算法离线求解贝叶斯纳什均衡,得到可查表的最优混合策略。
需求建模和算法设计
→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么选择行动类型?选牌如何更优?如何编程实现。
行动类型选择:优先级策略。
- 手牌有三张相同则执行赠与操作
- 手牌有两对则进行竞争操作
- 优先弃掉对方比自己多的牌,阻止对手得分
- 根据双方中牌的数量判断牌的重要性,然后选取密约
- 回退至随机策略
选牌策略:
- 密约时:提高高分牌的优先级,同时避免拿对手已经有优势的牌
- 回应赠与选牌时:优先选大牌,除非对手已经领先;其次抓可完成收集的牌,再抓对手少数牌,最后退回随机策略
- 回应竞争选牌时:优先选打牌,除非对手领先;其次选完成度更高的组合的牌,其次选数值更大的牌,最后随机
编程实现:
- 设计Player结构体:记录手牌、桌面牌、已做动作、未做动作
- 设计Action结构体,对action封装
- 定义Strategy trait,同时定义两个决策接口(give_advice和give_feedback)
辅助函数:
- have_triple():检测三连张牌(供赠与选择)
- have_double_double():检测两对(供竞争选择)
- have_discard():检测玩家手里可丢弃的牌
- is_critical():比较双方持有量判断手牌的关键性
- would_complete():判断拿了此牌是否可以直接收集成功
构建RandomStrategy,用随机策略作为保底
代码可复用性与需求变更
→ 📖 Q3.5(P) 请说明针对该任务,你们对 🧑💻 T2 中已实现的代码进行了哪些复用和修改。
复用了T2中的Player结构体和Action结构体。
→ 📖 Q3.6(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
将策略类与基础代码进行分离:这样只需要设计好接口,就可以方便地切换不同的策略。在这次项目中,我们设计了随机策略、贪心策略。如果后续需要添加其他策略,只需要实现对应的策略类,即可。
软件度量
→ 📖 Q3.7(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块决策能力很强?”,尝试提出一些可能的定量分析方式或测试方式。
通过修改给予的test.js代码,使其可以随机发牌,同时写脚本进行100次测评,观察胜率以及对局过程。(借用同学的胶水文件,或者与随机策略进行对比)
总结
→ 📖 Q3.8(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026/4/9 18.36
→ 📖 Q3.9(I) 请写下本部分的心得体会。
最难的一部分是设计和实现策略,反而编程因为前两问的存在没有太难。
在设计方面,为了权衡代码工作量和实现效果部分,在讨论的部分花费了大量的时间。最终选择了局部最优化和贪心算法的结合。
在设计的过程中,两个人互补,说服对方改进方案从而不断优化,这也是结对编程的一个优势。
结对项目总结
结对过程回顾和反思
→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。
1、部分函数命名不够直观,导致调用辅助函数时需要在代码中反复查找才能理解其用途
2、在动手编码之前,对整体架构和模块划分的设计讨论不够充分。
3、结对过程中的技术讨论有时表述不够精准,导致双方对同一问题的理解出现偏差。
→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。
优点:1、仔细,无论作为编程手还是审核员都能仔细检查代码,避免错误。
2、代码能力强,学习新语言非常快,同时还能指出我的错误。
3、有合作精神,善于通过讨论解决问题。缺点:自称懒()
对结对编程的理解
→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。
优点:
- 两个人一起做代码审核,可以及时发现错误,提高代码质量。
- 提高效率,避免摸鱼。
- 两人讨论出的方案通常比单人的更稳健,不易陷入思维盲区。
缺点:
- 需要有足够的时间讨论,还要有时间磨合
- 结对有时比单人更疲倦,需要保持良好的沟通和合作精神。
代码实现提交
→ 📖 Q4.5(P) 请提供你们完成代码实现的代码仓库链接。
浙公网安备 33010602011771号