cleartree angepasst, Kommentare vollständig

This commit is contained in:
Kristin 2025-12-11 16:16:52 +01:00
parent 99a974cc9b
commit 9fb140fecf
7 changed files with 188 additions and 156 deletions

View File

@ -109,15 +109,18 @@ void *nextTreeData(TreeNode *root) {
} }
// Releases all memory resources (including data copies). // Releases all memory resources (including data copies).
void clearTree(TreeNode *root) { void clearTree(TreeNode **root) { // rekursive Funktion zum freigeben des
if (root == NULL) // Speichers und Nullsetzen der Pointer
if (root == NULL || *root == NULL)
return; return;
clearTree(root->left); clearTree(&(*root)->left); // linken Teilbaum löschen
clearTree(root->right); clearTree(&(*root)->right); // rechten Teilbaum löschen
free(root->data); free((*root)->data); // Daten freigeben
free(root); (*root)->data = NULL;
free(*root); // Knoten freigeben
*root = NULL; // Zeiger auf NULL setzen
} }
// Returns the number of entries in the tree given by root. // Returns the number of entries in the tree given by root.

View File

@ -25,7 +25,7 @@ TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize,
// the top node and push all its left nodes. // the top node and push all its left nodes.
void *nextTreeData(TreeNode *root); void *nextTreeData(TreeNode *root);
// Releases all memory resources (including data copies). // Releases all memory resources (including data copies).
void clearTree(TreeNode *root); void clearTree(TreeNode **root);
// Returns the number of entries in the tree given by root. // Returns the number of entries in the tree given by root.
unsigned int treeSize(const TreeNode *root); unsigned int treeSize(const TreeNode *root);

View File

