
# tecs.ecs.random


Seeded generation, in named streams a snapshot carries.

```teal
tecs.ecs.random.seed(world, 20260726)

local loot <const> = tecs.ecs.random.stream(world, "game.loot")
local spawns <const> = tecs.ecs.random.stream(world, "game.spawns")
local roll <const> = loot:integer(1, 20)
```

## Streams

The world seed and stream name determine each
[`Random`](/modules/ecs/random/#tecs.ecs.random.Random) sequence. Drawing from `loot` never
advances `spawns`, so adding a stream leaves existing consumers unchanged.
Use namespaced, nonempty names and call `seed` during world setup. Calling it
later restarts every stream.

Use `newRandom` for tools, tests, and benchmarks that need a generator
outside a world. Do not share a generator between threads.

## Snapshots

The first `seed` or `stream` call installs the snapshot handler. Make that
call before loading a snapshot. A load updates existing generators in place,
so systems that captured a stream during setup retain the same object.

## Ranges

```teal
local unit <const> = loot:next() -- [0, 1)
local d20 <const> = loot:integer(20) -- [1, 20]
local offset <const> = loot:integer(-3, 3) -- [-3, 3]
local speed <const> = loot:range(2.0, 5.0) -- [2, 5)
```

`integer` includes both ends and rejects an empty range. `range` excludes its
upper end.


## Module contents

### Constructors

| Constructor | Description |
| --- | --- |
| [`newRandom`](/modules/ecs/random/#tecs.ecs.random.newRandom) | Creates a generator outside every world and snapshot. |

### Types

| Type | Kind | Description |
| --- | --- | --- |
| [`Random`](/modules/ecs/random/#tecs.ecs.random.Random) | <span class="tealdoc-kind-badge tealdoc-kind-record">record</span> | Represents a generator through four 32-bit words of xoshiro128 state and the number of draws taken from it. |

### Functions

| Function | Kind | Description |
| --- | --- | --- |
| [`seed`](/modules/ecs/random/#tecs.ecs.random.seed) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Sets the world's seed and restarts every stream in it from that seed. |
| [`stream`](/modules/ecs/random/#tecs.ecs.random.stream) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Returns the generator named name in world, creating it on the first call and returning the same object afterwards. |

## Constructors

<a id="tecs.ecs.random.newRandom"></a>
### tecs.ecs.random.newRandom <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Creates a generator outside every world and snapshot. Tools,
benchmarks, and tests use this; games usually use `stream`.

A seed is read as a 32-bit word, so 2^31 and -2^31 name the same one.



```teal
function tecs.ecs.random.newRandom(seed: integer): Random
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `seed` | `integer` | Omitted takes a fixed constant, not a clock, so an unseeded generator still repeats run to run. |

#### Returns

| Type | Description |
| --- | --- |
| [`Random`](/modules/ecs/random/#tecs.ecs.random.Random) | A generator nothing else holds and nothing else knows about: two calls on one seed give two objects that draw the same sequence, each at its own pace. |

## Types

<a id="tecs.ecs.random.Random"></a>
### tecs.ecs.random.Random <span class="tealdoc-kind-badge tealdoc-kind-record">record</span>

Represents a generator through four 32-bit words of xoshiro128** state
and the number of draws taken from it.

Not thread-safe, and not meant to be: a generator shared across threads
would produce an order that depends on which one got there first, which
is the whole thing this module exists to avoid. Give each thread a
stream of its own.


```teal
record tecs.ecs.random.Random
    integer: function(self, m: integer, n: integer): integer
    next: function(self): number
    range: function(self, lo: number, hi: number): number
    reseed: function(self, seed: integer)
    setState: function(self, words: {integer})
    shuffle: function<T>(self, list: {T}): {T}
    state: function(self): {integer}
end
```

<a id="tecs.ecs.random.Random.integer"></a>
#### tecs.ecs.random.Random:integer <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the next integer in [1, m], or in [m, n] when both are
given. It includes both ends and advances the generator.

Errors on an empty range, because a caller asking for a number
between 5 and 3 has a bug and a silent 5 hides it.



```teal
function tecs.ecs.random.Random.integer(
    self, m: integer, n: integer
): integer
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `Random` |  |
| `m` | `integer` | The upper end when it is the only argument, and the lower end when `n` follows it. The one-argument form counts from 1, so `integer(0)` is the empty range [1, 0] and raises. |
| `n` | `integer` | The upper end, included. Nil takes the one-argument form. |

##### Returns

| Type | Description |
| --- | --- |
| `integer` | An integer in the range from one draw whatever the range is. The method scales and floors instead of resampling, so a width that does not divide 2^32 has a bias of about one part in 2^32. |

<a id="tecs.ecs.random.Random.next"></a>
#### tecs.ecs.random.Random:next <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the next value and advances the generator by one round.



```teal
function tecs.ecs.random.Random.next(self): number
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `Random` |  |

##### Returns

| Type | Description |
| --- | --- |
| `number` | A multiple of 2^-32 in [0, 1). Zero is a value it takes; one is not. |

<a id="tecs.ecs.random.Random.range"></a>
#### tecs.ecs.random.Random:range <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the next value in [lo, hi) and advances the generator.



```teal
function tecs.ecs.random.Random.range(
    self, lo: number, hi: number
): number
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `Random` |  |
| `lo` | `number` | The included end, whether or not it is the smaller of the two. |
| `hi` | `number` | The excluded end. A reversed pair is not an error and is not swapped either: the draw is `lo + next() * (hi - lo)` and `next` never reaches one, so `range(7, 3)` draws from (3, 7] rather than [3, 7). |

##### Returns

| Type | Description |
| --- | --- |
| `number` | A value between the two ends, and `lo` exactly when the two are equal. |

<a id="tecs.ecs.random.Random.reseed"></a>
#### tecs.ecs.random.Random:reseed <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Restarts the sequence from `seed` in place. The generator retains
its identity, so existing holders draw from the restart.



```teal
function tecs.ecs.random.Random.reseed(self, seed: integer)
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `Random` |  |
| `seed` | `integer` | Read as a 32-bit word, as `newRandom` reads one, so 2^31 and -2^31 restart the same sequence. Zero is a seed like any other; the generator expands it instead of rejecting it. |

##### Returns

None.

<a id="tecs.ecs.random.Random.setState"></a>
#### tecs.ecs.random.Random:setState <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Puts four state words back, in place, so anything already holding
this generator draws from what was put back.



```teal
function tecs.ecs.random.Random.setState(self, words: {integer})
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `Random` |  |
| `words` | `{integer}` | Exactly four, in the order `state` gives them, and each read as a 32-bit word, so a `state` result round-trips unchanged. Any other length raises, as does nil, as does all four being zero. |

##### Returns

None.

<a id="tecs.ecs.random.Random.shuffle"></a>
#### tecs.ecs.random.Random:shuffle <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Shuffles a table in place with Fisher-Yates and returns the same
table. It advances the generator once per element past the first.



```teal
function tecs.ecs.random.Random.shuffle<T>(self, list: {T}): {T}
```

##### Type Parameters

| Name | Constraint | Description |
| --- | --- | --- |
| `T` |  |  |

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | [`Random`](/modules/ecs/random/#tecs.ecs.random.Random) | The generator advances once per element after the first. |
| `list` | `{T}` | The method reorders this list over `1..#list`. A list of one or none stays unchanged and draws nothing, so its length determines how far a shared generator advances. |

##### Returns

| Type | Description |
| --- | --- |
| `{T}` | `list` itself rather than a copy, so the caller's own reference is already shuffled and the return is a convenience. |

<a id="tecs.ecs.random.Random.state"></a>
#### tecs.ecs.random.Random:state <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the four state words as plain integers that a snapshot,
log line, or bug report can carry.



```teal
function tecs.ecs.random.Random.state(self): {integer}
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `Random` |  |

##### Returns

| Type | Description |
| --- | --- |
| `{integer}` | A fresh four-element array each call, and a copy: writing to it does not move the generator, and the generator moving does not change it. |

## Functions

<a id="tecs.ecs.random.seed"></a>
### tecs.ecs.random.seed <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Sets the world's seed and restarts every stream in it from that seed.

Call it during setup. Calling it mid-run is well defined and rewinds
everything, which is rarely what a caller means.



```teal
function tecs.ecs.random.seed(world: types.World, seed: integer)
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `world` | [`types.World`](/modules/ecs/#tecs.World) | The call reseeds each existing stream in place, so a holder keeps the object. It also installs the snapshot handler, which is why games that load snapshots call it during setup. |
| `seed` | `integer` | Read as a 32-bit word, as `newRandom` reads one. There is no way to ask a world for its seed back; take it from a snapshot instead. |

#### Returns

None.

<a id="tecs.ecs.random.stream"></a>
### tecs.ecs.random.stream <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Returns the generator named `name` in `world`, creating it on the first
call and returning the same object afterwards.

Names use dot namespaces like snapshot data keys. The engine uses
`tecs.audio` and `tecs.runif`, so game names should carry their own
prefix.



```teal
function tecs.ecs.random.stream(
    world: types.World, name: string
): Random
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `world` | [`types.World`](/modules/ecs/#tecs.World) | The first ask installs a snapshot handler named `tecs.random` on it. A world that loads a snapshot before anything has asked for a stream has no handler yet and drops the saved seed, which `random.seed` during setup avoids. |
| `name` | `string` | Nil or empty raises. The module compares names byte for byte, so two spellings of the same idea create independent streams. |

#### Returns

| Type | Description |
| --- | --- |
| [`Random`](/modules/ecs/random/#tecs.ecs.random.Random) | The world's generator for this name, not a copy: two callers asking for one name draw from the same sequence, in the order they happen to ask. |