[P] 结对项目:花见小路
结对项目:博客问题清单
→ 📖 Q0.0(P) 【你可以在结对结束后补充】如果你的代码仓库包含 AIGC 的部分,列举使用的工具、模型和使用范围。若未使用则填写:本组提交的全部代码不包含AI补全或生成的部分。
- 使用的工具、模型:使用copilot中的Gemini 3.1 pro。
- 使用范围:主要用于T3的策略设计
Chapter.0 wasm从安装到入门
引入
→ 📖 Q0.1(P) 请记录下目前的时间。
2026-04-07 09:40
调查
→ 📖 Q0.2(I) 【你可以在结对结束后另行补充。】作为本项目的调查
对 Wasm 的熟悉程度分级:II. 仅限于听说过相关名词(仅知道 Wasm 是面向 Web 的汇编语言,无具体认知);
对桌游花见小路的熟悉程度:I. 不了解玩法和规则(完全未接触过该桌游,不清楚任何规则和玩法)。
总结
→ 📖 Q0.3(P) 请记录下目前的时间。
2026-04-07 10:48
Chapter.1 七色之缨
结对过程
→ 📖 Q1.1(P) 请记录下目前的时间。
2026-04-07 10:49
→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 预估耗时:60 分钟。
- 依次做的事情:
- 阅读规则,明确判定的核心:11 分获胜和 4 个标记获胜这两种立即获胜情形。
- 分析第三轮特殊结算时的判定优先级:总分 -> 最高档位标记。
- 编写 get_score_from_board 计算分数和数量的辅助函数。
- 编写 hanamikoji_judge 主函数并进行分支判断。
- 编写相应的边界和常规判定测试样例,发现前两轮只要没达到立刻获胜条件就得继续,平局条件要判定。
- 使用 Rust 语言,查阅了 wasm-bindgen 和 JavaScript 导出相关细节,解决类型交互问题。
设计
→ 📖 Q1.3(P) 请说明你们为这个判定模块设计了哪些中间量或辅助函数;如果没有额外设计,也请说明为什么认为直接实现已经足够清晰。
我们设计了一个辅助方法来计算双方的得分和标记数量。因为核心的结算规则就是基于“达到 11 分”或“拿到至少 4 个标记”。为了保持逻辑清晰,我们在主体函数之外先进行两次遍历把这些数据求出,避免在分支里重复算分。
→ 📖 Q1.4(I) 请说明在这样一个规则判定类模块中,如何避免“漏判”“错判”或分支顺序错误等问题。
在规则判定模块中,我会先按优先级梳理所有分支:先判断立即胜利条件,再判断回合限制,最后判断平局与梯队比较。同时为每一种可能的胜负场景编写独立测试,确保不会出现漏判、错判或顺序覆盖问题。
测试
→ 📖 Q1.5(P) 请说明你们设计了哪些测试用例,这些测试分别覆盖了哪一类规则或边界情况。
- 分数压制测试:一方 11 分,一方不满,立即获胜。
- 数量压制测试:一方刚好 4 标记但没 11 分,另一方没有 11 分,标记 4 的一方获胜。
- 第 1/2 轮没满足获胜条件:虽然目前可能比分领先,但需要返回 0让局数继续。
- 第 3 轮总分高测试:没有达到立即获胜但是到了最后一轮第三轮,直接看总分。
- 第 3 轮总分相同同分档位判定:如双方总分都是 10 分,比较最高优先级的对应标记。
- 全0初始状态:没有进展判定 0。
- 平局情况测试。
→ 📖 Q1.6(I) 请说明你对“先写测试再实现”与“先实现再补测试”两种方式的理解。
先写测试可以提前锁定正确行为,减少后期返工,但对新手不够友好。先实现再补测试更容易快速搭建可用版本,适合探索性开发,不过测试容易写得不够全面,需要刻意补充边界用例。
总结
→ 📖 Q1.7(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026-04-07 12:30
→ 📖 Q1.8(I) 请写下本部分的心得体会。
第一次用 Rust 编写 Wasm 模块,强类型系统有效避免了类型错误,让跨语言调用更稳定。结对讨论也让我们快速对齐规则,避免了个人理解偏差带来的逻辑错误。
Chapter.2 不祥之影
准备
→ 📖 Q2.1(P) 请记录下目前的时间。
2026-04-07 14:27
→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 预估耗时:180 分钟。
- 依次做的事情:
- 阅读规则和 T2 的需求:从 history 行动池和初始 board 来结算本轮结束后的状态(双方面板牌数量及新 board 倾心标记)。
- 开始解析 history:将由空格和短划线连接的字符串分割并根据字符进行识别,分配到我方和对方的出牌统计中。
- 对 4 种类型行动分别处理:密约(1 张扣留)、取舍(扣掉 2 张不要的牌)、赠送(3 选 1 分配)、竞争(4 分两组选 1 组分配)。
- 加上对隐藏牌 X 的判定:X 表示打出但还不公开的牌(比如对方选的密约、取舍)。
- 提取对局操作的逻辑后,更新 board:计算各类型的总持有量(公开的和确定的),再加上历史 board 得到新 board,如遇平局则保持上一轮 board 不变。
- 针对一些未确定但是能从历史推出的隐式数量进行完善代码,使用 NPM 进行自动化 JS 测试。
代码可复用性与需求变更
→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑💻 T1 中已实现的代码进行了哪些复用和修改。
T2 的结果输出 board 是 T1 的输入条件。但本轮 T2 是计算小轮结束后的盘面的。原本想把 T1 直接拿来但发现需求是输出状态而不是给出胜负,所以我们并没有修改复用 T1 的具体代码,只是我们对 board 数组结构与表示(七个位置、表示方向等)的概念一致了,这是对于游戏数据状态定义的一次复用和深入理解。
→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
提高代码适应性可以采用分层设计,将动作解析、状态更新、分数计算拆成独立阶段。同时抽象通用接口,预留扩展字段,让规则变更只影响局部代码,不破坏整体结构。
头脑风暴环节
→ 📖 Q2.5(P) 头脑风暴环节:
我们终于快要开始让程序玩游戏了!请尝试分析:T2 中不带 X 的操作记录比起实际对局多出了多少信息?如果加上 X,也就是失去了这部分信息的话,如何处理对小轮结束后状态的估计?
比起实际对局,不带 X 的操作记录多出了对方执行的“密约”和“取舍”(不要的两张牌),这就直接等于上帝视角甚至知道了牌堆剩什么,也就没了博弈感。
如果在真实对局中加上 X 隐藏这部分信息,对于小轮结束后的状态估计:只能记录已知落到自己或桌面公开给你的牌,把密约和取舍当作系统暗牌或手牌进行概率推理(类似于斗地主的算牌);真正结束时候游戏会亮开密约牌再做计分,在此之前(出牌决定时),需要用贝叶斯概率或期望模型来评估某个选择能赢得某个标记的具体概率。
总结
→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录 A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026-04-07 19:55。
→ 📖 Q2.7(I) 请写下本部分的心得体会。
复杂动作序列的解析必须结构化拆解,逐字段校验,否则很容易出现符号、顺序、主体错误。结对编程在这部分优势明显,一人写逻辑一人查错误,大幅减少调试时间。
Chapter.3 道途之荆
准备
→ 📖 Q3.1(P) 请记录下目前的时间。
2026-04-08 14:02
→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 预估耗时:300 分钟。
- 依次做的事情:
- 梳理游戏的状态和决策,写出骨架函数:分辨出是回合内行动决策(从手里挑牌组成行动发给对手或放到桌面),还是回合内响应对方动作(3 或 4,挑选牌或组)。
- 开始查阅两人完全信息(假设没有 X 的简化博弈)下极小极大值算法。但是在不完全信息情况,还是采用更具针对性的贪心出牌策略(根据当前局面标记的权重进行打分)。
- 实现了一个可以为手里的每张卡单独打出“得胜价值分”的方法 get_card_score:由于角色 G 分数高(5 分),给高优先级。并结合目前标记是在我方还是对方或中立,如果是对方,价值提高因为需要夺回。
- 对 3 和 4 的动作做响应处理(try_generate_response),遇到对手来时选对自己有利的。
- 接着在正常出牌(generate_normal_action)时,对未动作过的类型按照情况判断,手里有几张对应价值的牌,优先保证能用高价值牌动作来确立优势。
- 写完并逐步重构这几个逻辑(将原本大函数的判断拆成如上两个更清晰的部分)。
- 对接完成,测试和调整 JS 脚本与 Rust 胶水的参数,成功完成。
头脑风暴环节
→ 📖 Q3.3(P) 头脑风暴环节:
假设提供更充裕的时间和资源,这个游戏中你能找到的最优策略有可能是什么形式的?进行调研并总结分析。你还可以在任务结束后试着实现(不计分)。
如果资源不受限,最优策略可能基于马尔可夫决策过程 (MDP) 或不完全信息博弈的蒙特卡洛树搜索 (CFR/MCTS),或者是深度强化学习(类似 AlphaZero 的方法,通过自己和自己对弈千万局生成)。
因为花见小路是一个双人不完全信息的对弈,手牌的非对称和“密约/取舍的 X”,让每一轮对方的决定带有骗术(Bluffing)。最优解是建立在“推算对方手牌范围的概率分布 -> 然后根据博弈矩阵计算纳什均衡策略”。
甚至可以构建对方玩家的画像(Aggressive 或 Conservative 用户)
需求建模和算法设计
→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么选择行动类型?选牌如何更优?如何编程实现。
我们采用了当前局面收益最大化的动态加权启发式搜索:
对“选牌更优”:我们通过 get_card_score 进行估值:基础分加上棋盘状态,base * (3 - board_status),即如果倾向在对手那里,我们给它的权重是基础分的 4 倍,中立是 3 倍,已经在我们这则是 2 倍(保住它)。
对“行动类型”的判断:在 generate_normal_action 中,优先出不费高价值核心牌但能耗轮次的行动;比如当有多张废牌时先出“取舍 2”。最后在行动 3 和 4 时出强牌逼迫对手选择。
代码可复用性与需求变更
→ 📖 Q3.5(P) 请说明针对该任务,你们对 🧑💻 T2 中已实现的代码进行了哪些复用和修改。
T2 中关于计算局面状态以及解析 history 行动池串中提取未做过的可用行动,我们复用了这段思想。在 T3 中实现了一个 parse_history 获取当前四个动作是否被用过(布尔数组 us_used)。对于 T2 中的按字符比对也被精简后用作了回应的提取动作组操作。
→ 📖 Q3.6(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
把游戏状态与决策行为解耦,统一通过状态接口访问数据,同时支持多策略并存与切换。加入日志埋点记录决策过程,方便后续分析与优化,提升代码面对变更的稳定性。
软件度量
→ 📖 Q3.7(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块决策能力很强?”,尝试提出一些可能的定量分析方式或测试方式。
我们可以采取自对弈擂台赛:写几个 baseline 的机器人(随机出牌机器人、优先选高分机器人、固定顺序出牌机器人),然后让我们的程序模块分别跟这三个机器人各自对战 100 局,计算胜率(Win Rate),从而给出一个明确量化的棋力 Elo 积分系统评价。
其次是引入记录对手平均能拿的分数等作为胜出的强度的定量体现。
总结
→ 📖 Q3.8(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026-04-10 20:15。
→ 📖 Q3.9(I) 请写下本部分的心得体会。
在不断打磨估值函数、让程序的决策越来越合理的过程中,我能清晰看到项目一点点完善、越来越接近真实的样子。这种看得见的进步让我很有成就感,也是我们这次结对工作最能体现智能与价值的部分。
结对项目总结
结对过程回顾和反思
→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。
在时间分配上由于这是第一次采用完全结对,一开始我们对领航员和驾驶员的角色分配有些僵硬:往往变成一个人在“说”然后写错了另一个人指出来而不是真正对代码构思协同思考。在做 T3 这样的高强度逻辑时才真正体现协同,我们在测试设计上可以在 T1, T2 投入更多时间。另外对 Git 的使用也应当规划得更有意义些,避免为了交而 commit,应当是模块完成再提交。
→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。
优点是逻辑梳理能力强、测试意识全面、沟通耐心负责;缺点是对新语法不熟悉,编码与调试速度稍慢。
对结对编程的理解
→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。
结对编程优点是双人互查减少错误、问题解决更快、知识互补成长快;缺点是存在沟通成本、两人节奏难统一、效率受状态影响较大。
代码实现提交
→ 📖 Q4.5(P) 请提供你们完成代码实现的代码仓库链接。
https://github.com/shiki1205/pair
附录
附录 A:基于 PSP 2.1 修改的 PSP 表格
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | 60 | 68 |
| - Estimate | - 估计这个任务需要多少时间 | 60 | 68 |
| DEVELOPMENT | 开发 | 280 | 410 |
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 30 | 40 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 60 | 80 |
| - Coding Standard | - 代码规范 | 10 | 10 |
| - Design | - 具体设计(确定怎么实现) | 50 | 80 |
| - Coding | - 具体编码 | 90 | 140 |
| - Code Review | - 代码复审 | 20 | 30 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 10 | 15 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 10 | 15 |
| REPORTING | 报告 | 30 | 35 |
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 10 | 10 |
| - Size Measurement | - 计算工作量 | 10 | 5 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 10 | 20 |
| TOTAL | 合计 | 370 | 513 |

浙公网安备 33010602011771号