Compare commits

..

No commits in common. "6aa59ce710b6932781ca8d3469664b38f044378b" and "abf78fb87f6c479e543342bec72e9a0f8a1fdf8c" have entirely different histories.

9 changed files with 313 additions and 357 deletions

View File

@ -13,50 +13,42 @@
// ordering. Accepts duplicates if isDuplicate is NULL, otherwise ignores // ordering. Accepts duplicates if isDuplicate is NULL, otherwise ignores
// duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). // duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).
TreeNode *createTreeNode(const void *data, size_t dataSize) { void copyData(void *dest, const void *src, size_t size) {
TreeNode *node = unsigned char *d = dest;
malloc(sizeof(TreeNode)); // Speicher für neuen Knoten reservieren const unsigned char *s = src;
if (node == NULL) for (size_t i = 0; i < size; i++) {
return NULL; // Abbrechen bei Fehler d[i] = s[i];
node->data = malloc(dataSize); // Speicher für Daten reservieren
if (node->data == NULL) {
free(node);
return NULL;
} }
memcpy(node->data, data, dataSize); // Standardfunktion string.h, kopiert
// size bytes von data nach node->data,
// daten dürfen sich nicht überschneiden
// speichern der Daten in node->data
node->left = NULL; // Kinder sind NULL
node->right = NULL;
return node;
} }
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize,
CompareFctType compareFct, int *isDuplicate) { CompareFctType compareFct, int *isDuplicate) {
// isDuplicate initialisieren (auf 0 setzen), verhindert Änderung am Baum // isDuplicate initialisieren (auf 0 setzen)
if (isDuplicate) { if (isDuplicate) {
*isDuplicate = 0; *isDuplicate = 0;
} // bei 0: neuer Wert wurde eingefügt, bei 1: Wert war bereits im Baum }
// leerer Baum // leerer Baum
if (root == NULL) { if (root == NULL) {
return createTreeNode(data, dataSize); TreeNode *node = malloc(sizeof(TreeNode));
node->data = malloc(dataSize);
copyData(node->data, data, dataSize);
node->left = NULL;
node->right = NULL;
return node;
} }
// mit compareFct <0 links >0 rechts =0 Duplikat // mit compareFct <0 links >0 rechts =0 Duplikat
int compare = compareFct(data, root->data); int cmp = compareFct(data, root->data);
if (compare < 0) { // Eintrag links if (cmp < 0) {
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
} else if (compare > 0) { // Eintrag rechts } else if (cmp > 0) {
root->right = root->right =
addToTree(root->right, data, dataSize, compareFct, isDuplicate); addToTree(root->right, data, dataSize, compareFct, isDuplicate);
} else { // Duplikat } else {
// isDuplicate auf 1 setzen, keine Änderung am Baum // isDuplicate auf 1 setzen
if (isDuplicate) { if (isDuplicate) {
*isDuplicate = 1; *isDuplicate = 1;
} }
@ -70,57 +62,52 @@ TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize,
// the root node and all left nodes first. On returning the next element, push // the root node and all left nodes first. On returning the next element, push
// 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) {
static StackNode *stack = NULL; // static -> behält Wert bei mehreren Aufrufen static StackNode *stack = NULL;
// Neue Iteration starten // Neue Iteration starten
if (root != NULL) { if (root != NULL) {
clearStack(&stack); // alte Stack-Inhalte werden gelöscht clearStack(&stack);
TreeNode *currentNode = root; TreeNode *curr = root;
while (currentNode != while (curr != NULL) {
NULL) { // alle linken Knoten werden vom root an auf den Stack gelegt
StackNode *oldStack = stack; StackNode *oldStack = stack;
StackNode *newStack = push(stack, currentNode); StackNode *newStack = push(stack, curr);
if (newStack == oldStack) if (newStack == oldStack)
return NULL; // push fehlgeschlagen return NULL; // push fehlgeschlagen
stack = newStack; stack = newStack;
currentNode = currentNode->left; curr = curr->left;
} }
} }
if (stack == NULL) if (stack == NULL)
return NULL; // wenn Stack leer ist sind keine Elemente mehr vorhanden, return NULL; // alles durchlaufen
// Iteration beendet
// oberster Knoten vom Stack // Oberstes Element abrufen
TreeNode *node = top(stack); TreeNode *node = (TreeNode *)top(stack);
stack = pop(stack); stack = pop(stack);
// Rechten Teilbaum pushen // Rechten Teilbaum pushen
TreeNode *currentNode = node->right; TreeNode *curr = node->right;
while (currentNode != NULL) { while (curr != NULL) {
StackNode *oldStack = stack; StackNode *oldStack = stack;
StackNode *newStack = push(stack, currentNode); StackNode *newStack = push(stack, curr);
if (newStack == oldStack) if (newStack == oldStack)
return NULL; // push fehlgeschlagen return NULL; // push fehlgeschlagen
stack = newStack; stack = newStack;
currentNode = currentNode->left; curr = curr->left;
} }
return node->data; // Pointer auf Daten return node->data;
} }
// Releases all memory resources (including data copies). // Releases all memory resources (including data copies).
void clearTree(TreeNode **root) { // rekursive Funktion zum freigeben des void clearTree(TreeNode *root) {
// Speichers und Nullsetzen der Pointer if (root == NULL)
if (root == NULL || *root == NULL)
return; return;
clearTree(&(*root)->left); // linken Teilbaum löschen clearTree(root->left);
clearTree(&(*root)->right); // rechten Teilbaum löschen clearTree(root->right);
free((*root)->data); // Daten freigeben free(root->data);
(*root)->data = NULL; free(root);
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

@ -11,7 +11,7 @@ typedef struct node {
struct node *right; struct node *right;
} TreeNode; } TreeNode;
TreeNode *createTreeNode(const void *data, size_t dataSize); void copyData(void *dest, const void *src, size_t size);
// Adds a copy of data's pointer destination to the tree using compareFct for // Adds a copy of data's pointer destination to the tree using compareFct for
// ordering. Accepts duplicates if isDuplicate is NULL, otherwise ignores // ordering. Accepts duplicates if isDuplicate is NULL, otherwise ignores
@ -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,129 +1,134 @@
#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]; {
int score; char name[MAX_PLAYER_NAME_LEN];
int score;
} HighscoreEntry; } HighscoreEntry;
static TreeNode *highscoreTree = NULL; static TreeNode *highscoreTree = NULL;
// Compare two highscore entries by score (descending), then by name // Compare two highscore entries by score (descending), then by name (ascending).
// (ascending). static int compareHighscoreEntries(const void *arg1, const void *arg2)
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); {
entry.name[MAX_PLAYER_NAME_LEN - 1] = '\0'; strncpy(entry.name, name, MAX_PLAYER_NAME_LEN);
} 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 *scoreStr = strtok(NULL, ";\n"); char *name = strtok(buffer, ";\n");
char *scoreStr = strtok(NULL, ";\n");
if (name != NULL && scoreStr != NULL) { if(name != NULL && scoreStr != NULL)
HighscoreEntry entry = {
createHighscoreEntry(name, strtol(scoreStr, NULL, 10)); HighscoreEntry entry = createHighscoreEntry(name, strtol(scoreStr, NULL, 10));
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry), highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry), compareHighscoreEntries, NULL);
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 = {
createHighscoreEntry(name, calculateScore(timeInSeconds, len)); HighscoreEntry entry = createHighscoreEntry(name, calculateScore(timeInSeconds, len));
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry), highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry), compareHighscoreEntries, NULL);
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 *stripes = 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;
"------------------------------------------------";
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);
entry = nextTreeData(NULL); 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);
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); {
entry = nextTreeData(NULL); fprintf(file, "%s;%d\n", entry->name, entry->score);
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); {
highscoreTree = NULL; clearTree(highscoreTree);
highscoreTree = NULL;
} }

View File

@ -1,10 +1,10 @@
Kristin;49209 Kristin;9944
krisp;29797 Kristin;7947
krisp;29792 Kristin;6962
Kristin;29782 Kristin;5987
Kristin;19943 Kristin;5975
krisp;19934 krisp;4986
krisp;19916 krisp;4985
kristin;19861 Kristin;4972
Kristin;19858 player1;3999
p;19729 Kristin;3992

132
main.c
View File

@ -1,88 +1,90 @@
#include "highscore.h" #include <stdlib.h>
#include <stdio.h>
#include "numbers.h" #include "numbers.h"
#include "timer.h" #include "timer.h"
#include <stdio.h> #include "highscore.h"
#include <stdlib.h>
#include <time.h>
// Read an unsigned integer from stdin with prompt (retries until valid). // Read an unsigned integer from stdin with prompt (retries until valid).
int inputNumber(const char *promptText) { int inputNumber(const char *promptText)
unsigned int number; {
int numberOfInputs = 0; unsigned int number;
int numberOfInputs = 0;
while (numberOfInputs != 1) { while(numberOfInputs != 1)
printf("%s", promptText); {
numberOfInputs = scanf("%u", &number); printf("%s", promptText);
while (getchar() != '\n') { numberOfInputs = scanf("%u", &number);
} // clear input buffer while(getchar() != '\n') {} // clear input buffer
} }
return number; return number;
} }
// Print an array of numbers. // Print an array of numbers.
void showNumbers(const unsigned int *numbers, unsigned int len) { void showNumbers(const unsigned int *numbers, unsigned int len)
if (numbers != NULL) { {
printf("Numbers:"); if(numbers != NULL)
{
printf("Numbers:");
for (int i = 0; i < len; i++) for(int i = 0; i < len; i++)
printf(" %5d", numbers[i]); printf(" %5d", numbers[i]);
printf("\n"); printf("\n");
} }
} }
// Main game loop: generate numbers, ask user for duplicate, measure time, // Main game loop: generate numbers, ask user for duplicate, measure time, update highscores.
// update highscores. int main(int argc, char *argv[])
int main(int argc, char *argv[]) { {
srand(time(NULL)); // seed für srand int exitCode = EXIT_FAILURE;
int exitCode = EXIT_FAILURE;
if (argc != 2) { if(argc != 2)
fprintf(stderr, "Usage: %s <player name>\n", argv[0]); {
exitCode = EXIT_FAILURE; fprintf(stderr, "Usage: %s <player name>\n", argv[0]);
} else { exitCode = EXIT_FAILURE;
const char *highscorePath = "highscores.txt"; }
const char *playerName = argv[1]; else
unsigned int *numbers = NULL; {
unsigned int duplicate = 0; const char *highscorePath = "highscores.txt";
double measuredSeconds; const char *playerName = argv[1];
unsigned int userInput; unsigned int *numbers = NULL;
unsigned int numberOfElements = 0; unsigned int duplicate = 0;
double measuredSeconds;
unsigned int userInput;
unsigned int numberOfElements = 0;
// ask until valid number of elements (3..1000) // ask until valid number of elements (3..1000)
while (numberOfElements < 3 || numberOfElements > 1000) while(numberOfElements < 3 || numberOfElements > 1000)
numberOfElements = numberOfElements = inputNumber("Wie viele Zahlen sollen gezeigt werden: ");
inputNumber("Wie viele Zahlen sollen gezeigt werden: ");
// create numbers and show them // create numbers and show them
numbers = createNumbers(numberOfElements); numbers = createNumbers(numberOfElements);
showNumbers(numbers, numberOfElements); showNumbers(numbers, numberOfElements);
// measure time while user guesses the duplicate // measure time while user guesses the duplicate
startTimer(); startTimer();
userInput = inputNumber("Welche Zahl kommt doppelt vor: "); userInput = inputNumber("Welche Zahl kommt doppelt vor: ");
measuredSeconds = stopTimer(); measuredSeconds = stopTimer();
duplicate = getDuplicate(numbers, numberOfElements); duplicate = getDuplicate(numbers, numberOfElements);
// check result and update highscores // check result and update highscores
if (userInput == duplicate) { if(userInput == duplicate)
int score = addHighscore(playerName, measuredSeconds, numberOfElements); {
printf("Sie haben die korrekte Zahl in %.6lf Sekunde(n) gefunden und %u " int score = addHighscore(playerName, measuredSeconds, numberOfElements);
"Punkte erzielt.\n", printf("Sie haben die korrekte Zahl in %.6lf Sekunde(n) gefunden und %u Punkte erzielt.\n", measuredSeconds, score);
measuredSeconds, score); }
} else else
printf("Leider ist %u nicht korrekt. Richtig waere %u gewesen.\n", printf("Leider ist %u nicht korrekt. Richtig waere %u gewesen.\n", userInput, duplicate);
userInput, duplicate);
loadHighscores(highscorePath); loadHighscores(highscorePath);
showHighscores(); showHighscores();
saveHighscores(highscorePath); saveHighscores(highscorePath);
clearHighscores(); clearHighscores();
exitCode = EXIT_SUCCESS; exitCode = EXIT_SUCCESS;
} }
return exitCode; return exitCode;
} }

106
numbers.c
View File

@ -3,6 +3,19 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
//Vergleicht
int compareUnsignedInt(const void *a, const void *b) {
unsigned int x = *(unsigned int *)a;
unsigned int y = *(unsigned int *)b;
if (x < y)
return -1;
if (x > y)
return 1;
return 0;
}
// TODO: getDuplicate und createNumbers implementieren // TODO: getDuplicate und createNumbers implementieren
/**Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an /**Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an
@ -15,82 +28,65 @@
// different, except for two entries. Returns NULL on errors. Use your // different, except for two entries. Returns NULL on errors. Use your
// implementation of the binary search tree to check for possible duplicates // implementation of the binary search tree to check for possible duplicates
// while creating random numbers. // while creating random numbers.
// vergleicht zwei Werte: a<b: -1 a>b: 1 a=b: 0
int compareUnsignedInt(const void *a, const void *b) {
unsigned int x = *(unsigned int *)a;
unsigned int y = *(unsigned int *)b;
return (x < y) ? -1 : (x > y);
}
unsigned int *createNumbers(unsigned int len) { unsigned int *createNumbers(unsigned int len) {
if (len < 2) // Duplikat bei zwei Einträgen sinnlos if (len < 2)
return NULL; return NULL;
unsigned int *numbersArray = malloc( unsigned int *arr = malloc(sizeof(unsigned int) * len);
sizeof(unsigned int) * len); // Speicher für das Ausgabearray reservieren: if (!arr)
// Größe eines Eintrags * Größe des Arrays
if (!numbersArray) // Speicher konnte nicht reserviert werden
return NULL; return NULL;
TreeNode *root = TreeNode *root = NULL;
NULL; // Binärbaum zum Generieren der Zufallszahlen ohne Duplikate srand((unsigned int)time(NULL));
for (unsigned int i = 0; i < len; i++) { for (unsigned int i = 0; i < len - 1; i++) {
unsigned int currentNumber; unsigned int num;
int isDuplicate; int isDuplicate;
do { // mindestens eine Zufallszahl erzeugen
currentNumber = (rand() % (2 * len)) + 1; // Zahlenbereich 1 bis 2*len do {
num = (rand() % (2 * len)) + 1;
isDuplicate = 0; isDuplicate = 0;
root = addToTree(root, &currentNumber, sizeof(unsigned int),
compareUnsignedInt, root = addToTree(root, &num, sizeof(unsigned int), compareUnsignedInt,
&isDuplicate); // compareUnsignedInt wird zum Verwenden &isDuplicate);
// bei Vergleichen übergeben
} while (isDuplicate); // wenn isDuplicate gesetzt wird, muss eine neue Zahl } while (isDuplicate); // nur akzeptieren, wenn eindeutig
// erzeugt werden, die Schleife wird wiederholt
numbersArray[i] = currentNumber; arr[i] = num;
} }
// Ein zufälliges Duplikat erzeugen // Jetzt gezielt EIN Duplikat erzeugen
unsigned int duplicateIndex = unsigned int duplicateIndex = rand() % (len - 1);
rand() % len; // Index des Duplikats per Zufall bestimmen arr[len - 1] = arr[duplicateIndex];
unsigned int newIndex;
do {
newIndex = rand() % len;
} while (newIndex == duplicateIndex); // zweiten Index bestimmen, der nicht
// mit dem ersten übereinstimmt
numbersArray[newIndex] = clearTree(root);
numbersArray[duplicateIndex]; // Wert vom ersten Index kopieren return arr;
clearTree(&root); // Speicher wieder freigeben, wird nicht mehr benötigt
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( unsigned int getDuplicate(const unsigned int *numbers, unsigned int len) {
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; // fehlerhaftes Array return 0;
TreeNode *root = NULL; // leerer Baum unsigned int *copy = malloc(sizeof(unsigned int) * len);
unsigned int duplicateValue = 0; // Wert des Duplikats if (!copy)
return 0;
for (unsigned int i = 0; i < len && duplicateValue == 0; i++) { // Schleife memcpy(copy, numbers, sizeof(unsigned int) * len);
int isDuplicate = 0;
// Zahl in den Baum einfügen // Sortierung
root = addToTree(root, &numbers[i], sizeof(unsigned int), qsort(copy, len, sizeof(unsigned int), compareUnsignedInt);
compareUnsignedInt, &isDuplicate);
// Duplikat erkannt // Duplikat finden: zwei gleiche nebeneinander
if (isDuplicate && duplicateValue == 0) { unsigned int duplicate = 0;
duplicateValue = numbers[i]; // Duplikat merken, for-Schleife wird beendet for (unsigned int i = 0; i < len - 1; i++) {
if (copy[i] == copy[i + 1]) {
duplicate = copy[i];
break;
} }
} }
clearTree(&root); // Baum freigeben free(copy);
return duplicateValue; // 0, falls kein Duplikat return duplicate;
} }

View File

@ -3,14 +3,12 @@
int compareUnsignedInt(const void *a, const void *b); int compareUnsignedInt(const void *a, const void *b);
// Returns len random numbers between 1 and 2x len in random order which are all // Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries.
// different, except for two entries. Returns NULL on errors. Use your // Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while
// implementation of the binary search tree to check for possible duplicates // creating random numbers.
// while creating random numbers.
unsigned int *createNumbers(unsigned int len); unsigned int *createNumbers(unsigned int len);
// 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);
#endif #endif

View File

@ -4,7 +4,6 @@
#include <string.h> #include <string.h>
#include "bintree.h" #include "bintree.h"
int compareUnsignedInt(const void *a, const void *b) { int compareUnsignedInt(const void *a, const void *b) {
unsigned int x = *(unsigned int *)a; unsigned int x = *(unsigned int *)a;
unsigned int y = *(unsigned int *)b; unsigned int y = *(unsigned int *)b;
@ -22,91 +21,71 @@ 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 isDuplicate; int isDup;
unsigned int testInt = 10; unsigned int val = 10;
root = addToTree(root, &testInt, sizeof(testInt), compareUnsignedInt, root = addToTree(root, &val, sizeof(val), compareUnsignedInt, &isDup);
&isDuplicate); TEST_ASSERT_NOT_NULL(root);
TEST_ASSERT_NOT_NULL(root); // Knoten wurde erfolgreich erzeugt TEST_ASSERT_EQUAL_UINT(10, *(unsigned int *)root->data);
TEST_ASSERT_EQUAL_UINT( TEST_ASSERT_EQUAL_INT(0, isDup);
10, TEST_ASSERT_EQUAL_UINT(1, treeSize(root));
*(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 isDuplicate; int isDup;
unsigned int val1 = 10, val2 = 10; // Duplikate unsigned int val1 = 10, val2 = 10;
root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt, root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt, &isDup);
&isDuplicate); // val 1 zum leeren Baum hinzufügen TEST_ASSERT_EQUAL_INT(0, isDup);
TEST_ASSERT_EQUAL_INT(0, isDuplicate); // erster Knoten->kein Duplikat root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt, &isDup);
root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt, TEST_ASSERT_EQUAL_INT(1, isDup);
&isDuplicate); // val 2 hinzufügen TEST_ASSERT_EQUAL_UINT(1, treeSize(root)); // Duplikate nicht 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}; // erwartete Ausgabe: 10 -> 20 -> 30 unsigned int values[] = {20, 10, 30};
int isDuplicate; int isDup;
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,
&isDuplicate); // Baum füllen &isDup);
} }
unsigned int expected[] = {10, 20, 30}; // erwartet in Order Reihenfolge unsigned int expected[] = {10, 20, 30};
int valueID = 0; int idx = 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[valueID], TEST_ASSERT_EQUAL_UINT(expected[idx], *(unsigned int *)data);
*(unsigned int *)data); // entspricht erwartetem Wert idx++;
valueID++;
data = nextTreeData(NULL); // weitere Elemente abrufen data = nextTreeData(NULL); // weitere Elemente abrufen
} }
TEST_ASSERT_EQUAL_INT(3, valueID); // alle 3 Knoten besucht TEST_ASSERT_EQUAL_INT(3, idx); // alle 3 Knoten besucht
} }
// Testet, dass clearTree Speicher freigibt und Root auf NULL setzt // Test clearTree gibt Speicher frei
void test_clearTree_sets_root_null(void) { void test_clearTree(void) {
int isDuplicate; unsigned int val = 42;
unsigned int val1 = 10, val2 = 20; int isDup;
root = addToTree(root, &val, sizeof(val), compareUnsignedInt, &isDup);
root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt, &isDuplicate); clearTree(root);
root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt, &isDuplicate); root = NULL; // clearTree löscht nicht die root-Variable selbst
// 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 testInts[] = {10, 20, 5}; unsigned int vals[] = {10, 20, 5};
int isDuplicate; int isDup;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
root = addToTree(root, &testInts[i], sizeof(testInts[i]), root =
compareUnsignedInt, &isDuplicate); addToTree(root, &vals[i], sizeof(vals[i]), compareUnsignedInt, &isDup);
} }
TEST_ASSERT_EQUAL_UINT(3, treeSize(root)); TEST_ASSERT_EQUAL_UINT(3, treeSize(root));
} }
@ -120,7 +99,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_sets_root_null); RUN_TEST(test_clearTree);
RUN_TEST(test_treeSize); RUN_TEST(test_treeSize);
return UNITY_END(); return UNITY_END();
} }

View File

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