C语言——扫雷游戏

C语言——扫雷游戏

利用C语言学习到的知识,就可以写一些简单的小游戏,比如:扫雷游戏。
在开始敲代码之前,需要做如下准备:

一、 回顾一下怎么玩扫雷:
点击格子中的任意一个位置,如果点到雷,那么就炸死,游戏结束,如果这个位置没有雷,就会显示周围8个位置的雷的总数,同时会展开该位置周围没雷的地方,就这样直到游戏结束;

二、思考用C语言实现游戏:

要求如下:
- 扫雷中第一步不能被炸死;
- 排雷过程中要可以展开周围不是雷的地方;
- 游戏可以选择两个难度,初级与高级;

⑴、给出两个数组,一个是用来布雷的(mine数组),另外一个用来显示给玩家,当然就不能把雷的位置给出来啦(show数组);
⑵、打印游戏的菜单,分装一个menu()函数;
⑶、选择游戏的难度,分装一个level_menu()函数;
⑷、初始化布雷数组,对于初级难度,在mine1数组中布置雷,布置雷的时候注意不能超过给的数组大小,同理操作高级难度;
⑸、初始化给玩家展示的数组,两个难度初始化都为’*‘;
⑹、打印,在刚开始写的时候,为了更好的操控,将布雷数组也打印;
⑺、开始扫雷;
⑻、判断玩家是否赢了游戏。

三、具体化想法设计(以下内容举例初级难度,高级难度同理):
注意:以下内容均关于游戏的一些实现,全部置于game.c这个源文件中。

1.初始化两个数组中,可以很巧妙的利用memset()函数, 代码如下:

void InitBoard1(char board[ROWS1][COLS1], int rows, int cols, char set)
{
    memset(board, set, rows*cols*sizeof(board[0][0]));
}

注意:
关于memset()函数,函数原型是:extern void memset(void buffer, int c, int count),buffer为指针或者数组,c为赋给buffer的值,count为buffer的长度。

2、打印出扫雷的格子,代码如下:

void DisplayBoard1(char board[ROWS1][COLS1], int row, int col)
{
    int i = 0;
    int j = 0;
    for(i=0; i<=row; i++)
    {
        printf("%2d ",i);//第一行的序号,方便扫雷输入坐标
    }
    printf("\n");
    for(i=1; i<=row; i++)
    {
        printf("%d ",i);//第一列的序号
        for(j=1; j<=col; j++)
        {
            printf("%3c", board[i][j]);
        }
        printf("\n");
    }
}

3、随机布置雷的位置,代码如下:

void SetMine1(char mine1[ROWS1][COLS1], int row, int col, int count)//初级mine数组中布置雷
{
     int x = 0;
     int y = 0;
     while(count)
     {
         x = rand()%row+1;
         y = rand()%col+1;
         if(mine1[x][y] == '0')
         {
             mine1[x][y] = '1';
             count--;
         }
     }
}

注意:
布置雷的时候,千万注意坐标的取值问题,利用rand()函数生成随机数为坐标值,在利用rand()函数时,需要同时调用srand()函数,并加入相应头文件。

4、未踩到雷时,显示周围8个坐标的雷的总数,代码如下:

static int GetMineCount1(char mine[ROWS1][COLS1], int x, int y)
{
    return mine[x-1][y+1]+mine[x][y+1]\
           +mine[x+1][y+1]+mine[x+1][y]\
           +mine[x+1][y-1]+mine[x][y+1]\
           +mine[x-1][y-1]+mine[x-1][y]-8*'0';//注意返回类型为整型
}

5、没有踩到雷时,展开周围无雷的地方,代码如下:

static void OpenMine1(char mine1[ROWS1][COLS1],char show1[ROWS1][COLS1],int row ,int col, int x,int y)
{
    int ret = 0;
    ret = GetMineCount1(mine1, x, y); 
    if(ret == 0)
    {
        show1[x][y]=' '; 
        if(x-1>0 && y>0 && show1[x-1][y]=='*')
            OpenMine1(mine1, show1, row, col, x-1, y);

        if(x-1>0 && y+1<=col && show1[x-1][y+1]=='*')
            OpenMine1(mine1, show1, row, col,  x-1, y+1);

        if(x>0 && y+1<=col && show1[x][y+1]=='*')
            OpenMine1(mine1, show1, row, col, x, y+1);

        if(x+1<=row && y+1<=col && show1[x+1][y+1]=='*')
            OpenMine1(mine1, show1, row, col, x+1, y+1);

        if(x+1<=row && y>0 && show1[x+1][y]=='*')
            OpenMine1(mine1, show1, row, col, x+1, y);

        if(x+1<=row && y-1>0 && show1[x+1][y-1]=='*')
            OpenMine1(mine1, show1, row, col, x+1, y-1);

        if(x>0 && y-1>0 && show1[x][y-1]=='*')
            OpenMine1(mine1, show1, row, col, x, y-1);

        if(x-1>0 && y-1>0 && show1[x-1][y-1]=='*')
            OpenMine1(mine1, show1, row, col, x-1, y-1);

    }
    else
    {
        show1[x][y] = GetMineCount1(mine1, x, y)+'0';//若坐标周围有雷,显示雷数
    }
}

6、为增加游戏趣味性,确保第一步不被炸死,代码如下:

void FirstSafe1(char mine1[ROWS1][COLS1], char show1[ROWS1][COLS1], int row, int col)
{
    int x = 0;
    int y = 0;
    int count = 0;
    int tmp = 0;
    int a = 0;
    int b = 0;
    printf("请输入要排查的坐标:>");
    scanf("%d%d", &x, &y);
    a = x;
    b = y;
    if(mine1[x][y] == '1')
    {
        mine1[x][y] = '0';
        count = GetMineCount1(mine1, x, y);
        show1[x][y] = count+'0';
        while(tmp)
        {
            x = rand()%row+1;
            y = rand()%col+1;
            if(mine1[x][y] == '0')
            {
                mine1[x][y] = '1';
            }
            tmp--;
        }
    }
    OpenMine1(mine1, show1, row, col, a, b);
    DisplayBoard1(show1, ROW1, COL1);
}

7、判断玩家是否赢了该局游戏,代码如下:

int IsWin1(char show1[ROWS1][COLS1], int row, int col)
{
    int i = 0;
    int j = 0;
    int count = 0;
    for(i=0; i<=row; i++)
    {
        for(j=0; j<=col; j++)
        {
            if(show1[i][j] == '*')
            {
                count++;
            }
        }
    }
    return count;
}

8、扫雷过程,代码如下:

void FindMine1(char mine1[ROWS1][COLS1], char show1[ROWS1][COLS1], int row, int col,int count)//扫雷初级
{
    int x = 0;
    int y = 0;
    int win = 0;
    while(wincount)
    {
        FirstSafe1(mine1, show1, row, col);//第一步安全

        if(x>=1 && x<=row && y>=1 && y<=col)
        {
            if(mine1[x][y] == '1')
            {
                printf("很遗憾,你被炸死了!\n");
                DisplayBoard1(mine1, ROW1, COL1);
                break;
            }
            else
            {
                int count = GetMineCount1(mine1, x, y);
                show1[x][y] = count + '0';
                OpenMine1(mine1,show1,row ,col, x,y);
                DisplayBoard1(show1, ROW1, COL1);
                win++;
            }
        }
    }
    if(IsWin1(show1, row, col) == LOW_COUNT)
    {
        printf("恭喜你,扫雷成功!\n");
        DisplayBoard1(show1, ROW1, COL1);
    }
}

四、游戏两个难度整体代码如下:

1、game.h头文件中:

#ifndef __GAME_H__
#define __GAME_H__

#include 
#include 
#include 
#include 

#define LOW_COUNT 10//初级版雷的个数
#define HIGH_COUNT 40//高级版雷的个数

#define ROW1 9//初级数组
#define COL1 9

#define ROWS1 ROW1+2
#define COLS1 COL1+2

#define ROW2 16//高级数组
#define COL2 16

#define ROWS2 ROW2+2
#define COLS2 COL2+2

void InitBoard1(char board[ROWS1][COLS1], int rows, int cols, char set);
void InitBoard2(char board[ROWS2][COLS2], int rows, int cols, char set);

void DisplayBoard1(char board[ROWS1][COLS1], int row, int col);
void DisplayBoard2(char board[ROWS2][COLS2], int row, int col);

void SetMine1(char mine1[ROWS1][COLS1], int row, int col, int count);
void SetMine2(char mine2[ROWS2][COLS2], int row, int col, int count);

void FindMine1(char mine1[ROWS1][COLS1], char show1[ROWS1][COLS1], int row, int col,int count);//初级扫雷
void FindMine2(char mine2[ROWS2][COLS2], char show1[ROWS2][COLS2], int row, int col,int count);//初级扫雷

