[Juego Buscaminas] Realice el juego Buscaminas con recursividad en lenguaje C

El código se divide en tres partes, test.c (el marco general del juego), game.c (la implementación del juego, la mayoría de las funciones definidas), game.h (el archivo de encabezado utilizado)

Tabla de contenido

1. Flujo del juego

En segundo lugar, la función definida

Tres, la realización de la función.

1.menú vacío();

2. juego nulo ();

2.void Initboard(char board[ROWS][COLS],int row,int col,char set);

4.void Displayboard(charboard[ROWS][COLS], int row, int col);

 5.void leiboard(char board[ROWS][COLS], int row, int col);

6. void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col);

 7.int leicount(charboard[ROWS][COLS], int x, int y);

8.void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y);

 9.int iswin(char placa de usuario[ROWS][COLS], int fila, int columna);

Cuarto, el código completo.

1.prueba.c

2.juego.c

3.juego.h

5. Pruebas de juego

1. Ganaste (hay muchos pasos, puedes jugar solo, je, je)

 2. Pierdes (mi suerte, el primer centavo se murió volando jaja)

3. Las coordenadas de entrada son ilegales, vuelva a ingresar

4. Ha verificado esta ubicación, vuelva a ingresar


1. Flujo del juego

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

En segundo lugar, la función definida

void menu();
void game();
void Initboard(char board[ROWS][COLS],int row,int col,char set);
void Displayboard(char board[ROWS][COLS], int row, int col);
void leiboard(char board[ROWS][COLS], int row, int col);
void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col);
//返回类型为整型,返回用户输入坐标周围雷的个数
int leicount(char board[ROWS][COLS],  int x, int y);
void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y);
int iswin(char userboard[ROWS][COLS], int row, int col);

Tres, la realización de la función.

1.menú vacío();

void menu()
{
	printf("*********************************\n");
	printf("*********   1.play     **********\n");
	printf("*********   0.end      **********\n");
	printf("*********************************\n");
}

2. juego nulo ();

void game()
{
	char board1[ROWS][COLS];
	char board2[ROWS][COLS];
	printf("开始游戏\n");
	//初始化扫雷棋盘
	Initboard(board1, ROW, COL, '0');
	//给用户展示的排雷页面的初始化
	//放雷,把雷初始化好,雷是放在棋盘1
	leiboard(board1, ROW, COL);
	Initboard(board2, ROW, COL, '*');
	//打印一下给用户展示的棋盘
	Displayboard(board2, ROW, COL);
	//这个打印棋盘
	//1.初始化为0以及放入雷后的棋盘
	//2.用户排雷失败被炸死的时候,让用户被炸的明白用这个给打印出来
	//3.让程序员好用来测试完成扫雷游戏,最后注释掉
	//Displayboard(board1, ROW, COL);
	//用户进行扫雷,输入要排的坐标,都是在棋盘1上进行的,棋盘2,只是为了方便给用户展示,总不能把雷的位置也给用户展示了吧
	usermove(board1, board2, ROW, COL);

}

2.void Initboard(char board[ROWS][COLS],int row,int col,char set);

//初始化棋盘
//多初始化的两行,两列棋盘是为了判断边缘是否有雷时,数组会被越界访问
void Initboard(char board[ROWS][COLS], int row, int col, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row + 2; i++)
	{
		for (j = 0; j < col + 2; j++)
		{
			board[i][j] = set;
		}
	}
}

4.void Displayboard(charboard[ROWS][COLS], int row, int col);

//打印1-9的初始化的那部分棋盘
void Displayboard(char board[ROWS][COLS], int row, int col)
{
	int i = 1;
	int j = 1;
	for (i = 0; i < row + 1; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i < row + 1; i++)
	{
		printf("%d ", i);//打印出行数,竖着的一排嘛,方便看是第几行
		for (j = 1; j < col + 1; j++)
		{
			printf("%c ", board[i][j]); 
		}
		printf("\n");
	}
}

 5.void leiboard(char board[ROWS][COLS], int row, int col);

