前言
扫雷游戏规则:
1、点击方格,如果出现数字,数字表示这个格子周围八个格子的雷的总数。
2、如果点击的方格里有雷,那么游戏结束,如果没有雷,则显示旁边一圈(8个)格子的总雷数。
为了更加清楚地实现效果,我们将设置两个字符型数组,一个放置雷,一个放置排查出来雷的个数,便于我们实现扫雷。同时,我们创建两个源文件以及一个头文件,便于修改,提高代码可读性:
- 首先是自己最先创建,包含主函数的.c文件,例如在此游戏中是test.c,用来测试。
- 我们通常会新建一个头文件,例如此游戏新建game.h,此头文件通常用来完成函数声明、头文件的引用、宏定义变量。
- 新建一个.c文件,例如在此游戏新建game.c,编写涉及到的功能函数实现。
一、需要思考的问题
1、如果只有一个棋盘,如何明白当我们点击格子时显示的数字是雷的个数还是表示这个位置有雷?
这里我们设定两个字符型的数组,数组mine来存储雷(用1表示雷,0表示非雷),数组show用来存放排查出来的雷的个数(即在数组mine中点击格子,那么对应的数组show中对应的位置会显示雷的个数)
其中:刚开始我们可以设置数组mine里面的元素全部为字符0,之后再随机生成雷;设置数组show里面的元素全部为字符*,计算出数组mine在数组show对应位置旁边雷的个数之后放置字符。
2、如何避免使用数组时越界?
我们知道扫雷点击方格之后出现的数字是旁边一圈(8个)格子里面雷的总数,如果设置格子的大小为9×9,在查找边界格子周围的雷的个数时会越界,为避免越界,我们将格子扩大一圈,变成11×11的格子大小,但是只使用中间9×9部分的格子。
二、具体代码及实现步骤
1、main()函数实现让用户决定是否开始游戏。
?
int main()
{
int a;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入:\n");
scanf("%d", &a);
switch (a)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
} while (a);
return 0;
}
2、棋盘初始化。
这里为了不在排查雷的时候越界,我们设置11×11的格子大小:在放置雷的mine数组中,我们首先是将元素都设置为字符0(方便后面随机雷的分布);在排查雷的show数组中,我们将所以元素设置为字符*(后面计算出一个格子一圈(8个)旁边雷的个数之后好改变)。
?
?3、打印棋盘。
我们需要放置雷的棋盘实际上是9x9的棋盘,所以我们打印出来的还是9x9的棋盘,但是我们去排雷(计算)一个格子旁边一圈雷的总数的时候我们还是用的是11x11的棋盘,所以这里我们传给函数的参数还是11x11的棋盘,但是穿的行和列的参数都为9,我们将会在game.c文件里面用用循环的方式使用数组下标1-9去打印9x9棋盘。
【注意】
COL?ROW 在头文件game.h中定义为9,COLS ROWS在game.h中定义为COL+2 ROW+2
【注意】这里我们增加设置了一横行以及一竖行0-9,便于我们清楚坐标。那么除了打印出来的9x9棋盘,最上方和最右方有0-9。
void Printboard(char board[ROWS][COLS], int row, int col)
{
int i, j;
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 ", board[i][j]);
}
printf("\n");
}//确保是中间9x9的区域 通过下标来定位
printf("----------------------\n");
}
4、布置雷。
生成1-9间的随机数,利用随机数确定放置雷的行和列。并且在放置雷之前要判断此位置是否被放置过,如果被放置过就换一个随机数,直至放满指定的雷的个数。(成功放置一个雷之后,那么定义的雷的个数要减1)
【注意】
1、指定雷的个数,我们在头文件game.h中定义了#define EASY_COUNT 10
2、为什么会生成1-9之间的随机数呢?
? ? 一个数x%一个数y,这样取得余数是小于y的值,范围0到y-1。我们已经传参使得row=9,col=9,所以余数范围肯定为0到8,那么再加一就是1到9的范围。(打印棋盘中,增加设置了一横行以及一竖行0-9,便于我们清楚坐标。那么除了打印出来的9x9棋盘,最上方和最右方有0-9。)
?
5、排雷。
1、排雷首先要确定输入的坐标是否有效,无效坐标需要重新输入。 2、如果选择的格子是雷,则游戏结束。 3、如果选择的格子不是雷,那么我们开始计算选择的格子旁边一圈的雷的总数。
【注意】:int GetmineCount(char MINE[ROWS][COLS], int x, int y) 用来计算雷的总数,这里我们计算的是整数,因为字符‘0’的ASCII码是48,字符‘3’的ASCII码是51,所以整数3=‘3’-‘0’,同理,整数8也是如此,所以我们便可以理解这个函数里面雷的总数计算。
4、同时设置一个整型win为0,对非雷格子进行计数,排雷一次win的个数加1,如果win与非雷个数相等,则排雷成功。(非雷个数:行x列-雷数)
?
//排查雷
void Findmine(char MINE[ROWS][COLS], char SHOW[ROWS][COLS], int row, int col)
{
int x, y;
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 (MINE[x][y] == '1')
{
printf("你被炸死了\n");
Printboard(MINE, ROW, COL);
break;
}
else
{
int count = GetmineCount(MINE,x,y);
SHOW[x][y] = count + '0';//'3'-'0'=3;
Printboard(SHOW, ROW, COL);
win++;
}
}
else
{
printf("坐标非法,请重新输入");
}
}
if (win == row*col - EASY_COUNT)
{
printf("恭喜你,排雷成功");
}
}
int GetmineCount(char MINE[ROWS][COLS], int x, int y)
{
return (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] + MINE[x - 1][y + 1]
- 8 * '0');
}
6、运行结果
?三、源代码
1、test.c
//扫雷游戏
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void menu()
{
printf("------------------------------\n");
printf("-----------请输入:-----------\n");
printf("------游戏开始(输入1):-----\n");
printf("------退出游戏(输入0):-----\n");
printf("------------------------------\n");
}
void game()
{
char mine[ROWS][COLS] = {0};//存放雷
char show[ROWS][COLS] = {0};//存放排查出的雷
Initialboard(mine, ROWS, COLS,'0');
Initialboard(show, ROWS, COLS,'*');//初始化两个棋盘(防止越界)
//布置雷
Setmine(mine, ROW, COL);
// Printboard(mine, ROW, COL);//打印防止雷的区域
//排查雷
Findmine(mine, show, ROW, COL);
}
int main()
{
int a;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入:\n");
scanf("%d", &a);
switch (a)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
} while (a);
return 0;
}
2、game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
//雷的个数
#define EASY_COUNT 10
#define ROWS ROW+2
#define COLS COL+2 //防止越界
void Initialboard(char board[ROWS][COLS], int rows, int cols, char ret);
void Printboard(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);
3、game.c
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void Initialboard(char board[ROWS][COLS], int rows, int cols,char ret)
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = ret;
}
}
}
void Printboard(char board[ROWS][COLS], int row, int col)
{
int i, j;
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 ", board[i][j]);
}
printf("\n");
}//确保是中间9x9的区域 通过下标来定位
printf("----------------------\n");
}
//布置雷
void Setmine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
//1、生成随机下标
int x = rand() % row + 1;//产生下标为1-9
int y = rand() % col + 1;
if (board[x][y] != '1')
{
board[x][y] = '1';
count--;
}
}
}
//排查雷
void Findmine(char MINE[ROWS][COLS], char SHOW[ROWS][COLS], int row, int col)
{
int x, y;
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 (MINE[x][y] == '1')
{
printf("你被炸死了\n");
Printboard(MINE, ROW, COL);
break;
}
else
{
int count = GetmineCount(MINE,x,y);
SHOW[x][y] = count + '0';//'3'-'0'=3;
Printboard(SHOW, ROW, COL);
win++;
}
}
else
{
printf("坐标非法,请重新输入");
}
}
if (win == row*col - EASY_COUNT)
{
printf("恭喜你,排雷成功");
}
}
int GetmineCount(char MINE[ROWS][COLS], int x, int y)
{
return (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] + MINE[x - 1][y + 1]
- 8 * '0');
}
源代码链接:
https://gitee.com/ltianyuu/c-language/tree/master/test-7-28-1
希望对大家的学习有所帮助,创作不易,希望大家给博主能点个赞啦!谢谢!!!笔芯哦!
|