C语言实现扫雷游戏
C语言实现扫雷游戏,可以大致分为一下几个部分。
· 选择两个棋盘,一个棋盘负责显示,另一个棋盘进行布雷。
· 初始化两个棋盘,显示棋盘全部初始化为:‘*’
,布雷棋盘全部初始化为:‘0’
。
· 进行布雷操作,采用随机数,对布雷棋盘进行随机布雷。
· 显示棋盘。对用户输入的坐标进行显示,并将该坐标显示为附近坐标的雷数。
· 炸开输入坐标附近无雷的坐标。
· 结果判定,若显示棋盘上的‘*’
数和雷数NUM
相等,则扫雷成功。
1. 选择两个棋盘。
char board[ROW][COL];
char mine[ROW][COL];
这两个棋盘都是12 * 12 的,但显示的时候只显示10 * 10的,为什么呢?
里面是一个10 * 10的棋盘,外面为12 * 12的棋盘。
当初始化的时候,对全部进行初始化, 而当在计算的布雷和显示的时候,仅仅只显示10 * 10的棋盘。
在计算附近雷数的时候,可以很方面的计算出,第一行第一列,最后一行最后一列附近的雷数,而不用再进行if
判定。
比如这样:
这样就可以直接计算出(1,1)
坐标附近的雷数。
2.初始化棋盘
void Initial(char board[][COL], int row, int col,char p)//棋盘初始化函数,在这里,需要对全部棋盘进行初始化
{
int i = 0;
for (; i < row; i++)
{
int j = 0;
for (; j < row; j++)
{
board[i][j] = p;
}
}
}
棋盘初始化函数,在这里,需要对全部棋盘进行初始化。因为,后面需要计算输入坐标附近的雷数,则需要对整个棋盘进行初始化。
3.布雷
void SetMine(char mine[][COL], int row, int col,int n)//布雷,使用随机数进行布雷,同样,只对1~10行列进行布雷
{
while (n)
{
int i = rand() % (row - 2) + 1;
int j = rand() % (col - 2) + 1;
if (mine[i][j] == ONE)
{
continue;
}
mine[i][j] = ONE;
n--;
}
}
进行布雷,只需要对10 * 10大小的进行布雷。
ONE='1',为雷,ZERO='0',无雷。
4.显示棋盘
void Show(char board[][COL], int row, int col)//棋盘显示,这里只显示1~10行列的棋盘
{
int i = 0;
for (i = 1; i < row - 1; i++)
{
printf("%s", "---");
}
printf("---\n");
printf(" ");
for (i=1; i < row - 1; i++)
{
printf("%2d|", i);
}
printf("\n");
for (i = 1; i < row - 1; i++)
{
printf("%s", "---");
}
printf("---\n");
for (i = 1; i < row - 1; i++)
{
printf("%2d|", i);
int j = 1;
for (; j < col - 1; j++)
{
printf("%2c|", board[i][j]);
}
printf("\n");
for (j = 1; j < row - 1; j++)
{
printf("%s", "---");
}
printf("---\n");
}
}
在这里,显示同样只显示10 * 10 大小的棋盘。
5.显示输入坐标附近的雷数
char GetNum(char mine[][COL], int x, int y)//获得输入坐标附近的雷数
{
return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] +\
mine[x][y - 1] + mine[x][y + 1] + \
mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 7 * ZERO;
}
输入坐标(x,y)
,显示附近⑧个坐标总的雷数,并返回字符。‘1’=‘0’+1,‘2’=‘0’+2,‘3’=‘0’+3
6.炸开输入坐标附近的坐标
在这里,可以使用递归方式炸开,但这样炸开,直接就炸开了整个坐标系。
void Boom(char mine[][COL], char board[][COL], int x, int y)//递归展开,这样展开就展开了全部棋盘
{
char num = mine[x][y];
if (num == ZERO)
{
board[x][y] = GetNum(mine, x, y);
if (board[x - 1][y - 1] == '*')
{
Boom(mine, board, x - 1, y - 1);
}
if (board[x - 1][y ] == '*')
{
Boom(mine, board, x - 1, y );
}
if (board[x - 1][y + 1] == '*')
{
Boom(mine, board, x - 1, y + 1);
}
if (board[x ][y - 1] == '*')
{
Boom(mine, board, x , y - 1);
}
if (board[x][y + 1] == '*')
{
Boom(mine, board, x, y + 1);
}
if (board[x+1][y - 1] == '*')
{
Boom(mine, board, x+1, y - 1);
}
if (board[x + 1][y ] == '*')
{
Boom(mine, board, x + 1, y );
}
if (board[x + 1][y+1] == '*')
{
Boom(mine, board, x + 1, y+1);
}
}
}
这样炸,会将整个棋盘全部炸开,扫雷就自动实现了。
另一种方法,只炸开,输入坐标附近的⑧个坐标。
void Boom2(char mine[][COL], char board[][COL], int x, int y)//炸开输入坐标附近的几个坐标的雷数
{
board[x][y] = GetNum(mine, x, y);
if (mine[x - 1][y - 1] == ZERO)
{
board[x - 1][y - 1] = GetNum(mine, x - 1, y - 1);
}
if (mine[x - 1][y] == ZERO)
{
board[x - 1][y] = GetNum(mine, x - 1, y);
}
if (mine[x - 1][y + 1] == ZERO)
{
board[x - 1][y + 1] = GetNum(mine, x - 1, y + 1);
}
if (mine[x][y - 1] == ZERO)
{
board[x][y - 1] = GetNum(mine, x, y - 1);
}
if (mine[x][y + 1] == ZERO)
{
board[x][y + 1] = GetNum(mine, x, y + 1);
}
if (mine[x + 1][y - 1] == ZERO)
{
board[x + 1][y - 1] = GetNum(mine, x + 1, y - 1);
}
if (mine[x + 1][y] == ZERO)
{
board[x + 1][y] = GetNum(mine, x + 1, y);
}
if (mine[x + 1][y + 1] == ZERO)
{
board[x + 1][y + 1] = GetNum(mine, x + 1, y + 1);
}
}
这样就可以一步步完成扫雷。
7.结果判定
for (i = 1; i < ROW - 1; i++)//计算board上‘*’的数为多少
{
int j = 0;
for (j = 1; j < ROW - 1; j++)
{
if (board[i][j] == '*')
{
number++;
}
}
}
if (number == NUM)//若‘*’数和NUM相等,结束循环
{
break;
}
if (number == NUM)//结果判定
{
Sleep(2000);
system("cls");
printf("\n恭喜你,完美通关!\n");
}
else
{
Sleep(2000);
system("cls");
printf("\n很遗憾,游戏失败,再接再厉!\n");
}
源程序及注释:
//分了三个文件夹写
//test.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>
#pragma warning(disable:4996)
#define ROW 12 //棋盘数
#define COL 12
#define NUM 50 //雷数
#define ZERO '0' //没有雷
#define ONE '1' //雷
void Game();
void Initial(char board[][COL], int row, int col,char p);//初始化
void Show(char board[][COL], int row, int col);//显示棋盘
void SetMine(char mine[][COL], int row, int col,int n);//布雷
char GetNum(char mine[][COL],int x,int y);//获得附近的雷数
void Boom(char mine[][COL], char board[][COL], int x, int y);//递归展开
void Boom2(char mine[][COL], char board[][COL], int x, int y);//展开附近几个点的雷数
//main.c
void Menu()
{
printf("###############################\n");
printf("## 1.Play 2.Quit ##\n");
printf("###############################\n");
printf("Please input your choice:>");
}
int main()
{
int select = 1;
while (select == 1)
{
Menu();
scanf("%d", &select);
switch (select)
{
case 1:
Game();
printf("\n要不要再玩一局?\n");
break;
case 2:
break;
default:
break;
}
}
return 0;
}
//test.c
void Initial(char board[][COL], int row, int col,char p)//棋盘初始化函数,在这里,需要对全部棋盘进行初始化
{
int i = 0;
for (; i < row; i++)
{
int j = 0;
for (; j < row; j++)
{
board[i][j] = p;
}
}
}
void Show(char board[][COL], int row, int col)//棋盘显示,这里只显示1~10行列的棋盘
{
int i = 0;
for (i = 1; i < row - 1; i++)
{
printf("%s", "---");
}
printf("---\n");
printf(" ");
for (i=1; i < row - 1; i++)
{
printf("%2d|", i);
}
printf("\n");
for (i = 1; i < row - 1; i++)
{
printf("%s", "---");
}
printf("---\n");
for (i = 1; i < row - 1; i++)
{
printf("%2d|", i);
int j = 1;
for (; j < col - 1; j++)
{
printf("%2c|", board[i][j]);
}
printf("\n");
for (j = 1; j < row - 1; j++)
{
printf("%s", "---");
}
printf("---\n");
}
}
void SetMine(char mine[][COL], int row, int col,int n)//布雷,使用随机数进行布雷,同样,只对1~10行列进行布雷
{
while (n)
{
int i = rand() % (row - 2) + 1;
int j = rand() % (col - 2) + 1;
if (mine[i][j] == ONE)
{
continue;
}
mine[i][j] = ONE;
n--;
}
}
char GetNum(char mine[][COL], int x, int y)//获得输入坐标附近的雷数
{
return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] +\
mine[x][y - 1] + mine[x][y + 1] + \
mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 7 * ZERO;
}
void Boom(char mine[][COL], char board[][COL], int x, int y)//递归展开,这样展开就展开了全部棋盘
{
char num = mine[x][y];
if (num == ZERO)
{
board[x][y] = GetNum(mine, x, y);
if (board[x - 1][y - 1] == '*')
{
Boom(mine, board, x - 1, y - 1);
}
if (board[x - 1][y ] == '*')
{
Boom(mine, board, x - 1, y );
}
if (board[x - 1][y + 1] == '*')
{
Boom(mine, board, x - 1, y + 1);
}
if (board[x ][y - 1] == '*')
{
Boom(mine, board, x , y - 1);
}
if (board[x][y + 1] == '*')
{
Boom(mine, board, x, y + 1);
}
if (board[x+1][y - 1] == '*')
{
Boom(mine, board, x+1, y - 1);
}
if (board[x + 1][y ] == '*')
{
Boom(mine, board, x + 1, y );
}
if (board[x + 1][y+1] == '*')
{
Boom(mine, board, x + 1, y+1);
}
}
}
void Boom2(char mine[][COL], char board[][COL], int x, int y)//炸开输入坐标附近的几个坐标的雷数
{
board[x][y] = GetNum(mine, x, y);
if (mine[x - 1][y - 1] == ZERO)
{
board[x - 1][y - 1] = GetNum(mine, x - 1, y - 1);
}
if (mine[x - 1][y] == ZERO)
{
board[x - 1][y] = GetNum(mine, x - 1, y);
}
if (mine[x - 1][y + 1] == ZERO)
{
board[x - 1][y + 1] = GetNum(mine, x - 1, y + 1);
}
if (mine[x][y - 1] == ZERO)
{
board[x][y - 1] = GetNum(mine, x, y - 1);
}
if (mine[x][y + 1] == ZERO)
{
board[x][y + 1] = GetNum(mine, x, y + 1);
}
if (mine[x + 1][y - 1] == ZERO)
{
board[x + 1][y - 1] = GetNum(mine, x + 1, y - 1);
}
if (mine[x + 1][y] == ZERO)
{
board[x + 1][y] = GetNum(mine, x + 1, y);
}
if (mine[x + 1][y + 1] == ZERO)
{
board[x + 1][y + 1] = GetNum(mine, x + 1, y + 1);
}
}
void Game()
{
srand((int)time(0));
char board[ROW][COL];
char mine[ROW][COL];
Initial(board, ROW, COL, '*');//显示棋盘初始化,初始化为‘*’
Initial(mine, ROW, COL, ZERO);//初始化布雷棋盘,初始化为‘0’
SetMine(mine, ROW, COL,NUM);//布雷,布雷个数为NUM个,布雷为‘1’
//Show(board, ROW, COL);
//Show(mine, ROW, COL);
int number = 0;//这里是为了判定,显示棋盘上的‘*’和NUM数相等,就表示扫雷成功
while (1)
{
system("cls");
Show(board, ROW, COL);
int x = 0;
int y = 0;
int i = 0;
number = 0;
printf("请输入要扫的坐标:>");
scanf("%d %d", &x, &y);
printf("正在显示....\n");
if (x<1 || x>(ROW - 2) || y<1 || y>(ROW - 2))//对输入进行判定,输入坐标大了
{
printf("输入坐标错误,请重新输入...\n");
Sleep(1000);
continue;
}
if (board[x][y] != '*')//输入坐标被扫过了
{
printf("输入坐标已被扫过,请重新输入...\n");
Sleep(1000);
continue;
}
if (mine[x][y] == ZERO)//输入坐标无雷
{
//Boom(mine, board, x, y);//递归展开,这样展开就展开了全部
Boom2(mine, board, x, y);//炸开输入坐标附近的坐标
//char num = GetNum(mine, x, y);
//board[x][y] = num;
Sleep(1000);
}
else//输入坐标有雷
{
printf("\n游戏结束,(%d,%d)坐标有雷\n",x,y);
break;
}
for (i = 1; i < ROW - 1; i++)//计算board上面,‘*’的数为多少
{
int j = 0;
for (j = 1; j < ROW - 1; j++)
{
if (board[i][j] == '*')
{
number++;
}
}
}
if (number == NUM)//若‘*’数和NUM相等,结束循环
{
break;
}
}
if (number == NUM)//结果判定
{
Sleep(2000);
system("cls");
printf("\n恭喜你,完美通关!\n");
}
else
{
Sleep(2000);
system("cls");
printf("\n很遗憾,游戏失败,再接再厉!\n");
}
Show(mine, ROW, COL);//再显示一下mine棋盘
Sleep(2000);
}
运行结果:
需要程序的小伙伴可以来这里直接下载完整代码:扫雷游戏
未自动实现难度升级。
上一篇: 用C++和EasyX图形库编写一个简单的打砖块游戏(下)
下一篇: PHP中数据类型的转换方法