#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #define M_Symbol 'F' //打印雷的符號 typedef struct node{ char chess; //存放棋盤節點的值 char mine; //存放雷盤節點的值 }Node; int M,N; //M:用戶設置雷的個數,N:用戶輸入棋盤的大小(N*N) Node** panel; void print_hline(),set_size(),title(); void chess_panel(),update_chess(),mine_panel(); void show_mine(),check(),zero_open(),play_game(); int main() { set_size(); title(); chess_panel(); mine_panel(); play_game(); return 0; } //print horizontal line void print_hline() { int i; for(i=0;i<3*(N-1)+1;i++) printf("-"); printf("\n"); } //set size of panel void set_size() { print_hline(); int i; for(i=0;i<(3*N-22)/2;i++) printf(" "); printf("Welcome to minesweeper\n"); print_hline(); input_size: printf("棋盤大小_雷的個數:"); scanf("%d %d",&N,&M); if(N*N<M) { printf("Error:the mines was greater then chess,pls re-input\n"); goto input_size; } system("clear"); } //set title of panel void title() { int i; print_hline(); for(i=0;i<(3*N-24)/2;i++) printf(" "); printf("Welcome to minesweeper\n"); for(i=0;i<(3*N-18)/2;i++) printf(" "); printf("Panel:%d*%d Mine:%d\n",N,N,M); print_hline(); } //chess panel genarate void chess_panel() { int i,j; panel=(Node**)malloc(N*sizeof(Node*)); for(i=0;i<N;i++) { panel[i]=(Node*)malloc(N*sizeof(Node)); for(j=0;j<N;j++) { panel[i][j].chess='*'; printf("%-3c",panel[i][j].chess); if(j==N-1) printf("\n"); } } print_hline(); } //update chess panel void update_chess() { int i,j; title(); for(i=0;i<N;i++) { for(j=0;j<N;j++) { printf("%-3c",panel[i][j].chess); if(j==N-1) printf("\n"); } } print_hline(); } //mine panel genarate void mine_panel() { /*-------建立一個動態數組存放M個雷的下標-------*/ int* a=(int*)malloc(M*sizeof(int)); if(!a) { printf("內存分配失敗\n"); return; } /*-------在0~N*N內產生M個不一樣的下標-------*/ int i=0,j,k; srand(time(NULL)); a[i++]=rand()%(N*N); while(1) { k=rand()%(N*N); for(j=0;j<i;j++) { if(k==a[j]) break; if(j==i-1) { a[i++]=k;break;} } if(i==M) break; } /*建立一個臨時(N+2)*(N+2)二維字符數組用來輔助計算每一個點的周圍雷的個數*/ char** temp; temp=(char**)malloc((N+2)*sizeof(char*)); for(i=0;i<N+2;i++) { temp[i]=(char*)malloc((N+2)*sizeof(char)); for(j=0;j<N+2;j++) { temp[i][j]=0; for(k=0;k<M;k++) { if(a[k]==(i-1)*N+j-1 && i>=1 && j>=1 && i<=N && j<=N) temp[i][j]=1; } } } /*---用臨時二維數組來輔助計算每一個點的周圍雷的個數---*/ char tmp; for(i=0;i<N+2;i++) { for(j=0;j<N+2;j++) { if(i>=1 && i<=N && j>=1 && j<=N) { tmp=temp[i-1][j-1]+ temp[i-1][j]+ temp[i-1][j+1]+ temp[i][j-1]+ temp[i][j+1]+ temp[i+1][j-1]+ temp[i+1][j]+ temp[i+1][j+1]; panel[i-1][j-1].mine=tmp+48; } } } free(temp); /*-----------將雷盤上有雷的地方置爲M_Symbol-----------*/ for(i=0;i<N;i++) { for(j=0;j<N;j++) { for(k=0;k<M;k++) { if(a[k]==i*N+j) panel[i][j].mine=M_Symbol; } if(panel[i][j].mine=='0') panel[i][j].mine='-'; } } free(a); } void show_mine() { title(); int i,j; for(i=0;i<N;i++) { for(j=0;j<N;j++) { printf("%-3c",panel[i][j].mine); if(j==N-1) printf("\n"); } } print_hline(); } void check() { int i,j; for(i=0;i<N;i++) { for(j=0;j<N;j++) { if(panel[i][j].mine!=panel[i][j].chess) return; } } printf("You Win !\n"); exit(1); } void zero_open(int x,int y) { if(x<0||x>=N||y<0||y>=N) //若是座標值越界則返回 return; if(panel[x][y].mine=='-' && panel[x][y].chess=='*') //若是雷盤上該點雷的個數爲0而且該點用戶尚未選擇過,則其周圍8個點確定無雷,故用遞歸將其周圍8個點都顯示出來 { panel[x][y].chess=panel[x][y].mine; zero_open(x-1,y-1); zero_open(x-1,y); zero_open(x-1,y+1); zero_open(x,y-1); zero_open(x,y+1); zero_open(x+1,y-1); zero_open(x+1,y); zero_open(x+1,y+1); } else panel[x][y].chess=panel[x][y].mine; //若是雷盤上該點雷的個數不爲零則只將其顯示出來 } void play_game() { int x,y,flag; //x:存放用戶輸入的x座標 y:存放用戶輸入的y座標 flag:存放用戶輸入的選擇,0爲該點非雷,1爲該點是雷 char mine,chess; while(1) { printf("[(x,y)_flag]>"); scanf("%d,%d %d",&x,&y,&flag); if(1>x || x>N || 1>y || y>N || 0>flag || flag>1) //若用戶輸入的座標值超出棋盤範圍,則給出提示並從新輸入 { printf("超出範圍,請從新輸入\n"); sleep(1); continue; } system("clear"); x=x-1;y=y-1; //將用戶習慣的座標轉換爲與二維數組對應的座標 mine=panel[x][y].mine; chess=panel[x][y].chess; if(mine!='-' && mine!=M_Symbol && chess=='*' && flag==0) //根據輸入座標對應的雷盤值來決策玩家是否勝出 { panel[x][y].chess=mine; update_chess(); } else if(mine==M_Symbol && chess=='*' && flag==1) { M--; panel[x][y].chess=mine; update_chess(); } else if(mine==M_Symbol && chess=='*' && flag==0) { show_mine(); printf("Game Over\n"); exit(-1); } else if(mine=='-' && chess=='*' && flag==0) { zero_open(x,y); update_chess(); } else if(mine!=M_Symbol && chess==M_Symbol && flag==0) { M++; panel[x][y].chess=mine; update_chess(); } else if(mine!=M_Symbol && chess!=M_Symbol && chess!='*') { update_chess(); printf("Error:Already open\n"); continue; } else if(mine!=M_Symbol && chess=='*' && flag==1) { M--; panel[x][y].chess=M_Symbol; update_chess(); } else { show_mine(); printf("Game Over\n"); exit(-1); } check(); } }