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.
256 lines
8.6 KiB
C
256 lines
8.6 KiB
C
/*
|
|
* spielfeld.c
|
|
*
|
|
* Created on: Mar 15, 2024
|
|
* Author: Nico
|
|
*/
|
|
|
|
#include "spielfeld.h"
|
|
#include "main.h"
|
|
|
|
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;
|
|
}
|
|
|
|
uint32_t random_int(void) {
|
|
uint32_t z;
|
|
HAL_RNG_GenerateRandomNumber(&hrng, &z);
|
|
return z;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void freeGameBoard(int** gameBoard, int size) {
|
|
for (int i = 0; i < size; i++) {
|
|
free(gameBoard[i]);
|
|
}
|
|
free(gameBoard);
|
|
}
|
|
|
|
void freeHiddenGameBoard(int** hiddenGameBoard, int size) {
|
|
for (int i = 0; i < size; i++) {
|
|
free(hiddenGameBoard[i]);
|
|
}
|
|
free(hiddenGameBoard);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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) {
|
|
printf("Ungültige Position\n");
|
|
|
|
}
|
|
|
|
// Überprüfen, ob die Zelle bereits aufgedeckt ist
|
|
if (hiddenGameBoard[pos.row][pos.col] != HIDDEN_CELL) {
|
|
printf("Position bereits aufgedeckt\n");
|
|
|
|
}
|
|
if (gameBoard[pos.row][pos.col] == BOMB_CELL) {
|
|
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;
|
|
}
|
|
|
|
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)++;
|
|
}
|
|
}
|
|
|
|
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! Starte neu mit der ON Taste.\r\n";
|
|
HAL_UART_Transmit(&huart2, (uint8_t*)message, sizeof(message), 100);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
void handleBombExploded() {
|
|
char message[] = "Spiel Verloren! Du hast eine Bombe getroffen\r\n";
|
|
HAL_UART_Transmit(&huart2, (uint8_t*)message, sizeof(message), 100);
|
|
}
|
|
|
|
|