news 2026/8/3 4:45:52

C语言做扫雷游戏(下)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言做扫雷游戏(下)

上半部分我们将准备工作完成,下面我们将完成game函数中所有子函数:

void game() { char mine[ROWS][COLS] = { 0 }; char show[ROWS][COLS] = { 0 }; //初始化 init_board(mine, ROWS, COLS, '0'); init_board(show, ROWS, COLS, '*'); //打印 print_board(show, ROWS, COLS); //部署雷 put_mine(mine, ROWS, COLS); //排雷 pai_mine(mine, show, ROWS, COLS); }

一. 初始化

//初始化 void init_board(char arr[ROWS][COLS], int r, int c,char in) { int i = 0; int j = 0; for (i = 0;i < r;i++) { for (j = 0;j < c;j++) { arr[i][j] = in; } } }

用经典的双变量循环对mine数组和show数组进行初始化赋值,i 表示处在第几行,j 表示处在第几列,此代码块写在game.c中。这里我们用r和c分别接收ROWS(行数)和COLS(列数)。注意因为show数组要有隐秘性,所以我们可以选择字符‘*’初始化show数组。而此初始化函数应具有推广性,即mine数组也应可以用它进行初始化,所以可以用字符‘0’初始化mine数组以保持与show数组初始常量类型一样。而‘*’,‘0’均可以用char in进行接收所以这个函数共有四个形参,与四个实参相对应:

init_board( mine, ROWS, COLS, '0'); init_board( show, ROWS, COLS, '*'); init_board(char arr[ROWS][COLS], int r, int c,char in)

打印(下面讲打印函数)的效果:

show数组 mine数组

二. 打印

void print_board(char arr[ROWS][COLS], int r, int c) { int i = 0; int j = 0; printf("\n"); for (i = 1;i <= ROW;i++) { for (j = 1;j <= COL;j++) { printf("%c ", arr[i][j]); } printf("\n"); } printf("\n"); }

打印同理用双变量法,因为是打印游戏部分,所以i和j最大分别到ROW和COL,但是效果是这样:

玩家不能立马分清第几行和第几列,所以要加上行和列的标注,改代码:

void print_board(char arr[ROWS][COLS], int r, int c) { int i = 0; int j = 0; for (j = 0;j <= COL ;j++) { printf("%d ", j); } printf("\n"); for (i = 1;i <= ROW;i++) { printf("%d ", i); for (j = 1;j <= COL;j++) { printf("%c ", arr[i][j]); } printf("\n"); } printf("\n"); }

在打印棋盘之前先打出0~COL,再在打印每行之前打印行数,然后效果:

如此玩家可以更加方便选择排查坐标。

三. 部署地雷

void put_mine(char mine[ROWS][COLS], int r, int c) { int s = 1; while (s <= COUNT) { int x = rand() % ROW + 1; int y = rand() % COL + 1; if (mine[x][y] != '1') { mine[x][y] = '1'; s++; } } }

简单模式下一般设置10个地雷,为了更加灵活,可在game.h文件中引入COUNT表示雷数:

#define COUNT 10//雷数

因为要保证部署的随机性,因此可以用srand((unsigned int)time(NULL))(放在main函数开头);和rand()生成0~ROW和0~COL随机数,然后int x = rand() % ROW + 1和int y = rand() % COL + 1记录行(x)和列(y)。接着将mine[x][y] = '1'即可,注意这里用字符‘1’表示地雷。但在部署地雷之前需要先判断是否已经部署过,所以用if语句进行判断。然后在while语句中循环,用s记录已部署次数,即在每次成功部署后s加一,直到COUNT。结果:

正好10颗!

四. 排雷并给予提示

//排雷 void pai_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int r, int c) { int win = 0; while (win<=71) { int x = 0, y = 0; printf("请输入你想要排查的坐标:"); scanf("%d%d", &x, &y); if (x >= 1 && x <= ROW-1 && y >= 1 && y <= COL-1) { if (show[x][y] == '*') { if (mine[x][y] == '0') { show[x][y] = find_mine(mine, x, y) + '0'; print_board(show, ROWS, COLS); win++; } else { printf("你被炸死了\n"); print_board(mine, ROWS, COLS); break; } } else { printf("此处已排查\n"); print_board(show, ROWS, COLS); } } else { printf("输入错误\n"); print_board(show, ROWS, COLS); } } }

这里mine数组和show数组均用到,所以有两个数组形参。先引入行x,列y并让玩家输入,然后判断输入是否正确即第一层if语句,然后在判断此地是否已经被排查即第二层if语句,接着·判断此地是否有雷即第三层if语句。第三层时就是判断show[x][y]为‘1’还是‘*’。若是前者,则游戏结束;若是后者,则要在此处标记附近雷的个数,此时用find_mine(mine, x, y)函数:

static size_t find_mine(char mine[ROWS][COLS], int x, int y) { int i = 0; int j = 0; size_t n = 0; for (i = -1;i <= 1;i++) { for (j = -1;j <= 1;j ++) { n += (mine[x + i][y + j] - '0'); } } return n; }

find_mine(mine, x, y)函数只用于pai_mine()中,所以应放在pai_mine()上方,可以用stasic静态修饰,防止其他文件误用。

size_t类型指无符号整形类型,此处用于函数的返回类型,因为雷个数n无负数。因为数字的ASCLL码值-‘0’的ASCLL码值即为数字本身,所以将show[x][y]周围的字符数字-‘0’后相加即为周围雷的个数,怎样相加呢?观察这个图:

引入i和j初始为-1,然后用双变量for循环将mine[x + i][y + j] - '0'全部相加得到雷数n,再返回给show[x][y],这样便完成标识,然后在开头引入int win,每次成功排雷后win++直到ROW*COL-COUNT(无雷个数),然后成功,游戏结束。进入下一次循环。

五. 总结

做扫雷游戏几乎将之前学的所有知识全部复习了一遍例如:选择判断,循环语句,函数定义与调用等等。我亲手实践并写了这两篇博客后我对C语言的理解有加深了一步,所以你跟着我将扫雷游戏做完也一定收获颇丰。但是这只是一个简单的版本,你也可以用opencode和VS code对其进行优化,比如:如果排查位置不是雷,周围也没有雷,可以展开周围的一片(这个需要学习函数递归等)可以用特殊符号标记雷,可以加上排雷的时间显示等等。这里就不再展示。希望这两篇博客对你有所帮助,有问题在评论区讨论,感谢你的阅读!

六. 代码展示

还没有注册git?我给你完整代码!

text.c

#define _CRT_SECURE_NO_WARNINGS #include"game.h" void menu() { printf("------------------------\n"); printf("------ 1-开始 ------\n"); printf("------ 0-退出 ------\n"); printf("------------------------\n"); printf("请选择:"); } void game() { char mine[ROWS][COLS] = { 0 }; char show[ROWS][COLS] = { 0 }; //初始化 init_board(mine, ROWS, COLS, '0'); init_board(show, ROWS, COLS, '*'); //打印 print_board(show, ROWS, COLS); //print_board(mine,ROWS,COLS); //部署雷 put_mine(mine, ROWS, COLS); //print_board(mine, ROWS, COLS); //排雷 pai_mine(mine, show, ROWS, COLS); } int main() { srand((unsigned int)time(NULL)); int input = 0; do { menu(); scanf("%d", &input); switch (input) { case 1: { game(); break; } case 0: { printf("退出\n"); break; } default: { printf("输入错误\n"); break; } } } while (input); return 0; }

game.c

#define _CRT_SECURE_NO_WARNINGS #include"game.h" //初始化 void init_board(char arr[ROWS][COLS], int r, int c,char in) { int i = 0; int j = 0; for (i = 0;i < r;i++) { for (j = 0;j < c;j++) { arr[i][j] = in; } } } //打印 void print_board(char arr[ROWS][COLS], int r, int c) { int i = 0; int j = 0; for (j = 0;j <= COL ;j++) { printf("%d ", j); } printf("\n"); for (i = 1;i <= ROW;i++) { printf("%d ", i); for (j = 1;j <= COL;j++) { printf("%c ", arr[i][j]); } printf("\n"); } printf("\n"); } //部雷 //随机生成COUNT个雷 void put_mine(char mine[ROWS][COLS], int r, int c) { int s = 1; while (s <= COUNT) { int x = rand() % ROW + 1; int y = rand() % COL + 1; if (mine[x][y] != '1') { mine[x][y] = '1'; s++; } } } //标雷 static size_t find_mine(char mine[ROWS][COLS], int x, int y) { int i = 0; int j = 0; size_t n = 0; for (i = -1;i <= 1;i++) { for (j = -1;j <= 1;j ++) { n += (mine[x + i][y + j] - '0'); } } return n; } //排雷 void pai_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int r, int c) { int win = 0; while (win <= (ROW*COL-COUNT)) { int x = 0, y = 0; printf("请输入你想要排查的坐标:"); scanf("%d%d", &x, &y); if (x >= 1 && x <= ROW-1 && y >= 1 && y <= COL-1) { if (show[x][y] == '*') { if (mine[x][y] == '0') { show[x][y] = find_mine(mine, x, y) + '0'; print_board(show, ROWS, COLS); win++; } else { printf("你被炸死了\n"); print_board(mine, ROWS, COLS); break; } } else { printf("此处已排查\n"); print_board(show, ROWS, COLS); } } else { printf("输入错误\n"); print_board(show, ROWS, COLS); } } }

game.h

#pragma once #include<stdio.h> #include<stdlib.h> #include<time.h> #define ROW 9//行 #define COL 9//列 #define ROWS ROW+2 #define COLS COL+2 #define COUNT 10//雷数 //初始化 void init_board(int arr[11][11], int r, int c, char in); //打印 void print_board(char arr[ROWS][COLS], int r, int c); //部雷 void put_mine(char mine[ROWS][COLS], int r, int c); //排雷 void pai_mine(mine, show, r, c);
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/3 4:39:14

Python学习新思维:从零到项目实战,构建问题解决能力

你是不是也刷到过那种标题——“七天从小白到大神”“学完即可就业”“最全零基础教程”&#xff1f;点进去一看&#xff0c;几十上百个小时的视频&#xff0c;从安装Python讲到人工智能&#xff0c;感觉什么都讲了&#xff0c;又感觉什么都没记住。收藏夹里塞满了&#xff0c;…

作者头像 李华
网站建设 2026/8/3 4:36:43

UReport2报表图片加载优化:动态URL参数重写与防裂图实践

1. 项目概述&#xff1a;当报表图片加载遇到“拦路虎”最近在折腾一个老项目&#xff0c;里面用到了UReport2这个报表引擎。需求很简单&#xff0c;就是要在报表里动态插入一些图片&#xff0c;比如用户头像、产品示意图或者公司Logo。按理说&#xff0c;UReport2本身是支持图片…

作者头像 李华
网站建设 2026/8/3 4:35:04

信噪比(SNR)原理、测量与提升实战指南

1. 从“听不清”到“测不准”&#xff1a;无处不在的信噪比最近在调试一个传感器数据采集系统&#xff0c;发现采集到的信号波形上总是叠加着一层“毛刺”&#xff0c;导致关键的特征峰值难以准确识别。同事看了一眼示波器&#xff0c;随口说了句&#xff1a;“你这信噪比太低了…

作者头像 李华
网站建设 2026/8/3 4:35:03

MyBatis TypeHandler原理与LocalDateTime转换实战

1. TypeHandler类型转换器概述在持久层框架中&#xff0c;TypeHandler&#xff08;类型处理器&#xff09;是处理Java类型与数据库类型之间转换的核心组件。当我们在MyBatis等ORM框架中遇到字段类型不匹配的情况时&#xff0c;TypeHandler能够自动完成双向的类型转换工作。比如…

作者头像 李华