diff options
Diffstat (limited to 'scripts')
| -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 |
