Compare commits

..

2 Commits

4 changed files with 296 additions and 177 deletions

View File

@ -2,117 +2,27 @@
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define MAX_RAND_TRIES_PER_WORD 10
#define EMPTY_CHAR 0
//TODO: Spiellogik implementieren:
/* * Wörter aus der Wortliste zufällig horizontal oder vertikal platzieren
* restliche Felder mit zufälligen Buchstaben füllen */
// Creates the word salad by placing words randomly and filling empty spaces
int createWordSalad(char salad[MAX_SEARCH_FIELD_LEN][MAX_SEARCH_FIELD_LEN], unsigned int searchFieldLen, const char words[][MAX_WORD_LEN], unsigned int wordCount)
{
srand(time(NULL));
//Fill salad with empty_char
for(int i = 0; i < searchFieldLen; i++){
for(int j = 0; j < searchFieldLen; j++){
salad[i][j] = EMPTY_CHAR;
}
}
int wordsPlaced = 0; //Track number of words successfully placed
//Try to place each word
for(int w = 0; w < wordCount; w++){
int wordLen = strlen(words[w]);
int placed = 0;
if(wordLen > searchFieldLen){
//printf("Word %s is too long!\n", words[w]);
break;
}
//Try multiple times to find a valid position
for(int attempt = 0; attempt < MAX_RAND_TRIES_PER_WORD && !placed; attempt++){
//Random orientation: 0 = horizontal, 1 = vertical
int orientation = rand() % 2;
int row, col;
if(orientation == 0){ //Horizontal
row = rand() % searchFieldLen;
col = rand() % (searchFieldLen - wordLen + 1); //Ensure word fits
//Check if position is free
int canPlace = 1;
for(int i = 0; i < wordLen; i++){
if(salad[row][col + i] != EMPTY_CHAR && salad[row][col + i] != words[w][i]){
canPlace = 0;
break;
}
}
//Place word
if(canPlace){
for(int i = 0; i < wordLen; i++){
salad[row][col + i] = words[w][i];
}
placed = 1;
wordsPlaced++;
}
}
else{ //Vertical
row = rand() % (searchFieldLen - wordLen + 1); //Ensure word fits
col = rand() % searchFieldLen;
//Check if position is free
int canPlace = 1;
for(int i = 0; i < wordLen; i++){
if(salad[row + i][col] != EMPTY_CHAR && salad[row + i][col] != words[w][i]){
canPlace = 0;
break;
}
}
//Place word if position is valid
if(canPlace){
for(int i = 0; i < wordLen; i++){
salad[row + i][col] = words[w][i];
}
placed = 1;
wordsPlaced++;
}
}
}
}
//Fill remaining empty cells with random letters
for(int i = 0; i < searchFieldLen; i++){
for(int j = 0; j < searchFieldLen; j++){
if(salad[i][j] == EMPTY_CHAR){
salad[i][j] = 'A' + (rand() % 26);
}
}
}
return wordsPlaced;
}
// Prints the word salad to console
void showWordSalad(const char salad[MAX_SEARCH_FIELD_LEN][MAX_SEARCH_FIELD_LEN], unsigned int searchFieldLen)
{
for(int i = 0; i < searchFieldLen; i++){
for(int j = 0; j < searchFieldLen; j++){
printf("%c ", salad[i][j]);
}
puts("\n");
}
}
}
//Fill up Word salad
void fillWordSalad(char salad[MAX_SEARCH_FIELD_LEN][MAX_SEARCH_FIELD_LEN]){
}
}

View File

