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

FunctionSignatureDescription
seedi64 → voidSeed 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

FunctionSignatureDescription
rand_inti32 → i32Random integer in [0, max)
rand_range(i32, i32) → i32Random integer in [min, max] inclusive
rand_bool→ boolRandom true/false (50/50)

rand_int uses rejection sampling for unbiased distribution (no modulo bias).

Float Functions

FunctionSignatureDescription
rand_f32→ f32Random float in [0.0, 1.0)
rand_f64→ f64Random double in [0.0, 1.0)
rand_f32_range(f32, f32) → f32Random 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

FunctionSignatureDescription
simplex1f32 → f321D noise (curves, wobble)
simplex2(f32, f32) → f322D noise (heightmaps, textures)
simplex3(f32, f32, f32) → f323D noise (volumetric, animated 2D)
simplex4(f32, f32, f32, f32) → f324D noise (animated 3D)

When to Use Each Dimension

DimensionUse Case
1DWobble effects, procedural curves, audio-like signals
2DTerrain heightmaps, 2D texture generation, cloud patterns
3D3D volumes (caves, fog), or animated 2D (simplex3(x, y, time))
4DAnimated 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.

FunctionSignatureDescription
fbm2(x, y, octaves, lacunarity, gain) → f322D fractal noise
fbm3(x, y, z, octaves, lacunarity, gain) → f323D fractal noise

Parameters:

ParameterTypical ValueDescription
octaves4–8Number of noise layers. More = more detail, more cost
lacunarity2.0Frequency multiplier per octave (how much finer each layer)
gain0.5Amplitude 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 -lm needed on Windows. On Linux, the linker may require -lm for 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