c语言初阶-扫雷游戏

一、扫雷游戏的分析和设计

目录

一、扫雷游戏的分析和设计

1.1扫雷游戏展示

1.2扫雷游戏功能说明

1.3扫雷游戏功能实现

1.3.1菜单设计

1.3.2初始化棋盘

1.3.3打印棋盘

1.3.4布置雷

1.3.4扫描雷

二、全部源码

frame.c

game.h

game.c

三、扫雷游戏拓展

四、总结


1.1扫雷游戏展示

初始界面

排雷成功一次

排雷失败

1.2扫雷游戏功能说明

我们要实现这样的功能:玩家可以通过菜单实现继续玩或者退出游戏,进入游戏后,玩家输入雷的坐标,系统向玩家展示该位置的情况:若是雷,则输出被炸死且游戏结束,重新开始游戏;若不是雷,则输出一次棋盘,并在该棋盘中向玩家展示该位置四周八个位置的雷的数量;若把所有非雷的位置都找出来,则排雷成功,游戏结束。

1.3扫雷游戏功能实现

1.3.1菜单设计

使用printf输出菜单信息后,可以使用switch函数来判断,例如,输入1则进入游戏,输入2则退出游戏,输入其他数字则输出“输入错误”。该switch函数整体封装到while中,以实现循环进入游戏。

int main() {
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		caidan();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 2:
			break;
		default:
			printf("你的输入有误,请重新输入\n");
			break;
		}
	} while (input != 2);
	return 0;
}

1.3.2初始化棋盘

我们可以初始化两个棋盘来实现以上功能。一个棋盘布置雷(mine棋盘),另一个棋盘标记雷(mark棋盘)。

若我们需要在9*9 的棋盘上设计游戏,首先想到的就是创建一个9*9 的数组来存放信息。使用1来说明此位置是雷,没有雷就存放0(这样方便在统计雷的数量时可直接做加法运算)。在标记雷时,我们扫描该位置一周8个位置的1的数量,并输出在mark棋盘中。但是,若我们检查的位置在边界处,那么就会报错,产生数组越界,所以我们在设计数组时将其扩大一圈,且在布置雷时最外面一圈不去布置雷,这样就有效解决了数组越界问题。所以我们将棋盘设置为11*11的数组。

那么该数组要定义为什么类型的呢?若是定义为int型,则无法很清晰的表达mine棋盘。所以使用char类型定义数组,这样封装初始化棋盘的函数较为方便。

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
char mine[ROWS][COLS] = { '0' };
char mark[ROWS][COLS] = { '0' };
//初始化棋盘
Init_Board(mine,ROWS,COLS,'0');
Init_Board(mark,ROWS,COLS,'*');
void Init_Board(char board[ROWS][COLS], int a, int b, char z) {
	for (int i = 0; i < a; i++)
		for (int j = 0; j < b; j++)
			board[i][j] = z;
}

1.3.3打印棋盘

这里要注意我们不仅需要输出棋盘,还要输出横纵坐标。

void Print_Board(char board[ROWS][COLS],int row,int col){
	for (int i = 0; i <= row;i++)
		printf("%d", i);
	printf("\n");
	for (int i = 1; i <= row; i++) 
	{
		printf("%d", i);
		for (int j = 1; j <= col; j++)
			printf("%c", board[i][j]);
		printf("\n");
	}
}

1.3.4布置雷

利用time()函数传递时间戳来更新每一次的随机数种子,确保雷的位置是随机生成。

srand((unsigned int)time(NULL));
void Set_Board(char board[ROWS][COLS], int row, int col,int count_mine) {
	while (count_mine) {
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (board[x][y] != '1')
		{
			board[x][y] = '1';
			count_mine--;
		}
	}
}

其中变量count_mine代表雷的数量,使用全局变量实现。

#define COUNT_MINE 10

1.3.4扫描雷

我们在输入一个雷的坐标时,三种情况已在上述的功能说明中阐述,这里注意游戏成功的条件,即将所有雷都找到,使用win局部变量控制。

