练习时长两年半的扫雷

这篇具有很好参考价值的文章主要介绍了练习时长两年半的扫雷。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

设计思路

游戏运行效果

函数的声明

头文件game.h

游戏主体(源文件)

1.game.c

2.test.c

各文件的阐述

各部分设计心得

1.打印菜单

2.初始化雷池

3.打印雷池以及玩家界面

打印效果

如何改变雷的数量与雷池大小

4.生成随机雷

5.排雷与对局判断

对于越界的看法


设计思路

1.菜单

2.棋盘  需要一个9 * 9 的数组  为了防止越界可以用11 * 11  游戏的实现用11 * 11  玩家看到的则是9 * 9

3.布置雷   非雷 '0'   雷'1'   这里的 零 一 均为字符

4.排查雷  玩家输入坐标  非雷周围一圈的坐标有几个雷就将坐标显示替换为该数

5.判断输赢 全部雷排序除即胜利

游戏运行效果

练习时长两年半的扫雷

 练习时长两年半的扫雷

这里就不把全部雷排完了,需要一定时间,待会的心得我会分享一个非常舒服的测试小技巧

函数的声明

头文件game.h

#define _CRT_SECURE_NO_WARNINGS 1


#include <stdio.h>

#include<time.h>


#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2


#define EASY_COUNT 10           //雷的个数


//设计思路
//1.选择菜单
//2.棋盘  需要一个9 * 9 的数组   为了越界可以用11 * 11 游戏的实现用11 * 11   玩家看到的则是9 * 9
//3.布置雷   非雷 '0'   雷'1'    这里的 零 一 均为字符
//4.排查雷    玩家输入坐标   非雷周围一圈的坐标有几个雷就显示几
//5.判断输赢     全部雷排序除即胜利







//打印菜单
void menu();

//初始化棋盘   1.游戏内部棋盘    2.玩家棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ch);


//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);

//布置雷
void SetMine(char Mine[ROWS][COLS], int row, int col);

//排查雷
void FindMine(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col);
int Find(char Mine[ROWS][COLS], int row, int col);

游戏主体(源文件)

1.game.c

#define _CRT_SECURE_NO_WARNINGS 1


#include "game.h"





void InitBoard(char board[ROWS][COLS], int rows, int cols, char ch)
{
    int i = 0;
    for (i = 0; i < rows; i++)  //注意取值范围  不要越界
    {
        int j = 0;
        for (j = 0; j < cols; j++)
        {
            board[i][j] = ch;
        }
    }
}



//注意:需要打印的坐标是x与y的范围是 1-9
//故循环中的 i 与 j 不要初始化为 0  避免后面布置雷的个数一直不对

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
    int x = 0;
    printf("------扫雷游戏------\n");

    for (x = 0; x <= row; x++)
    {
        printf("%d ", x);
    }
    printf("\n");



    int i = 1;
    int j = 1;
    for (i = 1; i <= row; i++)
    {

        printf("%d", i);

        for (j = 1; j <= col; j++)
        {
            printf(" %c", board[i][j]);
        }

        printf("\n");
    }
}




//注意:随机数的生成要在循环内部  每次判断前都要生成一次
//否则坐标字符一直为'1'  会出现死循环   

void SetMine(char Mine[ROWS][COLS], int row, int col)
{


    int count = EASY_COUNT;

    while (count)
    {
        int x = rand() % row + 1;
        int y = rand() % row + 1;

        if (Mine[x][y] == '0')
        {
            Mine[x][y] = '1';
            count--;
        }
    }

}



int Find(char Mine[ROWS][COLS], int x, int y)
{
    return(Mine[x - 1][y - 1] + Mine[x - 1][y] + Mine[x - 1][y + 1] + Mine[x][y - 1] + Mine[x][y + 1] + Mine[x + 1][y - 1] + Mine[x + 1][y] + Mine[x + 1][y + 1] - 8 * '0');
}