@ -1,134 +1,129 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "highscore.h" #include "highscore.h"
#include "bintree.h" #include "bintree.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LEN 100 #define MAX_LINE_LEN 100
#define MAX_PLAYER_NAME_LEN 20 #define MAX_PLAYER_NAME_LEN 20
typedef struct typedef struct {
{ char name[MAX_PLAYER_NAME_LEN];
char name[MAX_PLAYER_NAME_LEN]; int score;
int score;
} HighscoreEntry; } HighscoreEntry;
static TreeNode *highscoreTree = NULL; static TreeNode *highscoreTree = NULL;
// Compare two highscore entries by score (descending), then by name (ascending). // Compare two highscore entries by score (descending), then by name
static int compareHighscoreEntries(const void *arg1, const void *arg2) // (ascending).
{ static int compareHighscoreEntries(const void *arg1, const void *arg2) {
const HighscoreEntry *entry1 = (const HighscoreEntry *)arg1; const HighscoreEntry *entry1 = (const HighscoreEntry *)arg1;
const HighscoreEntry *entry2 = (const HighscoreEntry *)arg2; const HighscoreEntry *entry2 = (const HighscoreEntry *)arg2;
int result = entry2->score - entry1->score; int result = entry2->score - entry1->score;
if(result == 0) if (result == 0)
result = strcmp(entry1->name, entry2->name); result = strcmp(entry1->name, entry2->name);
return result; return result;
} }
// Create a new highscore entry from name and score. // Create a new highscore entry from name and score.
static HighscoreEntry createHighscoreEntry(const char *name, int score) static HighscoreEntry createHighscoreEntry(const char *name, int score) {
{ HighscoreEntry entry = {"", score};
HighscoreEntry entry = {"", score};
if(name != NULL) if (name != NULL) {
{ strncpy(entry.name, name, MAX_PLAYER_NAME_LEN);
strncpy(entry.name, name, MAX_PLAYER_NAME_LEN); entry.name[MAX_PLAYER_NAME_LEN - 1] = '\0';
entry.name[MAX_PLAYER_NAME_LEN-1] = '\0'; }
}
return entry; return entry;
} }
// Calculate score based on time used and number of shown numbers. // Calculate score based on time used and number of shown numbers.
static int calculateScore(double timeInSeconds, unsigned int len) static int calculateScore(double timeInSeconds, unsigned int len) {
{ return (1000.0 - timeInSeconds) * len;
return (1000.0 - timeInSeconds) * len;
} }
// Load highscores from file into memory. // Load highscores from file into memory.
void loadHighscores(const char *path) void loadHighscores(const char *path) {
{ FILE *file = fopen(path, "r");
FILE *file = fopen(path, "r");
if(file != NULL) if (file != NULL) {
{ char buffer[MAX_LINE_LEN + 1];
char buffer[MAX_LINE_LEN+1];
while(fgets(buffer, MAX_LINE_LEN+1, file) != NULL) while (fgets(buffer, MAX_LINE_LEN + 1, file) != NULL) {
{ char *name = strtok(buffer, ";\n");
char *name = strtok(buffer, ";\n"); char *scoreStr = strtok(NULL, ";\n");
char *scoreStr = strtok(NULL, ";\n");
if(name != NULL && scoreStr != NULL) if (name != NULL && scoreStr != NULL) {
{ HighscoreEntry entry =
HighscoreEntry entry = createHighscoreEntry(name, strtol(scoreStr, NULL, 10)); createHighscoreEntry(name, strtol(scoreStr, NULL, 10));
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry), compareHighscoreEntries, NULL); highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry),
} compareHighscoreEntries, NULL);
} }
fclose(file);
} }
fclose(file);
}
} }
// Add a new highscore entry and return the calculated score. // Add a new highscore entry and return the calculated score.
int addHighscore(const char *name, double timeInSeconds, unsigned int len) int addHighscore(const char *name, double timeInSeconds, unsigned int len) {
{ HighscoreEntry entry =
HighscoreEntry entry = createHighscoreEntry(name, calculateScore(timeInSeconds, len)); createHighscoreEntry(name, calculateScore(timeInSeconds, len));
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry), compareHighscoreEntries, NULL); highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry),
compareHighscoreEntries, NULL);
return entry.score; return entry.score;
} }
// Print highscores (up to NUMBER_OF_SHOWN_HIGHSCORES) in a formatted table. // Print highscores (up to NUMBER_OF_SHOWN_HIGHSCORES) in a formatted table.
void showHighscores() void showHighscores() {
{ const char *blanks =
const char *blanks = " "; " "
const char *stripes = "------------------------------------------------------------------------------------------------------------------------"; " ";
const char *header = "H I G H S C O R E S"; const char *stripes =
const int lineWidth = MAX_PLAYER_NAME_LEN + MAX_PLAYER_NAME_LEN + 5; "------------------------------------------------------------------------"
"------------------------------------------------";
const char *header = "H I G H S C O R E S";
const int lineWidth = MAX_PLAYER_NAME_LEN + MAX_PLAYER_NAME_LEN + 5;
int blankSpace = (int)(lineWidth - strlen(header)) / 2; int blankSpace = (int)(lineWidth - strlen(header)) / 2;
HighscoreEntry *entry = nextTreeData(highscoreTree); HighscoreEntry *entry = nextTreeData(highscoreTree);
printf("+%*.*s+\n", lineWidth, lineWidth, stripes);
printf("|%*.*s%s%*.*s|\n", blankSpace, blankSpace, blanks, header, blankSpace,
blankSpace, blanks);
printf("+%*.*s+\n", lineWidth, lineWidth, stripes);
for (int i = 0; i < NUMBER_OF_SHOWN_HIGHSCORES && entry != NULL; i++) {
printf("| %-*s | %*d |\n", MAX_PLAYER_NAME_LEN, entry->name,
MAX_PLAYER_NAME_LEN, entry->score);
printf("+%*.*s+\n", lineWidth, lineWidth, stripes); printf("+%*.*s+\n", lineWidth, lineWidth, stripes);
printf("|%*.*s%s%*.*s|\n", blankSpace, blankSpace, blanks, header, blankSpace, blankSpace, blanks); entry = nextTreeData(NULL);
printf("+%*.*s+\n", lineWidth, lineWidth, stripes); }
for(int i = 0; i < NUMBER_OF_SHOWN_HIGHSCORES && entry != NULL; i++)
{
printf("| %-*s | %*d |\n", MAX_PLAYER_NAME_LEN, entry->name, MAX_PLAYER_NAME_LEN, entry->score);
printf("+%*.*s+\n", lineWidth, lineWidth, stripes);
entry = nextTreeData(NULL);
}
} }
// Save highscores to file (up to NUMBER_OF_SHOWN_HIGHSCORES). // Save highscores to file (up to NUMBER_OF_SHOWN_HIGHSCORES).
void saveHighscores(const char *path) void saveHighscores(const char *path) {
{ FILE *file = fopen(path, "w");
FILE *file = fopen(path, "w");
if(file != NULL) if (file != NULL) {
{ HighscoreEntry *entry = nextTreeData(highscoreTree);
HighscoreEntry *entry = nextTreeData(highscoreTree);
for(int i = 0; i < NUMBER_OF_SHOWN_HIGHSCORES && entry != NULL; i++) for (int i = 0; i < NUMBER_OF_SHOWN_HIGHSCORES && entry != NULL; i++) {
{ fprintf(file, "%s;%d\n", entry->name, entry->score);
fprintf(file, "%s;%d\n", entry->name, entry->score); entry = nextTreeData(NULL);
entry = nextTreeData(NULL);
}
fclose(file);
} }
fclose(file);
}
} }
// Free all memory used for highscores. // Free all memory used for highscores.
void clearHighscores() void clearHighscores() {
{ clearTree(&highscoreTree);
clearTree(highscoreTree); highscoreTree = NULL;
highscoreTree = NULL;
} }

