/* mine.c: 지뢰찾기 소스 파일(TUI) 종류: win32 console program 언어: C 제작자: 윤종하 제작 시작일: 2010년 12월 24일 1차 종료일: 2010년 12월 29일*/ #include<stdio.h> #include<stdlib.h> #include<time.h> #include<conio.h> #include<windows.h> #define TRUE 1 #define FALSE 0 //#define NO_STATE 3 typedef struct cell//1개 셀에 포함된 데이터의 구조체 { int iIsRevealed; int iIsMine; int iNumOfMine;//주변에 있는 지뢰의 개수 int iIsUnknown; int iIsFined; }CELL; COORD* make_mine_map(CELL** map,COORD size,int iNumOfMine); void print_map(CELL** map,COORD size,int iNumOfMine,int iCurrentFindedMine); int click_cell(CELL** map,COORD size,int *iNumOfLeftCell); void one_right_click_cell(CELL** map,COORD size,COORD *cPosOfMine,int iNumOfMine,int *iFindedRealMine); void double_right_click_cell(CELL** map,COORD size); void find_mine(CELL** map,COORD size,COORD pos,int *iNumOfLeftCell); void count_time(int iSecond); void print_one_cell(CELL** map,int xpos,int ypos,int mine); COORD coord_input(COORD size); void initialize_cell(CELL *input); int search_mine(int iNumOfMine,COORD* real_mine_cell,COORD target_cell); int main(int argc,char* argv[]) { CELL **map; COORD size; COORD *cPosOfMine; int iNumOfMine,iCurrentFindedMine=0,iNumOfLeftCell,iIsAlive=TRUE,tempX,tempY,iFindedRealMine=0,i,j; time_t tStartTime,tEndTime; char cSelect; /*걍 멋있으라고 한 시작화면*/ for(i=0;i<5;i++) printf("*****************************************************************************\n"); printf("********** **********\n"); printf("********** **********\n"); printf("********** **********\n"); printf("********** 지뢰찾기 **********\n"); printf("********** **********\n"); printf("********** **********\n"); printf("********** **********\n"); printf("********** **********\n"); printf("********** 크리스마스에 할 거 없어서 만듦*********\n"); for(i=0;i<5;i++) printf("\*****************************************************************************\n"); /*map 작성 시작*/ if(argc==4){//argument로의 맵사이즈 입력이 있을 경우 size.X=(short)atoi(argv[1]); size.Y=(short)atoi(argv[2]); } else{//argument로의 입력이 없을 경우 printf("맵의 사이즈를 입력하세요(가로 세로): "); scanf("%d %d",&tempX,&tempY); size.X=tempX; size.Y=tempY; } map=(CELL**)malloc(sizeof(CELL)*size.Y);//1차동적할당 for(i=0;i<size.Y;i++){ map[i]=(CELL*)malloc(sizeof(CELL)*size.X);//2차동적할당 for(j=0;j<size.X;j++) initialize_cell(&map[i][j]);//초기화 시킴 } if(argc==4) iNumOfMine=atoi(argv[3]);////argument로의 지뢰 개수 입력이 있을 경우 else{ printf("지뢰의 개수를 입력하세요: "); scanf("%d",&iNumOfMine); } cPosOfMine=make_mine_map(map,size,iNumOfMine); iNumOfLeftCell=size.X*size.Y; printf("입력한 데이터에 따른 맵 및 데이터의 세팅이 성공적으로 완료됐습니다.\n3초 후 게임이 시작됩니다.\n"); count_time(3); //system("pause"); /*게임을 위한 루프 시작*/ time(&tStartTime);//시작시간 저장 do{ print_map(map,size,iNumOfMine,iCurrentFindedMine); printf("수행할 작업을 선택하세요\na: 누르기\ts: 지뢰가 확실히 있음\td: 여기는 뭐가뭔지 모르겠음\tq: 종료"); cSelect=getch(); fflush(stdin); cSelect=tolower(cSelect); switch(cSelect){ case 'a': iIsAlive=click_cell(map,size,&iNumOfLeftCell); if(iIsAlive==FALSE){ printf("지뢰가 폭발했습니다\n"); system("pause");//위에 문장은 읽어야되니까 } break; case 's': one_right_click_cell(map,size,cPosOfMine,iNumOfMine,&iFindedRealMine); iCurrentFindedMine++; break; case 'd': double_right_click_cell(map,size); break; case 'q': for(i=0;i<size.Y;i++) free(map[i]);//2차 동적할당 해제 완료 free(map); free(cPosOfMine); printf("게임을 종료합니다.\n제작: 크리스마스에 할게 없었다니까\n"); system("pause"); exit(0); break; default: printf("잘못된 입력입니다."); } }while(iNumOfLeftCell>iNumOfMine && iIsAlive==TRUE && iFindedRealMine!=iNumOfMine); time(&tEndTime);//종료시간 저장 free(cPosOfMine); /*승패 알림 메시지 출력*/ system("cls"); if(iIsAlive==TRUE) printf("축하합니다! 당신이 승리했습니다.\a\a\a\n"); else if(iIsAlive==FALSE) printf("당신이 졌습니다.\a\a\n"); else printf("Unproteted error is occured!\a"); /*모든 지뢰의 위치 출력*/ for(i=0;i<size.Y;i++){ for(j=0;j<size.X;j++) print_one_cell(map,j,i,TRUE); free(map[i]);//2차 동적할당 해제 Sleep(500); printf("\n"); } free(map);//1차 동적할당 해제 printf("소요시간: %ldsec.\n",tEndTime-tStartTime);//소요시간 출력 printf("2010년 크리스마스에 할거 없어서 만듦\n"); system("pause"); return 0; } COORD* make_mine_map(CELL **map,COORD size,int iNumOfMine) { int i,j; static COORD *pos_data; //FILE *txtForDebug=fopen("mine_pos.txt","w"); srand(time(NULL)); pos_data=(COORD*)malloc(sizeof(COORD)*iNumOfMine);//지뢰 개수만큼 동적할당 /*지뢰좌표 생성*/ for(i=0;i<iNumOfMine;){ pos_data[i].X=rand()%size.X; pos_data[i].Y=rand()%size.Y; /*중복 좌표 검사*/ for(j=0;j<i;j++) if(pos_data[i].X==pos_data[j].X && pos_data[i].Y==pos_data[j].Y) continue;//중복 좌표가 생기면 재생성 i++; } /*맵에 지뢰좌표 입력 및 디버깅용 파일 출력*/ for(i=0;i<iNumOfMine;i++){ //printf("%d: %d %d\n",i,pos_data[i].X,pos_data[i].Y); map[pos_data[i].Y][pos_data[i].X].iIsMine=TRUE; //fprintf(txtForDebug,"%d: %d %d\n",i,(int)pos_data[i].X,(int)pos_data[i].Y); } //system("pause"); return pos_data; } void print_map(CELL **map,COORD size,int iNumOfMine,int iCurrentFindedMine) { int xIndex,yIndex; system("cls"); for(yIndex=-1;yIndex<size.Y;yIndex++){ for(xIndex=-1;xIndex<size.X;xIndex++){ if(yIndex==-1){ if(xIndex==-1) printf(" "); else printf("%d ",xIndex); } else if(xIndex==-1) printf("%d",yIndex); else{ print_one_cell(map,xIndex,yIndex,FALSE); } } printf("\n"); } printf("남은 지뢰의 개수: %d\n",iNumOfMine-iCurrentFindedMine); } int click_cell(CELL** map,COORD size,int *iNumOfLeftCell) { COORD input=coord_input(size); if(map[input.Y][input.X].iIsRevealed==TRUE) return TRUE;//이미 깐 것을 눌렀을 경우 else if(map[input.Y][input.X].iIsMine==TRUE) return FALSE;//지뢰를 눌렀을 경우 else find_mine(map,size,input,&(*iNumOfLeftCell)); return TRUE; } void one_right_click_cell(CELL **map,COORD size,COORD *cPosOfMine,int iNumOfMine,int *iFindedRealMine) { COORD input=coord_input(size); if(map[input.Y][input.X].iIsRevealed==TRUE) return;//이미 깐 것을 눌렀을 경우 else{ if(map[input.Y][input.X].iIsFined==TRUE) map[input.Y][input.X].iIsFined=FALSE; else map[input.Y][input.X].iIsFined=TRUE; } if(search_mine(iNumOfMine,cPosOfMine,input)==TRUE) (*iFindedRealMine)++; } void double_right_click_cell(CELL **map,COORD size) { COORD input=coord_input(size); if(map[input.Y][input.X].iIsRevealed==TRUE) return;//이미 깐 것을 눌렀을 경우 else{ if(map[input.Y][input.X].iIsUnknown==FALSE) map[input.Y][input.X].iIsUnknown=TRUE; else map[input.Y][input.X].iIsUnknown=FALSE; } } void find_mine(CELL **map,COORD size,COORD pos,int *iNumOfLeftCell) { int iNumOfMine=0,coordX,coordY; COORD temp_pos=pos; if(map[pos.Y][pos.X].iIsMine==TRUE) return;//만약 지뢰이면 검사 종료 map[pos.Y][pos.X].iIsRevealed=TRUE;//까줌 (*iNumOfLeftCell)--; for(coordY=-1;coordY<=1;coordY++){ for(coordX=-1;coordX<=1;coordX++){ temp_pos=pos; if(coordX==0 && coordY==0) continue;//기존 위치에 있는 데이터를 참조했을 때 temp_pos.X=pos.X+coordX; temp_pos.Y=pos.Y+coordY; if((temp_pos.X>size.X-1 || temp_pos.X<0) || (temp_pos.Y>size.Y-1 || temp_pos.Y<0)) continue;//범위를 초과했을 경우 else if(map[temp_pos.Y][temp_pos.X].iIsRevealed==TRUE) continue;//이미 깐 것일 경우 else if(map[temp_pos.Y][temp_pos.X].iIsMine==TRUE) iNumOfMine++; } } map[pos.Y][pos.X].iNumOfMine=iNumOfMine;//주변 지뢰의 개수 저장 if(map[pos.Y][pos.X].iNumOfMine!=0) return;//지뢰의 개수가 0개가 아니면 끝 else{//주변의 데이터 탐색시작 for(coordY=-1;coordY<=1;coordY++){ for(coordX=-1;coordX<=1;coordX++){ temp_pos=pos; temp_pos.X+=coordX; temp_pos.Y+=coordY; if((temp_pos.X>size.X-1 || temp_pos.X<0) || (temp_pos.Y>size.Y-1 || temp_pos.Y<0)) continue;//범위를 초과했을 경우 if(coordX==0 && coordY==0) continue;//기존 위치를 참조했을 경우. 지우면 stack overflow의 향연 if(map[temp_pos.Y][temp_pos.X].iIsRevealed==TRUE) continue;//열려있을 경우는 검사할 필요가 없잖아 find_mine(map,size,temp_pos,&(*iNumOfLeftCell)); } } } } void count_time(int iSecond) { for(;iSecond>0;iSecond--){ printf("%d\a ",iSecond); Sleep(1000); } printf("%d\a\n",iSecond); } void print_one_cell(CELL **map,int xpos,int ypos,int mine) { if(map[ypos][xpos].iIsRevealed==TRUE){ if(mine==TRUE && map[ypos][xpos].iIsMine==TRUE) printf(" *"); else if(map[ypos][xpos].iNumOfMine==0) printf("□"); else printf(" %d",map[ypos][xpos].iNumOfMine); } else{ if(map[ypos][xpos].iIsFined==TRUE) printf(" m"); else if(map[ypos][xpos].iIsUnknown==TRUE) printf(" ?"); else if(mine==TRUE && map[ypos][xpos].iIsMine) printf(" *"); else printf("■"); } } COORD coord_input(COORD size) { COORD temp; int tempX,tempY; printf("좌표를 입력하세요(x y): "); scanf("%d %d",&tempX,&tempY); temp.X=(short)tempX; temp.Y=(short)tempY; while(temp.X<0 || temp.X>size.X-1 || temp.Y<0 || temp.Y>size.Y-1){ printf("좌표 입력이 잘못됐습니다. 다시 입력하세요.\n좌표를 입력하세요(x y): "); scanf("%d %d",&tempX,&tempY); temp.X=(short)tempX; temp.Y=(short)tempY; } return temp; } void initialize_cell(CELL *input) { input->iIsFined=FALSE; input->iIsMine=FALSE; input->iIsRevealed=FALSE; input->iIsUnknown=FALSE; } int search_mine(int iNumOfMine,COORD *real_mine_cell,COORD target_cell) { int i; for(i=0;i<iNumOfMine;i++) if(real_mine_cell[i].X==target_cell.X && real_mine_cell[i].Y==target_cell.Y) return TRUE; return FALSE; }
작년 크리스마스에 할게 없어서 모태솔로잉여프로젝트로 지뢰찾기를 제작해봤습니다.
콘솔 프로그램으로 열심히 짜봤구요, 음주코딩의 위대함을 깨달았습니다.
콘솔 프로그램으로 열심히 짜봤구요, 음주코딩의 위대함을 깨달았습니다.
근데 버그가 넘쳐나는거 같아요 ㅠ