练习时长两年半的扫雷

news2024/12/30 2:50:17

目录

设计思路

游戏运行效果

函数的声明

头文件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);
    }

}

对于越界的看法

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

         ⠰⢷⢿⠄
⠀⠀⠀⠀⠀⣼⣷⣄
⠀⠀⣤⣿⣇⣿⣿⣧⣿⡄
⢴⠾⠋⠀⠀⠻⣿⣷⣿⣿⡀
🏀 ⠀⢀⣿⣿⡿⢿ ⠈⣿
⠀⠀⠀⢠⣿⡿⠁⠀⡊⠀ ⠙
⠀⠀⠀⢿⣿⠀⠀⠹⣿
⠀⠀⠀⠀⠹⣷⡀⠀⣿⡄
⠀⠀⠀⠀⣀⣼⣿⠀⢈⣧                                              我能在这打篮球,你能吗?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/530440.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Pruning 系列 (五)Dropout、Dropconnect剪枝

环境 python 3.9numpy 1.24.1pytorch 2.0.0+cu117一、Dropout dropout在全连接层使用。 假设丢弃概率是P,有两种实现方式,不管是在《测试阶段》还是《训练阶段》对每层的输出做缩放,都是为了保持伯努利分布的期望np。《测试阶段》没dropout 而是全量神经元参与运算,不然预…

JAVA8的新特性——lambda表达式

JAVA8的新特性——lambda表达式 此处&#xff0c;我们首先对于Java8的一些特性作为一个简单介绍 Java 8是Java编程语言的一个重要版本&#xff0c;于2014年发布。Java 8引入了许多新特性和改进&#xff0c;以提高开发效率和性能。以下是Java 8的一些主要新特性&#xff1a; Lam…

Liunx基础命令 - pwd命令

pwd命令 – 显示当前工作目录的路径 ​ pwd 命令来自英文词组“print working directory”的缩写&#xff0c;其功能是用于显示当前工作目录的路径&#xff0c;即显示所在位置的绝对路径。在实际工作中&#xff0c;我们经常会在不同目录之间进行切换&#xff0c;为了防止“迷路…

【Android】Exam5 ListView组件简单应用

Exam5 ListView组件简单应用 ListView组件简单应用 Exam5 ListView组件简单应用目的实验内容及实验步骤采用SimpleAdapter自定义Adapter运行及结果&#xff1a;实验总结 目的 掌握常用的UI布局及组件&#xff1b; 掌握使用Intent启动Activity的方法 掌握ListView组件的简单应用…

什么是微服务中的熔断器设计模式?

在本文中&#xff0c;我将解释什么是熔断器设计模式以及它解决了什么问题。 我们将仔细研究熔断器设计模式&#xff0c;并探讨如何使用Spring Cloud Netflix Hystrix在Java中实现它。到本文结束时&#xff0c;您将更好地了解如何使用熔断器设计模式提高微服务架构的弹性。 熔断…

创建基于oracle jdk8的自定义docker镜像

创建基于oracle jdk8的自定义docker镜像 1:查看服务器java版本&#xff1a; 如果服务器的版本是open-jdk&#xff0c;则进行如下操作 拷贝相关jdk压缩包&#xff08;.tar.gz后缀&#xff09;到服务器目录&#xff08;例&#xff1a;/usr/local&#xff09; 解压&#xff1a;…

Liunx基础命令 - ls命令

ls命令 – 显示目录中文件及其属性信息 ls命令来自英文单词”list“的缩写&#xff0c;中文译为“列出”&#xff0c;其功能是用于显示目录中文件及其属性信息&#xff0c;是最常被使用到的Linux命令之一。 默认不添加任何参数的情况下&#xff0c;ls命令会列出当前工作目录中的…

Servlet编程---Day 04

一、HttpServletRequest (请求对象) &#xff08;一&#xff09;HttpServletRequest对象 HttpServletRequest对象是 tomcat 为我们封装的对象 HttpServletRequest是 ServletRequest 接口的子接口 , 专门做 http 协议的请求对象 &#xff08;二&#xff09;常用方法 //设置…

Python3: 扫描库文件并获取版本号信息

文章目录 1. 目的2. 原理Linux: strings 命令Windows: strings 命令 3. 基于 Python 实现 strings 命令4. 基于Python的版本号查找5. 最终调用&#xff1a;一句话使用 1. 目的 在 C/C 开发中使用了第三方库&#xff0c;具体说是 .a, .lib, .dll 等文件&#xff0c;想通过 Pyth…

C++: 通过CMake配置AddressSanitizer并执行内存泄漏和越界检查

文章目录 1. 目的2. 区分编译和链接选项3. 在CMake中全局开启ASan1. 目的 在 C/C++ 工程中, 得益于 Google 工程师开发的 Address Sanitizer 这一神器, 可以快速、准确的发现不规范的内存使用, 包括而不限于: 内存泄漏检查, 例如忘记释放, 或原本持有内存的的指针被赋予…

[230522] 托福阅读词汇题 |持续更新|5月15日

infiniteimmensevast breakthroughdiscovery pivotalessential perceivedapparent 明显的 statutorilylegally 法律上 triggerprompt 引发 adolescentyouthful 青少年的 theorizedproposed 提出 replenishrenew 补充 prospersucceed pursueresearch signalindicate …

WPF MaterialDesign 初学项目实战(4)侧边栏路由管理

原视频内容 WPF项目实战合集(2022终结版) 24P 其他内容 WPF MaterialDesign 初学项目实战&#xff08;0&#xff09;:github 项目Demo运行 WPF MaterialDesign 初学项目实战&#xff08;1&#xff09;首页搭建 WPF MaterialDesign 初学项目实战&#xff08;2&#xff09;首…

ESLint配置详解

ESLint配置详解 ESLint 是一个代码检查工具&#xff0c;用来检查代码是否符合指定的规范&#xff0c;防止在多人协作开发时代码格式不统一。 安装 全局安装 npm install eslint -g当前项目安装 npm install eslint -D安装之后运行eslint --init进行初始化&#xff0c;使用…

你真的理解分布式数据的分区吗?

分布式数据存储是指将数据分散存储在多个节点或服务器上的技术。而分区是将数据划分为逻辑上的片段或部分&#xff0c;每个分区可以在分布式系统中的不同节点上存储。分区主要是为了可扩展性。不同的分区可以放在不共享集群中的不同节点上&#xff0c;可以帮助实现负载均衡、高…

玩转Google开源C++单元测试框架Google Test系列(gtest)之四 - 参数化

一、前言 在设计测试案例时&#xff0c;经常需要考虑给被测函数传入不同的值的情况。我们之前的做法通常是写一个通用方法&#xff0c;然后编写在测试案例调用它。即使使用了通用方法&#xff0c;这样的工作也是有很多重复性的&#xff0c;程序员都懒&#xff0c;都希望能够少…

Liunx基础命令 - cd命令

cd命令 – 切换目录 cd命令来自英文词组“change directory”的缩写&#xff0c;其功能是用于更改当前所处的工作目录&#xff0c;路径可以是绝对路径&#xff0c;也可以是相对路径&#xff0c;若省略不写则会跳转至当前使用者的家目录。 **语法格式&#xff1a;**cd [参数] …

VMware Workstation 17 Pro安装配置CentOS 7与ssh工具链接配置

VMware Workstation 17 Pro安装配置CentOS 7与ssh工具链接配置 下载安装虚拟机VMware Workstation 17 Pro 虚拟机官网&#xff1a;点击直达 下载Cent os 7 镜像文件 123网盘地址&#xff1a;点击直达 提取码1213 在虚拟机中安装Cent os 7 第一步 点击 创建新的虚拟机 第二步 默…

解释什么是蓝绿发布?

蓝绿发布(Blue-green release)是一种软件部署策略&#xff0c;主要用于应对新版本软件在生产环境中的测试和部署。这种策略将新版本软件分为两个阶段&#xff1a;蓝色阶段和绿色阶段。蓝色阶段通常在开发和测试环境中进行&#xff0c;而绿色阶段则在生产环境中进行。 蓝色阶段…

C语言运算符:赋值与计算

目录 赋值运算符 算术运算符 赋值运算符 下表列出了 C 语言支持的赋值运算符&#xff1a; 运算符描述实例简单的赋值运算符&#xff0c;把右边操作数的值赋给左边操作数C A B 将把 A B 的值赋给 C加且赋值运算符&#xff0c;把右边操作数加上左边操作数的结果赋值给左边操…

C语言基础知识:关系运算符与逻辑运算符

目录 1、关系运算符介绍 2、应用示例 3、逻辑运算符介绍 4、逻辑表达式的书写 5、不得不说的逻辑非 1、关系运算符介绍 关系运算&#xff08;Relational Operators&#xff09;&#xff0c;用于判断条件&#xff0c;决定程序的流程。 关系数学中的表示C语言的表示小于&l…