Skip to content

Architecture

Open-Lotto Wiki edited this page Jun 5, 2026 · 1 revision

Architecture

Open-Lotto is structured as a core engine with pluggable game modules, dual GUI front-ends, and a lightweight CLI layer.


Module Map

main.c  ──▶  validate.c / config.c        (argument parsing & validation)
        ──▶  plugin_loader.c               (dlopen game plugins)
        ──▶  plugin_registry.c             (runtime game registry)
        ──▶  combogen.c                    (Fisher-Yates draw engine)
                 ├── random.c              (PCG32 RNG)
                 └── random_seed.c         (hybrid entropy seeding)
        ──▶  export.c                      (CSV / JSON file output)
        ──▶  gui_sdl.c    (--gui 2D)       (SDL2 animated 2D GUI)
        └──▶ gui_opengl.c (--gui 3D)       (OpenGL 3D drum simulator)

RNG & Seeding

Hybrid entropy seed (random_seed.c)

Each draw generates a fresh 64-bit seed by XOR-combining three independent entropy sources:

Source API Notes
Kernel entropy getrandom() CSPRNG-quality, always available on Linux
Hardware entropy RDRAND instruction Used when CPU supports it; gracefully skipped otherwise
Monotonic clock jitter clock_gettime(CLOCK_MONOTONIC) Low bits capture sub-nanosecond jitter

The combined seed is used to initialise a single PCG32 state for the draw.

PCG32 RNG (random.c)

Open-Lotto uses the PCG32 algorithm — a 64-bit LCG with output permutation. Key properties:

  • Period: 2⁶⁴
  • Statistical quality: passes BigCrush, PractRand
  • Speed: ~241 k Lotto draws/sec on a typical desktop CPU

Draw Engine (combogen.c)

The core draw uses Fisher-Yates shuffle (inside-out variant) for unbiased sampling without replacement:

  1. Fill a pool array with integers [min … max].
  2. For each pick position i from 0 to count-1:
    • Draw a uniform random integer j in [i, pool_size).
    • Swap pool[i] and pool[j].
  3. pool[0 … count-1] are the drawn numbers.

Main numbers and extra numbers are drawn from independent pools in a single call to generate_draw().

Constraints checked at runtime:

  • extra_range >= extra_count (cannot draw more numbers than exist in range)
  • main_range >= main_count
  • All counts bounded by MAX_MAIN_NUMBERS = 7 and MAX_EXTRA_NUMBERS = 3

Plugin System

Discovery & loading (plugin_loader.c)

On startup, the loader scans <binary_dir>/plugins/ for *.so files and calls dlopen() on each. It resolves three required symbols:

const LotteryInfo *plugin_get_info(void);
const char        *plugin_get_name(void);
void               plugin_draw(LotteryResult *out, draw_event_callback cb);

Plugins that fail to export all three symbols are skipped with a warning.

Registry (plugin_registry.c)

Loaded plugins are stored in a flat array. --list-games iterates the registry and prints each plugin_get_name() result. Game lookup is case-insensitive.

Bundled games

Plugin file Game name Main numbers Extra numbers
liblotto.so Lotto 6aus49 6 from 1–49 1 Superzahl from 0–9
libeurojackpot.so Eurojackpot 5 from 1–50 2 from 1–12

GUI Modes

2D SDL GUI (gui_sdl.c) — --gui 2D (default)

Renders a terminal-style animated draw using SDL2 and SDL2_ttf. Balls appear one by one with a spinner animation.

3D OpenGL GUI (gui_opengl.c) — --gui 3D

A real-time physically simulated lottery drum. See the 3D Physics Engine page for a full description.


Export (export.c)

Flag Format Example row
--export csv Comma-separated values 1,3 14 27 38 44 49,7
--export json Structured JSON {"game":"Lotto 6aus49","draws":[...]}

Use --output <filename> to specify the destination file; defaults to stdout-equivalent naming.


Validation & Configuration

validate.c

All CLI arguments are validated before any draw runs:

  • Game name must match a loaded plugin
  • Draw count must be a positive integer
  • Export format must be csv or json
  • GUI mode must be 2D or 3D
  • Conflicting options are detected and reported with hints

--validate-only exits after validation without performing a draw — useful in automation.

config.c.lottorc file

If a .lottorc file exists in the current directory, it is parsed as key=value pairs before CLI arguments are applied. CLI arguments always take precedence.


Logging (log.c)

Logging uses a macro-based API defined in include/log.h. The log level is controlled by --log-level <level> (default: warn). Available levels: debug, info, warn, error.