鱼C论坛

 找回密码
 立即注册
查看: 1021|回复: 6

[技术交流] 扫雷游戏

[复制链接]
发表于 2020-5-21 16:12:27 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 就是要努力呀 于 2020-5-21 16:13 编辑
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

void menu(int *map_x, int *map_y);        //主菜单
char **make_map(int map_x, int map_y);        //生成地图
char **make_mine_map(int mine_x, int mine_y, int mine_num);        //生成地雷地图
void print_all_map(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y);        //打印地图
int begin_game(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int mine_num);        //开始游戏
int open_place(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int x, int y);        //打开玩家选择的位置
void expand(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int x, int y);        //通过递归方式实现扫雷的扩展功能,游戏最重要的部分
int check_mine(char **mine_map, int mine_x, int mine_y, int x, int y);        //检测一个位置周围8格以内的地雷数
int check_win(char **map, int mine_x, int mine_y, int mine_num);        //检测是否赢得游戏
void win(char **map, int map_x, int map_y);        //赢得游戏,打印所有地雷所在位置

void win(char **map, int map_x, int map_y)
{
        int i, j;

        for(i = 0; i < map_x; i++)
        {
                for(j = 0; j < map_y; j++)
                {
                        if(map[i][j] == '+')
                        {
                                map[i][j] = '@';
                        }

                        printf("%c ", map[i][j]);
                }

                putchar('\n');
        }
}

int check_win(char **map, int mine_x, int mine_y, int mine_num)
{
        int i, j;
        int num = 0;

        for(i = 1; i < mine_x; i++)
        {
                for(j = 1; j < mine_y; j++)
                {
                        if(map[i][j] == '+')
                        {
                                num++;
                        }
                }
        }

        if(num == mine_num)
        {
                printf("恭喜你赢了\n");

                return 1;
        }

        return 0;
}

int check_mine(char **mine_map, int mine_x, int mine_y, int x, int y)
{
        int num = 0;

        //判断该位置周围8格的地雷数

        if(x - 1 > 0 && mine_map[x - 1][y] == '@')
        {
                num++;
        }

        if(x + 1 < mine_x && mine_map[x + 1][y] == '@')
        {
                num++;
        }

        if(y - 1 > 0 && mine_map[x][y - 1] == '@')
        {
                num++;
        }

        if(y + 1 < mine_y && mine_map[x][y + 1] == '@')
        {
                num++;
        }

        if(x - 1 > 0 && y - 1 > 0 && mine_map[x - 1][y - 1] == '@')
        {
                num++;
        }

        if(x - 1 > 0 && y + 1 < mine_y && mine_map[x - 1][y + 1] == '@')
        {
                num++;
        }

        if(x + 1 < mine_x && y + 1 < mine_x && mine_map[x + 1][y + 1] == '@')
        {
                num++;
        }

        if(x + 1 < mine_x && y - 1 > 0 && mine_map[x + 1][y - 1] == '@')
        {
                num++;
        }

        return num;
}

void expand(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int x, int y)
{
        int num; 
        
        if(!(num = check_mine(mine_map, mine_x, mine_y, x, y)))        //判断这个位置的周围8格是否有地雷,如果有将该位置设置为地雷数,并停止对该位置后续的展开
        {
                map[x][y] = ' ';
                
                //向该位置的8个方向进行展开

                if(x - 1 > 0 && map[x - 1][y] == '+')
                {
                        expand(map, map_x, map_y, mine_map, mine_x, mine_y, x - 1, y);
                }

                if(x + 1 < mine_x && map[x + 1][y] == '+')
                {
                        expand(map, map_x, map_y, mine_map, mine_x, mine_y, x + 1, y);
                }

                if(y - 1 > 0 && map[x][y - 1] == '+')
                {
                        expand(map, map_x, map_y, mine_map, mine_x, mine_y, x, y - 1);
                }

                if(y + 1 < mine_y && map[x][y + 1] == '+')
                {
                        expand(map, map_x, map_y, mine_map, mine_x, mine_y, x, y + 1);
                }
                
                if(x - 1 > 0 && y - 1 > 0 && map[x - 1][y - 1] == '+')
                {
                        expand(map, map_x, map_y, mine_map, mine_x, mine_y, x - 1, y - 1);
                }

                if(x - 1 > 0 && y + 1 < mine_y && map[x - 1][y + 1] == '+')
                {
                        expand(map, map_x, map_y, mine_map, mine_x, mine_y, x - 1, y + 1);
                }
                
                if(x + 1 < mine_x && y + 1 < mine_y && map[x + 1][y + 1] == '+')
                {
                        expand(map, map_x, map_y, mine_map, mine_x, mine_y, x + 1, y + 1);
                }

                if(x + 1 < mine_x && y - 1 > 0 && map[x + 1][y - 1] == '+')
                {
                        expand(map, map_x, map_y, mine_map, mine_x, mine_y, x + 1, y - 1);
                }
        }
        else 
        {
                map[x][y] = num + 48;
        }
}

