diff --git a/bintree.c b/bintree.c index 5cf82a9..9761ea8 100644 --- a/bintree.c +++ b/bintree.c @@ -1,36 +1,128 @@ #include #include "stack.h" #include "bintree.h" +#include -//TODO: binären Suchbaum implementieren +// TODO: binären Suchbaum implementieren /* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv), - * `clearTree`: gibt den gesamten Baum frei (rekursiv), - * `treeSize`: zählt die Knoten im Baum (rekursiv), - * `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */ + * `clearTree`: gibt den gesamten Baum frei (rekursiv), + * `treeSize`: zählt die Knoten im Baum (rekursiv), + * `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */ // Adds a copy of data's pointer destination to the tree using compareFct for ordering. Accepts duplicates // if isDuplicate is NULL, otherwise ignores duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate) { + if (isDuplicate) + *isDuplicate = 0; + if (root == NULL) + { + TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode)); + if (!newNode) + { + return NULL; + } + newNode->data = malloc(dataSize); + if (!newNode->data) + { + free(newNode); + return NULL; + } + + memcpy(newNode->data, data, dataSize); + newNode->left = NULL; + newNode->right = NULL; + return newNode; + } + + int cmp = compareFct(data, root->data); + + if (cmp < 0) + { + root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); + } + else if (cmp > 0) + { + root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate); + } + else + { + + if (isDuplicate) + { + *isDuplicate = 1; // ignorieren + return root; + } + else + { + // Duplikate erlaubt -> nach rechts + root->right = addToTree(root->right, data, dataSize, compareFct, NULL); + } + } + return root; } // Iterates over the tree given by root. Follows the usage of strtok. If tree is NULL, the next entry of the last tree given is returned in ordering direction. // Use your implementation of a stack to organize the iterator. Push the root node and all left nodes first. On returning the next element, // push the top node and push all its left nodes. +static StackNode *iterator = NULL; void *nextTreeData(TreeNode *root) { + if (root != NULL) + { + clearStack(iterator); + iterator = NULL; + // Root + alle linken Nachfolger pushen + TreeNode *current = root; + while (current != NULL) + { + iterator = push(iterator, current); + current = current->left; + } + } + + // Wenn Stack leer -> fertig + if (iterator == NULL) + { + return NULL; + } + + + // Top-Node holen + TreeNode *node = (TreeNode *)top(iterator); + iterator = pop(iterator); + + // rechten Teilbaum + linke Kette pushen + TreeNode *right = node->right; + while (right != NULL) + { + iterator = push(iterator, right); + right = right->left; + } + + return node->data; } // Releases all memory resources (including data copies). void clearTree(TreeNode *root) { + if (root != NULL) + { + clearTree(root->left); + clearTree(root->right); + free(root->data); + free(root); + } } // Returns the number of entries in the tree given by root. unsigned int treeSize(const TreeNode *root) { + if (root == NULL) + return 0; + return 1 + treeSize(root->left) + treeSize(root->right); } \ No newline at end of file diff --git a/bintree.o b/bintree.o new file mode 100644 index 0000000..861d2b2 Binary files /dev/null and b/bintree.o differ diff --git a/doble.exe b/doble.exe new file mode 100644 index 0000000..85ea193 Binary files /dev/null and b/doble.exe differ diff --git a/doble_initial.exe b/doble_initial.exe new file mode 100644 index 0000000..3db2f66 Binary files /dev/null and b/doble_initial.exe differ diff --git a/highscore.o b/highscore.o new file mode 100644 index 0000000..e9b31f1 Binary files /dev/null and b/highscore.o differ diff --git a/highscores.txt b/highscores.txt index 4edd5a7..6977b89 100644 --- a/highscores.txt +++ b/highscores.txt @@ -1 +1,2 @@ -player1;3999 +player_name;5967 +jan;2993 diff --git a/main.o b/main.o new file mode 100644 index 0000000..a5219de Binary files /dev/null and b/main.o differ diff --git a/makefile b/makefile index 1f15f75..b03448f 100644 --- a/makefile +++ b/makefile @@ -35,15 +35,41 @@ $(program_obj_filesobj_files): %.o: %.c # -------------------------- # Unit Tests # -------------------------- -unitTests: - echo "needs to be implemented" +unitTests: test_stack test_tree test_numbers +test_stack: test_stack.o stack.o unity/unity.c + $(CC) $(FLAGS) -I$(unityfolder) $^ -o test_stack + +test_tree: test_tree.o bintree.o stack.o unity/unity.c + $(CC) $(FLAGS) -I$(unityfolder) $^ -o test_tree + +test_numbers: test_numbers.o numbers.o bintree.o stack.o unity/unity.c + $(CC) $(FLAGS) -I$(unityfolder) $^ -o test_numbers + +test_stack.o: test_stack.c + $(CC) -c $(FLAGS) -I$(unityfolder) $< -o $@ + +stack.o: stack.c + $(CC) -c $(FLAGS) $< -o $@ + +test_tree.o: test_tree.c + $(CC) -c $(FLAGS) -I$(unityfolder) $< -o $@ + +test_numbers.o: test_numbers.c + $(CC) -c $(FLAGS) -I$(unityfolder) $< -o $@ + +bintree.o: bintree.c + $(CC) -c $(FLAGS) $< -o $@ + +numbers.o: numbers.c + $(CC) -c $(FLAGS) $< -o $@ + # -------------------------- # Clean # -------------------------- clean: ifeq ($(OS),Windows_NT) - del /f *.o doble + del /f *.o doble $(TEST_BIN).exe else - rm -f *.o doble + rm -f *.o doble $(TEST_BIN) endif \ No newline at end of file diff --git a/numbers.c b/numbers.c index f59d9a2..24b4ae3 100644 --- a/numbers.c +++ b/numbers.c @@ -5,22 +5,108 @@ #include "numbers.h" #include "bintree.h" -//TODO: getDuplicate und createNumbers implementieren +// TODO: getDuplicate und createNumbers implementieren /* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen. - * Sicherstellen, dass beim Befüllen keine Duplikate entstehen. - * Duplizieren eines zufälligen Eintrags im Array. - * in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */ + * Sicherstellen, dass beim Befüllen keine Duplikate entstehen. + * Duplizieren eines zufälligen Eintrags im Array. + * in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */ // Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries. // Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while // creating random numbers. + +static void duplicateRandomEntry(unsigned int *numbers, unsigned int len) +{ + if (!numbers || len < 2) + return; + + unsigned int src = rand() % len; + unsigned int dst = rand() % len; + + while (dst == src) + dst = rand() % len; + + numbers[dst] = numbers[src]; +} + + +static int compare(const void *a, const void *b) +{ + unsigned int x = *(const unsigned int *)a; + unsigned int y = *(const unsigned int *)b; + return (x > y) - (x < y); +} + + + + unsigned int *createNumbers(unsigned int len) { + if (len < 2) + return NULL; + + unsigned int *numbers = malloc(sizeof(unsigned int) * len); + if (!numbers) + return NULL; + + static int seeded = 0; + if (!seeded) { + srand((unsigned)time(NULL)); + seeded = 1; + } + + TreeNode *root = NULL; + unsigned int i = 0; + + while (i < len) + { + unsigned int val = (rand() % (2 * len)) + 1; + int isDup = 0; + + root = addToTree(root, &val, sizeof(unsigned int), compare, &isDup); + if (!root) + { + free(numbers); // malloc-Fehler + return NULL; + } + + if (!isDup) + numbers[i++] = val; + } + + duplicateRandomEntry(numbers, len); + clearTree(root); + return numbers; } // Returns only the only number in numbers which is present twice. Returns zero on errors. unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) { + if (!numbers || len < 2) + { + return 0; + } -} \ No newline at end of file + unsigned int *copy = (unsigned int *)malloc(len * sizeof(unsigned int)); + if (!copy) + { + return 0; + } + + memcpy(copy, numbers, len * sizeof(unsigned int)); + qsort(copy, len, sizeof(unsigned int), compare); + + unsigned int dup = 0; + for (unsigned int i = 1; i < len; i++) + { + if (copy[i] == copy[i - 1]) + { + dup = copy[i]; + break; + } + } + + free(copy); + return dup; +} diff --git a/numbers.o b/numbers.o new file mode 100644 index 0000000..247f8c4 Binary files /dev/null and b/numbers.o differ diff --git a/stack.c b/stack.c index e3a90d4..a85e3d8 100644 --- a/stack.c +++ b/stack.c @@ -10,24 +10,53 @@ // Pushes data as pointer onto the stack. StackNode *push(StackNode *stack, void *data) { + StackNode *newNode = malloc(sizeof(StackNode)); + if(newNode == NULL) + { + return stack; //Speicher konnte nicht allokiert werden. + } + newNode->data = data; + newNode->next = stack; + + return newNode; } // Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be // freed by caller.) StackNode *pop(StackNode *stack) { + if (stack == NULL) + { + return NULL; // stack leer nichts zu löschen + } + StackNode *next = stack->next; + + free(stack); + return next; } // Returns the data of the top element. void *top(StackNode *stack) { + if(stack == NULL) + { + return NULL; + } + return stack->data; } // Clears stack and releases all memory. void clearStack(StackNode *stack) { + while (stack != NULL) + { + StackNode *next = stack->next; + free(stack); + stack = next; + } + } \ No newline at end of file diff --git a/stack.h b/stack.h index f7d542d..98505af 100644 --- a/stack.h +++ b/stack.h @@ -9,6 +9,11 @@ The latest element is taken from the stack. */ //TODO: passenden Datentyp als struct anlegen +typedef struct StackNode { + void *data; + struct StackNode* next; +} StackNode; + // Pushes data as pointer onto the stack. StackNode *push(StackNode *stack, void *data); diff --git a/stack.o b/stack.o new file mode 100644 index 0000000..381a8d2 Binary files /dev/null and b/stack.o differ diff --git a/test_numbers.c b/test_numbers.c new file mode 100644 index 0000000..1db8867 --- /dev/null +++ b/test_numbers.c @@ -0,0 +1,72 @@ +#include +#include "numbers.h" +#include "unity.h" +#include "unity_internals.h" + +void test_createNumbers_no_null(void) +{ + unsigned int *arr = createNumbers(10); + TEST_ASSERT_NOT_NULL(arr); + free(arr); +} + +void test_createNumbers_has_exactly_one_duplicate(void) +{ + unsigned int len = 100; + unsigned int *arr = createNumbers(len); + TEST_ASSERT_NOT_NULL(arr); + + unsigned int dup = getDuplicate(arr, len); + TEST_ASSERT_NOT_EQUAL(0, dup); + + int count = 0; + for (unsigned int i = 0; i < len; i++) + { + if (arr[i] == dup) + count++; + } + + TEST_ASSERT_EQUAL(2, count); + + free(arr); +} + +void test_createNumbers_has_correct_value_range(void) +{ + unsigned int len = 10; + unsigned int *arr = createNumbers(len); + TEST_ASSERT_NOT_NULL(arr); + + // Check all numbers are within valid range (1 to 2*len) + for (unsigned int i = 0; i < len; i++) + { + TEST_ASSERT_TRUE(arr[i] >= 1); + TEST_ASSERT_TRUE(arr[i] <= 2 * len); + } + + free(arr); +} + +void test_getDuplicate_returns_correct_value(void) +{ + unsigned int arr[6] = {4, 1, 7, 7, 3, 2}; + unsigned int d = getDuplicate(arr, 6); + TEST_ASSERT_EQUAL_UINT(7, d); +} + +void setUp(void) { } +void tearDown(void) { } + +int main(void) +{ + UNITY_BEGIN(); + + printf("\n============================\n Numbers tests\n============================\n"); + + RUN_TEST(test_createNumbers_no_null); + RUN_TEST(test_createNumbers_has_exactly_one_duplicate); + RUN_TEST(test_createNumbers_has_correct_value_range); + RUN_TEST(test_getDuplicate_returns_correct_value); + + return UNITY_END(); +} \ No newline at end of file diff --git a/test_numbers.exe b/test_numbers.exe new file mode 100644 index 0000000..b176541 Binary files /dev/null and b/test_numbers.exe differ diff --git a/test_stack.c b/test_stack.c new file mode 100644 index 0000000..2bb7df6 --- /dev/null +++ b/test_stack.c @@ -0,0 +1,155 @@ +#include +#include +#include +#include "unity.h" +#include "stack.h" + +// Hilfsfunktion: int dynamisch anlegen +static int *makeInt(int value) +{ + int *p = (int *)malloc(sizeof(int)); + if (p != NULL) + { + *p = value; + } + return p; +} + +void test_pushAndTopReturnLastPushed(void) +{ + StackNode *stack = NULL; + + int *v1 = makeInt(10); + int *v2 = makeInt(20); + int *v3 = makeInt(30); + + TEST_ASSERT_NOT_NULL(v1); + TEST_ASSERT_NOT_NULL(v2); + TEST_ASSERT_NOT_NULL(v3); + + stack = push(stack, v1); + TEST_ASSERT_NOT_NULL(stack); + TEST_ASSERT_EQUAL_PTR(v1, top(stack)); + TEST_ASSERT_EQUAL_INT(10, *(int *)top(stack)); + + stack = push(stack, v2); + TEST_ASSERT_EQUAL_PTR(v2, top(stack)); + TEST_ASSERT_EQUAL_INT(20, *(int *)top(stack)); + + stack = push(stack, v3); + TEST_ASSERT_EQUAL_PTR(v3, top(stack)); + TEST_ASSERT_EQUAL_INT(30, *(int *)top(stack)); + + TEST_ASSERT_EQUAL_PTR(v3, top(stack)); + free(v3); + stack = pop(stack); + + TEST_ASSERT_EQUAL_PTR(v2, top(stack)); + free(v2); + stack = pop(stack); + + TEST_ASSERT_EQUAL_PTR(v1, top(stack)); + free(v1); + stack = pop(stack); + + TEST_ASSERT_NULL(stack); +} + +void test_popOnEmptyStackReturnsNull(void) +{ + StackNode *stack = NULL; + + StackNode *newStack = pop(stack); + TEST_ASSERT_NULL(newStack); + + TEST_ASSERT_NULL(top(newStack)); +} + +void test_pushAndPopLifoOrder(void) +{ + StackNode *stack = NULL; + + int *v1 = makeInt(1); + int *v2 = makeInt(2); + int *v3 = makeInt(3); + + TEST_ASSERT_NOT_NULL(v1); + TEST_ASSERT_NOT_NULL(v2); + TEST_ASSERT_NOT_NULL(v3); + + stack = push(stack, v1); + stack = push(stack, v2); + stack = push(stack, v3); + + TEST_ASSERT_EQUAL_PTR(v3, top(stack)); + TEST_ASSERT_EQUAL_INT(3, *(int *)top(stack)); + free(v3); + stack = pop(stack); + + TEST_ASSERT_EQUAL_PTR(v2, top(stack)); + TEST_ASSERT_EQUAL_INT(2, *(int *)top(stack)); + free(v2); + stack = pop(stack); + + + TEST_ASSERT_EQUAL_PTR(v1, top(stack)); + TEST_ASSERT_EQUAL_INT(1, *(int *)top(stack)); + free(v1); + stack = pop(stack); + + TEST_ASSERT_NULL(stack); +} + +void test_topOnEmptyStackReturnsNull(void) +{ + StackNode *stack = NULL; + TEST_ASSERT_NULL(top(stack)); +} + +void test_clearStackFreesAllNodes(void) +{ + StackNode *stack = NULL; + + int a = 11; + int b = 22; + int c = 33; + + stack = push(stack, &a); + stack = push(stack, &b); + stack = push(stack, &c); + + TEST_ASSERT_NOT_NULL(stack); + TEST_ASSERT_EQUAL_INT(33, *(int *)top(stack)); + + clearStack(stack); + + stack = NULL; + + + +} + +void setUp(void) +{ + +} + +void tearDown(void) +{ + +} + +int main(void) +{ + UNITY_BEGIN(); + + printf("\n============================\nStack tests\n============================\n"); + + RUN_TEST(test_pushAndTopReturnLastPushed); + RUN_TEST(test_popOnEmptyStackReturnsNull); + RUN_TEST(test_pushAndPopLifoOrder); + RUN_TEST(test_topOnEmptyStackReturnsNull); + RUN_TEST(test_clearStackFreesAllNodes); + + return UNITY_END(); +} diff --git a/test_stack.exe b/test_stack.exe new file mode 100644 index 0000000..92e047f Binary files /dev/null and b/test_stack.exe differ diff --git a/test_tree.c b/test_tree.c new file mode 100644 index 0000000..6c1ab69 --- /dev/null +++ b/test_tree.c @@ -0,0 +1,118 @@ +#include "unity.h" +#include "bintree.h" +#include +#include + +static int compare(const void *a, const void *b) +{ + return (*(int *)a > *(int *)b) - (*(int *)a < *(int *)b); +} + +void setUp(void) { } +void tearDown(void) { } + +void test_addToTree_single_element(void) +{ + TreeNode *root = NULL; + int value = 10; + int dup; + + root = addToTree(root, &value, sizeof(int), compare, &dup); + + TEST_ASSERT_NOT_NULL(root); + TEST_ASSERT_EQUAL_INT(10, *(int*)root->data); + TEST_ASSERT_EQUAL_INT(0, dup); + + clearTree(root); +} + +void test_addToTree_multiple_elements_and_size(void) +{ + TreeNode *root = NULL; + int values[] = {5, 3, 7, 1, 4}; + int dup; + + for (int i = 0; i < 5; i++) + root = addToTree(root, &values[i], sizeof(int), compare, &dup); + + TEST_ASSERT_EQUAL_UINT(5, treeSize(root)); + + clearTree(root); +} + +void test_addToTree_duplicate_detection(void) +{ + TreeNode *root = NULL; + int val = 42; + int dup; + + root = addToTree(root, &val, sizeof(int), compare, &dup); + TEST_ASSERT_EQUAL_INT(0, dup); + + root = addToTree(root, &val, sizeof(int), compare, &dup); + TEST_ASSERT_EQUAL_INT(1, dup); + + clearTree(root); +} + +void test_treeSize_empty_tree_detection(void) +{ + TEST_ASSERT_EQUAL_UINT(0, treeSize(NULL)); +} + +void test_nextTreeData_returns_inorder(void) +{ + TreeNode *root = NULL; + int values[] = {5, 3, 7, 2, 4, 6, 8}; + + for (int i = 0; i < 7; i++) + root = addToTree(root, &values[i], sizeof(int), compare, NULL); + + int expected[] = {2,3,4,5,6,7,8}; + + int idx = 0; + void *p = nextTreeData(root); + + while (p != NULL) + { + TEST_ASSERT_EQUAL_INT(expected[idx], *(int*)p); + idx++; + p = nextTreeData(NULL); + } + + TEST_ASSERT_EQUAL_INT(7, idx); + + clearTree(root); +} + +void test_treeSize_returns_correct_size() +{ + TreeNode *root = NULL; + int values[] = {8, 3, 10, 1, 6, 14}; + + for (int i = 0; i < 6; i++) + root = addToTree(root, &values[i], sizeof(int), compare, NULL); + + TEST_ASSERT_EQUAL_UINT(6, treeSize(root)); + + clearTree(root); + root = NULL; + + TEST_ASSERT_EQUAL_UINT(0, treeSize(root)); +} + +int main(void) +{ + UNITY_BEGIN(); + + printf("\n============================\n Bintree tests\n============================\n"); + + RUN_TEST(test_addToTree_single_element); + RUN_TEST(test_addToTree_multiple_elements_and_size); + RUN_TEST(test_addToTree_duplicate_detection); + RUN_TEST(test_treeSize_empty_tree_detection); + RUN_TEST(test_nextTreeData_returns_inorder); + RUN_TEST(test_treeSize_returns_correct_size); + + return UNITY_END(); +} diff --git a/test_tree.exe b/test_tree.exe new file mode 100644 index 0000000..77ab89a Binary files /dev/null and b/test_tree.exe differ diff --git a/timer.o b/timer.o new file mode 100644 index 0000000..5af0f96 Binary files /dev/null and b/timer.o differ