int IsWin1(char show1[ROWS1][COLS1], int row, int col);
int IsWin2(char show2[ROWS2][COLS2], int row, int col);

void FirstSafe1(char mine1[ROWS1][COLS1], char show1[ROWS1][COLS1], int row, int col);
void FirstSafe2(char mine2[ROWS2][COLS2], char show2[ROWS2][COLS2], int row, int col);

#endif //__GAME_H__

2、test.c源文件,用于测试游戏大的,整体代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void menu()
{
    printf("**************************** ^@^ ***\n");
    printf("**********     1. play    **********\n");
    printf("**********     0. exit    **********\n");
    printf("************************************\n");
}

void level_menu()
{
    printf("##  1. 初级 ##\n");
    printf("##  2. 高级 ##\n");
}

void game()
{
    int level = 0;
    int row = 0;
    int col = 0;
    int x = 0;
    int y = 0;
    char mine1[ROWS1][COLS1]={0};
    char show1[ROWS1][COLS1]={0};
    char mine2[ROWS2][COLS2]={0};
    char show2[ROWS2][COLS2]={0};

    do
    {
        level_menu();
        printf("请选择游戏难度:\n");
        scanf("%d",&level);
        switch(level)
        {
        case 1:
            InitBoard1(mine1,ROWS1,COLS1,'0');
            InitBoard1(show1,ROWS1,COLS1,'*');
            SetMine1(mine1, ROW1, COL1, LOW_COUNT);//布置雷
            //DisplayBoard1(mine1, ROW1, COL1);
           // printf("\n");
            DisplayBoard1(show1, ROW1, COL1);
            FindMine1(mine1, show1, ROW1, COL1, LOW_COUNT);//扫雷
            IsWin1(show1, row, col);

            break;
        case 2:
            InitBoard2(mine2,ROWS2,COLS2,'0');
            InitBoard2(show2,ROWS2,COLS2,'*');
            SetMine2(mine2, ROW2, COL2,HIGH_COUNT);//布置雷
            //DisplayBoard2(mine2, ROW2, COL2);
            //printf("\n");
            DisplayBoard2(show2, ROW2, COL2);
            FindMine2(mine2, show2, ROW2, COL2, HIGH_COUNT);//扫雷
            IsWin2(show2, row, col);

            break;
        default:
            printf("选择错误,请重新选择!\n");
            break;
        }

    }while((level==1)||(level==2));
}

void test()
{
    int input = 0;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d",&input);
        switch(input)
        {
        case 1:
            game();
            break;
        case 0:
            printf("退出游戏\n");
            break;
        default:
            printf("选择错误!\n");
            break;
        }
    }while(input);
}

int main()
{
    test();
    return 0;
}

3、game.c源文件,存放游戏相关的函数,代码如下:

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

void InitBoard1(char board[ROWS1][COLS1], int rows, int cols, char set)
{
    memset(board, set, rows*cols*sizeof(board[0][0]));
}
void InitBoard2(char board[ROWS2][COLS2], int rows, int cols, char set)
{
    memset(board, set, rows*cols*sizeof(board[0][0]));
} 

void DisplayBoard1(char board[ROWS1][COLS1], int row, int col)
{
    int i = 0;
    int j = 0;
    for(i=0; i<=row; i++)
    {
        printf("%2d ",i);//第一行的序号,方便扫雷输入坐标
    }
    printf("\n");
    for(i=1; i<=row; i++)
    {
        printf("%d ",i);//第一列的序号
        for(j=1; j<=col; j++)
        {
            printf("%3c", board[i][j]);
        }
        printf("\n");
    }
}

void DisplayBoard2(char board[ROWS2][COLS2], int row, int col)
{
    int i = 0;
    int j = 0;
    for(i=0; i<=row; i++)
    {
        printf("%3d",i);
    }
    printf("\n");
    for(i=1; i<=row; i++)
    {
        printf("%2d ",i);
        for(j=1; j<=col; j++)
        {
            printf("%3c", board[i][j]);
        }
        printf("\n");
    }
}


void SetMine1(char mine1[ROWS1][COLS1], int row, int col, int count)//初级mine数组中布置雷
{
     int x = 0;
     int y = 0;
     while(count)
     {
         x = rand()%row+1;
         y = rand()%col+1;
         if(mine1[x][y] == '0')
         {
             mine1[x][y] = '1';
             count--;
         }
     }
}

