Random Module
GX includes a random module for pseudo-random number generation and simplex noise. The PRNG uses xoshiro256** (high quality, deterministic), and the noise functions implement simplex noise in 1D through 4D with fractal layering.
Usage
Import individual sub-modules:
import random.random // seed, rand_int, rand_f32, rand_range, etc.
import random.noise // simplex1-4, fbm2, fbm3
Build with -I modules so the compiler finds the modules/random/gx/ directory:
gx myapp.gx -I modules -o myapp.exe
Random Numbers (random.random)
High-quality pseudo-random number generation using the xoshiro256** algorithm. Period of 2^256-1, passes all BigCrush statistical tests.
Seeding
| Function | Signature | Description |
|---|---|---|
seed | i64 → void | Seed the generator (same seed = same sequence) |
The generator starts with a default seed. Call seed() for deterministic,
reproducible results:
seed(42)
// From here, every rand call produces the same sequence every run
Integer Functions
| Function | Signature | Description |
|---|---|---|
rand_int | i32 → i32 | Random integer in [0, max) |
rand_range | (i32, i32) → i32 | Random integer in [min, max] inclusive |
rand_bool | → bool | Random true/false (50/50) |
rand_int uses rejection sampling for unbiased distribution (no modulo bias).
Float Functions
| Function | Signature | Description |
|---|---|---|
rand_f32 | → f32 | Random float in [0.0, 1.0) |
rand_f64 | → f64 | Random double in [0.0, 1.0) |
rand_f32_range | (f32, f32) → f32 | Random float in [min, max) |
Example
import random.random
fn main() {
seed(12345)
// Roll a d6
var die = rand_range(1, 6)
print("Rolled: {die}\n")
// Random color component
var r = rand_f32()
var g = rand_f32()
var b = rand_f32()
print("Color: ({r}, {g}, {b})\n")
// Random position in range
var x = rand_f32_range(-10.0, 10.0)
var y = rand_f32_range(-10.0, 10.0)
print("Position: ({x}, {y})\n")
// Coin flip
if (rand_bool()) {
print("Heads!\n")
} else {
print("Tails!\n")
}
}
Simplex Noise (random.noise)
Simplex noise is a gradient noise function that produces smooth, natural-looking random values. Unlike white noise (which is fully random per-pixel), simplex noise has spatial coherence — nearby inputs produce similar outputs, creating organic patterns useful for terrain, textures, clouds, and animation.
All simplex functions return values in approximately [-1, 1].
Core Functions
| Function | Signature | Description |
|---|---|---|
simplex1 | f32 → f32 | 1D noise (curves, wobble) |
simplex2 | (f32, f32) → f32 | 2D noise (heightmaps, textures) |
simplex3 | (f32, f32, f32) → f32 | 3D noise (volumetric, animated 2D) |
simplex4 | (f32, f32, f32, f32) → f32 | 4D noise (animated 3D) |
When to Use Each Dimension
| Dimension | Use Case |
|---|---|
| 1D | Wobble effects, procedural curves, audio-like signals |
| 2D | Terrain heightmaps, 2D texture generation, cloud patterns |
| 3D | 3D volumes (caves, fog), or animated 2D (simplex3(x, y, time)) |
| 4D | Animated 3D effects (simplex4(x, y, z, time)) |
Fractal Brownian Motion (fBm)
Single octaves of noise look too smooth for natural phenomena. fBm layers multiple octaves at increasing frequency and decreasing amplitude, producing detail at all scales — like real terrain, coastlines, or clouds.
| Function | Signature | Description |
|---|---|---|
fbm2 | (x, y, octaves, lacunarity, gain) → f32 | 2D fractal noise |
fbm3 | (x, y, z, octaves, lacunarity, gain) → f32 | 3D fractal noise |
Parameters:
| Parameter | Typical Value | Description |
|---|---|---|
octaves | 4–8 | Number of noise layers. More = more detail, more cost |
lacunarity | 2.0 | Frequency multiplier per octave (how much finer each layer) |
gain | 0.5 | Amplitude multiplier per octave (how much quieter each layer) |
Example: 2D Terrain Heightmap
import random.noise
fn main() {
// Generate a 20x10 ASCII heightmap
var y:i32 = 0
while (y < 10) {
var x:i32 = 0
while (x < 20) {
var n = simplex2(x * 0.15, y * 0.15)
if (n > 0.3) { print("#") } // mountain
else if (n > 0.0) { print("+") } // hill
else if (n > -0.3) { print(".") } // plains
else { print("~") } // water
x = x + 1
}
print("\n")
y = y + 1
}
}
Example: Animated Noise (3D as 2D + Time)
import random.noise
fn get_animated_value:f32(x: f32, y: f32, time: f32) {
// Use z dimension as time for smooth animation
return simplex3(x * 0.1, y * 0.1, time * 0.5)
}
Example: Layered Terrain with fBm
import random.noise
fn terrain_height:f32(x: f32, y: f32) {
// 6 octaves, lacunarity 2.0, gain 0.5
// Produces detail at multiple scales
var h = fbm2(x * 0.01, y * 0.01, 6, 2.0, 0.5)
// Map [-1,1] to [0, 100] for height in meters
return (h + 1.0) * 50.0
}
Controlling Scale
The noise functions have a natural frequency of about 1 unit per cycle. Scale the input coordinates to control feature size:
// Large features (continents)
var big = simplex2(x * 0.001, y * 0.001)
// Medium features (hills)
var med = simplex2(x * 0.01, y * 0.01)
// Small features (rocks)
var small_n = simplex2(x * 0.1, y * 0.1)
// Combine them manually (or just use fbm2)
var height = big * 0.6 + med * 0.3 + small_n * 0.1
Platform Notes
- All functions work identically across TCC, clang, and gcc.
- The PRNG is fully deterministic — same seed produces the same sequence on all platforms and compilers.
- Simplex noise uses no platform-specific code. The permutation table is constant, so noise values are also platform-independent.
- No
-lmneeded on Windows. On Linux, the linker may require-lmfor the math functions used by simplex noise.
Module Layout
modules/
random/
gx/
random.gx seed, rand_int, rand_range, rand_f32, rand_f64, rand_bool
noise.gx simplex1-4, fbm2, fbm3
c/
random.h xoshiro256** PRNG implementation
noise.h Simplex noise 1D-4D + fBm