【C】扫雷

目录

一、设计思路

二、函数和宏

三、主函数

四、自定义函数实现 

1、menu(); //菜单

2、init(); //初始化

3、display(); //打印地图

5、play();  //游戏

6、detect(); //输赢检测

五、全部代码

一、设计思路

用两个二维数组,一个表示底层的雷和空地周围雷的数量(字符),一个表示表层的状态(揭开了,未揭开,标记为雷)。遍历判断即可。

二、函数和宏

因为判断格子周围雷的数量时需要判断上下左右的格子,所以我们的底层格子需要比表层的格子大一圈(长度大2),但是为什么我的表层的格子也大了1呢?因为我不打算用下标为0的元素,第一排第一个格子用surface[1][1],表示显得更为直观。

#define ROW 8  //行
#define COL 20 //列

int surface[ROW + 1][COL + 1]; //表层状态
char under[ROW + 2][COL + 2];  //底层状态
int s;                         //雷的总数量
int menu();                    //菜单
void init();                   //初始化
void display();                //打印地图

void play();                  //游戏
int detect();                 //输赢检测

三、主函数

为了实现雷的随机生成,我用到了随机数函数,头文件要用到<stdlib.h>(rand和srand)还要用到time函数生成随机数种子<time.h>(time)。

int main()
{
    srand((unsigned)time(NULL)); 设置随机数种子
    int c = menu();
    char i;
    while (c)
    {
        while (1)
        {
            init();
            while (1)
            {
                display();
                play();
                if (detect())//输或赢会返回1或-1,未结束会返回0
                {
                    display();
                    break;
                }
            }

            if (detect() == 1)
            {
                system("cls");
                puts("恭喜你,获胜了!");
            }
            else if (detect() == -1)
            {

                puts("很遗憾,你输了。");
            }

            Sleep(1000);
            system("pause");
            system("cls");
            puts("是否继续游戏(y/n)");
            fflush(stdin);
            scanf("%c", &i);
            if (i == 'n')
                break;
        }
    }
    return 0;
}

四、自定义函数实现 

1、menu(); //菜单

int menu()
{
    puts("--------------------------");
    puts("   ***    扫雷    ***   ");
    puts("--------------------------");
    puts("--------1.开始游戏--------");
    puts("--------0.退出游戏--------");
    puts("--------------------------");
    int choice = 0;
    puts("请作出你的选择:");
    scanf("%d", &choice);
    return choice;
}

2、init(); //初始化

显然,想要打印出雷的图标只能用字符输出,所以底层的雷是以字符型储存的,那么我们的数字(表示周围的雷)也尽量用字符型储存(数字也不是不行,但输出时要判断有点麻烦)

void init() //传入的参数是为了让玩家输入的第一个位置不是雷
{
    int i, j;
    s = 0; //初始化雷的数量
    for (i = 0; i < ROW + 2; i++)
        for (j = 0; j < COL + 2; j++)
        {
            under[i][j] = ' ';
        }
    for (i = 1; i < ROW + 1; i++) //初始化表层的原因是不止一次
        for (j = 1; j < COL + 1; j++)
        {
            surface[i][j] = 0;
        }
    for (i = 1; i < ROW + 1; i++)
        for (j = 1; j < COL + 1; j++)
        {
            if (rand() % 10 > 5)
            {
                under[i][j] = '*';
                s++;
            }
        }
    int count;
    for (i = 1; i < ROW + 1; i++)
        for (j = 1; j < COL + 1; j++)
        {
            count = 0;
            if (under[i][j] == ' ')
            {
                if (under[i + 1][j] == '*')
                    count++;
                if (under[i][j + 1] == '*')
                    count++;
                if (under[i - 1][j] == '*')
                    count++;
                if (under[i][j - 1] == '*')
                    count++;
                if (under[i + 1][j - 1] == '*')
                    count++;
                if (under[i - 1][j + 1] == '*')
                    count++;
                if (under[i + 1][j + 1] == '*')
                    count++;
                if (under[i - 1][j - 1] == '*')
                    count++;

                under[i][j] = '0' + count;
            }
        }
}

3、display(); //打印地图

底层直接用字符就是舒服。

void display()
{
    int i, j;

    for (i = 1; i <= ROW; i++)
    {
        for (j = 1; j <= COL; j++)
        {
            if (surface[i][j] == 0)
                printf("%c", ' ');
            else if (surface[i][j] == 1) //说明插了旗
                printf("%c", 'R');
            else
                printf("%c", under[i][j]); //说明表层没了打印底层
            printf("|");
        }
        puts("");

        for (j = 1; j <= COL; j++)
        {
            printf("-");
            printf("|");
        }
        puts("");
    }
}

5、play();  //游戏

注意不要“出格”或重复扫。

void play()
{
    char ch;
    int x, y;
    fflush(stdin);
    puts("请问你是排雷(a)还是标记雷(d)(输入a/d)(排雷会清除标记)");
    scanf("%[ad]c", &ch);
    puts("请输入排雷或标记雷的坐标(例:1,2)");
    while (scanf("%d,%d", &x, &y))
        if (x > 0 && y > 0 && x < ROW + 1 && y < COL + 1)//不能超出范围
        {
            if (surface[x][y] != -1) //排除已揭开的雷
            {
                if (ch == 'a')
                    surface[x][y]--;
                else
                    surface[x][y] = 1;
                break;
            }
            else
                puts("此位置已揭开");
        }
        else
            puts("没有这个位置");
}

