Executando verificação de segurança...
12

ꡌ‍ Pathfinding com labirinto dinâmico: Autômatos Celulares + Árvores na prática! 🌳

No labirinto a seguir, é trivial sair do canto superior esquerdo e chegar no canto inferior direito:

Mas como você faria isso se o labirinto mudasse (deterministicamente) a cada movimento?

E em labirintos maiores? Têm como resolver com a menor quantidade possível de movimentos?

O que isso tem haver com Autômatos Celulares e Árvores?

Bem, esse labirinto dinâmico é um Autômato Celular e o algoritmo que encontra o caminho até a saída utiliza como base uma Árvore para otimizar a busca da solução!

Se você reparar bem, todos os labirintos seguem as seguintes regras de mudança a cada movimento:

  • As células cinza com 2 ou 3 vizinhos viram azúis na próxima geração.
  • As células azúis com 4 ou 5 ou 6 vizinhos permanecem azúis. Do contrário, viram cinza.

Além disso, a própria busca pelo caminho é naturalmente modelada como uma árvore, onde cada movimento aumenta uma unidade na profundidade da mesma.

A seguir podemos ver a árvore sendo formada. Nela, cada bolinha verde é um nó folha que representa o final de um possível caminho até à saída do labirinto. Nós folha que não conseguem mais se expandir são podados da árvore, pois representam caminhos sem saída. Quando algum nó folha chega na saída, encontramos um caminho solução do labirinto.

O projeto conta ainda com 3 modos de jogo:

Fun

Você pode jogar manualmente usando o teclado (além de poder ativar/desativar a exibição de quantidade de vizinhos + hints de próximo estado):

Debug

Você pode ver o algoritmo rodando passo a passo (controlando a execução via teclado). Bem útil para entender como o algoritmo funciona.

Release

Para labirintos gigantes onde queremos apenas a solução final, sem ficar renderizando na tela cada movimento.

Gerei alguns tabuleiros com estado inicial aleatório (e tamanhos cada vez maiores) pra ver:

  • Quantos movimentos são necessários para chegar na saída
  • Quanto tempo leva pro algoritmo encontrar a solução
SizeMovesTime
100 x 10027697 ms
500 x 5001.3764,1 s
1.000 x 1.0002.77634,2 s
1.500 x 1.5004.1742,5 min
2.000 x 2.0005.5065,2 min

O projeto conta ainda com mais de 80 casos de teste, pois utilizei o TDD durante grande parte da implementação:

Código completo no GitHub: https://github.com/ZaqueuCavalcante/mayz

Encontrei esse problema em um desafio da Stone anos atrás, que foi coordenado pelo pessoal da Sigma Geek.

Carregando publicação patrocinada...
1

Rapaz, estou vendo justamente isso na disciplina de IA na faculdade, parte de buscas e buscas guiadas por agentes(busca gulosa e IDS) recentemente fiz uma implementação "com uma ajuda" de IDS ao A*, BFS e DDFS já estou mais acostumando. Fiz a implementação em python, e você em java, bem legal, também sou mais chegado ao C++, porém a disciplina pede python. Muito legal seu trabalho. :)

1
2

Interface gráfica não, apenas mostra dados do caminho expansão etc. É um projeto para resolver 8-puzzle. Sendo que se pode escolher qual é o tabuleiro final.
A "interface" é algo do tipo:
=== Solução por BFS Gulosa ===
Caminho da solução: esquerda -> baixo -> direita -> cima -> direita -> cima -> esquerda -> baixo -> baixo -> direita
Custo da solução: 10
Nós expandidos: 25
Tamanho da fronteira: 22
Tamanho máximo da fronteira: 23
Profundidade da busca: 10
Profundidade máxima da busca: 12
Tempo de execução: 0.000388 segundos
Uso de memória: 114.98 MB

=== Solução por A* ===
Caminho da solução: direita -> cima -> esquerda -> baixo -> esquerda -> baixo -> direita -> direita
Custo da solução: 8
Nós expandidos: 13
Tamanho da fronteira: 11
Tamanho máximo da fronteira: 12
Profundidade da busca: 8
Profundidade máxima da busca: 8
Tempo de execução: 0.000172 segundos
Uso de memória: 114.98 MB

Vou ver se organizo para postar, valeu :D