用C语言简单编写一个游戏:扫雷
用C语言编写一个游戏:扫雷
一、简单说明:
Minesweeper 是一款流行型普及型智力游戏,在规定时间内识别并标记出所有安全区域的同时避免触发地mine 导致比赛结束。 Minesweeper 游戏因其简单易学而广受欢迎,并成为许多人的童年回忆。今天我们将利用 C 语言开发一个基础版 Minesweeper 游戏程序以提升玩家的操作体验与竞技水平。
二、 编写思路:
编写之前,在程序设计阶段首先要解决的问题是如何在程序中模拟扫雷游戏中所有格子的状态。为此我们可以采用二维数组这一数据结构来模拟格子地图的状态。每一处格子需要携带的信息包括未翻开状态的标记以及已翻开状态下的数字提示(可以用字符'0'到'8'分别表示周围不同数量的地雷)。为了实现这一功能我们需要定义两个二维数组分别存储地雷分布的信息以及当前显示的状态信息。其中第一个二维数组用于记录每个位置是否已被翻开的状态(可用字符'*'表示未翻开);第二个二维数组则用于记录每个位置周围存在的地雷数量(可用字符'0'到'8'分别代表不同数量的地雷)。接下来我们需要探讨的是如何通过这些数据结构组织地雷分布的信息并完成相应的逻辑运算以实现游戏的基本功能。为了保证程序运行时结果的唯一性和可重复性我们通常会采用随机算法来生成地雷分布模式并结合时间戳作为随机种子以确保每次运行结果不同
三、游戏流程:
- 地图创建及初始化操作分为两步:首先处理showMap变量,在其二维数组中所有单元格均赋值为星号*;其次处理mineMap变量,在其二维数组中所有单元格初始设为零0,并随机选定十个位置标记为一1以表示地雷。
- 显示当前的地图界面 showMap。
- 请玩家输入一个坐标点。
- 检测玩家是否踩中地雷。
- 更新显示界面 showMap,在翻开相应位置时展示周围区域的地雷数量。
- 确认游戏结束状态是否达成。
//扫雷游戏
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include <time.h>
#define MAX_ROW 9
#define MAX_COL 9
#define MINE_COUNT 10
void init(char showMap[MAX_ROW][MAX_COL], char mineMap[MAX_ROW][MAX_COL]){
/*for (int row = 0;row < MAX_ROW;row++) {
for (int col = 0;col < MAX_COL;col++) {
showMap[row][col] = '*';
}
}*/
//mem=>memory 内存
//set :设置,集合
//memset的功能就是把一段内存上的每个字节都设置成一个具体的值
//数组隐式转成了指针,所以不可以用sizeof来求数组长度
//二维数组的每个元素都是在一个连续的内存空间上布局的
memset(showMap, '*', MAX_ROW * MAX_COL);
memset(mineMap, '0', MAX_ROW * MAX_COL);
//随机产生10个位置作为地雷
//先设置随机种子
srand((unsigned int)time(0));
int mineCount = 0;
while (mineCount<MINE_COUNT) {
int row = rand() % MAX_ROW;
int col = rand() % MAX_COL;
if (mineMap[row][col] == '1') {
continue;
}
mineMap[row][col] = '1';
mineCount++;
}
}
//希望这一个函数能同时具备打印两种地图的功能
//取决于实参填啥
//形参名字叫做"map"不太合适.C++标准库里有一个std:map
void print(char theMap[MAX_ROW][MAX_COL]) {
for (int row = 0;row < MAX_ROW;row++) {
for (int col = 0;col < MAX_COL;col++) {
printf("%c",theMap[row][col]);
}
printf("\n");
}
}
void update(char showMap[MAX_ROW][MAX_COL],
char mineMap[MAX_ROW][MAX_COL], int row, int col) {
//表示周围地雷的个数
int count = 0;
for(int r = row - 1;r <= row + 1;r++) {
for (int c = col - 1;c <= col + 1;c++) {
if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) {
//此时r,c坐标超出棋盘的范围,直接跳过
continue;
}
if (r == row && c == col) {
//不需要判断,直接下次循环
continue;
}
if (mineMap[r][c] == '1') {
count++;
}
}
}
//如果直接赋值的话,此时假设count是2
//当前row,col位置的元素就被设置成了ASCII值为2的字符
//而不是'2'
// 类似于这样的转换, 只是 C 语言中是这么写的.
// 其他的主流编程语言中, 一般是不允许 字符类型 和 整数类型 进行混合运算的
showMap[row][col] = '0'+count;
}
int main() {
//创建地图并进行初始化
char showMap[MAX_ROW][MAX_COL] = { 0 };
char mineMap[MAX_ROW][MAX_COL] = { 0 };
init(showMap, mineMap);
int openedCount = 0;
while (1) {
//2.打印地图
print(showMap);
//3.玩家输入坐标
//此处是为了验证update函数的正确性
//先把地雷的布局也打印出来
int row = 0;
int col = 0;
printf("请输入坐标(row,col):");
scanf("%d %d", &row, &col);
//进行合法性判定
if (row<0 || row>=MAX_ROW || col<0 || col>=MAX_COL) {
printf("您输入的坐标有误!请重新输入!\n");
continue;
}
if (showMap[row][col]!= '*') {
printf("您输入的位置已经翻开了!\n");
continue;
}
//4.判断是否踩雷
if (mineMap[row][col] == '1') {
printf("您踩雷了!游戏结束!\n");
break;
}
//5.更新showMap,显示当前位置周围有多少个雷
update(showMap, mineMap, row, col);
//6.进行游戏胜利的判定,统计当前一共翻开了多少个格子
openedCount++;
if (openedCount == MAX_ROW * MAX_COL - MINE_COUNT) {
printf("恭喜你游戏胜利!\n");
break;
}
}
//print(mineMap);
system("pause");
return 0;
}
AI写代码
运行页面如下

注意!!代码中用常量定义数字是为了避免魔鬼数字的出现。
所谓魔鬼数字,是指在代码中没有具体含义的数字、字符串。魔鬼数字主要影响了代码可读性,读者看到数字无法理解其含义,从而难以理解程序的意图。当程序中的魔鬼数字过多时,代码的可维护性将会急剧下降,代码变得难以修改,并容易引入错误。但并不是任何情况下将数字定义为常量都是有利的,如果常量的名称没有意义,无法帮助理解代码,同样也是一种魔鬼数字。除此之外,在个别情况下,将数字定义为常量反而会导致代码更加难以理解,此时就不应该强求将数字定义为常量。
在扫雷游戏中,在更新过程中进行判断:当统计结果为零时,在当前位置为中心处将周围的八个位置都纳入到更新过程。
总的来说,在编写一个相对简单的扫雷游戏程序时就可以完成这个开发任务。对于新手来说,在编程过程中还是有一定难度的,主要依赖于对数组的知识掌握。为了更好地完成项目目标,请多加练习和实践!
