diff options
| author | Alec Goncharow <alec@goncharow.dev> | 2026-07-10 12:22:02 -0400 |
|---|---|---|
| committer | Alec Goncharow <alec@goncharow.dev> | 2026-07-10 12:22:02 -0400 |
| commit | 356465b85ba7e16eaaec68cbc22cd5e84a0a2a44 (patch) | |
| tree | 9be1bae951ab3de710eedcbc3a12e5c639d36d71 | |
| parent | 93ad8a5cdeb8421bcf02195bc470257935062138 (diff) | |
Some old patches
| -rw-r--r-- | src/apps/maze_app.jai | 110 | ||||
| -rw-r--r-- | src/main.jai | 1 | ||||
| -rw-r--r-- | src/ui_panel.jai | 24 |
3 files changed, 121 insertions, 14 deletions
diff --git a/src/apps/maze_app.jai b/src/apps/maze_app.jai index b3b588c..7efb0ab 100644 --- a/src/apps/maze_app.jai +++ b/src/apps/maze_app.jai @@ -1,6 +1,7 @@ #import "Basic"; #import "Math"; #import "String"; +#import "Random"; Maze_Data :: struct { rows: int; @@ -23,6 +24,17 @@ Maze_Data :: struct { font: *Simp.Dynamic_Font; panel: UI_Panel; + + // Generator State + is_generating: bool; + frontier: [..] Int2; + time_since_last_step: float; + generate_speed: float; +} + +Int2 :: struct { + x: int; // col + y: int; // row } init_maze_app :: (widget: *Widget_State) { @@ -49,17 +61,20 @@ init_maze_app :: (widget: *Widget_State) { // Setup UI Panel data.panel.x = 20.0; - data.panel.y = cast(float)window_height - 300.0; + data.panel.y = cast(float)window_height - 340.0; data.panel.w = 200.0; - data.panel.h = 240.0; + data.panel.h = 280.0; data.panel.userdata = data; // Give callback access to our data! data.panel.app_owner = widget; // Bind panel visibility to this app! array_add(*data.panel.elements, .{type=.HEADER, id=5, x0=0.0, y0=data.panel.h - 40.0, x1=data.panel.w, y1=data.panel.h, label="Controls"}); // Inputs (from top to bottom, note Simp Y=0 is bottom, so highest Y is top) - array_add(*data.panel.elements, .{type=.TEXT_INPUT, id=1, x0=10.0, y0=data.panel.h - 100.0, x1=190.0, y1=data.panel.h - 60.0, label="Width:", input_buf=*data.width_input}); - array_add(*data.panel.elements, .{type=.TEXT_INPUT, id=2, x0=10.0, y0=data.panel.h - 160.0, x1=190.0, y1=data.panel.h - 120.0, label="Height:", input_buf=*data.height_input}); + array_add(*data.panel.elements, .{type=.TEXT_INPUT, id=1, x0=10.0, y0=data.panel.h - 100.0, x1=190.0, y1=data.panel.h - 60.0, label="Width:", input_buf=*data.width_input, text_filter=ui_filter_for_nums }); + array_add(*data.panel.elements, .{type=.TEXT_INPUT, id=2, x0=10.0, y0=data.panel.h - 160.0, x1=190.0, y1=data.panel.h - 120.0, label="Height:", input_buf=*data.height_input,text_filter=ui_filter_for_nums }); + + // Generate Button + array_add(*data.panel.elements, .{type=.BUTTON, id=3, x0=10.0, y0=data.panel.h - 220.0, x1=190.0, y1=data.panel.h - 180.0, label="Generate", action=generate_maze_callback}); // Back button at bottom array_add(*data.panel.elements, .{type=.BUTTON, id=4, x0=10.0, y0=10.0, x1=190.0, y1=50.0, label="Back", action=(userdata: *void) { switch_app(*menu_state); }}); @@ -75,31 +90,101 @@ init_maze_app :: (widget: *Widget_State) { widget.update = (widget: *Widget_State, dt: float) { data := cast(*Maze_Data) widget.data; - - // maze gen / solving step happens in here maybe? - }; - - widget.shutdown = (widget: *Widget_State) { - data := cast(*Maze_Data) widget.data; - ui_unregister_panel(*data.panel); + if data.is_generating { + data.time_since_last_step += dt; + steps := cast(int)(data.time_since_last_step * data.generate_speed); + if steps > 0 { + data.time_since_last_step -= cast(float)steps / data.generate_speed; + for 1..steps { + if data.frontier.count > 0 { + idx := cast(int)(random_get() % cast(u64)data.frontier.count); + cell := data.frontier[idx]; + array_ordered_remove_by_index(*data.frontier, idx); + + if !data.grid[cell.y * data.cols + cell.x] continue; // already visited + + empty_neighbors: [..] Int2; + if cell.y >= 2 && !data.grid[(cell.y - 2) * data.cols + cell.x] array_add(*empty_neighbors, .{cell.x, cell.y - 2}); + if cell.y < data.rows - 2 && !data.grid[(cell.y + 2) * data.cols + cell.x] array_add(*empty_neighbors, .{cell.x, cell.y + 2}); + if cell.x >= 2 && !data.grid[cell.y * data.cols + cell.x - 2] array_add(*empty_neighbors, .{cell.x - 2, cell.y}); + if cell.x < data.cols - 2 && !data.grid[cell.y * data.cols + cell.x + 2] array_add(*empty_neighbors, .{cell.x + 2, cell.y}); + + if empty_neighbors.count > 0 { + n_idx := cast(int)(random_get() % cast(u64)empty_neighbors.count); + n := empty_neighbors[n_idx]; + + wall_x := (cell.x + n.x) / 2; + wall_y := (cell.y + n.y) / 2; + data.grid[wall_y * data.cols + wall_x] = false; + data.grid[cell.y * data.cols + cell.x] = false; + + if cell.y >= 3 && data.grid[(cell.y - 2) * data.cols + cell.x] array_add(*data.frontier, .{cell.x, cell.y - 2}); + if cell.y < data.rows - 3 && data.grid[(cell.y + 2) * data.cols + cell.x] array_add(*data.frontier, .{cell.x, cell.y + 2}); + if cell.x >= 3 && data.grid[cell.y * data.cols + cell.x - 2] array_add(*data.frontier, .{cell.x - 2, cell.y}); + if cell.x < data.cols - 3 && data.grid[cell.y * data.cols + cell.x + 2] array_add(*data.frontier, .{cell.x + 2, cell.y}); + } + array_free(empty_neighbors); + } else { + data.is_generating = false; + break; + } + } + } + } }; - widget.update = (widget: *Widget_State, dt: float) {}; widget.handle_input = handle_input; widget.render = render; widget.shutdown = (widget: *Widget_State) { data := cast(*Maze_Data) widget.data; + ui_unregister_panel(*data.panel); array_free(data.grid); array_free(data.width_input); array_free(data.height_input); + array_free(data.frontier); free(data); }; } #scope_file +generate_maze_callback :: (userdata: *void) { + data := cast(*Maze_Data) userdata; + + // Fill with walls + for r: 0..data.rows-1 { + for c: 0..data.cols-1 { + data.grid[r * data.cols + c] = true; + } + } + + // Pick start node (odd, odd) + start_r := 1; + start_c := 1; + if data.rows > 2 && data.cols > 2 { + start_r = cast(int)(random_get() % cast(u64)(data.rows / 2)) * 2 + 1; + start_c = cast(int)(random_get() % cast(u64)(data.cols / 2)) * 2 + 1; + } + + data.grid[start_r * data.cols + start_c] = false; + + array_reset(*data.frontier); + // Add neighbors of start node + if start_r >= 3 array_add(*data.frontier, .{start_c, start_r - 2}); + if start_r < data.rows - 3 array_add(*data.frontier, .{start_c, start_r + 2}); + if start_c >= 3 array_add(*data.frontier, .{start_c - 2, start_r}); + if start_c < data.cols - 3 array_add(*data.frontier, .{start_c + 2, start_r}); + + data.is_generating = true; + data.time_since_last_step = 0; + data.generate_speed = 60.0; // steps per second +} + apply_resize :: (data: *Maze_Data) { + data.is_generating = false; + + w_str: string; w_str.data = data.width_input.data; w_str.count = data.width_input.count; @@ -176,6 +261,7 @@ handle_input :: (widget: *Widget_State, occluded: bool) -> (occludes: bool) { if data.panel.focus != 0 { apply_resize(data); data.panel.focus = 0; + ui_clear_focus(); } } diff --git a/src/main.jai b/src/main.jai index 897cfb7..176f390 100644 --- a/src/main.jai +++ b/src/main.jai @@ -35,7 +35,6 @@ switch_app :: (new_app: *Widget_State) { active_app = new_app; } - main :: () { window = create_window(window_width, window_height, "Jai Sandbox"); Simp.set_render_target(window); diff --git a/src/ui_panel.jai b/src/ui_panel.jai index cc0a2e2..c27b40d 100644 --- a/src/ui_panel.jai +++ b/src/ui_panel.jai @@ -9,6 +9,7 @@ UI_Element :: struct { x0, y0, x1, y1: float; label: string; input_buf: *[..] u8; + text_filter: (char: u32) -> bool = null; action: (userdata: *void) = null; } @@ -32,6 +33,7 @@ UI_Panel :: struct { #scope_file active_panels: [..] *UI_Panel; text_edit: *[..] u8; +text_filter: (char: u32) -> bool; #scope_export ui_register_panel :: (panel: *UI_Panel) { @@ -47,6 +49,15 @@ ui_bring_to_front :: (panel: *UI_Panel) { array_add(*active_panels, panel); } +ui_filter_for_nums :: (value: u32) -> bool { + return value >= #char "0" && value <= #char "9"; +} + +ui_clear_focus :: () { + text_edit = null; + text_filter = null; +} + ui_handle_input :: (active_app: *void) -> (occludes: bool) { occludes := false; mouse_x, mouse_y, success := get_mouse_pointer_position(window, true); @@ -83,6 +94,11 @@ ui_handle_input :: (active_app: *void) -> (occludes: bool) { if text_edit { dirty_text = true; value := it.utf32; + if text_filter { + if !text_filter(value) { + continue; + } + } str := Unicode.character_utf32_to_utf8(value); for 0..str.count-1 { @@ -161,6 +177,7 @@ ui_handle_input :: (active_app: *void) -> (occludes: bool) { } else if elem.type == .TEXT_INPUT { panel.focus = elem.id; text_edit = elem.input_buf; + text_filter = elem.text_filter; } else if elem.type == .BUTTON && mouse_released { if elem.action elem.action(panel.userdata); } @@ -173,10 +190,15 @@ ui_handle_input :: (active_app: *void) -> (occludes: bool) { if !hit_element { panel.focus = 0; - text_edit = null; + ui_clear_focus(); } } return true; + } else { + if mouse_btn { + panel.focus = 0; + ui_clear_focus(); + } } } return false; |
