- 介绍扫雷游戏规则
- 对扫雷游戏代码实现的思考及解决
- 扫雷游戏代码实现
- 初始化棋盘
- 打印棋盘
- 布置雷
- 排查雷
4.扫雷游戏代码
5.写写我踩过的坑🕳️
介绍扫雷游戏
相信大家都或多或少知道扫雷游戏,接下来让我介绍一下扫雷游戏的规则吧~
游戏目标:玩家需要在最短的时间内识别出所有非雷区的格子,同时避免触碰到地雷。游戏区域由多个隐藏格子组成,每个格子可能隐藏着地雷或数字,数字表示周围八个格子中地雷的数量。
游戏模式:扫雷游戏默认三个等级:初级、中级、高级。初级游戏由9x9的平铺网格组成,共有10个地雷;中级游戏由16x16的平铺网格组成,共有40个地雷;高级游戏由16x30个平铺网格组成,共有99个地雷。
对扫雷游戏代码实现的思考及解决
- 在检索雷的个数的时候,需要检索周围的8个格子,当在边角时,周围不满8个格子,会出现越界访问,怎么办?
- 雷布置为 1,当周边有1个雷时,产生了歧义,怎么办?
- 对于已经排查过的坐标怎么办?
- 排查的坐标超过表格的范围怎么办?
解决方法:
本文以9*9为例:
1. 由于一个一个判断情况很麻烦,我们直接把棋盘扩大2行,变成11*11
初始化时把11*11初始化,打印时只打印9*9,再排查雷时就不会出现越界访问o(^・x・^)o~
2.由于表示雷的个数“1”与表示雷的“1”会有冲突,我们可以设置两个棋盘(一个为 mine,即自己可以看到的;另一个为 show,即显示在外的)
为了打印和计算方便,我建议大家把 mine 都初始化为'0',把 show 初始化为'*'(也是为了看起来更神秘_(:зゝ∠)_)
3.我们要设计代码,排除已经排查过的坐标
4.规定输入坐标的范围
首先:
我们演示的是9*9的格子,为了以后好改动,我们把行列定义出来,到时候升级时,容易改动~
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
初始化棋盘:
void initboard(char board[ROWS][COLS], int rows, int cols, char x)
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = x;
}
}
}
打印棋盘:
void displayboard(char board[ROWS][COLS], int row, int col)
{
int i, j;
for (i = 0; i < 10; 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");
}
}
结果:
布置雷:
用我们学过的随机数,随机布置雷,为了以后修改方便,我们也用#define
#define COUNT 10
void setmine(char board[ROWS][COLS],int row,int col)
{
int count = COUNT;
while(count)
{
int i = rand() % row+1;
int j = rand() % col+1;
if (board[i][j] == '0')//防止雷设置重复
{
board[i][j] = '1';
count--;
}
}
打印结果
排雷:
要想得知周围雷的数量:
通过周围的坐标-8*0得到值,因为mine上显示的是字符。
int num(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');
void findmine(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col)
{
int x = 0, y = 0;
int win = 0;
while (win < ROW * COL - COUNT)//ROW*COL-COUNT为除雷之外的空格子
{
printf("请输入坐标: ");
scanf("%d %d", &x, &y);
if ((x > 0 && x <= row) && (y > 0 && y <= col))//判断在棋盘内
{
if (show[x][y] != '*')
printf("这个坐标你已经排查过了~\n");
else if (mine[x][y] == '1')
{
printf("你被炸死了\n");
displayboard(mine, ROW, COL);
break;
}
else
{
show[x][y] = num(mine, x, y) + '0';//由于得到的是一个int类型的整数,+'0'再变成字符
displayboard(show, ROW, COL);
}
}
else
printf("你输入的坐标已经超过范围\n");
}
if (win == ROW * COL - COUNT)
{
printf("恭喜你,排雷成功\n");
displayboard(mine, ROW, COL);
}
}
总代码
game.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define COUNT 10
void initboard(char board[ROWS][COLS], int rows, int cols, char x);
void displayboard(char board[ROWS][COLS], int row, int col);
void setmine(char board[ROWS][COLS],int row,int col);
int num(char mine[ROWS][COLS], int x, int y);
void findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
game.c
#include"game.h"
void initboard(char board[ROWS][COLS], int rows, int cols, char x)
{
int i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = x;
}
}
}
void displayboard(char board[ROWS][COLS], int row, int col)
{
int i, j;
for (i = 0; i < 10; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i+1);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
void setmine(char board[ROWS][COLS],int row,int col)
{
int count = COUNT;
while(count)
{
int i = rand() % row+1;
int j = rand() % col+1;
if (board[i][j] == '0')//防止雷设置重复
{
board[i][j] = '1';
count--;
}
}
}
int num(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');
}
void findmine(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col)
{
int x = 0, y = 0;
int win = 0;
while (win < ROW * COL - COUNT)
{
printf("请输入坐标: ");
scanf("%d %d", &x, &y);
if ((x > 0 && x <= row) && (y > 0 && y <= col))//判断在棋盘内
{
if (show[x][y] != '*')//由于数组下标从0开始,我们的坐标-1才能得到正确的值
printf("这个坐标你已经排查过了~\n");
else if (mine[x][y] == '1')
{
printf("你被炸死了\n");
displayboard(mine, ROW, COL);
break;
}
else
{
show[x][y] = num(mine, x, y) + '0';
displayboard(show, ROW, COL);
}
}
else
printf("你输入的坐标已经超过范围\n");
}
if (win == ROW * COL - COUNT)
{
printf("恭喜你,排雷成功\n");
displayboard(mine, ROW, COL);
}
}
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];
char show[ROWS][COLS];
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);
findmine(mine, show, ROW, COL);
}
int main()
{
int n = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择: ");
scanf("%d", &n);
switch (n)
{
case 1:
printf("您已进入游戏\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("出错了,重新输入\n");
break;
}
} while (n);
return 0;
}
我踩过的坑🕳️:
- 把数组写的太过笼统
eg: mine为arr1,show为arr2
最后把他们搞混😖,并且很难找到问题所在
- 直接复制函数声明去用
比较懒,就复制了函数声明,把里面的删了再用,结果用函数的时候,忘记删了 返回类型 ,最终导致错误❌
eg: void initboard(mine,ROWS,COLS,'0');
- 打印棋盘时,下标从0开始
导致最终结果与找的坐标不一样
虽然做了补救