day18
谁能横刀立马,唯我飞牛大将军!
#扫雷游戏的实现
说说我的想法,再给上代码。
扫雷规则:玩家输入一个位置,如果有雷,则直接被炸死;如果无雷,它会在该坐标上显示周围8个位置雷的个数,但是雷具体在哪不知道。就这样最终把所有的雷都排除就算成功。
1>先建立多文件模式,所有的固定套路写完
<2>思考 编写一个游戏,先把代码的小框架给搭出来!!!
<3>首先得有菜单吧,所以就有了我们的第一个函数void Menu()
printf("###############################");
printf("##### 欢迎来到扫雷游戏!#####\n");
printf("###############################\n");
printf("###### 1.Play 2.exit ######");
printf("###############################");
printf("Please select < 1 , 2 > :");
<4>联系到Menu()中有用户需要输入的select选项,所以这时我们在main.c函数中需要添加一个scanf函数
<5>用户输入一个数之后,要有一个响应的接口,这时候就可以写一个switch语句用户输入 1,这时候游戏开始,所以又需要一个游戏的页面,这时候就要在test.c中编写一个void Game()
用户输入 2,这时候对应的是退出选项,那么处于人性的设计,我们可以写printf(“欢迎下次再玩,再见咯!\n”);再接着break退出。
用户既不输入 1,也不输入2,那么再次处于人性化的考虑,printf(“你的输入有误,请重新输入…”);接着break退出。
<6>对于一个游戏来说,我们设计的可以让用户一直玩,所以,以上的main.c中的函数语句,我们要用一个循环语句来包含他,这时候,我们可以定义一个quit变量,int quit = 0;让循环跑起来的判断条件应该是while(!quit),那么这里修改了,case 2肯定也要修改,否则循环会一直跑,无法终止,在case 2中添加quit = 1,这时候在while(!quit)时相当于while(0),终止循环。
<7>main.c的架子我们已经基本上搭出来了,这时候我想先测试一下我的小框架代码,那么首先在void Game()函数中编写两个输出代码,我来简单的测试一下printf(“游戏开始!\n”); printf(“游戏结束!\n”); 好的,代码跑完没问题,我们把它注释掉。
<8>下面来搭void Game()的架子
(1)既然是扫雷的游戏,我们首先应该想到是有一个面板,所以第一步是定义面板,这里虽然用一个面板也是可以实现,因为电脑
有很多种实现方法。但不过**为了我们编写方便,我们可以定义两个面板,一个是供显示,一个是供记录雷的分布,这样简单一点,**考虑到后期游戏结束的时候,我们需要让玩家看到雷的分布,让他们“死的明明白白”,就还是要额外定义一个雷分布的面板。
我们想定义一个10X10的面板,但是这里有个问题,并不是所有的位置都是周围有8个雷的,比如边缘,这个时候我们要定义12X12的面板,只用最中心的区域。就可以满足,要在头文件声明一下,#define ROW 12 #define COL 12
char board[ROW][COL]; //显示面板 char mine[ROW][COL];//记录雷的分布
(2)有了面板之后,我们这个时候就是迫不及待地初始化了,那就InitBoard(board ,ROW,COL,’*’); InitBoard(mine, ROW, COL,‘0’);
这里注意,我们在声明的时候,我们想要这两个面板初始化用一个接口,而不是分别初始化,这么麻烦,这时候这样声明:
void InitBoard(char board[][ROW],int row,int col,char elem);
(3)初始化完了之后,我们需要布雷了吧,这里需要用到随机数种子,需要先声明,后使用,先写头文件,#include<stdlib.h>
#include<time.h>,我们可以在void Game()的最开始埋种子srand((unsigned long)time(NULL));
Game()重要的框架伪代码
srand((unsigned long)time(NULL));
char board[ROW][COL];
char mine[ROW][COL];
InitBoard(board ,ROW,COL,'*');
InitBoard(mine, ROW, COL,'0');
SetMine(mine, ROW, COL);
(4)接下来,我们的想法就是需要面板能显示给玩家,于是有了ShowBoard(),然后我们需要让玩家输入坐标,这个坐标,我们必须
先进行判定,第一坐标是不是合理(x>=1 && x<=10 && y>=1 && y<= 10),第二,坐标是不是已经被输入过了。这是排雷的过程
游戏,在雷没有排完之前,我们肯定想让玩家一直看到显示面板,一直输入坐标,进行游戏,所以,从面板的显示开始,我们需要用循环
将其囊括。输入坐标之后,和mine面板比较,如果mine[x][y] 等于 ‘0’,就代表没雷,就将周围的雷个数显示在上面,这时候需要计算一下,
所以GetNum()就写出来了。此时该位置已经被占用,count–,继续循环,如果mine[x][y] !=‘0’,就代表有雷,炸死。
int count = (ROW - 2)*(COL - 2) - NUM;//这个代表不是雷的个数,循环条件是count > 0。我们想知道,我们是输了还是成功了,那
就在循环外面加个if判定,如果跳出循环了并且还count > 0,说明一定是被雷炸死,否则扫雷成功!游戏结束,显示mine面板,让玩家
“死的明明白白”。
int count = (ROW - 2)*(COL - 2) - NUM;
while (count > 0)
{
system("cls");
ShowBoard(board,ROW,COL);
int x = 0;
int y = 0;
printf("请输入你想要的坐标< x, y> ");
scanf("%d %d",&x,&y);
if (x < 1 || x > 10 || y < 1 || y > 10)
{
printf("您输入的坐标不合理,请重新输入\n");
Sleep(1000);
continue;
}
if (board[x][y] != '*')
{
printf("您输入的坐标已被占用,请重新输入\n");
}
if (mine[x][y] == '0')
{
count--;
char num = GetNum(mine, x, y);
board[x][y] = num;
}
else
{
printf("(%d,%d)处有雷,你已经被炸死了\n",x,y);
break;
}
}
if (count > 0)
{
printf("很遗憾,扫雷失败\n");
}
else
{
printf("你成功了!\n");
}
ShowBoard(mine, ROW, COL);
<9>Game()的架子已经搭好,开始各功能逐渐精细
先来编写初始化代码
void InitBoard(char board[][ROW], int row, int col, char elem)
{
int i = 0;
for (; i < row; i++)
{
int j = 0;
for (; j < col; j++)
{
board[i][j] = elem;
}
}
}
再来编写置雷的代码
void SetMine(char mine[][ROW], int row, int col )
{
int n = NUM;
while (n)
{
int x = rand() % (row - 2) + 1;
int y = rand() % (col - 2) + 1;
if (mine[x][y] == '1')//这是防止重复置雷
{
continue;
}
mine[x][y] = '1';
n--;
}
}
接着来编写计算周围雷个数的代码
这里是要返回雷的个数,且以字符形式呈现,所以是char类型
‘1’=‘0’+1,为啥是 -7*‘0’,自己推,这不难噢
char GetNum(char mine[][ROW], 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][y + 1]/
+ + mine[x + 1][y - 1] /
+ mine[x + 1][y] + mine[x + 1][y + 1] - 7 * '0';
}
最后是最恶心的显示面板,不难,但是要自己慢慢调
void ShowBoard(char board[][ROW], int row, int col)
{
printf(" ");
int i = 1;
for (; i <= col-2; i++)
{
printf(" %d |",i);
}
printf("\n");
printf("----");
for (i = 1; i <= col - 2; i++)
{
printf("----");
}
printf("\n");
for ( i = 1; i <= row - 2; i++)
{
printf(" %2d| ",i);
int j = 1;
for (; j <= col-2; j++)
{
printf(" %-2c|", board[i][j]);
}
printf("\n");
for (j = 1; j <= col - 2; j++)
{
printf("----");
}
printf("----");
printf("\n");
}
}
Last one,代码奉上
//main.c
#include "test.h"
int main()
{
int quit = 0;
while (!quit)
{
int select = 0;
Menu();
scanf("%d",&select);
switch (select)
{
case 1:
printf("游戏开始!\n");
Game();
printf("再玩一把?\n");
break;
case 2:
printf("下次再见咯!\n");
quit = 1;
break;
default:
printf("您的输入有误,请重试!\n");
break;
}
}
system("pause");
return 0;
}
//test.h
#ifndef _TEST_H_
#define _TEST_H_
#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<time.h>
#pragma warning(disable:4996)
#define ROW 12 //行
#define COL 12 //列
#define NUM 20 //雷的个数为20
void Menu();
void Game();
void InitBoard(char board[][ROW],int row,int col,char elem);
void SetMine(char mine[][ROW], int row, int col);
char GetNum(char mine[][ROW], int x, int y);
void ShowBoard(char board[][ROW], int row, int col);
#endif
//test.c
#include "test.h"
void Menu()
{
printf("####################\n");
printf("##欢迎来到扫雷游戏##\n");
printf("## 1.Play 2.exit##\n");
printf("####################\n");
printf("请输入<1 or 2 > ");
}
void Game()
{
srand((unsigned long)time(NULL));
char board[ROW][COL];
char mine[ROW][COL];
InitBoard(board ,ROW,COL,'*');
InitBoard(mine, ROW, COL,'0');
SetMine(mine, ROW, COL);
int count = (ROW - 2)*(COL - 2) - NUM;
while (count > 0)
{
system("cls");
ShowBoard(board,ROW,COL);
int x = 0;
int y = 0;
printf("请输入你想要的坐标< x, y> ");
scanf("%d %d",&x,&y);
if (x < 1 || x > 10 || y < 1 || y > 10)
{
printf("您输入的坐标不合理,请重新输入\n");
Sleep(1000);
continue;
}
if (board[x][y] != '*')
{
printf("您输入的坐标已被占用,请重新输入\n");
}
if (mine[x][y] == '0')
{
count--;
char num = GetNum(mine, x, y);
board[x][y] = num;
}
else
{
printf("(%d,%d)处有雷,你已经被炸死了\n",x,y);
break;
}
}
if (count > 0)
{
printf("很遗憾,扫雷失败\n");
}
else
{
printf("你成功了!\n");
}
ShowBoard(mine, ROW, COL);
}
void InitBoard(char board[][ROW], int row, int col, char elem)
{
int i = 0;
for (; i < row; i++)
{
int j = 0;
for (; j < col; j++)
{
board[i][j] = elem;
}
}
}
void SetMine(char mine[][ROW], int row, int col )
{
int n = NUM;
while (n)
{
int x = rand() % (row - 2) + 1;
int y = rand() % (col - 2) + 1;
if (mine[x][y] == '1')
{
continue;
}
mine[x][y] = '1';
n--;
}
}
char GetNum(char mine[][ROW], 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][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 7 * '0';
}
void ShowBoard(char board[][ROW], int row, int col)
{
printf(" ");
int i = 1;
for (; i <= col-2; i++)
{
printf(" %d |",i);
}
printf("\n");
printf("----");
for (i = 1; i <= col - 2; i++)
{
printf("----");
}
printf("\n");
for ( i = 1; i <= row - 2; i++)
{
printf(" %2d| ",i);
int j = 1;
for (; j <= col-2; j++)
{
printf(" %-2c|", board[i][j]);
}
printf("\n");
for (j = 1; j <= col - 2; j++)
{
printf("----");
}
printf("----");
printf("\n");
}
}
本文详细介绍了如何从零开始设计并实现一个扫雷游戏,包括游戏规则解析、多文件模式搭建、菜单设计、游戏界面展示、雷区设置、玩家交互处理及游戏逻辑实现等关键步骤。

被折叠的 条评论
为什么被折叠?



