Last active
August 23, 2017 12:11
-
-
Save Leask/c11ee24147496504fc6475020bfc0823 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <cstdlib> | |
#include <unistd.h> | |
#include <vector> | |
#include <set> | |
#include <sstream> | |
using namespace std; | |
struct Node { | |
int x; | |
int y; | |
bool isBomb; | |
bool marked; | |
bool revealed; | |
}; | |
struct Game { | |
int width; | |
int height; | |
int bombCount; | |
vector< vector< Node > > nodes; | |
}; | |
Game *game; | |
string toString(const int value) { | |
std::ostringstream oss; | |
oss << value; | |
return oss.str(); | |
} | |
int fromString(const string* str) { | |
istringstream ss(*str); | |
int i; | |
ss >> i; | |
return i; | |
} | |
void clearScreen() { | |
cout << "\x1B[2J\x1B[H"; | |
} | |
int aroundBombs(Node* node) { | |
int x = node->x; | |
int y = node->y; | |
bool isTop = y == 0; | |
bool isBottom = y == game->height - 1; | |
bool isLeft = x == 0; | |
bool isRight = x == game->width - 1; | |
int count = 0; | |
if (!isTop) { | |
count += game->nodes[y - 1][x].isBomb ? 1 : 0; | |
if (!isLeft) { | |
count += game->nodes[y - 1][x - 1].isBomb ? 1 : 0; | |
} | |
if (!isRight) { | |
count += game->nodes[y - 1][x + 1].isBomb ? 1 : 0; | |
} | |
} | |
if (!isBottom) { | |
count += game->nodes[y + 1][x].isBomb ? 1 : 0; | |
if (!isLeft) { | |
count += game->nodes[y + 1][x - 1].isBomb ? 1 : 0; | |
} | |
if (!isRight) { | |
count += game->nodes[y + 1][x + 1].isBomb ? 1 : 0; | |
} | |
} | |
if (!isLeft) { | |
count += game->nodes[y][x - 1].isBomb ? 1 : 0; | |
} | |
if (!isRight) { | |
count += game->nodes[y][x + 1].isBomb ? 1 : 0; | |
} | |
return count; | |
} | |
int remainBombs() { | |
int count = game->bombCount; | |
for (int i = 0; i < game->nodes.size(); i++) { | |
for (int j = 0; j < game->nodes[i].size(); j++) { | |
if (game->nodes[i][j].marked) { | |
count --; | |
} | |
} | |
} | |
if (count < 0) count = 0; | |
return count; | |
} | |
void render() { | |
clearScreen(); | |
cout << "\nWelcome to Mattsweeper!\n"; | |
cout << "\nYou have " << remainBombs() << " bombs still to find\n\n"; | |
// Header row numbers | |
cout << " "; | |
for (int i = 0; i < game->width; i++) { | |
cout << " " << i; | |
} | |
// Header row dashs | |
cout << endl << " "; | |
for (int i = 0; i < game->width; i++) { | |
cout << " " << '-'; | |
} | |
for (int row = 0; row < game->height; row++) { | |
cout << endl << row << " "; | |
for (int i = 0; i <= game->width; i++) { | |
cout << "| "; | |
if (i == game->width) { | |
continue; | |
} | |
Node node = game->nodes[row][i]; | |
if (node.marked) { | |
cout << 'M'; | |
} else if (node.revealed && node.isBomb) { | |
cout << 'X'; | |
} else if (node.revealed) { | |
int count = aroundBombs(&node); | |
cout << count; | |
} else { | |
cout << ' '; | |
} | |
cout << ' '; | |
} | |
cout << endl << " "; | |
for (int i = 0; i < game->width; i++) { | |
cout << " " << '-'; | |
} | |
} | |
cout << endl; | |
} | |
void func1(Node node) { | |
node.x = 1; | |
} | |
void func2(Node *node) { | |
node->x = 2; | |
} | |
void initNodes() { | |
int width = game->width; | |
int height = game->height; | |
set<string> randoms; | |
while (randoms.size() < game->bombCount) { | |
ostringstream s; | |
s << rand() % width; | |
s << "," << rand() % height; | |
string point = s.str(); | |
randoms.insert(point); | |
} | |
// Init two dimen vector | |
vector<vector <Node> > ivec(height, vector<Node>(width)); | |
for (int row = 0; row < height; row++) { | |
int random = rand() % width; | |
for (int column = 0; column < width; column++) { | |
Node node; | |
node.x = column; | |
node.y = row; | |
node.revealed = false; | |
node.marked = false; | |
ostringstream s; | |
s << column; | |
s << "," << row; | |
string point = s.str(); | |
if (randoms.find(point) != randoms.end()) { | |
node.isBomb = true; | |
} else { | |
node.isBomb = false; | |
} | |
ivec[row][column] = node; | |
} | |
} | |
game->nodes = ivec; | |
} | |
template<typename Out> | |
void split(const string &s, char delim, Out result) { | |
stringstream ss; | |
ss.str(s); | |
string item; | |
while (getline(ss, item, delim)) { | |
*(result++) = item; | |
} | |
} | |
vector<string> split(const std::string &s, char delim) { | |
std::vector<std::string> elems; | |
split(s, delim, std::back_inserter(elems)); | |
return elems; | |
} | |
bool isWon() { | |
int nodeCount = game->width * game->height; | |
int revealedCount = 0; | |
int markedCount = 0; | |
int markedBoomCount = 0; | |
for (int i = 0; i < game->nodes.size(); i++) { | |
for (int j = 0; j < game->nodes[i].size(); j++) { | |
Node *node = &game->nodes[i][j]; | |
if (node->revealed) { | |
revealedCount++; | |
} | |
if (node->marked) { | |
markedCount++; | |
} | |
if (node->marked && node->isBomb) { | |
markedBoomCount++; | |
} | |
} | |
} | |
if (markedBoomCount == markedCount && markedCount == game->bombCount) { | |
return true; | |
} | |
if (markedCount == markedBoomCount && revealedCount + game->bombCount == nodeCount) { | |
return true; | |
} | |
return false; | |
} | |
void revealAll() { | |
for (int i = 0; i < game->nodes.size(); i++) { | |
for (int j = 0; j < game->nodes[i].size(); j++) { | |
Node *node = &game->nodes[i][j]; | |
node->revealed = true; | |
} | |
} | |
} | |
int main() { | |
game = new Game(); | |
game->width = 5; | |
game->height = 10; | |
game->bombCount = 10; | |
initNodes(); | |
render(); | |
while (true) { | |
cout << "Select a point, X,Y: "; | |
string input = ""; | |
getline(cin, input); | |
vector<string> eles = split(input, ','); | |
if (eles.size() != 2) { | |
cout << "Invalid point: " << input << endl; | |
getline(cin, input); | |
continue; | |
} | |
render(); | |
int x = fromString(&eles[0]); | |
int y = fromString(&eles[1]); | |
if (x >= game->width || x < 0) { | |
cout << "X is out of bound, Press enter to retry"; | |
getline(cin, input); | |
continue; | |
} | |
if (y >= game->height || y < 0) { | |
cout << "Y is out of bound, Press enter to retry"; | |
getline(cin, input); | |
continue; | |
} | |
bool valid = false; | |
do { | |
cout << "What would you like to do? (r)eveal, (m)ark: "; | |
getline(cin, input); | |
valid = input == "r" || input == "m"; | |
if (!valid) { | |
cout << "Invalid action!" << endl; | |
} | |
} while (!valid); | |
Node *node = &game->nodes[y][x]; | |
if (input == "r") { | |
node->revealed = true; | |
} else { | |
node->marked = true; | |
} | |
if (node->isBomb && input == "r") { | |
revealAll(); | |
render(); | |
cout << "BOOM! You Lose\n"; | |
exit(1); | |
} | |
if (isWon()) { | |
revealAll(); | |
cout << "Congratulation! You WON!\n"; | |
exit(0); | |
} | |
render(); | |
} | |
// for (int i = 0; i < game->nodes.size(); i++) { | |
// for (int j = 0; j < game->nodes[i].size(); j++) { | |
// Node node = game->nodes[i][j]; | |
// cout << node.x << ',' << node.y << "," << (node.isBomb ? 'X' : ' ') << '\t'; | |
// } | |
// cout << endl; | |
// } | |
// cout << aroundBombs(&game->nodes[1][2]); | |
delete game; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment