Files
sganggs 01a44cd288 卫戍协议:盟约 web remake — initial import
Online co-op browser remake of Arknights' Stronghold Protocol: Alliance
(client-simulated combat, official waves/bonds/items/strategies, 3D board,
facing wheel, operator loadout, official emotes, deployment scripts).
2026-09-29 16:21:31 +08:00

57 lines
1.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// server/sim/rng.js — seeded PRNG (mulberry32) + helpers. The ONLY source of randomness in the sim.
/**
* Create a deterministic PRNG. Returns a function producing floats in [0, 1) with helper methods.
* @param {number} seed uint32 (any number is coerced)
*/
export function createRng(seed = 1) {
let s = (Number(seed) >>> 0) || 0x9e3779b9;
const next = () => {
s = (s + 0x6d2b79f5) >>> 0;
let t = s;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
const rng = () => next();
/** integer in [0, n) */
rng.int = (n) => Math.floor(next() * Math.max(0, n));
/** float in [a, b) */
rng.range = (a, b) => a + next() * (b - a);
/** true with probability p */
rng.chance = (p) => next() < p;
/** random element (undefined for empty) */
rng.pick = (arr) => (arr && arr.length ? arr[Math.floor(next() * arr.length)] : undefined);
/** in-place Fisher–Yates shuffle, returns arr */
rng.shuffle = (arr) => {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(next() * (i + 1));
const tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
}
return arr;
};
/** weighted pick: items with weightFn(item) */
rng.weighted = (arr, weightFn) => {
let total = 0;
for (const x of arr) total += Math.max(0, weightFn(x));
if (total <= 0) return undefined;
let r = next() * total;
for (const x of arr) { r -= Math.max(0, weightFn(x)); if (r < 0) return x; }
return arr[arr.length - 1];
};
/** current internal state (for debugging / hashing) */
rng.state = () => s;
return rng;
}
/** Derive a child seed deterministically (e.g. per field). */
export function deriveSeed(seed, salt) {
let h = (Number(seed) >>> 0) ^ 0x85ebca6b;
const str = String(salt);
for (let i = 0; i < str.length; i++) {
h = Math.imul(h ^ str.charCodeAt(i), 0x9e3779b1);
h ^= h >>> 13;
}
return h >>> 0;
}