Juego de biblioteca de gráficos Easyx --- laberinto

Inserte la descripción de la imagen aquí

Fuente: "Base de aprendizaje de programación" de la cuenta oficial de WeChat

Generación del laberinto

① Versión recursiva de división cruzada

② BFS (es decir, algoritmo de amplitud)

Generación de métodos de segmentación cruzada

Se requiere que el laberinto esté lleno de pasajes al principio, y luego cruzados al azar para construir paredes, y luego perforados al azar en tres paredes para conectar los cuatro subespacios.

Requisitos: Tanto las coordenadas horizontales como verticales del punto de cruce deben ser números pares (es decir, las filas y columnas del mapa son números impares) y los puntos de perforación deben ser números impares.

Generación del método DFS:

Como una tuza que perfora agujeros, el laberinto requiere todos los obstáculos (paredes) inicialmente, y luego agujeros en direcciones aleatorias (excavación de paredes).

Se requiere que el camino del muro a cavar (la dirección del agujero) solo se pueda penetrar con el nodo que se ha visitado.

Ejercicio de combate real

División cruzada

Un método muy simple, pero el efecto del juego no es muy bueno. A continuación se describe el proceso del algoritmo:

Encierre todo primero, luego haga una pared transversal

Inserte la descripción de la imagen aquí

Rompe tres paredes de la pared transversal.

Inserte la descripción de la imagen aquí

Genere de forma recursiva una pared transversal y luego abra tres paredes cualesquiera

Inserte la descripción de la imagen aquí

Luego se genera el laberinto más simple (de hecho, no hay laberinto para huevos, solo piense en ello como una recursividad de revisión)

Método DFS

En realidad es un algoritmo para cavar muros Bueno, eso creo. Explique este algoritmo en detalle.

Echemos un vistazo a la estructura de nodo que define el mapa.

#define MAP_ROW 20	
#define MAP_COL 25
Node map[MAP_ROW][MAP_COL] = {
    
     0 };	//每个墙 都没打通的  每个结点 都是没有访问过
struct Node
{
    
    
	int flag;						//表示关键结点是否访问过 0:未访问 1:已访问 2:待访问
									// 3:人物 4:目的地
	bool left, right, top, buttom;	//表示这个节点周围的四堵墙 0:不可通过的墙 1:可通过的空地
};

Luego es generar el mapa del laberinto, que es la función de inicialización init (), primero seleccione la esquina superior izquierda como la entrada al laberinto, que es también la ubicación del personaje

map[0][0].flag = 1;			//这个节点已经访问过

Definir la matriz auxiliar para almacenar los nodos que se visitarán.

COORD waitForVisit[MAP_COL * MAP_ROW];	//存放待访问的结点
int len = 0;							//map里面的坐标的个数

Al mismo tiempo, hay nodos para visitar alrededor de los nodos visitados , agréguelos a la matriz auxiliar,

waitForVisit[len++] = {
    
     1, 0 };		//下方的结点 可以访问
map[1][0].flag = 2;					//待访问
waitForVisit[len++] = {
    
     0, 1 };		//右边的结点 可以访问
map[0][1].flag = 2;					//待访问

El efecto es el siguiente:

Inserte la descripción de la imagen aquí

Al dibujar el mapa, establezca el blanco como nodos no visitados , el rosa como nodos visitados y el azul como nodos a visitar

if (map[i][j].flag == 0)				//没有访问过这个节点
{
    
    
	setfillcolor(WHITE);
}
else if (map[i][j].flag == 1)			//访问过
{
    
    
	setfillcolor(RGB(255, 193, 193));  
}
else if(map[i][j].flag == 2)			//待访问
{
    
    
	setfillcolor(BLUE);
}

Luego, visite los nodos que se visitarán uno por uno, y asegúrese de requerir que se visiten todos los nodos, es decir, buscar primero la amplitud

len为待访问节点的数量,从中随机选取一个节点进行访问,并将访问后该节点周围的未访问节点初始化为待访问节点

while (len > 0)
{
    
    
	//随机选取其中的一个结点  进行访问
	m = rand() % len;	//从可以访问的结点中随机取一个
	/*打通这个节点  把这个节点相邻的结点放到map里面*/
	borderThrough(map, waitForVisit[m]);	//borderThrough作用:打通waitForVisit[m]节点的任意一面(上下左右任意一面)
	map[waitForVisit[m].X][waitForVisit[m].Y].flag = 1;		/*标记已访问*/
}

La función borderThrough () para abrir el nodo es abrir cualquier lado del nodo donde se pasa el segundo parámetro (arriba, abajo, izquierda y derecha). El requisito para abrir es que los nodos adyacentes de esta superficie sean nodos que han sido visitados .

void borderThrough(Node map[][MAP_COL], const COORD node)///函数原型

Supere las condiciones:

(node.X + 1 < MAP_ROW) && map[node.X + 1][node.Y].flag == 1	//向下打通
(node.Y - 1 >= 0) && map[node.X][node.Y - 1].flag == 1		//向左打通

Después de la apertura, el nodo se establece como el nodo visitado (bandera == 1), y luego los cuatro nodos circundantes (nodos no visitados, si los hay) se configuran como los nodos que se van a visitar.

m为随机选取的待访问节点下标

/*周围的四个节点(如果有) 全部放到map里面*/
if (waitForVisit[m].X - 1 >= 0 && map[waitForVisit[m].X - 1][waitForVisit[m].Y].flag == 0)
{
    
    
	//如果上方的结点没有访问过   设置为待访问 并且把这个位置放到map里面
	map[waitForVisit[m].X - 1][waitForVisit[m].Y].flag = 2;	/*标记待访问*/
	waitForVisit[len++] = {
    
     waitForVisit[m].X - 1, waitForVisit[m].Y };/*添加进待访问节点辅助数组里面*/
}
if (waitForVisit[m].X + 1 < MAP_ROW && map[waitForVisit[m].X + 1][waitForVisit[m].Y].flag == 0)
{
    
    
	//下
	map[waitForVisit[m].X + 1][waitForVisit[m].Y].flag = 2; /*标记待访问*/
	waitForVisit[len++] = {
    
     waitForVisit[m].X + 1, waitForVisit[m].Y };/*添加进待访问节点辅助数组里面*/
}

Los nodos que se han marcado como visitados se eliminarán de la matriz de nodos que se visitarán

//map[m]已经访问过  从map里面删掉就可以
if (m == len - 1)
	len--;
else
{
    
    
	waitForVisit[m] = waitForVisit[len - 1];
	len--;
}

La reproducción a cámara lenta de todo el proceso es la siguiente:

Inserte la descripción de la imagen aquí

El movimiento de los personajes se ha explicado muchas veces, y puedes consultar los tutoriales anteriores como [Sokoban] a través del artículo anterior / siguiente.

Para operaciones más detalladas, envíe palabras clave en segundo plano [algoritmo de laberinto] para obtener el código fuente

Supongo que te gusta

Origin blog.csdn.net/qq_44519484/article/details/109280047
Recomendado
Clasificación