From ec5f4f6543360e5d0e2a2e8d697b344a1e92c0fe Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Thu, 12 Dec 2024 19:59:08 +0200 Subject: [PATCH] add sorter with respecting testcase collections --- Makefile | 7 +- inc/sorter.h | 1 + src/sorter.c | 44 +++++++++++ src/tester.c | 141 ++++++++++++++++++++++++++++------- test/testcases_sort_custom | 2 + test/testcases_sort_official | 5 ++ test/testcases_sort_wrong | 1 + 7 files changed, 174 insertions(+), 27 deletions(-) create mode 100644 inc/sorter.h create mode 100644 src/sorter.c create mode 100644 test/testcases_sort_custom create mode 100644 test/testcases_sort_official create mode 100644 test/testcases_sort_wrong diff --git a/Makefile b/Makefile index 97b715d..80d1d81 100644 --- a/Makefile +++ b/Makefile @@ -4,12 +4,15 @@ build: main test: tester -tester: out/tester.o out/swapper.o - gcc $(CFLAGS) out/tester.o out/swapper.o -o tester +tester: out/tester.o out/sorter.o + gcc $(CFLAGS) out/tester.o out/sorter.o -o tester out/tester.o: out/ src/tester.c gcc $(CFLAGS) -c src/tester.c -o out/tester.o +out/sorter.o: out/ src/sorter.c + gcc $(CFLAGS) -c src/sorter.c -o out/sorter.o + out/: mkdir out/ diff --git a/inc/sorter.h b/inc/sorter.h new file mode 100644 index 0000000..b51decc --- /dev/null +++ b/inc/sorter.h @@ -0,0 +1 @@ +void sorter_insertion_sort(char **arr, int size); diff --git a/src/sorter.c b/src/sorter.c new file mode 100644 index 0000000..2a49b7b --- /dev/null +++ b/src/sorter.c @@ -0,0 +1,44 @@ +#include +#include "sorter.h" + +#define MIN(a, b) ( ((a) < (b)) ? (a) : (b) ) + +static int lt(char *a, char *b) +{ + int len_a = strlen(a); + int len_b = strlen(b); + + for (int i = 0; i < MIN(len_a, len_b); i++) { + if (a[i] < b[i]) + return 1; + else if (a[i] > b[i]) + return -1; + } + + return (len_a > len_b); +} + +static void swap(char **arr, int x, int y) +{ + char *tmp = arr[x]; + arr[x] = arr[y]; + arr[y] = tmp; +} + +void sorter_insertion_sort(char **arr, int len) +{ + for (int i = 0; i < len-1; i++) { + char *min = arr[i]; + int min_index = i; + + for (int j = i+1; j < len; j++) { + if (lt(arr[j], min) == 1) { + min_index = j; + min = arr[j]; + } + } + + if (min_index != i) + swap(arr, i, min_index); + } +} diff --git a/src/tester.c b/src/tester.c index a8ecafd..c96ef8e 100644 --- a/src/tester.c +++ b/src/tester.c @@ -1,12 +1,14 @@ #include +#include +#include #include #include -#include "swapper.h" +#include "sorter.h" enum read_state { LEN = 0, - STR1 = 1, - STR2 = 2, + ARR1 = 1, + ARR2 = 2, FINISH = 3, IMPOSSIBLE_STATE = 4 }; @@ -44,30 +46,55 @@ static int read_more(int f, char *buf, int bytes_read) return 1024 - bytes_read + new_bytes; } -static int parse_case(char *cmd, int *target_length_diff, char *str_a, char *str_b) +static int parse_case(char *cmd, int *array_size, char ***a, char ***b) { int bytes_read; int write_offset = 0; + int array_offset = 0; char len_buffer[4] = {0}; enum read_state rs = LEN; for (bytes_read = 0; bytes_read < 1024; bytes_read++) { switch (cmd[bytes_read]) { + case ',': + switch (rs) { + case ARR1: + (*a)[array_offset][write_offset] = '\0'; + break; + case ARR2: + (*b)[array_offset][write_offset] = '\0'; + break; + } + + write_offset = 0; + array_offset++; + break; + case ' ': switch (rs) { case LEN: - *target_length_diff = to_int(len_buffer); + *array_size = to_int(len_buffer); + + *a = (char **) malloc(sizeof(char *) * (*array_size)); + *b = (char **) malloc(sizeof(char *) * (*array_size)); + + for (int i = 0; i < *array_size; i++) { + (*a)[i] = malloc(sizeof(char) * 128); + (*b)[i] = malloc(sizeof(char) * 128); + } + break; - case STR1: - str_a[write_offset] = '\0'; + case ARR1: + (*a)[array_offset][write_offset] = '\0'; break; } rs++; write_offset = 0; + array_offset = 0; break; case '\n': - str_b[write_offset] = '\0'; + (*b)[array_offset][write_offset] = '\0'; bytes_read++; goto finish; break; @@ -77,11 +104,11 @@ static int parse_case(char *cmd, int *target_length_diff, char *str_a, char *str case LEN: len_buffer[write_offset] = cmd[bytes_read]; break; - case STR1: - str_a[write_offset] = cmd[bytes_read]; + case ARR1: + (*a)[array_offset][write_offset] = cmd[bytes_read]; break; - case STR2: - str_b[write_offset] = cmd[bytes_read]; + case ARR2: + (*b)[array_offset][write_offset] = cmd[bytes_read]; break; } write_offset++; @@ -93,30 +120,90 @@ static int parse_case(char *cmd, int *target_length_diff, char *str_a, char *str return bytes_read; } -static int assert_length(int test_id, int target_length_diff, char *a, char *b) +static void destroy_array(char **a, int array_size) { - int len_diff = swapper_length_difference(a, b); + for (int i = 0; i < array_size; i++) + free(a[i]); - if (len_diff == target_length_diff) { + free(a); +} + +static int cmp_arrays(int array_size, char **a, char **b) +{ + int mismatch_byte = 0; + + for (int i = 0; i < array_size; i++, mismatch_byte++) { + int la = strlen(a[i]); + int lb = strlen(b[i]); + + if (la != lb) + return mismatch_byte; + + for (int j = 0; j < la; j++, mismatch_byte++) { + if (a[i][j] != b[i][j]) + return mismatch_byte; + } + } + + return -1; +} + +static void print_array(int array_size, char **arr) +{ + for (int i = 0; i < array_size; i++) + printf("%s ", arr[i]); + + puts(""); +} + +static void print_mismatch(int position) +{ + for (int i = 0; i < position; i++) + fputs(" ", stdout); + + puts("^"); + + for (int i = 0; i < position; i++) + fputs(" ", stdout); + + puts("sort mismatch"); +} + +static int assert_sort(int test_id, int array_size, char **a, char **b) +{ + sorter_insertion_sort(a, array_size); + + int result = cmp_arrays(array_size, a, b); + + if (result == -1) { printf("[TEST#%02d] OK\r", test_id); return 0; } else { printf("\n[TEST#%02d] FAILED!\n", test_id); printf("Case details:\n"); - printf("Str1: %s\n", a); - printf("Str2: %s\n", b); - printf("Mismatch: %d expected, %d retrieved\n", target_length_diff, len_diff); + printf("Retrieved array: "); + print_array(array_size, a); + + printf("Expected array: "); + print_array(array_size, b); + + print_mismatch(result + 17); + return 1; } } - -int main(void) +int main(int argc, char **argv) { int success_tests_counter = 0; int failed_tests_counter = 0; - int f = open("test/testcases_len", O_RDONLY); + int f; + + if (argc == 2) + f = open(argv[1], O_RDONLY); + else + f = open("test/testcases_sort_official", O_RDONLY); if (f < 0) return 1; @@ -126,16 +213,20 @@ int main(void) remaining_buffer_length = read(f, cmd, 1024); while (remaining_buffer_length) { - char str_a[1024], str_b[1024]; - int target_length_diff; + char **a, **b; + int array_size; - int bytes_read = parse_case(cmd, &target_length_diff, str_a, str_b); + int bytes_read = parse_case(cmd, &array_size, &a, &b); - if (assert_length(success_tests_counter + failed_tests_counter + 1, target_length_diff, str_a, str_b)) + if (assert_sort(success_tests_counter + failed_tests_counter + 1, array_size, a, b)) failed_tests_counter++; else success_tests_counter++; + // clean up before next iteration + destroy_array(a, array_size); + destroy_array(b, array_size); + if (remaining_buffer_length == 1024) remaining_buffer_length = read_more(f, cmd, bytes_read); else diff --git a/test/testcases_sort_custom b/test/testcases_sort_custom new file mode 100644 index 0000000..49b7a91 --- /dev/null +++ b/test/testcases_sort_custom @@ -0,0 +1,2 @@ +3 banana,apple,egg apple,banana,egg +4 banana,test,apple,egg apple,banana,egg,test diff --git a/test/testcases_sort_official b/test/testcases_sort_official new file mode 100644 index 0000000..adb71b1 --- /dev/null +++ b/test/testcases_sort_official @@ -0,0 +1,5 @@ +5 banana,apple,cherry,date,elderberry apple,banana,cherry,date,elderberry +1 hello hello +3 alpha,beta,gamma alpha,beta,gamma +3 gamma,beta,alpha alpha,beta,gamma +8 hello,world,foo,bar,baz,qux,quux,corge bar,baz,corge,foo,hello,quux,qux,world diff --git a/test/testcases_sort_wrong b/test/testcases_sort_wrong new file mode 100644 index 0000000..cd97136 --- /dev/null +++ b/test/testcases_sort_wrong @@ -0,0 +1 @@ +3 1,2,3 2,1,3