Stoycho_KK

minesweeper final

Jan 3rd, 2021 (edited)
249
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.57 KB | None | 0 0
  1. #include <iostream>
  2. #include<cstdlib>
  3. #include<ctime>
  4. #include<windows.h>
  5.  
  6. const char DEF_FILL = '#';
  7. const char DEF_MINE = '@';
  8. const char DEF_MASK = '-';
  9.  
  10. const int EASY = 1;
  11. const int MEDIUM = 2;
  12. const int HARD = 3;
  13. const int CUST = 4;
  14.  
  15. bool winner(char**, int**, int, const int&, const int&);
  16. bool gameover = false;
  17.  
  18. void goAgain();
  19.  
  20. void onStartUp() {
  21.     system("title = MINE SWEEPER");
  22.  
  23.     std::cout << "Choose level:" << std::endl <<
  24.         "1-Easy" << std::endl <<
  25.         "2-Medium" << std::endl <<
  26.         "3-Hard" << std::endl <<
  27.         "4-Customize the field and the number of mines" << std::endl;
  28. }
  29.  
  30. void validateNumber(int& userInput, int lowerBound, int higherBound) {
  31.     bool err = false;
  32.  
  33.     std::cin >> userInput;
  34.    
  35.     while (userInput <= lowerBound || userInput >= higherBound) {
  36.         std::cout << "Invalid Input!" << std::endl;
  37.  
  38.         bool textErr = ((bool)(std::cin));
  39.         if (!textErr) {
  40.             std::cin.clear();
  41.             std::cin.ignore(255, '\n');
  42.             userInput = -1;
  43.         }
  44.         std::cin >> userInput;
  45.     }
  46. }
  47.  
  48. bool isMemberOfMinesArray(int** databaseMines, int x, int y, const int& heightOfDatabase) {
  49.     for (int i = 0; i < heightOfDatabase; i++)
  50.         if (databaseMines[i][0] == x && databaseMines[i][1] == y)
  51.             return true;
  52.  
  53.     return false;
  54. }
  55.  
  56. void initDatabaseForLocationOfMines(int** databaseMines, const int& amountOfMines) {
  57.     for (int i = 0; i < amountOfMines; i++)
  58.         for (int j = 0; j < 2; j++)
  59.             databaseMines[i][j] = -1;
  60. }
  61.  
  62. void getCoordinatesOfMines(int** minesLocationData, const int& amountOfMines, const int& length, const int& height) {
  63.     for (int i = 0; i < amountOfMines; i++) {
  64.         srand(time(NULL));
  65.         int indexOne = rand() % length;
  66.         int indexTwo = rand() % height;
  67.  
  68.         while (isMemberOfMinesArray(minesLocationData, indexOne, indexTwo, amountOfMines)) {
  69.             indexOne = rand() % length;
  70.             indexTwo = rand() % height;
  71.         }
  72.         minesLocationData[i][0] = indexOne;
  73.         minesLocationData[i][1] = indexTwo;
  74.     }
  75. }
  76.  
  77. void initWithMines(char** gameboard, int** databaseOfMines, const int& minesCount, const int& length, const int& height) {
  78.     for (int i = 0; i < height; i++)
  79.         for (int j = 0; j < length; j++) {
  80.             if (isMemberOfMinesArray(databaseOfMines, i, j, minesCount))
  81.                 gameboard[i][j] = DEF_MINE;
  82.             else
  83.                 gameboard[i][j] = DEF_MASK;
  84.         }
  85. }
  86.  
  87. void printBoard(char** gameboard, const int& length, const int& height, int locationOfFoundMineX = -1, int locationOfFoundMineY = -1) {
  88.     system("CLS");
  89.     HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
  90.  
  91.     std::cout << " ";
  92.     for (int n = 0; n < length; n++) {
  93.         SetConsoleTextAttribute(hConsole, rand() % 14 + 1);
  94.         if (n < 10)
  95.             std::cout << "  " << n << " ";
  96.         else
  97.             std::cout << " " << n << " ";
  98.     }
  99.     SetConsoleTextAttribute(hConsole, 7);
  100.  
  101.     std::cout << std::endl;
  102.  
  103.     for (int i = 0; i < height; i++) {
  104.         std::cout.width(2);
  105.         SetConsoleTextAttribute(hConsole, rand() % 14 + 1);
  106.         std::cout << i << " ";
  107.         SetConsoleTextAttribute(hConsole, 7);
  108.  
  109.         for (int j = 0; j < length; j++) {
  110.             if (i == locationOfFoundMineX && j == locationOfFoundMineY) {
  111.                 SetConsoleTextAttribute(hConsole, 4);
  112.                 std::cout << "@";
  113.                 SetConsoleTextAttribute(hConsole, 7);
  114.                 std::cout << " | ";
  115.             }
  116.             else if (gameboard[i][j] == DEF_MASK || gameboard[i][j] == DEF_MINE)
  117.                 std::cout << DEF_FILL << " | ";
  118.             else if (gameboard[i][j] == '0')
  119.                 std::cout << " " << " | ";
  120.             else {
  121.                 SetConsoleTextAttribute(hConsole, 6);
  122.                 std::cout << gameboard[i][j];
  123.                 SetConsoleTextAttribute(hConsole, 7);
  124.                 std::cout << " | ";
  125.             }
  126.         }
  127.         std::cout << std::endl;
  128.     }
  129. }
  130.  
  131. bool isOpen(const char com[5]) {
  132.     char open[5] = { 'o', 'p', 'e', 'n', '\0' };
  133.  
  134.     bool isFirst = strcmp(open, com);
  135.  
  136.     return !(isFirst);
  137. }
  138.  
  139. bool isMark(const char com[5]) {
  140.     char mask[5] = { 'm', 'a', 'r', 'k', '\0' };
  141.  
  142.     bool isSec = strcmp(mask, com);
  143.  
  144.     return !(isSec);
  145. }
  146.  
  147. bool isValidMove(char** gameboard, char com[5], int X, int Y, const int len, const int height) {
  148.     return !((X < 0) || (X >= height)) && !((Y < 0) || (Y >= len)) &&
  149.         (isOpen(com) || isMark(com));
  150. }
  151.  
  152. bool isMoveInBoundOfArray(const int& X, const int& Y, const int& len, const int& height) {
  153.     return X >= 0 && X < height&& Y >= 0 && Y < len;
  154. }
  155.  
  156. int cellWorth(char** gameboard, int** databaseOfMinesLocations, const int& amountOfMines, int x, int y, int len, int height) {
  157.     int cellWorth = 0;
  158.  
  159.     if (gameboard[x][y] == DEF_MINE)
  160.         return -1;
  161.  
  162.     for (int i = -1; i < 2; i++)
  163.         for (int j = -1; j < 2; j++) {
  164.             if (i == 0 && j == 0)
  165.                 continue;
  166.  
  167.             if (isMoveInBoundOfArray(x + i, y + j, len, height) && isMemberOfMinesArray(databaseOfMinesLocations, x + i, y + j, amountOfMines))
  168.                 cellWorth++;
  169.         }
  170.  
  171.     return cellWorth;
  172. }
  173.  
  174. void getMove(char** gameboard, char com[5], int& x, int& y, const int len, const int height) {
  175.     char open[5] = { 'o', 'p', 'e', 'n', '\0' };
  176.     char mark[5] = { 'm', 'a', 'r', 'k', '\0' };
  177.  
  178.     int ind = 0;
  179.  
  180.     do {
  181.         char c;
  182.         std::cin.get(c);
  183.         if (c == open[ind] || c == mark[ind]) {
  184.             com[ind] = c;
  185.             ++ind;
  186.         }
  187.         else if ((int)c == 10 && ind != 4) {
  188.             ind = 0;
  189.             com[0] = '\0';
  190.         }
  191.  
  192.         if (ind == 4) {
  193.             com[ind] = '\0';
  194.             if (isOpen(com) || isMark(com))
  195.                 break;
  196.             else {
  197.                 ind = 0;
  198.                 com[0] = '\0';
  199.             }
  200.         }
  201.     } while (true);
  202.  
  203.     std::cin >> x >> y;
  204.  
  205.     if (!isValidMove(gameboard, com, x, y, len, height)) {
  206.         std::cout << "Invalid Input" << std::endl;
  207.         x = -1; y = -1; com[0] = '\n';
  208.         getMove(gameboard, com, x, y, len, height);
  209.         return;
  210.     }
  211. }
  212.  
  213. void openCell(char** gameboard, int** databaseOfMinesLocations, int amountOfMines, int worth, int x, int y, int len, int heigth, bool alreadyMarked) {
  214.  
  215.     //try removing already marked later
  216.     if (gameboard[x][y] == 'X' && alreadyMarked) {
  217.         gameboard[x][y] = DEF_MASK;
  218.         return;
  219.     }
  220.  
  221.     //end of recursion:
  222.     if (gameboard[x][y] != DEF_MASK && gameboard[x][y] != DEF_MINE)
  223.         return;
  224.  
  225.     gameboard[x][y] = worth + '0';
  226.  
  227.     //start of recursion:
  228.     if (worth == 0) {
  229.         for (int i = 0; i < 3; i++) {
  230.             for (int j = 0; j < 3; j++) {
  231.                 if (j == 1 && i == 1)
  232.                     continue;
  233.  
  234.                 int newX = x + i - 1; int newY = y + j - 1;
  235.                 if (isMoveInBoundOfArray(newX, newY, len, heigth)) {
  236.                     int newWorth = cellWorth(gameboard, databaseOfMinesLocations, amountOfMines, newX, newY, len, heigth);
  237.                     openCell(gameboard, databaseOfMinesLocations, amountOfMines, newWorth, newX, newY, len, heigth, false);
  238.                 }
  239.             }
  240.         }
  241.     }
  242. }
  243.  
  244. void markCell(char** gameboard, int x, int y) {
  245.     if (gameboard[x][y] == DEF_MASK || gameboard[x][y] == DEF_MINE)
  246.         gameboard[x][y] = 'X';
  247. }
  248.  
  249. void makeMove(char** gameboard, int** dataMines, int amountOfMines, const int len, const int height) {
  250.     char com[5];
  251.  
  252.     int x; int y;
  253.  
  254.     std::cout << "Please enter a comand: open or mark!" << std::endl <<
  255.         "Comand: ";
  256.  
  257.  
  258.     //making move:
  259.     getMove(gameboard, com, x, y, len, height);
  260.  
  261.     //getting value of cell:
  262.     int val = cellWorth(gameboard, dataMines, amountOfMines, x, y, len, height);
  263.  
  264.     if (isOpen(com) && val != -1) {
  265.         //try removing true!
  266.         openCell(gameboard, dataMines, amountOfMines, val, x, y, len, height, true);
  267.     }
  268.     else if (isOpen(com) && cellWorth(gameboard, dataMines, amountOfMines, x, y, len, height) == -1) {
  269.         printBoard(gameboard, len, height, x, y);
  270.         gameover = true;
  271.     }
  272.     else if (isMark(com)) {
  273.         markCell(gameboard, x, y);
  274.     }
  275.     else {
  276.         std::cout << "Fatal error!";
  277.     }
  278.  
  279. }
  280.  
  281. bool winner(char** gameboard, int** databaseOfMines, int amountOfMines, const int& len, const int& height) {
  282.     for (int i = 0; i < amountOfMines; i++)
  283.         if (gameboard[databaseOfMines[i][0]][databaseOfMines[i][1]] != 'X')
  284.             return false;
  285.  
  286.     return true;
  287. }
  288.  
  289. void play(int level) {
  290.     int length = 0; int height = 0; int minesCount = 0;
  291.  
  292.     switch (level) {
  293.     case EASY:
  294.         length = 7; height = 7; minesCount = 6;
  295.         break;
  296.     case MEDIUM:
  297.         length = 10; height = 10; minesCount = 25;
  298.         break;
  299.     case HARD:
  300.         length = 15; height = 15; minesCount = 40;
  301.         break;
  302.     case CUST:
  303.         system("cls");
  304.  
  305.         std::cout << "Enter length [5 < length < 50]: ";
  306.         validateNumber(length, 5, 51);
  307.  
  308.         std::cout << "Enter height [5 < height < 50]: ";
  309.         validateNumber(height, 5, 51);
  310.  
  311.         minesCount = 0.2 * length * height;
  312.         break;
  313.     }
  314.  
  315.     char** gameboard = new char* [height];
  316.  
  317.     for (int i = 0; i < length; i++)
  318.         gameboard[i] = new char[length];
  319.  
  320.     int** minesLocationData = new int* [minesCount];
  321.  
  322.     for (int i = 0; i < minesCount; i++)
  323.         minesLocationData[i] = new int[2];
  324.  
  325.     initDatabaseForLocationOfMines(minesLocationData, minesCount);
  326.  
  327.     getCoordinatesOfMines(minesLocationData, minesCount, length, height);
  328.  
  329.     initWithMines(gameboard, minesLocationData, minesCount, length, height);
  330.  
  331.     while (!gameover && !winner(gameboard, minesLocationData, minesCount, length, height)) {
  332.         printBoard(gameboard, length, height);
  333.         makeMove(gameboard, minesLocationData, minesCount, length, height);
  334.     }
  335.  
  336.     for (int i = 0; i < minesCount; i++)
  337.         delete[] minesLocationData[i];
  338.  
  339.     for (int i = 0; i < height; i++)
  340.         delete[] gameboard[i];
  341.  
  342.     if (gameover)
  343.         std::cout << "you lose :(";
  344.     else
  345.         std::cout << "you win :)";
  346. }
  347.  
  348. void Create() {
  349.     onStartUp();
  350.  
  351.     int mode = 0;
  352.     validateNumber(mode, 0, 5);
  353.  
  354.     switch (mode) {
  355.     case 1: play(EASY);
  356.         break;
  357.     case 2: play(MEDIUM);
  358.         break;
  359.     case 3: play(HARD);
  360.         break;
  361.     case 4: play(CUST);
  362.         break;
  363.     default:
  364.         std::cout << "Fatal error.";
  365.         break;
  366.     }
  367.  
  368.     goAgain();
  369. }
  370.  
  371. void goAgain() {
  372.     int command;
  373.     std::cout << "\nWanna go again?\n 1 restart \n 0 exit\n";
  374.     validateNumber(command, -1, 2);
  375.     switch (command)
  376.     {
  377.     case 1: system("cls"); gameover = false; Create(); break;
  378.     case 0: exit(0);
  379.     default:
  380.         std::cout << "Fatal error! :(";
  381.         break;
  382.     }
  383. }
  384.  
  385. int main() {
  386.     Create();
  387. }
Add Comment
Please, Sign In to add comment