//放雷
void leiboard(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int i = 0;
	//放十个雷,用字符1表示
	for (i = 0; i < pri_count; i++)
	{
		//用随机数产生1-9的随机数(再棋盘为9*9的情况下,改变ROW和COL会改变)
		x = rand() % row + 1;//放到内圈 整个大圈时0-10 内圈是需要初始化和放雷的 即1-9
		y = rand() % col + 1;
		//这个if也是为了让雷在内圈,多的两行两列只是为了判断边缘的雷的情况,如果不设置的话会比较麻烦,或者会越界访问数组。
		//还有个条件就是这个地方没有雷才能放
		if (x > 0 && x < row + 1 && y>0 && y < col + 1&& board[x][y] == '0')
		{
			board[x][y] = '1';
		}
		else
			i--;//因为如果上一个if没进去的话,i就多加了一个1,但是没有放上雷,所以就减去一个1
	}
}

6. void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col);

void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	do
	{
		printf("请输入你要排除的坐标:>");
		scanf_s("%d %d", &x, &y);
		//判断输入的坐标是否正确
		if (x > 0 && x < row + 1 && y>0 && y < col + 1)
		{
			//判断是否为雷
			if (board[x][y] == '1')
			{
				printf("很遗憾,你被炸死了,哈哈哈,太遗憾了\n");
				printf("下面是本局雷的分布\n");
				Displayboard(board, ROW, COL);//被炸死后把这个棋盘打印出来,让用户知道自己踩了哪里的雷,以及雷都分布在哪里
				break;
			}
			else if(board[x][y] == '0' && userboard[x][y] == '*')
			{
				//设计一个函数,计算这个坐标周围八个位置的雷的数量
				userboard[x][y] = leicount(board, x, y);
				openaround(board, userboard, x, y);
				Displayboard(userboard, ROW, COL);
				//判断棋盘上剩余的雷的个数,等于初级设计的地雷的个数,就赢了
				if (iswin(userboard, row, col) == pri_count)
				{
					printf("恭喜你,赢了!!!!\n");
					Displayboard(board, ROW, COL);
					break;
				}
				//if (win == row * col - pri_count)
				//{
				//	printf("恭喜你,赢了!!!!\n");
				//	break;
				//}
			}
			else {
				printf("你已经排查过这个位置,请重新输入!\n");
			}
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}
	} while(1);
}

 7.int leicount(charboard[ROWS][COLS], int x, int y);

(//El tipo de devolución es un número entero, devolviendo el número de minas alrededor de las coordenadas ingresadas por el usuario)

int leicount(char board[ROWS][COLS], int x, int y)
{
	return board[x - 1][y] + board[x - 1][y + 1] +
	board[x][y + 1] + board[x + 1][y + 1] +
	board[x + 1][y] + board[x + 1][y - 1] +
	board[x][y - 1] + board[x - 1][y - 1] - 8 * '0';
}
	//字符1和字符0 的ASCLL码的十进制相差1,所以相减为1
	// 有雷的话减去字符0,就表示一颗雷,所以八个坐标全判断一下
	//例:(用户坐标头上的这个位置)board[x-1][y]-'0'
	//如果每一个都减'0'就比较繁琐,所以直接八个坐标的位置直接相加 减去八倍的字符0	
    //所以以用户输入的坐标为中心

8.void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y);

void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y)
{
	if (x > 0 && x < ROW + 1 && y>0 && y < COL + 1)
	{
		//这里两个限制条件,第一个限制条件就是为了展开没有雷的位置的周围的雷的情况
		//第二个限制条件就是为了防止弄成死递归,可以想一下,如果不限制,就会进入死递归,最终导致栈溢出
		if (leicount(board, x, y) == 0 && userboard[x][y] != ' ')
		{
			userboard[x][y] = ' ';
				openaround(board, userboard, x - 1, y);
				openaround(board, userboard, x - 1, y + 1);
				openaround(board, userboard, x, y + 1);
				openaround(board, userboard, x + 1, y + 1);
				openaround(board, userboard, x + 1, y);
				openaround(board, userboard, x + 1, y - 1);
				openaround(board, userboard, x, y - 1);
				openaround(board, userboard, x - 1, y - 1);
		}
		//这个限制条件也是为了防止把已经赋值为空格的坐标又给赋值为0了
		else if(userboard[x][y] != ' ')
		{
			userboard[x][y] = leicount(board, x, y) + '0';
			//这里解释一下 为什么加一个字符0
			//因为首先返回来的是一个整型,而这个数组是一个字符型
			//一个整型被进行强制类型转换为字符型的话,也会造成二进制位的丢失,打印出来也不确定打印棋盘时,打印出来的也不确定
			//所以这里加上字符0,字符零在其十进制上加返回来的十进制位数,对应的也是字符的也是整型的那个数
		}
	}
}

 9.int iswin(char placa de usuario[ROWS][COLS], int fila, int columna);

