目录
一、游戏选择界面
这里我们运用do..while循环做出选择界面,之所以用do..while是为了使选择界面至少出现一次。然后就运用选择语句if来看玩家是否进入游戏。这里会出现三种情况,第一种是玩家输入1,选择进入游戏;第二种是玩家输入0,退出游戏(这里注意输入0恰好while的循环条件即为0,退出循环);而其他的情况则报错,告诉玩家输入错误,重新输入。
void game_interface()
{
printf("*************************\n");
printf("****** 1.进入游戏 *******\n");
printf("****** 0.退出游戏 *******\n");
printf("*************************\n");
}
int main()
{
int num = 0;
do
{
game_interface();//(游戏界面)
printf("请输入是否进入游戏:");
scanf("%d", &num);
if (1 == num)
{
game();
}
else if (0 == num)
{
printf("退出游戏\n");
}
else
{
printf("输入错误,请重新输入!\n");
}
} while (num);
return 0;
}
二、完成棋盘函数
//一些小知识点
- 棋盘应该分为表棋盘和里棋盘,这样建棋盘的原因是为了能将地雷棋盘与玩家棋盘分隔开来,即里棋盘用来放地雷,表棋盘掩盖地雷。
- 在里棋盘中用1表示炸弹,0表示安全,表棋盘用*掩盖。
- 数组内容我们用#define来定义行与列的大小,这样可以便于后期更改棋盘大小
注意这里还定义了另一个行(ROWS)与列(FILES),将原来定义的行(ROW)与列(FILE)分别+2,这样是为了防止出现误差。
- 这里我们可以看到如果加上2则在检验获胜时可以避免越界访问的问题。
- 棋盘的初始化我们用函数完成,这样可以让代码的可读性更强。
- 在函数传值时我们需要将数组,行,列和需要用到的符号传过去(传符号过去的主要原因是为了方便将两个数组所要用到的符号用一个函数完成,达成一个函数完成两个函数的功能,使函数更加高效、整洁)
1.对棋盘初始化
注意我们举例打印的是一个9*9的棋盘。
#define ROW 9
#define FILE 9
#define ROWS ROW + 2
#define FILES FILE + 2
void game()
{
//初始化数组表与内
char ches_sur[ROWS][FILES] = { 0 };
char ches_in[ROWS][FILES] = { 0 };
//初始化棋盘表与内
Initializes_the_chessboard(ches_sur, ROWS, FILES, '*');
Initializes_the_chessboard(ches_in, ROWS, FILES, '0');
//打印表内棋盘
//Print_the_chessboard(ches_sur, ROW, FILE);
//Print_the_chessboard(ches_in, ROW, FILE);
}
2.对棋盘布局
//初始化棋盘
void Initializes_the_chessboard(char ches[ROWS][FILES], int rows, int files, char sym)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < files; j++)
{
ches[i][j] = sym;
}
}
}
3.对棋盘的打印
//棋盘打印
void Print_the_chessboard(char ches[ROWS][FILES], int row, char file)
{
printf("----------扫雷----------\n");
for (int j = 0; j <= file; j++)
{
printf("%d ", j);
}
printf("\n");
for (int i = 1; i <= row; i++)//打印下标1到9的棋盘
{
printf("%d ", i);
for (int j = 1; j <= file; j++)
{
printf("%c ", ches[i][j]);
}
printf("\n");
}
printf("----------扫雷----------\n");
}
这里要注意的是我们之前为了防止数组的越界访问使行与列往外面扩了一个单位,因此我们原本是的下标应该是0到8,扩完之后就是1到9。
三、电脑在棋盘布置地雷
1.布置地雷前的准备
我们命名一个布置地雷的函数,将里棋盘的数组,行和列传至函数中
Computer_input(ches_in, ROW, FILE);
注意在电脑布置地雷时,我们的随机数是用时间戳产生的,因此我们还应当在main函数中定义一个时间戳函数,让游戏一运行就产生随机坐标。
#include<stdlib.h>
#include<time.h>
//时间撮
int main()
{
srand((unsigned int)time(NULL));
}
2.布置地雷函数
函数实现的思路则是用时间戳在里棋盘产生随机坐标,将产生坐标的数组名标为1,表示为炸弹。
//电脑在内棋盘中埋地雷
#define BOMB 10
void Computer_input(char ches_in[ROWS][FILES], int row, int file)
{
int x = 0;
int y = 0;
int b = BOMB;
int n = 0;
while (n < b)
{
x = rand() % row + 1;
y = rand() % file + 1;
if (ches_in[x][y] == '0')
{
ches_in[x][y] = '1';
n++;
}
}
}
这里需要注意的是我们的x和y坐标产生后应当是在我们的1到9坐标内,因此我们将时间戳产生的数用行和列余出来,即0到8,加上1即1到9。
四、玩家下棋
我们命名一个玩家下棋的函数,将里表函数,行和列传至函数中
//玩家在表棋盘中排地雷并打印出来,且通过里棋盘打印出附近地雷个数
Player_input(ches_in, ches_sur, ROW, FILE);
函数实现的思路是玩家输入坐标后在表棋盘显示,通过里棋盘查看附近炸弹,若输入坐标是地雷则判定游戏失败,若不是地雷则再在表棋盘坐标上显示附近雷的个数(若输了则给玩家打印里棋盘让玩家知道炸弹在哪,赢了则打印表棋盘让玩家继续游戏)。
int look_bomb(char ches_in[ROWS][FILES], int x, int y)
{
int add = 0;
int i = 0;
int j = 0;
//雷个数
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
add = add + ches_in[i][j];
}
}
return add - 9 * '0';
}
void Player_input(char ches_in[ROWS][FILES], char ches_sur[ROWS][FILES], int row, int file)
{
//玩家输入查看的区域
int x = 0;
int y = 0;
while (1)
{
printf("请输入排查坐标:");
scanf("%d %d", &x, &y);
//打印出地雷个数
if (x > 0 && x <= row && y > 0 && y <= file)
{
if (ches_in[x][y] == '1')
{
printf("踩到炸弹,游戏结束!\n");
Print_the_chessboard(ches_in, ROW, FILE);//查看里棋盘
break;
}
else
{
if (ches_sur[x][y] == '*')
{
//得出范围内的雷个数
int lo = look_bomb(ches_in, x, y);
ches_sur[x][y] = lo + '0';
Print_the_chessboard(ches_sur, ROW, FILE);//查看表棋盘
}
else
printf("坐标被占用,请重新输入!\n");
}
}
else
printf("坐标非法,请重新输入!\n");
}
}
五、总结
我们了解完扫雷的原理后,可以自己写出一个扫雷小游戏了,为了代码的简洁我们可以分为三个文件写出。
1.test.c文件
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void game()
{
//初始化数组表与内
char ches_sur[ROWS][FILES] = { 0 };
char ches_in[ROWS][FILES] = { 0 };
//初始化棋盘表与内
Initializes_the_chessboard(ches_sur, ROWS, FILES, '*');
Initializes_the_chessboard(ches_in, ROWS, FILES, '0');
//打印表内棋盘
Print_the_chessboard(ches_sur, ROW, FILE);
//Print_the_chessboard(ches_in, ROW, FILE);
//电脑在内棋盘中埋地雷
Computer_input(ches_in, ROW, FILE);
//Print_the_chessboard(ches_in, ROW, FILE);
//玩家在表棋盘中排地雷并打印出来,且通过里棋盘打印出附近地雷个数
Player_input(ches_in, ches_sur, ROW, FILE);
}
void game_interface()
{
printf("*************************\n");
printf("****** 1.进入游戏 *******\n");
printf("****** 0.退出游戏 *******\n");
printf("*************************\n");
}
int main()
{
//时间戳
srand((unsigned int)time(NULL));
int num = 0;
do
{
game_interface();//(游戏界面)
printf("请输入是否进入游戏:");
scanf("%d", &num);
if (1 == num)
{
game();
}
else if (0 == num)
{
printf("退出游戏\n");
}
else
{
printf("输入错误,请重新输入!\n");
}
} while (num);
return 0;
}
2.game.h文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define FILE 9
#define ROWS ROW + 2
#define FILES FILE + 2
#define BOMB 10
//初始化棋盘
void Initializes_the_chessboard(char ches[ROWS][FILES], int rows, int files, char sym);
//棋盘打印
void Print_the_chessboard(char ches[ROWS][FILES], int row, int file);
//电脑在内棋盘中埋地雷
void Computer_input(char ches_in[ROWS][FILES], int row, int file);
//玩家在表棋盘中排地雷并打印出来,且通过里棋盘打印出附近地雷个数
void Player_input(char ches_in[ROWS][FILES], char ches_sur[ROWS][FILES], int row, int file);
3.game.c文件
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
//初始化棋盘
void Initializes_the_chessboard(char ches[ROWS][FILES], int rows, int files, char sym)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < files; j++)
{
ches[i][j] = sym;
}
}
}
//棋盘打印
void Print_the_chessboard(char ches[ROWS][FILES], int row, char file)
{
printf("----------扫雷----------\n");
for (int j = 0; j <= file; j++)
{
printf("%d ", j);
}
printf("\n");
for (int i = 1; i <= row; i++)//打印下标1到9的棋盘
{
printf("%d ", i);
for (int j = 1; j <= file; j++)
{
printf("%c ", ches[i][j]);
}
printf("\n");
}
printf("----------扫雷----------\n");
}
//电脑在内棋盘中埋地雷
void Computer_input(char ches_in[ROWS][FILES], int row, int file)
{
int x = 0;
int y = 0;
int b = BOMB;
int n = 0;
while (n < b)
{
x = rand() % row + 1;
y = rand() % file + 1;
if (ches_in[x][y] == '0')
{
ches_in[x][y] = '1';
n++;
}
}
}
//玩家在表棋盘中排地雷并打印出来,且通过里棋盘打印出附近地雷个数
int look_bomb(char ches_in[ROWS][FILES], int x, int y)
{
int add = 0;
int i = 0;
int j = 0;
//雷个数
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
add = add + ches_in[i][j];
}
}
return add - 9 * '0';
}
void Player_input(char ches_in[ROWS][FILES], char ches_sur[ROWS][FILES], int row, int file)
{
//玩家输入查看的区域
int x = 0;
int y = 0;
while (1)
{
printf("请输入排查坐标:");
scanf("%d %d", &x, &y);
//打印出地雷个数
if (x > 0 && x <= row && y > 0 && y <= file)
{
if (ches_in[x][y] == '1')
{
printf("踩到炸弹,游戏结束!\n");
Print_the_chessboard(ches_in, ROW, FILE);
break;
}
else
{
if (ches_sur[x][y] == '*')
{
//得出范围内的雷个数
int lo = look_bomb(ches_in, x, y);
ches_sur[x][y] = lo + '0';
Print_the_chessboard(ches_sur, ROW, FILE);
}
else
printf("坐标被占用,请重新输入!\n");
}
}
else
printf("坐标非法,请重新输入!\n");
}
}