Last active
September 2, 2017 12:06
-
-
Save omaraflak/3f4c3d61e0de390bd920b86f0473ffc1 to your computer and use it in GitHub Desktop.
Minesweeper in C for Windows
This file contains 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 <stdio.h> | |
#include <stdlib.h> | |
#include <conio.h> | |
#include <time.h> | |
#include <stdbool.h> | |
char **board; | |
char **displayedBoard; | |
const char BOMB = 'X'; | |
const char EMPTY = 'E'; | |
const char DISCOVERED = 'D'; | |
const char FLAG = 'F'; | |
bool allocateMemory(int width, int height) | |
{ | |
int i; | |
if ((displayedBoard = malloc(width * sizeof(char*))) != NULL){ | |
for(i=0 ; i<width ; i++){ | |
if ((displayedBoard[i] = malloc(height * sizeof(char*))) == NULL){ | |
return false; | |
} | |
} | |
} | |
if ((board = malloc(width * sizeof(char*))) != NULL){ | |
for(i=0 ; i<width ; i++){ | |
if ((board[i] = malloc(height * sizeof(char*))) == NULL){ | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
void freeMemory(int width) | |
{ | |
int i; | |
for(i=0 ; i<width ; i++) | |
{ | |
free(board[i]); | |
free(displayedBoard[i]); | |
} | |
free(board); | |
free(displayedBoard); | |
} | |
void generateRandomCoordinates(int *x, int *y, int width, int height) | |
{ | |
*x = rand()%width; | |
*y = rand()%height; | |
} | |
void generateBoardData(int width, int height, int bombs) | |
{ | |
int i,j,x,y; | |
// generate bombs | |
for(i=0 ; i<bombs ; i++){ | |
generateRandomCoordinates(&x, &y, width, height); | |
board[x][y] = BOMB; | |
} | |
// set numbers | |
int counter; | |
for(i=0 ; i<width ; i++){ | |
for(j=0 ; j<height ; j++){ | |
counter=0; | |
if(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<width && j+y>=0 && j+y<height){ | |
if(board[i+x][j+y]==BOMB){ | |
counter++; | |
} | |
} | |
} | |
} | |
} | |
if(counter!=0){ | |
board[i][j]=counter+48; | |
} | |
else{ | |
board[i][j]=EMPTY; | |
} | |
} | |
displayedBoard[i][j] = '.'; | |
} | |
} | |
} | |
void discoverSurroundingBoxes(int x, int y, int width, int height) | |
{ | |
board[x][y]=DISCOVERED; | |
displayedBoard[x][y]=DISCOVERED; | |
int i; | |
// search left | |
if(x>0) | |
{ | |
for(i=x-1 ; i>=0 ; i--) | |
{ | |
if(board[i][y]==EMPTY && board[i][y]!=BOMB && board[i][y]!=FLAG){ | |
discoverSurroundingBoxes(i,y,width,height); | |
} | |
else if(board[i][y]!=BOMB && board[i][y]!=DISCOVERED && board[i][y]!=EMPTY && board[i][y]!=FLAG && board[i+1][y]==DISCOVERED){ | |
displayedBoard[i][y] = board[i][y]; | |
} | |
else{ | |
break; | |
} | |
} | |
} | |
// search right | |
if(x<width-1) | |
{ | |
for(i=x+1 ; i<width ; i++) | |
{ | |
if(board[i][y]==EMPTY && board[i][y]!=BOMB && board[i][y]!=FLAG){ | |
discoverSurroundingBoxes(i,y,width,height); | |
} | |
else if(board[i][y]!=BOMB && board[i][y]!=DISCOVERED && board[i][y]!=EMPTY && board[i][y]!=FLAG && board[i-1][y]==DISCOVERED){ | |
displayedBoard[i][y] = board[i][y]; | |
} | |
else{ | |
break; | |
} | |
} | |
} | |
// search top | |
if(y>0) | |
{ | |
for(i=y-1 ; i>=0 ; i--) | |
{ | |
if(board[x][i]==EMPTY && board[x][i]!=BOMB && board[x][i]!=FLAG){ | |
discoverSurroundingBoxes(x,i,width,height); | |
} | |
else if(board[x][i]!=BOMB && board[x][i]!=DISCOVERED && board[x][i]!=EMPTY && board[x][i]!=FLAG && board[x][i+1]==DISCOVERED){ | |
displayedBoard[x][i] = board[x][i]; | |
} | |
else{ | |
break; | |
} | |
} | |
} | |
// search bottom | |
if(y<height-1) | |
{ | |
for(i=y+1 ; i<height ; i++) | |
{ | |
if(board[x][i]==EMPTY && board[x][i]!=BOMB && board[x][i]!=FLAG){ | |
discoverSurroundingBoxes(x,i,width,height); | |
} | |
else if(board[x][i]!=BOMB && displayedBoard[x][i]!=DISCOVERED && board[x][i]!=EMPTY && board[x][i]!=FLAG && board[x][i-1]==DISCOVERED){ | |
displayedBoard[x][i] = board[x][i]; | |
} | |
else{ | |
break; | |
} | |
} | |
} | |
} | |
void printBoard(int width, int height, int cursorX, int cursorY) | |
{ | |
int i,j; | |
for(i=0 ; i<height ; i++){ | |
for(j=0 ; j<width ; j++){ | |
printf("%c ", displayedBoard[j][i]); | |
} | |
printf("\n"); | |
if(i==cursorY){ | |
for(j=0 ; j<width ; j++){ | |
if(j==cursorX){ | |
printf("-"); | |
break; | |
} | |
else | |
printf(" "); | |
} | |
printf("\n"); | |
} | |
} | |
} | |
void refreshScreen(int width, int height, int cursorX, int cursorY) | |
{ | |
system("cls"); | |
printBoard(width, height, cursorX, cursorY); | |
} | |
bool hasWinned(int width, int height, int bombs) | |
{ | |
int i, j, discoveredBoxes=0; | |
for(i=0 ; i<width ; i++) | |
{ | |
for(j=0 ; j<height ; j++) | |
{ | |
if(displayedBoard[i][j]==DISCOVERED || (displayedBoard[i][j]!='.' && displayedBoard[i][j]!=FLAG)){ | |
discoveredBoxes++; | |
} | |
} | |
} | |
return discoveredBoxes==width*height-bombs; | |
} | |
bool saveGame(const char* filename, int width, int height, int bombs) | |
{ | |
int i,j; | |
FILE *file = fopen(filename, "w+"); | |
if(file==NULL){ | |
return false; | |
} | |
fprintf(file, "%d\n%d\n%d\n", width, height, bombs); | |
for(i=0 ; i<width ; i++){ | |
for(j=0 ; j<height ; j++){ | |
fprintf(file, "%d\n", board[i][j]); | |
fprintf(file, "%d\n", displayedBoard[i][j]); | |
} | |
} | |
fclose(file); | |
return true; | |
} | |
bool loadGame(const char* filename, int *width, int *height, int *bombs) | |
{ | |
int i,j,x; | |
FILE *file = fopen(filename, "r"); | |
if(file==NULL){ | |
return false; | |
} | |
fscanf(file, "%d", width); | |
fscanf(file, "%d", height); | |
fscanf(file, "%d", bombs); | |
if(!allocateMemory(*width, *height)){ | |
return false; | |
} | |
for(i=0 ; i<*width ; i++){ | |
for(j=0 ; j<*height ; j++){ | |
fscanf(file, "%d", &x); | |
board[i][j]=x; | |
fscanf(file, "%d", &x); | |
displayedBoard[i][j]=x; | |
} | |
} | |
fclose(file); | |
return true; | |
} | |
int main() | |
{ | |
srand(time(NULL)); | |
int WIDTH, HEIGHT, BOMBS; | |
bool gameFinished=false; | |
int code=0, choice=0; | |
int cursorX=0, cursorY=0; | |
char c; | |
/*************** | |
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", &WIDTH, &HEIGHT, &BOMBS)){ | |
refreshScreen(WIDTH, HEIGHT, cursorX, cursorY); | |
} | |
else{ | |
gameFinished=true; | |
code=1; | |
} | |
} | |
else { | |
if(choice==4){ | |
bool isOk = false; | |
while(!isOk){ | |
printf("Board width : "); | |
scanf("%d", &WIDTH); | |
printf("Board height : "); | |
scanf("%d", &HEIGHT); | |
printf("Bombs : "); | |
scanf("%d", &BOMBS); | |
if(WIDTH>0 && WIDTH<=100 && HEIGHT>0 && HEIGHT<=100 && BOMBS<WIDTH*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){ | |
WIDTH=20; | |
HEIGHT=20; | |
BOMBS=80; | |
} | |
else if(choice==2){ | |
WIDTH=15; | |
HEIGHT=15; | |
BOMBS=45; | |
} | |
else{ | |
WIDTH=8; | |
HEIGHT=8; | |
BOMBS=10; | |
} | |
if(allocateMemory(WIDTH, HEIGHT)){ | |
generateBoardData(WIDTH, HEIGHT, BOMBS); | |
refreshScreen(WIDTH, HEIGHT, cursorX, cursorY); | |
} | |
else{ | |
gameFinished=true; | |
code=1; | |
} | |
} | |
/*************** | |
GAME LOOP | |
***************/ | |
while (!gameFinished) | |
{ | |
if (kbhit()) | |
{ | |
c = getch(); | |
if(c==75){ // left | |
cursorX=cursorX==0?0:cursorX-1; | |
} | |
else if(c==72){ // up | |
cursorY=cursorY==0?0:cursorY-1; | |
} | |
else if(c==77){ // right | |
cursorX=cursorX==WIDTH-1?cursorX:cursorX+1; | |
} | |
else if(c==80){ // down | |
cursorY=cursorY==HEIGHT-1?cursorY:cursorY+1; | |
} | |
else if(c=='f'){ // "f" for flag | |
displayedBoard[cursorX][cursorY] = FLAG; | |
} | |
else if(c==' '){ // space | |
c = board[cursorX][cursorY]; | |
if(c==BOMB){ | |
displayedBoard[cursorX][cursorY] = board[cursorX][cursorY]; | |
gameFinished=true; | |
code=2; | |
} | |
else if(c==EMPTY){ | |
discoverSurroundingBoxes(cursorX, cursorY, WIDTH, HEIGHT); | |
} | |
else{ | |
displayedBoard[cursorX][cursorY] = board[cursorX][cursorY]; | |
} | |
} | |
else if(c=='q'){ | |
gameFinished=true; | |
printf("\nWould you like to save the game ? (Y/n) "); | |
c = getch(); | |
if(c=='Y' || c=='y' || c==13){ | |
if(saveGame("game", WIDTH, HEIGHT, BOMBS)){ | |
code=4; | |
} | |
else{ | |
code=1; | |
} | |
} | |
else{ | |
code=0; | |
} | |
} | |
refreshScreen(WIDTH, HEIGHT, cursorX, cursorY); | |
if(hasWinned(WIDTH, HEIGHT, BOMBS)){ | |
gameFinished=true; | |
code=3; | |
} | |
} | |
} | |
freeMemory(WIDTH); | |
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"); | |
getch(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment