commit 3d498ae176b7df9464a2c047c7a107c4e85567bc Author: jakub Date: Thu Sep 12 13:15:30 2024 +0200 nemám rád pojmenovávání commitů diff --git a/minesweeper.c b/minesweeper.c new file mode 100644 index 0000000..5fa7789 --- /dev/null +++ b/minesweeper.c @@ -0,0 +1,473 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define size 20 +#define mines 60 + +int tilesLeft = (size * size) - mines; +int flags = 0; + +int cursorX = 0; +int cursorY = 0; + +int timerSeconds = 0; +int timerMinutes = 0; + + +//Status hry: 0 = hra nezačala, 1 = výhra, 2 = prohra, 3 = hra běží +int gameStatus = 0; + +char tileField[size][size]; +char mineLocations[size][size]; +char mineCount[size][size]; + +char covered = 'c'; +char uncovered = '0'; +char mine = 'm'; +char flag = 'f'; + + +//EMOJI ZOOOOOOOONA +//Znaky, které do konzole vypisuje funkce drawField() +char coveredTile[] = "🌫️"; +char mineTile[] = "💣"; +//char cursorTile[] = "💠"; - Nakonec použita barva pozadí místo tohoto +char flagTile[] = "🚩"; +char zeroTile[] = "⬛"; +char oneTile[] = "1️⃣"; +char twoTile[] = "2️⃣"; +char threeTile[] = "3️⃣"; +char fourTile[] = "4️⃣"; +char fiveTile[] = "5️⃣"; +char sixTile[] = "6️⃣"; +char sevenTile[] = "7️⃣"; +char eightTile[] = "8️⃣"; + + +int generateStartingField(); +int drawField(); +int monitorKeys(); +int generateMines(); +int disableCanonicalMode(); +int moveCursorDown(); +int moveCursorUp(); +int moveCursorLeft(); +int moveCursorRight(); +int uncoverTiles(); +int flagSwitch(); +int uncoverMines(); +int countMines(); +int fastUncover(); +int fastUncoverUncoverAndContinue(); +int win(); +int prepareGame(); +int checkForBomb(); +int checkFlags(); +int startTimer(); + + +int main(){ + //Příprava hry + srand(time(NULL)); + generateStartingField(); + generateMines(); + countMines(); + drawField(); + struct termios orig_termios; + disableCanonicalMode(&orig_termios); + + //Průběh hry + monitorKeys(); + + return 0; +} + +//Hlavní herní funkce, která udržuje hru a spouští další funkce +int monitorKeys(){ + + char keyPressed = getchar(); + switch(tolower(keyPressed)){ + case 'w': + moveCursorUp(); + break; + case 'a': + moveCursorLeft(); + break; + case 'd': + moveCursorRight(); + break; + case 's': + moveCursorDown(); + break; + case 'f': + flagSwitch(); + break; + case 'e': + case ' ': + uncoverTiles(); + } + + if(tilesLeft < 1){ + win(); + } + drawField(); + monitorKeys(); + return 0; +} + +void* timer(void* arg) { + while (1) { + sleep(1); + timerSeconds++; + if(timerSeconds > 59){ + timerSeconds = 0; + timerMinutes++; + } + system("clear"); + drawField(); + } + return NULL; +} + +int prepareGame(){ + generateMines(); + countMines(); + gameStatus = 3; + if(mineCount[cursorY][cursorX] == '0'){ + + startTimer(); + return 0; + } + prepareGame(); + return 0; +} + +//Vygeneruje počáteční pole +int generateStartingField(){ + int i = 0; + + while(i < size){ + + int ii = 0; + + while(ii < size){ + tileField[i][ii] = covered; + ii++; + } + i++; + } + return 0; +} + +//Vygeneruje rozmíštění min +int generateMines(){ + int i = 0; + while(i < size){ + int ii = 0; + while(ii < size){ + mineLocations[i][ii] = '0'; + ii++; + } + i++; + } + i = 0; + while(i != mines){ + int mineX = rand() % size; + int mineY = rand() % size; + mineLocations[mineY][mineX] = 'm'; + i++; + } + return 0; +} + +//Spočítá počet min v okolí všech bloků a uloží pro pozdější užití +int countMines(){ + int i = 0; + while(i < size){ + int ii = 0; + while(ii < size){ + //Pokud je na pozici miny tak skip + if(mineLocations[i][ii] == 'm'){ + ii++; + continue; + } + int minesNextToTile = 0; + minesNextToTile = checkForBomb(ii-1, i, minesNextToTile); + minesNextToTile = checkForBomb(ii, i-1, minesNextToTile); + minesNextToTile = checkForBomb(ii-1, i-1, minesNextToTile); + minesNextToTile = checkForBomb(ii+1, i-1, minesNextToTile); + minesNextToTile = checkForBomb(ii-1, i+1, minesNextToTile); + minesNextToTile = checkForBomb(ii+1, i+1, minesNextToTile); + minesNextToTile = checkForBomb(ii, i+1, minesNextToTile); + minesNextToTile = checkForBomb(ii+1, i, minesNextToTile); + mineCount[i][ii] = '0' + minesNextToTile; + ii++; + } + i++; + } +} +int checkForBomb(int x, int y, int numberOfMines){ + if(x < 0 || x >= size || y < 0 || y >= size || mineLocations[y][x] != 'm'){ + return numberOfMines; + } + return numberOfMines+1; +} + +//Překreslí hrací pole to terminálu +int drawField(){ + system("clear"); + int i = 0; + int ii = 0; + int fieldSize = sizeof(tileField) / sizeof(tileField[0]); + printf("\n"); + while(i < fieldSize){ + ii = 0; + while(ii < fieldSize){ + + + if(gameStatus == 2){ + printf("\033[%dm", 40 + 1); + } + if(gameStatus == 1){ + printf("\033[%dm", 40 + 2); + } + if (i == cursorY && ii == cursorX){ + printf("\033[%dm", 40 + 4); + } + switch (tileField[i][ii]){ + case 'c': + printf(coveredTile); + break; + case 'm': + printf(mineTile); + break; + case 'f': + printf(flagTile); + break; + case '0': + printf(zeroTile); + break; + case '1': + printf(oneTile); + break; + case '2': + printf(twoTile); + break; + case '3': + printf(threeTile); + break; + case '4': + printf(fourTile); + break; + case '5': + printf(fiveTile); + break; + case '6': + printf(sixTile); + break; + case '7': + printf(sevenTile); + break; + case '8': + printf(eightTile); + break; + default: + printf("n"); + } + printf(" \033[%dm", 40 + 0); + ii++; + } + + printf("\n"); + i++; + } + printf("\n\n\033[%dm", 47); + printf(" \033[%dm", 30); + printf("POHYB = WASD, VLAJKA = F, ODKRÝT = E nebo SPACE"); + printf(" \033[%dm", 40); + printf("\n\n\033[%dm", 34); + printf("\e[1mZbývá min: "); + printf("\033[0;31m%d", mines-flags); + printf("\n\033[0;34m\e[1mČas: \033[0;31m"); + printf("%d", timerMinutes); + printf(":"); + + //Protože richard je perfekcionalista + if(timerSeconds < 10){ + printf("0"); + } + printf("%d", timerSeconds); + printf("\033[0;30m\n\n"); + return 0; +} + +//Vypnutí can. módu, aby bylo možné zaznamenávat stisk kláves +int disableCanonicalMode(struct termios *orig_termios){ + struct termios newTermios; + tcgetattr(STDIN_FILENO, orig_termios); + newTermios = *orig_termios; + newTermios.c_lflag &= ~(ICANON | ECHO); + newTermios.c_cc[VMIN] = 1; + newTermios.c_cc[VTIME] = 0; + tcsetattr(STDIN_FILENO, TCSANOW, &newTermios); +} + + +//Funkce pro pohybování kurzorem +int moveCursorDown(){ + if(cursorY != (size - 1)){ + cursorY++; + } + return 0; +} +int moveCursorUp(){ + if(cursorY != 0){ + cursorY--; + } + return 0; +} +int moveCursorLeft(){ + if(cursorX != 0){ + cursorX--; + } + return 0; +} +int moveCursorRight(){ + if(cursorX != (size - 1)){ + cursorX++; + } + return 0; +} + +//Označení tile vlaječkou :3 +int flagSwitch(){ + startTimer(); + char tile = tileField[cursorY][cursorX]; + if(tile == covered){ + tileField[cursorY][cursorX] = flag; + flags++; + } + if(tile == flag ){ + tileField[cursorY][cursorX] = covered; + flags--; + } + if(flags == mines){ + checkFlags(); + } + return 0; +} + +//Odekreje tile nebo ukončí hru pokud narazí na bombu +int uncoverTiles(){ + if(gameStatus == 0){ + prepareGame(); + } + if(tileField[cursorY][cursorX] == 'f'){ + return 0; + } + if(mineLocations[cursorY][cursorX] == 'm'){ + gameStatus = 2; + uncoverMines(); + printf("\033[%dm", 30 + 1); + printf("\nProhrál jsi!\n"); + exit(0); + } + + tileField[cursorY][cursorX] = mineCount[cursorY][cursorX]; + tilesLeft--; + fastUncover(cursorX, cursorY); + return 0; +} + + +//Odhalí všechny miny +int uncoverMines(){ + int i = 0; + + while(i < size){ + + int ii = 0; + + while(ii < size){ + if(mineLocations[i][ii] == 'm'){ + tileField[i][ii] = mine; + } + ii++; + } + i++; + } + + drawField(); + return 0; +} + +int fastUncover(int x, int y){ + if(mineCount[y][x] != '0'){ + return 0; + } + + fastUncoverUncoverAndContinue(x-1,y); + fastUncoverUncoverAndContinue(x,y-1); + fastUncoverUncoverAndContinue(x-1,y-1); + fastUncoverUncoverAndContinue(x+1,y-1); + fastUncoverUncoverAndContinue(x-1,y+1); + fastUncoverUncoverAndContinue(x+1,y+1); + fastUncoverUncoverAndContinue(x+1,y); + fastUncoverUncoverAndContinue(x,y+1); + return 0; +} +int fastUncoverUncoverAndContinue(int x, int y){ + + if(!(tileField[y][x] == covered || tileField[y][x] == flag) || x < 0 || x >= size || y < 0 || y >= size){ + return 0; + } + tilesLeft--; + tileField[y][x] = mineCount[y][x]; + fastUncover(x, y); + return 0; +} +int win(){ + gameStatus = 1; + uncoverMines(); + printf("\033[%dm", 30 + 2); + printf("\nVyhrál jsi!\n"); + exit(0); + return 0; +} + +//Zkontroluje zda jsou flagy správně dané na minách +int checkFlags(){ + int i = 0; + while(i < size){ + int ii = 0; + while(ii < size){ + if(tileField[i][ii] != flag){ + ii++; + continue; + } + if(mineLocations[i][ii] != 'm'){ + return 0; + } + ii++; + } + i++; + } + win(); + return 0; +} + +//Zapnout časoměru +int startTimer(){ + if(timerSeconds == 0 && timerMinutes == 0){ + pthread_t thread_id; + int interval = 2; + pthread_create(&thread_id, NULL, timer, &interval); + } +} +