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

Spring 2000 PIC 10a HW #6

Due by 10:30p.m. June 8

Required file name: MineSweeper.cpp

Purpose: To gain experience with multidimensional arrays and pointers. To experiment with dynamic memory allocation. To practice writing classes some more and to further gain practice extending/working with someone else's code.

Description: For this assignment you are to finish the program below that plays a simplified version of the game MineSweeper. The only things that have yet to be written for this program are the methods of the class MineSweeper.

Minesweeper is a game that commonly comes included with most Windows/Linux systems (look under Games). Numerous bored people have been known to waste a lot of time playing it. One logician Richard Kaye has even considered it from computational complexity point of view (showing it NP-complete). In the variant that we are writing the game board initially looks like:

Current Score:0

	    0  1  2  3  4  5  6  7  8  9
	 0  #  #  #  #  #  #  #  #  #  #
	 1  #  #  #  #  #  #  #  #  #  #
	 2  #  #  #  #  #  #  #  #  #  #
	 3  #  #  #  #  #  #  #  #  #  #
	 4  #  #  #  #  #  #  #  #  #  #
	 5  #  #  #  #  #  #  #  #  #  #
	 6  #  #  #  #  #  #  #  #  #  #
	 7  #  #  #  #  #  #  #  #  #  #
	 8  #  #  #  #  #  #  #  #  #  #
	 9  #  #  #  #  #  #  #  #  #  #
Select a row (-1 to quit)...
Please enter a number between -1 and 10:    

The user can select a row and then is prompted to select a column. The idea is that underneath a `#' is either an empty square or a bomb. The goal of the game is to see what's under as many `#'s as possible without seeing a bomb. Seeing a bomb ends the game. The score is the number of squares that have been looked at so far. To help the player figure out if there is a bomb nearby, when a square is checked the number of bombs in the squares adjacent to it is revealed. If there are no bombs adjacent then a space is printed. For example, suppose row 0 and column 0 is chosen as a first move. The resulting board drawn is:

Current Score:1

	    0  1  2  3  4  5  6  7  8  9
	 0     #  #  #  #  #  #  #  #  #
	 1  #  #  #  #  #  #  #  #  #  #
	 2  #  #  #  #  #  #  #  #  #  #
	 3  #  #  #  #  #  #  #  #  #  #
	 4  #  #  #  #  #  #  #  #  #  #
	 5  #  #  #  #  #  #  #  #  #  #
	 6  #  #  #  #  #  #  #  #  #  #
	 7  #  #  #  #  #  #  #  #  #  #
	 8  #  #  #  #  #  #  #  #  #  #
	 9  #  #  #  #  #  #  #  #  #  #
    

i.e., a space is drawn at location (0,0). This means there are no bombs in (0,1), (1,1), and (1,0). If for the next move we do (3,4) the resulting board looks like:

Current Score:2
qqy	    0  1  2  3  4  5  6  7  8  9
	 0     #  #  #  #  #  #  #  #  #
	 1  #  #  #  #  #  #  #  #  #  #
	 2  #  #  #  #  #  #  #  #  #  #
	 3  #  #  #  #  2  #  #  #  #  #
	 4  #  #  #  #  #  #  #  #  #  #
	 5  #  #  #  #  #  #  #  #  #  #
	 6  #  #  #  #  #  #  #  #  #  #
	 7  #  #  #  #  #  #  #  #  #  #
	 8  #  #  #  #  #  #  #  #  #  #
	 9  #  #  #  #  #  #  #  #  #  #

This means that two of the squares (3,3), (2,3), (2,4), (2,5), (3,5), (4,5), (4,4), (4,3) are bombs. This pretty much describes the game. To see what you need to write for each method see the comments next to its prototype.

Point Breakdown:

Compiles   		( 1 pt)
Comments   		( 1 pt)
getSize works   	( 1 pt)
getNumBombs works	( 1 pt)
destructor frees array
	correctly       ( 1 pt)
Constructor allocates
 board correctly        ( 1 pt)
Contructor sets up
 values of board pieces
 correctly              ( 1 pt)
move method works       ( 1 pt)
printBoard works        ( 1 pt)
scoreBoard works        ( 1 pt)

Bonus: (1pt) Lookup in a C or C++ book how time is handled. Use the system clock to set a seed value for the random number generation for bomb position, so that games are different each time you run program. (2 pt) Look at how minesweeper flips over squares in the version under Windows. Allow the user to set a option so that if this option is set your move function will implement this kind of flipping.

// 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()

//
// 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 the 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. 
			//Then it does delete [] board.

	MoveResult move(int x, int y); // if x and y is a BOMB 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.			
};


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

Homework 6 FAQ.

Homework 6 Solution.