【C語言結構體+動態二維數組】Linux終端掃雷小遊戲

#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();
    }
}
相關文章
相關標籤/搜索