C语言扫雷小游戏(保姆级教程)
一、前言
计算机编程的世界中,C语言一直以其高效、直接和灵活的特性而备受赞誉。对于初学者来说, C语言不仅是一种编程语言,更是一种理解和掌握计算机底层运作机制的桥梁。而扫雷游戏,作为一款经典的益智游戏,以其独特的游戏机制和挑战性,深受广大玩家喜爱。
接下来我将引领你一起探索如何使用C语言编写一个扫雷小游戏。在这个过程中,我们将深入了解C语言的语法、数据结构和算法,同时掌握如何使用C语言进行游戏编程。通过实践,你将学会如何使用C语言实现游戏的基本框架,如何处理用户输入,如何进行游戏逻辑计算,以及如何进行游戏的界面设计。
这不仅是一次学习编程语言的实践,更是一次锻炼逻辑思维和解决问题的能力的机会。
二、简单的了解扫雷游戏的规则
1.随意点击一个格子
2.点开的格子可能是空白,可能是数字,也可能是地雷。
3.点开的数字是1-8中的任意一个,数字是多少则代表这个格子周围环绕的其他八个格子里面有多少个地雷。
三、代码的简单理解
1、游戏的菜单(menu)
void menu()
{
printf("************************\n");
printf("***** 1.paly *******\n");
printf("***** 0.exit ******\n");
printf("************************\n");
printf("************************\n");
}
}
2、游戏的进入
在这里插入代码片int intput = 0;
do
{
menu();
printf("请选择:>");
scanf_s("%d", &intput);
switch (intput)
{
case 1:
game();
break;
case 0:
printf("游戏结束,退出游戏\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while (intput);
利用do {}while()的循环方式在里面写一个switch语句作为一个游戏开始的接口,从而实现多轮游戏的进行。选择1,则会进入game的函数从而开始扫雷游戏;选择0,则会直接退出游戏;选择其它的数字,则会显示选择错误,重新选择即可。
三、两个二维数组的创建
1、第一个数组就是存放布置好的雷的信息(即上帝视角)
1则代表为雷
0则代表此位置是安全的
2、第二个数组就是存放排查出的雷的信息(即玩家扫出雷的情况)
1则代表的是周围八个位置中有且仅有一个雷
0则代表的是周围八个位置没有雷`
3、两个数组代码的展示
//完成扫雷游戏
//mine数组中存放布置好的雷的信息
char mine[ROWS][COLS] = { 0 };//数组全部初始化为'0'
//show数组中存放排查出的雷的信息
char show[ROWS][COLS] = { 0 };//数组全部初始化为'*'
四、模块化代码的实现
在C语言中,模块化编程是一种将程序分解为独立、可重用的模块的思想。每个模块执行特定的任务,并通过明确的接口与其他模块通信。这种思想有助于提高代码的可读性、可维护性和可重用性。
模块化编程的核心思想包括以下几点:
1.分解问题:将复杂的程序分解为一系列相对简单、独立的小问题或任务。每个任务对应一个模块。
2.抽象:隐藏模块内部实现的细节,只通过明确的接口与其他模块通信。这使得模块的内部实现可以自由修改,而不会影响到其他模块。
3.独立性:每个模块都应该是独立的,不依赖于其他模块的内部实现。这样,模块可以独立编译和测试。
4.可重用性:设计模块时考虑到其可重用性。这样,相同的模块可以用于不同的项目,减少重复的代码编写工作。
5.清晰性:通过给每个模块分配特定的任务,可以使程序的结构更加清晰,提高代码的可读性
1、game.h
```c
#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 EASY_COUNT 20a
//以下是一些声明函数
//初始化棋盘的函数
void Initboard(char arr[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void Displayboard(char arr[ROWS][COLS], int row, int col);
//布置雷
void Setmine(char arr[ROWS][COLS], int row, int col);
//排查雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS],
int row, int col);
2、test.c
#include<stdio.h>
#include "game.h"
void menu()
{
printf("************************\n");
printf("***** 1.paly *******\n");
printf("***** 0.exit ******\n");
printf("************************\n");
printf("************************\n");
}
void game()
{
//完成扫雷游戏
char mine[ROWS][COLS] = { 0 };//使二维数组的每个数都为‘0’即0字符
char show[ROWS][COLS] = { 0 };//使二维数组的每个数都为‘*’
//初始化棋盘
Initboard(mine, ROWS, COLS, '0');
Initboard(show, ROWS, COLS, '*');
//布置雷
//在9*9的棋盘上随机布置10个雷
Setmine(mine, ROW, COL);
//打印棋盘
//Displayboard(mine, ROW,COL);(显示布置雷的信息)
//可以检查扫雷游戏的正确性
Displayboard(show, ROW, COL);
//排查雷
Findmine(mine, show, ROW, COL);
}
void test()
{
srand((unsigned int)time(NULL));
int intput = 0;
do
{
menu();
printf("请选择:>");
scanf_s("%d", &intput);
switch (intput)
{
case 1:
game();
break;
case 0:
printf("游戏结束,退出游戏\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while (intput);
}
int main()
{
test();
return 0;
}
在主函数中调用test函数从而进入扫雷游戏。
test函数中的 “srand((unsigned int)time(NULL));” 这行代码的目的是为了初始化随机数生成器,以便每次运行程序时都能得到不同的随机数序列。
- time(NULL): 这是C标准库中的time函数,它返回从1970年1月1日(UTC)到现在的秒数。当传递NULL作为参数时,它会返回当前的时间(秒)。
- (unsigned int): 这是一个类型转换,将time(NULL)返回的时间值(通常是一个time_t类型)转换为unsigned int类型。
- srand(): 这是C标准库中的srand函数,用于设置随机数生成器的种子。如果使用相同的种子值调用rand()函数,它将生成相同的随机数序列。通过使用当前时间作为种子,每次运行程序时都会获得不同的随机数序列。
3、game.c
#include<stdio.h>
#include "game.h"
void Initboard(char arr[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++) {
arr[i][j] = set;
}
}
}
void Displayboard(char arr[ROWS][COLS], int row, int col)
{
int i = 0;
//打印列号
printf("-----扫雷游戏----\n");
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
//打印行号
for (i = 1; i <= row; i++)
{
int j = 0;
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
//创建雷
void Setmine(char arr[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
//随机生成雷
int x = rand() % row + 1;
int y = rand() % col + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
//第一种计算周围有几个雷的方法
//static int Getminecount(char mine[ROWS][COLS], int x, int y)
//{
// return mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] +
// mine[x + 1][y - 1] + mine[x + 1][y] + mine[x][y + 1] + mine[x + 1][y + 1] + mine[x - 1][y + 1]-8*'0';
//
//}
//第二种计算周围有几个雷的方法
static int Getminecount(char mine[ROWS][COLS], int x, int y)
{
int i = 0;
int count = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
count += (mine[i][j] - '0');
}
}
return count;
}
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win < row * col - EASY_COUNT)
{
printf("请输入要排查的坐标:");
scanf_s("%d %d", &x, &y);
//判断坐标的有效性
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*')
{
if (mine[x][y]== '1')
{
printf("不好意思,你被炸死了!!!");
Displayboard(mine, ROW, COL);
break;
}
else
{
//该位置不是雷的话,就要统计周围有几个雷
int count = Getminecount(mine, x, y);
show[x][y] = count + '0';
Displayboard(show, ROW, COL);
win++;
}
}
else {
printf("该位置已经被排查过了,请重新输入!!");
}
}
else {
printf("坐标输入错误,请重新输入!!");
}
}
if (win == row * col - EASY_COUNT) {
printf("恭喜你,完成扫雷小游戏!!!\n");
Displayboard(mine, ROW, COL);
}
}
1.Initboard初始化棋盘
Initboard中的set是一个参数代表的是"0"和""。体现在这个二维数组中arr[i][j] = set;此时set可以代表“0”也可以代表“”,这就是一个灵活的运用参数去解决实际问题,避免代码的重复。
2.Displayboard打印棋盘
打印周围的坐标可以清晰的知道格子的位置坐标,从而对对应位置的判断。
3.Setmine创建雷的位置
我把 EASY_COUNT当作为雷的信息,count用来计算雷的个数,用两个rand()函数来随机生成雷的位置
4. Getminecount计算周围八个位置雷的个数
第一种方法就是:
把八个位置依次计算出来然后减去8个“0“对应的ASCII码的值,在ASCII码表中”1“对应的值为49;
”0“对应的为48;”1“-”0“=1,从而类推可以找出周围有几个雷;
第二种方法其实是第一种方法的简便方法:
就是用循环计算出周围雷的信息,最终求出附近有几个雷。
5.Findmine查找雷的位置
打印棋盘是相当于给棋盘建立了平面直角坐标系,只需要在控制台中输入坐标即可验证该格子的雷的信息了,每次验证后都会打印一次棋盘来展示出结果。
在Findmine中写明了游戏胜利的条件,即扫出全部的雷,即可获取胜利。
至此,一个C语言的扫雷小游戏就已经大功告成了!!!
五、游戏的演示
当扫到了雷就会显示失败