I build a solution board that the user can’t see
/* These are general descriptions of test cases. Yours should be a bit more detailed about the exact inputs Test case 1: Input: Play until hitting a bomb Expected Output: YOU LOSE (show board) Actual: Test case 2: Input: Play until expose all safe spots Expected Output: WINNER! (show board) Actual: Test case 3: Input: Increase the bomb_sparcity Expected Output: Fewer bombs (more zeroes, easier) Actual: */ #include <iostream> #include <string> #include <ctime> using namespace std; const int BOARD_DIMENSION = 5; const int BOMB_SPARCITY = 3; const string BOMB_STRING = "*"; const string UNKNOWN_STRING = " "; /* Function to randomly place bombs on a game board. Each position has a 1 in BOMB_SPARCITY chance of being a bomb @param board the uninitialized minesweeper solution board */ void add_bombs(string board[][BOARD_DIMENSION]) { // for every row for (int row = 0; row < BOARD_DIMENSION; row++) { // for every column for (int col = 0; col < BOARD_DIMENSION; col++) { // add bombs, but not every time (just one in BOMB_SPARCITY times) int bomb_roll = rand() % BOMB_SPARCITY; // generate a random number between 0 and BOMB_SPARCITY if (bomb_roll == 0) { board[row][col] = BOMB_STRING; } else { board[row][col] = " "; } } } } /* Function to return the bomb count at a particular cell position (i.e., 0 or 1) If cell position has invalid coordinates, 0 is returned. @param board solution board with bombs previously placed @param row row of cell position we want to know about @param col column of cell position we want to know about @return 1 or 0, depending on if there is a bomb at the specified position or not (respectively) */ int bomb_count_at_row_col(string board[][BOARD_DIMENSION], int row, int col) { if (row < 0 || col < 0 || row >= BOARD_DIMENSION || col >= BOARD_DIMENSION) { return 0; } if (board[row][col] == BOMB_STRING) { return 1; } else { return 0; } } /* For a particular row and column, this function computes the number of bombs in the surrounding cell positions, including diagonally @param board solution board with bombs placed previously @param row row that we want to calculate the bomb hint for @param col col that we want to calculate the bomb hint for @return number of bombs in cells immediately surrounding cell at row, col */ int get_hint_for_row_col(string board[][BOARD_DIMENSION], int row, int col) { int surround_bombs = 0; // for each surrounding cell, we add the number of bombs (i.e., 1 or 0) in that cell surround_bombs += bomb_count_at_row_col(board, row - 1, col - 1); // up left surround_bombs += bomb_count_at_row_col(board, row - 1, col); // up surround_bombs += bomb_count_at_row_col(board, row - 1, col + 1); // up right surround_bombs += bomb_count_at_row_col(board, row + 1, col - 1); // down left surround_bombs += bomb_count_at_row_col(board, row + 1, col); // down surround_bombs += bomb_count_at_row_col(board, row + 1, col + 1); // down right surround_bombs += bomb_count_at_row_col(board, row, col - 1); // left surround_bombs += bomb_count_at_row_col(board, row, col + 1); // right return surround_bombs; } /* Fills in the numeric bomb hints on a board with bombs already placed @param board solution board with bombs already placed */ void fill_hints(string board[][BOARD_DIMENSION]) { // for each row for (int row = 0; row < BOARD_DIMENSION; row++) { // for each column for (int col = 0; col < BOARD_DIMENSION; col++) { // that is not a bomb if (board[row][col] != BOMB_STRING) { // fill in the hint board[row][col] = to_string(get_hint_for_row_col(board, row, col)); } } } } /* Initialize a solution board by randomly placing bombs and then filling in the hints @param board uninitialized board */ void init_solution(string board[][BOARD_DIMENSION]) { // randomly add bombs add_bombs(board); // fill in the hints fill_hints(board); } /* Display an arbitrary game board with row heading and column heading @param board an arbitrary board (be it solution or guessing) */ void display_board(string board[][BOARD_DIMENSION]) { cout << " "; for (int row_heading = 0; row_heading < BOARD_DIMENSION; row_heading++) { cout << row_heading << " "; } cout << endl; for (int row = 0; row < BOARD_DIMENSION; row++) { cout << row << " "; for (int col = 0; col < BOARD_DIMENSION; col++) { cout << board[row][col] << " "; } cout << endl; } } /* Initlializes the guessing board by filling it with UNKNOWN_STRING values @param uninitialized guessing board */ void init_guess_board(string board[][BOARD_DIMENSION]) { for (int row = 0; row < BOARD_DIMENSION; row++) { for (int col = 0; col < BOARD_DIMENSION; col++) { board[row][col] = UNKNOWN_STRING; } } } /* Checks if the guess_board is fully solved, meaning every "safe" spot has been guessed @param sol_board solution board to consult for the true solution @param guess_board guess board to check if it is a solution @return true if every "safe" spot on the guess board has been */ bool is_solution(string sol_board[][BOARD_DIMENSION], string guess_board[][BOARD_DIMENSION]) { // Key is to assume it is a solution // Then check each cell for a situation which would make it NOT a solution for (int row = 0; row < BOARD_DIMENSION; row++) { for (int col = 0; col < BOARD_DIMENSION; col++) { // It's NOT a solution if: this is a safe spot && the spot isn't guessed yet if (sol_board[row][col] != BOMB_STRING && guess_board[row][col] == UNKNOWN_STRING) { // This would have also worked: // It's NOT a solution if: solution board is a safe spot at row,col && the guess_spot is different from the solution board // if (sol_board[row][col] != BOMB_STRING&& guess_board[row][col] != sol_board[row][col]) return false; } } } return true; } int main() { srand(time(0)); string user_input; do { // initialize the solution board string solution_board[BOARD_DIMENSION][BOARD_DIMENSION]; init_solution(solution_board); // initialize the guessing board string guessing_board[BOARD_DIMENSION][BOARD_DIMENSION]; init_guess_board(guessing_board); // print the visible board (get board as string) display_board(guessing_board); bool solved = false; bool bombed = false; // as long as it's not solved and we haven't hit a bomb while (!solved && !bombed) { // prompt the user for coordinates cout << "Gimme row col (e.g., 0 0):"; int row, col; cin >> row >> col; // get the solution value at the coordinates string solution_value = solution_board[row][col]; // update the guessing board at the coordinates guessing_board[row][col] = solution_value; // check if it's a bomb bombed = (solution_value == BOMB_STRING); // otherwise check if it's a solution solved = is_solution(solution_board, guessing_board); // print the visible board display_board(guessing_board); } display_board(solution_board); // print success or fail depending on whether or not we hit a bomb if (bombed) { cout << "YOU LOSE" << endl; } else { cout << "WINNER! WINNER! WINNER!" << endl; } cout << "Wanna play again(Y/N)? "; cin >> user_input; } while (user_input == "Y"); system("pause"); return 0; }