[P] 结对项目:花见小路
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 软件工程 |
| 这个作业的要求在哪里 | [P] 结对项目:花见小路 |
| 我在这个课程的目标是 | 掌握软件工程的核心理论,协作完成软件项目开发 |
| 这个作业在哪个具体方面帮助我实现目标 | 体验结对编程开发的具体流程,积累经验 |
→ 📖 Q0.0(P) 【你可以在结对结束后补充】如果你的代码仓库包含 AIGC 的部分,列举使用的工具、模型和使用范围。若未使用则填写:本组提交的全部代码不包含AI补全或生成的部分。
本组提交的全部代码不包含AI补全或生成的部分
Chapter.0 wasm从安装到入门
引入
→ 📖 Q0.1(P) 请记录下目前的时间。
4 月 2 日 14:10
调查
→ 📖 Q0.2(I) 【你可以在结对结束后另行补充。】作为本项目的调查:
请如实标注在开始项目之前对 Wasm 的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 没有听说过;
II. 仅限于听说过相关名词;
III. 听说过,且有一定了解;
IV. 听说过,且使用 Wasm 实际进行过开发(即便是玩具项目的开发)。
I. 没有听说过
请如实标注在开始项目之前对桌游花见小路的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 不了解玩法和规则;
II. 听说过,且有一定了解;
I. 不了解玩法和规则
总结
→ 📖 Q0.3(P) 请记录下目前的时间。
4 月 2 日 14:30
Chapter.1 七色之缨
结对过程
→ 📖 Q1.1(P) 请记录下目前的时间。
4 月 2 日 14:40
→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | 5 | 5 |
| - Estimate | - 估计这个任务需要多少时间 | 5 | 5 |
| DEVELOPMENT | 开发 | 140 | 140 |
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 20 | 10 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 20 | 30 |
| - Coding Standard | - 代码规范 | 10 | 15 |
| - Design | - 具体设计(确定怎么实现) | 10 | 5 |
| - Coding | - 具体编码 | 30 | 25 |
| - Code Review | - 代码复审 | 30 | 30 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 10 | 15 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 10 | 10 |
| REPORTING | 报告 | 30 | 25 |
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 10 | 10 |
| - Size Measurement | - 计算工作量 | 5 | 5 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 15 | 10 |
| TOTAL | 合计 | 175 | 170 |
- 完成编程任务期间,依次做了什么(例如查阅了哪些资料、如何设计判定逻辑、如何设计测试样例、遇到了什么问题、如何解决)。
- 查阅了 WebAssembly 的基础教程,学习了 as 的语法
- 仔细阅读胜负判定规则,明确立即胜利条件、前两轮继续、第三轮总分比较、最高分比较及平局的顺序。规划主函数和三个辅助函数,逐一实现函数
- 针对每一种规则分支:总分胜、标记数胜、继续、总分高胜、最高分胜、平局,构造测试用例,确保覆盖每一种情况
- 编写过程中遇到的问题:忘记在变量声明和返回值前添加
i8类型标注,导致编译报错,后续逐项补全
设计
→ 📖 Q1.3(P) 请说明你们为这个判定模块设计了哪些中间量或辅助函数;如果没有额外设计,也请说明为什么认为直接实现已经足够清晰。
我们设计了三个辅助函数
calculate_score用于统计两方当前获得的得分count_marks用于统计倾心标记的个数max_mark用于双方所拥有的最高分值的倾心标记的分值
→ 📖 Q1.4(I) 请说明在这样一个规则判定类模块中,如何避免“漏判”“错判”或分支顺序错误等问题。
严格按照规则中的顺序编写代码,先检查总分→再统计标记数→ 然后判断轮数是否小于3→最后处理第三轮的情况。处理每一个分支时不在主函数中写,而是用辅助函数,保证主函数的逻辑清晰性。
测试
→ 📖 Q1.5(P) 请说明你们设计了哪些测试用例,这些测试分别覆盖了哪一类规则或边界情况。
-
一方分值达到 11 分而获胜
-
我方胜,返回 1
board: [1, 0, 1, -1, -1, 1, 1], round: 2
-
对方胜,返回 -1
board: [1, 0, 1, 0, -1, -1, -1], round: 3
-
-
一方获得至少 4 枚倾心标记而获胜
-
我方胜,返回 1
board: [0, 1, 1, 1, 1, 0, -1], round: 3
-
对方胜,返回 -1
board: [-1, -1, -1, -1, 0, 0, 1], round: 1
-
-
前两小轮结束时尚未满足胜利条件,应返回 0
board: [1, 1, 0, 0, 0, -1, 0], round: 1
-
第三小轮结束时,总分不同,由总分高者获胜
-
我方胜,返回 1
board: [-1, -1, 0, 0, 0, 1, 1], round: 3
-
对方胜,返回 -1
board: [1, 0, 1, -1, -1, 0, 0], round: 3
-
-
第三小轮结束时,总分相同,由最高档位倾心标记判定胜负
-
我方胜,返回 1
board: [-1, -1, 0, 0, 0, 1, 0], round: 3
-
对方胜,返回 -1
board: [-1, 0, 0, 1, 1, -1, 0], round: 3
-
-
第三小轮结束时平局,应返回 2
board: [1, -1, 0, 1, -1, 0, 0], round: 3
→ 📖 Q1.6(I) 请说明你对“先写测试再实现”与“先实现再补测试”两种方式的理解。
先写测试再实现,需要编写者在编码前就深入理解规则,明确有哪些分支以及各个分支的预期结果,需要投入较多时间。实现时对规则已经非常了解,编写难度低,减少后期调试时间。
先实现再补测试,可以快速写出代码,之后测试符合思维习惯。但补测试时可能因代码已定型、思路已经固定而难以发现设计缺陷,容易遗漏边界情况,测试覆盖不充分。
总结
→ 📖 Q1.7(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
4 月 2 日 17:30
→ 📖 Q1.8(I) 请写下本部分的心得体会。
我初步掌握了AssemblyScript的基本语法,在这次编写过程中需要额外注意变量声明,每个变量和返回值都需要显式声明为 i8,否则编译会报错为i32,还学会了 i8[] 数组的正确初始化方式。体验了两个人结对编程,刚开始时效率比较低,两个人需要不断沟通思路、协调编码节奏。但也有很多好处,两个人比一个人更仔细,考虑到的细节也更多,比如一人写代码时,另一人能及时发现逻辑漏洞,最终的代码比单独完成的更加严谨、细节更完善。
Chapter.2 不祥之影
准备
→ 📖 Q2.1(P) 请记录下目前的时间。
4 月 2 日 19:00
→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | 5 | 5 |
| - Estimate | - 估计这个任务需要多少时间 | 5 | 5 |
| DEVELOPMENT | 开发 | 140 | 125 |
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 10 | 10 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 10 | 0 |
| - Coding Standard | - 代码规范 | 10 | 5 |
| - Design | - 具体设计(确定怎么实现) | 20 | 20 |
| - Coding | - 具体编码 | 60 | 60 |
| - Code Review | - 代码复审 | 30 | 30 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 5 | 0 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 0 | 0 |
| REPORTING | 报告 | 30 | 25 |
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 10 | 10 |
| - Size Measurement | - 计算工作量 | 5 | 5 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 15 | 10 |
| TOTAL | 合计 | 175 | 150 |
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
- T2 思路比较直接,我们根据题意,模拟两人出卡过程,将每个行动设计成一个函数单独计算得分,最后统计得分。
- 遇到了一个小 bug:AS 中的
substr(start, length)第二个参数是长度,不是结束下标。
代码可复用性与需求变更
→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑💻 T1 中已实现的代码进行了哪些复用和修改。
我们没有对 T1 的代码进行复用或修改。
→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
我们通过辅助函数add_cards, remove_cards封装4种行动操作,让每个函数只处理一个动作,当需求变更时,只修改对应辅助函数,不会影响主逻辑和其他操作。
我们可以为函数预留参数,为X预留处理分支,新增行动操作时,直接填充X分支逻辑即可,不破坏原有代码结构。
头脑风暴环节
→ 📖 Q2.5(P) 头脑风暴环节:
我们终于快要开始让程序玩游戏了!请尝试分析:T2 中不带 X 的操作记录比起实际对局多出了多少信息?如果加上 X,也就是失去了这部分信息的话,如何处理对小轮结束后状态的估计?
多出了对方玩家密约和取舍的牌面。
当历史记录包含X时,我们无法唯一确定双方场面上每种牌的张数,只能得到一个可能性集合。对于每个X,可能是任意未被公开的牌,我们可以通过回溯或枚举所有可能的实际牌型组合。
总结
→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录 A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
4 月 2 日 21:30
→ 📖 Q2.7(I) 请写下本部分的心得体会。
我体会到即使是简单功能,也需遵循单一职责和模块化思想,把每个操作动作抽离为独立函数,既能让逻辑清晰易懂,也能在需求变更时精准修改、降低影响。
结对编程的协作方式十分有效,我们在讨论中可以及时发现易出错的点,快速完成修正,显著提升了代码的准确性。
Chapter.3 道途之荆
准备
→ 📖 Q3.1(P) 请记录下目前的时间。
4 月 8 日 14:00
→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | 5 | 5 |
| - Estimate | - 估计这个任务需要多少时间 | 5 | 5 |
| DEVELOPMENT | 开发 | 330 | 330 |
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 10 | 10 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 10 | 10 |
| - Coding Standard | - 代码规范 | 10 | 10 |
| - Design | - 具体设计(确定怎么实现) | 120 | 120 |
| - Coding | - 具体编码 | 120 | 140 |
| - Code Review | - 代码复审 | 30 | 30 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 0 | 0 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 30 | 10 |
| REPORTING | 报告 | 30 | 25 |
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 10 | 10 |
| - Size Measurement | - 计算工作量 | 5 | 5 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 15 | 10 |
| TOTAL | 合计 | 365 | 360 |
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
- 我们通过在游戏实战中找到可以获得胜利的策略,不断讨论和检验策略的正确性
- 得出很多条获得胜利的策略后,对每一个动作的需求进行总结
- 在编码中将每一个动作抽离成一个函数,实现每一个动作总结的获胜策略
头脑风暴环节
→ 📖 Q3.3(P) 头脑风暴环节:
假设提供更充裕的时间和资源,这个游戏中你能找到的最优策略有可能是什么形式的?进行调研并总结分析。你还可以在任务结束后试着实现(不计分)。
用蒙特卡洛树搜索的方式,结合对手手牌的概率来推演对局,估算对手可能持有的各类牌,通过随机模拟多场对局判断怎么走更优。我们还可以分析对手的打法习惯,根据他之前是送牌还是抢牌的选择,反向推测他手里大概有什么牌,以及他是偏保守还是偏激进的玩法。之后再根据这些推断,随时调整自己的行动,针对性克制对手,这样就能在接近最优博弈平衡的情况下,最大程度提高自己的获胜概率。
需求建模和算法设计
→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么选择行动类型?选牌如何更优?如何编程实现。
赢的局面可以是: 2234, 2235, 245 , ... 其他局面不太容易达到. 我们主要追求 2234, 如果实在没有抽中 4, 那么争取拿到 5 分, 狗到下一局 (4 和 5 必须至少拿到 1 张才能不输).
密约 (隐藏 1 张): 如果手上有 4, 那么就藏 4; 如果没有 4, 那么藏 5
丢弃 (丢 2 张, 就不出现在牌局里了):
-
在已经有 2 张
4的情况下, 要扔且只扔 1 张4 -
当 ABC 已有 1 张时, 剩下那张可以丢
赠送 (选 3 张, 对手挑 1 张):
- 如果有 3 张 D / E, 就送这 3 张
- 选 3 张分值最接近的不同的牌
- 别人已经有的 1 张 + 2 张一样的牌
竞争 (选 4 张, 分成 2 组, 对手挑 1 组):
- 在没有特别好的密约 / 丢弃 / 赠送方案的时候, 才会进行竞争, 这往往是在后两手了, 此时可以模拟计算一下, 主要是看怎么分组
- 2 张不要的打牌 + 2 张小牌 / 比较平均的分组
编程实现
(1) 分析局势
-
根据历史记录计算已经打出的牌, 可能有隐藏的牌, 推测一下藏的啥
-
现在我能执行的行动
-
我需要争取的人物
(2) 考虑如何出牌
- 对每个当前可能执行的操作 (密约 / 丢弃 / ...), 算出此类操作最好的出牌方式, 同时粗略地给这个出牌估计一下分值
- 把上面得到的出牌方式按照分值排序, 选最好的那个, 如果分值相同, 按 3 → 1 → 2 → 4 的顺序选
(3) 对手出牌的时候选什么牌
- 设计了
weight_of函数, 综合角色基础分、实时出牌差、是否接近获胜线等因素
代码可复用性与需求变更
→ 📖 Q3.5(P) 请说明针对该任务,你们对 🧑💻 T2 中已实现的代码进行了哪些复用和修改。
复用了角色分值、总数等常量数组的定义,history字符串的解析方法
修改了种行动操作add_cards, remove_cards的函数
→ 📖 Q3.6(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
将角色分值、总数等定义为常量数组。
模块化思想,将游戏状态解析、辅助函数、决策逻辑分离。 weight_of 只负责评估单张牌的价值,不关心行动类型;decide 只负责调度。
软件度量
→ 📖 Q3.7(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块决策能力很强?”,尝试提出一些可能的定量分析方式或测试方式。
- 让程序自己跟自己打,分别用不同策略版本打1000局,看新版胜率是否有提高。
- 让程序跟随机生成的机器人打,胜率能到70%以上说明决策能力较强
- 设计几个经典局面,人工判断最优出法,看程序是否选对。
总结
→ 📖 Q3.8(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
4 月 8 日 20:00
→ 📖 Q3.9(I) 请写下本部分的心得体会。
空想是得不出答案的,结对编程可以让我们两个人通过游戏实战找到策略,反复验证策略的可行性,并调整策略。这次作业融合了博弈论、概率论等多种领域知识,我们不能光闭门造车,也要去学习一些先进的算法和策略,然后再根据实现的可能性和难度去选择最后我们花见小路的策略。
结对项目总结
结对过程回顾和反思
→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。
- 可以增加复盘环节,每次结对后总结协作中的问题,及时调整配合模式
- 分工可以更明确一点,提前划分“驾驶员”与“导航员”的核心职责
→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。
优点:
- 熟练操作各种编程语言软件和git
- 思考问题非常全面,能关注到题目的每一个细节
- 代码编写能力强,能将讨论出来的方案切实转换成代码语言
缺点:太熟悉了,容易闲聊
对结对编程的理解
→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。
优点:
- 思维互补,减少决策偏差与代码、策略漏洞
- 实时沟通,提升问题解决效率
- 互相监督,规范开发流程,降低后期测试与修改成本
缺点:
- 结对编程需要适应两个人的编码习惯,效率较低
- 结对要求双方时刻保持节奏一致,对沟通效率和默契度有很高要求
结对编程在初期使用时会大大降低编程效率,两个人的编程习惯和编程节奏是需要花费较多精力去达到一个平衡的。但是当平衡好这些点之后,结对编程互换工作可以让人的思维更灵活,也更容易发现编码或者逻辑中的漏洞。
代码实现提交
→ 📖 Q4.5(P) 请提供你们完成代码实现的代码仓库链接。

浙公网安备 33010602011771号