int iswin(char userboard[ROWS][COLS],int row,int col)
{
	int win = 0;
	int i = 0;
	int j = 0;
	for (i = 1; i < row + 1; i++)
	{
		for (j = 1; j < col + 1; j++)
		{
			if (userboard[i][j] == '*')
			{
				win++;
				//printf("%d\n", win);这个是我当时测试我的win是不是正确的时候弄得,我的思考过程,就注释掉,不删了吧
			}
		}
	}
	return win;
}

Cuarto, el código completo.

1.prueba.c

#define _CRT_SECURE_NO_WARNINGS 1//这个是因为我用的vs编译器认为scanf函数不安全,会报错

#include "game2.h"

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请输入:>");
		scanf_s("%d", &input);//因为加了上面那个不报错了,但是有警告,所以我还使用了scanf_s
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏结束\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

2.juego.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game2.h"

void menu()
{
	printf("*********************************\n");
	printf("*********   1.play     **********\n");
	printf("*********   0.end      **********\n");
	printf("*********************************\n");
}

void game()
{
	char board1[ROWS][COLS];
	char board2[ROWS][COLS];
	printf("开始游戏\n");
	//初始化扫雷棋盘
	Initboard(board1, ROW, COL, '0');
	//给用户展示的排雷页面的初始化
	//放雷,把雷初始化好,雷是放在棋盘1
	leiboard(board1, ROW, COL);
	Initboard(board2, ROW, COL, '*');
	//打印一下给用户展示的棋盘
	Displayboard(board2, ROW, COL);
	//这个打印棋盘
	//1.初始化为0以及放入雷后的棋盘
	//2.用户排雷失败被炸死的时候,让用户被炸的明白用这个给打印出来
	//3.让程序员好用来测试完成扫雷游戏,最后注释掉
	//Displayboard(board1, ROW, COL);
	//用户进行扫雷,输入要排的坐标,都是在棋盘1上进行的,棋盘2,只是为了方便给用户展示,总不能把雷的位置也给用户展示了吧
	usermove(board1, board2, ROW, COL);

}

//初始化棋盘
//多初始化的两行,两列棋盘是为了判断边缘是否有雷时,数组会被越界访问
void Initboard(char board[ROWS][COLS], int row, int col, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row + 2; i++)
	{
		for (j = 0; j < col + 2; j++)
		{
			board[i][j] = set;
		}
	}
}

//放雷
void leiboard(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int i = 0;
	//放十个雷,用字符1表示
	for (i = 0; i < pri_count; i++)
	{
		//用随机数产生1-9的随机数(再棋盘为9*9的情况下,改变ROW和COL会改变)
		x = rand() % row + 1;//放到内圈 整个大圈时0-10 内圈是需要初始化和放雷的 即1-9
		y = rand() % col + 1;
		//这个if也是为了让雷在内圈,多的两行两列只是为了判断边缘的雷的情况,如果不设置的话会比较麻烦,或者会越界访问数组。
		//还有个条件就是这个地方没有雷才能放
		if (x > 0 && x < row + 1 && y>0 && y < col + 1&& board[x][y] == '0')
		{
			board[x][y] = '1';
		}
		else
			i--;//因为如果上一个if没进去的话,i就多加了一个1,但是没有放上雷,所以就减去一个1
	}
}

//打印1-9的初始化的那部分棋盘
void Displayboard(char board[ROWS][COLS], int row, int col)
{
	int i = 1;
	int j = 1;
	for (i = 0; i < row + 1; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i < row + 1; i++)
	{
		printf("%d ", i);//打印出行数,竖着的一排嘛,方便看是第几行
		for (j = 1; j < col + 1; j++)
		{
			printf("%c ", board[i][j]); 
		}
		printf("\n");
	}
}

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