void FindMine(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col)
{
    int x = 0;
    int y = 0;
    int win = 0;
    char Visited[ROWS][COLS];    //用来存放已经输入过的坐标
    while (win < row * col - EASY_COUNT)
    {
        printf("请输入坐标:>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 1 && y <= col)
        {
            if (Mine[x][y] == '1')
            {
                printf("很遗憾,你被炸死了\n");
                DisplayBoard(Mine, ROW, COL);
                break;
            }
            if (Visited[x][y] == '1')
            {
                printf("该坐标已排查过,请重新输入\n");
                continue;
            }
            else
            {
                int count = Find(Mine, x, y);
                Show[x][y] = count + '0';
                DisplayBoard(Show, ROW, COL);
                win++;
                Visited[x][y] = '1';
            }

         

        }
        else
        {
            printf("坐标非法,请重新输入\n");
        }
    }
    if (win == row * col - EASY_COUNT)
    {
        printf("恭喜你,排雷成功\n");
        DisplayBoard(Mine, ROW, COL);
    }

}

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 game()
{

    char Mine[ROWS][COLS];//存放布置好的雷
    char Show[ROWS][COLS];//存放排查出的雷的信息  即玩家页面

        //初始化棋盘
    InitBoard(Mine, ROWS, COLS, '0');
    InitBoard(Show, ROWS, COLS, '*');

    //打印棋盘
    DisplayBoard(Show, ROW, COL);

    //布置雷
    SetMine(Mine, ROW, COL);
    DisplayBoard(Mine, ROW, COL);

    //排查雷
    FindMine(Mine, Show, ROW, COL);

}

int main()
{
    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);
    return 0;
}

各文件的阐述

game.h头文件用来声明函数
game.c游戏功能的实现
test调用game.c的函数,用于运行测试

分文件写代码可以很好的避免被开源

把game.c改为静态库  使用时导入静态库即可  

各部分设计心得

1.打印菜单

封装一个专门打印菜单的函数,后期想要美化菜单直接在函数修改即可,不用在海量的主体代码寻找菜单部分的代码,提高工作效率

2.初始化雷池

玩家所看到的棋盘是 9 * 9 的  为了防止越界 设计时调用的是 11 * 11的二维数组

需要两个雷池  一个是设计游戏的 雷池  一个是玩家所看到的雷池 

即      一个存放雷的信息         一个提供给玩家进行游玩

存放雷池的数组全部初始化为  '0'

(这里的'0'为字符   数组为字符数组)

玩家游玩数组全部初始化为 '*'   

这里的初始化排雷的时候有妙用

void InitBoard(char board[ROWS][COLS], int rows, int cols, char ch)
{
    int i = 0;
    for (i = 0; i < rows; i++)  //注意取值范围  不要越界
    {
        int j = 0;
        for (j = 0; j < cols; j++)
        {
            board[i][j] = ch;
        }
    }
}

由于对两个数组进行初始化的符号不同,故可以多增加一个形参接收初始化的字符

3.打印雷池以及玩家界面

封装一个打印函数,需要打印哪个数组就传哪个数组即可

为了方便玩家排雷   在雷池的周围标注行和列  优化游戏体验

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
    int x = 0;
    printf("------扫雷游戏------\n");

    for (x = 0; x <= row; x++)
    {
        printf("%d ", x);
    }
    printf("\n");



    int i = 1;
    int j = 1;
    for (i = 1; i <= row; i++)
    {

        printf("%d", i);

        for (j = 1; j <= col; j++)
        {
            printf(" %c", board[i][j]);
        }

        printf("\n");
    }
}

列的打印很简单 用一个循环先打印出来即可

行的打印则需要稍稍注意 在每次打印雷池数据时打印一个数即可

打印效果

练习时长两年半的扫雷

如何改变雷的数量与雷池大小

这是就体现了定义的好处了

可以通过修改定义来扩展雷池

//玩家页面

#define ROW 9       
#define COL 9        

//雷池信息

#define ROWS ROW+2
#define COLS COL+2

//雷的个数
#define EASY_COUNT 10     

 改变雷的数量和雷池大小直接从定义更改即可     

上一篇与坤对弈也有提到    性感坤坤在线邀请老铁对弈 (>_<)

4.生成随机雷

练习时长两年半的扫雷

