扫雷游戏。

头文件: game.h

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>

#define ROW 10 // 棋盘的行与列数
#define LIN 10

#define ROWS ROW+2 // 数组的行与列数
#define LINS LIN+2    

#define NUMBERMINE 10// 雷的个数

// 打印游戏菜单
void meau();

// 具体的扫雷游戏的逻辑
void game();

// 初始化数组
void init_board(char board[ROWS][LINS], int rows, int lins);

// 生成雷
void creat_mine(char board[ROWS][LINS], int row, int lin);

//打印数组,检查是否生成10个雷
void print_board(char board[ROWS][LINS], int row, int lin);

// 存储雷的数量
// 根据board1将数据存储在board2中
void number_mine(char board1[ROWS][LINS], int row, int lin);

// 判断该位置周围雷的数量,并以字符的形式返回
char how_much_mine(char board[ROWS][LINS], int x, int y);

//打印棋盘 
void print_mine_board(char board[ROWS][LINS], int row, int lin);

//该位置雷的个数为0个,则需要扩散
void kuo_san(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int x, int y);

//完全扩散
void wanquan_kuosan(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int x, int y, int row, int lin);

//将雷的位置纪录的打印的棋盘上
void writre_mine(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int row, int lin);

//记录标雷的个数
int number_flag(char mine_board[ROWS][LINS], int row, int lin);

//判断标记的位置与雷的位置匹配的个数
int flag_win(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int row, int lin);

//用来查看棋盘的使用个数
int number_of_x(char mine_board[ROWS][LINS], int row, int lin);

游戏代码: game.c

#define _CRT_SECURE_NO_WARNINGS 
#include"game.h"

// 打印游戏菜单
void meau()
{
    printf("******************\n");
    printf("*****1. play *****\n");
    printf("*****0. exit *****\n");
    printf("******************\n");
}

