目录
关于扫雷的普通实现和扫雷展开一片的实现已经在之前的博客中有过详细介绍,所以这里不做再次详细的说明,该篇文章将主要以实现标记雷和显示剩余雷数的功能为主,若想直线如何做到展开一片,可以进行查看之前的博客,在此附上链接:
扫雷的简易实现https://blog.csdn.net/weixin_72883322/article/details/127793890扫雷展开一片的实现
https://blog.csdn.net/weixin_72883322/article/details/127869684
一.实现逻辑
首先,由于作者还没有学习过c语言图形库,所以没办法做到像真正的扫雷游戏那样用右键来标记雷,之后作者一定会花时间学习一下图形库,将扫雷再次完善,如果有感兴趣的小伙伴也可以学习一下(c语言图形库是easy X,大学课堂不会教这个,可以去b大学查找相关资料)。
在无法使用右击鼠标的情况下想要做到标记雷,作者想了一个退而求其次的方法,就是将扫雷的操作排查雷,标记雷,取消标记(为避免错误标记,这个操作是必须的)用一个菜单的形式让作者来选择想要执行的操作(及每次在作者选择要操作的坐标之前,先让玩家选择要对该坐标执行什么操作),如果大家能想到更好的方法,欢迎评论区留言!效果如下:
然后解决了如何做到能让玩家选择模式之后,想要显示剩余雷数,就需要改进一下打印棋盘的函数(详情参见作者的扫雷的简易实现博客),然后在玩家每次标记雷之后,可以用传值调用的方式来修改剩余雷数,这就是大致的实现方式了。
二.具体实现
2.1 打印能够显示剩余雷数的函数
首先来看看要做到的效果:
要做到如此,首先要调整函数声明,在打印时将剩余雷数传给打印函数,下面是函数代码:
void print_board(char board[][COLS], int row, int col, int m)
{
int j = 0;
int i = 0;
printf("-----------扫雷----------\n");
for (i = 0; i <= row; i++)
{
if (i == 0)
printf(" ");
else
printf("%d ", i);
}
//这是为了让游戏可玩度更高,打印出了一个标识行
printf("\n");
for (i = 0; i <= row; i++)
{
printf("--");
if (i == 0)
printf("|");
}
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("剩余雷数:%d\n", m);
printf("-----------扫雷----------\n");
}//
2.2如何让玩家在选择其想进入的模式后就行对应操作
这里我用一个变量接受玩家输入的对应操作的标签,然后对应的标签将执行对应的程序,大致框架如下:
while(win<ROW * COL - EASY_PATTERN)//为什么这么做请查看扫雷简易实现的博客
{
int input = 0;
menu1();//打印选项菜单
printf("请输入你想进入的模式:>");
scanf("%d", &input);
system("cls");//为了让界面更美观
if (input == 1)
{
//进行排查雷的相关操作
}
else if (input == 0)
{
//进行标记雷相关的操作
}
else if(input == 3)
{
//进行取消标记的相关操作
}
else //输入的数字和菜单上没有对应的操作,提示用户重新输入
printf("输入错误,请重新输入。");
}
做到这之后,为了能够模块化设计程序,我们将标记雷和取消标记雷的操作分别用函数来包装起来,分别是sign_mine和第三_sign_mine,接下来作者会分别讲述如何实现这两块功能。
2.2标记雷(sign-mine函数实现)
首先我们大致想法如下,因为标记雷操作不需要对放置雷的棋盘进行操作,所以再给函数传递参数时,只需要传递显示的棋盘对其进行操作即可,同样,为了让函数能够看到规定范围的棋盘,我们需要传递行数和列数给行数,对用来标记的雷,我们用‘#’来表示已经标记,并且每次标记后通过传址调用的形式来使剩余雷数减一,同时我们要检查玩家给的坐标的正确性,若坐标错误或者已经被标记,提示玩家重新进行输入,大体思路就是这样 ,代码如下:
void sign_mine(char show[][COLS],int * m)
{
int x = 0;
int y = 0;
printf("请输入你要标记的雷的坐标:>");
scanf("%d %d", &x, &y);
while (1)
{
if (x<1 || y<1 || x>ROW || y>COL)
printf("输入错误!\n");
else
{
if (show[x][y] == '*')
{
show[x][y] = '#';
(*m)--;
break;
}
else
{
if (show[x][y] == '#')
printf("该位置已经被标记过,请重新输入!");
else
printf("该位置已经被排查过,请重新输入!");
}
}
}
}
2.3取消标记(dis_sign_mine)的实现
其实在知道如何实现sign_mine的实现之后,dis_sign_mine的实现也是类似的原理,这里我们要想一个问题,是否要检查玩家输入坐标是否被标记过呢? 这里我仔细思考了一下,最后觉得没这个必要,因为如果玩家不小心错误进入了取消标记雷的模式,那只需要随意输入一个坐标就可以关闭这个模式,不用再刻意的解除一个错误的标记。
同样,由于取消标记也不会对放置雷的棋盘进行操作,所以跟sign_mine函数一样不用把放置雷的二维数组传入,同时也要检查坐标合理性,另外,如果坐标被排查过,也不能对其进行修改,综上,代码如下:
void dis_sign_board(char show[][COLS], int* m)
{
int x = 0, y = 0;
printf("请输入要取消标记的坐标:>");
scanf("%d %d", &x, &y);
while (1)
{
if(x<1||x>ROW||y<1||y>COL)
printf("输入错误!\n");
else
{
if (show[x][y] == '#')
{
show[x][y] = '*';
(*m)++;
break;
}
else
{
if (show[x][y] == '*')
{
printf("该坐标没有被标记,无需取消标记!");
break;
}
else
printf("该坐标已经被排查,取消标记无效!");
}
}
}
}
至此,扫雷任务圆满完成,期待图形界面的实现哈哈哈!!!接下来附上全部代码
三.代码总览
3.1game.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_PATTERN 10
//初始化棋盘
void init_board(char board[][COLS], int rows, int cols, char c);
//打印棋盘
void print_board(char board[][COLS], int row, int col,int m);
//布置雷
void set_mine(char board[][COLS], int row, int col);
//排查雷
void mine_operate(char mine[][COLS], char show[][COLS], int row, int col);//
3.2text.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu(void)
{
printf("-------- 扫雷 ---------\n");
printf("************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exit *******\n");
printf("************************\n");
}
void game(void)
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
init_board(mine, ROWS, COLS, '0');
init_board(show, ROWS, COLS, '*');
set_mine(mine, ROW, COL);
system("cls");
mine_operate(mine, show, ROW , COL);//
}
void text(void)
{
srand((unsigned int)time(NULL));
int choice = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &choice);
switch (choice)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while (choice);
}
int main(void)
{
text();
return 0;
}
3.3game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void init_board(char board[][COLS], int rows, int cols, char c)
{//c为初始化内容的指定,用此技巧可以一个函数完成两个初始化功能
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
board[i][j] = c;
}
}
void print_board(char board[][COLS], int row, int col,int m)
{
int j = 0;
int i = 0;
printf("-----------扫雷----------\n");
for (i = 0; i <= row; i++)
{
if (i == 0)
printf(" ");
else
printf("%d ", i);
}
//这是为了让游戏可玩度更高,打印出了一个标识行
printf("\n");
for (i = 0; i <= row; i++)
{
printf("--");
if (i == 0)
printf("|");
}
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("剩余雷数:%d\n", m);
printf("-----------扫雷----------\n");
}//
void set_mine(char board[][COLS], int row, int col)
{
int count = 0;
while (count < EASY_PATTERN)
{
int i = rand() % row + 1;
int j = rand() % col + 1;
if (board[i][j] != '1')
{
count++;
board[i][j] = '1';
}
}
}
int mine_num(char board[][COLS], int x, int y)
{
return board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1]
+ board[x][y - 1] + board[x][y + 1] + board[x + 1][y - 1]
+ board[x + 1][y] + board[x + 1][y + 1]-8*'0';
}
void open_board(char show[][COLS],char mine[][COLS],int x,int y,int * z,int row,int col)
{
int count = 0;
count = mine_num(mine, x, y);
if (count == 0 && show[x][y] == '*'&&x>=1&&x<=row&&y>=1&&y<=col)
{
show[x][y] = ' ';
//print_board(show, ROW, COL);
(*z)++;
open_board(show, mine, x - 1, y - 1,z,row,col);
open_board(show, mine, x - 1, y,z, row, col);
open_board(show, mine, x - 1, y+1,z, row, col);
open_board(show, mine, x , y - 1,z, row, col);
open_board(show, mine, x , y + 1,z, row, col);
open_board(show, mine, x + 1, y - 1,z, row, col);
open_board(show, mine, x + 1, y ,z, row, col);
open_board(show, mine, x + 1, y + 1,z, row, col);
}
else if (count != 0 && show[x][y] == '*' && x >= 1 && x <= row && y >= 1 && y <= col)
{
show[x][y] = count + '0';
(*z)++;
}
}
void sign_mine(char show[][COLS],int * m)
{
int x = 0;
int y = 0;
printf("请输入你要标记的雷的坐标:>");
scanf("%d %d", &x, &y);
while (1)
{
if (x<1 || y<1 || x>ROW || y>COL)
printf("输入错误!\n");
else
{
if (show[x][y] == '*')
{
show[x][y] = '#';
(*m)--;
break;
}
else
{
if (show[x][y] == '#')
printf("该位置已经被标记过,请重新输入!");
else
printf("该位置已经被排查过,请重新输入!");
}
}
}
}
void menu1()
{
printf("******************************\n");
printf("***** 1. clear_mine *****\n");
printf("***** 0.mark_mine *****\n");
printf("***** 3.unmark_mine *****\n");
}
void dis_sign_board(char show[][COLS], int* m)
{
int x = 0, y = 0;
printf("请输入要取消标记的坐标:>");
scanf("%d %d", &x, &y);
while (1)
{
if(x<1||x>ROW||y<1||y>COL)
printf("输入错误!\n");
else
{
if (show[x][y] == '#')
{
show[x][y] = '*';
(*m)++;
break;
}
else
{
if (show[x][y] == '*')
{
printf("该坐标没有被标记,无需取消标记!");
break;
}
else
printf("该坐标已经被排查,取消标记无效!");
}
}
}
}
void mine_operate(char mine[][COLS], char show[][COLS], int row, int col)
{
int i = 0;
int j = 0;
int count = 0;
int win = 0;
int m = EASY_PATTERN;//
while (win < ROW * COL - EASY_PATTERN)
{
system("cls");
int input = 0;
print_board(show, ROW, COL, m);
menu1();//
printf("请输入你想进入的模式:>");
scanf("%d", &input);
system("cls");
//print_board(mine, ROW, COL);
if (input == 1)
{
print_board(show, ROW, COL, m);
printf("请输入要排查的坐标:>");
scanf("%d %d", &i, &j);
if (i >= 1 && i <= row && j >= 1 && j <= col)
{
if (show[i][j] == '*')
{
open_board(show, mine, i, j, &win, ROW, COL);
if (mine[i][j] == '1')
{
printf("你被炸死了,真惨!\n");
Sleep(500);
break;
}
}
else
{
if (show[i][j] == '#')
printf("该坐标已经被标记!\n");
else
printf("该坐标已经被排查过,请重新输入!\n");
Sleep(500);
}
}
else
{
printf("输入错误,请重新输入!\n");
Sleep(500);
}
system("cls");
}
else if (input == 0)
{
print_board(show, ROW, COL, m);
sign_mine(show, &m);
}
else if (input == 3)
{
print_board(show, ROW, COL, m);
dis_sign_board(show, &m);
}
else
{
printf("输入错误,请重新输入!");
Sleep(1000);
}
}
if (win == ROW * COL - EASY_PATTERN)
{
printf("你真是个排雷大师呢!\n");
print_board(mine, ROW, COL, m);
}
else
{
printf("真遗憾,下次努力把。\n");
print_board(mine, ROW, COL, m);
}
}