[P] 结对项目:花见小路

项目 内容
这个作业属于哪个课程 2026年春季软件工程
这个作业的要求在哪里 [P]结对项目:花见小路
我在这个课程的目标是 锻炼团队协作开发能力
这个作业在哪个具体方面帮助我实现目标 深入体会结对编程,提高了两人合作的协作开发能力

→ 📖 Q0.0(P) 【你可以在结对结束后补充】如果你的代码仓库包含 AIGC 的部分,列举使用的工具、模型和使用范围。若未使用则填写:本组提交的全部代码不包含AI补全或生成的部分。

Chapter 1 的判定模块代码(不含测试),使用 ChatGPT
Chapter 2 的实现函数代码(不含测试),使用 Gemini
Chapter 3 的行动逻辑实现函数代码,参考 Gemini;响应逻辑实现函数代码,使用 ChatGPT

Chapter.0 wasm从安装到入门

引入

→ 📖 Q0.1(P) 请记录下目前的时间。

2026/4/2 22:07

调查

→ 📖 Q0.2(I) 【你可以在结对结束后另行补充。】作为本项目的调查:

请如实标注在开始项目之前对 Wasm 的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)

I. 没有听说过;

II. 仅限于听说过相关名词;

III. 听说过,且有一定了解;

IV. 听说过,且使用 Wasm 实际进行过开发(即便是玩具项目的开发)。

I. 没有听说过

请如实标注在开始项目之前对桌游花见小路的熟悉程度分级,可以的话请细化具体的情况。(分别回答两人各自的情况)

I. 不了解玩法和规则;

II. 听说过,且有一定了解;

I. 不了解玩法和规则;

总结

→ 📖 Q0.3(P) 请记录下目前的时间。

2026/4/2 22:50

Chapter.1 七色之缨

结对过程

→ 📖 Q1.1(P) 请记录下目前的时间。

2026/4/11 9:46

→ 📖 Q1.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:

  1. 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
  2. 完成编程任务期间,依次做了什么(例如查阅了哪些资料、如何设计判定逻辑、如何设计测试样例、遇到了什么问题、如何解决)。

查阅资料

设计判定逻辑:大体设计好框架(先判定小轮直接获胜,再判定最终决胜),利用LLM生成最终代码

设计测试样例:手动编写(部分情况由LLM提供思路指导)

遇到的问题与解决

  • 代码最初编译错误,在分析之后得知wasm不支持数组作为函数形参时直接传长度,故进行了修改,修改后得以解决。

设计

→ 📖 Q1.3(P) 请说明你们为这个判定模块设计了哪些中间量或辅助函数;如果没有额外设计,也请说明为什么认为直接实现已经足够清晰。

设计的中间量:

  • my_count / op_count :统计双方分别获得多少倾心标记;
  • my_score / op_score :统计双方的分数;
  • tiers :数组,在最终判定阶段使用,把G、F、D/E、A/B/C四档列出,方便按规则从高到低比较。

辅助函数:

  • stats() :处理“统计某一方的数量和分值”这件事。

→ 📖 Q1.4(I) 请说明在这样一个规则判定类模块中,如何避免“漏判”“错判”或分支顺序错误等问题。

先写好明确的分支框架,确定骨干,再依次填充血肉。

测试

→ 📖 Q1.5(P) 请说明你们设计了哪些测试用例,这些测试分别覆盖了哪一类规则或边界情况。