// 具体的扫雷游戏的逻辑
void game()
{
    printf("欢迎进入扫雷游戏,祝您游戏愉快!!\n");
    // 首先生成雷,并用数组mine[ROWS][LINS] 存储,雷用字符1表示,非雷用字符0表示
    char mine[ROWS][LINS] = { 0 };

    // 初始化数组
    init_board(mine,ROWS,LINS,'0');

    // 生成雷
    srand((unsigned int)time(NULL));
    creat_mine(mine,  ROW, LIN);

    // 打印数组,检查是否生成10个雷
    //print_board(mine, ROW, LIN); // 测试:成功生成NUMBERMINE个雷

    // 存储每个格子周围雷的数量
    number_mine(mine, ROW, LIN);
    // 打印数组,测试雷的数量是否存储成功
    //printf("底层数据:\n");
    //print_board(mine, ROW, LIN); // 成功

    //用于界面显示的扫雷数组
    char mine_board[ROWS][LINS] = { 0 };
    //初始化数组
    init_board(mine_board, ROWS, LINS,'*');
    //打印数组
    //print_board(mine_board, ROW, LIN);
    

    // 先打印棋盘 
    print_mine_board(mine_board, ROW, LIN);
    // 第一次点击
    int x0 = 0;
    int y0 = 0;
    int flag0 = 0;
    printf("请选择位置点击或标记:\n");
    printf("例如您要点击(4,5)处 ,则输入4 5 1\n");
    printf("例如您要标记(4,5)处 ,则输入4 5 2\n");
    scanf(" %d %d %d", &x0, &y0, &flag0);
    //第一次使用只能选择点击模式,保证第一次点击至少扩散出NUMBERMINE格子以上
    //可以用扩散的格子数来控制循环
    int ksn = 0;
    while (ksn <= NUMBERMINE)
    {
        // 先打印棋盘 
        print_mine_board(mine_board, ROW, LIN);
        //若点击的位置mine不为0,则重新生成mine
        if (mine[x0][y0] != '0')
        {
            // 重新初始化数组
            init_board(mine, ROWS, LINS, '0');
            //重新生成雷
            creat_mine(mine, ROW, LIN);
            //重新生成雷数
            number_mine(mine, ROW, LIN);
            continue;
        }
        if(mine[x0][y0] == '0')
        {
            //若点击的位置为0;则要判断是否满足大于NUMBERMINE
            printf("底层数据:\n");
            print_board(mine, ROW, LIN);
            wanquan_kuosan(mine, mine_board, x0, y0, ROW, LIN);
            ksn = number_of_x(mine_board, ROW, LIN);
            if (ksn > 10)
            {
                break;
            }
            else
            {
                // 重新初始化数组
                init_board(mine, ROWS, LINS, '0');
                //重新生成雷
                creat_mine(mine, ROW, LIN);
                //重新生成雷数
                number_mine(mine, ROW, LIN);
                //棋盘也要初始化
                init_board(mine_board, ROWS, LINS, '*');
                continue;
            }
        }

    }

    
    while (1)
    {
        // 先打印棋盘 
        print_mine_board(mine_board, ROW, LIN);
        // 然后选择位置点击
        // 点击的位置必须是未没点击过且没有被>标记过
        int x = 0;
        int y = 0;
        int flag = 0;
        printf("请选择位置点击或标记:\n");
        printf("例如您要点击(4,5)处 ,则输入4 5 1\n");
        printf("例如您要标记(4,5)处 ,则输入4 5 2\n");
        scanf(" %d %d %d", &x, &y, &flag);

        // 若选择点击模式
        if (flag == 1)
        {
            //首先判断是否被点击或标记过,若被点击或过,直接跳入下一次循环
            if (mine_board[x][y] == '*')
            {
                //判断是否是雷,
                //若是雷,游戏结束
                if (mine[x][y] != '9')
                {
                    // 若不是雷,则显示该位置雷的个数
                    // 若该位置雷的个数为0,则显示周围的位置
                    if (mine[x][y] > '0')//该位置雷的个数不为0
                    {
                        //将雷的个数存储到mine_board中,并同时记录该位置已经被点击过
                        mine_board[x][y] = mine[x][y];
                        //之后打印棋盘
                        print_mine_board(mine_board, ROW, LIN);
                        //之后进入下一个循环
                        continue;
                    }
                    else//该位置周围无雷
                    {
                        //该位置雷的个数为0个,则需要扩散
                        //kuo_san(mine, mine_board, x, y);
                        // 从本位开始,直到扩散本位周围没有0为止
                        wanquan_kuosan(mine, mine_board, x, y, ROW, LIN);
                        // 扩散完之后打印棋盘
                        print_mine_board(mine_board, ROW, LIN);
                        continue;
                    }
                }
                else
                {
                    // 该位置是雷
                    // 则显示已经点击过的位置,并且将雷的位置显示出来
                    // 打印出的雷用@
                    printf("很遗憾,你败了,真是个废物0.0\n");
                    printf("废物看好了,看好你是怎么输的\n");
                    //将雷的位置纪录的打印的棋盘上
                    writre_mine(mine,mine_board,ROW,LIN);
                    //记录完之后打印棋盘
                    print_mine_board(mine_board, ROW, LIN);
                    break;
                }
            }
            else
            {
                printf("对不起,此位置已被点击过,请重新点击\n");
                continue;
            }
        }
        //若选择标记模式
        if (flag == 2)
        {
            //此位置之前未被标记过
            if (mine_board[x][y] == '*')
            {
                //记录标雷的个数,如果雷大于NUMBERMINE个,则无法继续标记
                int number = number_flag(mine_board, ROW, LIN);
                // 最多标记NUMBERMINE个雷
                if (number < NUMBERMINE)
                {
                    mine_board[x][y] = '>';
                    //当标记满十个以后,判断输赢
                    if ((number + 1) == NUMBERMINE)
                    {
                        //若赢了则恭喜
                        //若标记的NUMBERMINE个位置与雷的位置不符合,则不显示,知道标记的位置与显示的位置沾满整个棋盘,则提示您可能标记错误
                        //先判断赢的情况1
                        int win = flag_win(mine, mine_board, ROW, LIN);
                        if (win == NUMBERMINE)
                        {
                            printf("恭喜你,游戏通关\n");
                            print_mine_board(mine_board, ROW, LIN);
                            break;
                        }
                        //棋盘满了的情况,标记的位置+显示的位置是满的,此种情况获胜,被上面的情况所包含
                    }
                    continue;
                }
                else
                {
                    printf("对不起,最多只能标记 %d 个位置\n", NUMBERMINE);
                    continue;
                }
            }
            //若标记过则解除标记状态
            if (mine_board[x][y] == '>')
            {
                mine_board[x][y] = '*';
                continue;
            }
        }
    }

}

