Real-time step-by-step visualizer for sorting algorithms, built in C + Raylib.
Run up to four algorithms side-by-side, hear each comparison as a pitch-mapped tone, and control array size and speed live from a collapsible panel.
| 9 algorithms | Bubble, Selection, Insertion, Shell, Gnome, Cocktail Shaker, Merge, Quick, Heap |
| Multi-view | 1, 2, or 4 simultaneous visualizations in the same window |
| Live controls | Array size (8–512) and speed (1–32 steps/frame) via sliders |
| Sound | Pitch-mapped sine tones — the higher the bar, the higher the note |
| Panel toggle | Collapse/expand the side panel with the ◀ button or resize freely |
| Focus ring | Click any view to focus it; stats and sound follow the focused view |
| Colour semantics | Each bar state has a distinct vivid colour (see table below) |
| 42 Norm | All source files comply with École 42 Norminette v3 |
- GCC with C11 support
- Raylib 5.x installed system-wide
# Arch Linux
sudo pacman -S raylib
# Ubuntu / Debian
sudo apt install libraylib-dev
# macOS
brew install raylib
# From source (all platforms)
# https://github.com/raysan5/raylib# Build and launch immediately
make run
# Build only
make
# Remove object files and binary
make cleanThe Makefile compiles every src/*.c automatically — adding a new algorithm file requires no Makefile edits.
Custom Raylib path — if Raylib is not under
/usr, passRAYLIB_PATH:make run RAYLIB_PATH=/usr/local
| Input | Action |
|---|---|
Space |
Pause / Resume |
R |
Shuffle and restart all views |
1 |
Single-view mode |
2 |
Two views side by side |
4 |
Four views in a 2×2 grid |
| Click on any view | Focus that view (panel stats + sound follow it) |
| Scroll wheel | Scroll the algorithm list in the panel |
| ◀ / ▶ button | Toggle the side panel |
| Speed slider | Steps executed per frame (1 = slow-motion, 32 = fast) |
| Array Size slider | Number of elements (8 – 512) |
| ⏸ / ▶ button | Pause / Resume |
| ↺ button | Shuffle & restart |
make new_algo NAME=radix_sort
# → creates src/radix_sort.c with the full boilerplateOpen src/radix_sort.c. The update function must advance exactly one logical step per call — the engine calls it speed times per frame automatically.
#include "common.h"
static void update(t_sort_state *s)
{
if (s->sorted)
return ;
/*
* Use s->i, s->j as persistent cursors between frames.
* Use s->aux[] as scratch space (e.g. temp values, stack).
* Highlight up to 4 indices via s->hl[] / s->hl_count.
* Use s->pivot_idx for a yellow pivot marker (-1 = off).
*/
s->hl[0] = s->i;
s->hl_count = 1;
s->comparisons++;
/* ... your swap / write logic ... */
s->swaps++;
/* Signal completion: */
s->sorted = true;
s->hl_count = 0;
}
void register_radix_sort(void)
{
t_algorithm algo;
algo.name = "Radix Sort";
algo.category = "Non-comparison";
algo.update = update;
algo.reset = NULL; /* or a custom reset fn if needed */
algo.stable = true;
algo.complexity = "O(nk)";
register_algorithm(algo);
}Add two lines to src/main.c:
/* 1. Forward declaration — top of main.c, with the others */
void register_radix_sort(void);
/* 2. Call it — inside init_app(), with the other register_*() calls */
register_radix_sort();The algorithm appears in the panel list immediately on the next make run.
typedef struct s_sort_state
{
int values[MAX_SIZE]; /* the array being sorted */
int size; /* current length */
int i, j; /* persistent cursors — survive between frames*/
int aux[MAX_SIZE]; /* scratch: temp array, index stack, flags… */
int pivot_idx; /* yellow marker; set to -1 when not in use */
bool sorted; /* set true when the algorithm is done */
long comparisons; /* increment on every key comparison */
long swaps; /* increment on every swap or write */
double elapsed_ms; /* available for timing; unused by engine */
int speed; /* steps/frame — read-only inside update() */
int hl[4]; /* indices to highlight in red (up to 4) */
int hl_count; /* how many hl[] entries are active */
} t_sort_state;| Constant | Colour | Meaning |
|---|---|---|
COL_BAR_DEFAULT |
Indigo | Idle, unsorted |
COL_COMPARING |
Rose-red | Active indices in hl[] |
COL_SORTED |
Emerald | Confirmed final position |
COL_PIVOT |
Amber | pivot_idx — Quick Sort pivot |
COL_MIN |
Violet | Current minimum — Selection Sort |
COL_WRITE |
Sky-blue | Write target — Radix / Counting Sort |
sorting_visualizer/
├── include/
│ └── common.h ← types, palette macros, full public API
├── src/
│ ├── main.c ← window init, game loop, algorithm registry
│ ├── draw.c ← DrawSortBars(), DrawInfoOverlay()
│ ├── ui.c ← UiButton(), UiSlider(), DrawTxt(), SetAppFont()
│ ├── ui_misc.c ← UiLabel(), UiSeparator(), UiTag()
│ ├── views.c ← reset_view(), set_view_count(), view_bounds()
│ ├── loop.c ← update_sorts(), handle_sound(), handle_input(), draw_frame()
│ ├── toolbar.c ← top-bar rendering
│ ├── panel.c ← side panel: algorithm list, scrollbar, controls
│ ├── panel_info.c ← side panel: array-size and stats sections
│ ├── sound.c ← sine-tone synthesis via Raylib Wave API
│ ├── bubble_sort.c
│ ├── selection_sort.c
│ ├── insertion_sort.c
│ ├── shell_sort.c
│ ├── gnome_sort.c
│ ├── cocktail_sort.c
│ ├── merge_sort.c
│ ├── quick_sort.c
│ └── heap_sort.c
└── Makefile
game_loop()
├── update_sorts() calls algo.update() × speed for each active view
├── handle_sound() plays pitch-mapped tone for the focused view
├── handle_input() keyboard shortcuts + mouse click / focus routing
└── draw_frame()
├── DrawSortBars() × view_count render bars + header per view
├── draw_dividers() grid lines between split views
├── draw_panel() side panel (algo list, sliders, stats)
└── draw_toolbar() top bar (title, view buttons, speed)
The entire codebase follows Norminette v3 rules:
- ≤ 25 lines per function body (excluding braces)
- ≤ 5 functions per
.cfile (including static helpers) - ≤ 5 local variables per function
- ≤ 4 parameters per function
- No
forloops — all iteration useswhile - No
switch, no ternary?: - Declarations at the top of each block, before any instruction
- Tab indentation, lines ≤ 80 characters
t_prefix on all typedef structs
- Radix Sort (LSD)
- Counting Sort
- Tim Sort
- Bitonic Sort
- Race mode — timer per algorithm, winner highlighted
- Export comparison / swap metrics to CSV
