day18 C语言初阶——扫雷的实现

本文详细介绍了如何从零开始设计并实现一个扫雷游戏,包括游戏规则解析、多文件模式搭建、菜单设计、游戏界面展示、雷区设置、玩家交互处理及游戏逻辑实现等关键步骤。

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");
	}


}

美好的时光总是短暂的,我们下期再会!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值