Compare commits

..

11 Commits
main ... main

Author SHA1 Message Date
746b9b7219 Merge pull request 'fix: apply build FLAGS correctly' (#4) from wiesendsi102436/info2Praktikum-DobleSpiel:bugfix/makefile into main
Reviewed-on: freudenreichan/info2Praktikum-DobleSpiel#4
2025-12-15 14:20:07 +00:00
1f3fba80ec Merge pull request 'Hinweis hinzugefügt, dass Studis auch für den bintree Unittests schreiben sollen.' (#7) from schroederen/info2Praktikum-DobleSpiel:main into main
Reviewed-on: freudenreichan/info2Praktikum-DobleSpiel#7
2025-12-15 14:17:18 +00:00
1d363980f6 Hinweis hinzugefügt, dass Studis auch für den bintree Unittests schreiben sollen. 2025-12-15 15:16:50 +01:00
4ce3a6aac0
fix: apply build FLAGS correctly
A typo in the dependency variable program_obj_files caused make to fall back to implicit/default rules. FLAGS was ignored because the default behavior is to use CFLAGS.
2025-11-30 10:55:37 +01:00
c325131503 Merge pull request 'Update doble libs.' (#3) from schroederen/info2Praktikum-DobleSpiel:main into main
Reviewed-on: freudenreichan/info2Praktikum-DobleSpiel#3
2025-11-17 12:20:46 +00:00
6f7c21e179 Update doble libs.
timer.c ist nun plattformunabhängig.
2025-11-17 13:19:17 +01:00
0e13d1035e libdoble_complete.a gelöscht 2025-11-17 10:58:13 +00:00
f4dd2a5c08 Merge pull request 'Windows lib hinzugefügt.' (#2) from schroederen/info2Praktikum-DobleSpiel:main into main
Reviewed-on: freudenreichan/info2Praktikum-DobleSpiel#2
2025-11-17 10:57:37 +00:00
c29dd0606e Windows lib hinzugefügt. 2025-11-17 11:57:06 +01:00
4a21be2e21 Merge pull request 'Startcode angepasst, sodass nur eine Version für alle Plattformen existiert.' (#1) from schroederen/info2Praktikum-DobleSpiel:main into main
Reviewed-on: freudenreichan/info2Praktikum-DobleSpiel#1
2025-11-17 10:53:42 +00:00
85cb9514b2 Startcode angepasst, sodass nur eine Version für alle Plattformen existiert. 2025-11-17 11:52:26 +01:00
31 changed files with 119 additions and 426 deletions

Binary file not shown.

140
bintree.c
View File

@ -1,144 +1,36 @@
#include <stdlib.h>
#include <string.h>
#include "bintree.h"
#include "stack.h"
#include "bintree.h"
/* Fügt eine Kopie der Daten in den Baum ein, geordnet nach compareFct. Akzeptiert Duplikate,
wenn isDuplicate NULL ist, andernfalls ignoriert Duplikate und setzt isDuplicate auf 1 (oder auf 0 bei neuem Eintrag). */
//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. */
// 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)
{
// Überprüfe ungültige Eingabeparameter
if (compareFct == NULL || data == NULL || dataSize == 0)
return root; // ungültige Eingabe: nichts tun
// Wenn der Baum leer ist, erstelle einen neuen Wurzelknoten
if (root == NULL)
{
TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode));
if (node == NULL)
return NULL; // Speicherallokation fehlgeschlagen
node->data = malloc(dataSize);
if (node->data == NULL)
{
free(node);
return NULL;
}
memcpy(node->data, data, dataSize);
node->left = NULL;
node->right = NULL;
if (isDuplicate != NULL)
*isDuplicate = 0;
return node;
}
// Vergleiche neue Daten mit aktueller Wurzel
int cmp = compareFct(data, root->data);
// Wenn neue Daten kleiner sind, füge in linken Unterbaum ein
if (cmp < 0)
{
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
}
// Wenn neue Daten größer sind, füge in rechten Unterbaum ein
else if (cmp > 0)
{
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
}
// Wenn gleich (Duplikat)
else
{
// Wenn Duplikate erkannt werden sollen, setze Flag und ignoriere
if (isDuplicate != NULL)
{
*isDuplicate = 1;
}
// Andernfalls erlaube Duplikate durch Einfügen in rechten Unterbaum
else
{
root->right = addToTree(root->right, data, dataSize, compareFct, isDuplicate);
}
}
return root;
}
/* Iteriert über den Baum in aufsteigender Reihenfolge (in-order).
Verwendet die Logik von strtok: Wenn root != NULL, initialisiere/reset Iterator für diesen Baum.
Wenn root == NULL, setze Iteration von letzter Position fort.
Verwendet Stack zur Verwaltung des Traversierungs-Zustands. */
// 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)
{
// Statischer Stack zur Aufrechterhaltung des Iterator-Zustands zwischen Aufrufen
static StackNode *iterStack = NULL;
// Wenn ein neuer Baum bereitgestellt wird, initialisiere den Iterator
if (root != NULL)
{
// Lösche vorherigen Iterator-Zustand
clearStack(iterStack);
iterStack = NULL;
// Pushe die Wurzel und alle linken Nachfahren auf den Stack
TreeNode *cur = root;
while (cur != NULL)
{
iterStack = push(iterStack, cur);
cur = cur->left;
}
}
else
{
// Wenn Iteration fortgesetzt wird, aber kein Stack initialisiert, gib NULL zurück
if (iterStack == NULL)
return NULL;
}
// Wenn Stack leer ist, keine weiteren Elemente
if (iterStack == NULL)
return NULL;
// Poppe den nächsten Knoten vom Stack (in-order-Traversierung)
TreeNode *node = (TreeNode *)top(iterStack);
iterStack = pop(iterStack);
// Pushe den rechten Unterbaum des aktuellen Knotens und seine linken Nachfahren
TreeNode *r = node->right;
while (r != NULL)
{
iterStack = push(iterStack, r);
r = r->left;
}
return node->data;
}
/* Gibt alle Speicherressourcen frei (einschließlich Datenkopien). */
// Releases all memory resources (including data copies).
void clearTree(TreeNode *root)
{
// Basisfall: wenn Baum leer, nichts tun
if (root == NULL)
return;
// Rekursiv linken und rechten Unterbaum löschen
if (root->left != NULL)
clearTree(root->left);
if (root->right != NULL)
clearTree(root->right);
// Daten und Knoten selbst freigeben
free(root->data);
root->data = NULL;
free(root);
}
/* Gibt die Anzahl der Einträge im Baum zurück. */
// Returns the number of entries in the tree given by root.
unsigned int treeSize(const TreeNode *root)
{
// Basisfall: leerer Baum hat Größe 0
if (root == NULL)
return 0;
// Größe ist 1 (aktueller Knoten) plus Größen der Unterbäume
return 1 + treeSize(root->left) + treeSize(root->right);
}
}

BIN
bintree.o

Binary file not shown.

BIN
doble.exe

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
player1;3999

BIN
linux/libdoble_complete.a Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
main.o

Binary file not shown.

View File

@ -1,9 +1,19 @@
CC = gcc
FLAGS = -g -Wall -lm
BINARIES = ./windows
ifeq ($(OS),Windows_NT)
include makefile_windows.variables
else
UNAME = $(shell uname)
ifeq ($(UNAME),Linux)
include makefile_linux.variables
else
include makefile_mac.variables
endif
endif
raylibfolder = ./raylib
unityfolder = ./unity
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
# --------------------------
# Initiales Programm bauen (zum ausprobieren)
@ -14,10 +24,12 @@ doble_initial:
# --------------------------
# Selbst implementiertes Programm bauen
# --------------------------
program_obj_files = stack.o bintree.o numbers.o timer.o highscore.o
doble : main.o $(program_obj_files)
$(CC) $(FLAGS) $^ -o doble
$(program_obj_filesobj_files): %.o: %.c
$(program_obj_files): %.o: %.c
$(CC) -c $(FLAGS) $^ -o $@
# --------------------------
@ -30,4 +42,8 @@ unitTests:
# Clean
# --------------------------
clean:
rm -f *.o doble
ifeq ($(OS),Windows_NT)
del /f *.o doble
else
rm -f *.o doble
endif

2
makefile_linux.variables Normal file
View File

@ -0,0 +1,2 @@
LDFLAGS = -lGL -lX11 -lm
BINARIES = ./linux

3
makefile_mac.variables Normal file
View File

@ -0,0 +1,3 @@
LDFLAGS = -framework OpenGL -framework CoreFoundation -framework CoreGraphics -framework IOKit -framework Cocoa -framework CoreVideo
ARCH := $(shell uname -m)
BINARIES = ./macos-$(ARCH)

View File

@ -0,0 +1,2 @@
LDFLAGS = -lopengl32 -lgdi32 -lwinmm
BINARIES = ./windows

113
numbers.c
View File

@ -5,115 +5,22 @@
#include "numbers.h"
#include "bintree.h"
// --- Hilfsfunktion: Vergleich von unsigned int ------------------
static int compareUInt(const void *a, const void *b)
{
unsigned int ua = *(const unsigned int *)a;
unsigned int ub = *(const unsigned int *)b;
//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. */
if (ua < ub) return -1;
if (ua > ub) return 1;
return 0;
}
// --- Hilfsfunktion: Shuffle des Arrays (Fisher-Yates) ------------------
static void shuffle(unsigned int *array, unsigned int len)
{
for (unsigned int i = len - 1; i > 0; i--)
{
unsigned int j = rand() % (i + 1);
unsigned int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
// Gibt ein Array mit len zufälligen Zahlen zwischen 1 und 2*len zurück, die alle unterschiedlich sind,
// außer zwei Einträgen (ein Duplikat). Verwendet den Binärbaum, um Duplikate zu vermeiden.
// 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)
{
// Überprüfe ungültige Länge
if (len < 2)
return NULL;
// Allokiere Speicher für das Array
unsigned int *arr = malloc(sizeof(unsigned int) * len);
if (!arr)
return NULL;
// Initialisiere Zufallszahlengenerator
srand((unsigned int)time(NULL));
TreeNode *root = NULL;
unsigned int count = 0;
// Generiere len-1 eindeutige Zahlen
while (count < len - 1)
{
unsigned int val = (rand() % (2 * len)) + 1;
int isDup = 0;
// Füge in Baum ein und prüfe auf Duplikat
root = addToTree(root, &val, sizeof(unsigned int), compareUInt, &isDup);
if (!isDup)
{
arr[count++] = val;
}
}
// Wähle einen zufälligen bestehenden Wert als Duplikat
unsigned int duplicateIndex = rand() % (len - 1);
arr[len - 1] = arr[duplicateIndex];
// Shuffle das Array, damit das Duplikat nicht immer am Ende steht
shuffle(arr, len);
// Baum freigeben
clearTree(root);
return arr;
}
// Gibt die einzige Zahl im Array zurück, die zweimal vorkommt.
// 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)
{
// Überprüfe ungültige Eingaben
if (!numbers || len < 2)
return 0;
// Kopiere Array
unsigned int *copy = malloc(sizeof(unsigned int) * len);
if (!copy)
return 0;
memcpy(copy, numbers, sizeof(unsigned int) * len);
// Sortiere das Array (einfache Bubble-Sort)
for (unsigned int i = 0; i < len - 1; i++)
{
for (unsigned int j = i + 1; j < len; j++)
{
if (copy[j] < copy[i])
{
unsigned int t = copy[i];
copy[i] = copy[j];
copy[j] = t;
}
}
}
// Finde angrenzendes Duplikat
unsigned int duplicate = 0;
for (unsigned int i = 0; i < len - 1; i++)
{
if (copy[i] == copy[i + 1])
{
duplicate = copy[i];
break;
}
}
// Speicher freigeben
free(copy);
return duplicate;
}
}

BIN
numbers.o

Binary file not shown.

30
stack.c
View File

@ -1,45 +1,33 @@
#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 as pointer onto the stack.
StackNode *push(StackNode *stack, void *data)
{
StackNode *newNode = (StackNode *)malloc(sizeof(StackNode));
if (newNode == NULL)
return stack; // allocation failed: return unchanged stack
newNode->data = data;
newNode->next = stack;
return newNode;
}
// Deletes the top element of the stack (latest added element) and releases its memory. (Pointer to data has to be
// freed by caller.)
StackNode *pop(StackNode *stack)
{
if (stack == NULL)
return NULL;
StackNode *next = stack->next;
free(stack);
return next;
}
// Returns the data of the top element.
void *top(StackNode *stack)
{
if (stack == NULL)
return NULL;
return stack->data;
}
// Clears stack and releases all memory.
void clearStack(StackNode *stack)
{
while (stack != NULL)
{
StackNode *next = stack->next;
free(stack);
stack = next;
}
}
}

View File

@ -8,10 +8,6 @@ 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;
} StackNode;
// Pushes data as pointer onto the stack.
StackNode *push(StackNode *stack, void *data);

BIN
stack.o

Binary file not shown.

View File

@ -1,68 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bintree.h"
// Hilfsfunktion: Vergleich von int
static int compareInt(const void *a, const void *b) {
int ia = *(const int *)a;
int ib = *(const int *)b;
if (ia < ib) return -1;
if (ia > ib) return 1;
return 0;
}
int main() {
printf("===== TEST BINTREE =====\n");
TreeNode *root = NULL;
int isDup;
// Test 1: addToTree - Einfügen eindeutiger Werte
int val1 = 10, val2 = 5, val3 = 15;
root = addToTree(root, &val1, sizeof(int), compareInt, &isDup);
if (isDup != 0) { printf("FAIL: Erstes Einfügen sollte kein Duplikat sein\n"); return 1; }
root = addToTree(root, &val2, sizeof(int), compareInt, &isDup);
if (isDup != 0) { printf("FAIL: Zweites Einfügen sollte kein Duplikat sein\n"); return 1; }
root = addToTree(root, &val3, sizeof(int), compareInt, &isDup);
if (isDup != 0) { printf("FAIL: Drittes Einfügen sollte kein Duplikat sein\n"); return 1; }
printf("PASS: addToTree - eindeutige Werte\n");
// Test 2: addToTree - Duplikat hinzufügen
int dup = 10;
root = addToTree(root, &dup, sizeof(int), compareInt, &isDup);
if (isDup != 1) { printf("FAIL: Duplikat sollte erkannt werden\n"); return 1; }
printf("PASS: addToTree - Duplikat erkannt\n");
// Test 3: treeSize
unsigned int size = treeSize(root);
if (size != 3) { printf("FAIL: treeSize sollte 3 sein, ist %u\n", size); return 1; }
printf("PASS: treeSize\n");
// Test 4: nextTreeData - Iteration (in-order: 5, 10, 15)
void *data = nextTreeData(root);
if (data == NULL || *(int*)data != 5) { printf("FAIL: Erstes Element sollte 5 sein\n"); return 1; }
data = nextTreeData(NULL);
if (data == NULL || *(int*)data != 10) { printf("FAIL: Zweites Element sollte 10 sein\n"); return 1; }
data = nextTreeData(NULL);
if (data == NULL || *(int*)data != 15) { printf("FAIL: Drittes Element sollte 15 sein\n"); return 1; }
data = nextTreeData(NULL);
if (data != NULL) { printf("FAIL: Nach dem letzten Element sollte NULL kommen\n"); return 1; }
printf("PASS: nextTreeData - Iteration\n");
// Test 5: clearTree
clearTree(root);
root = NULL;
// Nach clearTree sollte treeSize 0 sein (aber da root NULL, testen wir indirekt)
printf("PASS: clearTree (no crash)\n");
// Test 6: Leerer Baum
size = treeSize(NULL);
if (size != 0) { printf("FAIL: Leerer Baum sollte Größe 0 haben\n"); return 1; }
data = nextTreeData(NULL);
if (data != NULL) { printf("FAIL: Leerer Baum sollte NULL zurückgeben\n"); return 1; }
printf("PASS: Leerer Baum\n");
printf("ALL BINTREE TESTS PASSED\n");
return 0;
}

Binary file not shown.

View File

@ -1,60 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include "numbers.h"
// Einfache Funktion, um zu zählen, wie oft eine Zahl im Array vorkommt
int countOccurrences(const unsigned int *arr, unsigned int len, unsigned int value) {
int count = 0;
for (unsigned int i = 0; i < len; i++) {
if (arr[i] == value) count++;
}
return count;
}
// Testfunktion für createNumbers und getDuplicate
void testNumbers(unsigned int len) {
printf("Teste mit Laenge %u:\n", len);
// Erstelle Zahlenarray
unsigned int *numbers = createNumbers(len);
if (numbers == NULL) {
printf("Fehler: Konnte Array nicht erstellen.\n");
return;
}
// Gib Array aus
printf("Generierte Zahlen: ");
for (unsigned int i = 0; i < len; i++) {
printf("%u ", numbers[i]);
}
printf("\n");
// Finde Duplikat
unsigned int duplicate = getDuplicate(numbers, len);
printf("Gefundenes Duplikat: %u\n", duplicate);
// Überprüfe, ob es genau zweimal vorkommt
int occ = countOccurrences(numbers, len, duplicate);
if (occ == 2) {
printf("Korrekte Überprüfung: %u kommt genau zweimal vor.\n", duplicate);
} else {
printf("Fehler: %u kommt %d mal vor (sollte 2 sein).\n", duplicate, occ);
}
// Speicher freigeben
free(numbers);
printf("\n");
}
int main() {
printf("Testprogramm für numbers.c\n");
printf("=========================\n\n");
// Teste mit verschiedenen Längen
testNumbers(5);
testNumbers(10);
testNumbers(20);
printf("Tests abgeschlossen.\n");
return 0;
}

Binary file not shown.

View File

@ -1,36 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
int main() {
printf("===== TEST STACK =====\n");
StackNode *s = NULL;
// Test push
int a = 10, b = 20, c = 30;
s = push(s, &a);
s = push(s, &b);
s = push(s, &c);
if (*(int*)top(s) != 30) {
printf("FAIL: top() should return 30\n");
return 1;
}
printf("PASS: push + top\n");
// Test pop
s = pop(s);
if (*(int*)top(s) != 20) {
printf("FAIL: pop() should remove 30\n");
return 1;
}
printf("PASS: pop\n");
// Clear
clearStack(s);
printf("PASS: clearStack (no crash)\n");
printf("ALL STACK TESTS PASSED\n");
return 0;
}

Binary file not shown.

38
timer.c
View File

@ -1,6 +1,37 @@
#include <time.h>
#include "timer.h"
#if __APPLE__
#include <sys/time.h>
static struct timespec start = {0, 0};
// Starts the timer.
void startTimer()
{
clock_gettime(CLOCK_MONOTONIC, &start);
}
// Returns the time in seconds since startTimer() was called.
double stopTimer()
{
struct timespec end;
clock_gettime(CLOCK_MONOTONIC, &end);
unsigned long long delta_us = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000;
double measuredSeconds = (double)delta_us / 1000000.;
if(start.tv_nsec > 0) {
start.tv_nsec = 0;
start.tv_sec = 0;
}
else
measuredSeconds = -1;
return measuredSeconds;
}
#else
#include <time.h>
static clock_t startClocks = 0;
// Starts the timer.
@ -18,6 +49,7 @@ double stopTimer()
startClocks = 0;
else
measuredSeconds = -1;
return measuredSeconds;
}
}
#endif

BIN
timer.o

Binary file not shown.

21
unity/LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2007-25 Mike Karlesky, Mark VanderVoord, & Greg Williams
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,3 +0,0 @@
unity: unity.c unity.h
gcc -c -Wall -o unity.o unity.c
ar rcs libunity.a unity.o

Binary file not shown.