> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/all-out-docs/docs-es/programacion/random-math-and-more.md).

# Aleatorio, matemáticas y más

Esta página es una miscelánea de utilidades de “las usarás constantemente”: RNG, formato, tiempo y algunos subsistemas básicos que aparecen en la mayoría de los juegos.

{% hint style="info" %}
Si buscas arreglos/slices, consulta [Arrays y colecciones](/all-out-docs/docs-es/programacion/arrays-and-collections.md).
{% endhint %}

## Números aleatorios (RNG)

Random usa una `u64` semilla explícita. Pasa la semilla por `ref` para que se actualice.

```go
rng: u64 = rng_root_seed();
// o determinista por entidad:
// rng: u64 = rng_seed(entity.id);

// Los valores del rango son inclusivos
roll := rng_range_int(ref rng, 1, 10);
chance := rng_range_float(ref rng, 0, 1);

// Puntos aleatorios y barajado
offset := rng_disk(ref rng, 0.5, 2.0);
spawn_points: [..]v2;
spawn_points.append({0, 0});
spawn_points.append({4, 0});
rng_shuffle(ref rng, spawn_points);

// Mezcla un valor en una semilla sin extraer un número aleatorio.
rng_mix(ref rng, entity.id);
independent_seed := mix_u64(rng, 123); // devuelve la semilla mezclada; rng no cambia
```

{% hint style="warning" %}
La aleatoriedad del gameplay debe ejecutarse en la ruta compartida de gameplay predicha. Empieza con `rng_root_seed()` u otra semilla estable; no siembres el gameplay con datos solo locales.
{% endhint %}

`mix_u64(a: u64, b: u64) -> u64` y `rng_mix(rng: ref u64, value: u64)` son intrínsecos con el mismo algoritmo de mezcla determinista. `rng_mix` guarda el resultado mezclado de vuelta en `rng`; el orden de las mezclas repetidas importa.

## Funciones matemáticas

Estas funciones se declaran en `core:basic`, que `core:ao` también importa. En las tablas, `F` significa `f32` y `f64` sobrecargas separadas; `float` es `f32`y `int` es `s64`. Los argumentos de una sobrecarga usan el mismo tipo. `T` denota un tipo numérico genérico, y `V` denota `v2`, `v3`y `v4` sobrecargas separadas.

### Referencia de matemáticas escalares

| Firma de la función                                                            | Comportamiento                                                                                                                                          |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ceil(x: F) -> F`                                                              | El menor valor entero mayor o igual que `x`: `ceil(1.25)` es `2.0`, `ceil(-1.25)` es `-1.0`.                                                            |
| `floor(x: F) -> F`                                                             | El mayor valor entero menor o igual que `x`: `floor(1.25)` es `1.0`, `floor(-1.25)` es `-2.0`.                                                          |
| `round(x: F) -> F`                                                             | El valor entero más cercano, con los casos a mitad de camino alejándose de cero: `round(2.5)` es `3.0`, `round(-2.5)` es `-3.0`.                        |
| `sin(v: F) -> F`                                                               | Seno de un ángulo en radianes.                                                                                                                          |
| `cos(v: F) -> F`                                                               | Coseno de un ángulo en radianes.                                                                                                                        |
| `atan2(y: F, x: F) -> F`                                                       | Ángulo en radianes a partir de una `(x, y)` dirección. Pasa **y primero**.                                                                              |
| `to_degrees(radians: F) -> F`                                                  | Convierte radianes a grados, conservando la precisión.                                                                                                  |
| `to_radians(degrees: F) -> F`                                                  | Convierte grados a radianes, conservando la precisión.                                                                                                  |
| `pow(b: F, e: F) -> F`                                                         | Eleva la base `b` al exponente `e`.                                                                                                                     |
| `sqrt(x: F) -> F`                                                              | Raíz cuadrada.                                                                                                                                          |
| `Math.exp(v: F) -> F`                                                          | Exponencial natural, e elevado a `v`.                                                                                                                   |
| `Math.log(v: F) -> F`                                                          | Logaritmo natural. La función global `log` es un alias de registro.                                                                                     |
| `abs(a: T) -> T`                                                               | Valor absoluto.                                                                                                                                         |
| `sign(v: T) -> T`                                                              | `-1` para valores negativos; `1` para cero y valores positivos.                                                                                         |
| `min(a: F, b: F) -> F`; `min(a: int, b: int) -> int`                           | El menor de dos valores.                                                                                                                                |
| `max(a: F, b: F) -> F`; `max(a: int, b: int) -> int`                           | El mayor de dos valores.                                                                                                                                |
| `clamp(a: F, min: F, max: F) -> F`; `clamp(a: int, min: int, max: int) -> int` | Restringe un valor a límites inclusivos, comprobando primero el límite inferior.                                                                        |
| `lerp(a: F, b: F, t: F) -> F`                                                  | Interpolación lineal; `t` no se limita.                                                                                                                 |
| `linear_step(start: float, end: float, time: float) -> float`                  | Normaliza `time` al intervalo y lo limita a `[0, 1]`; devuelve `1` si los extremos son iguales.                                                         |
| `next_power_of_two(n: s64) -> s64`                                             | La menor potencia de dos al menos `n`; devuelve `0` para entradas no positivas. Las entradas superiores a `2^62` desbordan al valor mínimo `s64` valor. |

`PI` también está disponible como constante.

Los ayudantes escalares y `dot` se ejecutan como instrucciones matemáticas de la VM. Vector `lerp` se traduce directamente a instrucciones aritméticas vectoriales. No requieren llamadas externas. Los ayudantes compuestos `in_range` y `normalize_vector_to_radius` siguen siendo código CSL construido a partir de estos primitivos.

Punto flotante `min` y `max` devuelven el segundo argumento cuando los valores comparan igual o cualquiera de ellos es NaN. `clamp` conserva una entrada NaN. `abs` conserva el cero con signo y NaN; entero `abs` conserva el valor mínimo con signo en caso de desbordamiento. Estos son los mismos comportamientos que los ayudantes CSL originales.

### Redondeo

`ceil`, `floor`y `round` devuelven un valor de punto flotante con la precisión de entrada. Los enteros exactos, los infinitos y el cero con signo no cambian; NaN produce NaN. Redondear hacia arriba significa hacia el infinito positivo, por lo que `ceil(-1.25)` es `-1.0`. `round` usa redondeo de mitad alejándose de cero, en lugar de empate al par.

```go
slots := ceil(2.25).(int);       // 3
cell := floor(-2.25).(int);      // -3
nearest := round(-2.5).(int);    // -3
truncated := (-2.25).(int);      // -2: los casts truncan hacia cero
precise: f64 = 1.0000000000000002;
rounded := ceil(precise);        // 2.0, sigue siendo f64
```

Convierte el resultado a `int` cuando sea finito y quepa en `int`. No existe `trunc` función. Para el formateo de visualización decimal, usa `format_float(value, decimals=2)`; no cambia el valor numérico.

### Referencia de matemáticas vectoriales

| Firma de la función               | Comportamiento                                                  |
| --------------------------------- | --------------------------------------------------------------- |
| `length(v: V) -> float`           | Longitud del vector.                                            |
| `length_squared(v: V) -> float`   | Longitud al cuadrado, evitando una raíz cuadrada.               |
| `normalize(v: V) -> V`            | Normaliza un vector.                                            |
| `dot(a: V, b: V) -> float`        | Producto punto.                                                 |
| `lerp(a: V, b: V, t: float) -> V` | Interpolación lineal componente a componente; `t` no se limita. |

### Ejemplos

```go
angle_sin := sin(x);
angle_cos := cos(x);
angle := atan2(dir.y, dir.x);
degrees := to_degrees(angle);
radians := to_radians(degrees);