void SetMine2(char mine2[ROWS2][COLS2], int row, int col, int count)//初级mine数组中布置雷
{
     int x = 0;
     int y = 0;
     while(count)
     {
         x = rand()%row+1;
         y = rand()%col+1;
         if(mine2[x][y] == '0')
         {
             mine2[x][y] = '1';
             count--;
         }
     }
}


static int GetMineCount1(char mine[ROWS1][COLS1], int x, int y)
{
    return mine[x-1][y+1]+mine[x][y+1]\
           +mine[x+1][y+1]+mine[x+1][y]\
           +mine[x+1][y-1]+mine[x][y+1]\
           +mine[x-1][y-1]+mine[x-1][y]-8*'0';
}

static int GetMineCount2(char mine[ROWS2][COLS2], int x, int y)
{
    return mine[x-1][y+1]+mine[x][y+1]\
           +mine[x+1][y+1]+mine[x+1][y]\
           +mine[x+1][y-1]+mine[x][y+1]\
           +mine[x-1][y-1]+mine[x-1][y]-8*'0';
}

static void OpenMine1(char mine1[ROWS1][COLS1],char show1[ROWS1][COLS1],int row ,int col, int x,int y)
{
    int ret = 0;
    ret = GetMineCount1(mine1, x, y); 
    if(ret == 0)
    {
        show1[x][y]=' '; 
        if(x-1>0 && y>0 && show1[x-1][y]=='*')
            OpenMine1(mine1, show1, row, col, x-1, y);

        if(x-1>0 && y+1<=col && show1[x-1][y+1]=='*')
            OpenMine1(mine1, show1, row, col,  x-1, y+1);

        if(x>0 && y+1<=col && show1[x][y+1]=='*')
            OpenMine1(mine1, show1, row, col, x, y+1);

        if(x+1<=row && y+1<=col && show1[x+1][y+1]=='*')
            OpenMine1(mine1, show1, row, col, x+1, y+1);

        if(x+1<=row && y>0 && show1[x+1][y]=='*')
            OpenMine1(mine1, show1, row, col, x+1, y);

        if(x+1<=row && y-1>0 && show1[x+1][y-1]=='*')
            OpenMine1(mine1, show1, row, col, x+1, y-1);

        if(x>0 && y-1>0 && show1[x][y-1]=='*')
            OpenMine1(mine1, show1, row, col, x, y-1);

        if(x-1>0 && y-1>0 && show1[x-1][y-1]=='*')
            OpenMine1(mine1, show1, row, col, x-1, y-1);

    }
    else
    {
        show1[x][y] = GetMineCount1(mine1, x, y)+'0';//若坐标周围有雷,显示雷数
    }
}

static void OpenMine2(char mine2[ROWS2][COLS2],char show2[ROWS2][COLS2],int row ,int col, int x,int y)
{
    int ret = 0;
    ret = GetMineCount2(mine2, x, y); 
    if(ret == 0)
    {
        show2[x][y]=' '; 
        if(x-1>0 && y>0 && show2[x-1][y]=='*')
            OpenMine2(mine2, show2, row, col, x-1, y);

        if(x-1>0 && y+1<=col && show2[x-1][y+1]=='*')
            OpenMine2(mine2, show2, row, col,  x-1, y+1);

        if(x>0 && y+1<=col && show2[x][y+1]=='*')
            OpenMine2(mine2, show2, row, col, x, y+1);

        if(x+1<=row && y+1<=col && show2[x+1][y+1]=='*')
            OpenMine2(mine2, show2 ,row, col, x+1, y+1);

        if(x+1<=row && y>0 && show2[x+1][y]=='*')
            OpenMine2(mine2, show2, row, col, x+1, y);

        if(x+1<=row && y-1>0 && show2[x+1][y-1]=='*')
            OpenMine2(mine2, show2, row, col, x+1, y-1);

        if(x>0 && y-1>0 && show2[x][y-1]=='*')
            OpenMine2(mine2, show2, row, col, x, y-1);

        if(x-1>0 && y-1>0 && show2[x-1][y-1]=='*')
            OpenMine2(mine2, show2, row, col, x-1, y-1);

    }
    else
    {
        show2[x][y] = GetMineCount2(mine2, x, y)+'0';//若坐标周围有雷,显示雷数
    }
}

