-
-
Notifications
You must be signed in to change notification settings - Fork 1
Architecture
Open-Lotto is structured as a core engine with pluggable game modules, dual GUI front-ends, and a lightweight CLI layer.
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)
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.
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
The core draw uses Fisher-Yates shuffle (inside-out variant) for unbiased sampling without replacement:
- Fill a pool array with integers
[min … max]. - For each pick position
ifrom 0 tocount-1:- Draw a uniform random integer
jin[i, pool_size). - Swap
pool[i]andpool[j].
- Draw a uniform random integer
-
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 = 7andMAX_EXTRA_NUMBERS = 3
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.
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.
| 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 |
Renders a terminal-style animated draw using SDL2 and SDL2_ttf. Balls appear one by one with a spinner animation.
A real-time physically simulated lottery drum. See the 3D Physics Engine page for a full description.
| 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.
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
csvorjson - GUI mode must be
2Dor3D - Conflicting options are detected and reported with hints
--validate-only exits after validation without performing a draw — useful in automation.
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 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.