Banjo API 1.0.0-rc.2
Low-level C99 game development API
Loading...
Searching...
No Matches
random_distribution.c
Go to the documentation of this file.
1
15
16#include <banjo/app.h>
17#include <banjo/main.h>
18#include <banjo/bitmap.h>
19#include <banjo/draw.h>
20#include <banjo/event.h>
21#include <banjo/log.h>
22#include <banjo/memory.h>
23#include <banjo/pixel.h>
24#include <banjo/random.h>
25#include <banjo/system.h>
26#include <banjo/window.h>
27
28#define FB_PIXEL_MODE BJ_PIXEL_MODE_XRGB8888
29
30#define WINDOW_W 800
31#define WINDOW_H 600
32
33#define BORDER_W 25
34#define BORDER_H 15
35
36#define GRAPH_W (WINDOW_W - BORDER_W * 2)
37#define GRAPH_H (WINDOW_H - 100)
38
39#define N_DISTRIBUTIONS 3
40
41typedef struct {
42 const char* name;
43 size_t result[GRAPH_W];
44 uint32_t color;
45 size_t min_y; /* fixed to 0 for histograms */
46 size_t max_y; /* per-distribution */
47 size_t n_steps;
49
50size_t n_steps_base = 524288;
51
54static void init_distributions(void) {
55 distributions[0].name = "uniform: %ld draws in [0;Xmax[ ; y = how many x";
56 distributions[0].color = bj_get_pixel_value(FB_PIXEL_MODE, 110, 231, 183);
57 distributions[0].min_y = 0;
58 distributions[0].max_y = 0;
59
60 distributions[1].name = "bernoulli: %ld draws with a probability p (x) ; y = how many hits";
61 distributions[1].color = bj_get_pixel_value(FB_PIXEL_MODE, 147, 197, 253);
62 distributions[1].min_y = 0;
63 distributions[1].max_y = 0;
64
65 distributions[2].name = "normal: %ld draws with Xmax/2 (mean) and 100 (deviation) ; y = how many x";
66 distributions[2].color = bj_get_pixel_value(FB_PIXEL_MODE, 196, 181, 253);
67 distributions[2].min_y = 0;
68 distributions[2].max_y = 0;
69}
70
71static void run_distributions() {
72
73 for (size_t d = 0; d < N_DISTRIBUTIONS; ++d) {
74 bj_memzero(distributions[d].result, sizeof(size_t) * GRAPH_W);
75 distributions[d].min_y = 0;
76 distributions[d].max_y = 0;
77 }
78
79 distributions[0].n_steps = n_steps_base;
80 distributions[1].n_steps = n_steps_base / 128;
81 distributions[2].n_steps = n_steps_base / 64;
82
83 // Uniform distribution: generates integers uniformly across [min, max].
84 // bj_uniform_int32_distribution(generator, gen_data, min, max)
85 // Every value in the range has equal probability. Use this for:
86 // - Random array indices, positions, rotations
87 // - Shuffling, dealing cards, rolling dice
88 for (size_t s = 0; s < distributions[0].n_steps; ++s) {
90 size_t y = ++distributions[0].result[x];
91 if (y > distributions[0].max_y) distributions[0].max_y = y;
92 }
93
94 // Bernoulli distribution: generates true/false with probability p.
95 // bj_bernoulli_distribution(generator, gen_data, p)
96 // Returns 1 with probability p, 0 with probability (1-p). Use this for:
97 // - Coin flips, critical hit chances, spawn decisions
98 // - Any yes/no outcome with a specific probability
99 // Here we vary p across x to show the linear relationship.
100 for (size_t px = 0; px < GRAPH_W; ++px) {
101 bj_real p = (bj_real)px / GRAPH_W;
102 for (size_t s = 0; s < distributions[1].n_steps; ++s) {
104 size_t y = ++distributions[1].result[px];
105 if (y > distributions[1].max_y) distributions[1].max_y = y;
106 }
107 }
108 }
109
110 // Normal (Gaussian) distribution: generates values in a bell curve.
111 // bj_normal_real_distribution(generator, gen_data, mean, std_deviation)
112 // Most values cluster near the mean, with probability decreasing away from it.
113 // Use this for:
114 // - Natural variation (damage ranges, spawn positions with clustering)
115 // - Measurement errors, particle velocities
116 // - Anything that should be "usually X but sometimes a bit more/less"
117 const bj_real mean = BJ_F(0.5) * (bj_real)(GRAPH_W - 1);
118 const bj_real sd = BJ_F(100.);
119 for (size_t s = 0; s < distributions[2].n_steps; ++s) {
121 long x = (long)bj_round(v);
122 if (x < 0 || x >= (long)GRAPH_W) continue; /* avoid OOB */
123 size_t y = ++distributions[2].result[(size_t)x];
124 if (y > distributions[2].max_y) distributions[2].max_y = y;
125 }
126}
127
128static uint32_t darken_color(uint32_t pixel, double factor, bj_bitmap* bmp) {
129 uint8_t r, g, b;
130 bj_make_pixel_rgb(bj_bitmap_mode(bmp), pixel, &r, &g, &b);
131 r = (uint8_t)(r * factor);
132 g = (uint8_t)(g * factor);
133 b = (uint8_t)(b * factor);
134 return bj_make_bitmap_pixel(bmp, r, g, b);
135}
136
137// Visualize distributions as histograms. For each distribution, the x-axis
138// represents value buckets and y-axis shows frequency (how many samples fell
139// in that bucket). Dots show raw data, smooth curves show moving averages.
140// This visualization helps understand how distributions behave statistically.
141void draw(bj_bitmap* bmp) {
142 bj_clear_bitmap(bmp);
143
144 const uint32_t color_box = bj_make_bitmap_pixel(bmp, 64, 72, 84);
145 const uint32_t white = bj_make_bitmap_pixel(bmp, 224, 230, 238);
146
147 bj_rect graph_box = (bj_rect){
148 .x = BORDER_W,
149 .y = WINDOW_H - BORDER_H - GRAPH_H,
150 .w = GRAPH_W,
151 .h = GRAPH_H
152 };
153 bj_draw_rectangle(bmp, &graph_box, color_box);
154
155 for (size_t d = 0; d < N_DISTRIBUTIONS; ++d) {
156 size_t min_y = distributions[d].min_y; /* 0 for histograms */
157 size_t max_y = distributions[d].max_y;
158 double scale = (max_y > min_y)
159 ? (double)(GRAPH_H - 1) / (double)(max_y - min_y)
160 : 0.0;
161
162 uint32_t color_curve = distributions[d].color;
163 uint32_t color_dots = darken_color(color_curve, 0.7, bmp);
164
165 /* dots */
166 for (int x = 0; x < GRAPH_W; ++x) {
167 size_t ycount = distributions[d].result[x];
168 int yscaled = (int)((ycount - min_y) * scale + 0.5);
169 if (yscaled < 0) yscaled = 0;
170 if (yscaled > GRAPH_H - 1) yscaled = GRAPH_H - 1;
171 int sx = graph_box.x + x;
172 int sy = WINDOW_H - BORDER_H - 1 - yscaled;
173 bj_put_pixel(bmp, sx, sy, color_dots);
174 }
175
176 /* moving-average curve */
177 const int W = 21;
178 int prev_set = 0, px = 0, py = 0;
179 for (int x = 0; x < GRAPH_W; ++x) {
180 int half = W / 2;
181 int xl = (x - half < 0) ? 0 : x - half;
182 int xr = (x + half >= GRAPH_W) ? GRAPH_W - 1 : x + half;
183 uint64_t sum = 0;
184 for (int i = xl; i <= xr; ++i) sum += distributions[d].result[i];
185 double avg = (double)sum / (double)(xr - xl + 1);
186 int yscaled = (int)((avg - (double)min_y) * scale + 0.5);
187 if (yscaled < 0) yscaled = 0;
188 if (yscaled > GRAPH_H - 1) yscaled = GRAPH_H - 1;
189 int sx = graph_box.x + x;
190 int sy = WINDOW_H - BORDER_H - 1 - yscaled;
191
192 if (prev_set) bj_draw_line(bmp, px, py, sx, sy, color_curve);
193 px = sx; py = sy; prev_set = 1;
194 }
195
196 /* legend */
197 int lx = BORDER_W, ly = 10 + 15 * (int)d;
199 bmp, &(bj_rect){ .x = lx, .y = ly, .w = 25, .h = 8 }, distributions[d].color);
200 bj_draw_textf(bmp, lx + 30, ly, 8, white, distributions[d].name, distributions[d].n_steps);
201 }
202 bj_draw_textf(bmp, BORDER_W, 10 + 15 * (N_DISTRIBUTIONS + 1), 8, white, "Use Left/Right arrow keys to change number of draws.");
203
204}
205
206static void on_draw(
207 struct bj_window* w,
208 struct bj_render_target* target,
209 const struct bj_rect* dirty,
210 void* user_data
211) {
212 (void)w; (void)dirty; (void)user_data;
214 // Force the dark background clear colour every draw. Setting it on
215 // the window's framebuffer is cheap and keeps roll() ignorant of
216 // the framebuffer.
218 draw(fb);
219}
220
221static void roll(void) {
224}
225
226// Interactive controls: adjust sample count to see how distributions converge.
227// With few samples, histograms are noisy. With many samples, they approach
228// the theoretical probability curves. This demonstrates the law of large numbers.
229void key_callback(bj_window* p_window, const bj_key_event* e, void* data) {
230 (void)data;
231 if (e->action != BJ_RELEASE) return;
232
233 switch (e->key) {
234 case BJ_KEY_RETURN:
235 roll(); break;
236 case BJ_KEY_LEFT:
237 if (n_steps_base > 10) { n_steps_base /= 2; roll(); }
238 break;
239 case BJ_KEY_RIGHT:
240 if (n_steps_base < 0x20000000) { n_steps_base *= 2; roll(); }
241 break;
242 case BJ_KEY_ESCAPE:
244 break;
245 default: break;
246 }
247}
248
249static void* setup(struct bj_app* app, void* init_data) {
250 (void)init_data;
251
252 if (!bj_begin(BJ_VIDEO_SYSTEM, 0)) {
253 bj_quit_app(app, 1);
254 return 0;
255 }
256
257 window = bj_bind_window("Random Distribution", 100, 100, WINDOW_W, WINDOW_H, 0, 0);
258
261
263 roll();
264 return 0;
265}
266
267static void step(struct bj_app* app, struct bj_tick_info tick, void* user_data) {
268 (void)tick;
269 (void)user_data;
272 bj_quit_app(app, 0);
273 }
274}
275
276static void teardown(struct bj_app* app, void* user_data) {
277 (void)user_data;
279 bj_end();
280}
281
282int main(int argc, char* argv[]) {
283 (void)argc; (void)argv;
284 return bj_run_app(setup, step, 0, teardown, 0);
285}
Application lifecycle: callback-driven setup, step, and teardown.
int main(int argc, char *argv[])
Definition audio_pcm.c:177
static void step(struct bj_app *app, struct bj_tick_info tick, void *user_data)
Definition audio_pcm.c:144
static void teardown(struct bj_app *app, void *user_data)
Definition audio_pcm.c:170
bj_audio_play_note_data data
Definition audio_pcm.c:104
static void * setup(struct bj_app *app, void *init_data)
Definition audio_pcm.c:107
Header file for Bitmap type.
static void on_draw(struct bj_window *w, struct bj_render_target *target, const struct bj_rect *dirty, void *user_data)
Definition bitmap_blit.c:32
#define WINDOW_W
Definition bitmap_blit.c:21
bj_window * window
Definition bitmap_blit.c:24
#define WINDOW_H
Definition bitmap_blit.c:22
Header file for Bitmap drawing functions.
void draw(bj_bitmap *bmp)
Definition drawing_2d.c:133
Sytem event management API.
void key_callback(bj_window *p_window, const bj_key_event *e, void *data)
int bj_run_app(bj_app_setup_fn setup, bj_app_step_fn step, bj_app_fixed_step_fn fixed_step, bj_app_teardown_fn teardown, void *init_data)
Drive the application lifecycle.
void bj_quit_app(struct bj_app *app, int exit_code)
Signal the given application to exit on the next iteration.
Timing snapshot handed to the step and fixed-step callbacks.
Definition app.h:106
void bj_clear_bitmap(struct bj_bitmap *bitmap)
Fills the entire bitmap with the clear colour.
uint32_t bj_make_bitmap_pixel(struct bj_bitmap *bitmap, uint8_t red, uint8_t green, uint8_t blue)
Returns an opaque value representing a pixel colour, given its RGB composition.
void bj_draw_textf(struct bj_bitmap *bitmap, int x, int y, unsigned height, uint32_t fg_native, const char *fmt,...)
Prints formatted text into a bitmap, similar to printf.
int bj_bitmap_mode(struct bj_bitmap *bitmap)
Get the pixel mode of the given bitmap.
void bj_put_pixel(struct bj_bitmap *bitmap, size_t x, size_t y, uint32_t value)
Change the pixel colour at given coordinate.
void bj_set_bitmap_color(struct bj_bitmap *bitmap, uint32_t color, uint8_t roles)
Sets one or more colour properties of a bitmap.
@ BJ_BITMAP_CLEAR_COLOR
Clear/fill colour for bj_clear_bitmap()
Definition bitmap.h:118
struct bj_render_target bj_render_target
Definition api.h:346
struct bj_bitmap bj_bitmap
Definition api.h:328
struct bj_window bj_window
Definition api.h:354
void bj_draw_rectangle(struct bj_bitmap *bitmap, const struct bj_rect *area, uint32_t pixel)
Draws a rectangle in the given bitmap.
void bj_draw_filled_rectangle(struct bj_bitmap *bitmap, const struct bj_rect *area, uint32_t pixel)
Draws a filled rectangle in the given bitmap.
void bj_draw_line(struct bj_bitmap *bitmap, int x0, int y0, int x1, int y1, uint32_t pixel)
Draws a line of pixels in the given bitmap.
enum bj_event_action action
Action (press/release/repeat)
Definition event.h:432
enum bj_key key
Key identifier.
Definition event.h:430
void bj_dispatch_events(void)
Poll and dispatch all pending events.
bj_key_callback_fn bj_set_key_callback(bj_key_callback_fn callback, void *user_data)
Set the global callback for keyboard key events.
@ BJ_KEY_ESCAPE
Esc key.
Definition event.h:176
@ BJ_KEY_LEFT
Left arrow key.
Definition event.h:186
@ BJ_KEY_RIGHT
Right arrow key.
Definition event.h:188
@ BJ_KEY_RETURN
Enter key.
Definition event.h:163
@ BJ_RELEASE
The key or button was released.
Definition event.h:391
Represent a keyboard key event.
Definition event.h:429
int16_t x
X coordinate of the top-left corner (pixels, can be negative).
Definition rect.h:34
#define bj_round
Round to nearest integer.
Definition math.h:245
#define BJ_F(x)
Literal suffix helper for bj_real when float is selected.
Definition math.h:78
float bj_real
Selected real type for float configuration.
Definition math.h:76
Axis-aligned rectangle: a top-left corner plus a width and height.
Definition rect.h:33
void bj_memzero(void *dest, size_t mem_size)
Zero out mem_size bytes at dest.
void bj_make_pixel_rgb(enum bj_pixel_mode mode, uint32_t value, uint8_t *red, uint8_t *green, uint8_t *blue)
Gets the RGB value of a pixel given its 32-bits representation.
uint32_t bj_get_pixel_value(enum bj_pixel_mode mode, uint8_t red, uint8_t green, uint8_t blue)
Returns an opaque value representing a pixel colour, given its RGB composition.
static uint32_t bj_pcg32_generator(void *state)
Adapter for distribution API (void* state).
Definition random.h:173
int32_t bj_uniform_int32_distribution(bj_random_u32_fn next, void *state, int32_t low, int32_t high)
Uniform 32-bit integer in [low, high].
int bj_bernoulli_distribution(bj_random_u32_fn next, void *state, bj_real probability)
Bernoulli(probability).
#define bj_normal_real_distribution
Alias to the real-typed normal distribution for the active precision.
Definition random.h:334
bj_bool bj_begin(int systems, struct bj_error **error)
Initialises the system.
void bj_end(void)
De-initialises the system.
@ BJ_VIDEO_SYSTEM
Definition system.h:81
void bj_set_draw_callback(struct bj_window *window, bj_window_draw_fn fn, void *user_data)
Register the redraw callback for window.
static void bj_invalidate_window(struct bj_window *window)
Mark the whole window as needing a repaint.
Definition window.h:470
void bj_set_window_should_close(struct bj_window *window)
Flag a given window to be closed.
struct bj_window * bj_bind_window(const char *title, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t flags, struct bj_error **error)
Create a new struct bj_window with the specified attributes.
struct bj_bitmap * bj_render_target_bitmap(struct bj_render_target *target)
Reach the software framebuffer behind a render target.
bj_bool bj_should_close_window(struct bj_window *window)
Get the close flag state of a window.
void bj_unbind_window(struct bj_window *window)
Deletes a struct bj_window object and releases associated memory.
Logging utility functions.
Portable main() replacement with platform-aware entry shim.
All memory-related functions, including custom allocators.
#define FB_PIXEL_MODE
Header file for general pixel manipulation facilities.
#define W
Definition pong.c:116
Pseudo-random number generation API.
distribution distributions[3]
static uint32_t darken_color(uint32_t pixel, double factor, bj_bitmap *bmp)
#define N_DISTRIBUTIONS
static void roll(void)
#define BORDER_W
#define GRAPH_W
const char * name
#define GRAPH_H
#define BORDER_H
static void run_distributions()
size_t result[(800 - 25 *2)]
size_t n_steps_base
static void init_distributions(void)
Header file for system interactions.
Header file for bj_window type.