C语言实现扫雷小游戏
勤奋出天才,实践出真知。因此,为了检验自己最近一段时间的学习成果,今天用C语言实现了一个初级版的扫雷小游戏。
成果展示
哈哈,话不多说,先展示一下我的成果!!!
********************************
************ 1. play ***********
************ 0. exit ***********
********************************
请输入您的选择>:1
0 | 1 2 3 4 5 6 7 8 9
---------------------------------------
1 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
2 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
3 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
4 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
5 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
6 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
7 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
8 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
9 | * | * | * | * | * | * | * | * | *
请输入你要排查的坐标:>1 1
0 | 1 2 3 4 5 6 7 8 9
---------------------------------------
1 | 1 | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
2 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
3 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
4 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
5 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
6 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
7 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
8 | * | * | * | * | * | * | * | * | *
|---|---|---|---|---|---|---|---|---
9 | * | * | * | * | * | * | * | * | *
请输入你要排查的坐标:>5 1
0 | 1 2 3 4 5 6 7 8 9
---------------------------------------
1 | 1 | 1 | | | | | | 1 | *
|---|---|---|---|---|---|---|---|---
2 | * | 1 | | | | 1 | 1 | 2 | *
|---|---|---|---|---|---|---|---|---
3 | 1 | 1 | | | | 1 | * | * | *
|---|---|---|---|---|---|---|---|---
4 | | | | | | 1 | 2 | * | *
|---|---|---|---|---|---|---|---|---
5 | | 1 | 2 | 2 | 1 | | 2 | * | *
|---|---|---|---|---|---|---|---|---
6 | | 1 | * | * | 1 | | 2 | * | *
|---|---|---|---|---|---|---|---|---
7 | 1 | 2 | * | 2 | 1 | | 1 | 1 | 1
|---|---|---|---|---|---|---|---|---
8 | * | * | * | 1 | | | | |
|---|---|---|---|---|---|---|---|---
9 | * | * | * | 1 | | | | |
请输入你要排查的坐标:>2 1
很遗憾,您被炸死了!
0 | 1 2 3 4 5 6 7 8 9
---------------------------------------
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|---|---|---|---|---|---|---|---|---
2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1
|---|---|---|---|---|---|---|---|---
3 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0
|---|---|---|---|---|---|---|---|---
4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|---|---|---|---|---|---|---|---|---
5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0
|---|---|---|---|---|---|---|---|---
6 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0
|---|---|---|---|---|---|---|---|---
7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|---|---|---|---|---|---|---|---|---
8 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|---|---|---|---|---|---|---|---|---
9 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0
********************************
************ 1. play ***********
************ 0. exit ***********
********************************
请输入您的选择>:0
退出游戏
请按任意键继续. . .
实现功能介绍
玩过扫雷的小伙伴都知道,我们的任务是找出所有没有地雷的方格,才算完成游戏。要扫雷,首先我们得先有一个雷盘用来存放我们的地雷,扫雷时如果该格子周围八个格子都没有雷,该格子就会被清空;踩到雷,游戏结束。整理好思路以后,我们就开始实现。
- 创建雷盘
- 初始化雷盘
- 打印雷盘
- 随机布置10颗雷
- 第一次排雷时不会被炸死
- 展开式排雷
功能实现
今天我们依旧采取多文件形式来进行实现。 vs2013创建一个新的工程文件,里面包含头文件 game.h,test.c,game.c三个文件。

