def hill_climbing(labyrinth, start, end): # Guardam os tempos da função begin_time = None found_time = None # Guarda as dimensões do labirinto x = len(labyrinth) y = len(labyrinth[0]) # Matriz que guarda os antecessores das posições já visitadas prev = [[[-1, -1] for i in range(y)] for j in range(x)] # Marca o elemento inicial para ser verificado primeiro cur = start # Marca a melhor heuristica encontrada até agora (inicia-se com um valor # maior que qualquer um que poderia ser retornado pela função) cur_dist = 2 * x * y # Marca o tempo de início e executa o hill climbing begin_time = time.time() while cur != None: # Verifica se um caminho foi encontrado # Se ele foi a busca encerra e o tempo é anotado if lb.is_end(labyrinth, cur): found = True found_time = time.time() break # Checa as adjacências do elemento e busca qual "colina subir" # Guarda o melhor elemento e seu valor na heuristica (inicia-se com um valor # maior que qualquer um que poderia ser retornado pela função) best = None # Direita next = lb.get_right(labyrinth, cur, prev) # [cur[0], cur[1] + 1] if next != None: # Escolhe esse nó se ele for melhor que o atual e melhor que os outros adjacentes (checado abaixo) next_dist = manhattan_distance(next, end) if next_dist < cur_dist: best = next # Já atualiza a distância atual para usa-la nas checagens abaixo cur_dist = next_dist # Baixo next = lb.get_bottom(labyrinth, cur, prev) # [cur[0] + 1, cur[1]] if next != None: next_dist = manhattan_distance(next, end) if next_dist < cur_dist: best = next cur_dist = next_dist # Esquerda next = lb.get_left(labyrinth, cur, prev) # [cur[0], cur[1] - 1] if next != None: next_dist = manhattan_distance(next, end) if next_dist < cur_dist: best = next cur_dist = next_dist # Cima next = lb.get_top(labyrinth, cur, prev) # [cur[0] - 1, cur[1]] if next != None: next_dist = manhattan_distance(next, end) if next_dist < cur_dist: best = next cur_dist = next_dist # "Sobe para a colina mais alta", se best for igual a None é porque o algoritmo # chegou em um melhor local, como não estamos usando backtracking ele deve parar if best != None: # Marca o antecessor do proximo elemento como sendo o atual prev[best[0]][best[1]] = [cur[0], cur[1]] cur = best else: # Marca o tempo que o algoritmo finalizou found_time = time.time() break # Gera o caminho a partir da matriz de predecessores # Nota-se que passamos cur ao invés de end para a função, # Isso é feito para podermos checar o melhor local encontrado # pelo algoritmo, já que muitas vezes ele não é capaz de achar # o melhor global path = lb.prev_to_path(prev, start, cur) # Retorna um objeto com os resultados return lb.Result(path, found_time - begin_time)
def bfs(labyrinth, start, end): # Guardam os tempos da função begin_time = None found_time = None # Queue usada para a BFS queue = [start] # Guarda as dimensões do labirinto x = len(labyrinth) y = len(labyrinth[0]) # Matriz que guarda os antecessores das posições já visitadas prev = [[[-1, -1] for i in range(y)] for j in range(x)] # Marca se um caminho foi encontrado found = False # Marca o tempo de início e executa a BFS begin_time = time.time() while len(queue) != 0: # Remove o primeiro elemento da fila cur = queue.pop(0) # Verifica se um caminho foi encontrado # Se ele foi a busca encerra e o tempo é anotado if lb.is_end(labyrinth, cur): found = True found_time = time.time() break # Checa as adjacências do elemento e as coloca na pilha se não foram visitadas # Direita next = lb.get_right(labyrinth, cur, prev) # [cur[0], cur[1] + 1] if next != None: queue.append(next) # Adiciona na fila prev[next[0]][next[1]] = cur # Marca o antecessor do proximo elemento como sendo o atual # Baixo next = lb.get_bottom(labyrinth, cur, prev) # [cur[0] + 1, cur[1]] if next != None: queue.append(next) prev[next[0]][next[1]] = cur # Esquerda next = lb.get_left(labyrinth, cur, prev) # [cur[0], cur[1] - 1] if next != None: queue.append(next) prev[next[0]][next[1]] = cur # Cima next = lb.get_top(labyrinth, cur, prev) # [cur[0] - 1, cur[1]] if next != None: queue.append(next) prev[next[0]][next[1]] = cur # Gera o caminho a partir da matriz de predecessores path = lb.prev_to_path(prev, start, end) # Retorna um objeto com os resultados if found: return lb.Result(path, found_time - begin_time) return lb.Result(None, None)
def best_first_search(labyrinth, start, end): # Marca o final do labirinto de forma que seja acessível à função de ordenação global global_end global_end = end # Guardam os tempos da função begin_time = None found_time = None # Priority queue usada para a best-first search p_queue = [start] # Guarda as dimensões do labirinto x = len(labyrinth) y = len(labyrinth[0]) # Matriz que guarda os antecessores das posições já visitadas prev = [[[-1, -1] for i in range(y)] for j in range(x)] # Marca se um caminho foi encontrado found = False # Marca o tempo de início e executa a best-first search begin_time = time.time() while len(p_queue) != 0: # Ordena a fila baseada em uma heuristica p_queue.sort(key=manhattan_distance) # Remove o primeiro elemento da fila cur = p_queue.pop(0) # Verifica se um caminho foi encontrado # Se ele foi a busca encerra e o tempo é anotado if lb.is_end(labyrinth, cur): found = True found_time = time.time() break # Checa as adjacências do elemento e as coloca na priority queue se não foram visitadas # Direita next = lb.get_right(labyrinth, cur, prev) # [cur[0], cur[1] + 1] if next != None: p_queue.append(next) # Adiciona na fila prev[next[0]][next[1]] = cur # Marca o antecessor do proximo elemento como sendo o atual # Baixo next = lb.get_bottom(labyrinth, cur, prev) # [cur[0] + 1, cur[1]] if next != None: p_queue.append(next) prev[next[0]][next[1]] = cur # Esquerda next = lb.get_left(labyrinth, cur, prev) # [cur[0], cur[1] - 1] if next != None and prev[next[0]][next[1]] == [-1, -1]: p_queue.append(next) prev[next[0]][next[1]] = cur # Cima next = lb.get_top(labyrinth, cur, prev) # [cur[0] - 1, cur[1]] if next != None and prev[next[0]][next[1]] == [-1, -1]: p_queue.append(next) prev[next[0]][next[1]] = cur # Gera o caminho a partir da matriz de predecessores path = lb.prev_to_path(prev, start, end) # Retorna um objeto com os resultados if found: return lb.Result(path, found_time - begin_time) return lb.Result(None, None)