// 初始化数组
void init_board(char board[ROWS][LINS],int rows,int lins,char ch)
{
    int i = 0;
    int j = 0;
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < lins; j++)
        {
            board[i][j] = ch;
        }
    }
}

// 生成雷
// 有雷的地方用9表示
void creat_mine(char board[ROWS][LINS], int row, int lin)
{
    int i = 0;
    int j = 0;
    // 统计雷的个数
    int count = 0;
    while (1)
    {
        // 生成随机的坐标用来放雷
        i = (rand() % row) + 1;
        j = (rand() % lin) + 1;
        if (board[i][j] == '0')
        {
            board[i][j] = '9';
            count++;
        }
        if (count == NUMBERMINE)
        {
            break;
        }
    }
}

//打印数组,检查是否生成10个雷
void print_board(char board[ROWS][LINS], int row, int lin)
{
    int i = 0;
    int j = 0;
    for (i = 1; i <= row; i++)
    {
        for (j = 1; j <= lin; j++)
        {
            printf("%c  ", board[i][j]);
        }
        printf("\n");
    }
}

// 存储雷的数量
// 根据board1将数据存储在board1中
void number_mine(char board[ROWS][LINS], int row, int lin)
{
    int i = 0;
    int j = 0;
    for (i = 1; i <= row; i++)
    {
        for (j = 1; j <= lin; j++)
        {
            //将该位置雷的个数以字符的形式存储在
            if (board[i][j] != '9')
            {
                board[i][j] = how_much_mine(board, i, j);
            }
        }
    }
}

// 判断该位置周围雷的数量,并以字符的形式返回
char how_much_mine(char board[ROWS][LINS], int x, int y)
{
    int sum = 0;
    sum = board[x-1][y-1] + board[x][y-1] + board[x+1][y-1] + 
        board[x-1][y] + board[x+1][y] + 
        board[x-1][y+1] + board[x][y+1] + board[x+1][y+1];
    sum = sum - (48 * 8);
    return ((sum / 9) + 48);
}

//打印棋盘 
void print_mine_board(char board[ROWS][LINS], int row, int lin)
{
    int i = 0;
    int j = 0;
    //打印列数
    for (j = 1; j <= lin; j++)
    {
        if (j == 1)
        {
            printf("    %-2d", j);
            continue;
        }
        printf("  %-2d", j);
    }
    printf("\n");
    //打印上边界
    for (j = 1; j <= lin; j++)
    {
        if (j == 1)
        {
            printf("   ---");
            continue;
        }
        printf(" ---");
    }
    printf("\n");
    //打印剩下的网格
    for (i = 1; i <= row; i++)
    {
        for (j = 1; j <= lin; j++)
        {
            if (j == 1)
            {
                printf("%-2d| %c |",i,board[i][j]);
                continue;
            }
            printf(" %c |", board[i][j]);
        }
        printf("\n");
        for (j = 1; j <= lin; j++)
        {
            if (j == 1)
            {
                printf("   ---");
                continue;
            }
            printf(" ---");
        }
        printf("\n");
    }
}

//该位置雷的个数为0个,则需要扩散
void kuo_san(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int x, int y)
{
    //要保证扩散的同时也要标记扩散的那些位置标记已经被使用过
    if (mine[x][y] == '0')
    {
        int i = x;
        int j = y;
        for (i = x - 1; i <= x + 1; i++)
        {
            for (j = y - 1; j <= y + 1; j++)
            {
                //标记的假定被认为是雷,此时不需要扩散
                if (mine_board[i][j] != '>')
                {
                    //若周围没有标记,则为0的地方显示空格
                    //是数字则显示数字
                    if (mine[i][j] == '0' || mine[i][j] ==' ')
                    {
                        mine_board[i][j] = ' ';
                    }
                    else
                    {
                        mine_board[i][j] = mine[i][j];
                    }
                }
            }
        }
    }
}

//完全扩散
void wanquan_kuosan(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int x, int y,int row,int lin)
{
    //若本位不为0 或者为‘ ’时也不需要扩散 或被标记过,则不需要扩散
    if (mine[x][y] != '0' || mine_board[x][y] == '>' || mine[x][y] == ' ' || mine[x][y] == '9')
    {
        return;
    }
    //先让本位扩散一边,然后标记一下,本位扩散过
    kuo_san(mine, mine_board, x, y);
    mine[x][y] = ' ';
    int i = 0;
    int j = 0;
    for (i = x - 1; i <= x + 1; i++)
    {
        for (j = y - 1; j <= y + 1; j++)
        {
            //保证在棋盘内
            if (((i>=1)&&(i<=row))&&((j>=1)&&(j<=lin)))
            {
                if ((mine[i][j] != ' ') && (mine[i][j] == '0'))
                {
                    kuo_san(mine, mine_board, i, j);
                    wanquan_kuosan(mine, mine_board, i, j, ROW, LIN);
                }
            }

        }
    }
}

//将雷的位置纪录的打印的棋盘上
void writre_mine(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int row, int lin)
{
    int i = 0;
    int j = 0;
    for (i = 1; i <= row; i++)
    {
        for (j = 1; j <= lin; j++)
        {
            if (mine[i][j] == '9')
            {
                //如果此位置时雷,则记录到打印的棋盘中
                mine_board[i][j] = '@';
            }
        }
    }
}

//记录标雷的个数
int number_flag(char mine_board[ROWS][LINS], int row, int lin)
{
    int i = 0;
    int j = 0;
    int count = 0;
    for (i = 1; i <= row; i++)
    {
        for (j = 1; j <= lin; j++)
        {
            if (mine_board[i][j] == '>')
            {
                count++;
            }
        }
    }
    return count;
}

//判断标记的位置与雷的位置匹配的个数
int flag_win(char mine[ROWS][LINS], char mine_board[ROWS][LINS], int row, int lin)
{
    int i = 0;
    int j = 0;
    int count = 0;
    for (i = 1; i <= row; i++)
    {
        for (j = 1; j <= lin; j++)
        {
            if ((mine[i][j] == '9') && (mine_board[i][j] == '>'))
            {
                count++;
            }
        }
    }
    return count;
}

//用来查看棋盘的使用个数
int number_of_x(char mine_board[ROWS][LINS], int row, int lin)
{
    int i = 0;
    int j = 0;
    int count = 0;
    for (i = 1; i <= row; i++)
    {
        for (j = 1; j <= lin; j++)
        {
            if (mine_board[i][j] != '*')
            {
                count++;
            }
        }
    }
    return count;
}



代码实现:test.c

#define _CRT_SECURE_NO_WARNINGS 
#include"game.h"

int main()
{
    //输入选择游戏模式
    int input = 0;
    do
    {
        printf("============================================================\n");
        meau();
        printf("请输入您要选择的模式 :\n");
        scanf(" %d", &input);
        switch (input)
        {
        case 1:
            //具体的扫雷游戏的逻辑
            //printf("玩游戏\n");
            game();
            break;
        case 0:
            printf("已成功退出扫雷游戏,谢谢使用\n");
            break;
        default:
            printf("对不起,您输入的模式非法!\n");
            break;
        }
    }
    while(input);
    return 0;
}

  • 15
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值