结对编程问题清单
结对项目:博客问题清单
请将本文件在代码仓库外复制一份,一边阅读和完成结对项目、一边填写入代码仓库外的版本,或采取简记、语音备忘等方式记载较复杂问题的要点之后再补充。请不要将本文档内的作答提交到代码仓库。
→ 📖 Q0.0(P) 【你可以在结对结束后补充】如果你的代码仓库包含 AIGC 的部分,列举使用的工具、模型和使用范围。若未使用则填写:本组提交的全部代码不包含AI补全或生成的部分。
本仓库使用ai版本:claude opus 4.6
使用范围:开发前练手项目辅助开发,工具链配置,博弈思路参考,博弈算法得分设计参考
Chapter.0 wasm从安装到入门
引入
→ 📖 Q0.1(P) 请记录下目前的时间。
3月29日 19:00
调查
→ 📖 Q0.2(I) 【你可以在结对结束后另行补充。】作为本项目的调查:
请如实标注在开始项目之前对 Wasm 的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 没有听说过;
II. 仅限于听说过相关名词;
III. 听说过,且有一定了解;
IV. 听说过,且使用 Wasm 实际进行过开发(即便是玩具项目的开发)。
I. 没有听说过;
请如实标注在开始项目之前对桌游花见小路的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 不了解玩法和规则;
II. 听说过,且有一定了解;
II. 听说过,且有一定了解;
总结
→ 📖 Q0.3(P) 请记录下目前的时间。
3月29日 20:00
Chapter.1 七色之缨
结对过程
→ 📖 Q1.1(P) 请记录下目前的时间。
4月5日 9:00
→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(例如查阅了哪些资料、如何设计判定逻辑、如何设计测试样例、遇到了什么问题、如何解决)。
- 参考资料:第一部分主要还在熟悉
rust语法和项目运行,参考了几个相关教学博客:rust菜鸟教程、rust程序设计中文版 - 开始编写前使用ai辅助设计了一个用于熟悉流程的小项目,熟悉完整的工具链
- 首先梳理出胜负规则的逻辑和胜负判定优先级:11分立即胜利 > 4枚标记胜利 > 未结束继续 > 第三轮最终判定
- 将胜负逻辑按优先级拆分成辅助函数
calc_score、count_markers、has_marker_in_tier,依次进行胜负判断 - 编写单元测试覆盖 6 类不同的胜负判断场景,通过
cargo test验证全部通过 - 遇到问题:主要是模式匹配语法判定比较严格,前期对语法不熟悉导致出现了很多次编译失败的结果,修改主要是逐步拆分匹配判定一路简化方便编写
- 测试用文件test.js无法用于测试,询问ai后发现是修改package.json导致的问题,修改为.cjs文件
设计
→ 📖 Q1.3(P) 请说明你们为这个判定模块设计了哪些中间量或辅助函数;如果没有额外设计,也请说明为什么认为直接实现已经足够清晰。
- 辅助函数为进行胜负逻辑判定的三个辅助函数
calc_score、count_markers、has_marker_in_tier calc_score(board, side) -> i32:统计指定方拥有的倾心标记总分值。遍历 board,对匹配 side 的标记累加对应的 SCORES 数组值(A/B/C=2, D/E=3, F=4, G=5)count_markers(board, side) -> i32:统计指定方拥有的倾心标记数量has_marker_in_tier(board, side, tier_idx) -> bool:判断指定方在某一档位中是否拥有至少一枚倾心标记。档位按分数从高到低定义- 辅助数据结构包括两个数组:
SCORES: [i32; 7]:每个角色对应的分值TIERS和TIER_LENS:档位分组索引和每组的元素个数。
→ 📖 Q1.4(I) 请说明在这样一个规则判定类模块中,如何避免“漏判”“错判”或分支顺序错误等问题。
- 避免“漏判”:在设计判定逻辑时,以流程图的形式展示各种可能的情况,并在每种情况中都有明确的输出结果,避免出现漏判的情况。
- 避免“错判”:对于每种情况,详细斟酌判定规则,确保能够准确地将文字规则翻译为代码控制流。
- 分支顺序错误:同样是采用流程图去规避逻辑误区
- 结合测试手段:最粗暴有效的避免bug的方式是通过全面的测试覆盖,确保每一个分支都能正确执行。
测试
→ 📖 Q1.5(P) 请说明你们设计了哪些测试用例,这些测试分别覆盖了哪一类规则或边界情况。
- 总分11分获胜
- 四枚标记获胜
- 本轮未分出胜负,继续比赛
- 第三轮总分最高者获胜
- 第三轮总分相同,按最高分数标记分胜负
- 第三轮总分相同,最高分数标记相同,平局
- 优先级验证:一方获得11分,另一方获得四枚标记
→ 📖 Q1.6(I) 请说明你对“先写测试再实现”与“先实现再补测试”两种方式的理解。
- 先写测试在实现本质上是先理清需求,然后面向需求编写代码,能够使得编写代码时的思路更加清晰,但整体开发速度会受到限制
- 先实现再补测试则是先编写代码,然后再补充测试用例,优点在于初期的开发速度会更快,但效果需要大量验证,测试发现bug时不易迅速解决
总结
→ 📖 Q1.7(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
4月5日 11:30
→ 📖 Q1.8(I) 请写下本部分的心得体会。
本部分的任务是基于小轮结束后的牌面情况判定输赢,引导我们先设计好算法,然后编写实现,最后再进行测试。我作为“结对”中领航员的角色,抛开具体实现的细节,只从大的策略角度出发去思考如何编写出如何设计判定逻辑,如何安排代码结构,以及如何进行测试,这种抛开细节专注于整体的思考,让我对于问题的思考和理解都更加全面。
Chapter.2 不祥之影
准备
→ 📖 Q2.1(P) 请记录下目前的时间。
4月5日 19:00
→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
- 阅读 T2 的任务要求,理解输入(history 字符串 + 初始 board)和输出(3×7 二维数组)的格式
- 重点研究了 history 字符串的解析规则:8 段行动记录、4 种行动类型、赠予和竞争中的选择用 - 连接。参照 README 中的示例表格逐步推导验证
- 在 T2 目录下创建 t2-rust 项目,额外添加了 js-sys 依赖用于返回 JS 数组。
- 核心实现思路:按空格分割 history,偶数索引为 P1 的行动、奇数索引为 P2 的行动。对每条行动,根据类型分别处理牌的归属
- 结算阶段复用了 T1 的比较逻辑:逐种牌比较双方数量,多者拿标记,平手保持原值
- 遇到的问题:竞争行动(类型4)需要判断对手选了哪一组。解决方法是将选择的牌排序后与两组分别比较
- 编写了 9 个测试,初次运行时有 2 个竞争相关测试失败,原因是测试预期值写错(遗漏了密约步骤的牌),修正预期值后全部通过
- 通过课程组的
npm run submit-test验证
代码可复用性与需求变更
→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑💻 T1 中已实现的代码进行了哪些复用和修改。
- 直接复用的函数:T2 结算阶段的 board 更新逻辑与 T1 的核心思想一致,通过比较双方同种牌的数量来决定标记归属。T1 中
calc_score和count_markers的设计思路被直接应用到 T2 的结算中 - 未直接导入 T1 函数:T2 是独立的 Rust 项目,没有通过 crate 依赖引入 T1 的代码,而是在 T2 中重新实现了结算逻辑。这是因为 T2 的结算更简单(直接比较牌数),不需要 T1 中完整的胜负判定(11 分、4 标记等条件)
- 共享的函数:
card_to_index函数(将 A-G 映射到 0-6 索引)是两个任务共用的基础工具,在 T2 中重新实现了一份
→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
提高代码适应需求变更能力的核心在于"封装变化,隔离稳定"——通过策略模式、依赖注入等机制将易变逻辑(如业务规则、外部接口)抽象为可插拔组件,同时以接口契约隔离稳定领域模型;设计冗余上,保留适度的扩展点(如配置化开关、事件钩子、预留字段)而非过度泛化,确保新增需求可通过"扩展而非修改"(开闭原则)实现,避免牵一发而动全身的级联改动。
头脑风暴环节
→ 📖 Q2.5(P) 头脑风暴环节:
我们终于快要开始让程序玩游戏了!请尝试分析:T2 中不带 X 的操作记录比起实际对局多出了多少信息?如果加上 X,也就是失去了这部分信息的话,如何处理对小轮结束后状态的估计?
T2 的不带 X 记录是完全信息,实际对局则存在 7 张隐藏牌(1 张暗弃、1 张己方密约、4 张双方取舍弃牌)的不对称信息;若加上 X,需采用蒙特卡洛模拟补全隐藏牌分布、贝叶斯更新对手信念状态,或结合期望最大化与极小极大算法进行概率推断,将 T2 的确定性计算封装为采样单元以支撑不完全信息决策。
总结
→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录 A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
4月5日 22:00
→ 📖 Q2.7(I) 请写下本部分的心得体会。
T2 让我们体会到,从一串操作记录里倒推出牌局状态比想象中麻烦——要搞清楚谁先手、谁响应、牌怎么分,细节一多就容易乱。结对编程时两人轮着写代码、互相检查确实能减少 bug,但也得花时间对齐思路,不然各自理解不同反而耽误事。这次的经验对后面做 T3 很有帮助,因为实际对局时看不到对手的暗牌,得靠猜和算概率,而 T2 的复盘逻辑正好可以用来验证猜得对不对。
Chapter.3 道途之荆
准备
→ 📖 Q3.1(P) 请记录下目前的时间。
4月6日 9:00
→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
- 博弈思路参考花见小路
- 阅读 T3 任务要求,理解输入(history、cards 手牌、board)和输出(行动字符串)的格式
- 确定了三类回合:主动行动、回应赠予(从 3 张中选 1 张)、回应竞争(从 2 组中选 1 组)
- 策略选择:采用 minimax 评估框架。对于赠予和竞争,假设对手会做出对自己最有利的选择(即对我最不利),在最坏情况下选评分最高的方案
- 实现了组合生成函数 select_cards:从手牌中选 k 张的所有不重复方式。以及 split_into_groups:将 4 张牌拆分为两组的所有不重复方式
- 设计了评估函数 evaluate_state:综合考虑分差、胜利条件奖励、手牌潜力
- 遇到的问题:需要正确判断当前是行动回合还是回应回合,通过分析 history 最后一条记录是否包含 - 来区分。
- 编写 12 个测试覆盖行动有效性、回应有效性、策略合理性、状态解析、组合生成、评估函数
- 通过自我对战测试(同时作为 P1 和 P2),验证了完整对局流程正常
头脑风暴环节
→ 📖 Q3.3(P) 头脑风暴环节:
假设提供更充裕的时间和资源,这个游戏中你能找到的最优策略有可能是什么形式的?进行调研并总结分析。你还可以在任务结束后试着实现(不计分)。
如果时间充裕,最优策略可能是用蒙特卡洛树搜索(MCTS)或强化学习——让程序自己跟自己打成千上万局,慢慢学会什么情况下该出牌还是弃牌,甚至能摸透对手的套路。另一种思路是博弈树搜索,把每一步可能的行动和对手回应都画成树,往前算好几步,选对自己最有利的分支。不过花见小路有隐藏信息(看不到对手的暗牌),所以需要加上概率推断,猜对手手里可能有什么牌。
需求建模和算法设计
→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么选择行动类型?选牌如何更优?如何编程实现。
- 行动类型选择:遍历所有尚未使用的行动类型(1-4,每种每轮只能用一次),对每种类型穷举所有合法的出牌组合,选择评估得分最高的方案。
-
选牌策略——Minimax 框架:
-
密约(类型1):直接评估将该牌暗置后的局面分数。倾向于密约高价值牌(如 G、F),因为这些牌对最终标记归属影响大。
-
取舍(类型2):弃掉对局面影响最小的牌,保留手中更有价值的牌用于后续行动。
-
赠予(类型3):假设对手会从 3 张牌中选走对他最有利的那张(minimax),在所有出牌组合的最坏情况中选最好的。策略上倾向于提供同类型或低价值的牌组合,降低对手选择的优势。
-
竞争(类型4):将 4 张牌拆为两组,假设对手会选对他更有利的组(minimax),在所有拆分方式的最坏情况中选最好的。策略上倾向于让两组价值尽量接近,减小对手选择带来的劣势。
- 评估函数:
- 基础分 = (我方标记总分 - 对手标记总分) × 100
- 胜利条件奖励:≥11分 → +10000,≥4枚标记 → +8000
- 手牌潜力:如果手中某种牌打出后能翻转该标记的归属,额外加分
(分数设计使用ai辅助参考)
- 编程实现:通过递归的 select_cards 函数生成所有不重复的组合,split_into_groups 生成所有不重复的分组方式,对每种方案调用 evaluate_state 评估,取最优。
代码可复用性与需求变更
→ 📖 Q3.5(P) 请说明针对该任务,你们对 🧑💻 T2 中已实现的代码进行了哪些复用和修改。
- 直接复用:
card_to_index函数、牌面字符与索引的映射逻辑在 T3 中完全复用。counts_to_string和cards_to_counts是在 T2 思路基础上新增的工具函数 - 改造复用:T2 中的 history 解析逻辑被改造为 T3 的
parse_game_state函数。核心区别是 T2 解析完整一轮记录后计算最终状态,而 T3 需要解析到当前时刻的中间状态(包含未知牌 X) - 新增内容:评估函数、组合生成、minimax 决策逻辑是 T3 全新的部分,T2 中没有对应内容
→ 📖 Q3.6(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
提高代码适应需求变更能力的核心在于"封装变化,隔离稳定"——通过策略模式、依赖注入等机制将易变逻辑(如业务规则、外部接口)抽象为可插拔组件,同时以接口契约隔离稳定领域模型;设计冗余上,保留适度的扩展点(如配置化开关、事件钩子、预留字段)而非过度泛化,确保新增需求可通过"扩展而非修改"(开闭原则)实现,避免牵一发而动全身的级联改动。
软件度量
→ 📖 Q3.7(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块决策能力很强?”,尝试提出一些可能的定量分析方式或测试方式。
可以试着通过胜率统计来验证决策能力:让程序跟随机策略、贪心策略以及其他小组的程序对战几百局,看赢多少、输多少、平多少。胜率明显高于 50% 说明比随机强,能稳定赢贪心策略说明有战术深度。
总结
→ 📖 Q3.8(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
4月6日 12:00
→ 📖 Q3.9(I) 请写下本部分的心得体会。
做 T3 最大的感受是"够用就行"和"精益求精"之间的权衡——花里胡哨的算法写起来费时,实际工程中往往不需要精益求精,只需要够用即可,后续需要提高要求时在进行优化。
结对项目总结
结对过程回顾和反思
→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。
结对过程中值得改进的方面包括:个人思考时间需要增加,长时间持续对话导致深度思考不足,交流效率需要提升,出现分歧时两人的沟通效率不高。
→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。
- 优点:
- 执行力强,在我提出一些建议时,他能快速、准确地给出反馈;
- 逻辑思维能力强,能迅速整理出解决问题的思路
- 眼光细致,能考虑到很多我注意不到的细节;
- 缺点:
- 不善于交流,整个过程中总是比较沉默和被动
对结对编程的理解
→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。
结对编程通过实时代码审查与知识交叉提升设计质量和缺陷发现效率,但需承担人力成本翻倍与认知负荷过载的代价;其本质是用即时协作换取长期质量与团队能力,适用于复杂逻辑或关键模块,而非所有场景。
代码实现提交
→ 📖 Q4.5(P) 请提供你们完成代码实现的代码仓库链接。
github链接
附录
附录 A:基于 PSP 2.1 修改的 PSP 表格
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 20 | 20 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 40 | 40 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 60 | 60 |
| - Coding Standard | - 代码规范 | 10 | 10 |
| - Design | - 具体设计(确定怎么实现) | 60 | 60 |
| - Coding | - 具体编码 | 180 | 120 |
| - Code Review | - 代码复审 | 40 | 60 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 30 | 60 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 60 | 90 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 30 | 40 |
| - Size Measurement | - 计算工作量 | 20 | 20 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 30 | 40 |
| TOTAL | 合计 | 580 | 620 |

浙公网安备 33010602011771号