Advertisement
adambkehl

Minesweeper (simplified)

Feb 22nd, 2019
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.50 KB | None | 0 0
  1. //------- minesweeper.h -------
  2. //Wrote in class 2/21/19
  3. //Fixed the flood function to match real minesweeper
  4. //Commented anything that wasn't simple or clear
  5.  
  6. #include <iostream>
  7. #include <cstdlib>
  8. #include <ctime>
  9. using namespace std;
  10.  
  11. #define EASY 15
  12. #define MED 17
  13. #define HARD 19
  14.  
  15. class cell {
  16. private:
  17.     int bombs_near;
  18.     bool is_flagged, is_exposed, is_bomb;
  19.  
  20. public:
  21.     friend ostream &operator<<(ostream & stream, cell const &c);
  22.     cell();
  23.     ~cell();
  24.     void set_bombs_near(int const c);
  25.     int get_bombs_near() const;
  26.     void set_flagged(bool const b);
  27.     bool get_flagged() const;
  28.     void set_exposed(bool const b);
  29.     bool get_exposed() const;
  30.     void set_bomb(bool const b);
  31.     bool get_bomb() const;
  32. };
  33.  
  34. class minesweeper {
  35. private:
  36.     cell **board;
  37.     int row, col, probability;
  38.  
  39. public:
  40.     friend ostream &operator<<(ostream & stream, minesweeper &m);
  41.     minesweeper();
  42.     ~minesweeper();
  43.     void count_bombs_near();
  44.     bool game_over();
  45.     void reveal_at(int reveal_row, int reveal_col);
  46.     void get_user_move();
  47.     void get_settings();
  48. };
  49.  
  50.  
  51.  
  52.  
  53. //------- main.cpp -------
  54. //#include "minesweeper.h"
  55.  
  56. int main(int argc, char **argv) {
  57.  
  58.     srand((unsigned int)time(0)); //seed random num generator
  59.  
  60.     minesweeper game;
  61.     game.count_bombs_near(); //calculates bombs near every piece
  62.  
  63.     while (!game.game_over()) {
  64.         system("cls"); //windows only, mac is:  system("clear");
  65.         cout << game;
  66.         game.get_user_move();
  67.     }
  68.  
  69.     cin.get(), cin.get();
  70.     return 0;
  71. }
  72.  
  73.  
  74.  
  75.  
  76. //------- cell.cpp -------
  77. //#include "minesweeper.h"
  78.  
  79. cell::cell() {
  80.     bombs_near= 0;
  81.     is_flagged = false;
  82.     is_bomb = false;
  83.     is_exposed = false;
  84. }
  85.  
  86. cell::~cell() {}
  87.  
  88. //Setters and getters (used instead of accessing variables directly)
  89. void cell::set_bombs_near(int const bomb_count) { bombs_near = bomb_count; }
  90. int cell::get_bombs_near() const { return bombs_near; }
  91. void cell::set_flagged(bool const flag) { is_flagged = flag; }
  92. bool cell::get_flagged() const { return is_flagged; }
  93. void cell::set_bomb(bool const bomb) { is_bomb = bomb; }
  94. bool cell::get_bomb() const { return is_bomb; }
  95. void cell::set_exposed(bool const expose) { is_exposed = expose; }
  96. bool cell::get_exposed() const { return is_exposed; }
  97.  
  98. //Overloaded << operator used in main:  cout << game;
  99. //Shows entire game board with custom characters
  100. ostream &operator<<(ostream & stream, cell const &current_cell) {
  101.     unsigned char block_character = 178; //block is: 178 "▓"
  102.     unsigned char dot_character = 249; //dot is 249 "∙"
  103.     unsigned char flag_character = 176; //flag is 176 "░" (or maybe 213 "╒"?)
  104.  
  105.     if (current_cell.is_flagged) {
  106.         stream << flag_character;
  107.         return stream;
  108.     }
  109.     if (current_cell.is_exposed) {
  110.         if (current_cell.bombs_near == 0) stream << dot_character;
  111.         else stream << current_cell.bombs_near ;
  112.     }
  113.     else {
  114.         stream << block_character;
  115.     }
  116.  
  117.     return stream;
  118. }
  119.  
  120.  
  121.  
  122.  
  123. //------- minesweeper.cpp -------
  124. //#include "minesweeper.h"
  125.  
  126. minesweeper::minesweeper() {
  127.     get_settings(); //gets size of board and difficulty
  128.  
  129.     //Allocates 2D array
  130.     board = new cell*[row];
  131.     for (int i = 0; i < row; i++) {
  132.         board[i] = new cell[col];
  133.     }
  134.  
  135.     //Places bombs
  136.     for (int i = 0; i < row; i++) {
  137.         for (int j = 0; j < col; j++) {
  138.             if (rand() % (row*col) + 1 < (probability / 100.00) * (row*col)) {
  139.                 board[i][j].set_bomb(true);
  140.             }
  141.         }
  142.     }
  143. }
  144.  
  145. minesweeper::~minesweeper() {
  146. //Deallocates our 2D array
  147.     for (int i = 0; i < row; i++) {
  148.         delete[] board[i];
  149.     }
  150.     delete[] board;
  151. }
  152.  
  153. //Gets user settings such as size and difficulty
  154. void minesweeper::get_settings() {
  155.     int row_size, column_size, difficulty;
  156.  
  157.     cout << "Enter row size: ";
  158.     cin >> row_size;
  159.     cout << "Enter column size: ";
  160.     cin >> column_size;
  161.     cout << "Enter difficulty (1 - easy, 2 - med, 3 - hard): ";
  162.     cin >> difficulty;
  163.  
  164.     row = row_size;
  165.     col = column_size;
  166.  
  167.     if (difficulty == 1) probability = EASY;
  168.     else if (difficulty == 2) probability = MED;
  169.     else if (difficulty == 3) probability = HARD;
  170.     else cout << "Invalid difficulty setting.";
  171. }
  172.  
  173. //Calculates number of bombs next to each cell
  174. //Assigns that number to the bombs_near variable
  175. void minesweeper::count_bombs_near() {
  176.     int count;
  177.     bool open_top, open_bottom, open_left, open_right;
  178.  
  179.     //Cycles through all positions on the board (including oob)
  180.     //
  181.     //Shorter way would be:
  182.     //for (int r = 1; r < row - 1; r++) {
  183.     //  for (int c = 1; c < col - 1; c++) {
  184.     //and then you wouldn't need the booleans
  185.     //
  186.     for (int r = 0; r < row; r++) {
  187.         for (int c = 0; c < col; c++) {
  188.  
  189.             count = 0;
  190.             open_top = false, open_bottom = false, open_left = false, open_right = false;
  191.  
  192.             //Determines if the cell is within bounds
  193.             //Longer way of doing:  if (x < 0 || y < 0 || x >= row || y >= col)
  194.             if (r > 0) open_top = true;
  195.             if (c > 0) open_left = true;
  196.             if (c < col - 1) open_right = true;
  197.             if (r < row - 1) open_bottom = true;
  198.  
  199.             //Checks for a bomb above, above and to the right, and above and to the left
  200.             if (open_top){
  201.                 if (board[r - 1][c].get_bomb()) count++;
  202.                 if (open_right)
  203.                     if (board[r - 1][c + 1].get_bomb()) count++;
  204.                 if (open_left)
  205.                     if (board[r - 1][c - 1].get_bomb()) count++;
  206.             }
  207.  
  208.             //Checks for a bomb below, below and to the right, and below and to the left
  209.             if (open_bottom) {
  210.                 if (board[r + 1][c].get_bomb()) count++;
  211.                 if (open_right)
  212.                     if (board[r + 1][c + 1].get_bomb()) count++;
  213.                 if (open_left)
  214.                     if (board[r + 1][c - 1].get_bomb()) count++;
  215.             }
  216.  
  217.             //Checks for a bomb to the left and right
  218.             if (open_right)
  219.                 if (board[r][c + 1].get_bomb()) count++;
  220.             if (open_left)
  221.                 if (board[r][c - 1].get_bomb()) count++;
  222.  
  223.  
  224.             //Finally, assigns the surrounding bomb count to the cell
  225.             board[r][c].set_bombs_near(count);
  226.  
  227.         }
  228.     }
  229. }
  230.  
  231. //Gets where the user selected, either to mark or expose
  232. void minesweeper::get_user_move() {
  233.     int selection, selection_row, selection_col;
  234.  
  235.     cout << endl << "(1) mark bomb" << endl << "(2) open cell" << endl;
  236.     cin >> selection;
  237.  
  238.     cout << "Enter row, then column: " << endl;
  239.     cin >> selection_row;
  240.     cin >> selection_col;
  241.  
  242.     if (selection == 1) {
  243.         //makes the flag opposite what it was previously
  244.         //i.e. if the cell is already flagged, it's not flagged anymore
  245.         board[selection_row][selection_col].set_flagged(!board[selection_row][selection_col].get_flagged());
  246.     }
  247.     else if (selection == 2) {
  248.         if (board[selection_row][selection_col].get_bomb()) {
  249.             //Losing condition. Marks as exposed, returns to main, main calls game_over, and
  250.             //game is now over because bomb is exposed
  251.             board[selection_row][selection_col].set_exposed(true);
  252.             return;
  253.         } else {
  254.             reveal_at(selection_row, selection_col);
  255.         }
  256.     } else {
  257.         cout << "Invalid selection." << endl;
  258.     }
  259. }
  260.  
  261. //Reveals the cell at location
  262. //Uses Dan's (killer) recursive function!
  263. void minesweeper::reveal_at(int r, int c) {
  264.     if (r < 0 || c < 0 || r >= row || c >= col) return; //checks for out of bounds
  265.     if (board[r][c].get_exposed() || board[r][c].get_bomb()) return; //stop if is bomb or already exposed
  266.  
  267.     //If the nearby bomb count is zero, we're clear to show ALL surrounding cells
  268.     if (board[r][c].get_bombs_near() == 0) {
  269.         board[r][c].set_exposed(true); //stops recursion from looping back on self
  270.         reveal_at(r - 1, c); //above
  271.         reveal_at(r + 1, c); //below
  272.         reveal_at(r, c - 1); //left
  273.         reveal_at(r, c + 1); //right
  274.         reveal_at(r + 1, c + 1); //up and right
  275.         reveal_at(r - 1, c - 1); //below and left
  276.         reveal_at(r + 1, c - 1); //up and left
  277.         reveal_at(r - 1, c + 1); //below and right
  278.     }
  279.     board[r][c].set_exposed(true); //stops recursion from looping back on self
  280. }
  281.  
  282. ostream &operator<<(ostream & stream, minesweeper &game){
  283.     for (int r = 0; r < game.row; r++) {
  284.         for (int c = 0; c < game.col; c++) {
  285.             stream << game.board[r][c];
  286.         }
  287.         stream << endl;
  288.     }
  289.     return stream;
  290. }
  291.  
  292. //Checks for game over condition: an exposed bomb
  293. bool minesweeper::game_over() {
  294.     int exposed_spaces = 0, flagged_count = 0;
  295.  
  296.     for (int r = 0; r < row; r++) {
  297.         for (int c = 0; c < col; c++) {
  298.             if (board[r][c].get_flagged()) {
  299.                 flagged_count++;
  300.             }
  301.             if (board[r][c].get_exposed()) {
  302.                 exposed_spaces++;
  303.                 if (board[r][c].get_bomb()) {
  304.                     cout << "You get nothing. You lose." << endl;
  305.                     return true; //game is over, but you lost
  306.                 }
  307.             }
  308.         }
  309.     }
  310.  
  311.     //All cells are exposed except for flagged bombs
  312.     if (exposed_spaces == (row * col - flagged_count)) {
  313.         cout << "You've won! You did it! Oh, I just knew you would." << endl;
  314.         return true; //game is over, and you won
  315.     }
  316.  
  317.     return false; //game is not over yet
  318. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement