summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 23:53:40 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 23:53:40 +0800
commitcc850bf7998daa0d785facaca59f89ec2aab6225 (patch)
tree973de59fb23f76dca23a77405c744b1fc60bb0c0
parent8bc60b461c5ec90ccf2820b7a3d8b1fc74b526a1 (diff)
downloadliving-village-cc850bf7998daa0d785facaca59f89ec2aab6225.tar.gz
perf(sim): M6a 谣言窗口扫描去中间表——最新在前早停递归替代 takeWhile/filter/sort,零分配且等价
-rw-r--r--src/LivingVillage.Kernel/Sim.fs44
1 files changed, 25 insertions, 19 deletions
diff --git a/src/LivingVillage.Kernel/Sim.fs b/src/LivingVillage.Kernel/Sim.fs
index fd50fed..cedadfa 100644
--- a/src/LivingVillage.Kernel/Sim.fs
+++ b/src/LivingVillage.Kernel/Sim.fs
@@ -685,17 +685,18 @@ module Sim =
trimRumors nowTick (rumor :: rumors)
let private latestRumorFor (receiver: NpcId) (world: World) : RumorEvent option =
- // 工作集最新在前且 Tick 非递增,故只需扫描新鲜窗口;窗口外条目本就会被过滤掉。
- world.Rumors
- |> List.takeWhile (fun rumor -> world.Tick - rumor.Tick <= rumorFreshnessTicks)
- |> List.filter (fun rumor ->
- rumor.Receiver = receiver
- && rumor.Tick <= world.Tick
- && rumorStrengthAt world.Tick rumor >= rumorMinimumStrength)
- |> List.sortByDescending (fun rumor ->
- let (RumorId id) = rumor.Id
- rumor.Tick, id)
- |> List.tryHead
+ // 工作集最新在前且 Tick 非递增:第一条命中的即“Tick 最大、Id 最大”,与原实现
+ // (filter 后 sortByDescending 取头)等价;窗口外无分配提前返回。
+ let rec loop (rest: RumorEvent list) : RumorEvent option =
+ match rest with
+ | [] -> None
+ | rumor :: tail ->
+ if world.Tick - rumor.Tick > rumorFreshnessTicks then None
+ elif rumor.Receiver = receiver
+ && rumor.Tick <= world.Tick
+ && rumorStrengthAt world.Tick rumor >= rumorMinimumStrength then Some rumor
+ else loop tail
+ loop world.Rumors
/// 工作集最新在前,头节点恒为最大 Id(每次追加 `max+1`),故 O(1) 取下一个 Id。
/// 裁剪只丢尾部旧条目,不会丢头,因此该不变量在裁剪后仍成立。
@@ -826,14 +827,19 @@ module Sim =
let private rumorIsDuplicate (request: ChatRequest) (parent: RumorEvent option) (world: World) : bool =
let parentId = parent |> Option.map (fun rumor -> rumor.Id)
- world.Rumors
- |> List.takeWhile (fun rumor -> world.Tick - rumor.Tick <= rumorFreshnessTicks)
- |> List.exists (fun rumor ->
- rumor.Narrator = request.Narrator
- && rumor.Receiver = request.Receiver
- && rumor.Parent = parentId
- && rumor.Tick <= world.Tick
- && rumorStrengthAt world.Tick rumor >= rumorMinimumStrength)
+ // 窗口外条目强度必 < rumorMinimumStrength,与原全表 exists 等价;命中或越窗即无分配返回。
+ let rec loop (rest: RumorEvent list) : bool =
+ match rest with
+ | [] -> false
+ | rumor :: tail ->
+ if world.Tick - rumor.Tick > rumorFreshnessTicks then false
+ elif rumor.Narrator = request.Narrator
+ && rumor.Receiver = request.Receiver
+ && rumor.Parent = parentId
+ && rumor.Tick <= world.Tick
+ && rumorStrengthAt world.Tick rumor >= rumorMinimumStrength then true
+ else loop tail
+ loop world.Rumors
type private ChatParticipant =
| AvatarParticipant