Skip to content

Commit a40401d

Browse files
committed
Add new_instance
1 parent 7d75aff commit a40401d

File tree

4 files changed

+241
-56
lines changed

4 files changed

+241
-56
lines changed

README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ _RETURNS_
5252
* __value__ - Random element from the array.
5353

5454
### splitmix64.weightedchoice(t)
55-
Takes table `t` where keys are choices and values are weights. Returns a random key. Weights must be ≥ 0. If all weights are 0 or a weight is negative, an error is raised.
55+
Takes table `t` where keys are choices and values are weights. Returns a random key. Keys are sorted deterministically (numbers first, then strings lexicographically) before selection, so the result is reproducible for the same seed across all platforms. Weights must be ≥ 0. If all weights are 0 or a weight is negative, an error is raised.
5656

5757
_PARAMETERS_
5858
* __t__ <kbd>table</kbd> - Table of key-weight pairs.
@@ -110,6 +110,34 @@ local state = splitmix64.state()
110110
splitmix64.randomseed(state) -- restore exact state
111111
```
112112

113+
### splitmix64.new_instance([seed])
114+
Creates a new independent RNG instance. Each instance has its own internal state, completely isolated from the global module state and from other instances. This allows running multiple RNG streams in parallel without interference.
115+
116+
_PARAMETERS_
117+
* __seed__ <kbd>number</kbd> or <kbd>string</kbd> _(optional)_ — Initial seed for the instance. Defaults to 0.
118+
119+
_RETURNS_
120+
* __rng__ <kbd>table</kbd> — A table with the same set of functions as the module: `random`, `randomseed`, `state`, `randomchoice`, `weightedchoice`, `toss`, `dice`.
121+
122+
#### Example
123+
124+
```lua
125+
-- Create two independent generators
126+
local rng_enemies = splitmix64.new_instance(42)
127+
local rng_loot = splitmix64.new_instance(999)
128+
129+
-- Each has its own state — they don't affect each other or the global module
130+
print(rng_enemies.random(1, 100))
131+
print(rng_loot.random(1, 100))
132+
133+
-- The global state is unchanged
134+
print(splitmix64.random())
135+
136+
-- Save/restore instance state
137+
local saved = rng_enemies.state()
138+
rng_enemies.randomseed(saved)
139+
```
140+
113141
### Advanced Usage
114142

115143
You can also globally substitute the built-in `math.random` with `splitmix64`:

example/example.script

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
11
local TINT_GREEN = vmath.vector4(0.3, 0.9, 0.3, 1)
22
local TINT_RED = vmath.vector4(0.9, 0.3, 0.3, 1)
33
local EPSILON = 0.00001
4-
local html5 = sys.get_sys_info().system_name == "HTML5"
54

65
function init(self)
76
msg.post("@render:", "use_fixed_fit_projection", { near = -1, far = 1 })
7+
8+
splitmix64.randomseed(123456)
9+
local saved_state = splitmix64.state()
10+
11+
local rng = splitmix64.new_instance(42)
12+
assert(math.abs(rng.random() - 0.74156487877182) < EPSILON, "rng.random() mismatch")
13+
assert(rng.random(1, 100) == 92, "rng.random(1, 100) mismatch")
14+
rng.randomseed(999)
15+
assert(rng.state() == "999", "rng.state() mismatch")
16+
assert(rng.randomchoice({"a", "b", "c"}) == "b", "rng.randomchoice mismatch")
17+
assert(rng.weightedchoice({red = 1, blue = 2, green = 3}) == "red", "rng.weightedchoice mismatch")
18+
assert(rng.toss() == 0, "rng.toss() mismatch")
19+
local rolls, total = rng.dice(2, splitmix64.D6)
20+
assert(rolls[1] == 4 and rolls[2] == 3, "rng.dice rolls mismatch")
21+
assert(total == 7, "rng.dice total mismatch")
22+
23+
assert(saved_state == splitmix64.state(), "module state changed by new_instance calls")
24+
print("new_instance test passed: module state unchanged")
825
end
926

1027
local function equal_rng(actual, expected, label_url)

splitmix64/api/splitmix64.script_api

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
desc: Random element from the array.
4343
- name: weightedchoice
4444
type: function
45-
desc: Takes table t where keys are choices and values are weights. Returns a random key. Weights must be >= 0. If all weights are 0 or a weight is negative, an error is raised.
45+
desc: Takes table t where keys are choices and values are weights. Returns a random key. Keys are sorted deterministically (numbers first, then strings lexicographically) before selection, so the result is reproducible for the same seed. Weights must be >= 0. If all weights are 0 or a weight is negative, an error is raised.
4646
parameters:
4747
- name: t
4848
type: table
@@ -58,6 +58,18 @@
5858
- name: value
5959
type: number
6060
desc: Returns 0 or 1.
61+
- name: new_instance
62+
type: function
63+
desc: Creates a new RNG instance with independent state. Optional seed (number or string) for reproducibility.
64+
parameters:
65+
- name: seed
66+
optional: true
67+
type: number|string
68+
desc: Optional seed for the new instance.
69+
returns:
70+
- name: rng
71+
type: userdata
72+
desc: RNG instance with methods random, randomseed, state, randomchoice, weightedchoice, toss, dice. Same API as the module but with isolated state.
6173
- name: dice
6274
type: function
6375
desc: Roll one or more dice of the given type. Returns a table of individual rolls and the total sum.

0 commit comments

Comments
 (0)