int open_place(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int x, int y)
{
        if(mine_map[x][y] == '@')
        {
                printf("游戏结束!\n");

                return 0;
        }
        else if(mine_map[x][y] == '+')
        {
                expand(map, map_x, map_y, mine_map, mine_x, mine_y, x, y);        //如果玩家选中的位置没有踩雷,就需要展它周围的空位置

                return 1;
        }

        return 1;
}

int begin_game(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y, int mine_num)
{
        char x = ' ', y = ' ';
        char choose;
        static int num = 0;

        do
        {
                printf("总地雷数:%d 当前地雷数:%d\n", mine_num, mine_num - num);
                printf("请输入行和列(qq退出游戏):");
                scanf("%c %c", &x, &y);
                getchar();

                if(x == 'q' && y == 'q')
                {
                        exit(0);
                }
        }
        while(x < '0' || y < '0' || x > (char)(map_x - 2 + 48) || y > (char)(map_y - 2 + 48));

        do
        {
                printf("1.打开:2.标记:3.取消标记:4.重新选择\n");
                printf("请选择你要执行的命令:");
                choose = getchar();
                getchar();
        }
        while(choose != '1' && choose != '2' && choose != '3');

        switch(choose)
        {
                case '1':
                        {
                                return open_place(map, map_x, map_y, mine_map, mine_x, mine_y, (int)x - 48, (int)y - 48);        //因为我们的x和y设置的是字符型,要将他强制转换成int型,方便open_place函数定位
                        }
                case '2':
                        {
                                num++;

                                map[(int)x - 48][(int)y - 48] =        '^'; 

                                break;
                        }

                case '3':
                        {
                                num--;

                                map[(int)x - 48][(int)y - 48] = '+';

                                break;
                        }
                case '4':
                        {
                                break;
                        }
        }
}

void print_all_map(char **map, int map_x, int map_y, char **mine_map, int mine_x, int mine_y)
{
        int i, j;

        for(i = 0; i < map_x; i++)
        {
                for(j = 0; j < map_y; j++)
                {
                        printf("%c ", map[i][j]);
                }

                putchar('\n');
        }
        
        /*for(i = 0; i < mine_x; i++)
        {
                for(j = 0; j < mine_y; j++)
                {
                        printf("%c ", mine_map[i][j]);
                }

                putchar('\n');
        }*/

}

char **make_mine_map(int mine_x, int mine_y, int mine_num)
{
        char **mine_map;
        int i, j;
        int x, y;
        int num = 0;

        mine_map = (char **)malloc(sizeof(char *) * mine_x);

        for(i = 0; i < mine_x; i++)
        {
                mine_map[i] = (char *)malloc(sizeof(char) * mine_y);
        }

        srand(time(NULL));

        for(i = 0; i < mine_x; i++)
        {
                for(j = 0; j < mine_y; j++)
                {
                        mine_map[i][j] = '+';
                }
        }

        while(num < mine_num)
        {
                do
                {
                        x = rand()%(mine_x - 1) + 1;
                        y = rand()%(mine_y - 1) + 1;
                }
                while(mine_map[x][y] != '+');

                mine_map[x][y] = '@';

                num++;
        }

        return mine_map;
}

