Chris Pollett>Old Classes>PIC 10a, Spring 2000>Hw6>Hw6 Solutions
// Put your personal info and Honesty statement here // // // // Program Name: MineSweeper.cpp // // Purpose: A program that plays a simplified version of the game minesweeper // // Known Bugs: random number generator generates same bomb positions // each time played would be better to connect to system clock #include<iostream.h> //for cout #include<stdlib.h> //for exit(), rand() #include<iomanip.h> // // Enumerated types and constants // enum SquareValues { EMPTY_SEEN=' ', EMPTY_UNSEEN=0, ONE_SEEN='1', ONE_UNSEEN=1, TWO_SEEN='2', TWO_UNSEEN=2, THREE_SEEN='3', THREE_UNSEEN=3, FOUR_SEEN='4', FOUR_UNSEEN=4, FIVE_SEEN='5', FIVE_UNSEEN=5, SIX_SEEN='6', SIX_UNSEEN=6, SEVEN_SEEN='7', SEVEN_UNSEEN=7, EIGHT_SEEN='8', EIGHT_UNSEEN=8, BOMB= 9}; // SquareValues enumerates the possible values // that can be stored in // a position on a minesweeper board enum MoveResult { MOVE_OUT_OF_RANGE, SUCCESSFUL, WAS_BOMB }; // MoveResult enumerates possible things that can happen // when attempting a move on a MineSweeper game const int MAX_UNSEEN = 9; // highest number in SquareValues that is // printed to screen as '#' const int DEFAULT_NUM_BOMBS =10; //number of bombs that // will be put on a minsweeper board // unless otherwise specified const int DEFAULT_SIZE =10; //the start-off size of a minesweeper board // is DEFAULT_SIZE X DEFAULT_SIZE // // // Classes // // // Class name: MineSweeper // // Purpose: Stores board used in minesweeper game. // Also keeps track of the number of bombs on the board // and the size of the board. Has methods which allows // a driver program to calculate the score, to print the // board to the screen, or to play a move on the board. // Known Bugs: none class MineSweeper { public: MineSweeper( int nBombs = DEFAULT_NUM_BOMBS, int boardSize = DEFAULT_SIZE); // Constructor for a MineSweeper object. // It sets size = boardSize and // numBombs= nBombs. Then it // creates memory for the board by doing // board[r] = new SquareValues [size]; // for each row. Next it sets each square // on board to be EMPTY_UNSEEN. // Then it adds BOMBS to numBombs many // random and **DISTINCT** places on board. // To select a row for a bomb randomly // row = (int)(size*rand()/(RAND_MAX+1.0)) // is used. (Columns are selected similarly) // rand() is in stdlib and is much like generator // from hw2. RAND_MAX is a constant defined in // stdlib. When each BOMB is added the values // of the surrounding non-BOMB squares are // incremented by one, so they accurately reflect // how many BOMBS are adjacent. ~MineSweeper(); //Destructor. Deletes game board. //Since board is a 2-dimensional array //must do delete [] board[r] for each row. MoveResult move(int x, int y); // if x and y is a BOMB or // or out of range the // corresponding MoveResult value // is returned. Otherwise, the square // board[x][y] is set to its // corresponding SEEN value and // SUCCESSFUL is returned. i.e., // ONE_UNSEEN would become ONE_SEEN void printBoard(); // prints out what the current board // looks like. If board[i][j] is less than // or equal MAX_UNSEEN then the square is printed // as a #. Otherwise char(board[i][j]) is printed. int scoreBoard(); // counts up the number of squares in // the board with value greater than // MAX_UNSEEN. This is the number of pieces that // have been seen. int getNumBombs(); // returns the value numBombs; int getSize(); // returns the value size private: SquareValues** board; // the minesweeper game board // a pointer to a pointer is // just like a 2-dimensional array int size; //store the size of current game board int numBombs; // stores the number of bombs used on current // game board. }; // Method name: MineSweeper // // Purpose: Constructor. Creates a board, places BOMBS on it, // and sets adjacent square accordingly // // Known Bugs: none MineSweeper::MineSweeper(int nBombs, int boardSize) { numBombs = nBombs; size = boardSize; int xRand, yRand; board = new SquareValues* [size]; for(int i =0; i <size; i++) { board[i] = new SquareValues [size]; for(int j=0; j <size; j++) { board[i][j] = EMPTY_UNSEEN; } } for(int i = 0; i <numBombs; i++) { do{ xRand = (int)(size*rand()/(RAND_MAX+1.0)); yRand = (int)(size*rand()/(RAND_MAX+1.0)); }while(board[xRand][yRand] == BOMB); for(int v = xRand-1; v <xRand+2; v++) { for(int w= yRand-1; w <yRand+2; w++) { if(v <0 || w <0 || v >=size || w >= size || board[v][w] == BOMB) continue; board[v][w] = (SquareValues)(board[v][w]+ 1); } } board[xRand][yRand] = BOMB; } } // Method name: ~MineSweeper // // Purpose: Destructor. Deletes each row of MineSweeper game. // // Known Bugs: none MineSweeper::~MineSweeper() { for(int i =0; i <size; i++) delete [] board[i]; delete [] board; } // Method name: move // // Purpose: if x and y is a BOMB or out of range // corresponding MoveResult value is returned. Otherwise, the square // board[x][y] is set to its corresponding SEEN value and // SUCCESSFUL is returned. i.e., ONE_UNSEEN would become ONE_SEEN // // Known Bugs: none MoveResult MineSweeper::move(int x, int y) { if( x <0 || y <0 || x >= size || y >= size) return MOVE_OUT_OF_RANGE; switch(board[x][y]) { case BOMB: return WAS_BOMB; case EMPTY_UNSEEN: board[x][y] = EMPTY_SEEN; break; default: board[x][y] = (SquareValues) (board[x][y] + '0'); } return SUCCESSFUL; } // Method name: printBoard // // Purpose: prints the score of the current board along with what it looks // like. // // Known Bugs: none void MineSweeper::printBoard() { int i; SquareValues tmp; cout <<"Current Score:" <<scoreBoard() <<"\n\n\t "; cout.setf(ios::right); for( i =0; i <size; i++) { cout <<setw(3)<<i; } for(i = 0; i <size; i++) { cout <<"\n\t" <<setw(2)<<i; for(int j = 0; j <size; j++) { tmp = board[i][j]; if(tmp > MAX_UNSEEN) cout <<" "<<char(tmp); else cout <<" #"; } } } // Method name: scoreBoard // // Purpose: returns the number of squares in the board that have been seen. // This is what the score is defined to be // // Known Bugs: none int MineSweeper::scoreBoard() { int score =0; for(int i = 0; i <size; i++) { for(int j = 0; j <size; j++) { if(board[i][j] > MAX_UNSEEN) score++; } } return score; } // Method name: getSize // // Purpose: returns size of current board // // Known Bugs: none int MineSweeper::getSize() { return size; } // Method name: getNumBombs // // Purpose: returns number of bombs on current board. // // Known Bugs: none int MineSweeper::getNumBombs() { return numBombs; } // // // Function Prototypes for Driver program // // void PrintMenu(); // Prints title screen and options available // also says what current game settings are void SetOptions(); //allows the user to change the size of the minesweeper //game along with the number of bombs used void PlayGame(); // Does game playing loop. Loop just prints the board // ask the user for a row and column does that move // and loops if game not terminated. int GetChoice(int lo, int hi); // Precondition: lo <hi have been assigned values // // Postcondition: has gotten a choice from the user between lo and hi // and returned it // typedef MineSweeper* MineSweeperPtr; MineSweeperPtr game = new MineSweeper(); //Used to store current //MineSweeper game // Function name: main // // Purpose: main loop for MineSweeper game, draws main menu, gets // a menu choice from user and does that task, then loops // // Known Bugs: none int main() { bool keepPlaying = true; int nBombs, size; while( keepPlaying) { nBombs = game->getNumBombs(); size = game->getSize(); delete game; game = new MineSweeper(nBombs, size); PrintMenu(); switch(GetChoice(1,3)) { case 1: SetOptions(); break; case 2: PlayGame(); break; case 3: keepPlaying =false; } } return 0; } // Function name: GetChoice(int lo, int hi) // // Purpose: if lo <hi have been assigned values then gets a choice from // the user between lo and hi // and returns it // // Known Bugs: Can screw up if a non-integer input by user int GetChoice(int lo, int hi) { int choice = lo-1; bool flag =true; do{ cout <<"\nPlease enter a number between " <<lo <<" and " <<hi <<": "; cin >> choice; if( choice <lo || choice > hi) cout <<"Invalid choice.\n"; else flag = false; }while(flag); return choice; } // Function name: PrintMenu // // Purpose: Prints title screen and options available. // Also says what current game settings are // // Known Bugs: none void PrintMenu() { cout <<"\nWelcome to MineSweeper\n"; cout <<"======================\n\n"; cout <<"Current game size is: " <<game->getSize() <<endl; cout <<"Games use " <<game->getNumBombs()<<" bombs" <<endl; cout <<"\nSelect:\n"; cout <<"(1) Change settings\n"; cout <<"(2) Play Game\n"; cout <<"(3) Quit\n"; } // Function name: SetOptions // // Purpose: Allows the user to change the size of the minesweeper // game along with the number of bombs used // // Known Bugs: none void SetOptions() { int bSize, nBombs; cout <<"\nSelect a new board size..."; bSize=GetChoice(5,15); cout <<"\nSelect number of bombs..."; nBombs=GetChoice(0,20); delete game; game = new MineSweeper(nBombs, bSize); } // Function name: PlayGame // // Purpose: Does game playing loop. Loop just prints the board, // asks the user for a row and column does that move // and loops if game not terminated. // // Known Bugs: none void PlayGame() { int row,col; do { game->printBoard(); cout <<"\nSelect a row (-1 to quit)..."; row =GetChoice(-1,game->getSize()-1); if (row == -1) exit(0); cout <<"\nSelect a column (-1 to quit)..."; col=GetChoice(-1,game->getSize()-1); if (col == -1) exit(0); } while(game->move(row,col) != WAS_BOMB); cout <<"\n\nThat was a bomb! Game over.\n"; cout <<"\n\nYour final score was: " <<game->scoreBoard() <<"\n\n"; }