目录
众所周知,扫雷是一个经典的电脑小游戏,本篇文章将带大家用C语言实现出一个扫雷游戏。
1.菜单制作
void menu()
{
printf("*******************************\n");
printf("******** 1. play ******\n");
printf("******** 0. exit ******\n");
printf("*******************************\n");
}
我的菜单制作的比较简易,用星号做了一个菜单,有才华的小伙伴可以做一个精美一点的。
2.游戏的重复进行
出于游戏的设计考虑,肯定是让玩家多玩才好,所以我们设置为只有玩家输入‘0’的时候猜退出游戏,代码如下:
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请输入(1/0):");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
这段代码也是我们的主函数,我们可以看到主函数里还有一个game()函数,这也就是我们的游戏部分的实现。
3.扫雷游戏的实现:game函数
3.1初始化棋盘
扫雷游戏的开始需要打印一个棋盘,这个棋盘会随着难度的提高而变得越来越大,雷的数量也会随之变多,为了在改变棋盘大小和雷的数量时更方便,我们直接把棋盘的行列和雷的数量定义出来
#define ROW 15
#define COL 15
#define EASY 20
然后就是对棋盘的初始化,首先我们需要的棋盘有两个,一个棋盘记录雷的位置,一个棋盘让玩家操作并记录,所以我们设置两个二维数组,为了判断玩家下棋的位置附近有几个雷,我们把数组扩大一些,当然也是以定义的方式
#define ROWS ROW+2
#define COLS COL+2
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
接下来就是初始化棋盘,棋盘的初始化相对比较简单,但是我们有两个棋盘需要初始化,按照一般的思路要用两个函数进行分别打印,但是这种方法太麻烦了,所以我们进行一个优化:也就是把要初始化的内容一起传给函数,这样初始化的时候,就可以用一个函数就搞定了,既简单有快捷。
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
3.2打印棋盘
打印棋盘就简单多了,按照行列正常打印就可以了,但是我们为了让玩家的游戏体验更好,所以在第一行和第一列打印行数和列数,并且在头尾加上扫雷游戏的字样,这样看起来更加美观,游戏效果也更好。
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i, j;
printf("-------------------扫雷游戏--------------------\n");
for (i = 0; i <= row; i++)//打印列数
{
printf("%-2d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%-2d ", i);//打印行数
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("-------------------扫雷游戏--------------------\n");
}
3.3布置地雷
棋盘做好了,下一步加上埋雷,在扫雷游戏里,每一把的雷出现的位置都不相同,为了实现出随机埋雷,我们需要运用随机数来随机埋雷,也就是随机一个行和随机一个列,然后判断这个位置如果没有雷,那么再次埋雷,直到埋玩足够数量的雷为止。
(随机数的种子已经提前设置在主函数里了)
void SetMine(char board[ROWS][COLS], int row, int col)//放置雷
{
int x, y, count = 0, i, j, l, k;
while (count != EASY)
{
x = rand() % ROW + 1;
y = rand() % COL + 1;
if (board[x][y] == '0')
{
board[x][y] = '#';
count++;
}
}
}
3.4玩家排雷
玩家排雷的过程我们设置为坐标输入,玩家输入一个坐标,我们进行判断此坐标是否合理之后,判断是否有雷,如果有雷,则提示炸死了给玩家打印雷的分布,然后回到菜单界面,如果没炸死就显示该坐标周围有几颗雷,以供玩家做出判断,如果玩家排出了所有的雷那么提示他赢了,然后回到菜单页面。
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x, y, count = 0, i, j;
while (1)
{
printf("请下棋:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] != '*')
{
printf("该坐标已经下过了,请重新输入\n");
continue;
}
else if (mine[x][y] == '#')
{
printf("很遗憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
SearchBlank(mine, show, x, y);
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("坐标非法,请重新输入\n");
continue;
}
count = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (show[i][j] != '*')
{
count++;
}
}
}
if (count == ROW * COL - EASY)
{
printf("恭喜你,你排出了所有的雷\n");
DisplayBoard(mine, ROW, COL);
break;
}
}
}
4.实现输入一个坐标显示一片信息
我们在玩扫雷的时候总是会发现点击一个位置就会显示一片空白和数字,那么这个在编译的时候该如何实现呢?我们用递归来完成他,首先我们判断这个坐标周围是否是合法坐标,在这前提下,如果该坐标周围有空位,则打印空位,如果有雷,则显示雷的数量,然后让周围没有雷的坐标在进行扩散,判断周围的情况,这样就实现了打印一片的扫雷
void SearchBlank(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
if (show[x][y] != '*')
return;
int count = NumberMine(mine, x, y);
if (count != 0)
{
show[x][y] = count + '0';
return;
}
if (count == 0)//层层递归下去
{
show[x][y] = '0';
SearchBlank(mine, show, x - 1, y - 1);
SearchBlank(mine, show, x - 1, y);
SearchBlank(mine, show, x - 1, y + 1);
SearchBlank(mine, show, x, y - 1);
SearchBlank(mine, show, x, y + 1);
SearchBlank(mine, show, x + 1, y - 1);
SearchBlank(mine, show, x + 1, y);
SearchBlank(mine, show, x + 1, y + 1);
}
}
}
5.扫雷原码
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY 10
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
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 board[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
#include "game.h"
void menu()
{
printf("*******************************\n");
printf("******** 1. play ******\n");
printf("******** 0. exit ******\n");
printf("*******************************\n");
}
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//打印棋盘
//DisplayBoard(mine, ROW, COL);
//DisplayBoard(show, ROW, COL);
//布置雷
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//下棋
FindMine(mine, show, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请输入(1/0):");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
#include "game.h"
int NumberMine(char mine[ROWS][COLS], int x, int y)
{
int i, j, count = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
if (mine[i][j] == '#')
{
count++;
}
}
}
return count;
}
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i, j;
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, j;
printf("----------扫雷游戏----------\n");
for (i = 0; i <= row; i++)
{
printf("%-2d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%-2d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("----------扫雷游戏----------\n");
}
void SetMine(char board[ROWS][COLS], int row, int col)
{
int x, y, count = 0, i, j, l, k;
while (count != EASY)
{
x = rand() % ROW + 1;
y = rand() % COL + 1;
if (board[x][y] == '0')
{
board[x][y] = '#';
count++;
}
}
}
void SearchBlank(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
if (show[x][y] != '*')
return;
int count = NumberMine(mine, x, y);
if (count != 0)
{
show[x][y] = count + '0';
return;
}
if (count == 0)
{
show[x][y] = '0';
SearchBlank(mine, show, x - 1, y - 1);
SearchBlank(mine, show, x - 1, y);
SearchBlank(mine, show, x - 1, y + 1);
SearchBlank(mine, show, x, y - 1);
SearchBlank(mine, show, x, y + 1);
SearchBlank(mine, show, x + 1, y - 1);
SearchBlank(mine, show, x + 1, y);
SearchBlank(mine, show, x + 1, y + 1);
}
}
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x, y, count = 0, i, j;
while (1)
{
printf("请下棋:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] != '*')
{
printf("该坐标已经下过了,请重新输入\n");
continue;
}
else if (mine[x][y] == '#')
{
printf("很遗憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
SearchBlank(mine, show, x, y);
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("坐标非法,请重新输入\n");
continue;
}
count = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (show[i][j] != '*')
{
count++;
}
}
}
if (count == ROW * COL - EASY)
{
printf("恭喜你,你排出了所有的雷\n");
DisplayBoard(mine, ROW, COL);
break;
}
}
}