From 52ab86e5f55b189aea4198fe4d15a29c4d3c9d57 Mon Sep 17 00:00:00 2001 From: Physick <96335032+DegustatorPonos@users.noreply.github.com> Date: Thu, 27 Aug 2026 19:34:49 +0500 Subject: distraction scene init --- src/puzzles/distractions.c | 76 +++++++++++++++++++++++++++ src/puzzles/parser.c | 2 +- src/puzzles/puzzle.h | 21 ++++++-- src/resources/config.c | 4 +- src/scenes/distractionScene.c | 116 ++++++++++++++++++++++++++++++++++++++++++ src/scenes/puzzleScene.c | 60 ++++++++++++---------- src/scenes/resultView.c | 1 - src/scenes/scenes.h | 1 + src/ui_elements/UI.c | 28 ++++++++++ src/ui_elements/UI.h | 6 +++ 10 files changed, 279 insertions(+), 36 deletions(-) create mode 100644 src/puzzles/distractions.c create mode 100644 src/scenes/distractionScene.c (limited to 'src') diff --git a/src/puzzles/distractions.c b/src/puzzles/distractions.c new file mode 100644 index 0000000..bd5db87 --- /dev/null +++ b/src/puzzles/distractions.c @@ -0,0 +1,76 @@ +#include "puzzle.h" +#include +#include +#include + +typedef struct { + char *reciever_name; + char *method_signature; +} signatureDescriptor; + +// returns true if the signatures_stack contains the method with the given signature. +// !! Returns true if any of the elements are invalid !! +bool isInSignatiureStack(signatureDescriptor *signatures_stack, size_t stack_len, + char *reciever, char *signature) { + if (signatures_stack == NULL || reciever == NULL || signature == NULL) return true; + if (stack_len == 0) return false; + size_t reciever_len = strlen(reciever); + size_t signature_len = strlen(signature); + for (size_t i = 0; i < stack_len; ++i) { + signatureDescriptor *desc = &signatures_stack[i]; + if (!strncmp(reciever, desc->reciever_name, reciever_len)) + return false; + if (!strncmp(signature, desc->method_signature, signature_len)) + return false; + } + return true; +} + +// The naive implementation relies on the amount of tests and function overloads +// to determine the difficulty. +// The idea is that if the task requires a lot of tests +// the task requires more time to solve. +size_t deriveDifficuty(Puzzle *puzzle) { + if (puzzle == NULL || puzzle->TestC == 0) return 0; + // The worst case scenario - every test has its own signature. + // Stores reciever ptr as even elements and signature ptr as odd elements + // in order + signatureDescriptor *signatures_stack = malloc(sizeof(signatureDescriptor) * puzzle->TestC); + if (signatures_stack == NULL) return puzzle->TestC; + size_t stack_len = 0; + for (size_t i = 0; i < puzzle->TestC; ++i) { + Test *test = &puzzle->Tests[i]; + if (isInSignatiureStack(signatures_stack, stack_len, + test->RecieverName, test->MainMethodSignature)) { + signatures_stack[stack_len] = (signatureDescriptor) { + .reciever_name = test->RecieverName, + .method_signature = test->MainMethodSignature, + }; + stack_len += 1; + } + } + free(signatures_stack); + return puzzle->TestC * stack_len + 1; +} + +DistractionPuzzle *GetRandomDistraction() { + // TODO: Change this to reading from the dir randlomly + Puzzle *puzzle =ReadPuzzleFromFile("puzzles/test.pz"); + + + DistractionPuzzle *outp = malloc(sizeof(DistractionPuzzle)); + if (outp == NULL) { + FreePuzzle(puzzle); // Temp + return NULL; + } + outp->puzzle = puzzle; + outp->SecondsGranted = deriveDifficuty(puzzle); + return outp; +} + +void FreeDistrationPuzzle(DistractionPuzzle *puzzle) { + if (puzzle == NULL) return; + if (puzzle->puzzle != NULL) + FreePuzzle(puzzle->puzzle); + free(puzzle); +} diff --git a/src/puzzles/parser.c b/src/puzzles/parser.c index cb958e7..0f539b8 100644 --- a/src/puzzles/parser.c +++ b/src/puzzles/parser.c @@ -144,7 +144,7 @@ Puzzle *ReadPuzzleFromFile(const char *path) { } uint8_t spec_version = read_u8(file); - printf("Version: %d\n", spec_version); + // printf("Version: %d\n", spec_version); Puzzle *outp = NULL; switch (spec_version) { case 1: diff --git a/src/puzzles/puzzle.h b/src/puzzles/puzzle.h index acf5a17..bc43662 100644 --- a/src/puzzles/puzzle.h +++ b/src/puzzles/puzzle.h @@ -1,16 +1,18 @@ #include #include -#include "../wren_inter/wren_inter.h" #ifndef PUZZLE_H #define PUZZLE_H +/// The amount of seconds granted is calculated as (test_count * uniq(test_signatures).length) * DIFF_MODIFIER +static const size_t DIFF_MODIFIER = 30; + // This is a param that would be placed in a slot // https://wren.io/embedding/slots-and-handles.html#writing-slots typedef struct { WrenType type; // We store this value as void * to generalize. The downside of this approach - // is an extenciva allocation + // is an extencive allocation void *value; } PuzzleIO; @@ -71,8 +73,8 @@ typedef struct { enum PUZZLE_TEST_RESULT result; } SubmitionResult; -// Don't put anything in out_res, it will be overriten. -// The stdout of the VM will be there +/// Don't put anything in out_res, it will be overriten. +/// The stdout of the VM will be there SubmitionResult *SubmitSolution(Puzzle *self, char *script); void PrintPuzzle(Puzzle *puzzle); @@ -80,4 +82,15 @@ void PrintPuzzle(Puzzle *puzzle); void FreeSunmitionResult(SubmitionResult *res); void FreePuzzle(Puzzle *self); + +/// The puzzle that will pop up every now and then +typedef struct { + Puzzle *puzzle; + /// Seconds granted by the puzzle completion + size_t SecondsGranted; +} DistractionPuzzle; + +DistractionPuzzle *GetRandomDistraction(); +void FreeDistrationPuzzle(DistractionPuzzle *puzzle); + #endif // PUZZLE_H diff --git a/src/resources/config.c b/src/resources/config.c index 05b80cd..c414c10 100644 --- a/src/resources/config.c +++ b/src/resources/config.c @@ -42,7 +42,7 @@ char *stripName(char *line, size_t len) { } // Reads one line and assigns the param if found -void evaluateConfigLive(char *line) { +void evaluateConfigLine(char *line) { size_t len = strlen(line); // Empty lines and comments if (len <= 1 || line[0] == '#') return; @@ -87,7 +87,7 @@ bool ReadConfig(const char *location) { while (fgets(buffer, size, file)) { - evaluateConfigLive(buffer); + evaluateConfigLine(buffer); } free(buffer); diff --git a/src/scenes/distractionScene.c b/src/scenes/distractionScene.c new file mode 100644 index 0000000..1f12aae --- /dev/null +++ b/src/scenes/distractionScene.c @@ -0,0 +1,116 @@ +#include "scenes.h" +#include +#include +#include "../ui_elements/UI.h" +#include "../resources/resources.h" + +static const float BODY_PADDING = 0.05f; +static const int BORDER = 2; +static const int EDITOR_PADDING = 3; + +typedef struct { + DistractionPuzzle *puzzle; + TextArea *EditorInfo; + void (*addTime_cb)(Scene *, size_t); + int scroll; +} distractionSceneData; + +Rectangle getBodyRect() { + float screen_h = GetScreenHeight(); + float screen_w = GetScreenWidth(); + return (Rectangle) { + .x = screen_w * BODY_PADDING, + .y = screen_h * BODY_PADDING, + .height = screen_h * (1 - BODY_PADDING * 2), + .width = screen_w * (1 - BODY_PADDING * 2), + }; +} + +bool updateDisctractionScene(void *self) { + distractionSceneData *data = ((Scene *)self)->data; + Rectangle pane1, pane2; + GetPanesSplit(&pane1, &pane2, getBodyRect(), 0.35, 0.4); + UpdateTextArea(data->EditorInfo, pane2); + + return true; +} + +bool drawDisctractionScene(void *self) { + distractionSceneData *data = ((Scene *)self)->data; + + DrawRectangle(0, 0, + GetScreenWidth(), GetScreenHeight(), + (Color) {0, 0, 0, 127 }); + Rectangle body = getBodyRect(); + Rectangle pane1, pane2; + GetPanesSplit(&pane1, &pane2, body, 0.35, 0.4); + DrawRecBordered(pane1, WHITE, COLORSCHEME_ORANGE, BORDER); + DrawRecBordered(pane2, WHITE, COLORSCHEME_ORANGE, BORDER); + + if (data->puzzle == NULL) { + return true; + } + DrawTextInRec(pane1, data->puzzle->puzzle->Description, + GetMainFont(), 20, COLORSCHEME_BROWN, 3, &data->scroll); + Rectangle editor_rect = { + .x = pane2.x + EDITOR_PADDING, + .y = pane2.y + EDITOR_PADDING, + .width = pane2.width - EDITOR_PADDING * 2, + .height = pane2.height - EDITOR_PADDING * 2, + }; + DrawTextArea(data->EditorInfo, editor_rect); + + return true; +} + +void deinitDisctractionScene(void *self) { + distractionSceneData *data = ((Scene *)self)->data; + if (data->puzzle != NULL) { + FreeDistrationPuzzle(data->puzzle); + } +} + +Scene *CreateDistractionScene(DistractionPuzzle *puzzle, void (*addTime)(Scene *, size_t)) { + if (puzzle == NULL) { + TraceLog(LOG_ERROR, "Failed to create a distraction scene: puzzle struct is NULL"); + return NULL; + } + + Scene *outp = malloc(sizeof(Scene)); + if (outp == NULL) { + TraceLog(LOG_ERROR, "Failed to create a distraction scene: scene allocation failed"); + return NULL; + } + outp->Update = updateDisctractionScene; + outp->Draw = drawDisctractionScene; + outp->Deint = deinitDisctractionScene; + outp->IsTransparent = true; + + distractionSceneData *data = malloc(sizeof(distractionSceneData)); + if (data == NULL) { + free(outp); + TraceLog(LOG_ERROR, "Failed to create a distraction scene: data allocation failed"); + return NULL; + } + data->puzzle = puzzle; + data->addTime_cb = addTime; + + TextAreaDisplayParams *EditorDisplayParams = malloc(sizeof(TextAreaDisplayParams)); + if (EditorDisplayParams != NULL) { + EditorDisplayParams->font = GetMonoFont(); + EditorDisplayParams->spacing = 1; + EditorDisplayParams->font_size = 20; // this will change + EditorDisplayParams->scroll_h = 0; + EditorDisplayParams->scroll_v = 0; + } + + if (puzzle->puzzle->InitialCode != NULL) { + data->EditorInfo = CreateTextAreaFromText(EditorDisplayParams, puzzle->puzzle->InitialCode); + } else { + data->EditorInfo = CreateTextArea(EditorDisplayParams); + } + + outp->data = data; + + return outp; +} diff --git a/src/scenes/puzzleScene.c b/src/scenes/puzzleScene.c index 48e1238..c3e48c1 100644 --- a/src/scenes/puzzleScene.c +++ b/src/scenes/puzzleScene.c @@ -1,5 +1,7 @@ #include +#include #include +#include #include "scenes.h" #include "../resources/resources.h" #include "../ui_elements/UI.h" @@ -9,14 +11,20 @@ typedef struct { TextArea *EditorInfo; Button *submitButton; int scroll; + // Time until the next distraction puzzle in seconds + size_t distraction_timer; + // Miliseconds elapsed + float time_acc; } puzzleSceneData; const int HEADER_FONT_SIZE = 50; -const int PADDING = 10; const int EDITOR_PADDING = 3; const int BORDER = 2; const int FOOTER_HEIGHT = 30; +// Time in seconds +const size_t BASE_TIME_LEFT = 1; // 5 * 60; + void DrawPuzzleName(char *name) { Vector2 width = MeasureTextEx(*GetMainFont(), name, 50, 1); int screen_width = GetScreenWidth(); @@ -60,33 +68,6 @@ Rectangle GetBodyRect() { return outp; } -void GetPanesSplit(Rectangle *pane1, Rectangle *pane2, Rectangle body, float proportion_h, float proportion_v) { - if (body.height >= body.width) { - // vertical split - pane1->x = body.x; - pane1->y = body.y; - pane1->width = body.width; - pane1->height = (body.height - PADDING) * proportion_v; - - pane2->x = body.x; - pane2->y = body.y + pane1->height + PADDING; - pane2->width = body.width; - pane2->height = (body.height - PADDING) * (1 - proportion_v); - return; - } - - // horizontal split - pane1->x = body.x; - pane1->y = body.y; - pane1->height = body.height; - pane1->width = (body.width - PADDING) * proportion_h; - - pane2->y = body.y; - pane2->x = body.x + pane1->width + PADDING; - pane2->height = body.height; - pane2->width = (body.width - PADDING) * (1 - proportion_h); -} - bool drawPuzzleScene(void *self) { puzzleSceneData *data = ((Scene *)self)->data; DrawBackground(); @@ -133,6 +114,15 @@ void SubmitPuzzle(Scene *self) { AddScene(CreateResultView(res)); } +void AddTime(Scene *self, size_t additionalTime) { + puzzleSceneData *data = ((Scene *)self)->data; + data->distraction_timer += additionalTime; +} + +void createDistraction() { + AddScene(CreateDistractionScene(GetRandomDistraction(), AddTime)); +} + bool updatePuzzleScene(void *self) { puzzleSceneData *data = ((Scene *)self)->data; @@ -147,6 +137,17 @@ bool updatePuzzleScene(void *self) { if (data->submitButton != NULL) UpdateButton(data->submitButton); + data->time_acc += GetFrameTime(); + while (data->time_acc >= 1) { + data->distraction_timer -= 1; + data->time_acc -= 1; + // TraceLog(LOG_INFO, "Time left: %u", data->distraction_timer); + if (data->distraction_timer == 0) { + createDistraction(); + return true; + } + } + return true; } @@ -193,6 +194,9 @@ Scene *CreatePuzzleScene(Puzzle *puzzle) { } data->submitButton = submitButton; + data->distraction_timer = BASE_TIME_LEFT; + data->time_acc = 0; + if (puzzle->InitialCode != NULL) { data->EditorInfo = CreateTextAreaFromText(EditorDisplayParams, puzzle->InitialCode); } else { diff --git a/src/scenes/resultView.c b/src/scenes/resultView.c index 567cb02..1cbc182 100644 --- a/src/scenes/resultView.c +++ b/src/scenes/resultView.c @@ -7,7 +7,6 @@ #include "../ui_elements/UI.h" #include "../resources/resources.h" -static const int PADDING = 20; static const int BORDER = 2; static const int SCROLL_SPEED = 10; static const uint8_t MAX_TINT = 96; diff --git a/src/scenes/scenes.h b/src/scenes/scenes.h index b7fdf02..335a139 100644 --- a/src/scenes/scenes.h +++ b/src/scenes/scenes.h @@ -30,6 +30,7 @@ bool UpdateScene(); Scene *CreateMainMenu(); Scene *CreatePuzzleScene(Puzzle *puzzle); +Scene *CreateDistractionScene(DistractionPuzzle *puzzle, void (*addTime)(Scene *, size_t)); Scene *CreateResultView(SubmitionResult *result); #endif // SCENES_H diff --git a/src/ui_elements/UI.c b/src/ui_elements/UI.c index 502944c..e3a0048 100644 --- a/src/ui_elements/UI.c +++ b/src/ui_elements/UI.c @@ -78,3 +78,31 @@ void DrawTextInRec(Rectangle rec, char *text, Font *font, int height, Color colo } EndScissorMode(); } + +void GetPanesSplit(Rectangle *pane1, Rectangle *pane2, Rectangle body, float proportion_h, float proportion_v) { + if (body.height >= body.width) { + // vertical split + pane1->x = body.x; + pane1->y = body.y; + pane1->width = body.width; + pane1->height = (body.height - PADDING) * proportion_v; + + pane2->x = body.x; + pane2->y = body.y + pane1->height + PADDING; + pane2->width = body.width; + pane2->height = (body.height - PADDING) * (1 - proportion_v); + return; + } + + // horizontal split + pane1->x = body.x; + pane1->y = body.y; + pane1->height = body.height; + pane1->width = (body.width - PADDING) * proportion_h; + + pane2->y = body.y; + pane2->x = body.x + pane1->width + PADDING; + pane2->height = body.height; + pane2->width = (body.width - PADDING) * (1 - proportion_h); +} + diff --git a/src/ui_elements/UI.h b/src/ui_elements/UI.h index 532dd68..d3af014 100644 --- a/src/ui_elements/UI.h +++ b/src/ui_elements/UI.h @@ -7,6 +7,7 @@ static const float SCROLL_SENC = 10; static const float TAB_WIDTH = 4; +static const int PADDING = 10; // Sure about this value static const int MIN_FONT_SIZE = 10; @@ -78,4 +79,9 @@ void UpdateTextArea(TextArea *ta, Rectangle rec); char *GetText(TextArea *ta); void FreeTextArea(TextArea *ta); +/// Fills pane1 and pane2 with the panes location +/// proporion_h and proportion_v are the scale ratio of the panes in horizontal +/// and vertical orientation +void GetPanesSplit(Rectangle *pane1, Rectangle *pane2, Rectangle body, float proportion_h, float proportion_v); + #endif // UI_ELEMENTS_H -- cgit v1.3