char **make_map(int map_x, int map_y)
{
        char **map;
        int i, j, k = 1;

        map = (char **)malloc(sizeof(char *) * map_x);

        for(i = 0; i < map_x; i++)
        {
                map[i] = (char *)malloc(sizeof(char) * map_y);
        }

        for(i = 0; i < map_x - 1; i++)
        {
                map[i][0] = i + 48;
        }

        for(j = 0; j < map_y - 1; j++)
        {
                map[0][j] = j + 48;
        }

        for(i = 1; i < map_x - 1; i++)
        {
                for(j = 1; j < map_y - 1; j++)
                {
                        map[i][j] = '+';
                }
        }
        
        return map;
}

void menu(int *map_x, int *map_y)
{
        char choose;

        do
        {
                printf("********************1.开始游戏*******************\n");
                printf("********************2.退出游戏*******************\n");
                printf("请选择:");
                choose = getchar();
                getchar();
        }
        while(choose != '1' && choose != '2');

        if(choose == '1')
        {
                do
                {
                        printf("1.初级:2.中级:3.高级:4.自定义");
                        printf("请选择:");
                        choose = getchar();
                        getchar();
                }
                while(choose != '1' && choose != '2' && choose != '3' && choose != '4');

                switch(choose)
                {
                        case '1':
                                {
                                        *map_x = 12;
                                        *map_y = 12;
                                        break;
                                }

                        case '2':
                                {
                                        *map_x = 22;
                                        *map_y = 22;
                                        break;
                                }

                        case '3':
                                {
                                        *map_x = 42;
                                        *map_y = 42;
                                        break;
                                }

                        case '4':
                                {
                                        do
                                        {
                                                printf("请输入行:");
                                                scanf("%d", map_x);
                                                getchar();
                                        }
                                        while(*map_x <= 0 || *map_x > 100);

                                        do
                                        {
                                                printf("请输入列:");
                                                scanf("%d", map_y);
                                                getchar();
                                        }
                                        while(*map_y <= 0 || *map_y > 100);

                                        *map_x += 2;
                                        *map_y += 2;
                                }
                }
        }
        else exit(0);
}

int main(void)
{
        int map_x, map_y;

        menu(&map_x, &map_y);

        char **map;        //设置一个二级指针来接受返回的动态二维数组

        map = make_map(map_x, map_y);        //为了使得行列可以自定义,用动态申请二维数组的方法

        char **mine_map;        //同样的方法设置一个地雷地图的二级指针
        int mine_x = map_x - 1;        //设置地雷地图的行列
        int mine_y = map_y - 1;
        int mine_num = mine_x + mine_y - 4;         //设置地雷数

        mine_map = make_mine_map(mine_x, mine_y, mine_num);        //动态申请一个二维数组

        do
        {
                print_all_map(map, map_x, map_y, mine_map, mine_x, mine_y);        //打印地图

                if(check_win(map, mine_x, mine_y, mine_num))        //玩家每走一步就检测是否赢得比赛
                {
                        win(map, map_x, map_y); 

                        break;
                }
        }
        while(begin_game(map, map_x, map_y, mine_map, mine_x, mine_y, mine_num));        //begin_game该游戏的主要函数


        return 0;
}

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +3 收起 理由
zyh1104 + 5 + 5 + 3 鱼C有你更精彩^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-5-22 10:23:50 | 显示全部楼层
这是原创吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-5-22 15:02:21 | 显示全部楼层

嗯自己写的,写了三个半天。裂开了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-22 15:28:36 | 显示全部楼层
就是要努力呀 发表于 2020-5-22 15:02
嗯自己写的,写了三个半天。裂开了

很厉害
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-5-24 18:41:45 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-25 00:32:17 | 显示全部楼层
学习到了!顶
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-5-25 10:41:05 From FishC Mobile | 显示全部楼层
糖逗 发表于 2020-5-25 00:32
学习到了!顶

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-14 02:31

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表