c언어의 구조체, 함수, 파일 입출력 등등 기본적인 c언어의 기능을 연습하기 위해 만든 게임이다.
#include <stdio.h>
#include <Windows.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
int height=10, width=10, mines=10, number=0;
#define MAX_H 27
#define MAX_W 30
struct Map
{
bool mine;
bool wond;
bool flag;
bool wall;
int num;
} map[MAX_H+1][MAX_W+1];
struct Record
{
char name[10];
float time;
int click;
int h;
int w;
int m;
} record[1000];
struct state
{
int time;
int bomb;
} State;
void gotoxy(int x, int y);
void menu();
void ConsoleMenu();
char KeyInp();
void GameStart();
void Setting();
void ScoreBoard();
void ConsoleGame(int height, int width);
void MapInp();
void textcolor(int color_number);
void GameOver(int ypos, int xpos);
void EntZero(int ypos, int xpos);
void GameClear();
int startmine(int ypos, int xpos);
void ScoreBoard()
{
int SBheight=height, SBwidth=width, SBmines=mines;
system("cls");
textcolor(15);
gotoxy(0, 4);
printf("num height width mines time click name\n");
printf("--------------------------------------------------------\n");
for(int i=1; i<number; i++)
printf("%2d %2d %2d %3d %.3f %4d %s\n", i, record[i].h, record[i].w, record[i].m, record[i].time, record[i].click, record[i].name);
system("pause");
menu();
}
void MapInp()
{
for(int i=0; i<=height+1; i++)
{
for(int j=0; j<=width+1; j++)
{
map[i][j].mine=0;
map[i][j].wond=0;
map[i][j].flag=0;
map[i][j].wall=0;
map[i][j].num=0;
if((i==0||j==0)||(i==height+1||j==width+1)){
map[i][j].wall=1; map[i][j].wond=1;
}
}
}
int maxmine=mines;
int mx, my;
srand(time(NULL));
while(maxmine)
{
mx=(rand())%height+1; my=(rand())%width+1;
if(map[mx][my].mine==0){
map[mx][my].mine=1; maxmine--;
}
}
for(int i=1; i<=height; i++)
{
for(int j=1; j<=width; j++)
{
if(map[i][j].mine==0)
{
for(int k=-1; k<=1; k++)
{
for(int l=-1; l<=1; l++)
{
if(k==0&&l==0) continue;
map[i][j].num+=map[i+k][j+l].mine;
}
}
}
}
}
}
int main()
{
FILE *fp1=fopen("minesweeper.txt", "at");
fclose(fp1);
FILE *fp=fopen("minesweeper.txt", "rt");
while (feof(fp) == 0){
number++;
fscanf(fp, "%d %d %d %f %d %s", &record[number].h, &record[number].w, &record[number].m, &record[number].time, &record[number].click, record[number].name);
}
if(number==0) number=-1;
fclose(fp);
menu();
}
void Setting()
{
system("mode con: cols=100 lines=30");
int option=0, End = 1;
gotoxy(40, 10);
printf("= 높이 : %d =", height);
gotoxy(40, 13);
printf("= 넓이 : %d =", width);
gotoxy(40, 16);
printf("= 지뢰 갯수 : %d =", mines);
gotoxy(35, 10+option*3);
printf("->");
while(End)
{
if(kbhit()==1)
{
char key=KeyInp();
switch(key){
case 'u':
option--;
break;
case 'd':
option++;
break;
case 'r':
switch(option){
case 0:
height++;
if(height>MAX_H) height--;
break;
case 1:
width++;
if(width>MAX_W) width--;
break;
case 2:
mines++;
if(mines>MAX_H*MAX_W) mines--;
break;
}
break;
case 'l':
switch(option){
case 0:
height--;
if(height<1) height++;
break;
case 1:
width--;
if(width<1) width++;
break;
case 2:
mines--;
if(mines<1) mines++;
break;
}
break;
case 'o':
End = 0;
break;
}
if(mines>=height*width) mines=height*width-1;
if(option==3) option-=3;
if(option==-1) option+=3;
system("cls");
gotoxy(40, 10);
printf("= 높이 : %d =", height);
gotoxy(40, 13);
printf("= 넓이 : %d =", width);
gotoxy(40, 16);
printf("= 지뢰 갯수 : %d =", mines);
gotoxy(35, 10+option*3);
printf("->");
}
}
menu();
system("cls");
}
void textcolor(int color_number)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color_number);
}
void MapOutp()
{
system("cls");
for(int i=0; i<=height+1; i++, puts(""))
{
for(int j=0; j<=width+1; j++)
{
if(map[i][j].wall==1) {textcolor(8); printf("■");}
else if(map[i][j].wond==0)
{
if(map[i][j].flag==1) {textcolor(9); printf("¶");}
else{
{textcolor(3); printf("■");}
}
}
else
{
if(map[i][j].num>0){
switch(map[i][j].num){
case 1: textcolor(15); break;
case 2: textcolor(14); break;
case 3: textcolor(13); break;
case 4: textcolor(12); break;
case 5: textcolor(11); break;
case 6: textcolor(10); break;
case 7: textcolor(9); break;
case 8: textcolor(8); break;
}
printf("%2d", map[i][j].num);
}
else printf(" ");
}
}
}
textcolor(15);
gotoxy((width+5)*2, 1);
printf("┌──────┐");
gotoxy((width+5)*2, 2);
printf("│ time %3d │", State.time/1000);
gotoxy((width+5)*2, 3);
printf("│ mine %3d │", State.bomb);
gotoxy((width+5)*2, 4);
printf("└──────┘");
}
void GameStart()
{
int st=0;
clock_t timest, timeed, timenow;
int xpos=1, ypos=1, solve=0;
MapInp();
system("cls");
for(int i=0; i<=height+1; i++, puts(""))
{
for(int j=0; j<=width+1; j++)
{
if(map[i][j].wall==1) {textcolor(8); printf("■");}
else if(map[i][j].wond==0)
{
{textcolor(3); printf("■");}
}
}
}
textcolor(15);
gotoxy((width+5)*2, 1);
printf("┌──────┐");
gotoxy((width+5)*2, 2);
printf("│ time %3d │", State.time/1000);
gotoxy((width+5)*2, 3);
printf("│ mine %3d │", State.bomb);
gotoxy((width+5)*2, 4);
printf("└──────┘");
gotoxy(xpos*2, ypos);
record[number].click=0;
State.time=0;
State.bomb=mines;
while(1)
{
if(st==1) {
st=2; timest=clock();
}
if(kbhit()==1)
{
char key=KeyInp();
switch(key){
case 'l':
if(xpos>1) xpos--; break;
case 'r':
if(xpos<width) xpos++; break;
case 'u':
if(ypos>1) ypos--; break;
case 'd':
if(ypos<height) ypos++; break;
default:
break;
}
if(key=='e')
{
record[number].click++;
ONE:
if(st!=2) st=1;
if(map[ypos][xpos].wond==0)
{
map[ypos][xpos].wond=1;
if(map[ypos][xpos].mine==1){
if(st==1){
map[ypos][xpos].mine=0;
map[ypos][xpos].wond=0;
if(startmine(ypos, xpos)==1){
int num=0;
for(int i=-1; i<=1; i++)
for(int j=-1; j<=1; j++){
num+=map[ypos+i][xpos+j].mine;
if(map[ypos+i][xpos+j].num>0) map[ypos+i][xpos+j].num--;
}
map[ypos][xpos].num=num;
}
goto ONE;
}
else{
timeed=clock();
record[number].time=(float)(timeed-timest)/1000;
GameOver(ypos, xpos);
return;
}
}
else if(map[ypos][xpos].flag==1) continue;
else if(map[ypos][xpos].num==0) EntZero(ypos, xpos);
}
else if(map[ypos][xpos].num>0)
{
int Flag=0;
int mine=0;
for(int i=-1; i<=1; i++)
{
for(int j=-1; j<=1; j++)
{
if(map[ypos+i][xpos+j].flag!=map[ypos+i][xpos+j].mine) mine=1;
Flag+=map[ypos+i][xpos+j].flag;
}
}
if(Flag==map[ypos][xpos].num)
{
if(mine==1) GameOver(ypos, xpos);
for(int i=-1; i<=1; i++)
{
for(int j=-1; j<=1; j++)
{
if(i==0&&j==0) continue;
if(map[ypos+i][xpos+j].wond==0&&map[ypos+i][xpos+j].flag==0)
{
map[ypos+i][xpos+j].wond=1;
if(map[ypos+i][xpos+j].num==0) EntZero(ypos+i, xpos+j);
}
}
}
}
}
}
else if(key=='s')
{
record[number].click++;
if(st!=2) st=1;
if(map[ypos][xpos].wond==0)
{
if(map[ypos][xpos].flag==0) {
map[ypos][xpos].flag=1; State.bomb--;
}
else {
map[ypos][xpos].flag=0; State.bomb++;
}
}
}
solve=0;
for(int i=1; i<=height; i++)
{
for(int j=1; j<=width; j++)
{
if(map[i][j].wond==1) solve++;
}
}
if(height*width==solve+mines){
timeed=clock();
record[number].time=(float)(timeed-timest)/1000;
record[number].h=height;
record[number].w=width;
record[number].m=mines;
GameClear(); return;
}
MapOutp();
gotoxy(xpos*2, ypos);
}
if(st==2){
timenow=clock();
if((timenow-timest)-State.time>=1000){
State.time+=1000;
gotoxy((width+5)*2+9, 2);
printf("%3d", State.time/1000);
gotoxy(xpos*2, ypos);
}
}
}
}
int startmine(int ypos, int xpos)
{
if(map[ypos-1][xpos].wall==0){
if(map[ypos-1][xpos].mine==0)
{
map[ypos-1][xpos].mine=1;
for(int i=-1; i<=1; i++)
for(int j=-1; j<=1; j++)
if(map[ypos-1+i][xpos+j].mine==0&&map[ypos-1+i][xpos+j].wall==0)
map[ypos-1+i][xpos+j].num++;
return 1;
}
else{
if(startmine(ypos-1, xpos)==1) return 1;
}
}
else if(map[height][xpos-1].wall==0)
{
if(map[height][xpos-1].mine==0)
{
map[height][xpos-1].mine=1;
for(int i=-1; i<=1; i++)
for(int j=-1; j<=1; j++)
if(map[ypos-1+i][xpos+j].mine==0&&map[ypos-1+i][xpos+j].wall==0)
map[ypos-1+i][xpos+j].num++;
return 1;
}
else{
if(startmine(height, xpos-1)==1) return 1;
}
}
else if(map[height][width].mine==0)
{
map[height][width].mine=1;
for(int i=-1; i<=1; i++)
for(int j=-1; j<=1; j++)
if(map[ypos-1+i][xpos+j].mine==0&&map[ypos-1+i][xpos+j].wall==0)
map[ypos-1+i][xpos+j].num++;
return 1;
}
else
{
if(startmine(height, width)==1) return 1;
}
}
void GameClear()
{
system("cls");
for(int i=0; i<=height+1; i++, puts(""))
{
for(int j=0; j<=width+1; j++)
{
if(map[i][j].wall==1) {textcolor(3); printf("■");}
else if(map[i][j].mine==1) {textcolor(12); printf("¶");}
else if(map[i][j].num==0) {textcolor(15); printf(" ");}
else {textcolor(15); printf("%2d", map[i][j].num);}
}
}
textcolor(15);
gotoxy((width+5)*2, 1);
printf("┌──────┐");
gotoxy((width+5)*2, 2);
printf("│ time %3d │", State.time/1000);
gotoxy((width+5)*2, 3);
printf("│ mine %3d │", State.bomb);
gotoxy((width+5)*2, 4);
printf("└──────┘");
gotoxy(0, height+2);
textcolor(3);
printf("%.3f ", record[number].time);
printf("(*^-^*)\n");
printf("6글자 영문으로 이름을 입력해주세요 : ");
scanf("%s", &record[number].name);
FILE *fp=fopen("minesweeper.txt", "at");
fprintf(fp, "%d %d %d %f %d %s\n", record[number].h, record[number].w, record[number].m, record[number].time, record[number].click, record[number].name);
fclose(fp);
system("pause");
number++;
menu();
}
void EntZero(int ypos, int xpos)
{
for(int i=-1; i<=1; i++)
{
for(int j=-1; j<=1; j++)
{
if(map[ypos+i][xpos+j].mine==1) continue;
if(map[ypos+i][xpos+j].flag==1) continue;
if(i==0&&j==0) continue;
if(map[ypos+i][xpos+j].wond==1) continue;
map[ypos+i][xpos+j].wond=1;
if(map[ypos+i][xpos+j].num==0) EntZero(ypos+i, xpos+j);
}
}
return;
}
void GameOver(int ypos, int xpos)
{
system("cls");
for(int i=0; i<=height+1; i++, puts(""))
{
for(int j=0; j<=width+1; j++)
{
if(map[i][j].wall==1) {textcolor(5); printf("■");}
else if(map[i][j].mine==1){
if(i==ypos&&j==xpos) {textcolor(76); printf("※");}
else {textcolor(12); printf("※");}
}
else
{
if(map[i][j].flag==1){textcolor(4); printf("¶");}
else if(map[i][j].num>0){
textcolor(16-map[i][j].num);
if(i==ypos&&j==xpos) {textcolor(80-map[i][j].num);}
printf("%2d", map[i][j].num);
}
else {textcolor(15); printf(" ");}
}
}
}
textcolor(15);
gotoxy((width+5)*2, 1);
printf("┌──────┐");
gotoxy((width+5)*2, 2);
printf("│ time %3d │", State.time/1000);
gotoxy((width+5)*2, 3);
printf("│ mine %3d │", State.bomb);
gotoxy((width+5)*2, 4);
printf("└──────┘");
gotoxy(0, height+2);
textcolor(3);
printf("%.3f ", record[number].time);
printf("(ㅠ_ㅠ)\n");
system("pause");
menu();
}
void gotoxy(int x, int y)
{
COORD pos={x, y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void menu()
{
textcolor(15);
ConsoleMenu();
int menu=0, End = 1;
system("cls");
gotoxy(40, 10);
printf("=게임 시작=");
gotoxy(40, 13);
printf("=설정=");
gotoxy(40, 16);
printf("=스코어보드=");
gotoxy(35, 10+menu*3);
printf("->");
while(End)
{
if(kbhit()==1)
{
char key=KeyInp();
switch(key){
case 'u':
menu--;
break;
case 'd':
menu++;
break;
case 'e':
End = 0;
break;
}
if(menu==3) menu-=3;
if(menu==-1) menu+=3;
system("cls");
gotoxy(40, 10);
printf("=게임 시작=");
gotoxy(40, 13);
printf("=설정=");
gotoxy(40, 16);
printf("=스코어보드=");
gotoxy(35, 10+menu*3);
printf("->");
}
}
system("cls");
if(menu==0) GameStart();
if(menu==1) Setting();
if(menu==2) ScoreBoard();
}
char KeyInp()
{
int key=getch();
if(key==224)
{
key=getch();
switch(key){
case 72:
return 'u';
break;
case 75:
return 'l';
break;
case 77:
return 'r';
break;
case 80:
return 'd';
break;
}
}
else if(key==13)
{
return 'e';
}
else if(key==27)
{
return 'o';
}
else if(key==32)
{
return 's';
}
}
void ConsoleMenu()
{
system("mode con: cols=100 lines=30");
system("title 지뢰찾기");
}
함수는 크게 4가지로 나뉜다. 게임 이전 설정, 게임 중 알고리즘, 게임 외적 부분, 도구 함수
게임 이전 설정에는 ConsoleMenu, Setting, MapInp, Startmine
게임 중 알고리즘에는 GameStart, GameOver, EntZero, GameClear, MapOutp
게임 외적 부분에는 Menu, ScoreBoard, main
도구 함수에는 gotoxy, KeyInp, textcolor