Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fcaa410fa | ||
|
|
c13d39f60c | ||
|
|
f90dc12bd0 | ||
|
|
9fb140fecf | ||
|
|
99a974cc9b | ||
|
|
799667ed1c | ||
|
|
c3b1cdd3a3 | ||
|
|
9d32e06f3a | ||
|
|
d9222b83b4 | ||
|
|
9268113f38 | ||
|
|
8f2dfb507c | ||
|
|
9bf5e6a541 | ||
|
|
57f9914e2b | ||
|
|
09d7f457dd | ||
|
|
13cb5d8c86 | ||
|
|
6528686fb0 | ||
|
|
a3d0585ac1 | ||
|
|
68563ec297 | ||
|
|
8cccbcf441 | ||
|
|
96a97c07c9 | ||
| 74fdcf500f | |||
|
|
55532cbb42 | ||
|
|
d3904ac6e4 | ||
|
|
0575eac07e | ||
|
|
5e96ec050c | ||
| 382c36b1b4 | |||
| 81de4b3d36 | |||
|
|
f42a997683 | ||
|
|
09426ae40a | ||
|
|
9443171664 | ||
|
|
b28deeaafb | ||
|
|
4bb0d7516e | ||
|
|
ddd4132e1f | ||
| 624a7d8b41 | |||
| 73ebc36c05 | |||
|
|
e7423f0a20 | ||
|
|
8b44089f23 | ||
|
|
654fb615a2 | ||
|
|
422ac38d54 | ||
|
|
7051134256 | ||
|
|
90612e4d04 | ||
|
|
17f4155891 | ||
|
|
735195460c | ||
|
|
a002901e2f | ||
|
|
55b25a227b |
5
.gitignore
vendored
5
.gitignore
vendored
@ -1 +1,4 @@
|
||||
highscores.txt
|
||||
doble_initial.exe
|
||||
*.o
|
||||
*.exe
|
||||
highscore.txt
|
||||
18
.vscode/c_cpp_properties.json
vendored
Normal file
18
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "windows-gcc-x64",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"compilerPath": "C:/ProgramData/mingw64/mingw64/bin/gcc.exe",
|
||||
"cStandard": "${default}",
|
||||
"cppStandard": "${default}",
|
||||
"intelliSenseMode": "windows-gcc-x64",
|
||||
"compilerArgs": [
|
||||
""
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
24
.vscode/launch.json
vendored
Normal file
24
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "C/C++ Runner: Debug Session",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"cwd": "c:/Users/Max-R/I2Pr/info2Praktikum-DobleSpiel",
|
||||
"program": "c:/Users/Max-R/I2Pr/info2Praktikum-DobleSpiel/build/Debug/outDebug",
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
59
.vscode/settings.json
vendored
Normal file
59
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"C_Cpp_Runner.cCompilerPath": "gcc",
|
||||
"C_Cpp_Runner.cppCompilerPath": "g++",
|
||||
"C_Cpp_Runner.debuggerPath": "gdb",
|
||||
"C_Cpp_Runner.cStandard": "",
|
||||
"C_Cpp_Runner.cppStandard": "",
|
||||
"C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat",
|
||||
"C_Cpp_Runner.useMsvc": false,
|
||||
"C_Cpp_Runner.warnings": [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Wpedantic",
|
||||
"-Wshadow",
|
||||
"-Wformat=2",
|
||||
"-Wcast-align",
|
||||
"-Wconversion",
|
||||
"-Wsign-conversion",
|
||||
"-Wnull-dereference"
|
||||
],
|
||||
"C_Cpp_Runner.msvcWarnings": [
|
||||
"/W4",
|
||||
"/permissive-",
|
||||
"/w14242",
|
||||
"/w14287",
|
||||
"/w14296",
|
||||
"/w14311",
|
||||
"/w14826",
|
||||
"/w44062",
|
||||
"/w44242",
|
||||
"/w14905",
|
||||
"/w14906",
|
||||
"/w14263",
|
||||
"/w44265",
|
||||
"/w14928"
|
||||
],
|
||||
"C_Cpp_Runner.enableWarnings": true,
|
||||
"C_Cpp_Runner.warningsAsError": false,
|
||||
"C_Cpp_Runner.compilerArgs": [],
|
||||
"C_Cpp_Runner.linkerArgs": [],
|
||||
"C_Cpp_Runner.includePaths": [],
|
||||
"C_Cpp_Runner.includeSearch": [
|
||||
"*",
|
||||
"**/*"
|
||||
],
|
||||
"C_Cpp_Runner.excludeSearch": [
|
||||
"**/build",
|
||||
"**/build/**",
|
||||
"**/.*",
|
||||
"**/.*/**",
|
||||
"**/.vscode",
|
||||
"**/.vscode/**"
|
||||
],
|
||||
"C_Cpp_Runner.useAddressSanitizer": false,
|
||||
"C_Cpp_Runner.useUndefinedSanitizer": false,
|
||||
"C_Cpp_Runner.useLeakSanitizer": false,
|
||||
"C_Cpp_Runner.showCompilationTime": false,
|
||||
"C_Cpp_Runner.useLinkTimeOptimization": false,
|
||||
"C_Cpp_Runner.msvcSecureNoWarnings": false
|
||||
}
|
||||
126
bintree.c
126
bintree.c
@ -1,6 +1,6 @@
|
||||
#include <string.h>
|
||||
#include "stack.h"
|
||||
#include "bintree.h"
|
||||
#include "stack.h"
|
||||
#include <string.h>
|
||||
|
||||
// TODO: binären Suchbaum implementieren
|
||||
/* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv),
|
||||
@ -8,29 +8,125 @@
|
||||
* `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)
|
||||
{
|
||||
// typedef int (*CompareFctType)(const void *arg1, const void *arg2);
|
||||
// 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 *createTreeNode(const void *data, size_t dataSize) {
|
||||
TreeNode *node =
|
||||
malloc(sizeof(TreeNode)); // Speicher für neuen Knoten reservieren
|
||||
if (node == NULL)
|
||||
return NULL; // Abbrechen bei Fehler
|
||||
|
||||
node->data = malloc(dataSize); // Speicher für Daten reservieren
|
||||
if (node->data == NULL) {
|
||||
free(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 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.
|
||||
void *nextTreeData(TreeNode *root)
|
||||
{
|
||||
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,
|
||||
CompareFctType compareFct, int *isDuplicate) {
|
||||
|
||||
// isDuplicate initialisieren (auf 0 setzen), verhindert Änderung am Baum
|
||||
if (isDuplicate) {
|
||||
*isDuplicate = 0;
|
||||
} // bei 0: neuer Wert wurde eingefügt, bei 1: Wert war bereits im Baum
|
||||
|
||||
// leerer Baum
|
||||
if (root == NULL) {
|
||||
return createTreeNode(data, dataSize);
|
||||
}
|
||||
|
||||
// mit compareFct <0 links >0 rechts =0 Duplikat
|
||||
int compare = compareFct(data, root->data);
|
||||
|
||||
if (compare < 0) { // Eintrag links
|
||||
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
|
||||
} else if (compare > 0) { // Eintrag rechts
|
||||
root->right =
|
||||
addToTree(root->right, data, dataSize, compareFct, isDuplicate);
|
||||
} else { // Duplikat
|
||||
// isDuplicate auf 1 setzen, keine Änderung am Baum
|
||||
if (isDuplicate) {
|
||||
*isDuplicate = 1;
|
||||
}
|
||||
}
|
||||
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.
|
||||
void *nextTreeData(TreeNode *root) {
|
||||
static StackNode *stack = NULL; // static -> behält Wert bei mehreren Aufrufen
|
||||
|
||||
// Neue Iteration starten
|
||||
if (root != NULL) {
|
||||
clearStack(&stack); // alte Stack-Inhalte werden gelöscht
|
||||
|
||||
TreeNode *currentNode = root;
|
||||
while (currentNode !=
|
||||
NULL) { // alle linken Knoten werden vom root an auf den Stack gelegt
|
||||
StackNode *oldStack = stack;
|
||||
StackNode *newStack = push(stack, currentNode);
|
||||
if (newStack == oldStack)
|
||||
return NULL; // push fehlgeschlagen
|
||||
stack = newStack;
|
||||
currentNode = currentNode->left;
|
||||
}
|
||||
}
|
||||
if (stack == NULL)
|
||||
return NULL; // wenn Stack leer ist sind keine Elemente mehr vorhanden,
|
||||
// Iteration beendet
|
||||
|
||||
// oberster Knoten vom Stack
|
||||
TreeNode *node = top(stack);
|
||||
stack = pop(stack);
|
||||
|
||||
// Rechten Teilbaum pushen
|
||||
TreeNode *currentNode = node->right;
|
||||
while (currentNode != NULL) {
|
||||
StackNode *oldStack = stack;
|
||||
StackNode *newStack = push(stack, currentNode);
|
||||
if (newStack == oldStack)
|
||||
return NULL; // push fehlgeschlagen
|
||||
stack = newStack;
|
||||
currentNode = currentNode->left;
|
||||
}
|
||||
return node->data; // Pointer auf Daten
|
||||
}
|
||||
|
||||
// Releases all memory resources (including data copies).
|
||||
void clearTree(TreeNode *root)
|
||||
{
|
||||
void clearTree(TreeNode **root) { // rekursive Funktion zum freigeben des
|
||||
// Speichers und Nullsetzen der Pointer
|
||||
if (root == NULL || *root == NULL)
|
||||
return;
|
||||
|
||||
clearTree(&(*root)->left); // linken Teilbaum löschen
|
||||
clearTree(&(*root)->right); // rechten Teilbaum löschen
|
||||
|
||||
free((*root)->data); // Daten freigeben
|
||||
(*root)->data = NULL;
|
||||
free(*root); // Knoten freigeben
|
||||
*root = NULL; // Zeiger auf NULL setzen
|
||||
}
|
||||
|
||||
// Returns the number of entries in the tree given by root.
|
||||
unsigned int treeSize(const TreeNode *root)
|
||||
{
|
||||
unsigned int treeSize(const TreeNode *root) {
|
||||
|
||||
if (root == NULL)
|
||||
return 0;
|
||||
return 1 + treeSize(root->left) + treeSize(root->right);
|
||||
}
|
||||
23
bintree.h
23
bintree.h
@ -5,22 +5,27 @@
|
||||
|
||||
typedef int (*CompareFctType)(const void *arg1, const void *arg2);
|
||||
|
||||
typedef struct node
|
||||
{
|
||||
typedef struct node {
|
||||
void *data;
|
||||
struct node *left;
|
||||
struct node *right;
|
||||
} TreeNode;
|
||||
|
||||
// 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);
|
||||
// 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.
|
||||
TreeNode *createTreeNode(const void *data, size_t dataSize);
|
||||
|
||||
// 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);
|
||||
// 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.
|
||||
void *nextTreeData(TreeNode *root);
|
||||
// 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.
|
||||
unsigned int treeSize(const TreeNode *root);
|
||||
|
||||
|
||||
BIN
doble_initial.exe
Normal file
BIN
doble_initial.exe
Normal file
Binary file not shown.
85
highscore.c
85
highscore.c
@ -1,23 +1,22 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "highscore.h"
|
||||
#include "bintree.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_LINE_LEN 100
|
||||
#define MAX_PLAYER_NAME_LEN 20
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
char name[MAX_PLAYER_NAME_LEN];
|
||||
int score;
|
||||
} HighscoreEntry;
|
||||
|
||||
static TreeNode *highscoreTree = NULL;
|
||||
|
||||
// Compare two highscore entries by score (descending), then by name (ascending).
|
||||
static int compareHighscoreEntries(const void *arg1, const void *arg2)
|
||||
{
|
||||
// Compare two highscore entries by score (descending), then by name
|
||||
// (ascending).
|
||||
static int compareHighscoreEntries(const void *arg1, const void *arg2) {
|
||||
const HighscoreEntry *entry1 = (const HighscoreEntry *)arg1;
|
||||
const HighscoreEntry *entry2 = (const HighscoreEntry *)arg2;
|
||||
|
||||
@ -30,12 +29,10 @@ static int compareHighscoreEntries(const void *arg1, const void *arg2)
|
||||
}
|
||||
|
||||
// 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};
|
||||
|
||||
if(name != NULL)
|
||||
{
|
||||
if (name != NULL) {
|
||||
strncpy(entry.name, name, MAX_PLAYER_NAME_LEN);
|
||||
entry.name[MAX_PLAYER_NAME_LEN - 1] = '\0';
|
||||
}
|
||||
@ -44,29 +41,26 @@ static HighscoreEntry createHighscoreEntry(const char *name, int score)
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Load highscores from file into memory.
|
||||
void loadHighscores(const char *path)
|
||||
{
|
||||
void loadHighscores(const char *path) {
|
||||
FILE *file = fopen(path, "r");
|
||||
|
||||
if(file != NULL)
|
||||
{
|
||||
if (file != NULL) {
|
||||
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");
|
||||
|
||||
if(name != NULL && scoreStr != NULL)
|
||||
{
|
||||
HighscoreEntry entry = createHighscoreEntry(name, strtol(scoreStr, NULL, 10));
|
||||
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry), compareHighscoreEntries, NULL);
|
||||
if (name != NULL && scoreStr != NULL) {
|
||||
HighscoreEntry entry =
|
||||
createHighscoreEntry(name, strtol(scoreStr, NULL, 10));
|
||||
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry),
|
||||
compareHighscoreEntries, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,19 +69,23 @@ void loadHighscores(const char *path)
|
||||
}
|
||||
|
||||
// Add a new highscore entry and return the calculated score.
|
||||
int addHighscore(const char *name, double timeInSeconds, unsigned int len)
|
||||
{
|
||||
HighscoreEntry entry = createHighscoreEntry(name, calculateScore(timeInSeconds, len));
|
||||
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry), compareHighscoreEntries, NULL);
|
||||
int addHighscore(const char *name, double timeInSeconds, unsigned int len) {
|
||||
HighscoreEntry entry =
|
||||
createHighscoreEntry(name, calculateScore(timeInSeconds, len));
|
||||
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry),
|
||||
compareHighscoreEntries, NULL);
|
||||
|
||||
return entry.score;
|
||||
}
|
||||
|
||||
// Print highscores (up to NUMBER_OF_SHOWN_HIGHSCORES) in a formatted table.
|
||||
void showHighscores()
|
||||
{
|
||||
const char *blanks = " ";
|
||||
const char *stripes = "------------------------------------------------------------------------------------------------------------------------";
|
||||
void showHighscores() {
|
||||
const char *blanks =
|
||||
" "
|
||||
" ";
|
||||
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;
|
||||
|
||||
@ -96,28 +94,26 @@ void showHighscores()
|
||||
HighscoreEntry *entry = nextTreeData(highscoreTree);
|
||||
|
||||
printf("+%*.*s+\n", lineWidth, lineWidth, stripes);
|
||||
printf("|%*.*s%s%*.*s|\n", blankSpace, blankSpace, blanks, header, blankSpace, blankSpace, blanks);
|
||||
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);
|
||||
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).
|
||||
void saveHighscores(const char *path)
|
||||
{
|
||||
void saveHighscores(const char *path) {
|
||||
FILE *file = fopen(path, "w");
|
||||
|
||||
if(file != NULL)
|
||||
{
|
||||
if (file != NULL) {
|
||||
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);
|
||||
}
|
||||
@ -127,8 +123,7 @@ void saveHighscores(const char *path)
|
||||
}
|
||||
|
||||
// Free all memory used for highscores.
|
||||
void clearHighscores()
|
||||
{
|
||||
clearTree(highscoreTree);
|
||||
void clearHighscores() {
|
||||
clearTree(&highscoreTree);
|
||||
highscoreTree = NULL;
|
||||
}
|
||||
@ -1 +1,10 @@
|
||||
player1;3999
|
||||
max20;19879
|
||||
max10;9970
|
||||
max;9965
|
||||
Kristin;9944
|
||||
Kristin;7947
|
||||
Kristin;6962
|
||||
Kristin;5987
|
||||
Kristin;5975
|
||||
krisp;4986
|
||||
krisp;4985
|
||||
|
||||
52
main.c
52
main.c
@ -1,30 +1,28 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "highscore.h"
|
||||
#include "numbers.h"
|
||||
#include "timer.h"
|
||||
#include "highscore.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
// 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;
|
||||
|
||||
while(numberOfInputs != 1)
|
||||
{
|
||||
while (numberOfInputs != 1) {
|
||||
printf("%s", promptText);
|
||||
numberOfInputs = scanf("%u", &number);
|
||||
while(getchar() != '\n') {} // clear input buffer
|
||||
while (getchar() != '\n') {
|
||||
} // clear input buffer
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
// Print an array of numbers.
|
||||
void showNumbers(const unsigned int *numbers, unsigned int len)
|
||||
{
|
||||
if(numbers != NULL)
|
||||
{
|
||||
void showNumbers(const unsigned int *numbers, unsigned int len) {
|
||||
if (numbers != NULL) {
|
||||
printf("Numbers:");
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
@ -34,18 +32,16 @@ void showNumbers(const unsigned int *numbers, unsigned int len)
|
||||
}
|
||||
}
|
||||
|
||||
// Main game loop: generate numbers, ask user for duplicate, measure time, update highscores.
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Main game loop: generate numbers, ask user for duplicate, measure time,
|
||||
// update highscores.
|
||||
int main(int argc, char *argv[]) {
|
||||
srand(time(NULL)); // seed für srand
|
||||
int exitCode = EXIT_FAILURE;
|
||||
|
||||
if(argc != 2)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <player name>\n", argv[0]);
|
||||
exitCode = EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
const char *highscorePath = "highscores.txt";
|
||||
const char *playerName = argv[1];
|
||||
unsigned int *numbers = NULL;
|
||||
@ -56,7 +52,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
// ask until valid number of elements (3..1000)
|
||||
while (numberOfElements < 3 || numberOfElements > 1000)
|
||||
numberOfElements = inputNumber("Wie viele Zahlen sollen gezeigt werden: ");
|
||||
numberOfElements =
|
||||
inputNumber("Wie viele Zahlen sollen gezeigt werden: ");
|
||||
|
||||
// create numbers and show them
|
||||
numbers = createNumbers(numberOfElements);
|
||||
@ -70,13 +67,14 @@ int main(int argc, char *argv[])
|
||||
duplicate = getDuplicate(numbers, numberOfElements);
|
||||
|
||||
// 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 Punkte erzielt.\n", measuredSeconds, score);
|
||||
}
|
||||
else
|
||||
printf("Leider ist %u nicht korrekt. Richtig waere %u gewesen.\n", userInput, duplicate);
|
||||
printf("Sie haben die korrekte Zahl in %.6lf Sekunde(n) gefunden und %u "
|
||||
"Punkte erzielt.\n",
|
||||
measuredSeconds, score);
|
||||
} else
|
||||
printf("Leider ist %u nicht korrekt. Richtig waere %u gewesen.\n",
|
||||
userInput, duplicate);
|
||||
|
||||
loadHighscores(highscorePath);
|
||||
showHighscores();
|
||||
|
||||
39
makefile
39
makefile
@ -1,5 +1,6 @@
|
||||
CC = gcc
|
||||
FLAGS = -g -Wall -lm
|
||||
ASAN_FLAGS = -fsanitize=address
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
include makefile_windows.variables
|
||||
@ -24,19 +25,46 @@ doble_initial:
|
||||
# --------------------------
|
||||
# Selbst implementiertes Programm bauen
|
||||
# --------------------------
|
||||
# alle Objektdateien
|
||||
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
|
||||
|
||||
# alle ausführbaren Dateien zu ausführbarem Programm linken
|
||||
doble : main.o $(program_obj_files)
|
||||
$(CC) $(FLAGS) $^ -o doble
|
||||
|
||||
$(program_obj_filesobj_files): %.o: %.c
|
||||
# Regel Kompilieren allgemein
|
||||
$(program_obj_files): %.o: %.c
|
||||
$(CC) -c $(FLAGS) $^ -o $@
|
||||
|
||||
# --------------------------
|
||||
# Unit Tests
|
||||
# --------------------------
|
||||
unitTests:
|
||||
echo "needs to be implemented"
|
||||
|
||||
STACK_TEST_BIN = runStackTests
|
||||
NUMBERS_TEST_BIN = runNumbersTests
|
||||
BINARY_TEST_BIN = runBinaryTests
|
||||
|
||||
# --- Stack Tests ---
|
||||
stackTests: stack.o test_stack.o
|
||||
$(CC) $(FLAGS) -I$(unityfolder) -o $(STACK_TEST_BIN) stack.o test_stack.o $(unityfolder)/unity.c
|
||||
|
||||
test_stack.o: test_stack.c
|
||||
$(CC) $(FLAGS) -I$(unityfolder) -c test_stack.c -o test_stack.o
|
||||
|
||||
|
||||
# --- Numbers Tests ---
|
||||
numbersTests: numbers.o bintree.o stack.o test_numbers.o
|
||||
$(CC) $(FLAGS) -I$(unityfolder) -o $(NUMBERS_TEST_BIN) numbers.o bintree.o stack.o test_numbers.o $(unityfolder)/unity.c
|
||||
|
||||
test_numbers.o: test_numbers.c
|
||||
$(CC) $(FLAGS) -I$(unityfolder) -c test_numbers.c -o test_numbers.o
|
||||
|
||||
|
||||
# --- Binary Tree Tests ---
|
||||
binaryTests: bintree.o stack.o test_binary.o
|
||||
$(CC) $(FLAGS) -I$(unityfolder) -o $(BINARY_TEST_BIN) bintree.o stack.o test_binary.o $(unityfolder)/unity.c
|
||||
|
||||
test_binary.o: test_binary.c
|
||||
$(CC) $(FLAGS) -I$(unityfolder) -c test_binary.c -o test_binary.o
|
||||
|
||||
|
||||
# --------------------------
|
||||
# Clean
|
||||
@ -47,3 +75,4 @@ ifeq ($(OS),Windows_NT)
|
||||
else
|
||||
rm -f *.o doble
|
||||
endif
|
||||
|
||||
|
||||
100
numbers.c
100
numbers.c
@ -1,26 +1,96 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include "numbers.h"
|
||||
#include "bintree.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// TODO: getDuplicate und createNumbers implementieren
|
||||
/* * * Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an Zufallszahlen.
|
||||
* Sicherstellen, dass beim Befüllen keine Duplikate entstehen.
|
||||
/**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. */
|
||||
* 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.
|
||||
unsigned int *createNumbers(unsigned int len)
|
||||
{
|
||||
// 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.
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
unsigned int *createNumbers(unsigned int len) {
|
||||
if (len < 2) // Duplikat bei zwei Einträgen sinnlos
|
||||
return NULL;
|
||||
|
||||
unsigned int *numbersArray = malloc(
|
||||
sizeof(unsigned int) * len); // Speicher für das Ausgabearray reservieren:
|
||||
// Größe eines Eintrags * Größe des Arrays
|
||||
if (!numbersArray) // Speicher konnte nicht reserviert werden
|
||||
return NULL;
|
||||
|
||||
TreeNode *root =
|
||||
NULL; // Binärbaum zum Generieren der Zufallszahlen ohne Duplikate
|
||||
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
unsigned int currentNumber;
|
||||
int isDuplicate;
|
||||
do { // mindestens eine Zufallszahl erzeugen
|
||||
currentNumber = (rand() % (2 * len)) + 1; // Zahlenbereich 1 bis 2*len
|
||||
isDuplicate = 0;
|
||||
root = addToTree(root, ¤tNumber, sizeof(unsigned int),
|
||||
compareUnsignedInt,
|
||||
&isDuplicate); // compareUnsignedInt wird zum Verwenden
|
||||
// bei Vergleichen übergeben
|
||||
} while (isDuplicate); // wenn isDuplicate gesetzt wird, muss eine neue Zahl
|
||||
// erzeugt werden, die Schleife wird wiederholt
|
||||
numbersArray[i] = currentNumber;
|
||||
}
|
||||
|
||||
// Ein zufälliges Duplikat erzeugen
|
||||
unsigned int duplicateIndex =
|
||||
rand() % len; // Index des Duplikats per Zufall bestimmen
|
||||
unsigned int newIndex;
|
||||
do {
|
||||
newIndex = rand() % len;
|
||||
} while (newIndex == duplicateIndex); // zweiten Index bestimmen, der nicht
|
||||
// mit dem ersten übereinstimmt
|
||||
|
||||
numbersArray[newIndex] =
|
||||
numbersArray[duplicateIndex]; // Wert vom ersten Index kopieren
|
||||
|
||||
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
|
||||
// on errors.
|
||||
unsigned int getDuplicate(
|
||||
const unsigned int *numbers,
|
||||
unsigned int len) { // array numbers, sowie die Länge wird übergeben
|
||||
if (!numbers || len < 2)
|
||||
return 0; // fehlerhaftes Array
|
||||
|
||||
TreeNode *root = NULL; // leerer Baum
|
||||
unsigned int duplicateValue = 0; // Wert des Duplikats
|
||||
|
||||
for (unsigned int i = 0; i < len && duplicateValue == 0; i++) { // Schleife
|
||||
int isDuplicate = 0;
|
||||
|
||||
// Zahl in den Baum einfügen
|
||||
root = addToTree(root, &numbers[i], sizeof(unsigned int),
|
||||
compareUnsignedInt, &isDuplicate);
|
||||
|
||||
// Duplikat erkannt
|
||||
if (isDuplicate && duplicateValue == 0) {
|
||||
duplicateValue = numbers[i]; // Duplikat merken, for-Schleife wird beendet
|
||||
}
|
||||
}
|
||||
|
||||
clearTree(&root); // Baum freigeben
|
||||
return duplicateValue; // 0, falls kein Duplikat
|
||||
}
|
||||
12
numbers.h
12
numbers.h
@ -1,12 +1,16 @@
|
||||
#ifndef NUMBERS_H
|
||||
#define NUMBERS_H
|
||||
|
||||
// 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.
|
||||
int compareUnsignedInt(const void *a, const void *b);
|
||||
|
||||
// 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.
|
||||
unsigned int *createNumbers(unsigned int len);
|
||||
|
||||
// Returns only the only number in numbers which is present twice. Returns zero on errors.
|
||||
// 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);
|
||||
|
||||
#endif
|
||||
BIN
runTests.exe
Normal file
BIN
runTests.exe
Normal file
Binary file not shown.
93
stack.c
93
stack.c
@ -1,5 +1,14 @@
|
||||
#include <stdlib.h>
|
||||
#include "stack.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*typedef struct {
|
||||
|
||||
void *data;
|
||||
struct StackNode *next;
|
||||
struct StackNode *prev;
|
||||
|
||||
} StackNode;*/
|
||||
|
||||
// TODO: grundlegende Stackfunktionen implementieren:
|
||||
/* * `push`: legt ein Element oben auf den Stack,
|
||||
@ -7,27 +16,85 @@
|
||||
* `top`: liefert das oberste Element zurück,
|
||||
* `clearStack`: gibt den gesamten Speicher frei. */
|
||||
|
||||
// Pushes data as pointer onto the stack.
|
||||
StackNode *push(StackNode *stack, void *data)
|
||||
{
|
||||
// [A] -> [B] -> [C] -> NULL
|
||||
// stack -> stack.next
|
||||
|
||||
// Funktion zum erstellen neuer nodes
|
||||
StackNode *createNode(void *data) {
|
||||
// Speicher reservieren
|
||||
StackNode *node = malloc(sizeof(StackNode));
|
||||
// Speicher konnte nicht reserviert werden
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
|
||||
node->data = data;
|
||||
node->next = NULL;
|
||||
node->prev = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Pushes data as pointer onto the stack.
|
||||
StackNode *push(StackNode *stack, void *data) {
|
||||
|
||||
StackNode *newNode = createNode(data);
|
||||
|
||||
// Fehler beim Reservieren des Speichers, stack wird unverändert zurückgegeben
|
||||
if (newNode == NULL) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
// der aktuelle Kopf wird der nächste Node
|
||||
newNode->next = stack;
|
||||
|
||||
// bisheriger Kopf bekommt Pointer auf oberstes Element
|
||||
if (stack != NULL) {
|
||||
stack->prev = newNode;
|
||||
}
|
||||
|
||||
return newNode; // neuer Kopf wird zurückgegeben
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
// Stack ohne Elemente
|
||||
if (stack == NULL)
|
||||
return NULL;
|
||||
|
||||
// Element unter Kopf wird als nextNode gespeichert
|
||||
StackNode *nextNode = stack->next;
|
||||
if (nextNode != NULL) {
|
||||
nextNode->prev = NULL; // der Zeiger zum Kopf wird auf NULL gesetzt
|
||||
}
|
||||
|
||||
free(stack);
|
||||
|
||||
stack = NULL; // Speicher des Kopfes freigeben
|
||||
|
||||
return nextNode; // neuen Kopf zurückgeben
|
||||
}
|
||||
|
||||
// Returns the data of the top element.
|
||||
void *top(StackNode *stack)
|
||||
{
|
||||
|
||||
void *top(StackNode *stack) {
|
||||
// wenn stack leer ist, wird NULL zurückgegeben
|
||||
// Zeiger auf Daten des obersten Elements
|
||||
return stack ? stack->data : NULL;
|
||||
}
|
||||
|
||||
// Clears stack and releases all memory.
|
||||
void clearStack(StackNode *stack)
|
||||
{
|
||||
void clearStack(StackNode **stack) { // Zeiger auf den Zeiger auf den Stackkopf
|
||||
// verändert den Zeiger selbst, mit *stack lokale Kopie
|
||||
// im Aufruf &stack verwenden
|
||||
while (*stack != NULL) {
|
||||
|
||||
(*stack)->prev = NULL; // späteren Pointerzugriff verhindern
|
||||
StackNode *next = (*stack)->next; // nächstes Element speichern
|
||||
|
||||
(*stack)->next = NULL; // späteren Pointerzugriff verhindern
|
||||
|
||||
free(*stack); // aktuelles Element freigeben
|
||||
*stack = next; // Zeiger auf nächsten Knoten setzen
|
||||
}
|
||||
}
|
||||
22
stack.h
22
stack.h
@ -1,25 +1,35 @@
|
||||
#ifndef STACK_H
|
||||
#define STACK_H
|
||||
|
||||
/* A stack is a special type of queue which uses the LIFO (last in, first out) principle.
|
||||
This means that with each new element all other elements are pushed deeper into the stack.
|
||||
The latest element is taken from the stack. */
|
||||
/* A stack is a special type of queue which uses the LIFO (last in, first out)
|
||||
principle. This means that with each new element all other elements are pushed
|
||||
deeper into the stack. The latest element is taken from the stack. */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// TODO: passenden Datentyp als struct anlegen
|
||||
|
||||
typedef struct StackNode {
|
||||
|
||||
void *data;
|
||||
struct StackNode *next;
|
||||
struct StackNode *prev;
|
||||
|
||||
} StackNode;
|
||||
|
||||
StackNode *createNode(void *data);
|
||||
|
||||
// Pushes data as pointer onto the stack.
|
||||
StackNode *push(StackNode *stack, void *data);
|
||||
|
||||
// Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be
|
||||
// freed by caller.)
|
||||
// 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);
|
||||
|
||||
// Returns the data of the top element.
|
||||
void *top(StackNode *stack);
|
||||
|
||||
// Clears stack and releases all memory.
|
||||
void clearStack(StackNode *stack);
|
||||
void clearStack(StackNode **stack);
|
||||
|
||||
#endif
|
||||
|
||||
126
test_binary.c
Normal file
126
test_binary.c
Normal file
@ -0,0 +1,126 @@
|
||||
#include "unity.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bintree.h"
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
TreeNode *root = NULL;
|
||||
|
||||
void setUp(void) {
|
||||
root = NULL; // vor jedem Test leeren
|
||||
}
|
||||
|
||||
void tearDown(void) { clearTree(&root); }
|
||||
|
||||
// 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) {
|
||||
int isDuplicate;
|
||||
unsigned int testInt = 10;
|
||||
root = addToTree(root, &testInt, sizeof(testInt), compareUnsignedInt,
|
||||
&isDuplicate);
|
||||
TEST_ASSERT_NOT_NULL(root); // Knoten wurde erfolgreich erzeugt
|
||||
TEST_ASSERT_EQUAL_UINT(
|
||||
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
|
||||
void test_addToTree_duplicate(void) {
|
||||
int isDuplicate;
|
||||
unsigned int val1 = 10, val2 = 10; // Duplikate
|
||||
root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt,
|
||||
&isDuplicate); // val 1 zum leeren Baum hinzufügen
|
||||
TEST_ASSERT_EQUAL_INT(0, isDuplicate); // erster Knoten->kein Duplikat
|
||||
root = addToTree(root, &val2, sizeof(val2), compareUnsignedInt,
|
||||
&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
|
||||
void test_nextTreeData_in_order(void) {
|
||||
unsigned int values[] = {20, 10, 30}; // erwartete Ausgabe: 10 -> 20 -> 30
|
||||
int isDuplicate;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
root = addToTree(root, &values[i], sizeof(values[i]), compareUnsignedInt,
|
||||
&isDuplicate); // Baum füllen
|
||||
}
|
||||
|
||||
unsigned int expected[] = {10, 20, 30}; // erwartet in Order Reihenfolge
|
||||
int valueID = 0;
|
||||
void *data;
|
||||
|
||||
// Neue Iteration starten
|
||||
data = nextTreeData(root);
|
||||
while (data != NULL) {
|
||||
TEST_ASSERT_EQUAL_UINT(expected[valueID],
|
||||
*(unsigned int *)data); // entspricht erwartetem Wert
|
||||
|
||||
valueID++;
|
||||
data = nextTreeData(NULL); // weitere Elemente abrufen
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(3, valueID); // alle 3 Knoten besucht
|
||||
}
|
||||
|
||||
// Testet, dass clearTree Speicher freigibt und Root auf NULL setzt
|
||||
void test_clearTree_sets_root_null(void) {
|
||||
int isDuplicate;
|
||||
unsigned int val1 = 10, val2 = 20;
|
||||
|
||||
root = addToTree(root, &val1, sizeof(val1), compareUnsignedInt, &isDuplicate);
|
||||
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 treeSize zählt korrekt
|
||||
void test_treeSize(void) {
|
||||
unsigned int testInts[] = {10, 20, 5};
|
||||
int isDuplicate;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
root = addToTree(root, &testInts[i], sizeof(testInts[i]),
|
||||
compareUnsignedInt, &isDuplicate);
|
||||
}
|
||||
TEST_ASSERT_EQUAL_UINT(3, treeSize(root));
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
UNITY_BEGIN();
|
||||
|
||||
printf(
|
||||
"\n------------------------binarytree test------------------------\n\n");
|
||||
|
||||
RUN_TEST(test_addToTree_basic);
|
||||
RUN_TEST(test_addToTree_duplicate);
|
||||
RUN_TEST(test_nextTreeData_in_order);
|
||||
RUN_TEST(test_clearTree_sets_root_null);
|
||||
RUN_TEST(test_treeSize);
|
||||
return UNITY_END();
|
||||
}
|
||||
73
test_numbers.c
Normal file
73
test_numbers.c
Normal file
@ -0,0 +1,73 @@
|
||||
#include "unity.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "numbers.h"
|
||||
|
||||
#define TEST_ARRAY_LEN 100
|
||||
|
||||
// Speicher für ein Array wird reserviert
|
||||
void test_createNumbers_length(void) { // erstellt ein Array der Länge hundert
|
||||
unsigned int *testArray = createNumbers(TEST_ARRAY_LEN);
|
||||
TEST_ASSERT_NOT_NULL(testArray);
|
||||
free(testArray);
|
||||
}
|
||||
|
||||
// Duplikat ist genau einmal vorhanden
|
||||
void test_createNumbers_single_duplicate(void) {
|
||||
unsigned int *testArray = createNumbers(TEST_ARRAY_LEN); // Array erstellen
|
||||
TEST_ASSERT_NOT_NULL(testArray); // Speicher konnte reserviert werden
|
||||
|
||||
unsigned int duplicate =
|
||||
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; // Anzahl der Duplikate
|
||||
for (unsigned int i = 0; i < TEST_ARRAY_LEN;
|
||||
i++) { // Einträge des testArrays auf Duplikate prüfen
|
||||
if (testArray[i] == duplicate) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
TEST_ASSERT_EQUAL_UINT(2, count); // Duplikat zwei mal vorhanden
|
||||
|
||||
free(testArray); // Speicher freigeben
|
||||
}
|
||||
|
||||
// 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 duplicate = getDuplicate(numbers, 5);
|
||||
TEST_ASSERT_EQUAL_UINT(20, duplicate);
|
||||
}
|
||||
|
||||
// getDuplicate erkennt fehlerhaftes Array
|
||||
void test_getDuplicate_invalid_input(void) {
|
||||
TEST_ASSERT_EQUAL_UINT(
|
||||
0, getDuplicate(NULL, 5)); // unsigned int getDuplicate(const unsigned int
|
||||
// *numbers, unsigned int len)
|
||||
unsigned int testArray[1] = {2};
|
||||
TEST_ASSERT_EQUAL_UINT(0, getDuplicate(testArray, 1));
|
||||
}
|
||||
|
||||
void setUp(void) {}
|
||||
void tearDown(void) {}
|
||||
|
||||
int main(void) {
|
||||
|
||||
UNITY_BEGIN();
|
||||
|
||||
printf("\n------------------------numbers test------------------------\n\n");
|
||||
|
||||
RUN_TEST(test_createNumbers_length);
|
||||
RUN_TEST(test_createNumbers_single_duplicate);
|
||||
RUN_TEST(test_getDuplicate_manual_array);
|
||||
RUN_TEST(test_getDuplicate_invalid_input);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
144
test_stack.c
Normal file
144
test_stack.c
Normal file
@ -0,0 +1,144 @@
|
||||
#include "unity.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "stack.h"
|
||||
|
||||
// StackNode *createNode(void *data) testen
|
||||
void test_createNode(void) {
|
||||
|
||||
int testInt = 26;
|
||||
StackNode *testNode = createNode(&testInt); // Adresse des testInts
|
||||
|
||||
TEST_ASSERT_NOT_NULL(
|
||||
testNode); // Speicher konnte reserviert werden, malloc ist nicht NULL
|
||||
TEST_ASSERT_EQUAL_PTR(&testInt, testNode->data); // data pointer gesetzt
|
||||
TEST_ASSERT_NULL(testNode->next); // vorheriger und nächster Eintrag NULL
|
||||
TEST_ASSERT_NULL(testNode->prev);
|
||||
|
||||
free(testNode); // Speicher freigeben
|
||||
}
|
||||
|
||||
// StackNode *push(StackNode *stack, void *data) testen
|
||||
void test_pushDataToStack(void) {
|
||||
|
||||
int testInts[] = {27, 28};
|
||||
|
||||
StackNode *testStack = NULL; // leeren testStack initialisieren
|
||||
|
||||
testStack =
|
||||
push(testStack, &testInts[0]); // leerer Stack mit Adresse des testInts
|
||||
|
||||
TEST_ASSERT_NOT_NULL(testStack); // im Fehlerfall wird testStack unverändert
|
||||
// zurückgegeben -> bei Fehler NULL
|
||||
TEST_ASSERT_EQUAL_PTR(&testInts[0], testStack->data); // data pointer gesetzt
|
||||
TEST_ASSERT_NULL(testStack->next); // vorheriger und nächster pointer auf NULL
|
||||
// gesetzt, da es nur einen Knoten gibt
|
||||
TEST_ASSERT_NULL(testStack->prev);
|
||||
|
||||
// zweiter Push
|
||||
StackNode *oldHead = testStack; // bisherigen head speichern
|
||||
testStack = push(testStack, &testInts[1]);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(testStack);
|
||||
TEST_ASSERT_NOT_EQUAL(
|
||||
oldHead,
|
||||
testStack); // bei malloc Fehler wird der head unverändert zurückgegeben
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(&testInts[0],
|
||||
oldHead->data); // data pointer wurden richtig gesetzt
|
||||
TEST_ASSERT_EQUAL_PTR(&testInts[1], testStack->data);
|
||||
|
||||
// richtige Verkettung: NULL <- testStack -> testStack->next -> oldHead ->
|
||||
// NULL
|
||||
TEST_ASSERT_EQUAL_PTR(oldHead, testStack->next);
|
||||
TEST_ASSERT_EQUAL_PTR(testStack, oldHead->prev);
|
||||
TEST_ASSERT_NULL(testStack->prev);
|
||||
|
||||
// Speicherfreigabe
|
||||
testStack->next = NULL; // pointer ungültig machen, damit nicht ausversehen
|
||||
// später aufgerufen
|
||||
oldHead->prev = NULL;
|
||||
|
||||
free(oldHead);
|
||||
free(testStack);
|
||||
}
|
||||
|
||||
void test_deleteTopElement(void) {
|
||||
|
||||
int testInts[] = {10, 20, 30};
|
||||
StackNode *stack = NULL;
|
||||
|
||||
for (int i = 0; i < 3;
|
||||
i++) { // Stack mit drei Elementen, oberestes Element mit data 30
|
||||
stack = push(stack, &testInts[i]);
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(&testInts[2], stack->data); // oberstes Element ist 30
|
||||
|
||||
stack = pop(stack); // oberstes Element löschen
|
||||
TEST_ASSERT_EQUAL_PTR(&testInts[1], stack->data);
|
||||
TEST_ASSERT_NULL(
|
||||
stack->prev); // pointer zum alten head wurde auf NULL gesetzt
|
||||
|
||||
stack = pop(stack);
|
||||
TEST_ASSERT_EQUAL_PTR(&testInts[0], stack->data);
|
||||
TEST_ASSERT_NULL(stack->prev);
|
||||
|
||||
stack = pop(stack); // bei leerem Stack wird NULL zurückgegeben
|
||||
TEST_ASSERT_NULL(stack);
|
||||
}
|
||||
|
||||
void test_returnData(void) {
|
||||
|
||||
int testInts[] = {10, 20, 30};
|
||||
StackNode *stack = NULL;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
stack = push(stack, &testInts[i]);
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(&testInts[2],
|
||||
top(stack)); // top gibt richtige Adresse zurück
|
||||
stack = pop(stack); // oberstes Element löschen
|
||||
TEST_ASSERT_EQUAL_PTR(&testInts[1], top(stack));
|
||||
|
||||
stack = pop(stack);
|
||||
TEST_ASSERT_EQUAL_PTR(&testInts[0], top(stack));
|
||||
|
||||
stack = pop(stack); // bei leerem Stack wird NULL zurückgegeben
|
||||
TEST_ASSERT_NULL(stack);
|
||||
}
|
||||
|
||||
void test_clearStack(void) {
|
||||
int testInts[] = {1, 2, 3, 4, 5};
|
||||
StackNode *stack = NULL;
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
stack = push(stack, &testInts[i]);
|
||||
}
|
||||
//printf("testints: %d,%d,%d,%d,%d",testInts[0],testInts[1],testInts[2],testInts[3],testInts[4]);
|
||||
|
||||
clearStack(&stack);
|
||||
|
||||
TEST_ASSERT_NULL(stack);
|
||||
}
|
||||
|
||||
void setUp(void) {}
|
||||
void tearDown(void) {}
|
||||
|
||||
int main(void) {
|
||||
|
||||
UNITY_BEGIN();
|
||||
|
||||
printf("\n------------------------stack test------------------------\n\n");
|
||||
|
||||
RUN_TEST(test_createNode);
|
||||
RUN_TEST(test_pushDataToStack);
|
||||
RUN_TEST(test_deleteTopElement);
|
||||
RUN_TEST(test_returnData);
|
||||
RUN_TEST(test_clearStack);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user