From db3294d89b24a84049d16e28d8da653b82dd7ac3 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Thu, 13 Aug 2026 23:20:37 -0400 Subject: [PATCH] Ensure no two sides are of the same length (makes selecting the answer really, really annoying lol) --- README.md | 2 +- src/c/triangles.c | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7c3a022..a6c9d7e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A habit-correcting alarm for heavy sleepers. Cannot be shut off until you solve ### Simple The app only has one page. You can only set one alarm. There is no snooze, there is no weekly schedule, and there is no way to disable the alarm (you'll always have one set - every day - like it or not). ### Persistent -The alarm cannot be stopped until you solve for theta in a randomized right triangle. Even if you force-close the app, it will re-open itself until you complete the equation. +The alarm cannot be stopped until you solve for theta in a randomized right triangle. Even if you force-close the app, it will re-open itself until you complete the equation. After you successfully disarm the alarm, it will open again (silently, no vibrations) in 9 minutes (standard snooze time) to verify you are still awake by having you solve another triangle. Fail to notice and solve it within a minute? Vibrations will resume and another alarm will be scheduled for 9 minutes after this one is solved. The alarm is not fully disarmed until the second, "awareness" alarm is solved within a minute of it appearing. ## Why Trigonometry? Because it requires the perfect amount of thought to activate your brain in the morning. If the app gave you a more typical math problem, you could just mindlessly punch it into a calculator. Trigonometry still requires a base amount of thought ("Do I need sine, cosine, or tangent?") before a calculator is of any use. diff --git a/src/c/triangles.c b/src/c/triangles.c index 14d7e54..d18cb59 100644 --- a/src/c/triangles.c +++ b/src/c/triangles.c @@ -45,21 +45,26 @@ RightTriangleLayer *right_triangle_layer_create(GRect frame, GColor color) { tri->color = color; // determine angles - tri->angle_A = 90; // right angle at apex - tri->angle_B = 5 + rand() % 81; // acute angle at left base vertex - tri->angle_C = 90 - tri->angle_B; // acute angle at right base vertex + tri->angle_A = 90; // right angle at apex tri->theta_angle_is_left = rand() % 2; - // choose hypotenuse length randomly uint16_t min_hyp = (frame.size.w < frame.size.h) ? frame.size.w / 2 : frame.size.h / 2; uint16_t max_hyp = (frame.size.w < frame.size.h) ? frame.size.w : frame.size.h; - tri->side_a = min_hyp + (rand() % (max_hyp - min_hyp + 1)); - // legs: side_b = hyp × sin(B), side_c = hyp × sin(C) = hyp × cos(B) - int32_t sin_B = sin_lookup(((int32_t)tri->angle_B * TRIG_MAX_ANGLE) / 360); - int32_t sin_C = sin_lookup(((int32_t)tri->angle_C * TRIG_MAX_ANGLE) / 360); - tri->side_b = (uint16_t)(((uint32_t)sin_B * tri->side_a) / TRIG_MAX_RATIO); - tri->side_c = (uint16_t)(((uint32_t)sin_C * tri->side_a) / TRIG_MAX_RATIO); + // regenerate until no two sides share a length + do { + tri->angle_B = 5 + rand() % 81; // acute angle at left base vertex + tri->angle_C = 90 - tri->angle_B; // acute angle at right base vertex + + // choose hypotenuse length randomly + tri->side_a = min_hyp + (rand() % (max_hyp - min_hyp + 1)); + + // legs: side_b = hyp × sin(B), side_c = hyp × sin(C) = hyp × cos(B) + int32_t sin_B = sin_lookup(((int32_t)tri->angle_B * TRIG_MAX_ANGLE) / 360); + int32_t sin_C = sin_lookup(((int32_t)tri->angle_C * TRIG_MAX_ANGLE) / 360); + tri->side_b = (uint16_t)(((uint32_t)sin_B * tri->side_a) / TRIG_MAX_RATIO); + tri->side_c = (uint16_t)(((uint32_t)sin_C * tri->side_a) / TRIG_MAX_RATIO); + } while (tri->side_a == tri->side_b || tri->side_a == tri->side_c || tri->side_b == tri->side_c); // create layer with room for a pointer-sized data slot & store the RightTriangleLayer* there tri->layer = layer_create_with_data(frame, sizeof(RightTriangleLayer *));