I've been working on this game for weeks now. I'm using gcc as my compiler and I am having an issue with two things. I'd love to get some help with this if I could please.
1) I can not play the same difficulty game twice in a row. I suspect that when the first game ends, the dynamic array is not being properly deleted. When the game ends either Win() or Lose() is called, and before those functions kick you back to the main menu they try to delete using two different ways. But I don't think either are working.
2) My Uncover() is not working properly, I want it to recursively check for zones with neighboring mines and ouput those. At the moment it's just looked for neighboring Zones with 0 mines in the surronding 8 squares, and sometimes it does not even do that correctly.
Sorry for the global variables etc, this is my first 8 weeks programming c++!
Thanks,
#include <iostream>
#include <fstream>
#include <iomanip>
#include <ctime>
using namespace std;
struct HighScore
{
string names;
float score;
};
time_t start,end;
char name [256];
char scores [100];
int BOARD_SIZE = 0;
int **minefield_board;
char **state_board;
int num_of_mines_placed = 0;
void DisplayMine(int **minefield_board);
void PlaceMines(int **&minefield_board, int &num_of_mines_placed);
void PlaceMine(int i, int j, int **&minefield_board);
void Counter(int **&minefield_board);
int Counter2(int i, int j ,int **minefield_board);
void InitializeState(char **&state_board);
void DisplayState(char **state_board);
void PlayGame(char **&state_board,int **minefield_board);
void Difficulty(int &BOARD_SIZE);
void DisplaySquareState(int row, int col);
void Uncover(int i, int j, char **&state_board);
void Lose(char **&state_board, int **&minefield_board);
bool CheckWin(char **state_board);
void ShowMenu ();
void DisplayBanner();
void HelpInst();
void MenuMenu();
void Win(char **&state_board, int **&minefield_board);
void ScoreStatSwap();
void ReadStats();
int main ()
{
ShowMenu();
}
void ShowMenu()
{
char choice;
//char N,Q,H,T,D;
char Q;
DisplayBanner ();
while (choice != Q)
{
MenuMenu();
cin >> choice;
switch (choice)
{
case 'Q':
cout << "\n\nThank you for playing. Goodbye.\n\n";
exit(0);
break;
case 'N':
DisplayBanner();
Difficulty(BOARD_SIZE);
PlaceMines(minefield_board, num_of_mines_placed);
InitializeState(state_board);
Counter(minefield_board);
PlayGame(state_board, minefield_board);
break;
case 'T':
cout << "Display top 3 scores\n";
Difficulty(BOARD_SIZE);
ReadStats();
break;
case 'H':
HelpInst();
break;
}
}
}
// Diplays the MineBoard for debug, cheat and endgame.
void DisplayMine(int **minefield_board)
{
cout << " ";
for (int i=1; i <= BOARD_SIZE; i++) cout << setw(3) << i << " ";
cout << endl << endl;
for ( int row= 0; row < BOARD_SIZE; row++ )
{
int f = (row +1);
if (f<=BOARD_SIZE)
{
cout << setw(2) << f << " ";
}
for ( int col = 0; col < BOARD_SIZE; col++ )
{
if (col < BOARD_SIZE)
{
if (minefield_board[row][col]==9)
cout << 'M';
else
cout << minefield_board[row][col];
cout << " | ";
}
}
cout << endl;
}
}
//Calls Placemine, seeds rand then randomdly generates the array index to place
void PlaceMines(int **&minefield_board, int &num_of_mines_placed)
{
minefield_board = new int*[BOARD_SIZE];
for (int i = 0; i < BOARD_SIZE; i++)
{
minefield_board[i]= new int[BOARD_SIZE];
}
int row, col;
srand(time(0));
while(num_of_mines_placed<BOARD_SIZE)
{
row = rand() % BOARD_SIZE;
col = rand() % BOARD_SIZE;
if (minefield_board[row][col]!= 9)
{
PlaceMine(row, col, minefield_board);
++num_of_mines_placed;
}
}
}
// place a mine on the given indexes
void PlaceMine(int i, int j, int **&minefield_board)
{
if(i<0 || i>=BOARD_SIZE || j<0 || j>=BOARD_SIZE)
return; // error, invalid indices
for(int i1=0; i1<BOARD_SIZE; ++i1)
for(int j1=0; j1<BOARD_SIZE; ++j1)
if(abs(i1-i)<=1 && abs(j1-j)<=1)
minefield_board[i][j] = 9;
time (&start);
}
//Calls Counter 2 and sets the number of neighboring mines variable
// and assigns to appropriate int array index
void Counter(int **&minefield_board)
{
for (int i=0; i <BOARD_SIZE; i++)
{
for (int j=0; j<BOARD_SIZE;j ++)
{
if (minefield_board[i][j]!=9)
{
int nm = Counter2(i,j,minefield_board);
minefield_board[i][j] = nm;
}
}
}
}
//Called by Counter, to check the minecount of neighbors
int Counter2(int i, int j ,int **minefield_board)
{
int neighbors = 0;
//check Zone above
if ( i > 0 )
{
if ( minefield_board[ i - 1 ][ j ] ==9)
{
neighbors++;
}
}
//check Zone below
if ( i < BOARD_SIZE - 1)
{
if ( minefield_board[ i + 1 ][ j ] ==9)
{
neighbors++;
}
}
//check Zone to the left
if ( j > 0 )
{
if ( minefield_board[ i ][ j - 1 ] ==9)
{
neighbors++;
}
}
//check Zone to the top left
if ( ( i > 0 ) && ( j > 0 ) )
{
if ( minefield_board[ i - 1 ][ j - 1 ] ==9)
{
neighbors++;
}
}
//check Zone to the bottom left
if ( ( i < BOARD_SIZE - 1 ) && ( j > 0 ) )
{
if ( minefield_board[ i + 1 ][ j - 1 ] ==9)
{
neighbors++;
}
}
//check Zone to the right
if ( j < BOARD_SIZE - 1)
{
if ( minefield_board[ i ][ j + 1 ] ==9)
{
neighbors++;
}
}
//check Zone to the top right
if ( ( i > 0) && ( j < BOARD_SIZE - 1 ) )
{
if ( minefield_board[ i - 1 ][ j + 1 ] ==9)
{
neighbors++;
}
}
//check Zone to the bottom right
if ( ( i < BOARD_SIZE - 1 ) && ( j < BOARD_SIZE - 1 ) )
{
if ( minefield_board[ i + 1 ][ j + 1 ] ==9)
{
neighbors++;
}
}
// cout << neighbors << " ";
return neighbors;
}
//To display the state board after initialization, Cheat and Debug
void DisplayState(char **state_board)
{
for (int i=0; i< BOARD_SIZE; i++)
{
for (int j=0; j<BOARD_SIZE; j++)
cout << state_board[i][j] << " ";
cout << endl;
}
}
// To initialize state board and populate with C's
void InitializeState(char **&state_board)
{
// initialze state_board
state_board = new char*[BOARD_SIZE];
for (int i=0; i<BOARD_SIZE; i++)
state_board[i]= new char[BOARD_SIZE];
//populate the state_board with C's
for (int i=0; i <BOARD_SIZE; i++)
for (int j=0; j<BOARD_SIZE;j ++)
state_board[i][j]='C';
}
void PlayGame(char **&state_board,int **minefield_board)
{
for ( int turns = 0; turns < BOARD_SIZE*BOARD_SIZE+20; turns++ )
{
if (CheckWin(state_board)==true)
Win(state_board, minefield_board);
system("clear");
cout << " ";
for (int i=1; i <= BOARD_SIZE; i++)
cout << setw(3) << i << " ";
cout << endl << endl;
for ( int row= 0; row < BOARD_SIZE; row++ )
{
int f = (row +1);
if (f<=BOARD_SIZE)
{
cout << setw(2) << f << " ";
}
for ( int col = 0; col < BOARD_SIZE; col++ )
{
if (col < BOARD_SIZE)
{
cout << " | ";
}
switch (state_board[row][col])
{
case 'C':
cout << '#';
break;
case 'U':
DisplaySquareState(row, col);
break;
case 'F':
cout << 'F';
break;
case '?':
cout << '?';
break;
default:
cout << '#';
}
}
cout << endl;
}
cout << endl;
cout << "\nEnter the desired row: ";
cout << "\n";
int row,col;
char flag;
cin >> row;
while (row <= 0 || row >= BOARD_SIZE+1)
{
cout << "\nEnter the desired row between 1 and " << BOARD_SIZE << ": ";
cin >> row;
}
row--;
cout << "Enter the desired column: ";
cout << "\n";
cin >> col;
while (col <= 0 || col >= BOARD_SIZE+1)
{
cout << "\nEnter the desired col between 1 and " << BOARD_SIZE << ": ";
cin >> col;
}
col--;
cout << "Enter flag; F to flag, U to uncover, ?, or C: ";
cout << "\n";
cin >> flag;
cout << "\n" << flag <<"\n";
state_board[row][col]=flag;
// UNCOMMENT THE FOLLOWING TO DEBUG
//DisplayState(state_board); //-----------------------------------------------------
//cout << endl;
//DisplayMine(minefield_board);
//cout << endl;
}
}
void Difficulty(int &BOARD_SIZE)
{
while (BOARD_SIZE <= 2 || BOARD_SIZE > 20)
{
cout << "Choose the board size you want to play (must be between 3 and 20: ";
cin >> BOARD_SIZE;
cout << "\n";
}
}
// called by Function Playgame to output the square/slab/zone neighboring mine count
void DisplaySquareState(int row, int col)
{
if (minefield_board[row][col] ==0)
{
cout << '0';
Uncover(row, col, state_board);
}
else if (minefield_board[row][col] ==1)
{
cout << '1';
}
else if (minefield_board[row][col] ==2)
{
cout << '2';
}
else if (minefield_board[row][col] ==3)
{
cout << '3';
}
else if (minefield_board[row][col] ==4)
{
cout << '4';
}
else if (minefield_board[row][col] ==5)
{
cout << '5';
}
else if (minefield_board[row][col] ==6)
{
cout << '6';
}
else if (minefield_board[row][col] ==7)
{
cout << '7';
}
else if (minefield_board[row][col] ==8)
{
cout << '8';
}
else
{
cout << 'M';
Lose(state_board, minefield_board);
}
}
//Uncovers, uncovers if zone is 0 everything around until zones with neighboring mines are found
void Uncover(int i, int j, char **&state_board)
{
//check Zone above
if (i>0 )
{
if ((minefield_board[i-1 ][j]==0) && (state_board[i-1][j]=='C'))
{
state_board[i-1][j]='U';
}
}
//check Zone below
if (i<BOARD_SIZE- 1)
{
if ((minefield_board[i+1][j]==0) && (state_board[i+1][j]=='C'))
{
state_board[i+1][j] ='U';
}
}
//check Zone to the left
if (j>0)
{
if ((minefield_board[i][j-1]==0) && (state_board[i][j-1]== 'C'))
{
state_board[i][j-1]='U';
}
}
//check Zone to the top left
if (( i>0) && (j>0))
{
if ((minefield_board[i-1][j-1] ==0) && (state_board[i-1][j-1]=='C'))
{
state_board[i-1][j-1]='U';
}
}
//check Zone to the bottom left
if ((i<BOARD_SIZE-1) && (j>0))
{
if ((minefield_board[i+1][j-1]==0) && (state_board[i+1][j-1] =='C'))
{
state_board[i+1][j-1] ='U';
}
}
//check Zone to the right
if (j<BOARD_SIZE-1)
{
if ((minefield_board[i][j+1]==0) && (state_board[i][j+1]=='C'))
{
state_board[i][j+1 ] ='U';
}
}
//check Zone to the top right
if ((i>0) && (j<BOARD_SIZE-1))
{
if ((minefield_board[i-1][j+1]==0) && (state_board[i-1][j+1]=='C'))
{
state_board[i-1][j+1]='U';
}
}
//check Zone to the bottom right
if ((i<BOARD_SIZE-1)&&(j<BOARD_SIZE-1))
{
if ((minefield_board[i+1][j+1]==0)&&(state_board[i+1][j+1]=='C'))
{
state_board[i-1][j+1]='U';
}
}
}
void Lose(char **&state_board, int **&minefield_board)
{
cout << "\n";
DisplayBanner ();
cout << endl << endl;
DisplayMine(minefield_board);
cout << endl << endl;
char foo;
cout << "You have lost, your time is not available. Press 'X' key then enter to return to the main menu\n";
cin >> foo;
BOARD_SIZE =0;
// There is a problem here, can't play more then one game per game initiation, how to delete correctly.
//for(int i=0; i<BOARD_SIZE; i++)
//{
//delete [] minefield_board[i];
//delete [] state_board[i];
//}
//delete [] minefield_board;
//delete [] state_board;
delete [] *minefield_board;
delete [] minefield_board;
delete [] *state_board;
delete [] state_board;
// minefield_board = NULL;
// state_board = NULL;
ShowMenu();
}
//If player wins, delete DAM and redirect to Stats
void Win(char **&state_board, int **&minefield_board)
{
DisplayBanner ();
cout << endl << endl;
DisplayMine(minefield_board);
cout << endl << endl;
cout << "You have won. The following screen will ask your name\n";
cout << "and compare you against the top 3 players\n";
char foo;
cin >> foo;
BOARD_SIZE =0;
for(int i=0; i<BOARD_SIZE; i++)
{
delete [] minefield_board[i];
delete [] state_board[i];
}
delete [] minefield_board;
delete [] state_board;
ScoreStatSwap();
}
//Check is player has won everyturn, return true if so, false if not.
//Stop the timer if player wins
bool CheckWin(char **state_board)
{
int uncovered = 0;
int to_win = ( BOARD_SIZE * BOARD_SIZE ) - num_of_mines_placed;
for( int i = 0; i < BOARD_SIZE; i++ )
{
for( int j = 0; j < BOARD_SIZE; j++ )
{
if(state_board[i][j] =='U')
{
uncovered++;
}
else
{
}
}
}
if( uncovered == to_win )
{
time (&end); // end time at the instant we know there is a win
return true;
}
else
{
return false;
}
}
// To display the banner
void DisplayBanner ()
{
system("clear");
cout << " ___ ________ _ _ _____ _____ _ _ _____ ___________ ___________ \n";
cout << " | \\/ |_ _| \\ | || ___/ ___|| | | | ___| ___| ___ \\ ___| ___ \\ \n";
cout << " | . . | | | | \\| || |__ \\ `--. | | | | |__ | |__ | |_/ / |__ | |_/ /\n";
cout << " | |\\/| | | | | . ` || __| `--. \\| |/\\| | __|| __|| __/| __|| / \n";
cout << " | | | |_| |_| |\\ || |___/\\__/ /\\ /\\ / |___| |___| | | |___| |\\ \\ \n";
cout << " \\_| |_/\\___/\\_| \\_/\\____/\\____/ \\/ \\/\\____/\\____/\\_| \\____/\\_| \\_|\n";
}
//Instructions on how to play
void HelpInst()
{
DisplayBanner();
cout << "\nYou have chosen the help menu. \n";
cout << "The purpose of the game is to open all the cells of the board which do not contain a bomb.\n";
cout << "You lose if you set off a bomb cell. \n";
cout << "You must choose a difficulty level, which is a board size of 5 - 20";
cout << "Every non-bomb cell you open will tell you the total number of bombs in the neighboring cells. \n";
cout << "Once you are sure that a cell contains a bomb, flag the square as reminder.\n";
cout << "Once you have flagged all the bombs around an open cell, you can quickly open the remaining non-bomb \n";
cout << "cells. YOU MUST FLAG ALL BOMBS and UNCOVER ALL OTHER ZONES before you can win. \n";
}
//Display Menu Options
void MenuMenu()
{
cout << " \n \n \n \n";
cout << " Enter Q (quit) " << endl;
cout << " Enter N (New Game-Difficulty) " << endl;
cout << " Enter T (Display top 3 scores) " << endl;
cout << " Enter H (Help) " << endl;
}
//If Player Wins they are kicked to this fucntion
//Here there name is taken and compared against the top three players.
//If no one has played before, file is generated with default values
//Highest scores are kept, while everything past 3rd place is kicked.
void ScoreStatSwap()
{
system("clear");
DisplayBanner ();
HighScore first, second, third, current, temp;
sprintf (scores,"scores%d.dat", BOARD_SIZE);
ofstream os;
ifstream is;
is.open(scores);
if (is.fail())
{
is.close();
os.open(scores);
os << "default_1 7000\n" << "default_2 8000\n" << "default_3 9000\n";
os.close();
}
is.close();
cout << "Enter your name, no whitespace and less then 15 characters please: ";
cin >> current.names;
current.score = difftime (end,start);
ifstream in;
in.open(scores );
if ( in.fail() )
{
cout << "File is in use or does not exist\n";
exit (-1);
}
char junk[8];
in.getline (name,128,' ');
first.names = name;
in.clear ();
in >> first.score;
in.getline(junk,8,'\n');
in.getline (name,128,' ');
second.names = name;
in.clear ();
in >> second.score;
in.getline(junk,8,'\n');
in.getline (name,128,' ');
third.names = name;
in.clear ();
in >> third.score;
in.getline(junk,8,'\n');
in.close();
cout << endl << endl;
cout << "This is the previous top 3 names and respective scores for this size of board.\n";
cout << first.names << " " << first.score <<endl;
cout << second.names << " " << second.score <<endl;
cout << third.names << " " << third.score <<endl;
// swap, we do not need a sophisticated sort since it's already in order.
if (current.score < third.score)
{
temp.names = third.names;
temp.score = third.score;
third.names = current.names;
third.score = current.score;
current.names = temp.names;
current.score = temp.score;
}
if (third.score < second.score)
{
temp.names = second.names;
temp.score = second.score;
second.names = third.names;
second.score = third.score;
third.names = temp.names;
third.score = temp.score;
}
if (second.score < first.score)
{
temp.names = first.names;
temp.score = first.score;
first.names = second.names;
first.score = second.score;
second.names = temp.names;
second.score = temp.score;
}
cout << endl << endl;
cout << "This is the current top 3 names and respective scores for this size of board.\n";
cout << first.names << " " << first.score <<endl;
cout << second.names << " " << second.score <<endl;
cout << third.names << " " << third.score <<endl;
cout << endl << endl;
os.open(scores);
if ( os.fail() )
{
cout << "Could not open file" << endl;
}
os << first.names << " " << first.score <<endl;
os << second.names << " " << second.score <<endl;
os << third.names << " " << third.score <<endl;
os.close();
cout << "Press Any Key and then the Enter button to continue.\n";
char blah;
cin >> blah;
ShowMenu();
}
// Stats read in right from the Menu, duplicate code can be Decomposed later
void ReadStats()
{
system("clear");
DisplayBanner ();
HighScore first, second, third, current, temp;
sprintf (scores,"scores%d.dat", BOARD_SIZE);
ofstream os;
ifstream is;
is.open(scores);
if (is.fail())
{
cout << "\n\n\n File does not exist for this difficulty level, creating it.\n";
is.close();
os.open(scores);
os << "default_1 7000\n" << "default_2 8000\n" << "default_3 9000\n";
os.close();
}
is.close();
ifstream in;
in.open(scores );
if ( in.fail() )
{
cout << "File is in use or does not exist\n";
exit (-1);
}
char junk[8];
in.getline (name,128,' ');
first.names = name;
in.clear ();
in >> first.score;
in.getline(junk,8,'\n');
in.getline (name,128,' ');
second.names = name;
in.clear ();
in >> second.score;
in.getline(junk,8,'\n');
in.getline (name,128,' ');
third.names = name;
in.clear ();
in >> third.score;
in.getline(junk,8,'\n');
in.close();
cout << endl << endl;
cout << "This is the current top 3 names and respective scores for this size of board.\n";
cout << first.names << " " << first.score <<endl;
cout << second.names << " " << second.score <<endl;
cout << third.names << " " << third.score <<endl;
cout << endl << endl;
cout << "Press Any Key and then the Enter Key to continue.\n";
BOARD_SIZE = 0;
char blah;
cin >> blah;
ShowMenu();
}

New Topic/Question
Reply




MultiQuote





|