From afa6976f1a6984d89944de8ac6b020cc56dd7a4c Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Fri, 23 Oct 2026 19:27:25 -0400 Subject: [PATCH] Progress toward dynamic triangle regeneration --- src/c/main.c | 264 +++++++++++++++++++++++++++------------------------ 1 file changed, 138 insertions(+), 126 deletions(-) diff --git a/src/c/main.c b/src/c/main.c index 4c0ee75..8bf5b72 100644 --- a/src/c/main.c +++ b/src/c/main.c @@ -59,7 +59,7 @@ static GColor s_setter_highlight_color; static uint8_t s_highlight_pos = 0; static bool s_skip_current_day = false; //// alarm -static uint8_t s_demotion_promotion_clocks[2]; +static uint8_t s_current_triangle_num; static uint8_t s_solution_indices[3]; static uint8_t s_selected_indices[3] = {9, 9, 9}; static uint8_t s_awareness_countdown_int = 0; @@ -456,6 +456,137 @@ static void live_wakeup_handler_for_alarm(WakeupId id, int32_t wakeup_reason) { } } +static void update_for_new_triangle() { + // pick & display 2 side lengths to the user + static char side_a_buffer[8], side_b_buffer[8], side_c_buffer[8]; + uint8_t ignored_side = rand() % 3; + uint8_t sin_index = rand() % 2; + uint8_t cos_index = rand() % 2; + uint8_t tan_index = rand() % 2; + switch (ignored_side) { + case 0: + snprintf(side_b_buffer, sizeof(side_b_buffer), "%u", s_triangle_layer->side_b); + snprintf(side_c_buffer, sizeof(side_c_buffer), "%u", s_triangle_layer->side_c); + s_options_over[0] = side_b_buffer; + s_options_over[1] = side_c_buffer; + s_options_under[0] = side_b_buffer; + s_options_under[1] = side_c_buffer; + + // store solution + s_solution_indices[0] = 2; // tan/cot + if (s_triangle_layer->theta_angle_is_left) { + if (tan_index == 0) { // tan + s_solution_indices[1] = 0; // b (opposite) + s_solution_indices[2] = 1; // c (adjacent) + } else { // cot + s_solution_indices[1] = 1; // c (adjacent) + s_solution_indices[2] = 0; // b (opposite) + } + } else { + if (tan_index == 0) { // tan + s_solution_indices[1] = 1; // c (opposite) + s_solution_indices[2] = 0; // b (adjacent) + } else { // cot + s_solution_indices[1] = 0; // b (adjacent) + s_solution_indices[2] = 1; // c (opposite) + } + } + + break; + case 1: + snprintf(side_a_buffer, sizeof(side_a_buffer), "%u", s_triangle_layer->side_a); + snprintf(side_c_buffer, sizeof(side_c_buffer), "%u", s_triangle_layer->side_c); + s_options_over[0] = side_a_buffer; + s_options_over[1] = side_c_buffer; + s_options_under[0] = side_a_buffer; + s_options_under[1] = side_c_buffer; + + // store solution + if (s_triangle_layer->theta_angle_is_left) { + s_solution_indices[0] = 1; // cos/sec + if (cos_index == 0) { // cos + s_solution_indices[1] = 1; // c (adjacent) + s_solution_indices[2] = 0; // a (hypotenuse) + } else { // sec + s_solution_indices[1] = 0; // a (hypotenuse) + s_solution_indices[2] = 1; // c (adjacent) + } + } else { + s_solution_indices[0] = 0; // sin/csc + if (sin_index == 0) { // sin + s_solution_indices[1] = 1; // c (opposite) + s_solution_indices[2] = 0; // a (hypotenuse) + } else { // csc + s_solution_indices[1] = 0; // a (hypotenuse) + s_solution_indices[2] = 1; // c (opposite) + } + } + + break; + case 2: + snprintf(side_a_buffer, sizeof(side_a_buffer), "%u", s_triangle_layer->side_a); + snprintf(side_b_buffer, sizeof(side_b_buffer), "%u", s_triangle_layer->side_b); + s_options_over[0] = side_a_buffer; + s_options_over[1] = side_b_buffer; + s_options_under[0] = side_a_buffer; + s_options_under[1] = side_b_buffer; + + // store solution + if (s_triangle_layer->theta_angle_is_left) { + s_solution_indices[0] = 0; // sin/csc + if (sin_index == 0) { // sin + s_solution_indices[1] = 1; // b (opposite) + s_solution_indices[2] = 0; // a (hypotenuse) + } else { // csc + s_solution_indices[1] = 0; // a (hypotenuse) + s_solution_indices[2] = 1; // b (opposite) + } + } else { + s_solution_indices[0] = 1; + if (cos_index == 0) { // cos + s_solution_indices[1] = 1; // b (adjacent) + s_solution_indices[2] = 0; // a (hypotenuse) + } else { // sec + s_solution_indices[1] = 0; // a (hypotenuse) + s_solution_indices[2] = 1; // b (adjacent) + } + } + } + text_layer_set_text(s_side_a_txt_layer, side_a_buffer); + text_layer_set_text(s_side_b_txt_layer, side_b_buffer); + text_layer_set_text(s_side_c_txt_layer, side_c_buffer); + + // set trigonometric function options + s_sin = s_sin_arr[sin_index]; + s_cos = s_cos_arr[cos_index]; + s_tan = s_tan_arr[tan_index]; + s_options_function[0] = s_sin; + s_options_function[1] = s_cos; + s_options_function[2] = s_tan; + + // setup vibes + static const uint32_t VIBE_ON_FLOOR = 120; // ensure motor is on long enough to be felt + static const uint32_t VIBE_ON_SCALE = 4; + static const uint32_t VIBE_GAP = 40; + s_vibe_segments[0] = VIBE_ON_FLOOR + (uint32_t)s_triangle_layer->angle_A * VIBE_ON_SCALE; + s_vibe_segments[1] = VIBE_GAP; + s_vibe_segments[2] = VIBE_ON_FLOOR + (uint32_t)s_triangle_layer->angle_B * VIBE_ON_SCALE; + s_vibe_segments[3] = VIBE_GAP; + s_vibe_segments[4] = VIBE_ON_FLOOR + (uint32_t)s_triangle_layer->angle_C * VIBE_ON_SCALE; + s_vibe_pattern = (VibePattern){ + .durations = s_vibe_segments, + .num_segments = ARRAY_LENGTH(s_vibe_segments), + }; + + // setup countdown + // TODO vary time based on progress: + // Store time step per triangle + // Determine time remaining from min+(s_total_count-s_current_triangle)*step + s_awareness_countdown_int = settings.TriangeMinSecs; + snprintf(s_awareness_countdown_buf, sizeof(s_awareness_countdown_buf), "%03u", s_awareness_countdown_int); + text_layer_set_text(s_countdown_txt_layer, s_awareness_countdown_buf); +} + static void alarm_window_load() { wakeup_service_subscribe(live_wakeup_handler_for_alarm); @@ -559,144 +690,25 @@ static void alarm_window_load() { text_layer_set_background_color(s_side_c_txt_layer, GColorClear); text_layer_set_font(s_side_c_txt_layer, s_font_mansalva_small); layer_add_child(window_layer, text_layer_get_layer(s_side_c_txt_layer)); - //// display 2 side lengths to the user - static char side_a_buffer[8], side_b_buffer[8], side_c_buffer[8]; - uint8_t ignored_side = rand() % 3; - uint8_t sin_index = rand() % 2; - uint8_t cos_index = rand() % 2; - uint8_t tan_index = rand() % 2; - switch (ignored_side) { - case 0: - snprintf(side_b_buffer, sizeof(side_b_buffer), "%u", s_triangle_layer->side_b); - snprintf(side_c_buffer, sizeof(side_c_buffer), "%u", s_triangle_layer->side_c); - s_options_over[0] = side_b_buffer; - s_options_over[1] = side_c_buffer; - s_options_under[0] = side_b_buffer; - s_options_under[1] = side_c_buffer; - // store solution - s_solution_indices[0] = 2; // tan/cot - if (s_triangle_layer->theta_angle_is_left) { - if (tan_index == 0) { // tan - s_solution_indices[1] = 0; // b (opposite) - s_solution_indices[2] = 1; // c (adjacent) - } else { // cot - s_solution_indices[1] = 1; // c (adjacent) - s_solution_indices[2] = 0; // b (opposite) - } - } else { - if (tan_index == 0) { // tan - s_solution_indices[1] = 1; // c (opposite) - s_solution_indices[2] = 0; // b (adjacent) - } else { // cot - s_solution_indices[1] = 0; // b (adjacent) - s_solution_indices[2] = 1; // c (opposite) - } - } - - break; - case 1: - snprintf(side_a_buffer, sizeof(side_a_buffer), "%u", s_triangle_layer->side_a); - snprintf(side_c_buffer, sizeof(side_c_buffer), "%u", s_triangle_layer->side_c); - s_options_over[0] = side_a_buffer; - s_options_over[1] = side_c_buffer; - s_options_under[0] = side_a_buffer; - s_options_under[1] = side_c_buffer; - - // store solution - if (s_triangle_layer->theta_angle_is_left) { - s_solution_indices[0] = 1; // cos/sec - if (cos_index == 0) { // cos - s_solution_indices[1] = 1; // c (adjacent) - s_solution_indices[2] = 0; // a (hypotenuse) - } else { // sec - s_solution_indices[1] = 0; // a (hypotenuse) - s_solution_indices[2] = 1; // c (adjacent) - } - } else { - s_solution_indices[0] = 0; // sin/csc - if (sin_index == 0) { // sin - s_solution_indices[1] = 1; // c (opposite) - s_solution_indices[2] = 0; // a (hypotenuse) - } else { // csc - s_solution_indices[1] = 0; // a (hypotenuse) - s_solution_indices[2] = 1; // c (opposite) - } - } - - break; - case 2: - snprintf(side_a_buffer, sizeof(side_a_buffer), "%u", s_triangle_layer->side_a); - snprintf(side_b_buffer, sizeof(side_b_buffer), "%u", s_triangle_layer->side_b); - s_options_over[0] = side_a_buffer; - s_options_over[1] = side_b_buffer; - s_options_under[0] = side_a_buffer; - s_options_under[1] = side_b_buffer; - - // store solution - if (s_triangle_layer->theta_angle_is_left) { - s_solution_indices[0] = 0; // sin/csc - if (sin_index == 0) { // sin - s_solution_indices[1] = 1; // b (opposite) - s_solution_indices[2] = 0; // a (hypotenuse) - } else { // csc - s_solution_indices[1] = 0; // a (hypotenuse) - s_solution_indices[2] = 1; // b (opposite) - } - } else { - s_solution_indices[0] = 1; - if (cos_index == 0) { // cos - s_solution_indices[1] = 1; // b (adjacent) - s_solution_indices[2] = 0; // a (hypotenuse) - } else { // sec - s_solution_indices[1] = 0; // a (hypotenuse) - s_solution_indices[2] = 1; // b (adjacent) - } - } - } - text_layer_set_text(s_side_a_txt_layer, side_a_buffer); - text_layer_set_text(s_side_b_txt_layer, side_b_buffer); - text_layer_set_text(s_side_c_txt_layer, side_c_buffer); - - // drop menus - //// determine trigonometric function options - s_sin = s_sin_arr[sin_index]; - s_cos = s_cos_arr[cos_index]; - s_tan = s_tan_arr[tan_index]; - //// set up menu options - s_options_function[0] = s_sin; - s_options_function[1] = s_cos; - s_options_function[2] = s_tan; - //// create drop window + // drop window s_drop_window = window_create(); window_set_window_handlers( s_drop_window, (WindowHandlers){.load = drop_menu_window_load, .unload = drop_menu_window_unload}); - // setup vibes - static const uint32_t VIBE_ON_FLOOR = 120; // ms: below this the motor never spins up - static const uint32_t VIBE_ON_SCALE = 4; - static const uint32_t VIBE_GAP = 40; // short off-time -> reads as continuous buzzing - s_vibe_segments[0] = VIBE_ON_FLOOR + (uint32_t)s_triangle_layer->angle_A * VIBE_ON_SCALE; - s_vibe_segments[1] = VIBE_GAP; - s_vibe_segments[2] = VIBE_ON_FLOOR + (uint32_t)s_triangle_layer->angle_B * VIBE_ON_SCALE; - s_vibe_segments[3] = VIBE_GAP; - s_vibe_segments[4] = VIBE_ON_FLOOR + (uint32_t)s_triangle_layer->angle_C * VIBE_ON_SCALE; - s_vibe_pattern = (VibePattern){ - .durations = s_vibe_segments, - .num_segments = ARRAY_LENGTH(s_vibe_segments), - }; - // countdown s_countdown_txt_layer = text_layer_create(GRect(0, (s_small_top_bar_height / 2) - PBL_IF_ROUND_ELSE(6, 10), PBL_DISPLAY_WIDTH, s_small_top_bar_height)); text_layer_set_background_color(s_countdown_txt_layer, GColorClear); text_layer_set_text_color(s_countdown_txt_layer, GColorWhite); text_layer_set_text_alignment(s_countdown_txt_layer, GTextAlignmentCenter); - s_awareness_countdown_int = settings.TriangeMinSecs; // TODO calculate max based on min and triangle count text_layer_set_font(s_countdown_txt_layer, s_font_lecoish_small); - snprintf(s_awareness_countdown_buf, sizeof(s_awareness_countdown_buf), "%03u", s_awareness_countdown_int); - text_layer_set_text(s_countdown_txt_layer, s_awareness_countdown_buf); layer_add_child(window_layer, text_layer_get_layer(s_countdown_txt_layer)); + + // configure UI around current triangle in s_triangle_layer + update_for_new_triangle(); + + // schedule recovery alarm and begin countdown :) schedule_alarm(WAKE_RECOVERY_ALARM); tick_timer_service_subscribe(SECOND_UNIT, awareness_alarm_seconds_handler); }