本人菜鸟一枚,文章中有那些错误或者有一些改进的意见,希望各位大神可以指正。
首先写任何代码之前要明白自己的代码功能,即要解决的问题、或者要实现的功能。(我没写图形界面,只完成了游戏的逻辑)。
我的扫雷游戏要实现功能有:
<1>玩家走第一步不能被炸死
<2>显示该点周围有几颗雷
<3>如果坐标周围没有雷,可以实现展开
然后我们来分析扫雷游戏的逻辑(最后附源代码)
<1>首先我们得有雷可扫,所以我们应该先制作棋盘,而棋盘,就是一个二维数组。
(1)因为以后我们要计算周围雷的个数,保证数组不越界,所以多两行两列
(2)因为不能显示雷的位置,所以我们制作两个二维数组,一个定义雷,一个显示给玩家
(3)我们需要初始化棋盘和打印棋盘,因为以后要反复初始化和打印,所以定义为函数
//初始化棋盘
void InitiaBorder(char border[ROWS][COLS], int row, int col,char set)
{
memset(border, set, col*row*sizeof(border[0][0]));
}
// 打印棋盘
void ShowBorder(char border[ROWS][COLS], int row, int col)
{
int i = 0;
//打印第一行
for (int i = 0; i < col-2; i++)
{
if (i == 0)
printf("|");
printf("---|");
}
printf("\n");
for (i = 1; i < row-1; i++)
{
int j = 0;
printf("|");//每行第一个打印一个|
//打印( %c |)
for (j = 1; j < col-1; j++)
{
printf(" %c |", border[i][j]);
}
printf("\n");
//打印(---|)
for (j = 0; j < col-2; j++)
{
if (j == 0)
printf("|");//每行第一个打印一个 |
printf("---|");
}
printf("\n");
}
}
<2>然后我们需要产生雷,将此功能封装为函数
//产生雷
void CreateMine(char border[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = EASY ;
while (count)
{
x = rand() % (row - 2) + 1;
y = rand() % (col - 2) + 1;
if (border[x][y] == '0')
{
border[x][y] = '1';
count--;
}
}
}
<3>用户扫雷
(1)用户首先输入坐标,先判断是否合法(是否在区域内),然后再判断是否该坐标已经被扫
(2)如果(1)条件满足,我们需要判断是否为雷,如果是雷,则游戏结束(先不考虑第一步被炸死)
(3)如果不是雷,则需要判断周围雷的数量(先不考虑展开),所以需要一个函数来判断周围雷的数量
//计算雷的数量
char MineCount(char border[ROWS][COLS],int x, int y)
{
return border[x - 1][y] + border[x - 1][y + 1] + border[x][y + 1] + border[x + 1][y + 1]
+ border[x + 1][y] + border[x + 1][y - 1] + border[x][y - 1] + border[x - 1][y - 1] - 7 * '0';
}
(4)现在我们来实现如果周围雷的数量为0,实现展开,
在实现展开时,我们应该先判断周围的区域是否已经被判断,如果已经被判断,如果再判断会造成死循环
//判断是否已经展开
int IsBlack(char border[ROWS][COLS],int row,int col,int x, int y)
{
if ((border[x][y] == '*'&&x >= 1 && x < row - 1 && y >= 1 && y < col - 1))
{
return 1;
}
return -1;
}
然后我们再判断周围的八个点(周围的八个点如果为零,则需要在判断,这就是递归)
//判断周围的雷
void JudegeMineCount(char border1[ROWS][COLS], char border2[ROWS][COLS],int x, int y)
{
int Judge = 1;
if (Judge == IsBlack(border2, ROWS, COLS, x, y - 1))
{
if (MineCount(border1, x, y - 1) != '0')
{
border2[x][y - 1] = MineCount(border1, x, y - 1);
}
else
{
border2[x][y - 1] = MineCount(border1, x, y - 1);
JudegeMineCount(border1, border2, x, y - 1);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x - 1, y - 1))
{
if (MineCount(border1, x - 1, y - 1) != '0')
{
border2[x - 1][y - 1] = MineCount(border1, x - 1, y - 1);
}
else
{
border2[x - 1][y - 1] = MineCount(border1, x - 1, y - 1);
JudegeMineCount(border1, border2, x - 1, y - 1);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x - 1, y))
{
if (MineCount(border1, x - 1, y) != '0')
{
border2[x - 1][y] = MineCount(border1, x - 1, y);
}
else
{
border2[x - 1][y] = MineCount(border1, x - 1, y);
JudegeMineCount(border1, border2, x - 1, y);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x - 1, y + 1))
{
if (MineCount(border1, x - 1, y + 1) != '0')
{
border2[x - 1][y + 1] = MineCount(border1, x - 1, y + 1);
}
else
{
border2[x - 1][y + 1] = MineCount(border1, x - 1, y + 1);
JudegeMineCount(border1, border2, x - 1, y + 1);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x, y + 1))
{
if (MineCount(border1, x, y + 1) != '0')
{
border2[x][y + 1] = MineCount(border1, x, y + 1);
}
else
{
border2[x][y + 1] = MineCount(border1, x, y + 1);
JudegeMineCount(border1, border2, x, y + 1);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x + 1, y + 1))
{
if (MineCount(border1, x + 1, y + 1) != '0')
{
border2[x + 1][y + 1] = MineCount(border1, x + 1, y + 1);
}
else
{
border2[x + 1][y + 1] = MineCount(border1, x + 1, y + 1);
JudegeMineCount(border1, border2, x + 1, y + 1);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x + 1, y))
{
if (MineCount(border1, x + 1, y) != '0')
{
border2[x + 1][y] = MineCount(border1, x + 1, y);
}
else
{
border2[x + 1][y] = MineCount(border1, x + 1, y);
JudegeMineCount(border1, border2, x + 1, y);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x + 1, y - 1))
{
if (MineCount(border1, x + 1, y - 1) != '0')
{
border2[x + 1][y - 1] = MineCount(border1, x + 1, y - 1);
}
else
{
border2[x + 1][y - 1] = MineCount(border1, x + 1, y - 1);
JudegeMineCount(border1, border2, x + 1, y - 1);
}
}
}
<5>实现第一步不被炸死,我们在定义一个变量count = 1;将它的地址传给找雷函数,(不能在函数内部创建,因为要多次调用找雷函数,count将每次被调用)如果第一步是雷,我们需要重新产生雷
char FindMine(char border1[ROWS][COLS], char border2[ROWS][COLS], int row, int col,int *count)
{
int x = 0;
int y = 0;
int x1 = 0;
int y1 = 0;
while (1)
{
printf("请输入要查找的坐标:");
scanf("%d%d", &x, &y);
if (x >= 1 && x < row - 1 && y >= 1 && y < col - 1)
{
if (border1[x][y] == '1'&&*count != 1)
{
return '1';
}
else
{
if ((*count) == 1 && border1[x][y] == '1')
//重新产生雷
{
border1[x][y] = '0';
while (*count)
{
x1 = rand() % (row - 2) + 1;
y1 = rand() % (col - 2) + 1;
if (border1[x1][y1] == '0')
{
border1[x1][y1] = '1';
(*count)--;
}
}
}
(*count)--;
if (border2[x][y] == '*')
{
if (MineCount(border1, x, y) != '0')
{
border2[x][y] = MineCount(border1, x, y);
}
else
{
border2[x][y] = MineCount(border1, x, y);
JudegeMineCount(border1, border2, x, y);
}
return 0;
}
else
{
printf("该坐标已被判断!!\n");
}
}
}
else
{
printf("请输入合法坐标\n");
}
}
}
<6>当未知区域等于雷的个数,游戏胜利,所以我们需要一个函数来计算当前未知区域的个数
//未判断的数量
int BlackCount(char border[ROWS][COLS],int row,int col)
{
int blackcount = 0;
int i = 1;
for (i = 1; i <= row; i++)
{
int j = 1;
for (j = 1; j <= col; j++)
{
if (border[i][j] == '*')
blackcount++;
}
}
return blackcount;
}
源代码
头文件
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#define EASY 20
#define ROW 10
#define COL 10
#define ROWS ROW + 2
#define COLS COL + 2
//初始化棋盘
void InitiaBorder(char border[ROWS][COLS], int row, int col,char set);
// 打印棋盘
void ShowBorder(char border[ROWS][COLS], int row, int col);
//产生雷
void CreateMine(char border[ROWS][COLS], int row, int col);
//找雷
char FindMine(char border1[ROWS][COLS],char border2[ROWS][COLS],int row, int col,int *count);
//未判断的数量
int BlackCount(char border[ROWS][COLS],int row,int col);
函数实现
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
//初始化棋盘
void InitiaBorder(char border[ROWS][COLS], int row, int col,char set)
{
memset(border, set, col*row*sizeof(border[0][0]));
}
// 打印棋盘
void ShowBorder(char border[ROWS][COLS], int row, int col)
{
int i = 0;
//打印第一行
for (int i = 0; i < col-2; i++)
{
if (i == 0)
printf("|");
printf("---|");
}
printf("\n");
for (i = 1; i < row-1; i++)
{
int j = 0;
printf("|");//每行第一个打印一个|
//打印( %c |)
for (j = 1; j < col-1; j++)
{
printf(" %c |", border[i][j]);
}
printf("\n");
//打印(---|)
for (j = 0; j < col-2; j++)
{
if (j == 0)
printf("|");//每行第一个打印一个 |
printf("---|");
}
printf("\n");
}
}
//产生雷
void CreateMine(char border[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = EASY ;
while (count)
{
x = rand() % (row - 2) + 1;
y = rand() % (col - 2) + 1;
if (border[x][y] == '0')
{
border[x][y] = '1';
count--;
}
}
}
//计算雷的数量
char MineCount(char border[ROWS][COLS],int x, int y)
{
return border[x - 1][y] + border[x - 1][y + 1] + border[x][y + 1] + border[x + 1][y + 1]
+ border[x + 1][y] + border[x + 1][y - 1] + border[x][y - 1] + border[x - 1][y - 1] - 7 * '0';
}
//判断是否已经展开
int IsBlack(char border[ROWS][COLS],int row,int col,int x, int y)
{
if ((border[x][y] == '*'&&x >= 1 && x < row - 1 && y >= 1 && y < col - 1))
{
return 1;
}
return -1;
}
//判断周围的雷
void JudegeMineCount(char border1[ROWS][COLS], char border2[ROWS][COLS],int x, int y)
{
int Judge = 1;
if (Judge == IsBlack(border2, ROWS, COLS, x, y - 1))
{
if (MineCount(border1, x, y - 1) != '0')
{
border2[x][y - 1] = MineCount(border1, x, y - 1);
}
else
{
border2[x][y - 1] = MineCount(border1, x, y - 1);
JudegeMineCount(border1, border2, x, y - 1);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x - 1, y - 1))
{
if (MineCount(border1, x - 1, y - 1) != '0')
{
border2[x - 1][y - 1] = MineCount(border1, x - 1, y - 1);
}
else
{
border2[x - 1][y - 1] = MineCount(border1, x - 1, y - 1);
JudegeMineCount(border1, border2, x - 1, y - 1);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x - 1, y))
{
if (MineCount(border1, x - 1, y) != '0')
{
border2[x - 1][y] = MineCount(border1, x - 1, y);
}
else
{
border2[x - 1][y] = MineCount(border1, x - 1, y);
JudegeMineCount(border1, border2, x - 1, y);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x - 1, y + 1))
{
if (MineCount(border1, x - 1, y + 1) != '0')
{
border2[x - 1][y + 1] = MineCount(border1, x - 1, y + 1);
}
else
{
border2[x - 1][y + 1] = MineCount(border1, x - 1, y + 1);
JudegeMineCount(border1, border2, x - 1, y + 1);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x, y + 1))
{
if (MineCount(border1, x, y + 1) != '0')
{
border2[x][y + 1] = MineCount(border1, x, y + 1);
}
else
{
border2[x][y + 1] = MineCount(border1, x, y + 1);
JudegeMineCount(border1, border2, x, y + 1);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x + 1, y + 1))
{
if (MineCount(border1, x + 1, y + 1) != '0')
{
border2[x + 1][y + 1] = MineCount(border1, x + 1, y + 1);
}
else
{
border2[x + 1][y + 1] = MineCount(border1, x + 1, y + 1);
JudegeMineCount(border1, border2, x + 1, y + 1);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x + 1, y))
{
if (MineCount(border1, x + 1, y) != '0')
{
border2[x + 1][y] = MineCount(border1, x + 1, y);
}
else
{
border2[x + 1][y] = MineCount(border1, x + 1, y);
JudegeMineCount(border1, border2, x + 1, y);
}
}
if (Judge == IsBlack(border2, ROWS, COLS, x + 1, y - 1))
{
if (MineCount(border1, x + 1, y - 1) != '0')
{
border2[x + 1][y - 1] = MineCount(border1, x + 1, y - 1);
}
else
{
border2[x + 1][y - 1] = MineCount(border1, x + 1, y - 1);
JudegeMineCount(border1, border2, x + 1, y - 1);
}
}
}
//找雷
char FindMine(char border1[ROWS][COLS], char border2[ROWS][COLS], int row, int col,int *count)
{
int x = 0;
int y = 0;
int x1 = 0;
int y1 = 0;
while (1)
{
printf("请输入要查找的坐标:");
scanf("%d%d", &x, &y);
if (x >= 1 && x < row - 1 && y >= 1 && y < col - 1)
{
if (border1[x][y] == '1'&&*count != 1)
{
return '1';
}
else
{
if ((*count) == 1 && border1[x][y] == '1')
//重新产生雷
{
border1[x][y] = '0';
while (*count)
{
x1 = rand() % (row - 2) + 1;
y1 = rand() % (col - 2) + 1;
if (border1[x1][y1] == '0')
{
border1[x1][y1] = '1';
(*count)--;
}
}
}
(*count)--;
if (border2[x][y] == '*')
{
if (MineCount(border1, x, y) != '0')
{
border2[x][y] = MineCount(border1, x, y);
}
else
{
border2[x][y] = MineCount(border1, x, y);
JudegeMineCount(border1, border2, x, y);
}
return 0;
}
else
{
printf("该坐标已被判断!!\n");
}
}
}
else
{
printf("请输入合法坐标\n");
}
}
}
//未判断的数量
int BlackCount(char border[ROWS][COLS],int row,int col)
{
int blackcount = 0;
int i = 1;
for (i = 1; i <= row; i++)
{
int j = 1;
for (j = 1; j <= col; j++)
{
if (border[i][j] == '*')
blackcount++;
}
}
return blackcount;
}
main函数
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void game1()
{
int count = 1;
char border1[ROWS][COLS] = { '0' };
char border2[ROWS][COLS] = { '0' };
int blackcount = 0;
//初始化棋盘
InitiaBorder(border1, ROWS, COLS, '0');
InitiaBorder(border2, ROWS, COLS, '*');
blackcount = BlackCount(border2, ROW, COL);
//产生雷
CreateMine(border1, ROWS, COLS);
//产生雷后的效果
ShowBorder(border1, ROWS, COLS);
ShowBorder(border2, ROWS, COLS);
//找雷
while (blackcount>EASY)
{
char result = FindMine(border1, border2, ROWS, COLS ,&count);
//判断结果
if (result == '1')
{
printf("很遗憾,您被炸死了!\n");
ShowBorder(border1, ROWS, COLS);
break;
}
system("cls");
ShowBorder(border2, ROWS, COLS);
blackcount = BlackCount(border2, ROW, COL);
printf("当前未判断空格数:%d\n", blackcount);
}
if (blackcount == EASY)
printf("恭喜您游戏胜利!!\n");
}
void game2()
{
printf("qwe");
}
void game3()
{
printf("qwe");
}
void menu()
{
printf("********* 1、简 单 ****************\n");
printf("********* 2、中 等 ****************\n");
printf("********* 3、困 难 ****************\n");
printf("********* 0、退出游戏 ****************\n");
}
void test()
{
int input = 0;
do
{
menu();
printf("\n");
printf("请选择模式:\n");
scanf("%d", &input);
switch (input)
{
case 1:
game1();
break;
case 2:
game2();
break;
case 3:
game3();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误!\n");
break;
}
} while (input);
}
int main()
{
system("color 2E");
test();
system("pause");
return 0;
}