void FirstSafe1(char mine1[ROWS1][COLS1], char show1[ROWS1][COLS1], int row, int col)
{
    int x = 0;
    int y = 0;
    int count = 0;
    int tmp = 0;
    int a = 0;
    int b = 0;
    printf("请输入要排查的坐标:>");
    scanf("%d%d", &x, &y);
    a = x;
    b = y;
    if(mine1[x][y] == '1')
    {
        mine1[x][y] = '0';
        count = GetMineCount1(mine1, x, y);
        show1[x][y] = count+'0';
        while(tmp)
        {
            x = rand()%row+1;
            y = rand()%col+1;
            if(mine1[x][y] == '0')
            {
                mine1[x][y] = '1';
            }
            tmp--;
        }
    }
    OpenMine1(mine1, show1, row, col, a, b);
    DisplayBoard1(show1, ROW1, COL1);
}

void FirstSafe2(char mine2[ROWS2][COLS2], char show2[ROWS2][COLS2], int row, int col)
{
    int x = 0;
    int y = 0;
    int count = 0;
    int tmp = 0;
    int a = 0;
    int b = 0;
    printf("请输入要排查的坐标:>");
    scanf("%d%d", &x, &y);
    a = x;
    b = y;
    if(mine2[x][y] == '1')
    {
        mine2[x][y] = '0';
        count = GetMineCount2(mine2, x, y);
        show2[x][y] = count+'0';
        while(tmp)
        {
            x = rand()%row+1;
            y = rand()%col+1;
            if(mine2[x][y] == '0')
            {
                mine2[x][y] = '1';
            }
            tmp--;
        }
    }
    OpenMine2(mine2, show2, row, col, a, b);
    DisplayBoard2(show2, ROW2, COL2);
}


int IsWin1(char show1[ROWS1][COLS1], int row, int col)
{
    int i = 0;
    int j = 0;
    int count = 0;
    for(i=0; i<=row; i++)
    {
        for(j=0; j<=col; j++)
        {
            if(show1[i][j] == '*')
            {
                count++;
            }
        }
    }
    return count;
}

int IsWin2(char show2[ROWS2][COLS2], int row, int col)
{
    int i = 0;
    int j = 0;
    int count = 0;
    for(i=0; i<=row; i++)
    {
        for(j=0; j<=col; j++)
        {
            if(show2[i][j] == '*')
            {
                count++;
            }
        }
    }
    return count;
}

void FindMine1(char mine1[ROWS1][COLS1], char show1[ROWS1][COLS1], int row, int col,int count)//扫雷初级
{
    int x = 0;
    int y = 0;
    int win = 0;
    while(wincount)
    {
        FirstSafe1(mine1, show1, row, col);//第一步安全

        if(x>=1 && x<=row && y>=1 && y<=col)
        {
            if(mine1[x][y] == '1')
            {
                printf("很遗憾,你被炸死了!\n");
                DisplayBoard1(mine1, ROW1, COL1);
                break;
            }
            else
            {
                int count = GetMineCount1(mine1, x, y);
                show1[x][y] = count + '0';
                OpenMine1(mine1,show1,row ,col, x,y);
                DisplayBoard1(show1, ROW1, COL1);
                win++;
            }
        }
    }
    if(IsWin1(show1, row, col) == LOW_COUNT)
    {
        printf("恭喜你,扫雷成功!\n");
        DisplayBoard1(show1, ROW1, COL1);
    }
}

void FindMine2(char mine2[ROWS2][COLS2], char show2[ROWS2][COLS2], int row, int col,int count)//扫雷初级
{
    int x = 0;
    int y = 0;
    int win = 0;
    while(wincount)
    {
         FirstSafe2(mine2, show2, row, col);//第一步安全

        if(x>=1 && x<=row && y>=1 && y<=col)
        {
            if(mine2[x][y] == '1')
            {
                printf("很遗憾,你被炸死了!\n");
                DisplayBoard2(mine2, ROW2, COL2);
                break;
            }
            else
            {
                int count = GetMineCount2(mine2, x, y);
                show2[x][y] = count + '0';
                OpenMine2(mine2,show2,row ,col, x,y);
                DisplayBoard2(show2, ROW2, COL2);
                win++;
            }
        }
    }
    if(IsWin2(show2, row, col) == HIGH_COUNT)
    {
        printf("恭喜你,扫雷成功!\n");
        DisplayBoard2(show2, ROW2, COL2);
    }
}

这是程序运行的图片,分别是初级难度和高级难度:
C语言——扫雷游戏_第1张图片

C语言——扫雷游戏_第2张图片

你可能感兴趣的:(C语言——扫雷游戏)