前言
扫雷游戏主要考察我们对数组和函数的掌握程度,经过这一过程,能让你巩固你所学的知识,并学会如何制作简易版扫雷游戏。
一.游戏规则
玩家随便点开一个方格,根据展开方格的数字去推断其相邻九宫格内未展开方格下面是否是地雷,最终任务就是点开所有没有地雷的方格,以找出所有的地雷。
二.所需手段
我们在写代码的时候,一般都是在一个源文件里写。但是对于一些代码量比较多的,这时候我们就可以采取多文件编程。
什么是多文件编程?
把一个程序所要实现的不同功能的函数分到各个文件里,需要用时调用就行
好处:分工明确,节省时间,易于维护。
扫雷所创建的三个文件:
game.h----用来声明函数
game.c-----实现扫雷的各项功能
test.c----主函数,调用game.c中的函数
三.制作菜单
开始之前,我们先创建上述的三个文件(两个源文件,一个头文件)
我们先创建一个菜单
void menu() //菜单
{
printf("**********************************\n");
printf("********* 1.play *************\n");
printf("********* 0.exit *************\n");
printf("**********************************\n");
}
并使用do...while循环来打印菜单,用switch语句来判断游戏是否开始。
int input = 0;
do
{
menu();//打印菜单
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
game();
break;
case 0:
printf("退出游戏\n");
default:
printf("输入有误,请重新输入\n");
break;
}
} while (input);
四.游戏的实现
扫雷游戏的实现,我们需要在game.c文件中定义函数的功能,并在test.c文件创建一个game(),并在game()中来调用game.c中的函数。话不多说,主要分为以下几个步骤:
- 制作棋盘
- 初始化棋盘
- 打印棋盘
- 布置雷
- 排查雷
1.制作棋盘
在game()函数中,我们先来创建两个字符型数组mine和show
创建棋盘
//创建两个棋盘,一个用来布置雷的信息,一个用来展现周围有几个雷
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
注意:ROW,COL表示行和列
这个是个9*9的棋盘,但是为什么在创建的时候二维数组的时候不用ROW,COL,而是用ROWS,COLS?其实就是我们在排雷的时候,是统计我们输入坐标周围雷的个数,如下图,排查坐标(9,8),如果访问下面三个坐标,必然是越界的。所以为了防止越界,我们给数组扩大一圈,就变成11*11的棋盘了。
2.初始化棋盘
欧克,完成上面的第一步。我们初始化棋盘
game.h中声明初始化函数
#include <stdio.h>
#include <time.h> //--->rand
#include <stdlib.h> //--->srand
#define ROW 9 //行
#define COL 9 //列
#define ROWS ROW+2
#define COLS COL+2
//初始化棋盘声明
void InitBoard(char arr[ROWS][COLS], int rows, int cols,char set);
game.c中定义功能
void InitBoard(char arr[ROWS][COLS], int rows, int cols,char set) //初始化棋盘
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
arr[i][j] = set;
}
}
在test.c中调用
//初始化棋盘
InitBoard(mine, ROWS, COLS,'0');//把0,*传到初始化函数去,想初始化为0或*,更方便,不必写两个初始化函数
InitBoard(show, ROWS, COLS,'*');
3.布置雷
先在game.h中宏定义雷的个数
#define EASY_COUNT 10 //雷的数量
由于雷的位置是随机的,所以我们要生成随机数,需要用到srand,rand
先看代码
在game.h中声明
//布置雷
void Setmine(char arr[ROWS][COLS], int row, int col);
在game.c中实现布置雷功能 (为什么rand()%row后还要加1呢?我们这里row为9,所以%row后,随机数只会生成1-8的数字,但我们要在9*9的棋盘内布雷,9这个位置取不到,所以要+1,取得9。才能在9的位置布雷)while循环中,每次if成立,就会放置雷,雷的数量就会减少,直到雷的数量为0.
注意:while循环次数>=10,不排除生成的随机数与前面生成的随机数相同
void Setmine(char arr[ROWS][COLS], int row, int col) //布置雷
{
//雷的数量
int count = EASY_COUNT;
//随机排放位置的位置
while (count)
{
int x = rand() % row + 1; //横坐标
int y = rand() % col + 1; //纵坐标
if (arr[x][y] == '0')
arr[x][y] = '1';
count--;
}
}
在test.c中调用布置雷函数,并在main函数中调用srand函数
//布置雷
Setmine(mine, ROW, COL);
srand((unsigned int)time(NULL));
4.打印棋盘
步骤与上面雷同
先在game.h中声明打印棋盘的函数
//棋盘打印
void DisplayBoard(char arr[ROWS][COLS], int row, int col);
在game.c实现打印棋盘的功能(为了更好的看清是几行几列,用第一个for循环打印列,再当打印数组中的元素时顺便打印行号)看代码
void DisplayBoard(char arr[ROWS][COLS], int row, int col) //打印棋盘
{
int i = 0;
int j = 0;
printf("-----扫雷游戏------\n");//为了分开棋盘,更加美观
for (i = 0; i <= row; i++) //打印列号
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++) //打印数组中的元素(即棋盘)
{
printf("%d ", i); //打印行号
for (j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
在test.c文件中调用打印棋盘的函数
//打印棋盘
//DisplayBoard(mine, ROW, COL); //看的到雷的棋盘
DisplayBoard(show, ROW, COL); //猜用的棋盘
5.排查雷
欧克,你能看到这里,证明你已经坚持下来了,最后一步!!!
让我们来排雷叭
首先,在game.h里声明一个排查雷的函数,我们这次需要把两个数组都传到这个排查雷的函数中。目的是当我们排查成功,他继续显示show棋盘,当我们排查失败,给我们展现我们棋盘中雷布置的位置。
//排查雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
其次,最重要的一步,在game.c文件里定义排查雷的功能。
容我细说:
1.先声明两个变量x,y;用来输入要排查的坐标,这两坐标的范围在9*9棋盘肯定是1-9,如果超出这个范围,肯定是错误的.
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) //排查雷
{
printf("请输入要排查的坐标:>");
int x = 0;
int y = 0;
if(x>=1&&x<=row&&y>=1&&y<=col)
{}
else
printf("您输入的坐标有误,请重新输入:");
}
2.如果x,y在这个范围内,还得判断在show棋盘中输入的x,y是否已经排除,排除了就不能再排除,这时就得提示
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) //排查雷
{
int x = 0;
int y = 0;
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*')
{
}
else
{
printf("该坐标已被排除,请重新输入\n");
}
}
else
{
printf("输入坐标有误,请重新输入\n");
}
}
3.当这个位置还没排除,那就判断这个位置是不是雷,是雷就游戏结束,不是就判断周围有几个雷。判断周围有几个雷我们用另外一个函数mine_count来判断.
mine_count函数如何判断周围有几个雷
当你输入坐标,会排查围着(x,y)的其他8个位置,那么就可以写成
法一:for循环来排查雷
int mine_count(char mine[ROWS][COLS], int x, int y)//统计坐标周围有几个雷
{
int i = 0;
int j = 0;
int count = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
count += mine[i][j] - '0';
}
return count;
法二:一一列出
int mine_count(char mine[ROWS][COLS], 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+1][y+1]
+mine[x+1][y]
+mine[x+1][y-1]
+mine[x][y-1]-8*'0';
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) //排查雷
{
int x = 0;
int y = 0;
int win = 0;
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
win++;
int count = mine_count(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("该坐标已被排除,请重新输入\n");
}
}
else
{
printf("输入坐标有误,请重新输入\n");
}
}
4.最后一步,我们排查不单单只排查一次,所以需要用一个while循环,声明一个变量win,每次排查成功就+1。我们布置的雷为EAST_COUNT,而棋盘上总共可以排查的坐标数为row*col,所以当while不满足row*col-EASY_COUNT时,则跳出循环,即赢了。
排查雷完整代码
int mine_count(char mine[ROWS][COLS], int x, int y)//统计坐标周围有几个雷
{
int i = 0;
int j = 0;
int count = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
count += mine[i][j] - '0';
}
return count;
}
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) //排查雷
{
int x = 0;
int y = 0;
int win = 0;
while (win < row * col - EASY_COUNT)
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
win++;
int count = mine_count(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("该坐标已被排除,请重新输入\n");
}
}
else
{
printf("输入坐标有误,请重新输入\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,你赢了\n");
DisplayBoard(mine, ROW, COL);
}
}
接下来让我们运行一下,看看是什么样?
五.源码
game.h
#pragma once
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define ROW 9 //行
#define COL 9 //列
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10 //雷的数量
//初始化棋盘声明
void InitBoard(char arr[ROWS][COLS], int rows, int cols,char set);
//棋盘打印
void DisplayBoard(char arr[ROWS][COLS], int row, int col);
//布置雷
void Setmine(char arr[ROWS][COLS], int row, int col);
//排查雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void InitBoard(char arr[ROWS][COLS], int rows, int cols,char set) //初始化棋盘
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
arr[i][j] = set;
}
}
void DisplayBoard(char arr[ROWS][COLS], int row, int col) //打印棋盘
{
int i = 0;
int j = 0;
printf("-----扫雷游戏------\n");//为了分开棋盘,更加美观
for (i = 0; i <= row; i++)//打印列
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);//打印行号
for (j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
void Setmine(char arr[ROWS][COLS], int row, int col) //布置雷
{
//雷的数量
int count = EASY_COUNT;
//随机排放位置的位置
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (arr[x][y] == '0')
arr[x][y] = '1';
count--;
}
}
int mine_count(char mine[ROWS][COLS], int x, int y)//统计坐标周围有几个雷
{
int i = 0;
int j = 0;
int count = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
count += mine[i][j] - '0';
}
return count;
}
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) //排查雷
{
int x = 0;
int y = 0;
int win = 0;
while (win < row * col - EASY_COUNT)
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
win++;
int count = mine_count(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("该坐标已被排除,请重新输入\n");
}
}
else
{
printf("输入坐标有误,请重新输入\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,你赢了\n");
DisplayBoard(mine, ROW, COL);
}
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#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');//把0,*传到初始化函数去,想初始化为0或*,更方便,不必写两个初始化函数
InitBoard(show, ROWS, COLS,'*');
//布置雷
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();//打印菜单
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
game();
break;
case 0:
printf("退出游戏\n");
default:
printf("输入有误,请重新输入\n");
break;
}
} while (input);
return 0;
}
欧克,记录结束~
后续会继续完善!
目录