[P]结对项目:花见小路
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 首页 - 2026年春季软件工程 - 北京航空航天大学 - 班级博客 - 博客园 |
| 这个作业的要求在哪里 | [P] 结对项目:花见小路 - 作业 - 2026年春季软件工程 - 班级博客 - 博客园 |
| 我在这个课程的目标是 | 系统掌握现代软件工程的核心概念与常用方法(需求分析、团队协作、开发流程、测试与发布等)。 |
| 这个作业在哪个具体方面帮助我实现目标 | 了解结对编程并进行实践,体会合作的思想 |
结对项目:博客问题清单
请将本文件在代码仓库外复制一份,一边阅读和完成结对项目、一边填写入代码仓库外的版本,或采取简记、语音备忘等方式记载较复杂问题的要点之后再补充。请不要将本文档内的作答提交到代码仓库。
→ 📖 Q0.0(P) 【你可以在结对结束后补充】如果你的代码仓库包含 AIGC 的部分,列举使用的工具、模型和使用范围。若未使用则填写:本组提交的全部代码不包含AI补全或生成的部分。
使用工具:cursor(Auto)
使用范围:T3
Chapter.0 wasm从安装到入门
引入
→ 📖 Q0.1(P) 请记录下目前的时间。
2026/4/6 14:47
调查
→ 📖 Q0.2(I) 【你可以在结对结束后另行补充。】作为本项目的调查:
请如实标注在开始项目之前对 Wasm 的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 没有听说过;
II. 仅限于听说过相关名词;
III. 听说过,且有一定了解;
IV. 听说过,且使用 Wasm 实际进行过开发(即便是玩具项目的开发)。
I. 没有听说过
请如实标注在开始项目之前对桌游花见小路的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)
I. 不了解玩法和规则;
II. 听说过,且有一定了解;
I. 不了解玩法和规则
总结
→ 📖 Q0.3(P) 请记录下目前的时间。
2026/4/6 14:50
Chapter.1 七色之缨
结对过程
→ 📖 Q1.1(P) 请记录下目前的时间。
2026/4/6 15:20
→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 2 | 2 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 5 | 5 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 40 | 20 |
| - Coding Standard | - 代码规范 | 3 | 3 |
| - Design | - 具体设计(确定怎么实现) | 10 | 3 |
| - Coding | - 具体编码 | 45 | 30 |
| - Code Review | - 代码复审 | 10 | 5 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 5 | 2 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 10 | 5 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 2 | 5 |
| - Size Measurement | - 计算工作量 | 5 | 4 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 10 | 15 |
| TOTAL | 合计 | 147 | 99 |
- 完成编程任务期间,依次做了什么(例如查阅了哪些资料、如何设计判定逻辑、如何设计测试样例、遇到了什么问题、如何解决)。
- 查阅 AssemblyScript/课程说明,确认
hanamikoji_judge(board, round)的输入含义(A~G 为 7 个位置的倾心状态)与输出语义(1/-1/0/2)。 - 按规则整理判定优先级:立即胜利(总分阈值或倾心数量阈值)优先于轮次;未到第三小轮则直接返回 0;第三小轮再按“总分→最高档位→平局”细分。
- 编码实现时先统计双方总分与倾心数量,再在第三小轮进入档位比较,档位比较按从高到低遍历以保证顺序正确。
- 设计测试样例覆盖每类返回值:立即胜利、前两轮返回 0、第三轮总分胜负、第三轮档位胜负、第三轮平局,并逐条对照输出结果。
设计
→ 📖 Q1.3(P) 请说明你们为这个判定模块设计了哪些中间量或辅助函数;如果没有额外设计,也请说明为什么认为直接实现已经足够清晰。
我们没有额外拆出独立的辅助函数,而是直接在 hanamikoji_judge 内部按规则顺序完成判定。原因是:该模块输入输出关系单一(倾心分布 + 轮次 → 胜负/状态),且判定分支的优先级在规则中已经固定(立即胜利→轮次→第三小轮细分),因此直接按顺序实现即可保持清晰且避免不必要的抽象。
为避免写错,我们在函数内部使用了以下中间量:
scores:A~G 对应分值表,用于把倾心分布累加成双方总分。myScore/oppScore:双方累计总分。myCount/oppCount:双方倾心标记数量,用于“至少 4 枚倾心直接胜利”的判断。tiers:第三小轮档位分值集合,并按从高到低扫描,保证档位比较顺序正确。
→ 📖 Q1.4(I) 请说明在这样一个规则判定类模块中,如何避免“漏判”“错判”或分支顺序错误等问题。
- 条件约束:立即胜利条件放在最前;只有在立即胜利不成立后才处理
round < 3的返回 0,从结构上避免因为判断顺序导致的错误。 统计结果时先一次遍历完成myScore/oppScore/myCount/oppCount的统计,再进入后续分支判断,避免分支之间读取到不一致的中间状态。 - 测试:为每个返回值都设计了对应输入用例(立即胜利、前两轮返回 0、第三轮总分胜负、第三轮档位胜负、第三轮平局),用测试保证每个分支都被覆盖到。
测试
→ 📖 Q1.5(P) 请说明你们设计了哪些测试用例,这些测试分别覆盖了哪一类规则或边界情况。
it("hanamikoji_judge", () => {
// 一方分值达到 11 分而获胜;
assert.equal(hanamikoji_judge([1, 1, 1, 1, 1, 1, 1], 1), 1);
assert.equal(hanamikoji_judge([-1, -1, -1, -1, 1, 1, 1], 1), 1);
assert.equal(hanamikoji_judge([0, 1, 1, -1, 1, -1, -1], 1), -1);
// 一方获得至少 4 枚倾心标记而获胜;
assert.equal(hanamikoji_judge([1, -1, -1, -1, -1, 1, 0], 1), -1);
assert.equal(hanamikoji_judge([1, 1, 0, -1, 1, 0, 1], 1), 1);
assert.equal(hanamikoji_judge([1, 1, 1, 1, 0, -1, -1], 3), 1);
// 前两小轮结束时尚未满足胜利条件,应返回 0;
assert.equal(hanamikoji_judge([1, 0, 1, -1, 0, -1, 0], 1), 0);
// 第三小轮结束时,总分不同,由总分高者获胜;
assert.equal(hanamikoji_judge([1, 0, 1, -1, 0, -1, 0], 3), -1);
// 第三小轮结束时,总分相同,由最高档位倾心标记判定胜负;
assert.equal(hanamikoji_judge([1, 1, 0, -1, 1, -1, 0], 3), -1);
// 第三小轮结束时平局,应返回 2。
assert.equal(hanamikoji_judge([0, 1, -1, -1, 1, 0, 0], 3), 2);
});
→ 📖 Q1.6(I) 请说明你对“先写测试再实现”与“先实现再补测试”两种方式的理解。
“先写测试再实现”:先根据需求写出一个预期失败的测试,然后编写刚好能让测试通过的最简实现,最后视需要重构。这种方式使人需要在编码前想清楚接口和边界,保证代码可以被测试,长期维护的效率更高,但是起步较慢,也不能保证测试的完全性。
“先实现再补测试”:先把功能代码写出来,等代码稳定后再回头补充测试。这种方式起步快,适合敏捷开发的场景,但容易忽略边界条件和异常场景,导致代码出现漏洞,并且随着需求增加,后续改动可能会需要大量重构。
总结
→ 📖 Q1.7(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026/4/6 16:59
→ 📖 Q1.8(I) 请写下本部分的心得体会。
T1 不难,但是理解游戏规则花了挺长时间,不过和队友玩了几回合之后感觉这个游戏还挺好玩的。第一次和别人一起结对编程,是一种新奇的体验,很有意思。
Chapter.2 不祥之影
准备
→ 📖 Q2.1(P) 请记录下目前的时间。
2026/4/6 17:00
→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 5 | 5 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 10 | 10 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 10 | 10 |
| - Coding Standard | - 代码规范 | 0 | 0 |
| - Design | - 具体设计(确定怎么实现) | 20 | 10 |
| - Coding | - 具体编码 | 55 | 50 |
| - Code Review | - 代码复审 | 15 | 10 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 10 | 10 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 20 | 38 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 5 | 5 |
| - Size Measurement | - 计算工作量 | 5 | 5 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 10 | 15 |
| TOTAL | 合计 | 165 | 168 |
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
- 我们先对照任务对“操作记录字符串”的格式约定,明确 1/2/3/4 四类行动分别应当如何影响双方“本轮已获得的牌计数”。
- 随后设计了解析流程:把
history按空格切成 token;每个 token 再按是否包含-分成“行动本体”和“选择项”。 - 针对四类行动实现解析:
1让发起者获得 1 张;2视为对局面无公开增量(保持全 0);3由对手拿走选择的 1 张、发起者拿剩余 2 张;4对手选择一组 2 张、发起者得到另一组 2 张。 - 在主函数
calc_current_state中,按 token 的奇偶位区分“谁是发起者”(第 0 个是己方),把增量累加进selfCards/oppCards。 - 最后把本轮计数与输入
board合并结算:若某角色本轮己方计数大于对手计数则置为 1,小于则置为 -1,相等则保持原值,得到newBoard。
代码可复用性与需求变更
→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑💻 T1 中已实现的代码进行了哪些复用和修改。
本任务主要复用了 T1 中对状态表示的约定,而非直接复用函数实现:
- 复用:延续倾心板
board的 7 位表示(A~G 对应 0~6;1/-1/0表示倾向你/对手/中立)。T2 的calc_current_state(history, board)直接沿用这一定义,用于在本轮结算后更新倾心状态。 - 修改/扩展:T2 新增了“本轮牌计数”的状态量(
selfCards/oppCards),并新增char_to_index、parse_action来把字符串行动转成计数增量,再基于计数生成newBoard。 - 未直接复用的原因:T1 的
hanamikoji_judge解决的是“胜负判定”,T2 解决的是“从行动序列推导轮末局面”,输入输出与职责不同,更适合共享数据结构而不是合并逻辑。
→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
- 分层与单一职责:把行为解析、中间分数计算与最终结果计算等流程拆开进行单独处理;这样当需求发生变化时,只需要改对应的模块而不需要大量修改。
- 适当保留中间结果:中间分数计算与最终结果计算分开,适当保留中间分数计算的结果。有利于后续调试,规则变更的话也有可能会用上。
- 显式状态结构:用固定长度7的数组表示计数与倾心,避免过多的局部变量;这样后续任务可以复用数据结构,后续若角色数量或分值变化,也可以直接进行修改。
头脑风暴环节
→ 📖 Q2.5(P) 头脑风暴环节:
我们终于快要开始让程序玩游戏了!请尝试分析:T2 中不带 X 的操作记录比起实际对局多出了多少信息?如果加上 X,也就是失去了这部分信息的话,如何处理对小轮结束后状态的估计?
在真实对局中,部分行动会隐藏牌面;若记录不带 X,就会把这些隐藏信息“泄露”为完全信息:
- 多出来的信息:在本应隐藏牌面的行动里(典型如 1/2 类行动中暗置/弃置的牌),不带
X的记录会直接暴露具体是 A~G 哪些牌,从而让程序在推演时知道得比真实玩家多。 - 加上
X的影响:用X代替隐藏牌后,我们无法确定这些隐藏位消耗了哪些 A~G,也就无法精确知道对手未来可能摸到/持有的牌构成。 - 如何估计:将
X视为“未知消耗”,不把它从某个具体角色计数里扣掉,而是把不确定性保留在一个“剩余牌池”里,用估计/概率来处理。T3 的做法是:computeRemainingCounts只从总数里扣除自己手牌与 history 中可见的 A~G,忽略X,得到保守的剩余计数;随后在决策时用“稀缺度”把不确定性折算进权重。
总结
→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录 A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026/4/6 19:48
→ 📖 Q2.7(I) 请写下本部分的心得体会。
做完T1之后明显感觉到T2上手更快了,而且随着任务变得更加复杂,结对编程的优势由此体现:两人一起讨论设计与实现的时候,分别有不同的思路和想法,综合得出一个比较好的方案,这能在一定程度上提升效率;同时结对编程时也可以互相查缺补漏,避免一些低级错误的产生。
Chapter.3 道途之荆
准备
→ 📖 Q3.1(P) 请记录下目前的时间。
2026/4/7 19:15
→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:
- 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | 5 | 5 |
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | 10 | 10 |
| - Technical Background | - 了解技术背景(包括学习新技术) | 5 | 5 |
| - Coding Standard | - 代码规范 | 5 | 5 |
| - Design | - 具体设计(确定怎么实现) | 60 | 120 |
| - Coding | - 具体编码 | 60 | 30 |
| - Code Review | - 代码复审 | 10 | 40 |
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | 10 | 5 |
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | 15 | 5 |
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | 5 | 5 |
| - Size Measurement | - 计算工作量 | 5 | 5 |
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | 10 | 10 |
| TOTAL | 合计 | 200 | 245 |
- 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
我们在 T3 的实现流程大致是:
- 查找关于花见小路桌游的相关论坛,阅读并学习游玩思路,并通过多次游玩对场面进行分析,尝试设计决策思路。
- 明确输入输出与约束:
hanamikoji_action(history, cards, board)在“普通行动回合”输出1/2/3/4+ 牌面字符串,在“选择回应回合”输出-+ 选择项。 - 基于 history 做回合判断:把 history 切成 token 列,用
isResponsePhase判断最后一 token 是否为未完成选择的 3/4 行动,从而决定当前是“回应”还是“主动”。 - 围绕 history 与 cards 尝试进行算牌,构建现在的场面局势,记录已知牌与未知牌,对 X 按“不可见但存在”的原则处理,避免把未知牌误当作确定信息。同时根据 history 的段数来收集自己与对手的行动记录。
- 设计启发式评价:结合角色分值、当前倾心状态与牌在对手手上的概率等设计单牌评分、牌组评分、简单局面评分。
- 实现四类行动的选择逻辑,并加入合法性约束,同时保留必要的规则化优先策略(例如特定牌型优先打法,比如同时持有3张相同3分牌使用行动3)。
- 为 3/4 行动加入小规模穷举优化,并补齐兜底分支,保证任何状态下都能返回合法形状的字符串。
- 尝试在原启发式上加入轻量模拟,用于评估候选动作在“对手下一步响应”后的平均局面价值,尽量避免局部最优而全局劣势的情况。
头脑风暴环节
→ 📖 Q3.3(P) 头脑风暴环节:
假设提供更充裕的时间和资源,这个游戏中你能找到的最优策略有可能是什么形式的?进行调研并总结分析。你还可以在任务结束后试着实现(不计分)。
在资源充足条件下,花见小路的“最优策略”更可能是基于不完全信息博弈求解的混合策略(如 CFR / Deep CFR)并配合在线信息集搜索,而不是固定规则。
但仅靠数学最优化还不完整,博弈中存在对手的选择,所以还必须考虑心理因素。
具体来说包括四个部分:
- 隐藏信息的更新:
根据 1X/2XX、3/4 的出题与选牌、行动顺序等行为信号,动态更新“对手手牌分布 + 对手意图分布”,而不是只估计牌面概率。 - 3/4 出题质量控制:
不只追求期望值最大,还要追求让对手做坏选择,或直接拿走对手选择权。 - 构建对手模型(包括心理):
不仅要算牌,还要从对手动作里读信息,在在线搜索中维护对手风格后验(例如保守/激进、抢11分优先/抢4标记优先、是否偏好高分角色等),并根据对手模型优化构造搜索空间,从而反制其心理预期。 - 目标策略的动态权衡:
在抢 11 分、抢 4 标记、第三轮比分数与最高挡位规则之间做阶段性切换:前两轮可在无法获胜的情况下退而追求平局,第3轮更重分数。
总而言之,最优策略应当在每一步同时回答两个问题:从均衡角度,这步是否安全?从心理角度,这步是否能诱导对手犯错?
需求建模和算法设计
→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么选择行动类型?选牌如何更优?如何编程实现。
我们采用“隐藏信息下的启发式评估 + 局部极大极小 + 轻量 rollout”的策略:
-
行动类型选择(实际实现):
- 先根据
history判断当前是“回应回合”还是“主动回合”(isResponsePhase)。 - 主动回合先统计我方已用行动,保证每种行动只使用一次(
getMyUsedTypes)。 - 规则优先分支:
- 若可用
3且有DDD或EEE,直接打3DDD/3EEE; - 若可用
3且存在三张同牌,优先打3xxx(G/F/D/E/A/B/C 依次判断); - 若可用
4且能构造两组相同多重集(XY|XY),优先使用。
- 若可用
- 否则在剩余可用动作里比较收益(
bestType),再输出对应动作。
- 先根据
-
选牌更优(动态权重 + 局面评分):
- 牌面权重由
evalCardForPerspective和evalCardsForPerspective计算:综合角色分值、当前倾心归属、角色优先级(G/F 更高)与剩余牌概率(CardTracker.opponentHasProb)。 - 新增了“全局局面评分”:
evaluateBoard(board):基于 CP、标记数、挡位优势(G>F>D/E>A/B/C)评估局势,并对“11 分 / 4 标记”给大权重;evaluatePosition(board, myField, oppField):用当前场面牌数近似本轮结算后标记,再调用evaluateBoard。
- 场面牌数由
buildFieldState(history)从已完成的 3/4 记录中恢复(myField/oppField)。
- 牌面权重由
-
实现方式(小范围穷举 + 对手最优假设):
- 赠送 3(
pickGiftFromCards):穷举三张组合,假设对手拿对他最有利的一张,我方拿剩下两张,取我方收益最大。 - 竞争 4(
pickCompeteFromCards):穷举四张与三种分组,假设对手选对他最有利的一组,我方拿另一组,取我方收益最大。 - 回应阶段:
- 对
3选单张最优; - 对
4选两张组最优(makeResponse)。
- 对
- 赠送 3(
-
模拟增强:
- 在行动
4的评估中加入轻量 2-ply rollout(rollout2PlyScore):- 采样对手手牌(
sampleOpponentHand), - 模拟“我方候选 4 动作 + 对手一步启发式回应”(
chooseOpponentActionOneStep), - 用
evaluatePosition回传平均分。
- 采样对手手牌(
- 这不是完整 MCTS,只是“简化搜索”,但比纯单步启发式更稳。
- 在行动
代码可复用性与需求变更
→ 📖 Q3.5(P) 请说明针对该任务,你们对 🧑💻 T2 中已实现的代码进行了哪些复用和修改。
T3 在实现中复用了 T2 的对history的处理策略的思路,并做了面向决策的扩展:
-
复用部分:
- 继续使用
A-G -> 0..6的索引映射与 7 维数组表示牌/标记状态; history仍按空格切分 token,并按 token 顺序理解时序;- 对 3/4 行动仍按“出牌 + 选择”的记录结构解析(
3...-x、4....-xx)。
- 继续使用
-
修改与扩展部分:
- 新增
isResponsePhase,区分“回应回合(输出 -)”和“主动回合(输出 1/2/3/4)”; - 新增
getMyUsedTypes,对当前是哪方行动做区分,只统计我方已使用的行动类型,保证每轮 1/2/3/4 不重复; - 在隐藏信息处理上,引入
CardTracker(维护seenCount/getRemaining/opponentHasProb),用于估计未知牌影响; - 实现 3/4 的组合穷举与“对手最优选择”假设(局部极大极小):
pickGiftFromCards、pickCompeteFromCards; - 加入若干策略优先规则(如
DDD/EEE直出 action 3、三同牌优先、可构造XY|XY时优先 action 4); - 新增
buildFieldState恢复双方当前场面牌数,并实现evaluateBoard和evaluatePosition做局面级评分; - 在竞争行动评估中加入轻量 2-ply rollout(
rollout2PlyScore),通过采样对手手牌并模拟对手一步行动,提高对高风险出牌的鲁棒性。
- 新增
→ 📖 Q3.6(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
- 分层与单一职责:划分为规则层、状态层与策略层。规则层负责动作合法性校验、解析历史行为等;状态层统一管理分数、、剩余牌估计等数据;策略层仅根据当前状态决定动作。当尝试优化策略时,只需修改策略层即可。
- 适当保留中间结果:除了最终动作,还保留部分中间结果。同样主要是为了方便调试,后续也可能会用上。
- 模块化封装:在策略层中,将局面评分、行为权重计算等部分封装封装为独立模块,统一进行调用。在优化时更加方便,也减少代码的修改量。
软件度量
→ 📖 Q3.7(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块决策能力很强?”,尝试提出一些可能的定量分析方式或测试方式。
可以从“胜率、优势、稳定性、隐藏信息鲁棒性”做定量度量:
- 对战胜率:与不同小组的胶水代码进行大量对局,统计胜率与置信区间。
- 期望优势:统计平均分差、平均倾心数量、进入第三轮最终判定的比例等。
- 稳定性:对相同输入重复运行观察动作分布;对相近局面做微扰动看行动策略的变化程度。
- 隐藏信息鲁棒性:对带
X的 history,用多种“补全 X 的可能世界”做抽样,评估同一决策的平均/最坏收益,检验是否过拟合可见信息。
目前我们只做了针对对战胜率的度量。
总结
→ 📖 Q3.8(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026/4/8 17:40
→ 📖 Q3.9(I) 请写下本部分的心得体会。
T3是整个项目最难的一个部分。对于这部分我们认为最难的部分是设计,因此花费大量的时间在设计具体出牌策略上。
编码部分我们通过将实现策略作为prompt给大模型,让其实现具体的编码工作。虽然编码部分变得很容易,但是代码复审与修正花费了比前两部分更多的时间,而且由于对具体实现不熟悉,导致两个人都变成了导航员一起看代码。优点是最后进行性能优化的时候,由于编码效率提升,我们得以尝试不同的思路,从而找出相对更优的方案。
结对项目总结
结对过程回顾和反思
→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。
-
前期共同学习与知识对齐不足
在这次结对编程中我们选择了新语言AS进行编程,两人对语言都很陌生导致“导航员”并没有很好地发挥作用,都不能发现语法错误、解决编译问题等。可以在编码前除了阅读官方文档,还可以一起跑通最小示例、改写简单程序等,保证互相熟悉环境,基线一致。 -
角色轮换与沟通节奏不清晰
在编写代码的时候两人的思维并不能完全同频,导致会出现“导航员”不知道代码写到哪个功能模块的问题。可以让“驾驶员”在编写某个具体函数、模块前,先进行两人沟通,理解一致后再进行。
→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。
很好很好,非常好的结对体验!
优点:
-
沟通顺畅,有耐心,遇到分歧能理性讨论
-
理解能力强,理解游戏规则和题目要求都很快,在我还没有看懂指导书的时候搭档已经理解了
-
思维缜密,能根据游戏规则很快提出一些想法,在后续测试的时候也能考虑到边界情况
缺点:
- 偶尔会钻牛角尖,比如在讨论游戏策略时纠结了很久
对结对编程的理解
→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。
在我看来,结对编程不仅仅是两个人一起写代码,它更加强调两个人之间的沟通、相互学习与互补,比较适合处理复杂逻辑或关键模块的开发。
优点:
结对编程时,实时有另一个人审查,能及时发现逻辑错误、边界问题或设计缺陷等问题,一定程度上提升效率;两个人能够相互学习、思维互补,可能会提出更好的设计方案;并且两人结对时有人监督和协作,也不容易走神或摸鱼。
缺点:
对两人配合的默契要求高,刚开始时需要花费时间磨合,中途也可能发生争执;以及做简单的任务时,结对编程的收益不大(比如本次作业的第一部分),反而可能浪费一些时间。
代码实现提交
→ 📖 Q4.5(P) 请提供你们完成代码实现的代码仓库链接。
https://github.com/REROSAMA/BUAASE2026-PairProgramming
附录
附录 A:基于 PSP 2.1 修改的 PSP 表格
| Personal Software Process Stages | 个人软件开发流程 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| PLANNING | 计划 | ||
| - Estimate | - 估计这个任务需要多少时间 | ||
| DEVELOPMENT | 开发 | ||
| - Analysis & Design Spec | - 需求分析 & 生成设计规格(确定要实现什么) | ||
| - Technical Background | - 了解技术背景(包括学习新技术) | ||
| - Coding Standard | - 代码规范 | ||
| - Design | - 具体设计(确定怎么实现) | ||
| - Coding | - 具体编码 | ||
| - Code Review | - 代码复审 | ||
| - Test Design | - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) | ||
| - Test Implement | - 测试实现(设计/生成具体的测试用例、编码实现测试) | ||
| REPORTING | 报告 | ||
| - Quality Report | - 质量报告(评估设计、实现、测试的有效性) | ||
| - Size Measurement | - 计算工作量 | ||
| - Postmortem & Process Improvement Plan | - 事后总结和过程改进计划(总结过程中的问题和改进点) | ||
| TOTAL | 合计 |

浙公网安备 33010602011771号