blob: e360775684058c48c84afaa2ed393fa693642598 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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
|