ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

C语言小项目(2)——扫雷(基础版)

2021-12-20 23:02:29  阅读:209  来源: 互联网

标签:COLS ROWS 项目 int mine C语言 char 扫雷 board


C语言小项目(2)——扫雷(基础版)

前言

扫雷游戏是C语言初学者都需要练习的一个小项目,本文所实现的扫雷为最基础的版本(即一次只能扫一格),实际的扫雷游戏会有一种功能:在玩家点击格子的时候会向外展开,直到即将遇到雷为止。本文目前暂无实现这一功能。

代码详解

一、主函数

int main()
{
	int i = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();//打印菜单
		scanf("%d", &i);
		switch (i)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏结束\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (i);
	return 0;
}

1、srand((unsigned int)time(NULL))

为随机数生成器,后续布置雷的时候需要利用到rand()函数。

2、do-while循环

用于玩家多次游玩,直到玩家选择游戏结束,则终止循环。
menu()函数为菜单函数,用于打印简易菜单供玩家选择。

void menu()
{
	printf("*************************\n");
	printf("****** 1、开始游戏 ******\n");
	printf("****** 0、结束游戏 ******\n");
	printf("*************************\n");
}

运用switch-case函数,若玩家输入"1",则开始游戏;若玩家输入"0",则游戏结束,同时循环中止;若玩家输入其他数字,则会提示玩家并让玩家重新输入,直到输入的数字为"0"或者"1"为止。

二、游戏实现函数

本扫雷游戏的实现依靠两个二维数组:mine数组用于系统随机布置雷,show数组展现给玩家,供玩家进行排雷。当除了雷以外的格子都被玩家选中之后,玩家获得胜利。

void game()
{
	//初始化
	char mine[ROWS][COLS] = { 0 };//存放布置雷的信息
	char show[ROWS][COLS] = { 0 };//存放玩家操作的信息
	//初始化布置雷界面
	Init_board(mine, ROWS, COLS, '0');
	//初始化玩家操作界面
	Init_board(show, ROWS, COLS, '*');
	//随机生成雷
	Mine_set(mine, ROW, COL);
	//打印扫雷界面
	Display_board(show, ROW, COL);
	//排雷
	Mine_sweep(mine, show, ROW, COL);
}

1、char mine[ROWS][COLS] = { 0 },char show[ROWS][COLS] = { 0 }

用于创建并初始化二维数组,作为扫雷的界面
本项目采用9*9的格子,为了便于日后的修改,此处采用了define ROW和COL的方式。
除了ROW和COL之外,额外定义了ROWS和COLS这两个变量名。玩家在扫雷的时候,若没有选到雷,被选中的格子会显示周围雷的个数,但边界处的格子在计算时会有一部分的格子在边界外,如果不加以处理的话不利于之后的计算。因此,本项目选择额外在最外围加了一圈,这样的即便是边界处也可以计算周围的雷的个数。

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

2、void Init_board(char board[ROWS][COLS], int row, int col, char set)

该函数声明为扫雷界面初始化函数声明,将mine初始化为字符’0’,show初始化为’*’(此处通过建立char类型的变量set,赋予set不同的值,可以将界面初始化为任何字符,避免了需要建立两个函数分别初始化mine和show

void Init_board(char board[ROWS][COLS], int row, int col, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = set;
		}
	}
}

3、Mine_set(mine, ROW, COL)

该函数用于随机生成雷。利用count计数,若该处未布置雷,则放置字符’1’代表雷(此处放置’1’便于之后的计算周围雷的个数),count相应减1。

void Mine_set(char board[ROWS][COLS], int row, int col)
{
	int count = easy_mode;
	while (count > 0)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

此处通过定义了easy_mode,便于日后对于雷的个数进行修改。

#define easy_mode 10

4、Display_board(show, ROW, COL)

该函数作用为打印界面供玩家进行扫雷,除了9*9格子外额外打印了行号和列号便于玩家输入坐标进行排雷。

void Display_board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	//打印列号
	for (j = 0; j <= col; j++) {
		printf("[%d]", j);
	}
	printf("\n");

	for (i = 1; i <= row; i++)
	{
		printf("[%d]", i);//打印行号
		for (j = 1; j <= col; j++)
		{
			printf(" %c ", board[i][j]);
		}
		printf("\n");

5、Mine_sweep(mine, show, ROW, COL)

该函数为整个扫雷游戏的核心。当玩家选择了所有除了雷以外的格子时,玩家获得胜利。

void Mine_sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row * col - easy_mode)
	{
		printf("请输入排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了,游戏结束\n");
				Display_board(mine, ROW, COL);
				break;
			}
			else
			{
				int n = get_mine_amount(mine, x, y);//判断周围雷的个数
				show[x][y] = n + '0';
				win++;
				Display_board(show, ROW, COL);
			}
		}
		else
		{
			printf("超出范围,请重新输入\n");
		}
	}
	if (win == row * col - easy_mode)
	{
		printf("恭喜你,获得胜利\n");
		Display_board(mine, ROW, COL);
	}
}