@ -1,69 +1,24 @@
/*
----- input.c--------------------------------------------------------
Description: ReadWords: Takes a file and separates all the words from one another, returns the wordcount and an array with all words
Project: Praktikum Informatik 2
Author: kobma99134@th-nuernberg.de
Date: 05-11-2025
-------------------------------------------------------------------------
*/
#include "input.h"
#include <string.h>
#include <ctype.h>
// TODO:
// eine Funktion implementieren, die ein einzelnes Wort aus einer Textdatei (words.txt) einliest und als C-String zurückgibt.
// Read words from file and store in 'words' array
int readWords(FILE *file, char words[][MAX_WORD_LEN], unsigned int maxWordCount)
{
// checks, if the file acually exists
if (file == NULL) {
return 0;
}
char word[MAX_WORD_LEN];
//return value: wordcount, as in the number of words that are being read
int wordcount = 0;
char readLine[MAX_LINE_LEN];
// we possibly don't need fopen, since file is already a parameter
// fopen(stream)
// collects the words line by line and adds them to the list, if its not exceeding the max word count
while (fgets(readLine, sizeof(readLine), file) != NULL && (wordcount < maxWordCount)) {
char word[MAX_WORD_LEN];
int wordIndex = 0;
//reads every character in the line from start to finish, until the Enter key ('\0')
for (int i = 0; readLine[i] != '\0'; i++) {
// is the character a letter from the alphabet?
if(isalpha(readLine[i])) {
if (wordIndex < MAX_WORD_LEN) {
// clean code: We want only uppercase or only lowercase letters to avoid future problems...
word[wordIndex++] = toupper(readLine[i]);
}
}
else {
//if its not a letter, it has to be another character dividing two words e.g. ' ', ',', ';' etc.
if (wordIndex > 0) {
// we want a full word, not an empty string
word[wordIndex] = '\0';
// add the word to the wordlist
strcpy(words[wordcount], word);
wordcount++;
wordIndex = 0;
fgets(word, MAX_WORD_LEN,file);
// fgets(string, length, file *stream)
if (wordcount >= maxWordCount) {
return wordcount;
}
}
}
}
//Edge case: If the last word ends on a '\0', right after the last letter
if (wordIndex > 0 && wordcount < maxWordCount) {
word[wordIndex] = '\0';
strcpy(words[wordcount], word);
wordcount++;
}
}
// regular case: return the total number of words
return wordcount;
strcpy(words[maxWordCount-1], word);
maxWordCount++;
// we possibly also won't need to close the
// fclose( *<stream>)
return 0;
}

View File

@ -7,7 +7,6 @@
#define MAX_NUMBER_OF_WORDS 100
#define SALAD_SIZE 20
int main(int argc, char *argv[])
{
int exitCode = EXIT_SUCCESS;
@ -33,19 +32,14 @@ int main(int argc, char *argv[])
// Read words from file and store in 'words' array
wordCount = readWords(file, words, MAX_NUMBER_OF_WORDS);
fclose(file);
// Create the word salad by placing words into grid
placedWords = createWordSalad(wordSalad, SALAD_SIZE, words, wordCount);
if(placedWords < wordCount){
printf("%d Words didn't fit!\n", wordCount-placedWords);
return -1;
}
showWordSalad(wordSalad, SALAD_SIZE);
startGame(wordSalad, SALAD_SIZE, words, wordCount, 600);
// TODO:
// Check if all words were successfully placed
// Start the game if successful
// error message if some words couldn't be placed
}
else

286
todo.md
View File

@ -1,13 +1,273 @@
## Todo
#### game.c
_Vorgegebene Anweisung:_
Wörter aus der Wortliste zufällig horizontal oder vertikal plazieren, restliche Felder mit zufälligen Buchstaben füllen
#### input.c
_Vorgegebene Anweisung:_
eine Funktion implementierenm die ein einzelnes Wort aus einer Textdatei (words.txt) einliest und als C-String zurückgibt
=> Die Methode sollte Fertig sein, ist aber noch nicht getestet.
#### main.c
_Vorgegebene Anweisung:_
Check if all words were successfully placed
start the game if successfull
error message if some words couldn't be placed
# Word Salad Game - Comprehensive TODO List
## Project Overview
A word search puzzle game where words are randomly placed in a grid (horizontally or vertically), and players must find them by drawing lines over the letters. Built with C and Raylib graphics library.
---
## 📋 Core Implementation Tasks
### 🔴 CRITICAL - Must be implemented for basic functionality
#### 1. **input.c - Word Reading Function** ⚠️ HIGH PRIORITY
**Function:** `readWords()`
**Requirements:**
- [ ] Read words from file (`words.txt`) line by line
- [ ] Handle multiple delimiters: comma (`,`), semicolon (`;`), space (` `), newline (`\n`)
- [ ] Convert all words to uppercase for consistency
- [ ] Store words in the provided `words[][]` array
- [ ] Return the total count of words read
- [ ] Handle empty files gracefully (return 0)
- [ ] Validate max word count limit (`maxWordCount`)
- [ ] Trim whitespace from words
- [ ] Skip empty words/lines
**Implementation Notes:**
- Use `fgets()` to read lines (max `MAX_LINE_LEN`)
- Use `strtok()` for tokenizing with multiple delimiters: `", ;\n\t\r"`
- Use `toupper()` to convert characters to uppercase
- Use `isalpha()` to validate word characters
- Handle buffer overflow protection
**Test Coverage:**
- `test_readWords_simple()` - Basic newline-separated words
- `test_readWords_with_delimiters()` - Multiple delimiter types
- `test_readWords_empty_file()` - Empty file handling
---
#### 2. **game.c - Word Salad Creation** ⚠️ HIGH PRIORITY
**Function:** `createWordSalad()`
**Requirements:**
- [ ] Initialize the grid with `EMPTY_CHAR` (0)
- [ ] Seed random number generator with `srand(time(NULL))`
- [ ] For each word, attempt placement:
- [ ] Try random positions and orientations (horizontal/vertical)
- [ ] Max attempts: `MAX_RAND_TRIES_PER_WORD` (10)
- [ ] Check if word fits without overlapping incorrectly
- [ ] Place word character by character
- [ ] Fill remaining empty cells with random uppercase letters (A-Z)
- [ ] Return count of successfully placed words
**Placement Algorithm:**
1. Random orientation: 0 = horizontal, 1 = vertical
2. Random starting position within valid bounds
3. Check if entire word fits
4. Check for conflicts (can overwrite same letter, not different letters)
5. Place word if valid
6. Increment placed counter
**Edge Cases:**
- Words too long for grid size
- Grid too small for multiple words
- All positions occupied
**Test Coverage:**
- `test_createWordSalad_all_fit()` - All words fit in large grid
- `test_createWordSalad_too_small()` - Grid too small for some words
- `test_createWordSalad_allWordsPlaced()` - Verify words are actually in grid
---
#### 3. **game.c - Display Function** 🟡 MEDIUM PRIORITY
**Function:** `showWordSalad()`
**Requirements:**
- [ ] Print grid to console in readable format
- [ ] Add spacing between characters for clarity
- [ ] Optional: Add row/column numbers for debugging
- [ ] Format: Each row on separate line
**Example Output:**
```
0 1 2 3 4
0 Y E T I X
1 N A B C D
2 M O N S T E R
3 O G H I J
```
---
#### 4. **main.c - Game Validation & Launch** ⚠️ HIGH PRIORITY
**Requirements:**
- [ ] Compare `placedWords` with `wordCount`
- [ ] If all words placed successfully:
- [ ] Call `startGame()` with word salad and parameters
- [ ] Pass `SALAD_SIZE` as search field size
- [ ] Use appropriate window size (e.g., 800)
- [ ] If some words couldn't be placed:
- [ ] Print error message to stderr
- [ ] Indicate how many words failed
- [ ] Set `exitCode = EXIT_FAILURE`
- [ ] Don't start the game
**Implementation:**
```c
// TODO: Complete this section
if (placedWords == wordCount) {
// All words successfully placed - start the game
showWordSalad(wordSalad, SALAD_SIZE); // Optional: show in console
startGame(wordSalad, SALAD_SIZE, words, wordCount, 800);
} else {
// Error: Not all words could be placed
fprintf(stderr, "Error: Only %u out of %u words could be placed in the grid.\n",
placedWords, wordCount);
exitCode = EXIT_FAILURE;
}
```
---
## 🧪 Testing & Validation
### Unit Tests
- [ ] Run all unit tests: `./unit_tests` or `make test`
- [ ] Ensure all 6 tests pass:
- [ ] `test_readWords_simple`
- [ ] `test_readWords_with_delimiters`
- [ ] `test_readWords_empty_file`
- [ ] `test_createWordSalad_all_fit`
- [ ] `test_createWordSalad_too_small`
- [ ] `test_createWordSalad_allWordsPlaced`
### Integration Testing
- [ ] Test with provided `words.txt` file
- [ ] Test with custom word lists
- [ ] Test with edge cases:
- [ ] Empty file
- [ ] Single word
- [ ] Very long words
- [ ] Maximum word count
- [ ] Special characters/numbers (should be filtered)
---
## 🔧 Build & Compilation
### Prerequisites
- [ ] GCC compiler installed
- [ ] Make utility available
- [ ] Raylib library (already included in project)
- [ ] Unity test framework (already included)
### Build Commands
```bash
# Build main executable
make
# Build and run unit tests
make test
# Clean build artifacts
make clean
```
### Platform-Specific Notes
- **Windows:** Use `Start_Windows/` directory
- **Linux:** Use `Start_Linux/` directory
- **macOS:** Use `Start_Mac/` directory
---
## 📦 Additional Enhancements (Optional)
### Nice-to-Have Features
- [ ] Add diagonal word placement
- [ ] Add backward word placement (reverse strings)
- [ ] Difficulty levels (grid size, word count)
- [ ] Save/load game state
- [ ] High score tracking
- [ ] Time-based gameplay
- [ ] Hint system
- [ ] Multiple language support
### Code Quality
- [ ] Add comprehensive comments
- [ ] Follow consistent naming conventions
- [ ] Memory leak detection with Valgrind
- [ ] Static analysis with cppcheck
- [ ] Code formatting with clang-format
### Documentation
- [ ] Update README.md with:
- [ ] Build instructions
- [ ] How to play
- [ ] Screenshots
- [ ] System requirements
- [ ] Add inline code documentation
- [ ] Create developer guide
---
## 🐛 Known Issues & Debugging
### Common Problems
- [ ] **Segmentation fault:** Check array bounds, null pointers
- [ ] **Words not found:** Ensure uppercase conversion in both placement and search
- [ ] **Random seed:** Call `srand(time(NULL))` only once
- [ ] **File not found:** Check relative paths, working directory
### Debugging Tips
- Use `printf()` to trace execution
- Test functions individually
- Use debugger (gdb/lldb) for complex issues
- Enable compiler warnings: `-Wall -Wextra`
---
## ✅ Definition of Done
A task is considered complete when:
- [ ] Code compiles without warnings
- [ ] All relevant unit tests pass
- [ ] Function meets specification requirements
- [ ] Edge cases are handled
- [ ] Code is properly commented
- [ ] No memory leaks (verified with Valgrind on Linux/Mac)
- [ ] Integrated and tested with other components
---
## 📅 Suggested Implementation Order
1. ✅ **Week 1:** Implement `readWords()` in `input.c`
- Start with simple parsing
- Add delimiter handling
- Test with unit tests
2. ✅ **Week 2:** Implement `createWordSalad()` in `game.c`
- Grid initialization
- Word placement algorithm
- Random fill
- Test with unit tests
3. ✅ **Week 3:** Implement `showWordSalad()` and complete `main.c`
- Console display
- Game validation logic
- Integration testing
4. ✅ **Week 4:** Testing, debugging, and polish
- Fix all unit test failures
- Test with various word lists
- Optimize performance
- Code cleanup
---
## 📝 Notes
- The graphical interface (`graphicalGame.c`) is already implemented
- Raylib library handles all graphics rendering
- Focus on the core game logic implementation
- Test frequently to catch bugs early
- Use the provided Unity test framework
---
**Last Updated:** November 5, 2025
**Project:** Word Salad Game (Wortsalat)
**Course:** Informatik 2 - Programmierung (3. Semester)