[P] 结对项目:花见小路
[P] 结对项目:花见小路
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 课程社区 |
| 这个作业的要求在哪里 | 作业要求 |
| 我在这个课程的目标是 | 更好地走进软件工程 |
| 这个作业在哪个具体方面帮助我实现目标 | 学习体会结对编程、敏捷开发等 |
→ 📖 Q0.0(P) 【你可以在结对结束后补充】如果你的代码仓库包含 AIGC 的部分,列举使用的工具、模型和使用范围。若未使用则填写:本组提交的全部代码不包含AI补全或生成的部分。
使用gemini-3.1-pro-preview,范围包括提供大致的启发与指导,与根据想法生成指定逻辑等。
Chapter.0 wasm从安装到入门
引入
→ 📖 Q0.1(P) 请记录下目前的时间。
4.3 22:06
调查
→ 📖 Q0.2(I) 【你可以在结对结束后另行补充。】作为本项目的调查:
请如实标注在开始项目之前对 Wasm 的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
- 没有听说过
请如实标注在开始项目之前对桌游花见小路的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
- 不了解玩法和规则
总结
→ 📖 Q0.3(P) 请记录下目前的时间。
4.3 23:32
Chapter.1 七色之缨
结对过程
→ 📖 Q1.1(P) 请记录下目前的时间。
4.10 10:00
→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(例如查阅了哪些资料、如何设计判定逻辑、如何设计测试样例、遇到了什么问题、如何解决)。
-
Personal Software Process Stages 个人软件开发流程 预估耗时(分钟) 实际耗时(分钟) PLANNING 计划 - Estimate - 估计这个任务需要多少时间 5 5 DEVELOPMENT 开发 - Analysis & Design Spec - 需求分析 & 生成设计规格(确定要实现什么) 10 15 - Technical Background - 了解技术背景(包括学习新技术) 10 13 - Coding Standard - 代码规范 0 0 - Design - 具体设计(确定怎么实现) 5 2 - Coding - 具体编码 15 11 - Code Review - 代码复审 10 5 - Test Design - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) 5 4 - Test Implement - 测试实现(设计/生成具体的测试用例、编码实现测试) 10 13 REPORTING 报告 - Quality Report - 质量报告(评估设计、实现、测试的有效性) 10 15 - Size Measurement - 计算工作量 5 3 - Postmortem & Process Improvement Plan - 事后总结和过程改进计划(总结过程中的问题和改进点) 5 3 TOTAL 合计 90 79 -
首先大致查阅了 AssemblyScript 官方文档,了解了 Wasm 与 JS 之间的数据传递机制。遇到测试环境配置报错(ES Modules 问题),通过修改 package.json 的 type 字段解决。最后编写了 6 个简单的本地自动化测试用例覆盖全部规则。
设计
→ 📖 Q1.3(P) 请说明你们为这个判定模块设计了哪些中间量或辅助函数;如果没有额外设计,也请说明为什么认为直接实现已经足够清晰。
中间量设计包括my_score,opp_score,my_tokens,opp_tokens等,整体判断逻辑已经很清楚,没有再设计辅助函数,就按照要求依次判断就搞定了。
→ 📖 Q1.4(I) 请说明在这样一个规则判定类模块中,如何避免“漏判”“错判”或分支顺序错误等问题。
首先厘清楚判断优先级,梳理好逻辑,想明白后再慢慢写,然后再在写的时候注意好命名规范与层次分明,就应该没什么问题。
测试
→ 📖 Q1.5(P) 请说明你们设计了哪些测试用例,这些测试分别覆盖了哪一类规则或边界情况。
按照课程组要求,我们编写了 my_test.js 进行自动化断言,共覆盖了 6 类情况:
- 分值溢出胜利:一方分数达到11分。
- 标记数达标胜利:一方获得至少 4 枚标记且对手未到 11 分。
- 未决状态继续游戏:前两小轮结束时尚未满足任何结束条件。
- 第三轮分值决胜:第三轮结束,双方分数不同,高分胜。
- 第三轮最高档位决胜:第三轮结束同分,判定最高档位 G/F。
- 最终同档平局判定:第三轮结束同分,最高档位均中立,且双方在 D/E 档位僵持,引发规则穷尽返回平局(2)。
→ 📖 Q1.6(I) 请说明你对“先写测试再实现”与“先实现再补测试”两种方式的理解。
先写测试要求我们对需求边界与特殊情况有清楚的感知,写代码时目标感较强。先实现则是一般的流程,思维阻力较小,适合快速开发。
总结
→ 📖 Q1.7(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
10:00 + 79min = 11:19
→ 📖 Q1.8(I) 请写下本部分的心得体会。
初次接触 WebAssembly,感受到了前端底层技术的魅力。大致理解了 Node.js、JS 胶水代码和 Wasm三者之间的关系。另外,感觉ts比较易上手,和python比较像。
Chapter.2 不祥之影
准备
→ 📖 Q2.1(P) 请记录下目前的时间。
12:15
→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
-
Personal Software Process Stages 个人软件开发流程 预估耗时(分钟) 实际耗时(分钟) PLANNING 计划 - Estimate - 估计这个任务需要多少时间 5 4 DEVELOPMENT 开发 - Analysis & Design Spec - 需求分析 & 生成设计规格(确定要实现什么) 10 11 - Technical Background - 了解技术背景(包括学习新技术) 10 10 - Coding Standard - 代码规范 0 0 - Design - 具体设计(确定怎么实现) 5 4 - Coding - 具体编码 15 15 - Code Review - 代码复审 5 6 - Test Design - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) 5 3 - Test Implement - 测试实现(设计/生成具体的测试用例、编码实现测试) 5 7 REPORTING 报告 - Quality Report - 质量报告(评估设计、实现、测试的有效性) 10 15 - Size Measurement - 计算工作量 5 3 - Postmortem & Process Improvement Plan - 事后总结和过程改进计划(总结过程中的问题和改进点) 5 5 TOTAL 合计 80 83 -
主要了解了更多关于ts的语法,最后是直接返回的包含 21 个元素的数组Int8Array,没有碰到什么大问题。
代码可复用性与需求变更
→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑💻 T1 中已实现的代码进行了哪些复用和修改。
主要是环境搭建的过程是一致的,代码层面似乎没什么复用
→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
重视可读性与层次;最好不要硬编码,可以适当保持一点可拓展性。如在解析“赠送(3)”和“竞争(4)”操作时,我们都是通过全集数量 - 选走数量 = 剩余数量的代数计算完成的分发。
头脑风暴环节
→ 📖 Q2.5(P) 头脑风暴环节:
我们终于快要开始让程序玩游戏了!请尝试分析:T2 中不带 X 的操作记录比起实际对局多出了多少信息?如果加上 X,也就是失去了这部分信息的话,如何处理对小轮结束后状态的估计?
T2 的操作记录不带 X,消除了“扣牌”的不确定性,使对局变成了一个绝对确定的状态机。如果加上 X 失去这部分信息,我们就失去了确定性。此时必须引入概率论和记牌器模型:用全集 21 张牌 - 场上明牌 - 己方手牌推导剩余未知牌池,基于概率分布去估算对手 X 牌的组成,从而推算小轮结束后的期望状态。
总结
→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录 A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
12:15 + 83min = 13:38
→ 📖 Q2.7(I) 请写下本部分的心得体会。
注意字符转换,字符串分切等操作。要善于使用数组。
Chapter.3 道途之荆
准备
→ 📖 Q3.1(P) 请记录下目前的时间。
15:00
→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
-
Personal Software Process Stages 个人软件开发流程 预估耗时(分钟) 实际耗时(分钟) PLANNING 计划 - Estimate - 估计这个任务需要多少时间 10 8 DEVELOPMENT 开发 - Analysis & Design Spec - 需求分析 & 生成设计规格(确定要实现什么) 20 15 - Technical Background - 了解技术背景(包括学习新技术) 20 17 - Coding Standard - 代码规范 5 5 - Design - 具体设计(确定怎么实现) 30 25 - Coding - 具体编码 90 97 - Code Review - 代码复审 15 13 - Test Design - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) 15 12 - Test Implement - 测试实现(设计/生成具体的测试用例、编码实现测试) 20 18 REPORTING 报告 - Quality Report - 质量报告(评估设计、实现、测试的有效性) 10 12 - Size Measurement - 计算工作量 5 3 - Postmortem & Process Improvement Plan - 事后总结和过程改进计划(总结过程中的问题和改进点) 20 18 TOTAL 合计 260 243 -
主要还是查阅了 README 中 T3 的规则说明和 AssemblyScript 的官方文档,确定了要用一维数组去追求极限性能。
因为 T3 是一场硬核的 AI 对抗,前期也是看了看
src/T3/hanamikoji-engine.js,搞清楚了history这个长字符串的拼接格式和局势推进流转的方式。实现时,先写了一个
parse_areas解析器把当前的明面战况还原成我们能算的数组;接着我们觉得光顺着步骤出牌太傻了,所以引入了一套基于最坏情况打分(Minimax)的推演组合方案:把对手能选走的情况全部暴力枚举出来,自己挑选分数最大化的打法,并且根据当前可用行动动态选择打出 1、2、3 还是 4。遇到的问题:第一是死牌浪费问题。AI 总是用好牌去抢已经笃定能赢的角色,后来我们引入了未知牌池的“信息追踪”,一旦测算出已构成绝对压制,就不再给该角色增加打分,AI 瞬间就变聪明了;第二个问题是一个非常坑的 Wasm 运行时 Bug,当遇到对方藏牌动作带有字母
X时,用它减去'A'强制寻址会导致Int8Array(7)越界崩溃,导致全盘报错。后来我们在代码里补上了0~6的安全防线才解决,配合自己在本地写的 30 组极限压力测试,逻辑才彻底稳健。
头脑风暴环节
→ 📖 Q3.3(P) 头脑风暴环节:
假设提供更充裕的时间和资源,这个游戏中你能找到的最优策略有可能是什么形式的?进行调研并总结分析。你还可以在任务结束后试着实现(不计分)。
高藩:我想的最优策略就是蒙特卡洛模拟,基于已有的信息去试何种操作推演到最后胜率最大,就选何种操作。当然在试的过程中也可以加入一些启发式规则的优化。
李延博:《花见小路》是一个经典的非完美信息博弈,且状态空间有限。若有更充足算力可以考虑以下:
- CFR(反事实遗憾最小化算法是目前解决非完美信息扑克游戏的最优解。通过引入信息集对所有可能的发牌组合做分布迭代,找到纳什均衡策略。
- MCTS (蒙特卡洛树搜索) + 信心上界 (UCT):利用模拟对局到底的方式,取代我们现在手写的固定参数启发式函数 (
evaluate_board_score)。当前我们在动作3/4只往前看了“1层”,但由于花见小路的局面收敛较快,若利用 MCTS 也许能看深 2~3 层。
需求建模和算法设计
→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么选择行动类型?选牌如何更优?如何编程实现。
怎么选择行动类型? 一开始我们图省事定死了 1->2->3->4 的出牌顺序,但发现这极其容易被针对。后来我们改成了‘平行打分机制’:在每回合,AI 查验自己这轮还能打哪些行动,然后把当前手牌分别假装套入这些可用行动去算分,哪个行动算出来的终局预测得分高,就打哪个。比如如果起手有全场最关键的 G,它就会动态优先发动密约(动作1)把 G 藏起来保护。
选牌如何更优? 对于最纠结的赠送(动作3,给3选1)和竞争(动作4,给4分组),我们用上了极小化极大(Minimax)博弈思想。把所有的给牌组合(比如 C(n,3) 和 C(4,2) 全排列)都用 for 循环暴力枚举出来。在推演中,假定对手极其聪明,肯定会挑走对我们伤害最大的牌。我们在所有这些‘最坏情况’里,挑出一个能让我们留存得分最高的组合给对方。
如何编程实现? 核心都在重写的 evaluate_board_score 函数里。我们抛弃了单纯论卡牌分值,只看终局效果:主要考量分差拉扯、距离 11 分或 4 个标记的吃紧程度。 我们还在代码里引入了 unknown_pool(未知数计算:用总牌单减去已知明牌和自己丢掉的牌)。靠这个池子,代码就能在推断出‘即使剩下未知的牌全给我我也赢不了’时判定绝对败局,或者判定绝对胜局。一旦触发绝对锁定,代码就把投入边际得分直接砍为 0,防止把宝贵的好牌浪费在“已经死局”的列上面。同时为了保证满足 2000 毫秒的性能红线,这些逻辑全部采用 Int8Array 展平计算,没有去套任何慢的类或复杂对象。”
代码可复用性与需求变更
→ 📖 Q3.5(P) 请说明针对该任务,你们对 🧑💻 T2 中已实现的代码进行了哪些复用和修改。
对底层的手牌解析遍历(parse_areas / 获取当前分布)进行了一定程度上的复用和强化,但将原本只有局部视野的静态 get_dynamic_value 改为了用于开局牌序快排的辅件。整体的决策内核(hanamikoji_action)由于策略维度由局部最优切换至全局优化,因此我们彻底重写并重构了以 evaluate_board_score 为中心的框架。
→ 📖 Q3.6(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
可以采用解耦的思想,设计不同的模块将逻辑分开,这样结构更清晰,也便于大家合作开发。
软件度量
→ 📖 Q3.7(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块决策能力很强?”,尝试提出一些可能的定量分析方式或测试方式。
设计一些基线方法,如纯随机出牌,简单贪心作为基线。如果通过大量的随机对局,模型都有很高的胜率,那么就可以定量证明模型的决策压制力。
由于 WebAssembly 运行飞快,在验证功能和质量上,我们在 my_test.js 中构建了 30 个包含极限边界(如全烂牌、即将输掉、特定信息封锁等)的白盒拦截压测。为了证明决策能力较强,可以采取以下定量测定:
- 自我对弈循环 (Self-Play benchmark):开启一万次本版本 AI 与原始“纯贪心”或“随机出牌”旧版本 AI 的循环对局。通过胜率统计结果是否达到
80%以上压制,以及分析录像看看它是否利用信息追踪提前弃掉了无用高价值牌。 - 并在真实环境下与其他同学编写的不同风格流派的 T3 bot 进行批量互打积分赛。
总结
→ 📖 Q3.8(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
15:00+243min = 19:03
→ 📖 Q3.9(I) 请写下本部分的心得体会。
对抗总是充满无限乐趣与挑战,但我们也需要保持投入与收益的平衡。
结对项目总结
结对过程回顾和反思
→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。
- 测试驱动(TDD)介入得还是稍晚了一些 反思:前期我们把大量精力花在了业务逻辑和数据结构的推演上,直到最后才补全了那 30 组自动化压力测试。这也导致了那个极其隐蔽的
Int8Array越界崩溃 Bug(也就是对方历史记录自带不可见字符 X 时导致寻址溢出)被压到最后环节才暴露出来。 改进:应该在写最基础的parse_areas方法时,就随手同步写几个异常字符的输入单测,做到“写一个接口就固化一个测试”,防止底层隐患堆积到上层爆发。 - 驾驶员(Driver)与领航员(Navigator)的节奏磨合可以更好 反思:在实现 Minimax 的深层嵌套逻辑(四层
for循环暴力枚举)时,由于思想比较复杂,有时驾驶员(写代码的人)会陷入专注敲代码的状态,写得太沉浸而导致领航员(审查的人)短暂跟不上思路,变成了单人作战。 改进:应该引入严格的“番茄钟机制”定期强行交换角色,并要求驾驶员必须随时嘴说出当前这一行要敲什么意图的代码,保证两人的思想波段 100% 同步。 - 对特定的技术栈特性需要更深的前置预研 反思:我们在把逻辑迁入 AssemblyScript 时遇到了一些折磨。原本以为 AS 只是带类型的 TypeScript,但实际上由于 WebAssembly 底层的静态化与扁平化设计,很多高阶容器及语法糖(比如原本顺手写的
Array.map等)受限制,直接导致了一次较大面的返工重构。 改进:对于陌生的执行环境,在着手写庞大的核心逻辑前,应该先花半小时写一两个“沙盒型”的练手小脚本,彻底摸清它的语言边界和底层特征再开工。”
→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。
易于沟通,随和友好,逻辑清晰。讨论效率不是很高。
对结对编程的理解
→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。
好处是能实时 Code Review,大大减少了低级逻辑错误。缺点是copilot可能没什么事做,pilot也会有比较大的心理压力,开发效率可能没那么高。我觉得现在AI作为copilot挺好的,真人结对编程可能没那么好了。
代码实现提交
→ 📖 Q4.5(P) 请提供你们完成代码实现的代码仓库链接。

浙公网安备 33010602011771号