玩家输入坐标后,首先要排查玩家输入的坐标是否在界面范围内,若在范围内,继续判断玩家是否踩到了雷,若踩到雷则跳出循环游戏结束,反之则利用get_mine_amount(mine, x, y)函数计算周围雷的个数,并将个数打印在界面上,供玩家进行下一步的判断。
此处利用了一个小技巧:一个数字加上字符’0’可以转变成相对应的字符(数字加上字符’0’相当于该数字加上’0’的ASCII码值)。
因此在get_mine_amount函数中,我们只需加总玩家选中的坐标周围8个格子里的字符后减去8乘上’0’,即可得到对应的雷的个数的数字,这也是先前选择字符’1’作为雷的标记的原因。

int get_mine_amount(char mine[ROWS][COLS], int x, int y)
{
	return mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1]
		+ mine[x - 1][y] + mine[x + 1][y]
		+ mine[x - 1][y + 1] + mine[x][y + 1] + mine[x + 1][y + 1]
		- 8 * '0';
}

由于二维数组show是char类型的,因此在赋值的时候需要加上字符’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 easy_mode 10

//初始化扫雷界面
void Init_board(char board[ROWS][COLS], int row, int col, char set);

//打印扫雷界面
void Display_board(char board[ROWS][COLS], int row, int col);

//随机生成雷
void Mine_set(char board[ROWS][COLS], int row, int col);

//排雷
void Mine_sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

二、test.c

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"

//菜单函数
void menu()
{
	printf("*************************\n");
	printf("****** 1、开始游戏 ******\n");
	printf("****** 0、结束游戏 ******\n");
	printf("*************************\n");
}

//扫雷游戏
void game()
{
	//初始化
	char mine[ROWS][COLS] = { 0 };//存放布置雷的信息
	char show[ROWS][COLS] = { 0 };//存放玩家操作的信息
	//初始化布置雷界面
	Init_board(mine, ROWS, COLS, '0');
	//初始化玩家操作界面
	Init_board(show, ROWS, COLS, '*');
	//随机生成雷
	Mine_set(mine, ROW, COL);
	//打印扫雷界面
	Display_board(show, ROW, COL);
	//排雷
	Mine_sweep(mine, show, ROW, COL);
}


//主函数
int main()
{
	int i = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();//打印菜单
		scanf("%d", &i);
		switch (i)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏结束\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (i);
	return 0;
}

三、game.c

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"

//初始化扫雷界面
void Init_board(char board[ROWS][COLS], int row, int col, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = set;
		}
	}
}

//打印扫雷界面
void Display_board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	//打印列号
	for (j = 0; j <= col; j++) {
		printf("[%d]", j);
	}
	printf("\n");

	for (i = 1; i <= row; i++)
	{
		printf("[%d]", i);//打印行号
		for (j = 1; j <= col; j++)
		{
			printf(" %c ", board[i][j]);
		}
		printf("\n");
	}
}

//随机生成雷
void Mine_set(char board[ROWS][COLS], int row, int col)
{
	int count = easy_mode;
	while (count > 0)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

//判断周围雷的个数
int get_mine_amount(char mine[ROWS][COLS], int x, int y)
{
	return mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1]
		+ mine[x - 1][y] + mine[x + 1][y]
		+ mine[x - 1][y + 1] + mine[x][y + 1] + mine[x + 1][y + 1]
		- 8 * '0';
}

//排雷
void Mine_sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row * col - easy_mode)
	{
		printf("请输入排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了,游戏结束\n");
				Display_board(mine, ROW, COL);
				break;
			}
			else
			{
				int n = get_mine_amount(mine, x, y);//判断周围雷的个数
				show[x][y] = n + '0';
				win++;
				Display_board(show, ROW, COL);
			}
		}
		else
		{
			printf("超出范围,请重新输入\n");
		}
	}
	if (win == row * col - easy_mode)
	{
		printf("恭喜你,获得胜利\n");
		Display_board(mine, ROW, COL);
	}
}

总结

本项目基本实现了扫雷游戏,但仍旧存在较大的修改空间,例如利用递归实现选中格子之后的展开功能……

标签:COLS,ROWS,项目,int,mine,C语言,char,扫雷,board
来源: https://blog.csdn.net/m0_61166151/article/details/122030977

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有