这是我们所需要的雷池数组   下标从0开始

画图方便理解   很容易可以看出 

生成的随机雷的坐标范围x,y只需要在1 - 9 

即图中红框内的范围

void SetMine(char Mine[ROWS][COLS], int row, int col)
{


    int count = EASY_COUNT;

    while (count)
    {
        int x = rand() % row + 1;
        int y = rand() % row + 1;

        if (Mine[x][y] == '0')
        {
            Mine[x][y] = '1';
            count--;
        }
    }

}

随机数的生成用rand()函数  需配合srand()使用  调用头文件#include <stdio.h>  

坐标范围是 1 - 9  故 rand() % row + 1 即  0 - 8  左右加一  故为 1 - 9

rand % row =   0   ~  row -1

5.排雷与对局判断

通过分析已知需要排查  row * col - EASY_COUNT  次

//可建立一个新数组来存放已经排查过的坐标
char Visited[ROWS][COLS]
 
 
int Find(char Mine[ROWS][COLS], int x, int y)
{
    return(Mine[x - 1][y - 1] + Mine[x - 1][y] + Mine[x - 1][y + 1] + Mine[x][y - 1] + Mine[x][y + 1] + Mine[x + 1][y - 1] + Mine[x + 1][y] + Mine[x + 1][y + 1] - 8 * '0');
}

这个函数计算了输入坐标周围的雷的个数 并返回了字符

数字 3 想变成 字符 '3'  只需减去一个'0' 字符零

ASCALL码    51  -   48  = 3