void Find_Board(char mine[ROWS][COLS], char mark[ROWS][COLS],int row,int col) {
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<ROW*COL- COUNT_MINE) {
		printf("请输入雷的坐标:");
		scanf("%d %d", &x, &y);
		if ((x > 0 && x <=row) && (y > 0 && y <= col)) {
			if (mine[x][y] == '1') {
				printf("失败,被雷炸死\n");
				break;
			}
			else
			{
				int count = Getcount(mine, x, y);
				mark[x][y] = count+'0';
				Print_Board(mark, ROW, COL);
				win++;
			}
		}
		else
			printf("坐标输入有误,请重新输入");
	}
	if (win==ROW*COL- COUNT_MINE) 
	{
		printf("恭喜你,扫雷成功\n");
		Print_Board(mine, ROW, COL);
	}
}

除此之外,我们还需要一个函数来检查某处四周雷的数量

int Getcount(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');
}

二、全部源码

frame.c

#define _CRT_SECURE_NO_WARNINGS

#include "game.h"
#include <stdio.h>

void caidan() {
	printf("******************\n");
	printf("****  1.paly  ****\n");
	printf("****  2.exit  ****\n");
	printf("******************\n");
}

void game() {
	char mine[ROWS][COLS] = { '0' };
	char mark[ROWS][COLS] = { '0' };
	//初始化棋盘
	Init_Board(mine,ROWS,COLS,'0');
	Init_Board(mark,ROWS,COLS,'*');
	//打印棋盘
	//Print_Board(mine,ROW,COL);
	Print_Board(mark,ROW,COL);
	//布置雷
	Set_Board(mine, ROW, COL, COUNT_MINE);
	//Print_Board(mine, ROW, COL);
	//扫描雷
	Find_Board(mine, mark,ROW,COL);
	Print_Board(mine, ROW, COL);
}
int main() {
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		caidan();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 2:
			break;
		default:
			printf("你的输入有误,请重新输入\n");
			break;
		}
	} while (input != 2);
	return 0;
}

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_MINE 10


//初始化棋盘
void Init_Board(char board[ROWS][COLS], int a, int b, char z);
//打印棋盘
void Print_Board(char board[ROWS][COLS],int row,int col);
//布置雷
void Set_Board(char borad[ROWS][COLS], int row, int col, int count_mine);
//扫描雷
void Find_Board(char mine[ROWS][COLS], char mark[ROWS][COLS], int row, int col);
//检查某处四周雷的数量
int Getcount(char mine, int x, int y);


game.c

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"

void Init_Board(char board[ROWS][COLS], int a, int b, char z) {
	for (int i = 0; i < a; i++)
		for (int j = 0; j < b; j++)
			board[i][j] = z;
}

void Print_Board(char board[ROWS][COLS],int row,int col){
	for (int i = 0; i <= row;i++)
		printf("%d", i);
	printf("\n");
	for (int i = 1; i <= row; i++) 
	{
		printf("%d", i);
		for (int j = 1; j <= col; j++)
			printf("%c", board[i][j]);
		printf("\n");
	}
}

void Set_Board(char board[ROWS][COLS], int row, int col,int count_mine) {
	while (count_mine) {
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (board[x][y] != '1')
		{
			board[x][y] = '1';
			count_mine--;
		}
	}
}

int Getcount(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 Find_Board(char mine[ROWS][COLS], char mark[ROWS][COLS],int row,int col) {
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<ROW*COL- COUNT_MINE) {
		printf("请输入雷的坐标:");
		scanf("%d %d", &x, &y);
		if ((x > 0 && x <=row) && (y > 0 && y <= col)) {
			if (mine[x][y] == '1') {
				printf("失败,被雷炸死\n");
				break;
			}
			else
			{
				int count = Getcount(mine, x, y);
				mark[x][y] = count+'0';
				Print_Board(mark, ROW, COL);
				win++;
			}
		}
		else
			printf("坐标输入有误,请重新输入");
	}
	if (win==ROW*COL- COUNT_MINE) 
	{
		printf("恭喜你,扫雷成功\n");
		Print_Board(mine, ROW, COL);
	}
}



三、扫雷游戏拓展

  • 是否可以选择游戏难度
  • 排雷后,展开其周围非雷的位置(递归)
  • 是否可以标记雷

四、总结

通过扫雷游戏的实现,不仅可以加强c语言数组、循环、条件语句、随机数的生成等知识点的学习,更是通过层层封装函数来进一步体会c语言的魅力,初学者可以根据自己的需要来设置游戏参数,让枯燥的代码变得有趣起来。大家可以先根据游戏实现的结果来自己思考实现各个功能,如果有问题可以参考上述的源码部分,或者来私聊我一起探讨。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值