针对 hanamikoji_judge() 函数设计了一组测试用例,具体如下:

  1. 分值胜利条件(≥11 分)
    当一方倾心标记总分达到或超过 11 分时判定胜负。

    • [1, 1, 1, 1, 1, 0, 0]:玩家得分 12,判定胜利
    • [-1, -1, -1, -1, -1, 0, 0]:对手得分 12,判定失败
    • [-1, -1, -1, -1, 1, 1, 1]:玩家得分 12,对手 9,判定胜利
  2. 标记数量胜利条件(≥4 枚)
    当一方获得的标记数量达到或超过 4 枚,且无人达到 11 分时判定胜负。

    • [1, 1, 1, 1, 0, 0, 0]:玩家获得 4 枚,判定胜利
    • [-1, 1, 0, 0, -1, -1, -1]:对手获得 4 枚,判定失败
  3. 前两轮平局情况
    在第 1、2 轮中,若双方均未满足胜利条件,则返回平局。

    • [1, 1, 1, 0, 0, 0, 0]
    • [-1, -1, 1, 1, 0, 1, -1]
  4. 第三轮分值比较
    第三轮结束时,若双方均未提前获胜,则按总分比较。

    • [-1, 0, 0, 0, 0, 0, 1]:玩家分值更高,判定胜利
    • [0, 0, 0, -1, 1, 1, -1]:对手分值更高,判定失败
  5. 第三轮高权重标记判定
    当总分相同时,按最高权重标记决定胜负。

    • [0, -1, 0, -1, 0, 0, 1]:双方同分,玩家拥有更高权重标记,判定胜利
    • [1, 1, 0, 0, 0, -1, 0]:对手高权重标记更优,判定失败
  6. 第三轮完全平局
    当总分及标记分布均无法区分胜负时,返回平局。

    • [0, 0, 0, 0, 0, 0, 0]
    • [1, -1, 0, 0, 0, 0, 0]
    • [-1, 1, 0, 1, -1, 0, 0]
  7. 非法输入情况
    当输入数组长度不为 7 时,应返回错误结果。

    • [1, 1, 1, 1, 1, 1]
    • [1, 1, 1, 1, 1, 1, 1, 1]

→ 📖 Q1.6(I) 请说明你对“先写测试再实现”与“先实现再补测试”两种方式的理解。

  1. 先写测试再实现,可以加深对于需求的理解,提高代码质量,减少后期修改的次数。
  2. 先实现再补测试,可以加快开发速度,但可能需要花费更多的时间来修复bug,并且测试可能质量不高。

总结

→ 📖 Q1.7(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。

2026/4/11 11:33

Personal Software Process Stages 个人软件开发流程 预估耗时(分钟) 实际耗时(分钟)
PLANNING 计划
- Estimate - 估计这个任务需要多少时间 5 4
DEVELOPMENT 开发
- Analysis & Design Spec - 需求分析 & 生成设计规格(确定要实现什么) 10 12
- Technical Background - 了解技术背景(包括学习新技术) 10 8
- Coding Standard - 代码规范 3 2
- Design - 具体设计(确定怎么实现) 15 14
- Coding - 具体编码 35 38
- Code Review - 代码复审 8 7
- Test Design - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) 8 9
- Test Implement - 测试实现(设计/生成具体的测试用例、编码实现测试) 10 9
REPORTING 报告
- Quality Report - 质量报告(评估设计、实现、测试的有效性) 2 2
- Size Measurement - 计算工作量 1 1
- Postmortem & Process Improvement Plan - 事后总结和过程改进计划(总结过程中的问题和改进点) 3 1
TOTAL 合计 110 107

→ 📖 Q1.8(I) 请写下本部分的心得体会。

第一部分中规中矩,有明确的规则,只需要根据分支优先级实现即可,印象比较深刻的是测试部分,尽量做到了全覆盖。

Chapter.2 不祥之影

准备

→ 📖 Q2.1(P) 请记录下目前的时间。

2026/4/11 11:53

→ 📖 Q2.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:

  1. 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
  2. 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);
  1. 查阅资料:课程组提供的 README 文档,主要聚焦于对四种操作的规则解释,以及回合制规则。
  2. 进行开发:首先使用 Gemini 生成初步函数框架,随后根据 README 文档的样例编写本地测试用例。
  3. 遇到问题:发现 AI 生成的内容并不能通过样例!
  4. 解决方式:
    • 首先仔细阅读规则,理解后对本地样例的期望输出进行人工推算比对,修改为正确的输出;
    • 然后逐行检查代码,初步发现“取舍操作”逻辑错误:当前逻辑为弃置的两张牌计入得分,期望逻辑为不计入得分;
    • 修改相关代码后,发现仍然不能通过测试,再次检查后发现对于回合制逻辑存在误解:当前逻辑为双方各连续行动 4 回合,期望逻辑为交替行动;
    • 修改相关代码后,通过本地测试。提交课程组测试,也顺利通过。

代码可复用性与需求变更

→ 📖 Q2.3(P) 请说明针对该任务,你们对 🧑‍💻 T1 中已实现的代码进行了哪些复用和修改。

没有进行复用或修改。

