I have implemented minesweeper in C++. You can get a box by entering the coordinates -row number, then column; starting from 0- of said box (eg: "0 0"); you can mark a box as a bomb by adding the prefix "mark" (eg: "mark 0 0"); you can unflag a box by adding the prefix "unmark" (eg: "unmark 0 0"). The game ends when all non-bomb boxes have been checked & all bombs have been marked. Any feedback/ideas on how to improve my code would be very much appreciated.
main.cpp
#include "Game.h"
int main()
{
Game* g = new Game(16, 40);
g->playGame();
return 0;
}
Game.h
#ifndef GAME_H
#define GAME_H
#include "Grid.h"
#include <string>
class Game
{
private:
Grid* grid;
int** closedSet;
int len;
int foundNum, closedSetSize;
public:
Game(int n, int b);
~Game();
void printClosedSet();
void playGame();
private:
void clearSpace(int n, int m);
};
#endif // GAME_H
Game.cpp
#include "Game.h"
#include <queue>
#include <cstddef>
#include <iomanip>
#include <cstring>
#include <iostream>
Game::Game(int n, int b) : foundNum(0), closedSetSize(0) {
grid = new Grid(n, b);
len = grid->getSize();
closedSet = new int*[len];
for(int i = 0; i < len; i++) {
closedSet[i] = new int[len];
std::memset(closedSet[i], 0, len * sizeof(int));
}
}
Game::~Game() {
delete grid;
for(int i = 0; i < len; i++)
delete[] closedSet[i];
delete[] closedSet;
}
void Game::printClosedSet() {
std::cout << " ";
for(int i = 0; i < len; i++) {
std::cout << std::setw(3) << i;
}
std::cout << std::endl;
std::cout << " ";
for(int i = 0; i < len; i++) {
std::cout << "---";
}
std::cout << std::endl;
for(int i = 0; i < len; i++) {
std::cout << std::setw(3) << i << "|";
for(int j = 0; j < len; j++) {
if(closedSet[i][j] == 1) {
std::cout << std::setw(3) << grid->getNum(i, j);
} else if(closedSet[i][j] == 0) {
std::cout << std::setw(3) << "-";
} else std::cout << std::setw(3) << "*";
}
std::cout << std::endl;
}
}
void Game::playGame() {
std::string s;
int n, m;
while(true) {
printClosedSet();
std::cin >> s;
if((s.find_first_not_of("0123456789") == std::string::npos) && ((std::stoi(s) <= len-1) && (std::stoi(s) >= 0))) {
n = std::stoi(s);
s = "placeholder";
while(s.find_first_not_of("0123456789") != std::string::npos) {
std::cin >> s;
if((s.find_first_not_of("0123456789") == std::string::npos) &&
((std::stoi(s) > len-1) || (std::stoi(s) < 0))) s = "placeholder";
}
m = std::stoi(s);
if(closedSet[n][m] == 0) {
if(grid->getNum(n, m) < 0) {
grid->printBombs(closedSet);
std::cout << "YOU HAVE LOST" << std::endl;
break;
}
clearSpace(n, m);
}
} else if (s == "mark" || s == "unmark"){
std::string temp = "placeholder";
while(temp.find_first_not_of("0123456789") != std::string::npos) {
std::cin >> temp;
if((temp.find_first_not_of("0123456789") == std::string::npos) &&
(std::stoi(temp) > len-1)) temp = "placeholder";
}
n = std::stoi(temp);
temp = "placeholder";
while(temp.find_first_not_of("0123456789") != std::string::npos) {
std::cin >> temp;
if((temp.find_first_not_of("0123456789") == std::string::npos) &&
(std::stoi(temp) > len-1)) temp = "placeholder";
}
m = std::stoi(temp);
if((s == "mark") && (closedSet[n][m] == 0)) {
closedSet[n][m] = 3;
if(grid->getNum(n, m) < 0) ++foundNum;
} else if((s == "unmark") && (closedSet[n][m] == 3)) {
closedSet[n][m] = 0;
if(grid->getNum(n, m) < 0) --foundNum;
}
} else continue;
if((grid->getBombNum() == foundNum) && (closedSetSize == len*len - grid->getBombNum())) {
printClosedSet();
std::cout << "YOU HAVE WON" << std::endl;
break;
}
}
grid->clearGrid();
grid->generateGrid();
for(int i = 0; i < len; i++)
std::memset(closedSet[i], 0, len * sizeof(int));
foundNum = 0;
closedSetSize = 0;
}
void Game::clearSpace(int n, int m) {
std::queue<std::pair<int, int>> q;
if(closedSet[n][m] == 0) ++closedSetSize;
closedSet[n][m] = 1;
if(grid->getNum(n, m) == 0) q.push(std::make_pair(n, m));
while(!q.empty()) {
n = q.front().first;
m = q.front().second;
closedSet[n][m] = 1;
if((n < len-1) && (closedSet[n+1][m] == 0)) {
if(grid->getNum(n+1, m) == 0)
q.push(std::make_pair(n+1, m));
closedSet[n+1][m] = 1;
++closedSetSize;
}
if((n < len-1) && (m < len-1) && (closedSet[n+1][m+1] == 0)) {
if(grid->getNum(n+1, m+1) == 0)
q.push(std::make_pair(n+1, m+1));
closedSet[n+1][m+1] = 1;
++closedSetSize;
}
if((n < len-1) && (m > 0) && (closedSet[n+1][m-1] == 0)) {
if(grid->getNum(n+1, m-1) == 0)
q.push(std::make_pair(n+1, m-1));
closedSet[n+1][m-1] = 1;
++closedSetSize;
}
if((m < len-1) && (closedSet[n][m+1] == 0)) {
if(grid->getNum(n, m+1) == 0)
q.push(std::make_pair(n, m+1));
closedSet[n][m+1] = 1;
++closedSetSize;
}
if((n > 0) && (closedSet[n-1][m] == 0)) {
if(grid->getNum(n-1, m) == 0)
q.push(std::make_pair(n-1, m));
closedSet[n-1][m] = 1;
++closedSetSize;
}
if((n > 0) && (m < len-1) && (closedSet[n-1][m+1] == 0)) {
if(grid->getNum(n-1, m+1) == 0)
q.push(std::make_pair(n-1, m+1));
closedSet[n-1][m+1] = 1;
++closedSetSize;
}
if((n > 0) && (m > 0) && (closedSet[n-1][m-1] == 0)) {
if(grid->getNum(n-1, m-1) == 0)
q.push(std::make_pair(n-1, m-1));
closedSet[n-1][m-1] = 1;
++closedSetSize;
}
if((m > 0) && (closedSet[n][m-1] == 0)) {
if(grid->getNum(n, m-1) == 0)
q.push(std::make_pair(n, m-1));
closedSet[n][m-1] = 1;
++closedSetSize;
}
q.pop();
}
}
Grid.h
#ifndef GRID_H
#define GRID_H
#include <vector>
class Grid
{
private:
int** grid;
int len;
int bombNum;
std::vector<std::pair<int, int>> s;
public:
Grid(int n, int b);
~Grid();
void printBombs(int** closedSet);
void generateGrid();
void clearGrid();
int getNum(int n, int m) {return grid[n][m];}
int getSize() {return len;}
int getBombNum() {return bombNum;}
};
#endif // GRID_H
Grid.cpp
#include "Grid.h"
#include <iostream>
#include <cstring>
#include <algorithm>
#include <chrono>
#include <random>
#include <iomanip>
Grid::Grid(int n, int b) : len(n), bombNum(b) {
grid = new int*[len];
s.reserve(len);
for(int i = 0; i < len; i++) {
for(int j = 0; j < len; j++)
s.push_back(std::make_pair(i, j));
grid[i] = new int[len];
std::memset(grid[i], 0, len * sizeof(int));
}
generateGrid();
}
Grid::~Grid() {
for(int i = 0; i < len; i++)
delete[] grid[i];
delete[] grid;
}
void Grid::printBombs(int** closedSet) {
std::cout << " ";
for(int i = 0; i < len; i++) {
std::cout << std::setw(3) << i;
}
std::cout << std::endl;
std::cout << " ";
for(int i = 0; i < len; i++) {
std::cout << "---";
}
std::cout << std::endl;
for(int i = 0; i < len; i++) {
std::cout << std::setw(3) << i << "|";
for(int j = 0; j < len; j++) {
if(grid[i][j] < 0) {
std::cout << std::setw(3) << "X";
} else if(closedSet[i][j] == 1) {
std::cout << std::setw(3) << grid[i][j];
} else std::cout << std::setw(3) << "-";
}
std::cout << std::endl;
}
}
void Grid::generateGrid() {
shuffle(s.begin(),
s.end(),
std::default_random_engine(std::chrono::system_clock::now().time_since_epoch().count()));
for(int i = 0; i < bombNum; i++) {
int randRow = s[i].first;
int randCol = s[i].second;
grid[randRow][randCol] = -1;
if(randRow > 0) {
if(grid[randRow-1][randCol] >= 0)
++grid[randRow-1][randCol];
if((randCol > 0) && (grid[randRow-1][randCol-1] >= 0))
++grid[randRow-1][randCol-1];
if((randCol < len-1) && (grid[randRow-1][randCol+1] >= 0))
++grid[randRow-1][randCol+1];
}
if(randRow < len-1) {
if(grid[randRow+1][randCol] >= 0)
++grid[randRow+1][randCol];
if((randCol > 0) && (grid[randRow+1][randCol-1] >= 0))
++grid[randRow+1][randCol-1];
if((randCol < len-1) && (grid[randRow+1][randCol+1] >= 0))
++grid[randRow+1][randCol+1];
}
if((randCol > 0) && (grid[randRow][randCol-1] >= 0))
++grid[randRow][randCol-1];
if((randCol < len-1) && (grid[randRow][randCol+1] >= 0))
++grid[randRow][randCol+1];
}
}
void Grid::clearGrid() {
for(int i = 0; i < len; i++) {
for(int j = 0; j < len; j++)
grid[i][j] = 0;
}
}