扫雷游戏 c语言
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了扫雷游戏 c语言相关的知识,希望对你有一定的参考价值。
本人学生一个,需要一个c语言的扫雷游戏,要求能在win7环境下运行,本人有win-Tc 和dev c++ 关于c++的代码最好没有,如果必须最好少一点,dos界面下的就不用了。如果那位大神能够急人所难,感激不尽。我只有10财富值,请不要嫌弃、。。。。
参考技术A 10块钱都没人搞 真心话 参考技术B c语言编写gui界面程序???开玩笑么追问首先我是一个小白,我刚才还百度了一下gui界面是什么,不过我同学自己用C语言遍了一个贪吃蛇出来,不是doc界面哦。
追答你同学可能用的mfc,或者也想上面那样用win32写的,调用api图形库函数,设计窗口注册窗口什么的,你要单纯用c写,绝对不可能,要写出来的话,你已经进微软了
参考技术C #include <windows.h>#include <CommCtrl.h> // 用于InitCommonControls
#pragma comment(lib, "comctl32.lib") // 用于InitCommonControls
// 常量
const int WINDOW_STYLES = WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION; // 窗口风格
const int MAX_WIDTH = 30; // 雷区最大宽度
const int MAX_HEIGHT = 25; // 雷区最大高度
const int FLAF_NULL = 0; // 格子无标记
const int FLAG_CAVEAT = 1; // 警告标记
const int FLAG_QUERY = 2; // 疑问标记
const int FLAG_OVERT = 3; // 已经打开的格子标记
const int FLAF_MINE = -1; // 地雷标记
const int CELL_SIZE = 25; // 格子大小
// 全局变量
static struct
HINSTANCE hInst; // 应用程序句柄实例
HWND hWnd; // 主窗口句柄
HWND Button; // 重新开始按钮句柄
HWND lButton; // 左边剩余地雷按钮
HWND rButton; // 右边时间显示按钮
Win;
static struct
HWND hWnd [MAX_WIDTH][MAX_HEIGHT]; // 雷区按钮句柄
WNDPROC Proc; // 按钮原来消息处理函数地址
int Code [MAX_WIDTH][MAX_HEIGHT]; // 存储数据
int Flag [MAX_WIDTH][MAX_HEIGHT]; // 用户标记
MineField;
static struct
int Width; // 雷区宽度
int Height; // 雷区高度
int CellNum; // 剩下的安全格子数量
int Rated_MineNum; // 额定地雷数量
int MineNum; // 剩余地雷数量
int time; // 时间
bool timeOn;
Game;
void toString(int val, char* string, int StringLen)
// 整数转换文本,本程序使用Unicode字符集,字符串长度需要大于2
char str [32];
int i = 0;
if (StringLen < 2)
return;
_itoa_s(val, str, 10);
while ((i < 32) && (i < (StringLen / 2 - 1)))
string [i * 2] = str [i];
string [i * 2 + 1] = 0;
i ++;
string [i] = string [i + 1] = 0;
int GetMineNum(int x, int y) // 寻找周围地雷的数目
int i, j, a, b, num = 0;
for (i = -1; i < 2; i++)
for (j = -1; j < 2; j++)
a = x + i;
b = y + j;
if ((a > -1) && (b > -1) && (a < Game.Width) && (b < Game.Height))
if (MineField.Code [a][b] == FLAF_MINE)
num ++;
return num;
void NewGame(void) // 新游戏
int i, j;
char text[32];
// 清空数组
for (i = 0; i < Game.Width; i++)
for (j = 0; j < Game.Height; j++)
MineField.Flag [i][j] = FLAF_NULL;
MineField.Code [i][j] = 0;
SetWindowText(MineField.hWnd [i][j], L" ");
// 埋放地雷
srand(GetTickCount()); // 使用系统时间作为随机数种子
for (int k = 0; k < Game.Rated_MineNum; k++)
i = rand() % Game.Width;
j = rand() % Game.Height;
if (MineField.Code [i][j] == FLAF_MINE)
k --; // 已经有地雷,埋放失败
else
MineField.Code [i][j] = FLAF_MINE;
// 设置数字 显示周围地雷数量
for (i = 0; i < Game.Width; i++)
for (j = 0; j < Game.Height; j++)
if (MineField.Code [i][j] != FLAF_MINE)
MineField.Code [i][j] = GetMineNum(i, j);
toString(Game.Rated_MineNum, text, 32);
SetWindowText(Win.lButton, (LPCTSTR) text);
SetWindowText(Win.rButton, L"0");
SetWindowText(Win.Button, L"∩_∩");
Game.time = 0;
Game.timeOn = false;
Game.MineNum = Game.Rated_MineNum;
Game.CellNum = Game.Width * Game.Height - Game.Rated_MineNum;
void OvertMine(void) // 显示地雷
char text[6], num;
Game.timeOn = false;
for (int i = 0; i < Game.Width; i++)
for (int j = 0; j < Game.Height; j++)
num = MineField.Code [i][j];
toString(num, text, 6);
SetWindowText(MineField.hWnd [i][j], num == FLAF_MINE ? L"雷" : (LPCTSTR) text);
// 雷区按键处理
void MineSub(int x, int y, bool LButton = true)
int i, j, Num;
char text[32];
// 坐标范围检查
if ((x < 0) || (x >= Game.Width) ||
(y < 0) || (y >= Game.Height))
return;
Num = MineField.Code [x][y];
if (LButton)
if ((MineField.Flag [x][y] == FLAG_CAVEAT) ||
MineField.Flag [x][y] == FLAG_OVERT)
return;
Game.timeOn = true;
MineField.Flag [x][y] = FLAG_OVERT;
if (Num == FLAF_MINE)
OvertMine();
SetWindowText(Win.Button, L">_<");
MessageBox(Win.hWnd, L"您踩到地雷啦,哈哈", L"您输了", 0);
NewGame();
return;
else
toString(Num, text, 6);
SetWindowText(MineField.hWnd [x][y], (LPCTSTR) text);
Game.CellNum --;
if (Game.CellNum == 0)
OvertMine();
MessageBox(Win.hWnd, L"恭喜你过关!", L"过关", 0);
NewGame();
return;
if (Num == 0)
for (i = -1; i < 2; i++)
for (j = -1; j < 2; j++)
if (Game.timeOn) // 递归函数在重新开始后可能进入死循环
MineSub(x + i, y + j);
else
i = MineField.Flag [x][y];
if (i != FLAG_OVERT)
if (i == FLAG_CAVEAT)
Game.MineNum ++;
i = (i + 1) % 3;
MineField.Flag [x][y] = i;
SetWindowText(MineField.hWnd [x][y],
i == FLAF_NULL ? L" " : i == FLAG_CAVEAT ? L"×" : L"?");
if (i == FLAG_CAVEAT)
Game.MineNum --;
toString(Game.MineNum, text, 32);
SetWindowText(Win.lButton, (LPCTSTR) text);
// 雷区按钮事件捕捉过程
static LRESULT CALLBACK MineFieldProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
int x = 0, y = 0, i, j;
for (i = 0; i < Game.Width; i++)
for (j = 0; j < Game.Height; j++)
if (MineField.hWnd [i][j] == hWnd)
x = i;
y = j;
switch(uMsg)
case WM_RBUTTONDOWN: // 鼠标右键按下
MineSub(x, y, false);
break;
case WM_KEYDOWN: // 键盘按键事件
switch(wParam)
case VK_UP: // 上
y = y > 0 ? y - 1 : 0;
break;
case VK_DOWN: // 下
y = y < (Game.Height - 1) ? y + 1 : Game.Height - 1;
break;
case VK_LEFT: // 左
x = x > 0 ? x - 1 : 0;
break;
case VK_RIGHT: // 右
x = x < (Game.Width - 1) ? x + 1 : Game.Width - 1;
break;
SetFocus(MineField.hWnd [x][y]); // 设置焦点控件
return CallWindowProc(MineField.Proc, hWnd, uMsg, wParam, lParam);
// 窗体事件捕捉过程
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
int id, msg;
char text[32];
switch (uMsg)
case WM_TIMER:
if (Game.timeOn)
Game.time ++;
toString(Game.time, text, 32);
SetWindowText(Win.rButton, (LPCTSTR) text);
break;
case WM_COMMAND: // 按钮发送的消息
id = LOWORD(wParam); // 获取按钮编号
msg = HIWORD(wParam); // 获取消息值
if (msg == BN_CLICKED) // 单击消息
if ((HWND) lParam == Win.Button)
NewGame();
else if (((HWND)lParam != Win.lButton) && ((HWND)lParam != Win.rButton))
MineSub(id & 255, id >> 8);
break;
case WM_DESTROY: // 退出
PostQuitMessage(0);
break;
default: // 其他事件
return DefWindowProc(hWnd, uMsg, wParam, lParam);
return FALSE;
// 入口过程
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
int w, h;
char text[32];
MSG msg;
WNDCLASSEX wce;
RECT rect;
// 初始化全局变量
Win.hInst = hInstance;
Game.Width = 15;
Game.Height = 10;
Game.Rated_MineNum = 15;
InitCommonControls(); // 初始化通用组件库
// 设置窗口
wce.cbSize = sizeof(WNDCLASSEX);
wce.style = 0;
wce.lpfnWndProc = (WNDPROC) WndProc;
wce.cbClsExtra = wce.cbWndExtra = 0;
wce.hInstance = hInstance;
wce.hIcon = LoadIcon(NULL,IDI_APPLICATION); // 窗口的最小化图标为默认图标
wce.hCursor = LoadCursor(NULL,IDC_ARROW); // 窗口采用箭头光标
wce.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
wce.lpszMenuName = NULL;
wce.lpszClassName = L"Window";
wce.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wce);
// 打开窗口
Win.hWnd = CreateWindow(L"Window", L"扫雷", WINDOW_STYLES, CW_USEDEFAULT,
CW_USEDEFAULT, 100, 100, NULL, NULL, hInstance, NULL);
if (Win.hWnd == NULL)
return -1;
ShowWindow(Win.hWnd, nCmdShow);
// 调整客户区大小
GetWindowRect(Win.hWnd, &rect);
rect.right = rect.left + Game.Width * CELL_SIZE;
rect.bottom = rect.top + (Game.Height + 2) * CELL_SIZE;
AdjustWindowRect(&rect, WINDOW_STYLES, FALSE); // 根据客户区大小计算窗口大小
w = rect.right - rect.left; // 宽度 20*25 应该是 大于500
h = rect.bottom - rect.top; // 高度 15*25 应该是 大于375
MoveWindow(Win.hWnd, rect.left, rect.top, w, h, TRUE);
toString(Game.Rated_MineNum, text, 32);
Win.lButton = CreateWindow(L"Button", (LPCTSTR) text, WS_CHILD | WS_VISIBLE, 10, 5,
CELL_SIZE * 2, CELL_SIZE * 2 - 10, Win.hWnd, 0, hInstance, NULL);
Win.Button = CreateWindow(L"Button", L"∩_∩", WS_CHILD | WS_VISIBLE, (Game.Width - 2) / 2 * CELL_SIZE,
5, CELL_SIZE * 2, CELL_SIZE * 2 - 10, Win.hWnd, 0, hInstance, NULL);
Win.rButton = CreateWindow(L"Button", L"0", WS_CHILD | WS_VISIBLE, (Game.Width - 2) * CELL_SIZE - 5,
5, CELL_SIZE * 2, CELL_SIZE * 2 - 10, Win.hWnd, 0, hInstance, NULL);
if ((Win.lButton == NULL) || (Win.Button == NULL) || (Win.rButton == NULL))
return -1;
SetTimer(Win.hWnd, 0, 1000, NULL); // 设置时钟
// 创建按钮,成为雷区
for (int y = 0; y < Game.Height; y++)
for (int x = 0; x < Game.Width; x++)
MineField.hWnd [x][y] = CreateWindow(L"Button", L" ", WS_CHILD | WS_VISIBLE,
x * CELL_SIZE, (y + 2)* CELL_SIZE, CELL_SIZE, CELL_SIZE, Win.hWnd,
(HMENU)(y * 256 + x), hInstance, NULL);
if (MineField.hWnd [x][y] == NULL)
return -1;
// end if
// 改变按钮消息接收函数地址,在此之前,记录原地址
MineField.Proc = (WNDPROC)GetWindowLong(MineField.hWnd [x][y], GWL_WNDPROC);
SetWindowLong(MineField.hWnd [x][y], GWL_WNDPROC, (LONG)MineFieldProc);
// next x
// next y
NewGame();
SetFocus(MineField.hWnd [0][0]);
// 接收消息
while (GetMessage(&msg, NULL, 0, 0))
TranslateMessage(&msg);
DispatchMessage(&msg);
return msg.wParam;
代码很乱,将就看吧
本回答被提问者和网友采纳C语言游戏超详解扫雷游戏完整版,细节满满!!
目录
扫雷
实现扫雷的算法有很多种,我在这里给大家最详细的代码介绍以及思考方法,细节满满哦!!
扫雷游戏规则介绍
每个格子有两种状态,有地雷或者没有地雷。玩家点到地雷游戏结束,玩家标记出所有地雷游戏胜利。
每个没有地雷的格子点开后显示相邻8个格子里面存在地雷的数目,周边没有地雷则可以递归地打开与空相邻的方块;如果不幸触雷,则游戏结束。
如何将扫雷游戏实现代码
与上次三子棋游戏模块一致,分类创建:
game.h:相关游戏函数的声明,变量的宏定义等;
game.c:游戏相关函数的功能实现;
test.c:游戏的测试,游戏的主题体;
基本思路
1.创建和打印游戏菜单
2.创建两个棋盘数组,一个是布置雷的棋盘数组,一个是排查雷的棋盘数组
3.初始化两个棋盘,为了防止后期统计排查雷的个数出现矛盾,所以我这里把布置雷的那个棋盘全部初始为'0',把排查雷的棋盘全部初始化为'*'
4.打印棋盘
5.布置雷,由电脑自主完成随机布置雷的个数,个数可以自己在头文件中定义
6.排查雷,在布置雷的数组里排查,如果是雷则打印被炸死,并退出游戏,打印排查雷的棋盘;如果不是雷,则统计雷的个数,是0则展开空白,不是0则将雷的个数传给排查雷的那个数组
7.判断输赢,如果空格的总的个数于行和列的乘积减去布雷的个数,则表示排雷成功
分步代码实现
创建和打印游戏菜单
void menu()
printf("**********************\\n");
printf("******* 1.play *******\\n");
printf("******* 0.exit *******\\n");
printf("**********************\\n");
int main()
int input = 0;
srand((unsigned int)time(NULL));//用于随机函数rand的调用
do
menu();
scanf_s("%d", &input);
switch (input)
case 1:
printf("扫雷游戏开始\\n");
game();
break;
case 0:
printf("退出游戏\\n");
break;
default:
printf("输入错误,请重新选择!\\n");
while (input);
return 0;
初始化棋盘
//两个数组初始化数组的实现,char board[ROWS][COLS]接收mine数组和show数组
//这里设置一个字符set接收mine和show数组传参过来的‘0’和‘*’
void Initboard(char board[ROWS][COLS], int rows, int cols,char set)
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
board[i][j] = set;
这里的初始化函数调用两次,分别初始化布雷数组和排雷数组,字符set分别接收'0'和'*';
打印棋盘
void Displayboard(char board[ROWS][COLS], int row, int col)
int i = 0;
int j = 0;
printf("————扫雷游戏 ————\\n");
for (i = 0; i <= col; i++)
printf("%d ", i); //为了方便用户判断行数和列数,将列数打印出来
printf("\\n");
for (i = 1; i <= row; i++)
printf("%d ", i); //每行开头打印行数
for (j = 1; j <=col; j++)
printf("%c ", board[i][j]);
printf("\\n");
printf("————扫雷游戏————\\n");
打印棋盘结果如下:
这样打印出来的棋盘好看也方便用户写入坐标
布置雷
void Setmine(char mine[ROWS][COLS], int row, int col)
int count = SETCOUNT; //为了灵活变通,可以自己设置布置雷的个数,在头文件中自定义个数
while (count) //直到count为0才退出循环,并且每次都是随机坐标布置雷,count是几,
x和y就要随机几次
int x = rand() % row + 1;//用户输入的坐标的范围就是行数列数的范围,应该是row+1才是正确
的坐标范围
int y = rand() % col + 1;
if (mine[x][y] == '0')
mine[x][y] = '1';
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 - SETCOUNT)
int count_blank = 0;//空白个数,每次进入循环都要重置,如果放在循环外面依旧是上一次的值会重复叠加空白;
printf("请输入排查雷的坐标:\\n");
scanf_s("%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;
else
int count_mine = get_mine_count(mine, x, y);
if (count_mine == 0 && show[x][y]=='*')//周围雷的个数为0,且没有被遍历
count_blank=get_showblank(mine, show, x, y);//递归展开空白,返回空白个数
win += count_blank;//空白的个数加到不是雷个数的总数中
else if(show[x][y]=='*')//这里用else不太合适,这里控制的条件是当周围个数不是0,但是没有被遍历
show[x][y] = count_mine + '0';//不是雷,则统计周围有几个雷,放入show数组对应坐标
win++;//他统计了周围雷的个数,但本身不是雷,加1
Displayboard(show, row, col);
else
printf("坐标不合法,请重新输入!\\n");
if (win== row * col - SETCOUNT)
printf("恭喜你,排雷成功!\\n");
Displayboard(show, row, col);
当排查雷时,(x,y)处不是雷且周围雷的个数不为0则需要统计周围雷的个数:
static int get_mine_count(char mine[ROWS][COLS], int x,int y) //static修饰函数,那这个函数
就只能在当前源文件里使用了
//统计这些坐标周围有几个雷
return mine[x][y - 1] +
mine[x - 1][y - 1] +
mine[x + 1][y - 1] +
mine[x - 1][y] +
mine[x - 1][y + 1] +
mine[x][y + 1] +
mine[x + 1][y + 1] +
mine[x + 1][y] - 8 * '0'; //这里返回的是数字,num+'0'='num';即一个数字加上字符0等于数字代表的字符
当(x,y)周围雷的个数为0时展开为空格,去递归遍历周围四个坐标雷的个数,并且统计空格的个数:
int get_showblank(char mine[ROWS][COLS], char show[ROWS][COLS], int x , int y)//当雷的个数为0时计算展开的空白个数
int count_mine = get_mine_count(mine, x,y);
int count_blank = 0;//初始化空白的个数
if(count_mine == 0)
show[x][y] = ' ';
count_blank++;//只要是空白就加1;下次递归也一样
//判断周围四个坐标合法性,并且要满足没有被遍历,依旧是*号,以防重复遍历
if (x - 1 >= 1 && x - 1 <= ROW && y >= 1 && y <= COL && show[x - 1][y] == '*')
count_blank+=get_showblank(mine, show, x - 1, y);//每递归一次,空白个数要累加,包括了x,y的空白和周围四个坐标的空白;
if (x >= 1 && x <= ROW && y - 1 >= 1 && y - 1 <= COL && show[x][y - 1] == '*')
count_blank += get_showblank(mine, show, x, y - 1);
if (x + 1 >= 1 && x + 1 <= ROW && y >= 1 && y <= COL && show[x + 1][y] == '*')
count_blank += get_showblank(mine, show, x + 1, y);
if (x >= 1 && x <= ROW && y + 1 >= 1 && y + 1 <= COL && show[x][y + 1] == '*')
count_blank += get_showblank(mine, show, x, y + 1);
return count_blank;//返回空白个数
游戏主体——game()函数
void game()
char mine[ROWS][COLS] = 0 ; //创建存放布置雷的数组
char show[ROWS][COLS] = 0 ; //创建存放排查雷的数组
Initboard(mine, ROWS, COLS,'0'); //初始化布置雷的棋盘,mine表示布置雷数组的首地址
Initboard(show, ROWS, COLS, '*'); //初始化排查雷的数组,show表示排查雷数组的首地址
//Displayboard(mine, ROW, COL); //打印布置雷的棋盘,这里不用打印扩展的两行两列,只需在中间的棋盘布雷,扫雷也同样
Displayboard(show, ROW, COL);
Setmine(mine, ROW, COL); //布置雷
//Displayboard(mine, ROW, COL);
Findmine(mine,show, ROW, COL); //排查雷
扫雷游戏主体函数则相比三子棋简单,只需要调用游戏相关函数即可,这里需要注意的是在调用这些函数进行数组传参时,要注意参数的顺序,这里创建mine和show数组都是用的ROWS和COLS,所以在实现相关函数的功能时用的依然是ROWS和COLS。
总代码实现
game.h
#pragma once
#define ROW 9
#define COL 9
#define SETCOUNT 10
#define ROWS ROW+2 //为了能成功遍历边界的棋盘,所以需要创建两个扩展的数组将布雷和扫雷一一对应,初始化时也一样要扩展
#define COLS COL+2
void Initboard(char board[ROWS][COLS], int rows, int cols,char set);
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);
test.c
#include<stdio.h>
#include"game.h"
#include<stdlib.h>
#include<time.h>
void game()
char mine[ROWS][COLS] = 0 ; //创建存放布置雷的数组
char show[ROWS][COLS] = 0 ; //创建存放排查雷的数组
Initboard(mine, ROWS, COLS,'0'); //初始化布置雷的棋盘,mine表示布置雷数组的首地址
Initboard(show, ROWS, COLS, '*'); //初始化排查雷的数组,show表示排查雷数组的首地址
//Displayboard(mine, ROW, COL); //打印布置雷的棋盘,这里不用打印扩展的两行两列,只需在中间的棋盘布雷,扫雷也同样
Displayboard(show, ROW, COL);
Setmine(mine, ROW, COL); //布置雷
//Displayboard(mine, ROW, COL);
Findmine(mine,show, ROW, COL); //排查雷
void menu()
printf("**********************\\n");
printf("******* 1.play *******\\n");
printf("******* 0.exit *******\\n");
printf("**********************\\n");
int main()
int input = 0;
srand((unsigned int)time(NULL));//用于随机函数rand的调用
do
menu();
scanf_s("%d", &input);
switch (input)
case 1:
printf("扫雷游戏开始\\n");
game();
break;
case 0:
printf("退出游戏\\n");
break;
default:
printf("输入错误,请重新选择!\\n");
while (input);
return 0;
game.c
#include<stdio.h>
#include"game.h"
//两个数组初始化数组的实现,char board[ROWS][COLS]接收mine数组和show数组
//这里设置一个字符set接收mine和show数组传参过来的‘0’和‘*’
void Initboard(char board[ROWS][COLS], int rows, int cols,char set)
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
board[i][j] = set;
void Displayboard(char board[ROWS][COLS], int row, int col)
int i = 0;
int j = 0;
printf("————扫雷游戏 ————\\n");
for (i = 0; i <= col; i++)
printf("%d ", i); //为了方便用户判断行数和列数,将列数打印出来
printf("\\n");
for (i = 1; i <= row; i++)
printf("%d ", i); //每行开头打印行数
for (j = 1; j <=col; j++)
printf("%c ", board[i][j]);
printf("\\n");
printf("————扫雷游戏————\\n");
void Setmine(char mine[ROWS][COLS], int row, int col)
int count = SETCOUNT; //为了灵活变通,可以自己设置布置雷的个数,在头文件中自定义个数
while (count)
//直到count为0才退出循环,并且每次都是随机坐标布置雷,count是几,x和y就要随机几次
int x = rand() % row + 1;//用户输入的坐标的范围就是行数列数的范围,应该是row+1才是正确的坐标范围
int y = rand() % col + 1;
if (mine[x][y] == '0')
mine[x][y] = '1';
count--;//每布置一个,雷的个数就减一;
static int get_mine_count(char mine[ROWS][COLS], int x,int y) //static修饰函数,那这个函数就只能在当前源文件里使用了
//统计这些坐标周围有几个雷
return mine[x][y - 1] +
mine[x - 1][y - 1] +
mine[x + 1][y - 1] +
mine[x - 1][y] +
mine[x - 1][y + 1] +
mine[x][y + 1] +
mine[x + 1][y + 1] +
mine[x + 1][y] - 8 * '0'; //这里返回的是数字,num+'0'='num';即一个数字加上字符0等于数字代表的字符
int get_showblank(char mine[ROWS][COLS], char show[ROWS][COLS], int x , int y)//当雷的个数为0时计算展开的空白个数
int count_mine = get_mine_count(mine, x,y);
int count_blank = 0;//初始化空白的个数
if(count_mine == 0)
show[x][y] = ' ';
count_blank++;//只要是空白就加1;下次递归也一样
//判断周围四个坐标合法性,并且要满足没有被遍历,依旧是*号,以防重复遍历
if (x - 1 >= 1 && x - 1 <= ROW && y >= 1 && y <= COL && show[x - 1][y] == '*')
count_blank+=get_showblank(mine, show, x - 1, y);//每递归一次,空白个数要累加,包括了x,y的空白和周围四个坐标的空白;
if (x >= 1 && x <= ROW && y - 1 >= 1 && y - 1 <= COL && show[x][y - 1] == '*')
count_blank += get_showblank(mine, show, x, y - 1);
if (x + 1 >= 1 && x + 1 <= ROW && y >= 1 && y <= COL && show[x + 1][y] == '*')
count_blank += get_showblank(mine, show, x + 1, y);
if (x >= 1 && x <= ROW && y + 1 >= 1 && y + 1 <= COL && show[x][y + 1] == '*')
count_blank += get_showblank(mine, show, x, y + 1);
return count_blank;//返回空白个数
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 - SETCOUNT)
int count_blank = 0;//空白个数,每次进入循环都要重置,如果放在循环外面依旧是上一次的值会重复叠加空白;
printf("请输入排查雷的坐标:\\n");
scanf_s("%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;
else
int count_mine = get_mine_count(mine, x, y);
if (count_mine == 0 && show[x][y]=='*')//周围雷的个数为0,且没有被遍历
count_blank=get_showblank(mine, show, x, y);//递归展开空白,返回空白个数
win += count_blank;//空白的个数加到不是雷个数的总数中
else if(show[x][y]=='*')//这里用else不太合适,这里控制的条件是当周围个数不是0,但是没有被遍历
show[x][y] = count_mine + '0';//不是雷,则统计周围有几个雷,放入show数组对应坐标
win++;//他统计了周围雷的个数,但本身不是雷,加1
Displayboard(show, row, col);
else
printf("坐标不合法,请重新输入!\\n");
if (win== row * col - SETCOUNT)
printf("恭喜你,排雷成功!\\n");
Displayboard(show, row, col);
总结
这是扫雷优化也叫完整版的扫雷游戏,博主花了一天时间思考和修改代码,整理博客,实属不易。这让我感觉到每一个游戏的实现离不开每一个细节的把控,如果忽略一个细节,整个游戏就无法完成。扫雷游戏细节颇多,对于我们的思考能力和代码实现能力有一定考验,彻底掌握则需要我们反复去琢磨,去动手实现,只有这样我们才能变得更强。如果这篇文章能帮助到你,请给我一键三连,有了大家的鼓励和指教我才能更进一步!!谢谢大家
以上是关于扫雷游戏 c语言的主要内容,如果未能解决你的问题,请参考以下文章