sav

Sorting Algorithms Visualized
Index Commits Files Refs README LICENSE
commit e8e9e2eb6739c670abd2da61e652887cca79f047
parent 27fae5ae15878b8f830d19228643544dd7b5187a
Author: klewer-martin <martin.cachari@gmail.com>
Date:   Thu, 14 Apr 2022 00:21:38 -0300

Added sav->sort_status, communication between threads changed

wait_main_thread() deprecated, before the child thread waited for the
main thread to updated the graphics, now the main thread updates the
graphics in every iteration while the child thread sorts the array.

A few keybindings where added, such as:
    - SPACE BAR: play/pause the sort
    - R: restart the sorting (only if the previos sort ends)

Diffstat:
Marray.c | 3+++
Mdrw.c | 97++++++++++++++++++++++---------------------------------------------------------
Mdrw.h | 10+++-------
Mmain.c | 61+++++++++++++++++++++++++++++++------------------------------
Msav.c | 7++++---
Msav.h | 6+++---
Msdl_extra.c | 12++++++------
Msdl_extra.h | 2+-
Msort.c | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mstatus.h | 1+
Mutil.c | 4++--
11 files changed, 158 insertions(+), 144 deletions(-)
diff --git a/array.c b/array.c
@@ -1,5 +1,6 @@
 #include "array.h"
 
+#include <stdio.h>
 #include <time.h>
 
 void
@@ -7,4 +8,6 @@ shuffle(Arr *arr) {
     srand((unsigned int)time(NULL));
     for(size_t i = 0; i < arr->len; i++)
         while(!(arr->v[i] = rand() % ARR_MAX));
+
+    printf("ARRAY: Shuffling array done\n");
 }
diff --git a/drw.c b/drw.c
@@ -38,7 +38,7 @@ drw_array_graph(Drw *drw, SAV *sav) {
         else if(i == sav->cmp) drw_element_color(drw, x, h, sav->arr->v[i], CMP_COLOR);
         else drw_element_color(drw, x, h, sav->arr->v[i], NORM_COLOR);
     }
-    /* drw_status_bar(drw, sav); */
+    drw_status_bar(drw, sav);
 }
 
 void
