扫雷小游戏相信很多人都玩过,以前家里的电脑都会有,那时候不懂就知道瞎点,根本不知道其中的原理以及游戏规则。
现在我们就用C语言来实现简单的扫雷游戏:
简单说明下设计扫雷时的几个要求:
*第一下不会被雷炸死;
*显示该坐标点周围雷的个数;
*该坐标周围没有雷时,可以实现展开一片没有雷的区域。
首先我们得建造出棋盘,一个为设计者看的棋盘显示所以雷的分布情况(方便设计者测试),还有一个棋盘就是全部都是由*组成的游戏棋盘来给玩家扫雷。
那我们就需要用二维数组来打印这两个棋盘,假设我们要打印10X10的棋盘,我们在设计算法时需要统计坐标周围8个方位雷的个数,假如要统计边界坐标周围雷的个数,那么就会有数组越界的问题,那我们就要在10X10的边界多上一圈元素,也就要定义12X12的数组元素,而多出来的一圈数组则不需要打印出来,同时也不会造成数组越界。
首先我们先用宏定义数组的大小,ROWS和COLS为数组的大小,ROW和COL则为需要打印出来的数组的大小。
#define COL 10
#define ROW 10
#define COLS COL+2
#define ROWS ROW+2
enum MINE_COUNT
{
EASY_COUNT = 10
};
开始我们扫雷的设计:
打印设计者棋盘用数组real_mine,打印玩家棋盘用数组show_mine,将两个数组初始化,在设计者棋盘中字符0代表不是雷,字符1代表雷:
void InitBoard()
{
int i = 0;
int j = 0;
for (int i = 0; i < ROWS; i++)
{
for (j = 0; j < COLS; j++)
{
show_mine[i][j] = '*';
real_mine[i][j] = '0';
}
}
}
初始化设计者棋盘并在棋盘X轴和Y轴方向打印坐标方便测试过程中查看雷的位置:
void PrintBoard()
{
int i = 0;
int j = 0;
printf("0 ");
for (i = 1; i <ROWS - 1; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <ROW; i++)
{
printf("%d ", i);
for (j = 1; j < COLS - 1; j++)
{
printf("%c ", show_mine[i][j]);
}
printf("\n");
}
printf("10 ");
for (i = 1; i < ROWS - 1; i++)
{
printf("%c ", show_mine[10][i]);
}
printf("\n");
}
初始化玩家棋盘并在棋盘X轴和Y轴方向打印坐标方便游戏过程中正确输入自己所扫雷的坐标:
void MineBoard()
{
int i = 0;
int j = 0;
printf("0 ");
for (i = 1; i <ROWS - 1; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <ROW; i++)
{
printf("%d ", i);
for (j = 1; j < COLS - 1; j++)
{
printf("%c ", real_mine[i][j]);
}
printf("\n");
}
printf("10 ");
for (i = 1; i < ROWS - 1; i++)
{
printf("%c ", real_mine[10][i]);
}
printf("\n");
}
给棋盘布雷区,为了在每一盘游戏中雷的位置都不同我们采用产生随机坐标的方式来布雷,为了防止在最外面那一圈不使用的数组布雷所以将随机产生的横竖坐标+1:
void SetMine()
{
int x = 0;
int y = 0;
int count = EASY_COUNT;
while (count)
{
int x = rand() % 10 + 1;
int y = rand() % 10 + 1;
if (real_mine[x][y] == '0')
{
real_mine[x][y] = '1';
count--;
}
}
}
设计一个函数来统计当前坐标周围雷的个数并显示在当前坐标上:
int CountMine(int x, int y)
{
int count = 0;
if (real_mine[x - 1][y - 1] == '1')
count++;
if (real_mine[x - 1][y] == '1')
count++;
if (real_mine[x - 1][y + 1] == '1')
count++;
if (real_mine[x][y - 1] == '1')
count++;
if (real_mine[x][y + 1] == '1')
count++;
if (real_mine[x + 1][y - 1] == '1')
count++;
if (real_mine[x + 1][y] == '1')
count++;
if (real_mine[x + 1][y + 1] == '1')
count++;
return count;
}
设计一个函数来实现我们前面说的,当第一下就直接踩到雷时不让玩家第一下就直接结束游戏,让玩家感觉到游戏体验极差,当第一下踩到雷时,该位置的雷重被新分配到其它没有雷的位置其它功能照常:
void SafeMine()
{
int x = 0;
int y = 0;
char ch = 0;
int count = 0;
int ret = 1;
printf("输入坐标扫雷\n");
while (1)
{
scanf_s("%d%d", &x, &y);
if ((x >= 1 && x <= 10) && (y >= 1 && y <= 10))
{
if (real_mine[x][y] == '1')
{
real_mine[x][y] = '0';
char ch = CountMine(x, y);
show_mine[x][y] = ch + '0';
OpenMine(x, y);
while (ret)
{
int x = rand() % 10 + 1;
int y = rand() % 10 + 1;
if (real_mine[x][y] == '0')
{
real_mine[x][y] = '1';
ret--;
break;
}
}break;
}
if (real_mine[x][y] == '0')
{
char ch = CountMine(x, y);
show_mine[x][y] = ch + '0';
OpenMine(x, y);
break;
}
}
else
{
printf("输入错误重新输入\n");
}
}
}
接着就是实现非雷区的展开,设计一个函数对输入的坐标周围没有雷的地方进行展开:
void OpenMine(int x, int y)
{
if (real_mine[x - 1][y - 1] == '0')
{
show_mine[x - 1][y - 1] = CountMine(x - 1, y - 1) + '0';
}
if (real_mine[x - 1][y] == '0')
{
show_mine[x - 1][y] = CountMine(x - 1, y) + '0';
}
if (real_mine[x - 1][y + 1] == '0')
{
show_mine[x - 1][y + 1] = CountMine(x - 1, y + 1) + '0';
}
if (real_mine[x][y - 1] == '0')
{
show_mine[x][y - 1] = CountMine(x, y - 1) + '0';
}
if (real_mine[x][y + 1] == '0')
{
show_mine[x][y + 1] = CountMine(x, y + 1) + '0';
}
if (real_mine[x + 1][y - 1] == '0')
{
show_mine[x + 1][y - 1] = CountMine(x + 1, y - 1) + '0';
}
if (real_mine[x + 1][y] == '0')
{
show_mine[x + 1][y] = CountMine(x + 1, y) + '0';
}
if (real_mine[x + 1][y + 1] == '0')
{
show_mine[x + 1][y + 1] = CountMine(x + 1, y + 1) + '0';
}
}
后面就是设计一个扫雷的函数,判断玩家输入的坐标,玩家是否踩到雷被雷炸死,玩家是否找到所有的雷获得游戏胜利:
int SweepMine()
{
int x = 0;
int y = 0;
int count = 0;
printf("输入坐标扫雷\n");
scanf_s("%d%d", &x, &y);
if ((x >= 1 && x <= 10) && (y >= 1 && y <= 10))
{
if (real_mine[x][y] == '0')
{
char ch = CountMine(x, y);
show_mine[x][y] = ch + '0';
OpenMine(x, y);
if (GetMineCount() == EASY_COUNT)
{
MineBoard();
printf("玩家赢!\n\n");
return 0;
}
}
else if (real_mine[x][y] == '1')
{
return 1;
}
}
else
{
printf("输入错误重新输入\n");
}
return 0;
}
为了判断最后玩家取得胜利,设计一个函数统计所剩余区域为雷的个数时玩家取得胜利:
int GetMineCount()
{
int count = 0;
int i = 0;
int j = 0;
for (i = 1; i <= ROW - 2; i++)
{
for (j = 1; j <= COL - 2; j++)
{
if (show_mine[i][j] == '*')
{
count++;
}
}
}
return count;
}
最好就是简单扫雷游戏三个组成部分:
第一部分:游戏的头文件
#ifndef __MINES_H__
#define __MINES_H__
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>
typedef unsigned int uint;
enum OPTION
{
EXIT,
START
};
enum MINE_COUNT
{
EASY_COUNT = 10
};
#define COL 10
#define ROW 10
#define COLS COL+2
#define ROWS ROW+2
void InitBoard(char board[ROWS][COLS], char show[ROWS][COLS], int rows, int cols);
void PrintBoard(char board[ROWS][COLS], int row, int col);
void MineBoard(char board[ROWS][COLS], int row, int col);
void SetMine();
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
void SafeMine();
void OpenMine(int row, int col);
int GetMineCount();
int SweepMine();
int CountMine(char mine[ROWS][COLS], int x, int y);
#endif//__MINES_H__
第二部分:游戏game()的函数部分
void PrintBoard()
{
int i = 0;
int j = 0;
printf("0 ");
for (i = 1; i <ROWS - 1; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <ROW; i++)
{
printf("%d ", i);
for (j = 1; j < COLS - 1; j++)
{
printf("%c ", show_mine[i][j]);
}
printf("\n");
}
printf("10 ");
for (i = 1; i < ROWS - 1; i++)
{
printf("%c ", show_mine[10][i]);
}
printf("\n");
}
void MineBoard()
{
int i = 0;
int j = 0;
printf("0 ");
for (i = 1; i <ROWS - 1; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <ROW; i++)
{
printf("%d ", i);
for (j = 1; j < COLS - 1; j++)
{
printf("%c ", real_mine[i][j]);
}
printf("\n");
}
printf("10 ");
for (i = 1; i < ROWS - 1; i++)
{
printf("%c ", real_mine[10][i]);
}
printf("\n");
}
void SetMine()
{
int x = 0;
int y = 0;
int count = EASY_COUNT;
while (count)
{
int x = rand() % 10 + 1;
int y = rand() % 10 + 1;
if (real_mine[x][y] == '0')
{
real_mine[x][y] = '1';
count--;
}
}
}
int CountMine(int x, int y)
{
int count = 0;
if (real_mine[x - 1][y - 1] == '1')
count++;
if (real_mine[x - 1][y] == '1')
count++;
if (real_mine[x - 1][y + 1] == '1')
count++;
if (real_mine[x][y - 1] == '1')
count++;
if (real_mine[x][y + 1] == '1')
count++;
if (real_mine[x + 1][y - 1] == '1')
count++;
if (real_mine[x + 1][y] == '1')
count++;
if (real_mine[x + 1][y + 1] == '1')
count++;
return count;
}
void SafeMine()
{
int x = 0;
int y = 0;
char ch = 0;
int count = 0;
int ret = 1;
printf("输入坐标扫雷\n");
while (1)
{
scanf_s("%d%d", &x, &y);
if ((x >= 1 && x <= 10) && (y >= 1 && y <= 10))
{
if (real_mine[x][y] == '1')
{
real_mine[x][y] = '0';
char ch = CountMine(x, y);
show_mine[x][y] = ch + '0';
OpenMine(x, y);
while (ret)
{
int x = rand() % 10 + 1;
int y = rand() % 10 + 1;
if (real_mine[x][y] == '0')
{
real_mine[x][y] = '1';
ret--;
break;
}
}break;
}
if (real_mine[x][y] == '0')
{
char ch = CountMine(x, y);
show_mine[x][y] = ch + '0';
OpenMine(x, y);
break;
}
}
else
{
printf("输入错误重新输入\n");
}
}
}
int SweepMine()
{
int x = 0;
int y = 0;
int count = 0;
printf("输入坐标扫雷\n");
scanf_s("%d%d", &x, &y);
if ((x >= 1 && x <= 10) && (y >= 1 && y <= 10))
{
if (real_mine[x][y] == '0')
{
char ch = CountMine(x, y);
show_mine[x][y] = ch + '0';
OpenMine(x, y);
if (GetMineCount() == EASY_COUNT)
{
MineBoard();
printf("玩家赢!\n\n");
return 0;
}
}
else if (real_mine[x][y] == '1')
{
return 1;
}
}
else
{
printf("输入错误重新输入\n");
}
return 0;
}
void OpenMine(int x, int y)
{
if (real_mine[x - 1][y - 1] == '0')
{
show_mine[x - 1][y - 1] = CountMine(x - 1, y - 1) + '0';
}
if (real_mine[x - 1][y] == '0')
{
show_mine[x - 1][y] = CountMine(x - 1, y) + '0';
}
if (real_mine[x - 1][y + 1] == '0')
{
show_mine[x - 1][y + 1] = CountMine(x - 1, y + 1) + '0';
}
if (real_mine[x][y - 1] == '0')
{
show_mine[x][y - 1] = CountMine(x, y - 1) + '0';
}
if (real_mine[x][y + 1] == '0')
{
show_mine[x][y + 1] = CountMine(x, y + 1) + '0';
}
if (real_mine[x + 1][y - 1] == '0')
{
show_mine[x + 1][y - 1] = CountMine(x + 1, y - 1) + '0';
}
if (real_mine[x + 1][y] == '0')
{
show_mine[x + 1][y] = CountMine(x + 1, y) + '0';
}
if (real_mine[x + 1][y + 1] == '0')
{
show_mine[x + 1][y + 1] = CountMine(x + 1, y + 1) + '0';
}
}
int GetMineCount()
{
int count = 0;
int i = 0;
int j = 0;
for (i = 1; i <= ROW - 2; i++)
{
for (j = 1; j <= COL - 2; j++)
{
if (show_mine[i][j] == '*')
{
count++;
}
}
}
return count;
}
第三部分是:游戏测试部分
#include"test.h"
void game()
{
char show_mine[ROWS][COLS] = { 0 };
char real_mine[ROWS][COLS] = { 0 };
int ret = 0;
InitBoard(show_mine,real_mine, ROW, COL );
SetMine();
MineBoard(real_mine,ROW,COL);)
printf("\n");
PrintBoard(show_mine,ROW,COL);
SafeMine();
if (GetMineCount() == EASY_COUNT)
{
MineBoard(real_mine,ROW,COL);
printf("玩家赢!\n\n");
return;
}
MineBoard(real_mine, ROW, COL);
printf("\n");
PrintBoard(show_mine, ROW, COL);
while (1)
{
int ret = SweepMine();
if (GetMineCount(show_mine, ROW, COL) == EASY_COUNT)
{
MineBoard(real_mine, ROW, COL);
printf("玩家赢!\n\n");
break;
}
if (ret)
{
printf("被雷炸死\t");
printf("\n");
MineBoard(real_mine, ROW, COL);
break;
}PrintBoard(show_mine, ROW, COL);
}
}
void menu()
{
printf("***************************************\n");
printf("* 1.play 0.exit *\n");
printf("***************************************\n");
}
int main()
{
int choice;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:");
scanf_s("%d", &choice);
switch (choice)
{
case 1:
game();
break;
case 0:
break;
default:
printf(" 输入错误,请重新输入!\n");
break;
}
} while (choice);
return 0;
}
丑陋代码,还望多多包涵。
希望能得到大家的指点。