头文件game.h
game.h包含了:库函数头文件的引用,宏定义的常量,以及功能函数的声明。
#ifndef __GAME_H__
#define __GAME_H__
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define MINE_COUNT 10
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ch);
void PrintBoard(char board[ROWS][COLS], int row, int col);
void SetMine(char board[ROWS][COLS], int row, int col);
void SearchMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
#endif
源文件 test.c
用来测试游戏的。 游戏菜单的实现,让玩家通过菜单选择进入或者退出游戏。
#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,'*');
PrintBoard(show, ROW, COL);
SetMine(mine, ROW, COL);
SearchMine(mine,show,ROW,COL);
}
int main(void)
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请输入您的选择>:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default :
printf("输入错误,请重新输入>:\n");
break;
}
} while (input);
return 0;
}
源文件game.c
这个文件里面是各个游戏功能函数的实现。
- 创建雷盘
由于雷的位置和排查出来的雷的信息需要分开统计,因此这里我们选择两个二维数组作为棋盘;棋盘大小设计为9X9,如图箭头所指的红格子所示。 如果棋盘大小设计为9X9,后期我们在统计一些边上和角落的棋子周围的雷的个数时,会比较麻烦,因此我们让棋盘大上一圈,选择用11X11的棋盘,但是我们只用其中9x9的格子,用来布置雷。 
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
- 初始化棋盘
我们知道数组mine用来存放雷的位置,用字符‘1’表示该位置为雷,用字符‘0’表示该位置非雷。因此初始化mine数组时,数组元素全部置为‘1’,表示还没有布置雷。 为了给玩家保留一点神秘感,show数组全部初始化为‘*’。
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ch)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = ch;
}
}
}
- 打印雷盘
为了让玩家在屏幕上看到这个雷盘,因此这里封装了了一个打印函数。
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
for (i = 0; i < row + 1; i++)
{
if (i == 0)
{
printf(" %d |", i);
}
else
{
printf(" %d ", i);
}
}
printf("\n");
printf("---------------------------------------\n");
for (i = 1; i < row + 1; i++)
{
int j = 0;
printf(" %d |", i);
for (j = 1; j < col + 1; j++)
{
printf(" %c ", board[i][j]);
if (j < col)
{
printf("|");
}
}
printf("\n");
if (i < row)
{
printf(" |");
for (j = 1; j < col + 1; j++)
{
printf("---");
if (j < col)
{
printf("|");
}
}
printf("\n");
}
}
printf("\n");
}
打印到屏幕上的效果大概就是下面这个样子: 
- 打印雷盘
雷用字符‘1’表示,布置在中间9X9的格子里。
void SetMine(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = MINE_COUNT;
while (count)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (board[x][y] != '1')
{
board[x][y] = '1';
count--;
}
}
printf("\n");
}
布置完成以后,我们这里打印一下雷盘,大致看一下雷的分布情况: 
- .扫雷
玩家输入一个坐标,如果是雷(为了增加游戏的可玩性,如果玩家第一次踩到雷了,我们把雷移走,在雷盘上重新找个非雷的位置,把雷布置在那里。 ),游戏结束;如果不是雷,展开一片。游戏继续,直所有非雷的位置全部排完。
int ConutMine(char show[ROWS][COLS], int row, int col)
{
int count = 0;
int i = 0;
for (i = 1; i <= row; i++)
{
int j = 0;
for (j = 1; j <= col; j++)
{
if (show[i][j] == '*')
{
count++;
}
}
}
return count;
}
void SearchMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int i = 1;
int count = ConutMine(show,row,col);
while (count != MINE_COUNT)
{
printf("请输入你要排查的坐标:>");
scanf("%d%d", &x, &y);
if ((x > 0 && x < 10) && (y > 0 && y < 10))
{
if (mine[x][y] == '1')
{
if (i == 1)
{
mine[x][y] = '0';
x = rand() % row + 1;
y = rand() % col + 1;
while (1)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (mine[x][y] != '1')
{
mine[x][y] = '1';
break;
}
}
Spread(mine, show, x, y);
PrintBoard(show, ROW, COL);
count = ConutMine(show, row, col);
}
else
{
printf("很遗憾,您被炸死了!\n");
PrintBoard(mine, ROW, COL);
break;
}
}
else
{
Spread(mine,show,x,y);
PrintBoard(show, ROW, COL);
count = ConutMine(show, row, col);
}
i = 2;
}
else
{
printf("您输入的坐标不合法,请重新输入你要排查的坐标!\n");
}
}
if (count == MINE_COUNT)
{
printf("恭喜您,排雷成功!\n");
}
}
注:当游戏中排到一个周围一圈都无雷的位置时,运用递归,实现扩展展开周围的一片无雷区。
int MineCount(char board[ROWS][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 Spread(char mine[ROWS][COLS], char show[ROWS][COLS],int x, int y)
{
int count_number = MineCount(mine, x, y);
if (count_number == 0)
{
show[x][y] = ' ';
if ((x - 1 > 0 && x - 1 < 10) && (y - 1 > 0 && y - 1 < 10) && show[x - 1][y - 1] == '*')
{
Spread(mine, show, x - 1, y - 1);
}
if ((x - 1 > 0 && x - 1 < 10) && (y > 0 && y < 10) && show[x - 1][y] == '*')
{
Spread(mine, show, x - 1, y );
}
if ((x - 1 > 0 && x - 1 < 10) && (y + 1 > 0 && y + 1 < 10) && show[x - 1][y + 1] == '*')
{
Spread(mine, show, x - 1, y + 1);
}
if ((x > 0 && x < 10) && (y - 1 > 0 && y - 1 < 10) && show[x][y - 1] == '*')
{
Spread(mine, show, x , y - 1);
}
if ((x > 0 && x < 10) && (y + 1 > 0 && y + 1 < 10) && show[x][y + 1] == '*')
{
Spread(mine, show, x, y + 1);
}
if ((x + 1 > 0 && x + 1 < 10) && (y - 1 > 0 && y - 1 < 10) && show[x + 1][y - 1] == '*')
{
Spread(mine, show, x + 1, y - 1);
}
if ((x + 1 > 0 && x + 1 < 10) && (y > 0 && y < 10) && show[x + 1][y] == '*')
{
Spread(mine, show, x + 1, y);
}
if ((x + 1 > 0 && x + 1 < 10) && (y + 1 > 0 && y + 1 < 10) && show[x + 1][y + 1] == '*')
{
Spread(mine, show, x + 1, y + 1);
}
}
else
{
show[x][y] = count_number + '0';
}
}
写在后面
以上程序还有很多可以完善的地方,比如增加计时功能,标记雷的位置的功能等,这些问题等到日后学习到了更多知识以后再来完善它。至此这篇关于C语言实现扫雷小游戏的文章到这里就告一段落了。  若本篇内容对您有所帮助,请三连点赞,关注,收藏支持下。
创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!
如果本篇博客有任何错误,请批评指教,不胜感激 !
|