@@ -57,21 +57,31 @@ drw_status_bar(Drw *drw, SAV *sav) {
     SDL_SetRenderDrawColor(drw->rend, 0, 0, 0, 0); /* RGBA */
     SDL_RenderFillRect(drw->rend, &rect);
 
-    if(sav->status == UPDATE) {
-        /* sprintf(drw->bar_text, "Press SPACE to start sorting the array or ESC/q to quit"); */
-        snprintf(drw->bar_text, drw->bar_text_len - 2,
-                "SORTING (%s sort)     L: %ld, C: %ld, S: %ld",
-                algo_strings[sav->sel_algo], sav->arr->len, sav->cmps,
-                sav->swps);
-
-        drw_text(drw, drw->bar_text, 0, drw->h - drw->font_size - 5);
-    } else if(sav->status == SORTED) {
-        snprintf(drw->bar_text, drw->bar_text_len - 2,
-                "SORTED (%s sort) done in %.2fs, L: %ld, C: %ld, S: %ld, extra storage used: %ld Bytes",
-                algo_strings[sav->sel_algo],
-                (double)(sav->tf - sav->ti) / CLOCKS_PER_SEC,
-                sav->arr->len, sav->cmps, sav->swps, sav->B_used);
-
+    if((sav->status == RUN) || (sav->status == UPDATE) || (sav->status == START)) {
+        if(sav->sort_status == SORTED) {
+            snprintf(drw->bar_text, drw->bar_text_len - 2,
+                    "SORTED (%s sort) done in %.2fs, L: %ld, C: %ld, S: %ld, extra storage used: %ld Bytes",
+                    algo_strings[sav->sort_algo],
+                    (double)(sav->tf - sav->ti) / CLOCKS_PER_SEC,
+                    sav->arr->len, sav->cmps, sav->swps, sav->B_used);
+        } else if(sav->sort_status == PAUSE) {
+            if(sav->status == START) {
+                snprintf(drw->bar_text, drw->bar_text_len - 2,
+                        "Welcome to sorting algorithms visualized - (%s sort selected) press SPACE to start sorting",
+                        algo_strings[sav->sort_algo], sav->arr->len, sav->cmps,
+                        sav->swps);
+            } else {
+                snprintf(drw->bar_text, drw->bar_text_len - 2,
+                        "PAUSED (%s sort) press SPACE to resume",
+                        algo_strings[sav->sort_algo], sav->arr->len, sav->cmps,
+                        sav->swps);
+            }
+        } else {
+            snprintf(drw->bar_text, drw->bar_text_len - 2,
+                    "SORTING (%s sort)     L: %ld, C: %ld, S: %ld",
+                    algo_strings[sav->sort_algo], sav->arr->len, sav->cmps,
+                    sav->swps);
+        }
         drw_text(drw, drw->bar_text, 0, drw->h - drw->font_size - 5);
     }
     memset(drw->bar_text, 0, sizeof(char) * drw->bar_text_len);
@@ -159,61 +169,8 @@ void
 Drw_destroy(Drw *drw) {
     if(drw == NULL) return;
 
-    SDL_cleanup(drw->win, drw->rend);
     TTF_CloseFont(drw->font);
+    SDL_cleanup(drw->win, drw->rend);
     free(drw->bar_text);
     free(drw);
 }
-
-void drw_array_graph_sav_free(Drw *drw, Arr *arr) {
-    int x, w, h;
-
-    SDL_GetWindowSize(drw->win, &w, &h);
-
-    SDL_SetRenderDrawColor(drw->rend, 29, 28, 28, 0);
-    SDL_RenderClear(drw->rend);
-
-    size_t i;
-    for(i = x = 0; i < arr->len; i++, x += RECT_WIDTH) {
-        if(i == sav->sel) drw_element_color(drw, x, h, arr->v[i], SEL_COLOR);
-        else if(i == sav->cmp) drw_element_color(drw, x, h, arr->v[i], CMP_COLOR);
-        else drw_element_color(drw, x, h, arr->v[i], NORM_COLOR);
-    }
-    /* drw_status_bar(drw, sav); */
-}
-
-void
-void drw_status_bar_sav_free(Drw *drw, SAV *sav) {
-    SDL_Rect rect;
-    int bar_border = 2;
-
-    rect.x = bar_border; /* top left + x */
-    rect.y = drw->h - bar_border; /* top left + y, (y < 0) */
-    rect.w = drw->w - (2 * bar_border); /* fixed width */
-    rect.h = -BAR_HEIGHT;
-
-    SDL_RenderDrawRect(drw->rend, &rect);
-
-    /* TODO: Make a variable to store statusbar background color */
-    SDL_SetRenderDrawColor(drw->rend, 0, 0, 0, 0); /* RGBA */
-    SDL_RenderFillRect(drw->rend, &rect);
-
-    if(sav->status == UPDATE) {
-        /* sprintf(drw->bar_text, "Press SPACE to start sorting the array or ESC/q to quit"); */
-        snprintf(drw->bar_text, drw->bar_text_len - 2,
-                "SORTING (%s sort)     L: %ld, C: %ld, S: %ld",
-                algo_strings[sav->sel_algo], sav->arr->len, sav->cmps,
-                sav->swps);
-
-        drw_text(drw, drw->bar_text, 0, drw->h - drw->font_size - 5);
-    } else if(sav->status == SORTED) {
-        snprintf(drw->bar_text, drw->bar_text_len - 2,
-                "SORTED (%s sort) done in %.2fs, L: %ld, C: %ld, S: %ld, extra storage used: %ld Bytes",
-                algo_strings[sav->sel_algo],
-                (double)(sav->tf - sav->ti) / CLOCKS_PER_SEC,
-                sav->arr->len, sav->cmps, sav->swps, sav->B_used);
-
-        drw_text(drw, drw->bar_text, 0, drw->h - drw->font_size - 5);
-    }
-    memset(drw->bar_text, 0, sizeof(char) * drw->bar_text_len);
-}
diff --git a/drw.h b/drw.h
@@ -4,9 +4,8 @@
 #include <SDL2/SDL.h>
 #include <SDL2/SDL_ttf.h>
 
-/* #include "sav.h" */
+#include "sav.h"
 #include "util.h"
-/* #include "sort.h" */
 #include "sdl_extra.h"
 
 #define SEL_COLOR    0x00FF0000 // RGBA (A not used rn)
@@ -47,10 +46,7 @@ void drw_element(SDL_Renderer *rend, int x, int y, int h);
 void drw_element_color(Drw *drw, int x, int y, int h, unsigned int col);
 void drw_text(Drw *drw, char *text, int x, int y);
 
-/* void drw_array_graph(Drw *drw, SAV *sav); */
-/* void drw_status_bar(Drw *drw, SAV *sav); */
-
-void drw_array_graph_sav_free(Drw *, Arr *);
-void drw_status_bar_sav_free(Drw *drw, SAV *sav);
+void drw_array_graph(Drw *drw, SAV *sav);
+void drw_status_bar(Drw *drw, SAV *sav);
 
 #endif // __DRAW_H__
diff --git a/main.c b/main.c
@@ -14,13 +14,13 @@ void *
 routine_wrapper(void *arg) {
     SAV *sav = (SAV *)arg;
 
-    switch(sav->sel_algo) {
+    switch(sav->sort_algo) {
         case BUBBLE_SORT:  bubble_sort(sav); break;
         case INSERTION_SORT: insertion_sort(sav); break;
         case MERGE_SORT: merge_sort_wrapper(sav); break;
         case QUICK_SORT: quick_sort_wrapper(sav); break;
         default:  {
-            fprintf(stderr, "\"sel_algo\" not set. exiting\n");
+            fprintf(stderr, "\"sort_algo\" not set. exiting\n");
             sav->status = STOP;
             break;
         }
@@ -42,30 +42,29 @@ main (void) {
     /* assigns random values to array */
     shuffle(sav->arr);
 
+    /* selecting the sorting algorithms */
+    sav->sort_algo = BUBBLE_SORT;
+
     /* start sorting thread */
     pthread_create(&p1, NULL, &routine_wrapper, (void *)sav);
 
-    /* selecting the sorting algorithms */
-    sav->sel_algo = QUICK_SORT;
+
+    sav->status = START;
+    sav->sort_status = PAUSE;
 
     /* main loop */
-    sav->status = RUN;
     while(sav->status != STOP) {
-        /* check_events(drw, sav); */
-        if(sav->status == UPDATE) {
-            /* drw_array_graph(drw, sav); */
-            sav->status = RUN;
-            SDL_RenderPresent(drw->rend);
-        }
-        if(sav->status == SORTED) {
-            /* p1 ended */
-            /* drw_array_graph(drw, sav); */
-            SDL_RenderPresent(drw->rend);
-        }
-        if(sav->status == RESTART) {
+        check_events(drw, sav);
+
+        drw_array_graph(drw, sav);
+        drw_status_bar(drw, sav);
+        SDL_RenderPresent(drw->rend);
+
+        if((sav->sort_status == SORTED) && (sav->status == RESTART)) {
             /* this state can only be achived if p1 ended */
             shuffle(sav->arr);
             sav->status = RUN;
+            sav->sort_status = RUN;
 
             /* let's call p1 again */
             pthread_create(&p1, NULL, &routine_wrapper, (void *)sav);
@@ -85,22 +84,24 @@ check_events(Drw *drw, SAV *sav) {
     SDL_Event event;
     while (SDL_PollEvent(&event)) {
         switch(event.type) {
-        case SDL_QUIT: sav->status = STOP; break;
+        case SDL_QUIT:
+            sav->status = sav->sort_status = STOP;
+            break;
         case SDL_KEYDOWN:
             switch(event.key.keysym.scancode) {
-            /* case SDL_SCANCODE_EQUALS: */ 
-            /*     if(speed > SPEED_MAX) speed -= SPEED_STEP; */
-            /*     break; */
-            /* case SDL_SCANCODE_MINUS: */
-            /*     if(speed < SPEED_MIN) speed += SPEED_STEP; */
-            /*     break; */
-            /* case SDL_SCANCODE_P: */
-            /*     if(status == PAUSE) *status = RUN; */
-            /*     else *status = PAUSE; */
-            /*     break; */
             case SDL_SCANCODE_R:
-                if(sav->status == SORTED) sav->status = RESTART;
-                else break;
+                if(sav->sort_status == SORTED) sav->status = RESTART;
+                break;
+            /* case SDL_SCANCODE_S: */
+            /*     shuffle(sav->arr); */
+            /*     break; */
+            case SDL_SCANCODE_SPACE:
+                printf("status: %d, sort_status: %d\n", sav->status, sav->sort_status);
+                /* if(sav->status == START) sav->status = sav->sort_status = RUN; */
+                if(sav->sort_status == PAUSE) sav->status = sav->sort_status = RUN;
+                else if(sav->sort_status == RUN) sav->sort_status = PAUSE;
+
+                break;
             default: break;
            }
         case SDL_WINDOWEVENT:
diff --git a/sav.c b/sav.c
@@ -12,10 +12,11 @@ SAV_new(SAV **sav) {
     if((*sav = (SAV *)malloc(sizeof(SAV))) == NULL)
         return ERROR_MEMORY_ALLOC;
 
-    (*sav)->sel = (*sav)->cmps = (*sav)->swps = (*sav)->its = (*sav)->B_used = 0;
-    (*sav)->cmp = ARR_MAX + 1;
+    (*sav)->sel = (*sav)->cmp = ARR_MAX + 1;
+    (*sav)->cmps = (*sav)->swps = (*sav)->its = (*sav)->B_used = 0;
     (*sav)->status = RUN;
-    (*sav)->sel_algo = SORT_MAX_ALGORITHMS;
+    (*sav)->sort_status = PAUSE;
+    (*sav)->sort_algo = SORT_MAX_ALGORITHMS;
 
     if(((*sav)->arr = (Arr *)malloc(sizeof(Arr))) == NULL)
         return ERROR_MEMORY_ALLOC;
diff --git a/sav.h b/sav.h
@@ -7,7 +7,6 @@
 #include <time.h>
 #include <SDL2/SDL.h>
 
-#include "drw.h"
 #include "util.h"
 #include "array.h"
 
@@ -24,8 +23,9 @@ typedef struct {
     size_t sel, cmp, cmps, swps, its, B_used;
     clock_t ti, tf;
     status_t status;
-    sort_t sel_algo;
-} SAV; // Sort?
+    status_t sort_status;
+    sort_t sort_algo;
+} SAV; 
 
 extern char *algo_strings[SORT_MAX_ALGORITHMS];
 
diff --git a/sdl_extra.c b/sdl_extra.c
@@ -12,15 +12,15 @@ SDL_setup(SDL_Window **win, SDL_Renderer **rend) {
         SDL_WINDOWPOS_UNDEFINED,
         0,
         0,
-        SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_UTILITY
+        SDL_WINDOW_RESIZABLE | SDL_WINDOW_UTILITY
     );
 
     *rend = SDL_CreateRenderer(*win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
 
-    /* TODO: return error codes */
-    if (*win == NULL) return ERROR_NULL_POINTER;
-    else if (*rend == NULL) return ERROR_NULL_POINTER;
-    else if(TTF_Init() == -1) return ERROR_SDL_FONT_INIT;
+    if ((*win == NULL) || (rend == NULL))
+        return ERROR_NULL_POINTER;
+    else if(TTF_Init() == -1)
+        return ERROR_SDL_FONT_INIT;
 
     SDL_SetRenderDrawColor(*rend, 32, 32, 32, 0);
     SDL_RenderClear(*rend);
@@ -37,7 +37,7 @@ SDL_setup(SDL_Window **win, SDL_Renderer **rend) {
 
 status_t
 SDL_cleanup(SDL_Window *win, SDL_Renderer *rend) {
-    if(win == NULL || rend == NULL)
+    if((win == NULL) || (rend == NULL))
         return ERROR_NULL_POINTER;
 
     SDL_DestroyRenderer(rend);
diff --git a/sdl_extra.h b/sdl_extra.h
@@ -14,7 +14,7 @@
 #define TOP_BORDER    50
 #define RECT_WIDTH    5
 
-#define WIN_TITLE "SAV - Sorting Algorithms Visualized"
+#define WIN_TITLE "SAV: Sorting Algorithms Visualized"
 
 status_t SDL_setup(SDL_Window **win, SDL_Renderer **rend);
 status_t SDL_cleanup(SDL_Window *win, SDL_Renderer *rend);
diff --git a/sort.c b/sort.c
@@ -4,11 +4,16 @@
 
 #include "sort.h"
 
+#define DELAY    5
+
 void
 insertion_sort(SAV *sav) {
     int key;
     size_t i, j;
 
+    if((sav->sort_status == STOP) || (sav->status == STOP)) return;
+    while(sav->sort_status == PAUSE);
+
     sav->ti = clock();
     for(i = 1; i < sav->arr->len; i++, sav->its++) {
         sav->cmps += 1;
@@ -23,29 +28,43 @@ insertion_sort(SAV *sav) {
             sav->cmp = j;
             sav->its++;
 
-            /* wait 'til main thread updates graphics */
-            wait_main_thread(&(sav->status));
-            if(sav->status == STOP) break;
+            /* Delay */
+            for(size_t i = 0; i < DELAY; i++) {
+                if((sav->sort_status == STOP) || (sav->status == STOP))
+                    goto end;
+
+                SDL_Delay(1);
+            }
+            while(sav->sort_status == PAUSE);
         }
         sav->arr->v[j + 1] = key;
         sav->sel = i;
         sav->cmp = j;
         sav->swps += 1;
 
-        /* wait 'til main thread updates graphics */
-        wait_main_thread(&(sav->status));
-        if(sav->status == STOP) break;
+        /* Delay */
+        for(size_t i = 0; i < DELAY; i++) {
+            if((sav->sort_status == STOP) || (sav->status == STOP))
+                goto end;
+
+            SDL_Delay(1);
+        }
+        while(sav->sort_status == PAUSE);
     }
+    end:
 
     sav->tf = clock();
 
-    if(sav->status != STOP) sav->status = SORTED;
+    if(sav->status != STOP) sav->sort_status = SORTED;
 }
 
 void
 bubble_sort(SAV *sav) {
     size_t i, j;
 
+    if((sav->sort_status == STOP) || (sav->status == STOP)) return;
+    while(sav->sort_status == PAUSE);
+
     sav->ti = clock();
     for(i = 0; i < sav->arr->len - 1; i++, sav->its++) {
         for(j = 0; j < (sav->arr->len - 1 - i); j++, sav->its++) {
@@ -57,21 +76,38 @@ bubble_sort(SAV *sav) {
                 sav->swps += 1;
             }
 
-            /* wait 'til main thread updates graphics */
-            wait_main_thread(&(sav->status));
-            if(sav->status == STOP) break;
+            /* Delay */
+            for(size_t i = 0; i < DELAY; i++) {
+                if((sav->sort_status == STOP) || (sav->status == STOP))
+                    goto end;
+
+                SDL_Delay(1);
+            }
+            while(sav->sort_status == PAUSE);
         }
-        wait_main_thread(&(sav->status));
-        if(sav->status == STOP) break;
+
+        /* Delay */
+        for(size_t i = 0; i < DELAY; i++) {
+            if((sav->sort_status == STOP) || (sav->status == STOP))
+                goto end;
+
+            SDL_Delay(1);
+        }
+        while(sav->sort_status == PAUSE);
     }
+    end:
+
     sav->tf = clock();
-    if(sav->status != STOP) sav->status = SORTED;
+    if(sav->status != STOP) sav->sort_status = SORTED;
 }
 
 void
 merge(SAV *sav, int low, int middle, int high) {
     size_t n1, n2, i, j, k;
 
+    if((sav->sort_status == STOP) || (sav->status == STOP)) return;
+    while(sav->sort_status == PAUSE);
+
     n1 = middle - low;
     n2 = high - middle;
 
@@ -97,9 +133,17 @@ merge(SAV *sav, int low, int middle, int high) {
         sav->cmps += 1;
         sav->its += 1;
 
-        wait_main_thread(&(sav->status));
-        if(sav->status == STOP) return;
+        while(sav->sort_status == PAUSE);
+
+        /* Delay */
+        for(size_t i = 0; i < DELAY; i++) {
+            if((sav->sort_status == STOP) || (sav->status == STOP))
+                goto end;
+
+            SDL_Delay(1);
+        }
     }
+    end:
 
     while(i < n1)
         sav->arr->v[k++] = B[i++];
@@ -112,6 +156,11 @@ void
 merge_sort(SAV *sav, int low, int high) {
     if(sav == NULL) return;
 
+    if((sav->sort_status == STOP) || (sav->status == STOP))
+        return;
+
+    while(sav->sort_status == PAUSE);
+
     int middle;
 
     middle = ((high + low) / 2);
@@ -134,7 +183,7 @@ void merge_sort_wrapper(SAV *sav) {
     merge_sort(sav, 0, sav->arr->len);
     sav->tf = clock();
     sav->sel = sav->arr->len + 1;
-    if(sav->status != STOP) sav->status = SORTED;
+    if(sav->status != STOP) sav->sort_status = SORTED;
 }
 
 void
@@ -143,7 +192,7 @@ quick_sort_partition(SAV *sav, int low, int *middle, int high) {
 
     pivot = high;
     sav->sel = pivot;
-    printf("SORT: pivot: %d\n", pivot);
+    /* printf("SORT: pivot: %d\n", pivot); */
 
     for(i = j = low; j < high; j++, sav->cmps += 1) {
         if(sav->arr->v[j] < sav->arr->v[pivot]) {
@@ -151,9 +200,15 @@ quick_sort_partition(SAV *sav, int low, int *middle, int high) {
             sav->swps += 1;
         }
 
-        wait_main_thread(&(sav->status));
-        if(sav->status == STOP) return;
+        if(sav->status != STOP) sav->status = UPDATE;
+        while(sav->sort_status == PAUSE);
+
+        for(size_t i = 0; i < 5; i++) {
+            if(sav->sort_status == STOP) goto end;
+            SDL_Delay(1);
+        }
     }
+    end:
 
     swap(&(sav->arr->v[i]), &(sav->arr->v[pivot]));
     sav->swps += 1;
@@ -165,8 +220,7 @@ quick_sort(SAV *sav, int low, int high) {
     int pivot;
 
     if(sav->status == STOP) return;
-    else if(sav->status == PAUSE)
-        wait_main_thread(&(sav->status));
+    while(sav->sort_status == PAUSE);
 
     if ((high - low) > 0) {
         quick_sort_partition(sav, low, &pivot, high);
@@ -179,6 +233,7 @@ void
 quick_sort_wrapper(SAV *sav) {
     sav->ti = clock();
     quick_sort(sav, 0, sav->arr->len - 1);
-    sav->status = SORTED;
+    printf("SORT: sorting array done\n");
+    if(sav->sort_status != STOP) sav->sort_status = SORTED;
     sav->tf = clock();
 }
diff --git a/status.h b/status.h
@@ -12,6 +12,7 @@ typedef enum {
     ERROR_NULL_POINTER,
     ERROR_DRW,
     SORTED,
+    START,
     RESTART,
     STOP
 } status_t;
diff --git a/util.c b/util.c
@@ -2,10 +2,10 @@
 
 void
 wait_main_thread(status_t *st) {
-    if(*st != STOP) *st = UPDATE;
+    if((*st != STOP) && (*st != PAUSE)) *st = UPDATE;
 
     /* wait 'til main thread changes st value to RUN */
-    while(*st == UPDATE);
+    while((*st == UPDATE) || (*st == PAUSE));
 }
 
 void