void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y)
{
	if (x > 0 && x < ROW + 1 && y>0 && y < COL + 1)
	{
		//这里两个限制条件,第一个限制条件就是为了展开没有雷的位置的周围的雷的情况
		//第二个限制条件就是为了防止弄成死递归,可以想一下,如果不限制,就会进入死递归,最终导致栈溢出
		if (leicount(board, x, y) == 0 && userboard[x][y] != ' ')
		{
			userboard[x][y] = ' ';
				openaround(board, userboard, x - 1, y);
				openaround(board, userboard, x - 1, y + 1);
				openaround(board, userboard, x, y + 1);
				openaround(board, userboard, x + 1, y + 1);
				openaround(board, userboard, x + 1, y);
				openaround(board, userboard, x + 1, y - 1);
				openaround(board, userboard, x, y - 1);
				openaround(board, userboard, x - 1, y - 1);
		}
		//这个限制条件也是为了防止把已经赋值为空格的坐标又给赋值为0了
		else if(userboard[x][y] != ' ')
		{
			userboard[x][y] = leicount(board, x, y) + '0';
			//这里解释一下 为什么加一个字符0
			//因为首先返回来的是一个整型,而这个数组是一个字符型
			//一个整型被进行强制类型转换为字符型的话,也会造成二进制位的丢失,打印出来也不确定打印棋盘时,打印出来的也不确定
			//所以这里加上字符0,字符零在其十进制上加返回来的十进制位数,对应的也是字符的也是整型的那个数
		}
	}
}

int iswin(char userboard[ROWS][COLS],int row,int col)
{
	int win = 0;
	int i = 0;
	int j = 0;
	for (i = 1; i < row + 1; i++)
	{
		for (j = 1; j < col + 1; j++)
		{
			if (userboard[i][j] == '*')
			{
				win++;
				//printf("%d\n", win);这个是我当时测试我的win是不是正确的时候弄得,我的思考过程,就注释掉,不删了吧
			}
		}
	}
	return win;
}

void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	do
	{
		printf("请输入你要排除的坐标:>");
		scanf_s("%d %d", &x, &y);
		//判断输入的坐标是否正确
		if (x > 0 && x < row + 1 && y>0 && y < col + 1)
		{
			//判断是否为雷
			if (board[x][y] == '1')
			{
				printf("很遗憾,你被炸死了,哈哈哈,太遗憾了\n");
				printf("下面是本局雷的分布\n");
				Displayboard(board, ROW, COL);//被炸死后把这个棋盘打印出来,让用户知道自己踩了哪里的雷,以及雷都分布在哪里
				break;
			}
			else if(board[x][y] == '0' && userboard[x][y] == '*')
			{
				//设计一个函数,计算这个坐标周围八个位置的雷的数量
				userboard[x][y] = leicount(board, x, y);
				openaround(board, userboard, x, y);
				Displayboard(userboard, ROW, COL);
				//判断棋盘上剩余的雷的个数,等于初级设计的地雷的个数,就赢了
				if (iswin(userboard, row, col) == pri_count)
				{
					printf("恭喜你,赢了!!!!\n");
					Displayboard(board, ROW, COL);
					break;
				}
				//if (win == row * col - pri_count)
				//{
				//	printf("恭喜你,赢了!!!!\n");
				//	break;
				//}
			}
			else {
				printf("你已经排查过这个位置,请重新输入!\n");
			}
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}
	} while(1);
}

3.juego.h

#pragma once

#define ROW 9
#define COL 9

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

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//初级版本的雷的数量
#define pri_count 10

void menu();
void game();
void Initboard(char board[ROWS][COLS],int row,int col,char set);
void Displayboard(char board[ROWS][COLS], int row, int col);
void leiboard(char board[ROWS][COLS], int row, int col);
void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col);
//返回类型为整型,返回用户输入坐标周围雷的个数
int leicount(char board[ROWS][COLS],  int x, int y);
void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y);
int iswin(char userboard[ROWS][COLS], int row, int col);

5. Pruebas de juego

1. Ganaste (hay muchos pasos, puedes jugar solo, je, je)

 

 

 

 

 

 

 

 

 

 

 

 

 2. Pierdes (mi suerte, el primer centavo se murió volando jaja)

3. Las coordenadas de entrada son ilegales, vuelva a ingresar

4. Ha verificado esta ubicación, vuelva a ingresar

 Finalmente, espero que pueda ayudar a todos, pruébalo ~

¡Por favor, corríjame si hay un error!

Supongo que te gusta

Origin blog.csdn.net/m0_57549888/article/details/124328485
Recomendado
Clasificación