void FindMine(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col)
{
    int x = 0;
    int y = 0;
    int win = 0;
    char Visited[ROWS][COLS];    //用来存放已经输入过的坐标
    while (win < row * col - EASY_COUNT)
    {
        printf("请输入坐标:>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 1 && y <= col)
        {
            if (Mine[x][y] == '1')
            {
                printf("很遗憾,你被炸死了\n");
                DisplayBoard(Mine, ROW, COL);
                break;
            }
            if (Visited[x][y] == '1')
            {
                printf("该坐标已排查过,请重新输入\n");
                continue;
            }
            else
            {
                int count = Find(Mine, x, y);
                Show[x][y] = count + '0';
                DisplayBoard(Show, ROW, COL);
                win++;
                Visited[x][y] = '1';
            }

         

        }
        else
        {
            printf("坐标非法,请重新输入\n");
        }
    }
    if (win == row * col - EASY_COUNT)
    {
        printf("恭喜你,排雷成功\n");
        DisplayBoard(Mine, ROW, COL);
    }

}

对于越界的看法

数组越界可能不会立即导致程序崩溃或报错。这取决于您使用的编程语言和运行时环境。有些语言和运行时环境会在数组越界时立即报错,而有些则不会。如果您的程序在数组越界时仍能正常运行,但在程序结束时报错,那么这可能是因为您使用的编程语言或运行时环境在程序结束时才检测到并报告了错误。

         ⠰⢷⢿⠄
⠀⠀⠀⠀⠀⣼⣷⣄
⠀⠀⣤⣿⣇⣿⣿⣧⣿⡄
⢴⠾⠋⠀⠀⠻⣿⣷⣿⣿⡀
🏀 ⠀⢀⣿⣿⡿⢿ ⠈⣿
⠀⠀⠀⢠⣿⡿⠁⠀⡊⠀ ⠙
⠀⠀⠀⢿⣿⠀⠀⠹⣿
⠀⠀⠀⠀⠹⣷⡀⠀⣿⡄
⠀⠀⠀⠀⣀⣼⣿⠀⢈⣧                                              我能在这打篮球,你能吗?
文章来源地址https://www.toymoban.com/news/detail-466000.html

到了这里,关于练习时长两年半的扫雷的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 黑客入侵丰田一年半,窃取海量用户数据

    近日安全研究人员发现,黑客入侵丰田(TOYOTA)服务提供商 Salesforce Marketing Cloud 长达一年半之久,窃取到丰田公司海量用户数据。 据调查,数据泄露的原因是,丰田数字营销自动化和分析软件服务提供商 Salesforce Marketing Cloud 无意公开了用户账户凭证访问权限。黑客获取了该

    2024年02月09日
    浏览(10)
  • 面试官一个简单的问题,让我emo了两年半

    面试官一个简单的问题,让我emo了两年半

    “ 小伙子,你擅长什么语言呢 ?😊😊😊” 眼前的面试官和善的问我。 “ 哼哼,当然是C语言,我可是C语言大佬! 😋😋😋”  我骄傲不已,想着自己一定能惊艳到面试官。 面试官递给我一道题目,看到这道题目, 我漏出自信迷人的微笑 。 模拟实现atoi函数 ,我心想这

    2023年04月09日
    浏览(10)
  • 自从外包三年半,程序员人废了一半

    自从外包三年半,程序员人废了一半

    如果不是女朋友和我提分手,我估计现在还没醒悟。大专生,18年通过校招进入湖南某软件公司,干了3年多的CRUD,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了3年的CRUD,已经让我变得不思进取,谈了2年的女

    2024年02月04日
    浏览(13)
  • 【K哥爬虫普法】一个人、一年半、挣了2000万!

    【K哥爬虫普法】一个人、一年半、挣了2000万!

    我国目前并未出台专门针对网络爬虫技术的法律规范,但在司法实践中,相关判决已屡见不鲜,K 哥特设了“K哥爬虫普法”专栏,本栏目通过对真实案例的分析,旨在提高广大爬虫工程师的法律意识,知晓如何合法合规利用爬虫技术,警钟长鸣,做一个守法、护法、有原则的

    2024年02月08日
    浏览(13)
  • 号称新物种,一年半烧了14多亿,卢放和岚图汽车终究是扶不起来?

    谈及新能源汽车的高端品牌,你可能会想到蔚来的“管家式”服务,也可能会想到小鹏的科技感,但对同样定位高端的岚图,存在感似乎很低,销量方面更是体现的淋漓尽致。 步入11月,也到了车企递交上月“成绩单”的时候,岚图汽车作为一份子,自然也不会缺席。数据显

    2024年02月05日
    浏览(9)
  • 视频上传,限制时长,获取视频时长

    使用element的upload上传文件时,除了类型和大小,需求需要限制只能长传18秒内的视频,这里通过upload的before-upload,以及创建一个音频元素对象拿到durtaion时长属性来实现。 loadedmetadata 事件是当指定的音频/视频的元数据已加载时触发,就可以得到元数据,包括时长,尺寸等;

    2024年02月12日
    浏览(13)
  • 如何获取视频与音频当前的时长,并设置时长

    ontimeupdate 事件在视频 / 音频 (audio / video)当前的播放位置发送改变时播放 简单来讲:就是视频在播放时,将不断触发。 此处用到了节流函数,每秒只会触发一次。 video.currentTime 可以获取到,当前播放时长 onloadeddata 事件在当前帧的数据加载完成且还没有足够的数据播放视

    2024年01月22日
    浏览(13)
  • 神舟电脑4年半的时间里 拆了N次,现在又 跳出 CMOS Message 问题,记录我的修机过程

    神舟电脑4年半的时间里 拆了N次,现在又 跳出 CMOS Message 问题,记录我的修机过程

    前言 这个国庆假期,坏了两个电子产品,分别为DIJ遥控器和已经陪伴我4年半的笔记本电脑(CMOS电压过低)。4 年半的时间里,这台神舟笔记本电脑拆了5 次以上,几次是日常扫灰保养,有一次是在21年12月固态坏了(当时进不了系统,开机屏幕都是暗黑的,还好之前重装系统时,

    2024年02月04日
    浏览(54)
  • js获取音频时长

    js获取音频时长

    上传音频文件时,需要将音频时长一起上传,纯 JavaScript 获取音频时长:使用 HTML5 的 Audio 对象和 duration 属性 来源 来源

    2024年02月03日
    浏览(8)
  • java ffmpeg获取视频时长

    nacos里面配置的ffmpegPath,如果不用这个,也可以自己写一个ffmpegPath的地址 代码

    2024年02月07日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包