Skip to content

Instantly share code, notes, and snippets.

@omaraflak
Last active September 11, 2017 18:45
Show Gist options
  • Save omaraflak/6cd10584a641be4826fd478d18f3932e to your computer and use it in GitHub Desktop.
Save omaraflak/6cd10584a641be4826fd478d18f3932e to your computer and use it in GitHub Desktop.
Minesweeper in C for Unix systems
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <time.h>
#include <stdbool.h>
const char BOMB = 'X';
const char EMPTY = 'E';
const char DISCOVERED = '0';
const char FLAG = 'F';
const char HIDDEN = '.';
typedef struct Cursor{
int x;
int y;
} Cursor;
typedef struct Game{
char **board;
char **displayedBoard;
int width;
int height;
int bombs;
} Game;
bool allocateMemory(Game *game)
{
int i;
if ((game->displayedBoard = malloc(game->width * sizeof(char*))) != NULL){
for(i=0 ; i<game->width ; i++){
if ((game->displayedBoard[i] = malloc(game->height * sizeof(char))) == NULL){
return false;
}
}
}
if ((game->board = malloc(game->width * sizeof(char*))) != NULL){
for(i=0 ; i<game->width ; i++){
if ((game->board[i] = malloc(game->height * sizeof(char))) == NULL){
return false;
}
}
}
return true;
}
void freeMemory(Game game)
{
int i;
for(i=0 ; i<game.width ; i++)
{
free(game.board[i]);
free(game.displayedBoard[i]);
}
free(game.board);
free(game.displayedBoard);
}
void generateRandomCoordinates(Game game, int *x, int *y)
{
*x = rand()%game.width;
*y = rand()%game.height;
}
void generateBoardData(Game *game)
{
int i,j,x,y;
// generate bombs
for(i=0 ; i<game->bombs ; i++){
generateRandomCoordinates(*game, &x, &y);
game->board[x][y] = BOMB;
}
// set numbers
int counter;
for(i=0 ; i<game->width ; i++){
for(j=0 ; j<game->height ; j++){
counter=0;
if(game->board[i][j]!=BOMB){
for(x=-1 ; x<2 ; x++){
for(y=-1 ; y<2 ; y++){
if(x!=0 || y!=0){
if(i+x>=0 && i+x<game->width && j+y>=0 && j+y<game->height){
if(game->board[i+x][j+y]==BOMB){
counter++;
}
}
}
}
}
if(counter!=0){
game->board[i][j]=counter+48;
}
else{
game->board[i][j]=EMPTY;
}
}
game->displayedBoard[i][j] = HIDDEN;
}
}
}
void discoverSurroundingBoxes(Game *game, int x, int y)
{
game->board[x][y]=DISCOVERED;
game->displayedBoard[x][y]=DISCOVERED;
int width = game->width;
int height = game->height;
int i;
// search left
if(x>0)
{
for(i=x-1 ; i>=0 ; i--)
{
if(game->board[i][y]==EMPTY && game->board[i][y]!=BOMB && game->board[i][y]!=FLAG){
discoverSurroundingBoxes(game, i, y);
}
else if(game->board[i][y]!=BOMB && game->board[i][y]!=DISCOVERED && game->board[i][y]!=EMPTY && game->board[i][y]!=FLAG && game->board[i+1][y]==DISCOVERED){
game->displayedBoard[i][y] = game->board[i][y];
}
else{
break;
}
}
}
// search right
if(x<width-1)
{
for(i=x+1 ; i<width ; i++)
{
if(game->board[i][y]==EMPTY && game->board[i][y]!=BOMB && game->board[i][y]!=FLAG){
discoverSurroundingBoxes(game, i, y);
}
else if(game->board[i][y]!=BOMB && game->board[i][y]!=DISCOVERED && game->board[i][y]!=EMPTY && game->board[i][y]!=FLAG && game->board[i-1][y]==DISCOVERED){
game->displayedBoard[i][y] = game->board[i][y];
}
else{
break;
}
}
}
// search top
if(y>0)
{
for(i=y-1 ; i>=0 ; i--)
{
if(game->board[x][i]==EMPTY && game->board[x][i]!=BOMB && game->board[x][i]!=FLAG){
discoverSurroundingBoxes(game, x, i);
}
else if(game->board[x][i]!=BOMB && game->board[x][i]!=DISCOVERED && game->board[x][i]!=EMPTY && game->board[x][i]!=FLAG && game->board[x][i+1]==DISCOVERED){
game->displayedBoard[x][i] = game->board[x][i];
}
else{
break;
}
}
}
// search bottom
if(y<height-1)
{
for(i=y+1 ; i<height ; i++)
{
if(game->board[x][i]==EMPTY && game->board[x][i]!=BOMB && game->board[x][i]!=FLAG){
discoverSurroundingBoxes(game, x, i);
}
else if(game->board[x][i]!=BOMB && game->displayedBoard[x][i]!=DISCOVERED && game->board[x][i]!=EMPTY && game->board[x][i]!=FLAG && game->board[x][i-1]==DISCOVERED){
game->displayedBoard[x][i] = game->board[x][i];
}
else{
break;
}
}
}
}
void printBoard(Game game, Cursor cursor)
{
int i,j;
for(i=0 ; i<game.height ; i++){
for(j=0 ; j<game.width ; j++){
printf("%c ", game.displayedBoard[j][i]);
}
printf("\n");
if(i==cursor.y){
for(j=0 ; j<game.width ; j++){
if(j==cursor.x){
printf("-");
break;
}
else
printf(" ");
}
printf("\n");
}
}
}
void refreshScreen(Game game, Cursor cursor)
{
system("clear");
printBoard(game, cursor);
}
int getDiscoveredBoxes(struct Game game)
{
int i, j, discoveredBoxes=0;
for(i=0 ; i<game.width ; i++)
{
for(j=0 ; j<game.height ; j++)
{
if(game.displayedBoard[i][j]==DISCOVERED || (game.displayedBoard[i][j]!=HIDDEN && game.displayedBoard[i][j]!=FLAG)){
discoveredBoxes++;
}
}
}
return discoveredBoxes;
}
bool hasWinned(Game game)
{
return getDiscoveredBoxes(game)==game.width*game.height-game.bombs;
}
bool saveGame(const char* filename, Game game)
{
int i,j;
FILE *file = fopen(filename, "w+");
if(file==NULL){
return false;
}
fprintf(file, "%d\n%d\n%d\n", game.width, game.height, game.bombs);
for(i=0 ; i<game.width ; i++){
for(j=0 ; j<game.height ; j++){
fprintf(file, "%d\n", game.board[i][j]);
fprintf(file, "%d\n", game.displayedBoard[i][j]);
}
}
fclose(file);
return true;
}
bool loadGame(const char* filename, Game *game)
{
int i,j,x;
FILE *file = fopen(filename, "r");
if(file==NULL){
return false;
}
fscanf(file, "%d", &(game->width));
fscanf(file, "%d", &(game->height));
fscanf(file, "%d", &(game->bombs));
if(!allocateMemory(game)){
return false;
}
for(i=0 ; i<game->width ; i++){
for(j=0 ; j<game->height ; j++){
fscanf(file, "%d", &x);
game->board[i][j] = x;
fscanf(file, "%d", &x);
game->displayedBoard[i][j] = x;
}
}
fclose(file);
return true;
}
int main()
{
srand(time(NULL));
Game game;
Cursor cursor;
bool gameFinished=false;
int code=0, choice=0;
char c;
cursor.x=0;
cursor.y=0;
/***************
GAME MENU
***************/
printf("###################################################\n");
printf("################ Minesweeper ####################\n");
printf("###################################################\n");
printf("###### 1 - Easy 8x8 10 bombs ##########\n");
printf("###### 2 - Medium 15x15 45 bombs ##########\n");
printf("###### 3 - Hard 20x20 80 bombs ##########\n");
printf("###### 4 - Custom game ##########\n");
printf("###### 5 - Resume Saved Game ##########\n");
printf("###################################################\n");
printf("###################################################\n\n");
printf("Choose: ");
scanf("%d", &choice);
if(choice==5){
if(loadGame("game", &game)){
refreshScreen(game, cursor);
}
else{
gameFinished=true;
code=1;
}
}
else {
if(choice==4){
bool isOk = false;
while(!isOk){
printf("Board width : ");
scanf("%d", &(game.width));
printf("Board height : ");
scanf("%d", &(game.height));
printf("Bombs : ");
scanf("%d", &(game.bombs));
if(game.width>0 && game.width<=100 && game.height>0 && game.height<=100 && game.bombs<game.width*game.height){
isOk=true;
}
else{
printf("\n/!\\ Width and Height must be smaller or equal to 100.\nThe number of bombs must be smaller than the total amount of rows.\n\n");
}
}
}
else if(choice==3){
game.width=20;
game.height=20;
game.bombs=80;
}
else if(choice==2){
game.width=15;
game.height=15;
game.bombs=45;
}
else{
game.width=8;
game.height=8;
game.bombs=10;
}
if(allocateMemory(&game)){
generateBoardData(&game);
refreshScreen(game, cursor);
}
else{
gameFinished=true;
code=1;
}
}
/***************
GAME LOOP
***************/
struct termios termios;
tcgetattr(0, &termios);
termios.c_lflag &= (~ICANON & ~ECHO);
tcsetattr(0, TCSANOW, &termios);
while (!gameFinished)
{
c = getchar();
if(c==68){ // left
cursor.x=cursor.x==0?0:cursor.x-1;
}
else if(c==65){ // up
cursor.y=cursor.y==0?0:cursor.y-1;
}
else if(c==67){ // right
cursor.x=cursor.x==game.width-1?cursor.x:cursor.x+1;
}
else if(c==66){ // down
cursor.y=cursor.y==game.height-1?cursor.y:cursor.y+1;
}
else if(c=='f'){ // "f" for flag
game.displayedBoard[cursor.x][cursor.y] = FLAG;
}
else if(c==' '){ // space
c = game.board[cursor.x][cursor.y];
if(c==BOMB){
game.displayedBoard[cursor.x][cursor.y] = game.board[cursor.x][cursor.y];
gameFinished=true;
code=2;
}
else if(c==EMPTY){
discoverSurroundingBoxes(&game, cursor.x, cursor.y);
}
else{
game.displayedBoard[cursor.x][cursor.y] = game.board[cursor.x][cursor.y];
}
}
else if(c=='q'){
gameFinished=true;
printf("\nWould you like to save the game ? (Y/n) ");
c = getchar();
if(c=='Y' || c=='y' || c==10){
if(saveGame("game", game)){
code=4;
}
else{
code=1;
}
}
else{
code=0;
}
}
refreshScreen(game, cursor);
if(hasWinned(game)){
gameFinished=true;
code=3;
}
}
freeMemory(game);
if(code==1){
printf("\nError happened...\n");
}
else if(code==2){
printf("\nYou lost !\n");
}
else if(code==3){
printf("\nYou winned !\n");
}
else if(code==4){
printf("\nGame saved !\n");
}
printf("Press any key to exit\n");
getchar();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment