CS 215 ­ Fundamentals of Programming II Spring 2011 ­ Project 4 30 points Out: February 21, 2011

advertisement
CS 215 ­ Fundamentals of Programming II
Spring 2011 ­ Project 4
30 points
Out: February 21, 2011
Due: March 16, 2011 (Wednesday after spring break)
Reminder: Programming Projects (as opposed to Homework problems) are to be your own work. See syllabus for definitions of acceptable assistance from others.
Reminder 2: THIS MATERIAL WILL BE ON THE MIDTERM EXAM!! START WORKING NOW!!!
Minesweeper is game with a two­dimensional grid playing field. Each grid location (called a cell) may contain a mine. Initially, all cells are covered, hiding any mines from the player. Play is conducted as follows: A cell may be uncovered. If a mine is uncovered, the game is lost. Otherwise, the total number of mines in any adjacent grid cells (all 8 directions) is shown in the cell. Using these numbers, together with skill, judgment, and a little luck, a player should be able to determine the locations of all mines. ● A covered cell may be marked. This is used to indicate a grid cell where the player thinks a mine is. ● A covered cell may be unmarked. This removes a mark from a grid cell. ● The game is won if all grid cells have been either marked or uncovered, and the number of marked grid cells is the same as the number of mines. I.e. the player has identified all the mines without uncovering any of them. ●
A graphical version is available on Ubuntu Linux machines under Applications­>Games­>Mines.
Consider the following specification for a SweeperGrid class that represents the Minesweeper playing field. Each grid cell contains a SweeperCell object, that contains information regarding the state of the cell. (The SweeperCell class is provided and is explained below.) Cell locations are given as coordinates (row, col) where (0,0) is the upper left­hand corner of the grid. Specification for SweeperGrid Class Data Attributes For this project, a SweeperGrid is modeled using a dynamically­allocated two­dimensional array of SweeperCells, as demonstrated in lecture, to allow grids of differing sizes to be created. Thus the data attributes include at least those shown below. You may add additional appropriate attributes.
Objects
Type
Name
number of rows
int
numRows
number of columns
int
numColumns
number of bombs in the grid
int
numBombs
pointer to grid
SweeperCell**
grid
02/20/2011
Page 1 of 11
D. Hwang
Operations ●
Explicit­value constructor ­ receives the number of rows and columns, and a density percentage. Default values are given below. If initialRows or initialCols is less than 5 (to make sure the grid is large enough) or if the density is not between 25 and 75 (to make sure not all cells are empty or all cells contain bombs) the constructor should print out an error message and exit. Otherwise the constructor should dynamically allocate a two­dimensional SweeperCell grid of the specified size as demonstrated in lecture. The constructor places density percentage number of bombs in the grid, and computes the number of adjacent cells containing bombs for each cell. Bombs are to be placed randomly into the grid in the density specified. Density is specified as an integer between 25 and 75 that represents the percentage of cells that will contain bombs. (E.g. 25 means 25%, or one­fourth, of the cells will contain bombs.) The easiest way to do this is to loop through the grid cells, and for each cell use the built­in random number generator to pick a number between 1 and 100. If the number generated is less than the density percentage, then place a bomb in the cell. Note: the random number generator under g++ works as follows. The generator is seeded using srand() (defined in <cstdlib>), which receives a long integer. We want the game to be different each time, so most programmers use the result of the time function (defined in <ctime>) to seed the generator by using: srand(time(0));
This should be done once before the first use of the random number generator. (Note: if you want the same numbers to be generated each time, e.g., when testing, use a constant as the argument to srand(), but your final submission should use time()).
The function rand() returns the next random integer between 0 and RAND_MAX. Scaling this result to numbers between 1 and 100 can be done by the following code fragment: rand() % 100 + 1
Recall that % is the remainder operator in C++. (As shown in the sample run below, the actual density percentage produced by this method can be off by quite a bit, but it should be within 10% or so.) Analysis ●
Objects
Default
Type
Movement
Name
number of rows
5
int
received
initialRows
number of columns
5
int
received
initialCols
density percentage
25
int
received
density
Copy constructor ­ creates a new SweeperGrid that is identical to an existing one. Analysis 02/20/2011
Page 2 of 11
D. Hwang
Objects
Type
Movement
Name
source SweeperGrid object
SweeperGrid
received
source
●
Destructor ­ deallocates the grid Analysis ­ no objects ●
operator= ­ overloaded assignment operator function. Makes an existing SweeperGrid object identical to the source SweeperGrid object. Analysis ●
Objects
Type
Movement
Name
source SweeperGrid object
SweeperGrid
received
source
GetRows ­ returns the number of rows in the grid Analysis ●
Objects
Type
Movement
Name
number of rows
int
returned
numRows
GetColumns ­ returns the number of columns in the grid Analysis
●
Objects
Type
Movement
Name
number of columns
int
returned
numColumns
GetBombs ­ returns the number of bombs in the grid Analysis ●
Objects
Type
Movement
Name
number of bombs
int
returned
numBombs
GameWon ­ returns true if the game has been won Analysis 02/20/2011
Objects
Type
Movement
Name
win result
bool
returned
­­­
Page 3 of 11
D. Hwang
●
PlaceBomb ­ place a bomb in the grid cell at location (row, col). Note this function must recompute the number of adjacent bombs of the cell's neighbors (all 8 directions). If the location (row, col) is not within the bounds of the grid, throws an out_of_range exception. (See notes below.)
Analysis ●
Objects
Type
Movement
Name
row index
int
received
row
column index
int
received
col
RemoveBomb ­ remove a bomb in the grid cell at location (row, col). Note this function must recompute the number of adjacent bombs of the cell's neighbors (all 8 directions). If the location (row, col) is not within the bounds of the grid, throws an out_of_range exception. (See notes below.)
Analysis ●
Objects
Type
Movement
Name
row index
int
received
row
column index
int
received
col
Uncover ­ uncovers the grid cell at location (row, col). Returns true if a bomb is uncovered; false otherwise. If the location (row, col) is not within the bounds of the grid, throws an out_of_range exception. (See notes below.)
Analysis ●
Objects
Type
Movement
Name
row index
int
received
row
column index
int
received
col
bomb check
bool
returned
­­­
Mark ­ marks the grid cell at location (row, col). If the location (row, col) is not within the bounds of the grid, throws an out_of_range exception. (See notes below.)
Analysis ●
Objects
Type
Movement
Name
row index
int
received
row
column index
int
received
col
Unmark ­ unmarks the grid cell at location (row, col). If the location (row, col) is not within the bounds of the grid, throws an out_of_range exception. (See notes below.)
02/20/2011
Page 4 of 11
D. Hwang
Analysis ●
Objects
Type
Movement
Name
row index
int
received
row
column index
int
received
col
Write ­ outputs the SweeperGrid in a two­dimensional grid to an output stream. (SweeperCell implements operator<< that outputs a cell as a single character. See SweeperCell implementation for details.) The columns of the grid should line up as shown in the sample run. (I.e., there should be two spaces in front of every cell and a newline should be after the last cell in each line.) Note this operation is a regular member function and is not operator<<.
Analysis Objects
Type
Movement
Name
output stream
ostream
received & passed back
out
Assignment The SweeperCell class is provided for this assignment. It may be copied from csserver directory /home/hwang/cs215/project4/*.* .
There are two files, sweepercell.h and sweepercell.cpp. You may not modify these files. However, if you feel you need more operations from the SweeperCell class, talk to the instructor. The SweeperCell class defines operations that allow the SweeperCell object to be manipulated and accessed in accordance with the Minesweeper game rules. The files contain comments explaining what each function does. Hopefully, this is sufficient. 1. Write the implementation of the SweeperGrid class specified above. The SweeperGrid class definition should be put in header file sweepergrid.h with suitable compilation guards. The implementations of the SweeperGrid member functions should be put in source file sweepergrid.cpp. The SweeperGrid class must be implemented using a dynamically­allocated two­dimensional array as discussed in lecture. Projects that do not use a dynamically­allocated two­dimensional array will be returned for resubmission with late penalty. The member function names and the order of the parameters must be as specified above. Your code will be linked with a grading driver program that expects this. Note that the main program game may not need to use all of the specified functions. However, all of the functions must be correct to receive full credit. 2. Write a main program sweeper.cpp that implements the Minesweeper game described above using the SweeperGrid class. This game will be text­based and interactive. It should have the following features: ●
It should be able to construct a user­specified size game grid with a user­specified density of bombs by accepting the number of rows, the number of columns, and the density of bombs to be created as command­line arguments. I.e., there will be a total of 4 arguments on the command line. (See example run below.) The program should check that the command­line arguments are valid for constructing a 02/20/2011
Page 5 of 11
D. Hwang
game grid. (I.e., the number of rows and columns is at least 5 and the density is between 25 and 75, inclusive.) If the arguments are not valid, the program should print an appropriate error message and exit.
Reminder: since argv is an array of C­strings, the command­line arguments will need to be converted to integers using the function atoi that is defined in <cstdlib>. (This was used in Homework 1.)
●
After construction, the number of bombs in the grid should be output to the screen. ●
The game must allow the user to repeatedly uncover a cell, mark a cell, or unmark a cell until a bomb is uncovered (and the game is lost), the game is won, or the player wants to quit. This most likely will be a menu­driven loop. ●
The game grid should be output to the screen before every player move. ●
When the game is over (by whatever means), the game grid with all cells uncovered should be output to the screen. ●
In addition, the program must handle the player entering an illegal location (i.e., indexes not in bounds) by handling the out_of_range exceptions thrown by the SweeperGrid functions. Such locations should be ignored by the program and the user asked to input a new location, or a new action choice and new location. (See notes below.)
A sample run of a program meeting these specifications is shown below. You must submit a makefile named Makefile.project4 that creates an executable named sweeper. It should conform to the examples demonstrated in class. REMINDER: Your project must compile for it to be graded. Submissions that do not compile will be returned for resubmission and assessed a late penalty. Submissions that do not substantially work also will be returned for resubmission and assessed a late penalty.
Follow the guidelines in the C++ Programming Style Guideline handout. As stated in the syllabus, part of the grade on a programming project depends on how well you adhere to the guidelines. The grader will look at your code listing and grade it according to the guidelines. Note that all of the external names (class and member function names, file names) must be as specified above, including case. All other identifiers must have consistent case usage, but do not have to match the style of these names.
What to submit Electronically submit a tarfile containing Makefile.project4, sweepergrid.h, sweepergrid.cpp, and sweeper.cpp as explained in the handout Submission Instructions for CS 215. Please do not submit sweepercell.h, sweepercell.cpp, object files, or executable files. The submission system will accept submissions no earlier than Monday, February 28.
Notes about using the out_of_range exception
Exception handling in C++ was covered in lecture on Friday, February 18, and is in Appendix L of the textbook (though there are errors in the syntax shown in the textbook). Here is a recap.
02/20/2011
Page 6 of 11
D. Hwang
Standard exception classes, including out_of_range, are defined in the <stdexcept> library. These classes have an explicit­value constructor that has one received parameter that is a message string. This parameter generally is used to store an error message. There is one operation, what(), that returns the message string.
An exception is thrown when a logic error in usage has occurred, such as trying to access a data structure with invalid indexes, by constructing an exception object and using the throw operator. Throwing an exception causes the function to terminate. For example, in the SweeperGrid functions, the code to prevent out of range access might be:
if ((row < 0 ) || (row >= numRows) || (col < 0) || (col >= numCols))
// construct and throw an exception object, terminates the function
throw out_of_range ("Location out of range.");
// everything is good, perform the operation
You might want to separate the possible errors in order to generate more specific error messages.
In the main program, exceptions are caught and handled using a try­catch construct. The function call that may throw an exception is placed inside the try block, while the exception object is listed like a parameter in the catch block header. The handler code for the exception is placed in the catch block. For example, to catch an out_of_range exception thrown by the Uncover function, the code might be:
try
{
cin >> inputRow >> inputCol;
bool move = grid.Uncover(inputRow, inputCol);
if (move) // bomb found
{
// do something
}
else // no bomb
{
// do something else
}
} // end try
catch (const out_of_range & re) // the thrown exception object
{ // print out its message
cout << re.what() << " Try again!" << endl;
} // end catch
Note that since all of the SweeperGrid functions throw the same exception type, one try­catch block may be used to handle all possible exceptions as long as all function calls are in the same try block.
02/20/2011
Page 7 of 11
D. Hwang
Sample run $ ./sweeper 8 12 25
There are 34 bombs in the grid.
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
Enter u to uncover, m to mark, k to unmark, q to quit: u
Enter a location (row col) to uncover: 0 0
2 # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
Enter u to uncover, m to mark, k to unmark, q to quit: u
Enter a location (row col) to uncover: 0 2
2 # 1 # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
Enter u to uncover, m to mark, k to unmark, q to quit: u
Enter a location (row col) to uncover: 0 3
2 # 1 0 # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
02/20/2011
Page 8 of 11
D. Hwang
Enter u to uncover, m to mark, k to unmark, q to quit: u
Enter a location (row col) to uncover: 1 2
2 # 1 0 # # # # # # # #
# # 1 # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
Enter u to uncover, m to mark, k to unmark, q to quit: u
Enter a location (row col) to uncover: 1 3
2 # 1 0 # # # # # # # #
# # 1 1 # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
Enter u to uncover, m to mark, k to unmark, q to quit: u
Enter a location (row col) to uncover: 8 0
Location out of range. Try again!
2 # 1 0 # # # # # # # #
# # 1 1 # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
Enter u to uncover, m to mark, k to unmark, q to quit: u
Enter a location (row col) to uncover: 0 4
2 # 1 0 1 # # # # # # #
# # 1 1 # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
Enter u to uncover, m to mark, k to unmark, q to quit: u
Enter a location (row col) to uncover: 1 4
02/20/2011
Page 9 of 11
D. Hwang
2 # 1 0 1 # # # # # # #
# # 1 1 2 # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
Enter u to uncover, m to mark, k to unmark, q to quit: u
Enter a location (row col) to uncover: 0 5
2 # 1 0 1 1 # # # # # #
# # 1 1 2 # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
Enter u to uncover, m to mark, k to unmark, q to quit: m
Enter a location (row col) to mark: 1 5
2 # 1 0 1 1 # # # # # #
# # 1 1 2 f # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
Enter u to uncover, m to mark, k to unmark, q to quit: m
Enter a location (row col) to mark: 1 0
2 # 1 0 1 1 # # # # # #
f # 1 1 2 f # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
# # # # # # # # # # # #
Enter u to uncover, m to mark, k to unmark, q to quit: u
Enter a location (row col) to uncover: 1 1
You've uncovered a mine! Game over!!
02/20/2011
Page 10 of 11
D. Hwang
2 2 1 0 1 1 2 2 2 2 * *
* * 1 1 2 * 4 * * 4 3 2
4 4 2 1 * 3 * * * * 3 1
* * 2 3 3 4 3 5 * * * 1
2 3 * 4 * * 2 3 * 5 2 1
1 2 3 * * * 3 3 * 4 1 0
3 * 4 3 4 * 3 3 * * 2 0
* * * 1 1 2 * 2 3 * 2 0
Extra credit There are two additions that may be completed for extra credit. Note that you may want or need to add additional attributes or operations to the SweeperGrid class to support these additions. (But it is still the case that the SweeperCell class should not be modified.) If you do the extra credit, you are expected to submit two versions of the project, one regular project without any extra credit code and one with any extra credit attempts. Thus, you may want to copy the regular project files into another subdirectory before working on the extra credit.
(10 points) Implement the auto­open feature when uncovering a cell with no bombs adjacent to it. When such a cell is uncovered, the program automatically uncovers all adjacent cells, since this is safe to do. This process is repeated on any newly uncovered cell with no bombs adjacent to it. Note this is a recursive process has similarities to Project 1.
● (5 points) Implement the no bomb on first move feature where the first move a player makes will never uncover a bomb. There are a number of different ways to do this. ●
What to submit for the extra credit
Electronically submit a tarfile containing Makefile.project4, sweepergrid.h, sweepergrid.cpp, and sweeper.cpp for the extra credit version as explained in the handout Submission Instructions for CS 215. Please do not submit sweepercell.h, sweepercell.cpp, object files, or executable files. The submission system will only test that the project compiles. It will not do any other testing.
02/20/2011
Page 11 of 11
D. Hwang
Download