Chris Pollett>Old Classes>PIC 10a, Spring 2000>Hw6>Hw6 Solutions

Spring 2000 PIC 10a HW6 Solutions Page

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

Return to homework page.