→ 📖 Q2.4(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。

  1. 模块化设计:将功能拆分为独立的模块,每个模块负责一个具体的功能。这样,当需求变更时,只需要修改相关模块,而不需要修改整个程序。
  2. 接口设计:为每个模块提供清晰的接口,使得模块之间的交互更加明确。这样,当需求变更时,只需要修改接口的实现,而不需要修改调用该接口的其他模块。
  3. 数据抽象:将数据抽象为类或结构体,使得数据的使用更加灵活。这样,当需求变更时,只需要修改数据结构,而不需要修改使用该数据结构的代码。

头脑风暴环节

→ 📖 Q2.5(P) 头脑风暴环节:

我们终于快要开始让程序玩游戏了!请尝试分析:T2 中不带 X 的操作记录比起实际对局多出了多少信息?如果加上 X,也就是失去了这部分信息的话,如何处理对小轮结束后状态的估计?

T2中不带 X 的操作比实际对局多出了:

  • 对手密约放置的牌和取舍弃置的牌
  • 初始状态下从牌库中移除的牌(因为其他所有牌都使用过了,剩下的那张牌就是这张)

加起来共4张牌,意味着加上 X 就会失去4张牌的信息。

如果这4张牌的类型均相同(例如4张G或4张F),也可以确定小轮结束后的状态;但如果这4张牌存在类型不同的牌,小轮结束后的状态就无法确定了,只能通过对已知的牌进行统计,来确定哪些种类的牌在这4张牌中可能出现。

总结

→ 📖 Q2.6(P) 请记录下目前的时间,并根据实际情况填写 附录 A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。

2026/4/11 14:21

Personal Software Process Stages 个人软件开发流程 预估耗时(分钟) 实际耗时(分钟)
PLANNING 计划
- Estimate - 估计这个任务需要多少时间 5 6
DEVELOPMENT 开发
- Analysis & Design Spec - 需求分析 & 生成设计规格(确定要实现什么) 15 18
- Technical Background - 了解技术背景(包括学习新技术) 10 20
- Coding Standard - 代码规范 3 3
- Design - 具体设计(确定怎么实现) 20 22
- Coding - 具体编码 50 48
- Code Review - 代码复审 10 9
- Test Design - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) 10 8
- Test Implement - 测试实现(设计/生成具体的测试用例、编码实现测试) 12 10
REPORTING 报告
- Quality Report - 质量报告(评估设计、实现、测试的有效性) 3 2
- Size Measurement - 计算工作量 2 1
- Postmortem & Process Improvement Plan - 事后总结和过程改进计划(总结过程中的问题和改进点) 3 1
TOTAL 合计 143 148

→ 📖 Q2.7(I) 请写下本部分的心得体会。

第二部分,难点在于规则的理解,因为相比前一部分规则更加深入了。同时还有 rust 语法的问题,起初似乎二维数组不能作为 wasm 的返回值,后来结合课程组的测试程序与搜索引擎,解决了问题。

Chapter.3 道途之荆

准备

→ 📖 Q3.1(P) 请记录下目前的时间。

2026/4/11 16:15

→ 📖 Q3.2(P) 请在完成任务的同时记录,并在完成任务后整理完善:

  1. 浏览任务要求,参照 附录A:基于 PSP 2.1 修改的 PSP 表格,估计任务预计耗时;
  2. 完成编程任务期间,依次做了什么(比如查阅了什么资料,随后如何进行了开发,遇到了什么问题,又通过什么方式解决);

难点在于策略算法的确定,我们首先查阅了花见小路的规则,随后面对面线下交流头脑风暴,最后确定策略算法,具体见下文。

头脑风暴环节

→ 📖 Q3.3(P) 头脑风暴环节:

假设提供更充裕的时间和资源,这个游戏中你能找到的最优策略有可能是什么形式的?进行调研并总结分析。你还可以在任务结束后试着实现(不计分)。

为了达成胜利有两条互斥的道路可选:

  • 分数达到 11 分
  • 获得 4 枚标记

然而游戏的牌库设计决定了分数高的更难获得,分数低的更易获得,因此这两条路线可以认为相反。

理想化最优策略应该基于当前历史记录、当前手牌、当前计分板决定选择哪条路,再决定怎么行动。

  • 历史记录可以确定牌库里还剩那些牌,以及对手当前情况
  • 当前手牌会实时影响行动,例如如果有 ABC 牌就马上 1 掉,反之更换策略
  • 当前计分板决定选择那条路达成胜利

