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";
}