You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
375 lines
12 KiB
C
375 lines
12 KiB
C
/*
|
|
* spielfeld.c
|
|
*
|
|
* Created on: Mar 15, 2024
|
|
* Author: Nico
|
|
*/
|
|
|
|
#include "spielfeld.h"
|
|
#include "main.h"
|
|
/*
|
|
* Beschreibung:
|
|
* Diese Funktion generiert ein Spielfeld mit der angegebenen Größe und initialisiert alle Zellen als leere Zellen.
|
|
*
|
|
* Parameter:
|
|
* size: Die Größe des Spielfelds (Anzahl der Zeilen/Spalten).
|
|
*
|
|
* Rückgabewert:
|
|
* Zeiger auf das erstellte Spielfeld (int**).
|
|
*/
|
|
int** generateGameBoard(int size) {
|
|
// Speicher für das Spielfeld reservieren
|
|
int** gameBoard = (int**)malloc(size * sizeof(int*));
|
|
for (int i = 0; i < size; i++) {
|
|
gameBoard[i] = (int*)malloc(size * sizeof(int));
|
|
}
|
|
|
|
// Initialisierung des Spielfelds
|
|
for (int i = 0; i < size; i++) {
|
|
for (int j = 0; j < size; j++) {
|
|
gameBoard[i][j] = EMPTY_CELL;
|
|
}
|
|
}
|
|
|
|
return gameBoard;
|
|
}
|
|
|
|
/*
|
|
* Beschreibung:
|
|
* Diese Funktion generiert eine zufällige ganze Zahl mithilfe des HAL-RNG-Moduls.
|
|
*
|
|
* Rückgabewert:
|
|
* Eine zufällige ganze Zahl (uint32_t).
|
|
*/
|
|
uint32_t random_int(void) {
|
|
uint32_t z;
|
|
HAL_RNG_GenerateRandomNumber(&hrng, &z);
|
|
return z;
|
|
}
|
|
|
|
/*
|
|
* Beschreibung:
|
|
* Diese Funktion platziert die Bomben zufällig auf dem Spielfeld und berechnet dann die Anzahl der umliegenden Bomben für jede Zelle.
|
|
*
|
|
* Parameter:
|
|
* gameBoard: Das Spielfeld, auf dem die Bomben platziert werden sollen.
|
|
* size: Die Größe des Spielfelds.
|
|
* numBombs: Die Anzahl der Bomben, die platziert werden sollen.
|
|
*/
|
|
void placeBombs(int** gameBoard, int size, int numBombs) {
|
|
// Zufälligen Seed initialisieren
|
|
srand(random_int());
|
|
|
|
// Platzieren der Bomben
|
|
while (numBombs > 0) {
|
|
int x = rand() % size;
|
|
int y = rand() % size;
|
|
|
|
if (gameBoard[x][y] != BOMB_CELL) {
|
|
gameBoard[x][y] = BOMB_CELL;
|
|
numBombs--;
|
|
}
|
|
}
|
|
|
|
// Berechnen der Zahlen um die Bomben herum und Markieren mit NUMBER_CELL
|
|
for (int i = 0; i < size; i++) {
|
|
for (int j = 0; j < size; j++) {
|
|
if (gameBoard[i][j] != BOMB_CELL) {
|
|
int count = 0;
|
|
|
|
// Überprüfe die Zellen um die aktuelle Zelle (i, j)
|
|
for (int dx = -1; dx <= 1; dx++) {
|
|
for (int dy = -1; dy <= 1; dy++) {
|
|
int newX = i + dx;
|
|
int newY = j + dy;
|
|
|
|
// Überprüfe, ob die Zelle innerhalb des Spielfelds liegt und eine Bombe enthält
|
|
if (newX >= 0 && newX < size && newY >= 0 && newY < size && gameBoard[newX][newY] == BOMB_CELL) {
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Setze die Anzahl der umliegenden Bomben in die aktuelle Zelle
|
|
gameBoard[i][j] = count;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Beschreibung:
|
|
* Diese Funktion zeigt das Spielfeld auf der UART-Schnittstelle an.
|
|
*
|
|
* Parameter:
|
|
* gameBoard: Das Spielfeld, das angezeigt werden soll.
|
|
* size: Die Größe des Spielfelds.
|
|
* numBombs: Die Gesamtanzahl der Bomben auf dem Spielfeld.
|
|
* numFlags: Die Anzahl der Flaggen, die auf dem Spielfeld platziert wurden.
|
|
*/
|
|
void displayGameBoardUART(int** gameBoard, int size, int numBombs, int numFlags) {
|
|
// Leere den Empfangspuffer der UART-Schnittstelle
|
|
clearSerialBuffer(&huart2);
|
|
|
|
char buffer[600]; // Puffer für den formatierten String
|
|
int offset = 0; // Offset für die Position im Puffer
|
|
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, "\rSpielfeld:\r");
|
|
|
|
// Formatieren des Spielfelds in den Puffer
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, "\r\n\n "); // Leerzeichen für die Ausrichtung
|
|
// Spaltenbezeichnungen (A, B, C, ...)
|
|
for (int i = 0; i < size; i++) {
|
|
char column = 'A' + i;
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, " %c", column);
|
|
}
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, "\r\n");
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, "%2d ", i + 1); // Zeilennummer
|
|
for (int j = 0; j < size; j++) {
|
|
if (gameBoard[i][j] == BOMB_CELL) {
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, "* "); // Bombe
|
|
} else if (gameBoard[i][j] == EMPTY_CELL) {
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, ". "); // Leerzelle
|
|
} else if (gameBoard[i][j] == HIDDEN_CELL) {
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, "# "); // Verdeckte Zelle
|
|
} else if (gameBoard[i][j] == FLAG_CELL) {
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, "? "); // Verdeckte Zelle
|
|
} else {
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, "%d ", gameBoard[i][j]); // Zahl
|
|
}
|
|
}
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, "\r\n");
|
|
}
|
|
|
|
// Anzeige der verbleibenden Anzahl von Bomben
|
|
offset += snprintf(buffer + offset, sizeof(buffer) - offset, "\r\nVerbleibende Anzahl von Bomben: %d\r\n", numBombs - numFlags);
|
|
|
|
// Senden des formatierten Strings über UART
|
|
HAL_UART_Transmit(&huart2, (uint8_t*)buffer, offset, 100);
|
|
}
|
|
|
|
/*
|
|
* Werden nicht benutzt
|
|
*
|
|
*/
|
|
void freeGameBoard(int** gameBoard, int size) {
|
|
for (int i = 0; i < size; i++) {
|
|
free(gameBoard[i]);
|
|
}
|
|
free(gameBoard);
|
|
}
|
|
|
|
/*
|
|
* Werden nicht benutzt
|
|
*
|
|
*/
|
|
void freeHiddenGameBoard(int** hiddenGameBoard, int size) {
|
|
for (int i = 0; i < size; i++) {
|
|
free(hiddenGameBoard[i]);
|
|
}
|
|
free(hiddenGameBoard);
|
|
}
|
|
|
|
/*
|
|
* Beschreibung:
|
|
* Diese Funktion erstellt ein verdecktes Spielfeld mit der angegebenen Größe.
|
|
*
|
|
* Parameter:
|
|
* gameBoard: Das Spielfeld, für das ein verdecktes Spielfeld erstellt werden soll.
|
|
* size: Die Größe des Spielfelds.
|
|
*
|
|
* Rückgabewert:
|
|
* Ein Zeiger auf das erstellte verdeckte Spielfeld (int**).
|
|
*/
|
|
int** createHiddenGameBoard(int** gameBoard, int size) {
|
|
int** hiddenGameBoard = (int**)malloc(size * sizeof(int*));
|
|
for (int i = 0; i < size; i++) {
|
|
hiddenGameBoard[i] = (int*)malloc(size * sizeof(int));
|
|
}
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
for (int j = 0; j < size; j++) {
|
|
hiddenGameBoard[i][j] = HIDDEN_CELL;
|
|
}
|
|
}
|
|
|
|
return hiddenGameBoard;
|
|
}
|
|
|
|
|
|
|
|
void getNewPosition(Position* pos, int dx, int dy, Position* newPos) {
|
|
newPos->col = pos->col + dy;
|
|
newPos->row = pos->row + dx;
|
|
}
|
|
|
|
|
|
/*
|
|
* Beschreibung:
|
|
* Diese Funktion deckt rekursiv alle leeren Zellen und ihre benachbarten leeren Zellen auf.
|
|
*
|
|
* Parameter:
|
|
* gameBoard: Das Spielfeld, auf dem die Operation ausgeführt wird.
|
|
* hiddenGameBoard: Das verdeckte Spielfeld, das aktualisiert wird.
|
|
* size: Die Größe des Spielfelds.
|
|
* pos: Die Position der aktuellen Zelle, die aufgedeckt wird.
|
|
*/
|
|
void revealEmptyCells(int** gameBoard, int** hiddenGameBoard, int size, Position pos) {
|
|
// Aufdecken der leeren Zelle
|
|
hiddenGameBoard[pos.row][pos.col] = gameBoard[pos.row][pos.col];
|
|
|
|
// Wenn die Zelle leer ist, müssen auch benachbarte leere Zellen aufgedeckt werden
|
|
if (hiddenGameBoard[pos.row][pos.col] == EMPTY_CELL) {
|
|
for (int dx = -1; dx <= 1; dx++) {
|
|
for (int dy = -1; dy <= 1; dy++) {
|
|
if (dx == 0 && dy == 0) continue; // Überspringe die aktuelle Zelle
|
|
|
|
Position newPos;
|
|
getNewPosition(&pos, dx, dy, &newPos);
|
|
|
|
// Überprüfen, ob die benachbarte Zelle innerhalb des Spielfelds liegt und verdeckt ist
|
|
if (newPos.row >= 0 && newPos.row < size && newPos.col >= 0 && newPos.col < size && hiddenGameBoard[newPos.row][newPos.col] == HIDDEN_CELL) {
|
|
// Wenn die benachbarte Zelle leer ist, rekursiv fortfahren
|
|
revealEmptyCells(gameBoard, hiddenGameBoard, size, newPos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Beschreibung:
|
|
* Diese Funktion deckt eine bestimmte Zelle auf dem Spielfeld auf und aktualisiert das verdeckte Spielfeld entsprechend.
|
|
*
|
|
* Parameter:
|
|
* gameBoard: Das Spielfeld, auf dem die Operation ausgeführt wird.
|
|
* hiddenGameBoard: Das verdeckte Spielfeld, das aktualisiert wird.
|
|
* size: Die Größe des Spielfelds.
|
|
* row: Die Zeilennummer der aufzudeckenden Zelle.
|
|
* col: Die Spaltennummer der aufzudeckenden Zelle.
|
|
*
|
|
* Rückgabewert:
|
|
* 1, wenn die Zelle erfolgreich aufgedeckt wurde.
|
|
* 0, wenn die Zelle eine Bombe war und das Spiel dadurch verloren wurde.
|
|
*/
|
|
int revealCell(int** gameBoard, int** hiddenGameBoard, int size, int row, int col) {
|
|
Position pos;
|
|
pos.row = row;
|
|
pos.col = col;
|
|
|
|
// Überprüfen, ob die Position im gültigen Bereich liegt
|
|
if (pos.row < 0 || pos.row >= size || pos.col < 0 || pos.col >= size) {
|
|
return 1;
|
|
}
|
|
// Überprüfen, ob die Zelle bereits aufgedeckt ist
|
|
if (hiddenGameBoard[pos.row][pos.col] != HIDDEN_CELL) {
|
|
return 1;
|
|
}
|
|
if (hiddenGameBoard[pos.row][pos.col] == FLAG_CELL){
|
|
return 1;
|
|
}
|
|
if (gameBoard[pos.row][pos.col] == BOMB_CELL) {
|
|
hiddenGameBoard[pos.row][pos.col] = gameBoard[pos.row][pos.col];
|
|
for (int i = 0; i < size; i++) {
|
|
for (int j = 0; j < size; j++) {
|
|
if (gameBoard[i][j] == BOMB_CELL) {
|
|
hiddenGameBoard[i][j] = gameBoard[i][j];
|
|
}
|
|
}
|
|
}
|
|
handleBombExploded();
|
|
return 0;
|
|
}
|
|
// Wenn die Zelle leer ist, müssen auch benachbarte leere Zellen aufgedeckt werden
|
|
if (gameBoard[pos.row][pos.col] == EMPTY_CELL) {
|
|
revealEmptyCells(gameBoard, hiddenGameBoard, size, pos);
|
|
} else {
|
|
// Aufdecken der Zelle im verdeckten Spielfeld
|
|
hiddenGameBoard[pos.row][pos.col] = gameBoard[pos.row][pos.col];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Beschreibung:
|
|
* Diese Funktion platziert oder entfernt eine Flagge auf einer bestimmten Zelle des verdeckten Spielfelds.
|
|
*
|
|
* Parameter:
|
|
* hiddenGameBoard: Das verdeckte Spielfeld, auf dem die Operation ausgeführt wird.
|
|
* row: Die Zeilennummer der Zelle, auf der die Flagge platziert/entfernt werden soll.
|
|
* col: Die Spaltennummer der Zelle, auf der die Flagge platziert/entfernt werden soll.
|
|
* numFlags: Ein Zeiger auf die Anzahl der Flaggen auf dem Spielfeld.
|
|
*/
|
|
void setFlag(int** hiddenGameBoard, int row, int col, int* numFlags) {
|
|
if (hiddenGameBoard[row][col] == FLAG_CELL)
|
|
{
|
|
hiddenGameBoard[row][col] = HIDDEN_CELL;
|
|
(*numFlags)--;
|
|
}
|
|
else if (hiddenGameBoard[row][col] == HIDDEN_CELL)
|
|
{
|
|
hiddenGameBoard[row][col] = FLAG_CELL;
|
|
(*numFlags)++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Beschreibung:
|
|
* Diese Funktion überprüft, ob das Spiel gewonnen wurde, indem sie prüft, ob alle Bomben markiert wurden und alle nicht-Bomben-Zellen aufgedeckt sind.
|
|
*
|
|
* Parameter:
|
|
* gameBoard: Das Spielfeld mit den Bomben.
|
|
* hiddenGameBoard: Das verdeckte Spielfeld.
|
|
* size: Die Größe des Spielfelds.
|
|
* numBombs: Die Anzahl der Bomben auf dem Spielfeld.
|
|
* numFlags: Die Anzahl der Flaggen auf dem Spielfeld.
|
|
*
|
|
* Rückgabewert:
|
|
* 1, wenn das Spiel gewonnen wurde.
|
|
* 0, wenn das Spiel noch nicht gewonnen wurde.
|
|
*/
|
|
int checkWin(int** gameBoard, int** hiddenGameBoard, int size, int numBombs, int numFlags) {
|
|
// Überprüfen, ob alle Bombenpositionen mit einer Flagge markiert wurden
|
|
for (int i = 0; i < size; i++) {
|
|
for (int j = 0; j < size; j++) {
|
|
if (gameBoard[i][j] == BOMB_CELL && hiddenGameBoard[i][j] != FLAG_CELL) {
|
|
return 0; // Nicht gewonnen, da nicht alle Bomben markiert sind
|
|
}
|
|
}
|
|
}
|
|
|
|
// Überprüfen, ob alle nicht-Bombenfelder aufgedeckt wurden
|
|
int totalCells = size * size;
|
|
int uncoveredCells = 0;
|
|
for (int i = 0; i < size; i++) {
|
|
for (int j = 0; j < size; j++) {
|
|
if (gameBoard[i][j] != BOMB_CELL && hiddenGameBoard[i][j] != HIDDEN_CELL) {
|
|
uncoveredCells++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Das Spiel ist gewonnen, wenn alle nicht-Bombenfelder aufgedeckt wurden und alle Bomben mit einer Flagge markiert wurden
|
|
if (uncoveredCells == totalCells - numBombs && numFlags == numBombs) {
|
|
char message[] = "Herzlichen Glückwunsch! Du hast gewonnen!\r\nStarte neu mit der ON Taste.\r\n";
|
|
HAL_UART_Transmit(&huart2, (uint8_t*)message, sizeof(message), 100);
|
|
return 1;
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Beschreibung:
|
|
* Diese Funktion gibt eine Meldung aus, dass das Spiel verloren wurde, da eine Bombe explodiert ist. *
|
|
*/
|
|
void handleBombExploded() {
|
|
char message[] = "Spiel Verloren! Du hast eine Bombe getroffen!\r\nStarte neu mit der ON Taste. \r\n";
|
|
HAL_UART_Transmit(&huart2, (uint8_t*)message, sizeof(message), 100);
|
|
|
|
|
|
}
|
|
|
|
|