View File

@ -7,4 +7,4 @@ krisp;19934
krisp;19916 krisp;19916
kristin;19861 kristin;19861
Kristin;19858 Kristin;19858
krisp;19460 p;19729

View File

@ -63,20 +63,22 @@ unsigned int *createNumbers(unsigned int len) {
numbersArray[newIndex] = numbersArray[newIndex] =
numbersArray[duplicateIndex]; // Wert vom ersten Index kopieren numbersArray[duplicateIndex]; // Wert vom ersten Index kopieren
clearTree(root); // Speicher wieder freigeben, wird nicht mehr benötigt clearTree(&root); // Speicher wieder freigeben, wird nicht mehr benötigt
return numbersArray; return numbersArray;
} }
// Returns only the only number in numbers which is present twice. Returns zero // Returns only the only number in numbers which is present twice. Returns zero
// on errors. // on errors.
unsigned int getDuplicate(const unsigned int *numbers, unsigned int len) { unsigned int getDuplicate(
const unsigned int *numbers,
unsigned int len) { // array numbers, sowie die Länge wird übergeben
if (!numbers || len < 2) if (!numbers || len < 2)
return 0; // Sicherheit: kein Array oder zu kurz return 0; // fehlerhaftes Array
TreeNode *root = NULL; TreeNode *root = NULL; // leerer Baum
unsigned int duplicateValue = 0; unsigned int duplicateValue = 0; // Wert des Duplikats
for (unsigned int i = 0; i < len; i++) { for (unsigned int i = 0; i < len && duplicateValue == 0; i++) { // Schleife
int isDuplicate = 0; int isDuplicate = 0;
// Zahl in den Baum einfügen // Zahl in den Baum einfügen
@ -85,10 +87,10 @@ unsigned int getDuplicate(const unsigned int *numbers, unsigned int len) {
// Duplikat erkannt // Duplikat erkannt
if (isDuplicate && duplicateValue == 0) { if (isDuplicate && duplicateValue == 0) {
duplicateValue = numbers[i]; // das erste Duplikat merken duplicateValue = numbers[i]; // Duplikat merken, for-Schleife wird beendet
} }
} }
clearTree(root); // Baum freigeben clearTree(&root); // Baum freigeben
return duplicateValue; // 0, falls kein Duplikat return duplicateValue; // 0, falls kein Duplikat
} }

View File

@ -22,71 +22,91 @@ void setUp(void) {
root = NULL; // vor jedem Test leeren root = NULL; // vor jedem Test leeren
} }
void tearDown(void) { clearTree(root); } void tearDown(void) { clearTree(&root); }
// Test, ob addToTree Knoten korrekt hinzufügt // Test, ob addToTree Knoten korrekt hinzufügt
/*TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize,
CompareFctType compareFct, int *isDuplicate) */
void test_addToTree_basic(void) { void test_addToTree_basic(void) {
int isDup; int isDuplicate;
unsigned int val = 10; unsigned int testInt = 10;
root = addToTree(root, &val, sizeof(val), compareUnsignedInt, &isDup); root = addToTree(root, &testInt, sizeof(testInt), compareUnsignedInt,
TEST_ASSERT_NOT_NULL(root); &isDuplicate);
TEST_ASSERT_EQUAL_UINT(10, *(unsigned int *)root->data); TEST_ASSERT_NOT_NULL(root); // Knoten wurde erfolgreich erzeugt
TEST_ASSERT_EQUAL_INT(0, isDup); TEST_ASSERT_EQUAL_UINT(
TEST_ASSERT_EQUAL_UINT(1, treeSize(root)); 10,
*(unsigned int *)root
->data); // Datenzeiger wurde richtig gesetzt, void pointer auf
// unsigned int pointer casten, mit *wird der Wert abgerufen
TEST_ASSERT_EQUAL_INT(0, isDuplicate); // kein Duplikat
TEST_ASSERT_EQUAL_UINT(1, treeSize(root)); // der tree hat einen Eintrag
} }
// Test, dass Duplikate erkannt werden // Test, dass Duplikate erkannt werden
void test_addToTree_duplicate(void) { void test_addToTree_duplicate(void) {
int isDup; int isDuplicate;
unsigned int val1 = 10, val2 = 10; unsigned int val1 = 10, val2 = 10; // Duplikate
root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt, &isDup); root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt,
TEST_ASSERT_EQUAL_INT(0, isDup); &isDuplicate); // val 1 zum leeren Baum hinzufügen
root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt, &isDup); TEST_ASSERT_EQUAL_INT(0, isDuplicate); // erster Knoten->kein Duplikat
TEST_ASSERT_EQUAL_INT(1, isDup); root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt,
TEST_ASSERT_EQUAL_UINT(1, treeSize(root)); // Duplikate nicht hinzufügen &isDuplicate); // val 2 hinzufügen
TEST_ASSERT_EQUAL_INT(1, isDuplicate); // Duplikat erkannt
TEST_ASSERT_EQUAL_UINT(1,
treeSize(root)); // Duplikate wurde nicht hinzugefügt
} }
// Test nextTreeData Traversierung // Test nextTreeData Traversierung
void test_nextTreeData_in_order(void) { void test_nextTreeData_in_order(void) {
unsigned int values[] = {20, 10, 30}; unsigned int values[] = {20, 10, 30}; // erwartete Ausgabe: 10 -> 20 -> 30
int isDup; int isDuplicate;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
root = addToTree(root, &values[i], sizeof(values[i]), compareUnsignedInt, root = addToTree(root, &values[i], sizeof(values[i]), compareUnsignedInt,
&isDup); &isDuplicate); // Baum füllen
} }
unsigned int expected[] = {10, 20, 30}; unsigned int expected[] = {10, 20, 30}; // erwartet in Order Reihenfolge
int idx = 0; int valueID = 0;
void *data; void *data;
// **Neue Iteration starten** // Neue Iteration starten
data = nextTreeData(root); data = nextTreeData(root);
while (data != NULL) { while (data != NULL) {
TEST_ASSERT_EQUAL_UINT(expected[idx], *(unsigned int *)data); TEST_ASSERT_EQUAL_UINT(expected[valueID],
idx++; *(unsigned int *)data); // entspricht erwartetem Wert
valueID++;
data = nextTreeData(NULL); // weitere Elemente abrufen data = nextTreeData(NULL); // weitere Elemente abrufen
} }
TEST_ASSERT_EQUAL_INT(3, idx); // alle 3 Knoten besucht TEST_ASSERT_EQUAL_INT(3, valueID); // alle 3 Knoten besucht
} }
// Test clearTree gibt Speicher frei // Testet, dass clearTree Speicher freigibt und Root auf NULL setzt
void test_clearTree(void) { void test_clearTree_sets_root_null(void) {
unsigned int val = 42; int isDuplicate;
int isDup; unsigned int val1 = 10, val2 = 20;
root = addToTree(root, &val, sizeof(val), compareUnsignedInt, &isDup);
clearTree(root); root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt, &isDuplicate);
root = NULL; // clearTree löscht nicht die root-Variable selbst root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt, &isDuplicate);
// Vor dem Clear prüfen, dass Root nicht NULL ist
TEST_ASSERT_NOT_NULL(root);
clearTree(&root);
// Nach dem Clear muss Root auf NULL gesetzt sein
TEST_ASSERT_NULL(root); TEST_ASSERT_NULL(root);
} }
// Test treeSize zählt korrekt // Test treeSize zählt korrekt
void test_treeSize(void) { void test_treeSize(void) {
unsigned int vals[] = {10, 20, 5}; unsigned int testInts[] = {10, 20, 5};
int isDup; int isDuplicate;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
root = root = addToTree(root, &testInts[i], sizeof(testInts[i]),
addToTree(root, &vals[i], sizeof(vals[i]), compareUnsignedInt, &isDup); compareUnsignedInt, &isDuplicate);
} }
TEST_ASSERT_EQUAL_UINT(3, treeSize(root)); TEST_ASSERT_EQUAL_UINT(3, treeSize(root));
} }
@ -100,7 +120,7 @@ int main(void) {
RUN_TEST(test_addToTree_basic); RUN_TEST(test_addToTree_basic);
RUN_TEST(test_addToTree_duplicate); RUN_TEST(test_addToTree_duplicate);
RUN_TEST(test_nextTreeData_in_order); RUN_TEST(test_nextTreeData_in_order);
RUN_TEST(test_clearTree); RUN_TEST(test_clearTree_sets_root_null);
RUN_TEST(test_treeSize); RUN_TEST(test_treeSize);
return UNITY_END(); return UNITY_END();
} }

