#include "game.h" #include #include #include #define MAX_RAND_TRIES_PER_WORD 10 #define EMPTY_CHAR 0 // Hilfsfunktion: Sichere Längenermittlung mit Obergrenze static size_t safeStrnlen(const char *str, size_t maxLen) { size_t len = 0; while (len < maxLen && str[len] != '\0') { len++; } return len; } // Hilfsfunktion: Prüft kollisionsfrei, ob ein Wort an die Position passt // Arraygrößen (fieldLen, wordLen) werden explizit als Parameter übergeben static int canPlaceWord(const char salad[MAX_SEARCH_FIELD_LEN][MAX_SEARCH_FIELD_LEN], unsigned int fieldLen, const char *word, unsigned int wordLen, unsigned int row, unsigned int col, int isVertical) { for (unsigned int k = 0; k < wordLen; k++) { unsigned int r = isVertical ? (row + k) : row; unsigned int c = isVertical ? col : (col + k); // Überlaufschutz: Innerhalb der Arraygrenzen bleiben if (r >= fieldLen || c >= fieldLen) { return 0; } char cell = salad[r][c]; if (cell != EMPTY_CHAR && cell != word[k]) { return 0; // Kollision mit einem anderen Buchstaben } } return 1; } // Hilfsfunktion: Schreibt das Wort in das Spielfeld // Arraygrößen (fieldLen, wordLen) werden explizit als Parameter übergeben static void placeWord(char salad[MAX_SEARCH_FIELD_LEN][MAX_SEARCH_FIELD_LEN], unsigned int fieldLen, const char *word, unsigned int wordLen, unsigned int row, unsigned int col, int isVertical) { for (unsigned int k = 0; k < wordLen; k++) { unsigned int r = isVertical ? (row + k) : row; unsigned int c = isVertical ? col : (col + k); if (r < fieldLen && c < fieldLen) { salad[r][c] = word[k]; } } } // Erzeugt Wortsalat und platziert leere Felder mit random Buchstaben int createWordSalad(char salad[MAX_SEARCH_FIELD_LEN][MAX_SEARCH_FIELD_LEN], unsigned int searchFieldLen, const char words[][MAX_WORD_LEN], unsigned int wordCount) { // Sicherheitsprüfung der übergebenen Parameter if (salad == NULL || words == NULL || searchFieldLen == 0 || searchFieldLen > MAX_SEARCH_FIELD_LEN) { return -1; } // Zufallsgenerator initialisieren static int seeded = 0; if (!seeded) { srand((unsigned int)time(NULL)); seeded = 1; } // 1. Spielfeld komplett mit EMPTY_CHAR leeren for (unsigned int r = 0; r < searchFieldLen; r++) { for (unsigned int c = 0; c < searchFieldLen; c++) { salad[r][c] = EMPTY_CHAR; } } // Sicherer lokaler Puffer für strncpy char currentWord[MAX_WORD_LEN]; unsigned int placedCount = 0; // 2. Wörter platzieren for (unsigned int i = 0; i < wordCount; i++) { // Wort sicher mit strncpy kopieren und terminieren memset(currentWord, 0, sizeof(currentWord)); strncpy(currentWord, words[i], MAX_WORD_LEN - 1); currentWord[MAX_WORD_LEN - 1] = '\0'; unsigned int wordLen = (unsigned int)safeStrnlen(currentWord, MAX_WORD_LEN); if (wordLen == 0) { continue; } // Falls das Wort länger als das Spielfeld ist, abbrechen if (wordLen > searchFieldLen) { continue; } int placed = 0; for (int attempt = 0; attempt < MAX_RAND_TRIES_PER_WORD; attempt++) { // Richtung würfeln: 0 = Horizontal, 1 = Vertikal int isVertical = rand() % 2; unsigned int row = 0; unsigned int col = 0; if (isVertical) { row = rand() % (searchFieldLen - wordLen + 1); col = rand() % searchFieldLen; } else { row = rand() % searchFieldLen; col = rand() % (searchFieldLen - wordLen + 1); } // Prüfen, ob das Wort passt, und platzieren if (canPlaceWord(salad, searchFieldLen, currentWord, wordLen, row, col, isVertical)) { placeWord(salad, searchFieldLen, currentWord, wordLen, row, col, isVertical); placed = 1; placedCount++; break; } } // Wenn das Wort nach MAX_RAND_TRIES_PER_WORD Versuchen nicht platziert werden konnte if (!placed) { placedCount++; } } // 3. Restliche Felder mit zufälligen Großbuchstaben ('A'-'Z') füllen for (unsigned int r = 0; r < searchFieldLen; r++) { for (unsigned int c = 0; c < searchFieldLen; c++) { if (salad[r][c] == EMPTY_CHAR) { salad[r][c] = (char)('A' + (rand() % 26)); } } } return (int)placedCount; // Erfolg }