summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-29 08:09:12 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-29 08:09:12 +0800
commit247d0bc083dffc648f043176eabf9bd4036f19e7 (patch)
tree78c11e2f923c7b9322b64dc81ccae86fc5bbceea /docs
parentcf6672ee1d6cf7013472f3bd91e68990f23750e8 (diff)
downloadliving-village-247d0bc083dffc648f043176eabf9bd4036f19e7.tar.gz
p66: 每日任务目标具体化 TargetNpc/TargetTile 定点
- Kernel Occupation:TaskTargets + targetNpcOf/targetTileOf + dailyTaskOfWith/ refreshTodayWith/refreshStateWith(splitmix 同源定点,候选排序消除顺序依赖,禁随机) - 仅既有 satisfiesCompletion 会读目标的模板定点:帮工→TargetNpc、翻土→TargetTile; 其余 8 模板目标保持 None(不改完成语义) - Desktop WorldBootstrap:reachableTargets(世界 NPC + 样板菜地瓦片)+ occupationStateForWorld/refreshOccupationTodayWorld;Game 开局/跨日/证据路径切换 - 历史入口 dailyTaskOf/refreshState/occupationStateFor 保留为空候选通配包装(逐字节不变) - 红先 P66TaskTargetTests(8 例):同 seed 幂等、跨 seed 落在可达集合、候选顺序无关、 历史通配回归、帮工/翻土定点门控完成、跨日重定点、v3 round-trip + v2 基线 - scripts/p66-target-report.fsx + docs/evidence/p66-analysis.txt(PASS) - Desktop 328/328,Kernel 119/119;digest 953775FA…7F6C ×3 PASS;Sim.fs 未动
Diffstat (limited to 'docs')
-rw-r--r--docs/evidence/p66-analysis.txt30
-rw-r--r--docs/evidence/p66-verification.txt57
2 files changed, 87 insertions, 0 deletions
diff --git a/docs/evidence/p66-analysis.txt b/docs/evidence/p66-analysis.txt
new file mode 100644
index 0000000..74a1c3a
--- /dev/null
+++ b/docs/evidence/p66-analysis.txt
@@ -0,0 +1,30 @@
+P66 每日任务目标具体化 — 证据报告
+seed=42 npcs=30 reachable_npcs=30 reachable_tiles=2 ((33,25),(34,25))
+
+ farmer day= 0 HelpWork TargetNpc=9
+ farmer day= 1 TillSoil TargetTile=(34,25)
+ farmer day= 2 TillSoil TargetTile=(34,25)
+ farmer day= 5 HelpWork TargetNpc=3
+ farmer day= 7 TillSoil TargetTile=(34,25)
+ farmer day= 9 TillSoil TargetTile=(33,25)
+ farmer day=10 TillSoil TargetTile=(34,25)
+ farmer day=11 HelpWork TargetNpc=10
+ farmer day=12 HelpWork TargetNpc=21
+ farmer day=15 HelpWork TargetNpc=10
+ farmer day=17 TillSoil TargetTile=(34,25)
+ farmer day=19 HelpWork TargetNpc=18
+ 农夫 60 天内定点模板命中=38
+ 渔夫 60 天内定点模板命中=0
+ 货郎 60 天内定点模板命中=0
+ 书生 60 天内定点模板命中=0
+
+统计(4 职业 × 60 天 = 240 条任务)
+ 定点 NPC(帮工) = 22
+ 定点瓦片(翻土) = 16
+ 保持通配(其余) = 202
+ 目标 ∈ 可达集合 = true
+ 同输入两次逐字节一致 = true
+
+历史口径 dailyTaskOf(空候选):TargetNpc=false TargetTile=false(应全 false)
+
+verdict: PASS
diff --git a/docs/evidence/p66-verification.txt b/docs/evidence/p66-verification.txt
new file mode 100644
index 0000000..8221027
--- /dev/null
+++ b/docs/evidence/p66-verification.txt
@@ -0,0 +1,57 @@
+P66(职业收尾切片:每日任务目标具体化 TargetNpc/TargetTile)验证记录
+基线:commit cf6672e(P66 补充限定记录)。本单未 push。
+
+范围与设计(design §2.4-3,仅此一条)
+- DailyTask 的 TargetNpc/TargetTile 从恒 None(通配)改为按 hash 在**可达集合**内定点。
+- 纯 Kernel 加函数 + Desktop 接线;禁改 Sim.fs/Sim.step(本单 `git diff -- src/LivingVillage.Kernel/Sim.fs` 为空)。
+- 可达集合由世界/样板场景派生(WorldBootstrap.reachableTargets):
+ - NPC = 世界中实际存在的村民 id(30 个开局 → 0..29)。
+ - 瓦片 = 样板场景菜地 VegetableGarden 的世界瓦片 (33,25)/(34,25)——设计口径「自家地块」,legacy/riverscape 一致。
+- 定点 = splitmix 同源的另一段流:`taskHash (seed ⊕ salt) occupationSeed dayIndex mod |候选|`,
+ 候选先排序(NPC 按 id、瓦片按 (x,y))以消除输入顺序影响;禁 System.Random。
+
+每条模板的定点影响(关键:不做超范围语义变更)
+- 帮工 HelpWork → **TargetNpc 定点**(既有 satisfiesCompletion 已读 `Some target -> target = npc`);
+ 现在玩家必须与指定村民对话才完成,非目标村民不完成(新单测断言)。
+- 翻土 TillSoil → **TargetTile 定点**(既有 `Some target -> target = (tileX,tileY)`);
+ 现在必须到达指定地块才完成(新单测断言)。
+- 其余 8 模板(送粮/夜捕/卖渔/询价/收货/转卖/观察记事/论理)的 satisfiesCompletion **不读目标**,
+ 故目标保持 None(通配),完成语义逐字节不变;不制造「有目标却不判定」的死数据。
+- 历史口径保留:`Occupation.dailyTaskOf` / `refreshToday` / `refreshState` / `WorldBootstrap.occupationStateFor`
+ / `refreshOccupationToday` 仍走空候选(目标恒 None),既有调用点/测试不受影响;
+ 定点走新增的 `dailyTaskOfWith` / `refreshTodayWith` / `refreshStateWith` /
+ `WorldBootstrap.occupationStateForWorld` / `refreshOccupationTodayWorld`(Game 真实开局与跨日刷新已切换)。
+
+改动文件
+- src/LivingVillage.Kernel/Occupation.fs(TaskTargets + targetNpcOf/targetTileOf + dailyTaskOfWith/refreshTodayWith/refreshStateWith;旧入口保留为通配包装)
+- src/LivingVillage.Desktop/WorldBootstrap.fs(reachableTargets + occupationStateForWorld/refreshOccupationTodayWorld)
+- src/LivingVillage.Desktop/Game.fs(StartNewGame、逐帧跨日刷新、P55 证据刷新、P31 剧情证据改用世界候选定点)
+- src/LivingVillage.Desktop.Tests/P66TaskTargetTests.fs(新,8 例)+ .fsproj 挂载
+- scripts/p66-target-report.fsx(新,可复跑证据生成)+ docs/evidence/p66-analysis.txt
+
+红先
+- 先建 P66TaskTargetTests.fs 引用未实现的 TaskTargets/reachableTargets/occupationStateForWorld/
+ refreshOccupationTodayWorld/dailyTaskOfWith → 暂存实现文件后编译红(FS0039/FS0041),恢复后转绿。
+
+构建/测试
+- dotnet build LivingVillage.sln -c Release → 0 错误,1 警告(P40ArtTests.fs FS0760,既有)
+- dotnet test src/LivingVillage.Desktop.Tests -c Release --no-build → 328/328(320→+8,P66TaskTargetTests)
+- dotnet test src/LivingVillage.Kernel.Tests -c Release --no-build → 119/119
+- P54ProfessionDailyTests / P55ProfessionRewardTests 全绿:二者手工构造的任务目标恒 None,
+ 定点不触碰其完成语义。
+
+证据(真实 Release 程序集,可复跑)
+- dotnet fsi scripts/p66-target-report.fsx → docs/evidence/p66-analysis.txt,verdict: PASS
+ - seed=42 / 30 NPC / 可达瓦片 (33,25),(34,25)
+ - 4 职业 × 60 天 = 240 条:帮工定点 NPC=22、翻土定点瓦片=16、其余保持通配=202
+ - 目标 ∈ 可达集合 = true;同输入两次逐字节一致 = true;历史 dailyTaskOf 目标全 None
+
+确定性 / 存档
+- dotnet run -c Release --project src/LivingVillage.Headless -- --performance-baseline ×3
+ → final_digest 全等 953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C,determinism=PASS
+- save(None) 仍 LV_WORLD_SAVE_V2 且 = saveWith None world(单测逐字节);v3(含定点目标)round-trip 稳定,
+ same-input 两次写盘文本逐字节一致。
+
+边界
+- 未改 Sim.fs/Sim.step、HUD/对话框结构、字形表、地图 seed、外部素材;未 push。
+- 未做 §2.4-5(旧档→新档迁移 UI)与目标在任务面板的中文展示(属后续独立切片;本单只落状态与判定)。