如果真的要实现这种策略,需要考虑的因素太多,而且需要实时计算,因此很难实现,分支太多。接入 AI(如 LLM) 可以认为是一种退而求其次的方法。

需求建模和算法设计

→ 📖 Q3.4(P) 请说明针对该任务,你们采取了哪些策略来优化决策。具体而言,怎么选择行动类型?选牌如何更优?如何编程实现。

本任务中,我们实现了一个基于优先级的贪心决策系统,用于在“花见小路”游戏中进行稳定且高效的行动选择,宏观表现为尽量争取获得 4 个倾心标记以达到胜利,因此优先选择保留分数低的牌。整体策略分为两个阶段:行动类型选择策略具体选牌策略,并结合历史记录进行状态约束。

一、行动类型选择策略

1.1 行动优先级设计

我们为四种行动设定固定优先级:

2(取舍) > 4(竞争) > 1(密约) > 3(赠予)

该优先级的设计基于以下原则:

  • 2(取舍)优先级最高:用于主动清理高价值牌,避免关键牌被对手利用
  • 4(竞争)次优先:可同时控制高低价值牌分布,保底一张低价值牌收入囊中
  • 1(密约)稳定收益:收割低价值牌,以尽快达到 4 个倾心标记
  • 3(赠予)最低优先级:这个行动最不稳定,留到最后
1.2 行动次数约束处理

每一小轮中,每种行动只能执行一次,因此:

  • 通过 history 解析历史记录
  • 按我方行动轮次提取已使用行动
  • 在优先级列表中跳过已使用行动
1.3 实现方式
  • history 按空格切分为 token 序列
  • 利用 index % 2 判断是否属于己方行动
  • 提取每个 token 首字符(1~4)记录已使用行动
  • 使用 HashSet 存储已用行动类型

二、选牌策略

2.1 手牌建模

将手牌转换为字符数组,并按收益排序:

A, B, C = 低价值(2分)
D, E    = 中价值(3分)
F       = 高价值(4分)
G       = 最高价值(5分)

通过分值函数进行排序:

hand.sort_by_key(|c| card_value(c))
2.2 各行动的选牌策略

(1)行动 2:取舍

策略:丢弃最高价值的两张牌

  • 目标:减少高价值牌进入对手选择空间

  • 方法:

    选择 hand[n-1], hand[n-2]
    

(2)行动 4:竞争

策略:构造极端对比组合

将手牌分为四张:

(最高 + 最低) + (次高 + 次低)
  • 目标:

    • 强迫对手在“高+低”之间做权衡
    • 保证至少一张低价值牌进入己方区域

(3)行动 1:密约

策略:最小价值牌保底

  • 选择当前手牌中最小的一张
hand[0]

(4)行动 3:赠予

策略:最拉的行动放到最后摆烂

  • 选择最高的三张牌
  • 避免我们想要的低价值牌被拿走
hand[n-1], hand[n-2], hand[n-3]

三、响应策略

在对手执行 3 或 4 时:

3.1 对手执行 3(赠予)
  • 直接选择字典序最小的一张牌
min(opponent_cards)

目标:尽快达到 4 个标记

3.2 对手执行 4(竞争)
  • 将两组牌分别排序
  • 进行字典序比较:
    • 先比较最小牌
    • 再比较次小牌
  • 选择整体较小的一组

目标:尽量选到小价值牌,尽快达到 4 个标记

四、程序实现结构

整体实现分为两大模块:

4.1 响应模块
  • 解析对手提供牌型
  • 直接输出选择结果(-X 或 -XY)
  • 具体算法见上文
4.2 行动模块

流程如下:

1. 解析 history → 识别己方已用行动
2. 手牌排序(按价值)
3. 按优先级尝试行动:
   2 → 4 → 1 → 3
4. 对可用行动执行对应选牌策略
5. 返回 action string

代码可复用性与需求变更

→ 📖 Q3.5(P) 请说明针对该任务,你们对 🧑‍💻 T2 中已实现的代码进行了哪些复用和修改。

没有复用或修改。

→ 📖 Q3.6(I) 请说明在编码实现时,可以采取哪些设计思想、考虑哪些设计冗余,来提高既存代码适应需求变更的能力。

  1. 写好注释,便于后续维护;
  2. 明确分支,如响应和行动分为两个部分;
  3. 为方便后续迭代新增新的行动,可以设计冗余接口。

