|
| 1 | +#include "advent_of_code.h" |
| 2 | +#include "solvers.h" |
| 3 | + |
| 4 | +void update_results(AdventOfCode* aoc, FuriString* part_1, FuriString* part_2) { |
| 5 | + furi_check(furi_mutex_acquire(aoc->model_mutex, FuriWaitForever) == FuriStatusOk); |
| 6 | + if(part_1) { |
| 7 | + furi_string_set(aoc->model->part_1, part_1); |
| 8 | + if(aoc->model->img_1->data) { |
| 9 | + free(aoc->model->img_1->data); |
| 10 | + aoc->model->img_1->data = NULL; |
| 11 | + } |
| 12 | + } |
| 13 | + if(part_2) { |
| 14 | + furi_string_set(aoc->model->part_2, part_2); |
| 15 | + if(aoc->model->img_2->data) { |
| 16 | + free(aoc->model->img_2->data); |
| 17 | + aoc->model->img_2->data = NULL; |
| 18 | + } |
| 19 | + } |
| 20 | + furi_mutex_release(aoc->model_mutex); |
| 21 | + view_port_update(aoc->view_port); |
| 22 | +}; |
| 23 | + |
| 24 | +void update_images(AdventOfCode* aoc, Image* img_1, Image* img_2) { |
| 25 | + furi_check(furi_mutex_acquire(aoc->model_mutex, FuriWaitForever) == FuriStatusOk); |
| 26 | + |
| 27 | + if(img_1) { |
| 28 | + if(aoc->model->img_1->data) free(aoc->model->img_1->data); |
| 29 | + |
| 30 | + aoc->model->img_1->width = img_1->width; |
| 31 | + aoc->model->img_1->height = img_1->height; |
| 32 | + |
| 33 | + size_t size = (size_t)img_1->width * (size_t)img_1->height; |
| 34 | + if(img_1->width % 8 > 0) size += img_1->height; |
| 35 | + |
| 36 | + aoc->model->img_1->data = malloc(size); |
| 37 | + memcpy(aoc->model->img_1->data, img_1->data, size); |
| 38 | + } |
| 39 | + |
| 40 | + if(img_2) { |
| 41 | + if(aoc->model->img_2->data) free(aoc->model->img_2->data); |
| 42 | + |
| 43 | + aoc->model->img_2->width = img_2->width; |
| 44 | + aoc->model->img_2->height = img_2->height; |
| 45 | + |
| 46 | + size_t size = (size_t)img_2->width * (size_t)img_2->height; |
| 47 | + if(img_2->width % 8 > 0) size += img_2->height; |
| 48 | + |
| 49 | + aoc->model->img_2->data = malloc(size); |
| 50 | + memcpy(aoc->model->img_2->data, img_2->data, size); |
| 51 | + } |
| 52 | + |
| 53 | + furi_mutex_release(aoc->model_mutex); |
| 54 | + view_port_update(aoc->view_port); |
| 55 | +}; |
| 56 | + |
| 57 | +void unimplemented(AdventOfCode* aoc, Stream* file_stream) { |
| 58 | + UNUSED(file_stream); |
| 59 | + FuriString* str = furi_string_alloc_set("unimplemented"); |
| 60 | + update_results(aoc, str, str); |
| 61 | + furi_string_free(str); |
| 62 | +} |
| 63 | + |
| 64 | +static void render_callback(Canvas* canvas, void* ctx) { |
| 65 | + FURI_LOG_D(TAG, "Render callback"); |
| 66 | + |
| 67 | + AdventOfCode* aoc = ctx; |
| 68 | + furi_check(furi_mutex_acquire(aoc->model_mutex, FuriWaitForever) == FuriStatusOk); |
| 69 | + int day = aoc->model->day; |
| 70 | + FuriString* part_1 = furi_string_alloc_set(aoc->model->part_1); |
| 71 | + FuriString* part_2 = furi_string_alloc_set(aoc->model->part_2); |
| 72 | + Image* img_1 = aoc->model->img_1; |
| 73 | + Image* img_2 = aoc->model->img_2; |
| 74 | + furi_mutex_release(aoc->model_mutex); |
| 75 | + |
| 76 | + canvas_clear(canvas); |
| 77 | + canvas_set_color(canvas, ColorBlack); |
| 78 | + canvas_set_font(canvas, FontPrimary); |
| 79 | + canvas_draw_str(canvas, 0, 12, "Advent of Code 2022"); |
| 80 | + |
| 81 | + char tmp_str[24]; |
| 82 | + snprintf(tmp_str, 24, " * Day %d *", day); |
| 83 | + canvas_draw_str(canvas, 0, 24, tmp_str); |
| 84 | + |
| 85 | + canvas_set_font(canvas, FontSecondary); |
| 86 | + |
| 87 | + if(img_1->data) { |
| 88 | + canvas_draw_bitmap(canvas, 32, 36, img_1->width, img_1->height, img_1->data); |
| 89 | + furi_string_set(part_1, ""); |
| 90 | + } else if(furi_string_size(part_1) == 0) { |
| 91 | + furi_string_set(part_1, "calculating..."); |
| 92 | + } |
| 93 | + |
| 94 | + if(img_2->data) { |
| 95 | + canvas_draw_bitmap(canvas, 32, 48, img_2->width, img_2->height, img_2->data); |
| 96 | + furi_string_set(part_2, ""); |
| 97 | + } else if(furi_string_size(part_2) == 0) { |
| 98 | + furi_string_set(part_2, "calculating..."); |
| 99 | + } |
| 100 | + |
| 101 | + snprintf(tmp_str, 24, "Part 1: %s", furi_string_get_cstr(part_1)); |
| 102 | + canvas_draw_str(canvas, 0, 42, tmp_str); |
| 103 | + if(day == 25) |
| 104 | + snprintf(tmp_str, 24, "(cont.) %s", furi_string_get_cstr(part_2)); |
| 105 | + else |
| 106 | + snprintf(tmp_str, 24, "Part 2: %s", furi_string_get_cstr(part_2)); |
| 107 | + canvas_draw_str(canvas, 0, 54, tmp_str); |
| 108 | + |
| 109 | + furi_string_free(part_2); |
| 110 | + furi_string_free(part_1); |
| 111 | +} |
| 112 | + |
| 113 | +static void input_callback(InputEvent* input_event, void* ctx) { |
| 114 | + FURI_LOG_D(TAG, "Input callback"); |
| 115 | + |
| 116 | + AdventOfCode* aoc = ctx; |
| 117 | + if(input_event->type == InputTypeShort) { |
| 118 | + furi_message_queue_put(aoc->input_queue, input_event, 0); |
| 119 | + } |
| 120 | +} |
| 121 | + |
| 122 | +void advent_of_code_reset_day(AdventOfCode* aoc, int day) { |
| 123 | + furi_check(furi_mutex_acquire(aoc->model_mutex, FuriWaitForever) == FuriStatusOk); |
| 124 | + aoc->model->day = day; |
| 125 | + furi_string_reset(aoc->model->part_1); |
| 126 | + if(aoc->model->img_1->data) { |
| 127 | + free(aoc->model->img_1->data); |
| 128 | + aoc->model->img_1->data = NULL; |
| 129 | + } |
| 130 | + furi_string_reset(aoc->model->part_2); |
| 131 | + if(aoc->model->img_2->data) { |
| 132 | + free(aoc->model->img_2->data); |
| 133 | + aoc->model->img_2->data = NULL; |
| 134 | + } |
| 135 | + furi_mutex_release(aoc->model_mutex); |
| 136 | + view_port_update(aoc->view_port); |
| 137 | +} |
| 138 | + |
| 139 | +AdventOfCode* advent_of_code_alloc() { |
| 140 | + AdventOfCode* aoc = malloc(sizeof(AdventOfCode)); |
| 141 | + |
| 142 | + AdventOfCodeModel* model = malloc(sizeof(AdventOfCodeModel)); |
| 143 | + model->day = 0; |
| 144 | + model->part_1 = furi_string_alloc(); |
| 145 | + model->part_2 = furi_string_alloc(); |
| 146 | + |
| 147 | + Image* img_1 = malloc(sizeof(Image)); |
| 148 | + img_1->width = 0; |
| 149 | + img_1->height = 0; |
| 150 | + img_1->data = NULL; |
| 151 | + Image* img_2 = malloc(sizeof(Image)); |
| 152 | + img_2->width = 0; |
| 153 | + img_2->height = 0; |
| 154 | + img_2->data = NULL; |
| 155 | + |
| 156 | + model->img_1 = img_1; |
| 157 | + model->img_2 = img_2; |
| 158 | + |
| 159 | + aoc->model = model; |
| 160 | + |
| 161 | + aoc->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); |
| 162 | + |
| 163 | + aoc->input_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); |
| 164 | + |
| 165 | + aoc->view_port = view_port_alloc(); |
| 166 | + view_port_draw_callback_set(aoc->view_port, render_callback, aoc); |
| 167 | + view_port_input_callback_set(aoc->view_port, input_callback, aoc); |
| 168 | + |
| 169 | + // Open GUI and register view_port |
| 170 | + aoc->gui = furi_record_open(RECORD_GUI); |
| 171 | + gui_add_view_port(aoc->gui, aoc->view_port, GuiLayerFullscreen); |
| 172 | + |
| 173 | + return aoc; |
| 174 | +} |
| 175 | + |
| 176 | +void advent_of_code_free(AdventOfCode* aoc) { |
| 177 | + FURI_LOG_D(TAG, "Freeing"); |
| 178 | + |
| 179 | + gui_remove_view_port(aoc->gui, aoc->view_port); |
| 180 | + furi_record_close(RECORD_GUI); |
| 181 | + view_port_free(aoc->view_port); |
| 182 | + |
| 183 | + furi_message_queue_free(aoc->input_queue); |
| 184 | + |
| 185 | + furi_mutex_free(aoc->model_mutex); |
| 186 | + |
| 187 | + if(aoc->model->img_2->data) free(aoc->model->img_2->data); |
| 188 | + free(aoc->model->img_2); |
| 189 | + if(aoc->model->img_1->data) free(aoc->model->img_1->data); |
| 190 | + free(aoc->model->img_1); |
| 191 | + |
| 192 | + furi_string_free(aoc->model->part_2); |
| 193 | + furi_string_free(aoc->model->part_1); |
| 194 | + free(aoc->model); |
| 195 | + free(aoc); |
| 196 | + |
| 197 | + FURI_LOG_D(TAG, "Free at last"); |
| 198 | +} |
| 199 | + |
| 200 | +int32_t advent_of_code_2022_app(void* p) { |
| 201 | + FURI_LOG_D(TAG, "Starting"); |
| 202 | + |
| 203 | + AdventOfCode* aoc = advent_of_code_alloc(); |
| 204 | + |
| 205 | + FURI_LOG_D(TAG, "Allocated"); |
| 206 | + |
| 207 | + FuriString* file_path; |
| 208 | + file_path = furi_string_alloc(); |
| 209 | + FuriString* file_name; |
| 210 | + file_name = furi_string_alloc(); |
| 211 | + |
| 212 | + do { |
| 213 | + FURI_LOG_D(TAG, "Checking file path"); |
| 214 | + if(p && strlen(p)) { |
| 215 | + FURI_LOG_D(TAG, "File path set"); |
| 216 | + furi_string_set(file_path, (const char*)p); |
| 217 | + } else { |
| 218 | + furi_string_set(file_path, ADVENT_OF_CODE_APP_BASE_PATH); |
| 219 | + |
| 220 | + FURI_LOG_D(TAG, "Opening file browser"); |
| 221 | + |
| 222 | + DialogsFileBrowserOptions browser_options; |
| 223 | + dialog_file_browser_set_basic_options( |
| 224 | + &browser_options, ADVENT_OF_CODE_APP_EXTENSION, &I_txt_10px); |
| 225 | + browser_options.base_path = ADVENT_OF_CODE_APP_BASE_PATH; |
| 226 | + browser_options.hide_ext = false; |
| 227 | + |
| 228 | + DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); |
| 229 | + bool res = dialog_file_browser_show(dialogs, file_path, file_path, &browser_options); |
| 230 | + |
| 231 | + furi_record_close(RECORD_DIALOGS); |
| 232 | + if(!res) { |
| 233 | + FURI_LOG_E(TAG, "No file selected"); |
| 234 | + break; |
| 235 | + } |
| 236 | + } |
| 237 | + |
| 238 | + path_extract_filename(file_path, file_name, true); |
| 239 | + FURI_LOG_D( |
| 240 | + TAG, |
| 241 | + "Selected file \'%s\' (%s)", |
| 242 | + furi_string_get_cstr(file_path), |
| 243 | + furi_string_get_cstr(file_name)); |
| 244 | + |
| 245 | + Storage* storage = furi_record_open(RECORD_STORAGE); |
| 246 | + Stream* file_stream = buffered_file_stream_alloc(storage); |
| 247 | + furi_record_close(RECORD_STORAGE); |
| 248 | + |
| 249 | + int day = atoi(furi_string_get_cstr(file_name)); |
| 250 | + |
| 251 | + if(day < 1 || day > 25) { |
| 252 | + FURI_LOG_E(TAG, "Not a valid day: %d", day); |
| 253 | + continue; |
| 254 | + } |
| 255 | + |
| 256 | + advent_of_code_reset_day(aoc, day); |
| 257 | + |
| 258 | + if(!buffered_file_stream_open( |
| 259 | + file_stream, furi_string_get_cstr(file_path), FSAM_READ, FSOM_OPEN_EXISTING)) { |
| 260 | + FURI_LOG_E(TAG, "Unable to open file"); |
| 261 | + } else { |
| 262 | + solvers[day - 1](aoc, file_stream); |
| 263 | + } |
| 264 | + |
| 265 | + buffered_file_stream_close(file_stream); |
| 266 | + stream_free(file_stream); |
| 267 | + |
| 268 | + InputEvent input; |
| 269 | + while(furi_message_queue_get(aoc->input_queue, &input, FuriWaitForever) == FuriStatusOk) { |
| 270 | + if(input.key == InputKeyBack) { |
| 271 | + break; |
| 272 | + } |
| 273 | + } |
| 274 | + } while(1); |
| 275 | + |
| 276 | + furi_string_free(file_path); |
| 277 | + advent_of_code_free(aoc); |
| 278 | + |
| 279 | + return 0; |
| 280 | +} |
0 commit comments