Jogo de biblioteca gráfica Easyx --- labirinto

Insira a descrição da imagem aqui

Fonte: WeChat Official Account "Programming Learning Base"

Geração do labirinto

① Versão recursiva de divisão cruzada

② BFS (ou seja, algoritmo de amplitude)

Geração de método de segmentação cruzada

É necessário que o labirinto esteja cheio de passagens no início, e depois cruzado aleatoriamente para construir paredes, e então furos aleatoriamente feitos em três paredes para conectar os quatro subespaços.

Requisitos: as coordenadas horizontal e vertical do ponto de cruzamento devem ser números pares (ou seja, as linhas e colunas do mapa são números ímpares) e os pontos de perfuração devem ser números ímpares.

Geração de método DFS:

Como um esquilo fazendo buracos, o labirinto requer todos os obstáculos (paredes) inicialmente e, em seguida, buracos em direções aleatórias (cavar paredes).

É necessário que o caminho da parede a ser escavada (direção do furo) só possa ser penetrado com o nó que foi visitado.

Exercício de combate real

Divisão cruzada

Um método muito simples, mas o efeito do jogo não é muito bom. O seguinte descreve o processo do algoritmo:

Envolva tudo primeiro, em seguida, faça uma parede transversal

Insira a descrição da imagem aqui

Rompa quaisquer três paredes da parede cruzada

Insira a descrição da imagem aqui

Gere recursivamente uma parede cruzada e, em seguida, abra quaisquer três paredes

Insira a descrição da imagem aqui

Em seguida, o labirinto mais simples é gerado (na verdade, não há labirinto para ovos, apenas pense nisso como uma recursão de revisão)

Método DFS

Na verdade, é um algoritmo para cavar paredes. Bem, acho que sim. Explique esse algoritmo em detalhes.

Vamos dar uma olhada na estrutura do Node que define o 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:可通过的空地
};

Então é para gerar o mapa do labirinto, que é a função de inicialização init (), primeiro selecione o canto superior esquerdo como a entrada para o labirinto, que também é a localização do personagem

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

Defina a matriz auxiliar para armazenar os nós a serem visitados

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

Ao mesmo tempo, existem nós a serem visitados em torno dos nós visitados , adicione-os à matriz auxiliar,

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

O efeito é o seguinte:

Insira a descrição da imagem aqui

Ao desenhar o mapa, defina branco como nós não visitados , rosa como nós visitados e azul como nós a serem visitados

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

Em seguida, visite os nós a serem visitados um a um, e certifique-se de exigir que cada nó seja visitado, ou seja, a amplitude da primeira pesquisa

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

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

A função borderThrough () para abrir o nó é abrir qualquer lado do nó onde o segundo parâmetro é passado (para cima, para baixo, para a esquerda e para a direita). O requisito para a abertura é que os nós adjacentes desta superfície sejam nós que foram visitados .

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

Condições de superação:

(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		//向左打通

Após a abertura, o nó é definido como o nó visitado (sinalizador == 1) e, em seguida, os quatro nós circundantes (nós não visitados, se houver) são definidos como os nós a serem visitados.

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 };/*添加进待访问节点辅助数组里面*/
}

Os nós que foram marcados como visitados serão excluídos da matriz de nós a serem visitados

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

A reprodução em câmera lenta de todo o processo é a seguinte:

Insira a descrição da imagem aqui

O movimento dos personagens foi explicado várias vezes, e você pode conferir os tutoriais anteriores como [Sokoban] até o artigo anterior / próximo.

Para operações mais detalhadas, envie palavras-chave em segundo plano [algoritmo de labirinto] para obter o código-fonte

Acho que você gosta

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