软件度量

→ 📖 Q3.7(P) 请说明你们如何量度所实现的程序模块的有效性,例如:“如何说明我们的程序模块决策能力很强?”,尝试提出一些可能的定量分析方式或测试方式。

如何说明我们的程序模块决策能力很强?

可能的测试方式:构造一个基于全随机策略(顾名思义,每回合的行动随机,每次行动使用的牌随机)指导的程序,与我们的程序进行重复比赛,若我们的程序显著由于全随机策略的程序,说明我们的程序模块决策能力很强。

总结

→ 📖 Q3.8(P) 请记录下目前的时间,并根据实际情况填写 附录A:基于 PSP 2.1 修改的 PSP 表格 的“实际耗时”栏目。

2026/4/11 18:56

Personal Software Process Stages 个人软件开发流程 预估耗时(分钟) 实际耗时(分钟)
PLANNING 计划
- Estimate - 估计这个任务需要多少时间 5 5
DEVELOPMENT 开发
- Analysis & Design Spec - 需求分析 & 生成设计规格(确定要实现什么) 20 16
- Technical Background - 了解技术背景(包括学习新技术) 15 12
- Coding Standard - 代码规范 3 2
- Design - 具体设计(确定怎么实现) 25 24
- Coding - 具体编码 55 65
- Code Review - 代码复审 10 11
- Test Design - 测试设计(确定怎么测,比如要测试哪些情景、设计哪些种类的测试用例) 10 9
- Test Implement - 测试实现(设计/生成具体的测试用例、编码实现测试) 12 13
REPORTING 报告
- Quality Report - 质量报告(评估设计、实现、测试的有效性) 3 2
- Size Measurement - 计算工作量 2 1
- Postmortem & Process Improvement Plan - 事后总结和过程改进计划(总结过程中的问题和改进点) 2 1
TOTAL 合计 163 161

→ 📖 Q3.9(I) 请写下本部分的心得体会。

第三部分可发挥地方很多,是最有意思的部分。我和队友首先讨论了什么策略能最快实现,想到了一种“傻瓜策略”,即每次决策都选第一个,后续分析发现这个策略可以认为是随机策略。

后来我们进行深入思考,加入让我们自己来玩这个游戏,我会用什么策略。发现人脑比代码能表示的算法复杂得多,针对许多的状态能有不同的策略,这要实现起来太难了。因此我们进行了抽象,抓大放小,总结了一套贪心策略,原则为优先选择保留分数低的牌,并进一步基于这个原则对每种分支进行推演。最终在代码中实现了。自己打自己发现全是平局(为什么)。

结对项目总结

结对过程回顾和反思

→ 📖 Q4.1(P) 提供两人在讨论的结对图像资料。

8b985277e485a0d45633f318f379b111

→ 📖 Q4.2(P) 回顾结对的过程,反思有哪些可以提升和改进的地方。

  1. 双方没有统一代码风格,导致代码可读性较差,后续维护困难;
  2. 沟通不畅,导致部分代码重复编写,效率低下;
  3. 分工不明确,导致部分任务进度缓慢。

→ 📖 Q4.3(I) 锐评一下你的搭档!并请至少列出三个优点和一个缺点。

优点:

  1. 规则理解透彻,思路清晰;
  2. 编程能力强,代码质量高;
  3. 沟通能力强,能够有效协调工作。

缺点:过于依赖 AI。

对结对编程的理解

→ 📖 Q4.4(I) 说明结对编程的优缺点、你对结对编程的理解。

优点:提高编程效率,提高编程乐趣,方便快速头脑风暴。
缺点:容易产生代码风格冲突,分工不明确,容易两个和尚没水喝。

我的理解:结对编程是一种高效、有趣的编程方式,可以促进团队成员之间的交流与合作,提高编程效率。两个人最好遵循一个人导航,一个人实现的原则,这样不容易产生冲突;但在必要的时候也要切换任务中心,扬长避短;在面临困难决策时,可以互相讨论,共同决策,激发灵感。现代编程中,AI 逐渐成为我们的编程助手,感觉也算一种结对编程。

代码实现提交

→ 📖 Q4.5(P) 请提供你们完成代码实现的代码仓库链接。

https://github.com/Wh04m1777/SoftwarePairProject

posted @ 2026-04-11 19:47  BaconToast  阅读(12)  评论(0)    收藏  举报