6、detect(); //输赢检测

检测时要注意标记错的地方要要“减分”,如果只是找是否全部雷被标记,那么我从头标到尾也会赢。

int detect()
{
    int count = 0;
    int i, j;
    for (i = 1; i < ROW + 1; i++)
        for (j = 0; j < COL + 1; j++)
        {
            if (under[i][j] == '*' && surface[i][j] == -1)
                count++;
        }
    if (count)
        return -1;

    for (i = 1; i < ROW + 1; i++)
        for (j = 0; j < COL + 1; j++)
        {
            if (under[i][j] == '*' && surface[i][j] == 1)
                count++;
            if (under[i][j] == ' ' && surface[i][j] == 1)
                count--;
        }
    if (count == s) //全部被标记
        return 1;
    else
        return 0;
}

五、全部代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#define ROW 8  //行
#define COL 20 //列

int surface[ROW + 1][COL + 1]; //表层状态
char under[ROW + 2][COL + 2];  //底层状态
int s;                         //雷的数量
int menu();                    //菜单
void init();                   //初始化
void display();                //打印地图

void play();  //游戏
int detect(); //输赢检测

int main()
{
    srand((unsigned)time(NULL)); 设置随机数种子
    int c = menu();
    char i;
    while (c)
    {
        while (1)
        {
            init();
            while (1)
            {
                display();
                play();
                if (detect())
                {
                    display();
                    break;
                }
            }

            if (detect() == 1)
            {
                system("cls");
                puts("恭喜你,获胜了!");
            }
            else if (detect() == -1)
            {

                puts("很遗憾,你输了。");
            }

            Sleep(1000);
            system("pause");
            system("cls");
            puts("是否继续游戏(y/n)");
            fflush(stdin);
            scanf("%c", &i);
            if (i == 'n')
                break;
        }
    }
    return 0;
}

void init() //传入的参数是为了让玩家输入的第一个位置不是雷
{
    int i, j;
    s = 0; //初始化雷的数量
    for (i = 0; i < ROW + 2; i++)
        for (j = 0; j < COL + 2; j++)
        {
            under[i][j] = ' ';
        }
    for (i = 1; i < ROW + 1; i++) //初始化表层的原因是不止一次
        for (j = 1; j < COL + 1; j++)
        {
            surface[i][j] = 0;
        }
    for (i = 1; i < ROW + 1; i++)
        for (j = 1; j < COL + 1; j++)
        {
            if (rand() % 10 > 5)
            {
                under[i][j] = '*';
                s++;
            }
        }
    int count;
    for (i = 1; i < ROW + 1; i++)
        for (j = 1; j < COL + 1; j++)
        {
            count = 0;
            if (under[i][j] == ' ')
            {
                if (under[i + 1][j] == '*')
                    count++;
                if (under[i][j + 1] == '*')
                    count++;
                if (under[i - 1][j] == '*')
                    count++;
                if (under[i][j - 1] == '*')
                    count++;
                if (under[i + 1][j - 1] == '*')
                    count++;
                if (under[i - 1][j + 1] == '*')
                    count++;
                if (under[i + 1][j + 1] == '*')
                    count++;
                if (under[i - 1][j - 1] == '*')
                    count++;

                under[i][j] = '0' + count;
            }
        }
}
void display()
{
    int i, j;

    for (i = 1; i <= ROW; i++)
    {
        for (j = 1; j <= COL; j++)
        {
            if (surface[i][j] == 0)
                printf("%c", ' ');
            else if (surface[i][j] == 1) //说明插了旗
                printf("%c", 'R');
            else
                printf("%c", under[i][j]); //说明表层没了打印底层
            printf("|");
        }
        puts("");

        for (j = 1; j <= COL; j++)
        {
            printf("-");
            printf("|");
        }
        puts("");
    }
}
void play()
{
    char ch;
    int x, y;
    fflush(stdin);
    puts("请问你是排雷(a)还是标记雷(d)(输入a/d)(排雷会清除标记)");
    scanf("%[ad]c", &ch);
    puts("请输入排雷或标记雷的坐标(例:1,2)");
    while (scanf("%d,%d", &x, &y))
        if (x > 0 && y > 0 && x < ROW + 1 && y < COL + 1)//不能超出范围
        {
            if (surface[x][y] != -1) //排除已揭开的雷
            {
                if (ch == 'a')
                    surface[x][y]--;
                else
                    surface[x][y] = 1;
                break;
            }
            else
                puts("此位置已揭开");
        }
        else
            puts("没有这个位置");
}
int detect()
{
    int count = 0;
    int i, j;
    for (i = 1; i < ROW + 1; i++)
        for (j = 0; j < COL + 1; j++)
        {
            if (under[i][j] == '*' && surface[i][j] == -1)
                count++;
        }
    if (count)
        return -1;

    for (i = 1; i < ROW + 1; i++)
        for (j = 0; j < COL + 1; j++)
        {
            if (under[i][j] == '*' && surface[i][j] == 1)
                count++;
            if (under[i][j] == ' ' && surface[i][j] == 1)
                count--;
        }
    if (count == s) //全部被标记
        return 1;
    else
        return 0;
}
int menu()
{
    puts("--------------------------");
    puts("   ***    扫雷    ***   ");
    puts("--------------------------");
    puts("--------1.开始游戏--------");
    puts("--------0.退出游戏--------");
    puts("--------------------------");
    int choice = 0;
    puts("请作出你的选择:");
    scanf("%d", &choice);
    return choice;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值