- Details
- Parent Category: Programming Assignments' Solutions
We Helped With This C++ Programming Assignment: Have A Similar One?
Short Assignment Requirements
Assignment Description
Mine Sweeper
In this project you will program the game Minesweeper (ref: http://www.wikihow.com/Play-Minesweeper ) in C++ using the curses library. Please read the following instructions carefully.
Program Notes:
1. A partial solution of this assignment is provided to you as a starting point. Once you implement the basic functionality of this assignment, you may add additional features if you want.
2. The maximum dimension of the game grid is defined by the value of MAX_GRID_SIZE. The actual size of the game grid is gridRows by gridCols. Both gridRows and gridCols must be less than or equal to MAX_GRID_SIZE.
3. The current state of the game board is stored in a 2D integer array called playerGrid of size MAX_GRID_SIZE by MAX_GRID_SIZE. This array will store characters as integers. Initially, all the values of the playerGrid will be set to o's. The user will change each 'o' to a space or a 'M' depending on whether marking a clear space or marking a bomb, respectively.
4. The positions of the bombs are stored in a 2D integer array called answerGrid of size MAX_GRID_SIZE by MAX_GRID_SIZE. Bomb locations are stores as x's and non-bomb locations are stored as a period.
5. The player's current location is stored in the variables row and col. The row and col variables are initially set to zero so that the game starts at the (0, 0) location on the grid.
6. The number of remaining bombs is stored in the variable remainingBombs.
Game Play
1. The size of the grid and the number of bombs can be hard coded. Alternatively, you may ask the user to enter the size of the grid and the number of bombs.
2. The bombs should be placed randomly. Make sure to place each bomb in a unique location.
3. The number of bombs should be decremented each time the user marks a bomb location. A user should not be able to mark more bomb locations than there are bombs.
4. Each time the user clears a space that does not contain a bomb, the new grid should display the number adjacent bombs to that space.
5. The game is over and the player loses when the player incorrectly labels a space as clear when it contains a bomb.
6. The player wins the game by correctly labeling each bomb location and clearing all the other spaces.
Step 1: Initialize the playerGrid and answerGrid
In this step you will write the function initGrids that initializes the playerGrid and answerGrid. The prototype for this function is
void initGrids(int answerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int playerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols, int numBombs);
This function should randomly place numBombs bombs in the answerGrid, i.e., this function should set answerGrid values without a bomb to '.' and with a bomb to 'x'. This function should also set all the values of playerGrid to 'o'.
Step 2: Draw the playerGrid to the screen
In this step, you will write the function printGrid to print the playerGrid to the screen. The prototype for this function is
void printGrid(int grid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols, int rowOffset, int colOffset);
Starting at the rowOffset and colOffset location on the screen, this function should print the values stored in playerGrid as characters to the screen as a 2D grid with gridRows number of rows and gridCols number of columns. You can use the command
mvprintw(row,col,"%c",value);
to print an integer stored in the variable value as a character to the screen at location (row, col).
Step 3: Draw the game instructions to the screen
In this step, you will write the function helpMenu to print the game instructions to the screen. The prototype for this function is
void helpMenu(int rowOffset, int colOffset);
The instructions should be printed starting at the screen location (rowOffset, colOffset). The instructions should be the following or something similar:
Help Menu:
Press W or up arrow to move up
Press A or left arrow to move left
Press S or down arrow to move down
Press D or right arrow to move right
Press Q to quit
Press R to restart
Press M to mark a bomb
Press F to check to see if you've won the game
Press spacebar to clear a space
Step 4: Move the cursor around the game grid
In this step, you will write the function moveCursor to move the cursor around the game grid using the keys 'w', 'a', 's', 'd' and the arrow keys. The prototype for this function is
void moveCursor(int moveChar, int &row, int &col, int gridRows, int gridCols);
The input to this function is the current position stored in (row, col) and the output of this function is the new position of the cursor in (row, col). The moveChar is the ascii code of the key that was pressed. The ascii code for the arrow keys are defined by the ncurses library as KEY_UP, KEY_DOWN, KEY_LEFT and KEY_RIGHT. This function must prevent the cursor from moving out of the grid.
After determining the new (row, col) location of the cursor (which could be the same location if the input would require and illegal move), your function should move the cursor and refresh the screen using the commands
move(row,col);
refresh();
Step 5: Count bombs
In this step, you will write the function countBombs which returns the number of bombs adjacent to the location (row, col). The prototype for this function is
int countBombs(int grid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols, int row, int col);
There are nine special cases to consider: the four corners, the four sides and the middle of the grid.
Step 6: Implement logic to show the bombs
In this step, you will write the function markBombs which updates the playerGrid with the locations of the bombs and clears all remaining hidden spaces. The prototype for this function is
void markBombs(int answerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int playerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols);
This function updates the playerGrid by changing all the remaining o's to spaces and sets each place with a bomb to an 'x'.
Step 7: Implement logic for marking a safe space
In this step, you will implement the logic in the loop of the main program when the user marks a safe space by pressing the space bar. If the user presses the space bar and there is a bomb at that location, then the game is over. Otherwise, the playerGrid is updated with number of bombs in the adjacent spaces. If there are no bombs in any adjacent spaces, the playerGrid should be cleared of all adjacent spaces that have no adjacent bombs and continue this until all spaces with no adjacent bombs are cleared. Once this is done, the playerGrid and the cursor should be redrawn.
Since recursive programming is not taught in this class, I have implemented this step for you. The only thing that you need to do for is to read and understand how the function clearGrid works.
Step 8: Implement logic for marking a bomb space
In this step, you will implement the logic in the loop of the main program when the user marks a bomb. If the cursor is at an 'o' in the playerGrid, then the playerGrid at location (row, col) should be updated to display an 'M' and the number of remaining bombs should be reduced by one. If the cursor is at an 'M' in the playerGrid, then the playerGrid at location (row, col) should be updated to display an 'o' and the number of bombs should be increase by one. Your program should not let the user place an 'M' if the number of remaining bombs would become negative. Remember, the number of remaining bombs is the difference between the starting number of bombs and the number of M's in the playerGrid. This number has no relationship to the number of correctly labeled bombs.
You should display the number of remaining bombs on the screen before the game starts and after each press of the 'M' key.
Step 9: Implement logic to check if the game was won
In this step, you will implement the logic in the loop of the main program when the user presses the 'f' key. Pressing the 'f' key should check to see if the user has won or lost the game. The conditions to win the game is there are no spaces marked as 'o' in the playerGrid and each 'M' in the playerGrid corresponds to an 'x' in the answerGrid. Your program should display a message saying that the player won or lost. If the game was lost, your program should call the markBombs function to show the location of the bombs and redraw the grid.
Step 10: Implement logic to reset the game
In this step, you will implement the logic in the loop of the main program when the user presses the 'r' key to reset the game.
Specific Requirements:
1. Your program must be properly documented.
2. You must use descriptive variable names in your program, i.e., lowerLimit instead of r, etc.
Additional documentation on curses can be found at:
http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/
http://pdcurses.sourceforge.net/doc/index.html
Assignment Code
/*******
*
* Programmer: YOUR NAME GOES HERE
* Date: TODAY'S DATE GOES HERE
* Name: Mine Sweeper
* Function: Mine Sweeper game implemented using pdcurses
*
*******/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <curses.h>
const int MAX_GRID_SIZE = 20;
const int NUM_BOMBS = 15;
void printGrid(int grid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols, int rowOffset, int colOffset);
void moveCursor(int moveChar, int &row, int &col, int gridRows, int gridCols);
void clearGrid(int row, int col, int answerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE],
int playerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols);
int countBombs(int grid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols, int row, int col);
void initGrids(int answerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int playerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols, int numBombs);
void markBombs(int answerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int playerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols);
void helpMenu(int rowOffset, int colOffset);
int main(void){
//Set up curses
WINDOW *wnd; // Handle to window
wnd=initscr(); // Initialize widow for ncurses
cbreak(); // cbreak mode disables line buffering and erase/kill character-processing
// making characters typed by the user immediately available to the program
noecho(); // When a key is pressed, do not print that letter to screen
int nrows,ncols; // Hold the number of rows and columns of the window
getmaxyx(wnd,nrows,ncols); // set nrows and ncols to the number of rows and columns of window
keypad(stdscr, true); // Needed for arrow keys to work with KEY_LEFT, KEY_RIGHT, etc
clear(); // Clear screen buffer
refresh(); // Redraw screen, this command draws the cleared screen
//Initialize the answerGrid and playerGrid
int remainingBombs = NUM_BOMBS;
int gridRows = 10;
int gridCols = 10;
int answerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE]; // 2D array that holds the location of the bombs
int playerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE]; // 2D array that holds the user guesses
// Seed the random number generator with current time and throw away first 10 random numbers
srand((int) time(NULL));
for(int i=0; i<10; i++){
rand();
}
initGrids(answerGrid, playerGrid, gridRows, gridCols, remainingBombs);
// Draw help menu and initial player grid
helpMenu(0,gridRows+6);
printGrid(playerGrid, gridRows, gridCols, 0, 0);
mvprintw(gridRows+1, 0, "Bombs remaining: %3d",remainingBombs);
// Set starting row and column location
int row=0;
int col=0;
int inputChar=getch();
while(inputChar != 'q'){
if(inputChar=='w' || inputChar=='a' || inputChar=='s' || inputChar=='d'
|| inputChar==KEY_LEFT || inputChar==KEY_RIGHT || inputChar==KEY_UP || inputChar==KEY_DOWN) {
moveCursor(inputChar, row, col, gridRows, gridCols);
}
else if(inputChar== ' '){
//Check to see if playerGrid is o at row, col
//If it's an o check answerGrid to see if it's a bomb
//If it's a bomb end the game and show answerGrid
//Otherwise count number of bombs and replace in the playerGrid the number of bombs
clearGrid(row, col, answerGrid, playerGrid, gridRows, gridCols);
printGrid(playerGrid, gridRows, gridCols, 0, 0);
move(row,col);
}
//m is for marking a bomb
else if(inputChar== 'm'){
// YOUR CODE GOES HERE
}
//r is for reset
else if(inputChar== 'r'){
// YOUR CODE GOES HERE
}
//f is for finish
else if(inputChar== 'f'){
// YOUR CODE GOES HERE
}
inputChar=getch();
}
endwin();
return 0;
}
void printGrid(int grid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols, int rowOffset, int colOffset){
// YOUR CODE GOES HERE
}
int countBombs(int grid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols, int row, int col){
// YOUR CODE GOES HERE
return 0; // Fix, returning zero is just to get the program to compile before you implement this function
}
void moveCursor(int moveChar, int &row, int &col, int gridRows, int gridCols){
// YOUR CODE GOES HERE
}
void initGrids(int answerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int playerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols, int numBombs){
// YOUR CODE GOES HERE
}
void clearGrid(int row, int col, int answerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE],
int playerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols){
int num;
if(row<0 || row>gridRows-1){
return;
}
if(col<0 || col>gridCols-1){
return;
}
if(playerGrid[row][col] == 'o'){
if(answerGrid[row][col] == '.'){
num=countBombs(answerGrid, gridRows, gridCols, row, col);
if(num == 0){
playerGrid[row][col]=' ';
clearGrid(row-1, col, answerGrid, playerGrid, gridRows, gridCols); //North neighbor
clearGrid(row-1, col+1, answerGrid, playerGrid, gridRows, gridCols); //Northeast neighbor
clearGrid(row, col+1, answerGrid, playerGrid, gridRows, gridCols); //East neighbor
clearGrid(row+1, col+1, answerGrid, playerGrid, gridRows, gridCols); //Southeast neighbor
clearGrid(row+1, col, answerGrid, playerGrid, gridRows, gridCols); //South neighbor
clearGrid(row+1, col-1, answerGrid, playerGrid, gridRows, gridCols); //Southwest neighbor
clearGrid(row, col-1, answerGrid, playerGrid, gridRows, gridCols); //West neighbor
clearGrid(row-1, col-1, answerGrid, playerGrid, gridRows, gridCols); //Northwest neighbor
}
else{
playerGrid[row][col]=num+'0';
}
}
else{
mvprintw(gridRows+1, 0, "BOMB... YOU LOSE! ");
markBombs(answerGrid, playerGrid, gridRows, gridCols);
printGrid(playerGrid, gridRows, gridCols, 0, 0);
}
}
}
void helpMenu(int rowOffset, int colOffset){
// YOUR CODE GOES HERE
}
void markBombs(int answerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int playerGrid[MAX_GRID_SIZE][MAX_GRID_SIZE], int gridRows, int gridCols){
// YOUR CODE GOES HERE
}