View File

@ -7,40 +7,52 @@
#define TEST_ARRAY_LEN 100 #define TEST_ARRAY_LEN 100
void test_createNumbers_length(void) { // Speicher für ein Array wird reserviert
unsigned int *arr = createNumbers(TEST_ARRAY_LEN); void test_createNumbers_length(void) { // erstellt ein Array der Länge hundert
TEST_ASSERT_NOT_NULL(arr); unsigned int *testArray = createNumbers(TEST_ARRAY_LEN);
free(arr); TEST_ASSERT_NOT_NULL(testArray);
free(testArray);
} }
// Duplikat ist genau einmal vorhanden
void test_createNumbers_single_duplicate(void) { void test_createNumbers_single_duplicate(void) {
unsigned int *arr = createNumbers(TEST_ARRAY_LEN); unsigned int *testArray = createNumbers(TEST_ARRAY_LEN); // Array erstellen
TEST_ASSERT_NOT_NULL(arr); TEST_ASSERT_NOT_NULL(testArray); // Speicher konnte reserviert werden
unsigned int duplicate = getDuplicate(arr, TEST_ARRAY_LEN); unsigned int duplicate =
TEST_ASSERT_TRUE(duplicate > 0); getDuplicate(testArray, TEST_ARRAY_LEN); // Duplikat holen
TEST_ASSERT_TRUE(duplicate > 0); // Duplikat ist größer als 0
TEST_ASSERT_TRUE(
duplicate <
(2 * TEST_ARRAY_LEN)); // Duplikat liegt im vorgegebenen Zahlenbereich
unsigned int count = 0; unsigned int count = 0; // Anzahl der Duplikate
for (unsigned int i = 0; i < TEST_ARRAY_LEN; i++) { for (unsigned int i = 0; i < TEST_ARRAY_LEN;
if (arr[i] == duplicate) { i++) { // Einträge des testArrays auf Duplikate prüfen
if (testArray[i] == duplicate) {
count++; count++;
} }
} }
TEST_ASSERT_EQUAL_UINT(2, count); TEST_ASSERT_EQUAL_UINT(2, count); // Duplikat zwei mal vorhanden
free(arr); free(testArray); // Speicher freigeben
} }
void test_getDuplicate_manual_array(void) { // getDuplicate testen
void test_getDuplicate_manual_array(
void) { // duplikat in fremden array wird gefunden
unsigned int numbers[5] = {10, 20, 30, 40, 20}; unsigned int numbers[5] = {10, 20, 30, 40, 20};
unsigned int dup = getDuplicate(numbers, 5); unsigned int duplicate = getDuplicate(numbers, 5);
TEST_ASSERT_EQUAL_UINT(20, dup); TEST_ASSERT_EQUAL_UINT(20, duplicate);
} }
// getDuplicate erkennt fehlerhaftes Array
void test_getDuplicate_invalid_input(void) { void test_getDuplicate_invalid_input(void) {
TEST_ASSERT_EQUAL_UINT(0, getDuplicate(NULL, 5)); TEST_ASSERT_EQUAL_UINT(
unsigned int arr[1] = {42}; 0, getDuplicate(NULL, 5)); // unsigned int getDuplicate(const unsigned int
TEST_ASSERT_EQUAL_UINT(0, getDuplicate(arr, 1)); // *numbers, unsigned int len)
unsigned int testArray[1] = {2};
TEST_ASSERT_EQUAL_UINT(0, getDuplicate(testArray, 1));
} }
void setUp(void) {} void setUp(void) {}