// Copyright (c) 2023-2026 Chris (boreddevnl) // This software is released under the GNU General Public License v3.0. See LICENSE file for details. // This header needs to maintain in any file it is present in, as per the GPL license terms. #include "syscall.h" #include "libui.h" #include "stdlib.h" #define WIN_W 400 #define WIN_H 210 #define NUM_ELEM (WIN_W / 2) #define BAR_W 2 static uint32_t *fb = NULL; static int heights[NUM_ELEM]; static int moves = 0; static unsigned long int next_rand = 1; static int my_rand(void) { next_rand = next_rand * 1103515245 + 12345; return (unsigned int)(next_rand / 65536) % 32768; } static void my_srand(unsigned int seed) { next_rand = seed; } static void render_state(ui_window_t win) { // Clear fb for (int i = 0; i < WIN_W * WIN_H; i++) { fb[i] = 0xFF1E1E1E; } // Draw bars for (int i = 0; i < NUM_ELEM; i++) { int h = heights[i]; if (h > WIN_H - 10) h = WIN_H - 10; int x = i * BAR_W; int y = WIN_H - h; // draw rect for (int yy = y; yy < WIN_H; yy++) { for (int xx = x; xx < x + BAR_W; xx++) { if (xx >= 0 && xx < WIN_W && yy >= 0 && yy < WIN_H) { fb[yy * WIN_W + xx] = 0xFF4A90E2; // Blue } } } } // Draw Border for Box - bottom left int box_x = 10; int box_y = WIN_H - 40; // moved up by 10 pixels int box_w = 120; int box_h = 24; for (int yy = box_y; yy < box_y + box_h; yy++) { for (int xx = box_x; xx < box_x + box_w; xx++) { if (xx == box_x || xx == box_x + box_w - 1 || yy == box_y || yy == box_y + box_h - 1) { fb[yy * WIN_W + xx] = 0xFFFFFFFF; } else { fb[yy * WIN_W + xx] = 0xFF1E1E1E; } } } // Draw framebuffer to window ui_draw_image(win, 0, 0, WIN_W, WIN_H, fb); // Draw text inside the box char buf[32]; strcpy(buf, "Moves: "); char num_buf[16]; itoa(moves, num_buf); strcat(buf, num_buf); ui_draw_string(win, box_x + 8, box_y + 4, buf, 0xFFFFFFFF); ui_mark_dirty(win, 0, 0, WIN_W, WIN_H); } int main(void) { ui_window_t win = ui_window_create("sort", 100, 100, WIN_W, WIN_H); fb = (uint32_t*)malloc(WIN_W * WIN_H * sizeof(uint32_t)); if (!fb) return 1; // Seed PRNG with system time (ticks) my_srand((unsigned int)sys_system(16, 0, 0, 0, 0)); // Initialize perfect slope int max_h = WIN_H - 40; // max height int min_h = 10; for (int i = 0; i < NUM_ELEM; i++) { heights[i] = min_h + (max_h - min_h) * i / (NUM_ELEM - 1); } // Shuffle for (int i = NUM_ELEM - 1; i > 0; i--) { int j = my_rand() % (i + 1); int t = heights[i]; heights[i] = heights[j]; heights[j] = t; } gui_event_t ev; // Cocktail shaker sort variables bool swapped = true; int start = 0; int end = NUM_ELEM - 1; bool done = false; // We render after each swap so the steps are extremely visual while (1) { if (ui_get_event(win, &ev)) { if (ev.type == GUI_EVENT_CLOSE) { break; } } if (!done) { swapped = false; // Forward pass for (int i = start; i < end; ++i) { if (heights[i] > heights[i + 1]) { int t = heights[i]; heights[i] = heights[i+1]; heights[i+1] = t; swapped = true; moves++; render_state(win); // Allow UI events while sorting if (ui_get_event(win, &ev)) { if (ev.type == GUI_EVENT_CLOSE) { goto exit_app; } } // No explicit sleep, rendering takes some time and provides natural visual delay. // If it's too fast, we'll add sleep(1) here later. } } if (!swapped) { done = true; continue; } swapped = false; end = end - 1; // Backward pass for (int i = end - 1; i >= start; --i) { if (heights[i] > heights[i + 1]) { int t = heights[i]; heights[i] = heights[i+1]; heights[i+1] = t; swapped = true; moves++; render_state(win); // Allow UI events if (ui_get_event(win, &ev)) { if (ev.type == GUI_EVENT_CLOSE) { goto exit_app; } } } } start = start + 1; } else { // Sort is done, just render and idle render_state(win); sleep(50); } } exit_app: free(fb); exit(0); return 0; }