result := pow(2.0, 3.0);   // 8.0
root := sqrt(16.0);        // 4.0

value := lerp(0.0, 100.0, 0.5);  // 50.0
clamped := clamp(value, 0.0, 10.0);
stepped := linear_step(0.0, 1.0, value);

absolute := abs(-5);
minimum := min(5, 10);
maximum := max(5, 10);
direction_sign := sign(-12);

len := length(v);
len_sq := length_squared(v);
normalized := normalize(v);
facing := dot(normalized, {1, 0});
```

## Formateo de cadenas

Usa `%` marcadores de posición con un arreglo de argumentos:

```go
format_string("Value: %", {42});
format_string("health: 100%");
```

Si necesitas un argumento junto a un signo de porcentaje (o junto a otro argumento), usa `%0` como alias de `%`:

```go
hp := 67;
format_string("health: %0%%", {hp}); // "health: 67%"
```

Para redondear decimales, usa `format_float`:

```go
value := 3.14159;
format_string("pi: %", {format_float(value, decimals=2)}); // "pi: 3.14"
```

Ayudantes comunes de cadenas:

```go
clean := string_trim("  hello  ");
parts := string_split("a,b,c", ",");
name_lower := to_lower(player.get_username());
name_upper := to_upper("ready");
short := string_substring("abcdef", 1, 3); // "bcd"
```

## Registro

El registro sigue las mismas reglas de formato:

```go
log_info("Name: %, age: %", {player.get_username(), 12});
```

## Tiempo

```go
current_time := get_time();       // segundos flotantes desde el inicio del juego
frame := get_frame_number();      // número actual de fotograma
now_ns := get_nanoseconds_since_epoch();
utc := get_utc_datetime();
```

## SFX

```go
sound := get_asset(SFX_Asset, "sfx/click.wav");

desc := SFX.default_sfx_desc();
desc.entity_to_follow = entity.id;
desc.delay = 0.25;

sound_id := SFX.play(sound, desc);
SFX.stop(sound_id);
```

{% hint style="warning" %}
Llama a los sonidos de gameplay desde la ruta compartida de gameplay. El motor reconcilia la reproducción predicha. Para un sonido que solo un jugador debe oír, establece `desc.specific_to_player = player`; no envuelvas `SFX.play` en `is_local()`.
{% endhint %}

## Inicio rápido de Economy (monedas)

Las monedas de Economy son **por jugador** y **persistidas automáticamente**.

```go
ao_before_scene_load :: proc() {
    coin_icon := get_asset(Texture_Asset, "ui/coin.png");
    Economy.register_currency("Coins", coin_icon);
}

Economy.deposit_currency(player, "Coins", 10);
coins := Economy.get_balance(player, "Coins");

COST :: 50;
if Economy.can_withdraw_currency(player, "Coins", COST) {
    Economy.withdraw_currency(player, "Coins", COST);
}
```

Los importes de depósito y retiro deben ser no negativos.

Ver [Economy](/all-out-docs/docs-es/datos-y-persistencia/economy.md) para la guía completa.
