北航敏捷软工结对项目:花见小路
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 2026年春季软件工程 (北京航空航天大学 - 计算机学院) |
| 这个作业的要求在哪里 | [P] 结对项目:花见小路 |
| 我在这个课程的目标是 | 学习融会软件工程理论,参与真实项目的开发全流程,积累软件开发的经验 |
| 这个作业在哪个具体方面帮助我实现目标 | 通过结对编程深入了解了一个团队敏捷开始的实际情况 |
结对项目:博客问题清单
请将本文件在代码仓库外复制一份,一边阅读和完成结对项目、一边填写入代码仓库外的版本,或采取简记、语音备忘等方式记载较复杂问题的要点之后再补充。请不要将本文档内的作答提交到代码仓库。
→ 📖 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) 请说明在这样一个规则判定类模块中,如何避免“漏判”“错判”或分支顺序错误等问题。
使用顺序约束与测试来降低漏判/错判/错序风险:
- 顺序约束:尽量不写并列条件判断,最好使用同一套分支,避免顺序错误。
- 调试:为不同分支增加不同的日志输出,并设计统一调试开关,便于观察分支。
- 测试:为不同分支出口设计测试样例,用测试保证分支进入的顺序正确。
测试
→ 📖 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) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
-
代码解耦,职责分离
把流程拆成“token 切分”“行动解析”“计数累加”“board 结算”四个阶段,各阶段由独立函数负责。这样规则变动(例如某一行动结算方式调整)时,只需要改对应模块,不会牵一发动全身。 -
统一表示
全程坚持 A~G 对应 0~6 的索引映射,board/selfCards/oppCards都使用同一套 7 位结构。统一数据结构能降低跨函数传递时的语义偏差,也方便后续从 T2 过渡到 T3 的策略模块复用。 -
预留扩展空间
把行动规则集中在解析层(如parse_action),把结算规则集中在newBoard生成层。未来出现新动作或新规则(如处理 X )时,只需替换局部逻辑,不必重写主流程。 -
适度冗余中间状态
保留selfCards/oppCards这类中间结果,而不是直接一步算出newBoard。虽然多了一层状态,但能显著提升调试效率(能定位到是“解析错”还是“结算错”),也更利于单元测试按阶段覆盖。
头脑风暴环节
→ 📖 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) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。
-
分层设计:规则层 / 状态层 / 策略层
- 规则层:只负责行动合法性、history 解析、场面恢复;
- 状态层:统一维护
board、myField/oppField、剩余牌估计等; - 策略层:只做“给定状态如何选动作”。
这样当需求从“启发式”升级到“搜索/MCTS”时,主要替换策略层,不破坏解析与状态逻辑。
-
独立可替换模块
将evaluateBoard、evaluatePosition、单牌/牌组权重函数单独封装,并统一由策略调用。需求变化(例如胜利条件权重、对高分角色优先级、对未知信息惩罚)时,只需调参或替换评估模块,不用改每个行动分支。 -
适度冗余保留中间状态
不只保留最终动作,还保留如myField/oppField、seenCount/remain、候选动作打分等中间量。
这些冗余能显著提升可观测性:方便定位“是 history 解析错、场面恢复错,还是策略比较错”。 -
候选生成与动作选择分离
对 3/4 行动先“生成候选集合”,再“统一评分选最优”,而不是在一个函数里硬编码所有 if-else。
这样后续新增策略(如心理诱导分组、风险控制、rollout)可以作为新的评分项叠加,不必重写动作生成逻辑。
软件度量
→ 📖 Q3.7(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块决策能力很强?”,尝试提出一些可能的定量分析方式或测试方式。
可以从“胜率、优势、稳定性、隐藏信息鲁棒性”做定量度量:
- 对战胜率:与不同小组的胶水代码进行大量对局,统计胜率与置信区间。
- 期望优势:统计平均分差、平均倾心数量、进入第三轮最终判定的比例等。
- 稳定性:对相同输入重复运行观察动作分布;对相近局面做微扰动看行动策略的变化程度。
- 隐藏信息鲁棒性:对带
X的 history,用多种“补全 X 的可能世界”做抽样,评估同一决策的平均/最坏收益,检验是否过拟合可见信息。
目前我们只做了针对对战胜率的度量。
总结
→ 📖 Q3.8(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。
2026/4/8 17:40
→ 📖 Q3.9(I) 请写下本部分的心得体会。
T3是一项偏开放的任务,在思考决策思路的时候比较困难,花了很多时间在收集信息上。同时因为编码难度上升,我们使用了AI辅助编程,但是在这个阶段,感觉结对编程就变得不伦不类,因为“驾驶员”对自己代码的熟悉程度不是很熟悉,“导航员”理清代码也很费事,结对之间的合作实际效果就比较薄弱。不过在后面考虑性能提升策略的时候,优势就很明显了,能够整合各种各样的idea进行尝试、分析,比单打独斗有效果。
结对项目总结
结对过程回顾和反思
→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。
-
前期共同学习与知识对齐不足
在这次结对编程中我们选择了新语言AS进行编程,两人对语言都很陌生导致“导航员”并没有很好地发挥作用,都不能发现语法错误、解决编译问题等。可以在编码前除了阅读官方文档,还可以一起跑通最小示例、改写简单程序等,保证互相熟悉环境,基线一致。 -
角色轮换与沟通节奏不清晰
在编写代码的时候两人的思维并不能完全同频,导致会出现“导航员”不知道代码写到哪个功能模块的问题。可以让“驾驶员”在编写某个具体函数、模块前,先进行两人沟通,理解一致后再进行。
→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。
搭档非常强,点赞👍
- 优点:
- 打字速度非常快,对工具熟练程度很高
- 思路清晰,收集信息能力很强,比如迅速想到并定位到花见小路游戏论坛
- 沟通顺畅,过程中愿意及时交流自己的想法
- 缺点:
- 推进比较快,在设计还不完善的情况下进行推进,比如T3打算先做算牌这一部分一不留神就全写完了
对结对编程的理解
→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。
- 优点:能整合两个人的灵感和思路,帮助完善设计和推进开发。
- 缺点:结对编程很吃交流,性格不合或者沟通效率低的时候,很容易发生争执,两个人找到共同空闲时间也有难度。而且对于一个比较陌生的编程环境或任务,没有达到1+1>2的预期效果。
- 理解:结对编程通过两人共同编程极致地放大模拟了团队协作场景,重点不是个人能力的突出,而是合作的效果。
代码实现提交
→ 📖 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号