SimulationDice: fmix32 moves out of FireControl, with the structured per-zone dice stream
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3035230bf9
commit
9116946874
3 changed files with 48 additions and 18 deletions
|
|
@ -667,22 +667,6 @@ public static class FireControl
|
|||
// so whether a gated shot draws is unobservable from anywhere. The claim this comment used to make is
|
||||
// gone with the stream it was about, and the test that asserted it became vacuous the same moment; what
|
||||
// replaced it pins the live rule instead (combat touches no shared stream, on any path).
|
||||
// 9.1 (docs/fire-control-cut.md): fmix32, MurmurHash3's 32-bit finalizer -- xor-shift, multiply,
|
||||
// xor-shift, multiply, xor-shift. Diffuses a structured seed (here, a zone seed XORed with a small,
|
||||
// low-bits-only ShotId) across every bit before the first xorshift draw reads it, so two seeds that
|
||||
// differ only in ShotId's low bits still land on uncorrelated first outputs. Caller-side mixing only
|
||||
// -- CultMath.Random itself is unchanged (see Commit's own note on why that follow-up is a separate
|
||||
// CultLib cut).
|
||||
private static uint MixSeed(uint seed)
|
||||
{
|
||||
seed ^= seed >> 16;
|
||||
seed *= 0x85ebca6bu;
|
||||
seed ^= seed >> 13;
|
||||
seed *= 0xc2b2ae35u;
|
||||
seed ^= seed >> 16;
|
||||
return seed;
|
||||
}
|
||||
|
||||
// Cut 12.2 (docs/fire-control-cut.md, "Bearing timing"): steps 1-5. Everything the shooter decided is
|
||||
// frozen in `shot` (R10); everything the target is doing -- position (deviation) and now also facing
|
||||
// (bearing) -- is read live, here, at the commit tick. The Cut 7 guard extends to cover the new factors:
|
||||
|
|
@ -722,11 +706,11 @@ public static class FireControl
|
|||
// round for NextFloat's first call, and one round does not diffuse a seed that differs from its
|
||||
// neighbours only in ShotId's low bits. Unmixed, every zone's first draw was a near-constant
|
||||
// function of ShotId (measured span ~0.125), making a shot a step function of p fixed at zone
|
||||
// creation, not a roll (Soul C1). MixSeed is a standard fmix32 finalizer (MurmurHash3): this is
|
||||
// creation, not a roll (Soul C1). SimulationDice.Mix is a standard fmix32 finalizer (MurmurHash3): this is
|
||||
// a caller's obligation, not a CultMath defect -- seeding xorshift with a structured value and
|
||||
// drawing once is the documented way to get a correlated first output, and a follow-up to give
|
||||
// CultMath.Random a mixed-seed entry point of its own is recorded for a separate CultLib cut.
|
||||
var random = new Random(MixSeed((zone.CombatSeed * 2654435761u) ^ (uint) shot.ShotId | 1u));
|
||||
var random = new Random(SimulationDice.Mix((zone.CombatSeed * 2654435761u) ^ (uint) shot.ShotId | 1u));
|
||||
var p = CommitProbability(shot, now, out var sil);
|
||||
|
||||
var hit = p > 0f && random.NextFloat() < p;
|
||||
|
|
|
|||
35
Assets/Scripts/ServerShared/SimulationDice.cs
Normal file
35
Assets/Scripts/ServerShared/SimulationDice.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
using Random = CultMath.Random;
|
||||
|
||||
// Structured simulation seeds: the one place a zone seed, a stream and an ordinal become a generator. Every
|
||||
// draw is a pure function of its arguments, never of a shared stream, so one roll cannot perturb another.
|
||||
public static class SimulationDice
|
||||
{
|
||||
public const uint LootStream = 1;
|
||||
public const uint MineStream = 2;
|
||||
|
||||
// 9.1 (docs/fire-control-cut.md): fmix32, MurmurHash3's 32-bit finalizer -- xor-shift, multiply,
|
||||
// xor-shift, multiply, xor-shift. Diffuses a structured seed (a zone seed XORed with a small,
|
||||
// low-bits-only id) across every bit before the first xorshift draw reads it, so two seeds that differ
|
||||
// only in their low bits still land on uncorrelated first outputs. Caller-side mixing only --
|
||||
// CultMath.Random itself is unchanged. FireControl.Commit's per-shot seed is built on this verbatim.
|
||||
public static uint Mix(uint seed)
|
||||
{
|
||||
seed ^= seed >> 16;
|
||||
seed *= 0x85ebca6bu;
|
||||
seed ^= seed >> 13;
|
||||
seed *= 0xc2b2ae35u;
|
||||
seed ^= seed >> 16;
|
||||
return seed;
|
||||
}
|
||||
|
||||
// The generator for the `ordinal`th roll of `stream` in the zone identified by `zoneSeed`.
|
||||
public static Random For(uint zoneSeed, uint stream, uint ordinal)
|
||||
{
|
||||
var seed = Mix(Mix(zoneSeed ^ Mix(stream)) ^ ordinal);
|
||||
return new Random(seed == 0 ? 1u : seed);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/ServerShared/SimulationDice.cs.meta
Normal file
11
Assets/Scripts/ServerShared/SimulationDice.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: da428be21afa46a991b55ab9b794d192
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in a new issue