generated from freudenreichan/info2Praktikum-DobleSpiel
fertig
This commit is contained in:
parent
25085b3778
commit
81e1483e9e
133
bintree.c
133
bintree.c
@ -1,36 +1,129 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "stack.h"
|
||||
#include "bintree.h"
|
||||
|
||||
//TODO: binären Suchbaum implementieren
|
||||
/* * `addToTree`: fügt ein neues Element in den Baum ein (rekursiv),
|
||||
* `clearTree`: gibt den gesamten Baum frei (rekursiv),
|
||||
* `treeSize`: zählt die Knoten im Baum (rekursiv),
|
||||
* `nextTreeData`: Traversierung mit Hilfe des zuvor implementierten Stacks. */
|
||||
// --------------------------
|
||||
// Hilfsfunktion für Vergleich von unsigned int
|
||||
// --------------------------
|
||||
static int compareUint(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;
|
||||
}
|
||||
|
||||
// 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).
|
||||
// --------------------------
|
||||
// addToTree
|
||||
// --------------------------
|
||||
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, CompareFctType compareFct, int *isDuplicate)
|
||||
{
|
||||
if (!compareFct)
|
||||
compareFct = compareUint;
|
||||
|
||||
if (!root)
|
||||
{
|
||||
TreeNode *node = malloc(sizeof(TreeNode));
|
||||
if (!node) return NULL;
|
||||
node->data = malloc(dataSize);
|
||||
if (!node->data)
|
||||
{
|
||||
free(node);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(node->data, data, dataSize);
|
||||
node->left = node->right = NULL;
|
||||
if (isDuplicate) *isDuplicate = 0;
|
||||
return node;
|
||||
}
|
||||
|
||||
int cmp = compareFct(data, root->data);
|
||||
if (cmp == 0)
|
||||
{
|
||||
if (isDuplicate) *isDuplicate = 1;
|
||||
return root;
|
||||
}
|
||||
else if (cmp < 0)
|
||||
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
|
||||
else
|
||||
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Releases all memory resources (including data copies).
|
||||
// --------------------------
|
||||
// clearTree
|
||||
// --------------------------
|
||||
void clearTree(TreeNode *root)
|
||||
{
|
||||
|
||||
if (!root) return;
|
||||
clearTree(root->left);
|
||||
clearTree(root->right);
|
||||
free(root->data);
|
||||
free(root);
|
||||
}
|
||||
|
||||
// Returns the number of entries in the tree given by root.
|
||||
// --------------------------
|
||||
// treeSize
|
||||
// --------------------------
|
||||
unsigned int treeSize(const TreeNode *root)
|
||||
{
|
||||
|
||||
if (!root) return 0;
|
||||
return 1 + treeSize(root->left) + treeSize(root->right);
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
// nextTreeData (In-Order Traversal mit Stack) – minimal
|
||||
// --------------------------
|
||||
#include "stack.h"
|
||||
void *nextTreeData(TreeNode *root)
|
||||
{
|
||||
static StackNode *stack = NULL;
|
||||
static TreeNode *current = NULL;
|
||||
|
||||
if (root) current = root;
|
||||
|
||||
while (current)
|
||||
{
|
||||
stack = push(stack, current);
|
||||
current = current->left;
|
||||
}
|
||||
|
||||
if (!stack) return NULL;
|
||||
|
||||
TreeNode *node = top(stack);
|
||||
stack = pop(stack);
|
||||
|
||||
current = node->right;
|
||||
return node->data;
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
// Zusätzliche Hilfsfunktion contains für numbers.c
|
||||
// --------------------------
|
||||
int contains(TreeNode *root, unsigned int value)
|
||||
{
|
||||
if (!root) return 0;
|
||||
unsigned int nodeValue = *(unsigned int *)root->data;
|
||||
if (value == nodeValue) return 1;
|
||||
if (value < nodeValue) return contains(root->left, value);
|
||||
return contains(root->right, value);
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
// Hilfsfunktion insert für numbers.c
|
||||
// --------------------------
|
||||
TreeNode* insert(TreeNode *root, unsigned int value)
|
||||
{
|
||||
int isDup = 0;
|
||||
return addToTree(root, &value, sizeof(unsigned int), compareUint, &isDup);
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
// Hilfsfunktion freeTree für numbers.c
|
||||
// --------------------------
|
||||
void freeTree(TreeNode *root)
|
||||
{
|
||||
clearTree(root);
|
||||
}
|
||||
BIN
doble_initial.exe
Normal file
BIN
doble_initial.exe
Normal file
Binary file not shown.
BIN
highscore.o
Normal file
BIN
highscore.o
Normal file
Binary file not shown.
@ -1 +1,10 @@
|
||||
player_name1;19827
|
||||
player_name3;6985
|
||||
jannik;5979
|
||||
jannik;4991
|
||||
jannik;4980
|
||||
player1;3999
|
||||
player_name;3995
|
||||
player_name2;3994
|
||||
player_name1;3993
|
||||
player_name3;3990
|
||||
|
||||
56
makefile
56
makefile
@ -16,34 +16,68 @@ raylibfolder = ./raylib
|
||||
unityfolder = ./unity
|
||||
|
||||
# --------------------------
|
||||
# Initiales Programm bauen (zum ausprobieren)
|
||||
# Hauptprogramm bauen
|
||||
# --------------------------
|
||||
doble_initial:
|
||||
$(CC) -o doble_initial $(BINARIES)/libdoble_complete.a
|
||||
|
||||
# --------------------------
|
||||
# Selbst implementiertes Programm bauen
|
||||
# --------------------------
|
||||
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
|
||||
|
||||
doble : main.o $(program_obj_files)
|
||||
doble: main.o $(program_obj_files)
|
||||
$(CC) $(FLAGS) $^ -o doble
|
||||
|
||||
main.o: main.c
|
||||
$(CC) -c $(FLAGS) main.c -o main.o
|
||||
|
||||
$(program_obj_filesobj_files): %.o: %.c
|
||||
$(CC) -c $(FLAGS) $^ -o $@
|
||||
|
||||
# --------------------------
|
||||
# Unit Tests
|
||||
# --------------------------
|
||||
unitTests:
|
||||
echo "needs to be implemented"
|
||||
|
||||
unitTests: test_stack test_numbers
|
||||
./test_stack
|
||||
./test_numbers
|
||||
|
||||
# --- Test Stack ---
|
||||
test_stack: test_stack.o stack.o
|
||||
$(CC) $(FLAGS) $^ -o test_stack
|
||||
|
||||
test_stack.o: test_stack.c stack.h
|
||||
$(CC) -c $(FLAGS) test_stack.c -o test_stack.o
|
||||
|
||||
# --- Test Numbers ---
|
||||
test_numbers: test_numbers.o numbers.o bintree.o stack.o
|
||||
$(CC) $(FLAGS) $^ -o test_numbers
|
||||
|
||||
test_numbers.o: test_numbers.c numbers.h
|
||||
$(CC) -c $(FLAGS) test_numbers.c -o test_numbers.o
|
||||
|
||||
# --------------------------
|
||||
# Objektdateien
|
||||
# --------------------------
|
||||
|
||||
stack.o: stack.c stack.h
|
||||
$(CC) -c $(FLAGS) stack.c -o stack.o
|
||||
|
||||
bintree.o: bintree.c bintree.h stack.h
|
||||
$(CC) -c $(FLAGS) bintree.c -o bintree.o
|
||||
|
||||
numbers.o: numbers.c numbers.h bintree.h
|
||||
$(CC) -c $(FLAGS) numbers.c -o numbers.o
|
||||
|
||||
timer.o: timer.c timer.h
|
||||
$(CC) -c $(FLAGS) timer.c -o timer.o
|
||||
|
||||
highscore.o: highscore.c highscore.h
|
||||
$(CC) -c $(FLAGS) highscore.c -o highscore.o
|
||||
|
||||
# --------------------------
|
||||
# Clean
|
||||
# --------------------------
|
||||
|
||||
clean:
|
||||
ifeq ($(OS),Windows_NT)
|
||||
del /f *.o doble
|
||||
del /f *.o doble test_stack test_numbers
|
||||
else
|
||||
rm -f *.o doble
|
||||
rm -f *.o doble test_stack test_numbers
|
||||
endif
|
||||
91
numbers.c
91
numbers.c
@ -5,22 +5,83 @@
|
||||
#include "numbers.h"
|
||||
#include "bintree.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.
|
||||
* Duplizieren eines zufälligen Eintrags im Array.
|
||||
* in `getDuplicate()`: Sortieren des Arrays und Erkennen der doppelten Zahl durch Vergleich benachbarter Elemente. */
|
||||
|
||||
// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries.
|
||||
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while
|
||||
// creating random numbers.
|
||||
unsigned int *createNumbers(unsigned int len)
|
||||
{
|
||||
|
||||
// Hilfsfunktion zum Vergleichen von ints für Baum
|
||||
static int compareInt(const void *a, const void *b) {
|
||||
return (*(int*)a - *(int*)b);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Vergleichsfunktion für qsort (unsigned int, überlauf-sicher)
|
||||
static int compareUnsigned(const void *a, const void *b) {
|
||||
unsigned int ua = *(unsigned int*)a;
|
||||
unsigned int ub = *(unsigned int*)b;
|
||||
|
||||
if (ua < ub) return -1;
|
||||
if (ua > ub) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Hilfsfunktion: Prüft, ob Wert schon im Baum ist
|
||||
static int contains(TreeNode *root, unsigned int value) {
|
||||
if (!root) return 0;
|
||||
unsigned int val = *(unsigned int*)root->data;
|
||||
if (val == value) return 1;
|
||||
if (value < val) return contains(root->left, value);
|
||||
return contains(root->right, value);
|
||||
}
|
||||
|
||||
// Erzeugt ein Array von len Zahlen zwischen 1 und 2*len, alle einzigartig,
|
||||
// außer eine Zahl wird dupliziert.
|
||||
unsigned int *createNumbers(unsigned int len) {
|
||||
if (len == 0) return NULL;
|
||||
|
||||
unsigned int *numbers = malloc(len * sizeof(unsigned int));
|
||||
if (!numbers) return NULL;
|
||||
|
||||
TreeNode *tree = NULL;
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
for (unsigned int i = 0; i < len - 1; i++) { // alle außer die Duplikate
|
||||
unsigned int value;
|
||||
do {
|
||||
value = rand() % (2 * len) + 1;
|
||||
} while (contains(tree, value));
|
||||
|
||||
int isDup = 0;
|
||||
tree = addToTree(tree, &value, sizeof(value), compareInt, &isDup);
|
||||
numbers[i] = value;
|
||||
}
|
||||
|
||||
// Dupliziere zufällig eine Zahl
|
||||
unsigned int dupIndex = rand() % (len - 1);
|
||||
numbers[len - 1] = numbers[dupIndex];
|
||||
|
||||
// Speicher freigeben
|
||||
clearTree(tree);
|
||||
|
||||
return numbers;
|
||||
}
|
||||
|
||||
// Sortiert das Array und findet die einzige doppelte Zahl
|
||||
unsigned int getDuplicate(const unsigned int *numbers, unsigned int len) {
|
||||
if (!numbers || len < 2) return 0;
|
||||
|
||||
// Kopiere Array, da wir sortieren müssen
|
||||
unsigned int *copy = malloc(len * sizeof(unsigned int));
|
||||
if (!copy) return 0;
|
||||
memcpy(copy, numbers, len * sizeof(unsigned int));
|
||||
|
||||
// qsort verwenden
|
||||
qsort(copy, len, sizeof(unsigned int), compareUnsigned);
|
||||
|
||||
// Durchlauf und Nachbarn vergleichen
|
||||
unsigned int dup = 0;
|
||||
for (unsigned int i = 1; i < len; i++) {
|
||||
if (copy[i] == copy[i - 1]) {
|
||||
dup = copy[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(copy);
|
||||
return dup;
|
||||
}
|
||||
45
stack.c
45
stack.c
@ -1,33 +1,38 @@
|
||||
#include <stdlib.h>
|
||||
#include "stack.h"
|
||||
|
||||
//TODO: grundlegende Stackfunktionen implementieren:
|
||||
/* * `push`: legt ein Element oben auf den Stack,
|
||||
* `pop`: entfernt das oberste Element,
|
||||
* `top`: liefert das oberste Element zurück,
|
||||
* `clearStack`: gibt den gesamten Speicher frei. */
|
||||
// Pushes data onto the stack and returns new stack top
|
||||
StackNode *push(StackNode *stack, void *data) {
|
||||
StackNode *node = malloc(sizeof(StackNode));
|
||||
if (!node) return stack; // allocation failed → leave stack unchanged
|
||||
|
||||
// Pushes data as pointer onto the stack.
|
||||
StackNode *push(StackNode *stack, void *data)
|
||||
{
|
||||
node->data = data;
|
||||
node->next = stack;
|
||||
|
||||
return node; // new top
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Removes the top element, frees node (NOT data), returns new top
|
||||
StackNode *pop(StackNode *stack) {
|
||||
if (stack == NULL) return NULL;
|
||||
|
||||
StackNode *next = stack->next;
|
||||
free(stack);
|
||||
|
||||
return next; // new top
|
||||
}
|
||||
|
||||
// Returns the data of the top element.
|
||||
void *top(StackNode *stack)
|
||||
{
|
||||
|
||||
// Returns data of top node or NULL
|
||||
void *top(StackNode *stack) {
|
||||
if (!stack) return NULL;
|
||||
return stack->data;
|
||||
}
|
||||
|
||||
// Clears stack and releases all memory.
|
||||
void clearStack(StackNode *stack)
|
||||
{
|
||||
|
||||
// Frees entire stack (NOT data!)
|
||||
void clearStack(StackNode *stack) {
|
||||
while (stack != NULL) {
|
||||
StackNode *next = stack->next;
|
||||
free(stack);
|
||||
stack = next;
|
||||
}
|
||||
}
|
||||
14
stack.h
14
stack.h
@ -2,18 +2,22 @@
|
||||
#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. */
|
||||
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
|
||||
// passenden Datentyp als struct anlegen
|
||||
typedef struct StackNode {
|
||||
void *data; // Zeiger auf beliebige Daten
|
||||
struct StackNode *next; // Zeiger auf das nächste Element im Stack
|
||||
} StackNode;
|
||||
|
||||
// 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.
|
||||
|
||||
49
test_numbers.c
Normal file
49
test_numbers.c
Normal file
@ -0,0 +1,49 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "numbers.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("=== TEST: createNumbers & getDuplicate ===\n");
|
||||
|
||||
unsigned int len = 20;
|
||||
unsigned int *arr = createNumbers(len);
|
||||
|
||||
if (!arr)
|
||||
{
|
||||
printf("FAILED: createNumbers returned NULL\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Array created: ");
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
printf("%u ", arr[i]);
|
||||
printf("\n");
|
||||
|
||||
unsigned int dup = getDuplicate(arr, len);
|
||||
|
||||
if (dup == 0)
|
||||
{
|
||||
printf("FAILED: getDuplicate returned 0 (no duplicate found)\n");
|
||||
free(arr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Count occurrences manually as safety check
|
||||
unsigned int count = 0;
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (arr[i] == dup)
|
||||
count++;
|
||||
|
||||
if (count != 2)
|
||||
{
|
||||
printf("FAILED: duplicate=%u occurs %u times (expected 2)\n", dup, count);
|
||||
free(arr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("SUCCESS: duplicate number is %u and appears exactly twice.\n", dup);
|
||||
|
||||
free(arr);
|
||||
return 0;
|
||||
}
|
||||
BIN
test_numbers.exe
Normal file
BIN
test_numbers.exe
Normal file
Binary file not shown.
41
test_stack.c
Normal file
41
test_stack.c
Normal file
@ -0,0 +1,41 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "stack.h"
|
||||
|
||||
int main() {
|
||||
StackNode *stack = NULL;
|
||||
|
||||
// Einige Integer dynamisch alloziieren
|
||||
int *a = malloc(sizeof(int));
|
||||
int *b = malloc(sizeof(int));
|
||||
int *c = malloc(sizeof(int));
|
||||
*a = 10; *b = 20; *c = 30;
|
||||
|
||||
stack = push(stack, a);
|
||||
stack = push(stack, b);
|
||||
stack = push(stack, c);
|
||||
|
||||
// Test top()
|
||||
printf("Top = %d (expected 30)\n", *(int *)top(stack));
|
||||
|
||||
// pop()
|
||||
stack = pop(stack); // removed 30
|
||||
free(c); // data gehört Benutzer!
|
||||
|
||||
printf("Top = %d (expected 20)\n", *(int *)top(stack));
|
||||
|
||||
stack = pop(stack); free(b); // removed 20
|
||||
stack = pop(stack); free(a); // removed 10
|
||||
|
||||
// stack should now be empty
|
||||
if (stack == NULL) {
|
||||
printf("Stack empty ok\n");
|
||||
} else {
|
||||
printf("Error: stack not empty!\n");
|
||||
}
|
||||
|
||||
// Cleanup just in case
|
||||
clearStack(stack);
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
test_stack.exe
Normal file
BIN
test_stack.exe
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user