diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-29 08:09:12 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-29 08:09:12 +0800 |
| commit | 247d0bc083dffc648f043176eabf9bd4036f19e7 (patch) | |
| tree | 78c11e2f923c7b9322b64dc81ccae86fc5bbceea /scripts/p66-target-report.fsx | |
| parent | cf6672ee1d6cf7013472f3bd91e68990f23750e8 (diff) | |
| download | living-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 'scripts/p66-target-report.fsx')
| -rw-r--r-- | scripts/p66-target-report.fsx | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/scripts/p66-target-report.fsx b/scripts/p66-target-report.fsx new file mode 100644 index 0000000..e360775 --- /dev/null +++ b/scripts/p66-target-report.fsx @@ -0,0 +1,87 @@ +// P66(每日任务目标具体化)证据报告:按 hash 在可达 NPC/瓦片内定点的命中数字 + 同 seed 复现断言。 +// 运行:dotnet fsi scripts/p66-target-report.fsx > docs/evidence/p66-analysis.txt +// 前置:已 dotnet build LivingVillage.sln -c Release。 +#r "../src/LivingVillage.Kernel/bin/Release/net8.0/LivingVillage.Kernel.dll" +#r "../src/LivingVillage.Desktop/bin/Release/net8.0/LivingVillage.Desktop.dll" + +open System +open LivingVillage.Kernel +open LivingVillage.Kernel.Sim +open LivingVillage.Desktop + +let seed = 42UL +let world = WorldBootstrap.initialWorldWithOccupation false seed Sim.npcCount None +let reachable = WorldBootstrap.reachableTargets world + +let npcLabel (NpcId id) = string id +let tileLabel (x, y) = sprintf "(%d,%d)" x y + +let stateAt (kind: Occupation.Kind) (day: int64) = + WorldBootstrap.occupationStateForWorld seed kind (day * Sim.ticksPerDay + 10L) world + +printfn "P66 每日任务目标具体化 — 证据报告" +printfn "seed=%d npcs=%d reachable_npcs=%d reachable_tiles=%d (%s)" + (int seed) world.Npcs.Length reachable.Npcs.Length reachable.Tiles.Length + (reachable.Tiles |> List.map tileLabel |> String.concat ",") +printfn "" + +let mutable totalTasks = 0 +let mutable npcTargeted = 0 +let mutable tileTargeted = 0 +let mutable wildcard = 0 +let mutable membershipOk = true +let mutable reproduceOk = true +let mutable concreteSamples = 0 + +for kind in Occupation.all do + let mutable hits = 0 + for day in 0L .. 59L do + let state = stateAt kind day + match state.Today with + | None -> () + | Some task -> + totalTasks <- totalTasks + 1 + let again = (stateAt kind day).Today.Value + if again <> task then reproduceOk <- false + match task.TemplateId with + | Occupation.HelpWork -> + npcTargeted <- npcTargeted + 1 + hits <- hits + 1 + match task.TargetNpc with + | Some npc when List.contains npc reachable.Npcs -> + concreteSamples <- concreteSamples + 1 + if concreteSamples <= 12 then + printfn " %-4s day=%2d HelpWork TargetNpc=%s" (Occupation.saveToken kind) day (npcLabel npc) + | _ -> membershipOk <- false + | Occupation.TillSoil -> + tileTargeted <- tileTargeted + 1 + hits <- hits + 1 + match task.TargetTile with + | Some tile when List.contains tile reachable.Tiles -> + concreteSamples <- concreteSamples + 1 + if concreteSamples <= 12 then + printfn " %-4s day=%2d TillSoil TargetTile=%s" (Occupation.saveToken kind) day (tileLabel tile) + | _ -> membershipOk <- false + | _ -> + wildcard <- wildcard + 1 + if task.TargetNpc.IsSome || task.TargetTile.IsSome then membershipOk <- false + printfn " %-8s 60 天内定点模板命中=%d" (Occupation.nameOf kind) hits + +printfn "" +printfn "统计(4 职业 × 60 天 = %d 条任务)" totalTasks +printfn " 定点 NPC(帮工) = %d" npcTargeted +printfn " 定点瓦片(翻土) = %d" tileTargeted +printfn " 保持通配(其余) = %d" wildcard +printfn " 目标 ∈ 可达集合 = %b" membershipOk +printfn " 同输入两次逐字节一致 = %b" reproduceOk +printfn "" + +// 空候选 → None(保留历史通配口径)。 +let legacyNone = + (Occupation.dailyTaskOf seed (Occupation.occupationSeedOf Occupation.Farmer) 3L Occupation.Farmer).Value +printfn "历史口径 dailyTaskOf(空候选):TargetNpc=%b TargetTile=%b(应全 false)" + legacyNone.TargetNpc.IsSome legacyNone.TargetTile.IsSome + +let verdict = if membershipOk && reproduceOk then "PASS" else "FAIL" +printfn "" +printfn "verdict: %s" verdict |
