Skip to content

Instantly share code, notes, and snippets.

@dgodfrey206
Last active April 15, 2022 16:18
Show Gist options
  • Save dgodfrey206/7b770e96f521e117098f3c725def6cff to your computer and use it in GitHub Desktop.
Save dgodfrey206/7b770e96f521e117098f3c725def6cff to your computer and use it in GitHub Desktop.
C++14 Minesweeper Console Game
#include <iostream>
#include <unordered_set>
#include <ctime>
#include <vector>
constexpr int n = 10;
int dx[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
int dy[8] = {1, 1, 1, 0, 0, -1, -1, -1};
bool gameOver = false;
void printBoard(char(&board)[n][n], int mines) {
std::cout << "Mines: " << mines << '\n';
for (int i = 0; i < n; i++) {
std::cout << "|";
for (int j = 0; j < n; j++) {
std::cout << " ";
if (gameOver && board[i][j] == '*') {
std::cout << '*';
} else {
std::cout << (board[i][j] == '*' ? '#' : board[i][j]);
}
std::cout << " |";
}
std::cout << '\n';
}
}
std::string trim_all(std::string const& str, std::string nope) {
std::unordered_set<char> us(nope.begin(), nope.end());
std::string temp;
for (int i = 0; i < str.size(); i++) {
if (us.find(str[i]) == us.end())
temp += str[i];
}
return temp;
}
bool valid_neighbor(int i, int j) {
return 0 <= i && i < n && 0 <= j && j < n;
}
auto& input(int& y, int& x) {
std::cout << "Enter a square (i, j) or q to quit: ";
std::string line;
if (!std::getline(std::cin >> std::ws, line)) {
std::cout << "Invalid input. Exiting program.\n";
std::cin.setstate(std::ios_base::failbit);
return std::cin;
}
line = trim_all(line, " -()");
if (line == "q") {
gameOver = true;
return std::cin;
}
if (line.find_first_of(",") == std::string::npos) {
std::cout << "Invalid input. Exiting program.\n";
std::cin.setstate(std::ios_base::failbit);
return std::cin;
}
std::size_t pos = line.find_first_of(",");
y = std::stoi(line.substr(0, pos));
x = std::stoi(line.substr(pos + 1));
if (!(0 <= y && y < n && 0 <= x && x < n)) {
std::cout << "Out of range. Exiting program.\n";
std::cin.setstate(std::ios_base::failbit);
}
return std::cin;
}
char dfs(char(&board)[n][n], bool(&visited)[n][n], int y, int x) {
// Invariant: board[y][x] != '*' and y,x in [0,n-1]
visited[y][x] = true;
int count = 0;
std::vector<std::pair<int, int>> neighbors;
for (int i = 0; i < 8; i++) {
if (!valid_neighbor(y + dy[i], x + dx[i]) || visited[y + dy[i]][x + dx[i]])
continue;
if (board[y + dy[i]][x + dx[i]] == '*')
count++;
else
neighbors.push_back({y + dy[i], x + dx[i]});
}
if (count == 0) {
for (auto p : neighbors) {
board[p.first][p.second] = dfs(board, visited, p.first, p.second);
}
return '-';
}
return count + '0';
}
char dfs(char(&board)[n][n], int y, int x) {
bool visited[n][n] = {};
return dfs(board, visited, y, x);
}
int main() {
std::srand(std::time(0));
char board[n][n] = {};
int mines = 10;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
board[i][j] = '#';
}
}
for (int i = 0; i < mines;) {
int y = rand() % n, x = rand() % n;
if (board[y][x] != '*') {
board[y][x] = '*';
i++;
}
}
printBoard(board, mines);
int selections = 0;
int y, x;
while (input(y, x)) {
if (gameOver) {
printBoard(board, mines);
break;
}
int idx = y * n + x;
if (board[y][x] == '*') {
gameOver = true;
} else {
board[y][x] = dfs(board, y, x);
}
printBoard(board, mines);
selections++;
if (selections == n*n - mines || gameOver) {
if (selections == n - mines)
std::cout << "You win.\n";
else
std::cout << "You lose.\n";
break;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment