¿Qué es el algoritmo A*?

El algoritmo A* (A-star) se utiliza principalmente para la búsqueda de rutas y el recorrido de grafos. Es famoso por su eficiencia a la hora de determinar la ruta más corta. Campos como la inteligencia artificial, la robótica y el desarrollo de juegos dependen de este algoritmo.

La fortaleza clave del algoritmo A* radica en su exploración sistemática de un gráfico o cuadrícula. A partir de un nodo inicial, busca eficientemente la ruta óptima hacia el nodo objetivo. Esta eficiencia se logra combinando la naturaleza integral del algoritmo de Dijkstra y el enfoque heurístico de Greedy Best-First Search.

La función de costo única del algoritmo A* lo distingue. Al considerar tanto el costo real de llegar a un nodo como una heurística estimada del costo restante, prioriza de manera inteligente los caminos más prometedores. Esta doble consideración agiliza la búsqueda, haciéndola muy precisa y valiosa.

En el siguiente artículo, profundizaremos en ejemplos detallados del algoritmo A* en acción, mostrando su eficacia y versatilidad.

Al mantener un tono formal y utilizar oraciones cortas y concisas, esta versión transmite los puntos clave sobre el algoritmo A* manteniendo un enfoque profesional y técnico.

Descripción general

  • Describe el uso principal de A* en la búsqueda de rutas y el recorrido de gráficos.
  • Explique los componentes de la función de costos: g(n)g(n)g(n), h(n)h(n)h(n) y f(n)f(n)f(n).
  • Identificar y diferenciar entre heurísticas de Manhattan, Euclidiana y Diagonal.
  • Implemente el algoritmo A* en Python para la búsqueda de rutas basada en cuadrículas.
  • Reconocer las aplicaciones de A* en IA, robótica y desarrollo de juegos.

¿Cómo funciona el algoritmo A*?

El algoritmo A* utiliza una combinación de distancias reales y heurísticas para determinar el mejor camino. Aquí están los componentes principales:

  • g(n) : El costo de la ruta desde el nodo inicial hasta el nodo actual nnn.
  • h(n) : una función heurística que estima el costo desde el nodo nnn hasta el objetivo.
  • f(n) : El costo total estimado de la ruta a través del nodo nnn (f(n)=g(n)+h(n)f(n) = g(n) + h(n)f(n)=g (n)+h(n)).

Algoritmo A*: Guía paso a paso

Inicialización

  • Cree una lista abierta para rastrear nodos para su evaluación.
  • Hacer una lista cerrada de los nodos que han sido evaluados.
  • Agregue el nodo de inicio a la lista abierta, marcando el comienzo de su camino.

Bucle principal

  • Continúe hasta que la lista abierta esté vacía o se alcance el objetivo:
    • Seleccione el nodo con el valor f(x) más bajo, lo que indica la ruta más prometedora.
    • Mueva el nodo seleccionado de la lista abierta a la lista cerrada.
    • Examine cada vecino del nodo seleccionado para determinar los próximos pasos.

Evaluación de vecinos

  • Para cada vecino:
    • Si es el objetivo, reconstruye el camino y devuélvelo como solución.
    • Omita a los vecinos que ya estén en la lista cerrada, ya que han sido evaluados.
  • Si un vecino no está en la lista abierta:
    • Súmalo y calcula sus valores g(x), h(x) y f(x).
  • Para los vecinos que ya están en la lista abierta:
    • Compruebe si la nueva ruta es más eficiente (valor g(x) más bajo).
    • Si es así, actualice los valores de g(x), h(x) y f(x) y establezca el nodo actual como su padre.

Heurística en A*

La heurística se utiliza para estimar la distancia desde el nodo actual hasta el objetivo. Las heurísticas comunes incluyen:

  • Distancia Manhattan: Se utiliza cuando los movimientos están restringidos a direcciones horizontales y verticales.

image

Distancia Euclidiana: Se utiliza cuando los movimientos pueden ser en cualquier dirección.

image

Distancia Diagonal: Se utiliza cuando los movimientos pueden ser en ocho direcciones posibles (como un rey en el ajedrez).

image

Implementación del algoritmo A* en Python

Ahora, veamos cómo implementar el algoritmo A* en Python. Definiremos un mapa simple basado en una cuadrícula donde 0 representa celdas transitables y 1 representa obstáculos.

Código:

import heapq

import math

class Node:

    def __init__(self, position, parent=None):

        self.position = position

        self.parent = parent

        self.g = 0  # Distance from start node

        self.h = 0  # Heuristic to goal

        self.f = 0  # Total cost

    def __eq__(self, other):

        return self.position == other.position

    def __lt__(self, other):

        return self.f < other.f

    def __repr__(self):

        return f"({self.position}, f: {self.f})"

def heuristic(a, b):

    return math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2)

def astar(maze, start, end):

    open_list = []

    closed_list = set()

    start_node = Node(start)

    end_node = Node(end)

    heapq.heappush(open_list, start_node)

    while open_list:

        current_node = heapq.heappop(open_list)

        closed_list.add(current_node.position)

        if current_node == end_node:

            path = []

            while current_node:

                path.append(current_node.position)

                current_node = current_node.parent

            return path[::-1]

        for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0), (-1, -1), (-1, 1), (1, -1), (1, 1)]:

            node_position = (current_node.position[0] + new_position[0], current_node.position[1] + new_position[1])

            if node_position[0] > (len(maze) - 1) or node_position[0] < 0 or node_position[1] > (len(maze[len(maze)-1]) - 1) or node_position[1] < 0:

                continue

            if maze[node_position[0]][node_position[1]] != 0:

                continue

            new_node = Node(node_position, current_node)

            if new_node.position in closed_list:

                continue

            new_node.g = current_node.g + 1

            new_node.h = heuristic(new_node.position, end_node.position)

            new_node.f = new_node.g + new_node.h

            if add_to_open(open_list, new_node):

                heapq.heappush(open_list, new_node)

    return None

def add_to_open(open_list, neighbor):

    for node in open_list:

        if neighbor == node and neighbor.g > node.g:

            return False

    return True

maze = [

    [0, 1, 0, 0, 0, 0, 0],

    [0, 1, 0, 1, 1, 1, 0],

    [0, 0, 0, 0, 0, 0, 0],

    [0, 1, 1, 1, 1, 1, 0],

    [0, 0, 0, 0, 0, 0, 0]

]

start = (0, 0)

end = (4, 6)

path = astar(maze, start, end)

print(path)

Producción: [(0, 0), (1, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 6), ( 4, 6)]

image

Explicación del resultado

Esta ruta representa la secuencia de pasos desde el punto inicial (0, 0) hasta el punto final (4, 6). Aquí hay una explicación detallada paso a paso del recorrido:

  • Comienza en (0, 0): esta es la posición inicial en la esquina superior izquierda del laberinto.
  • Mover a (1, 0): Bajar un paso a la primera fila.
  • Mover a (2, 1): Mueve un paso hacia abajo y un paso hacia la derecha, evitando el obstáculo en (1, 1).
  • Mover a (2, 2): Mover un paso a la derecha.
  • Mover a (2, 3): Mover un paso a la derecha.
  • Mover a (2, 4): Mover un paso a la derecha.
  • Mover a (2, 5): Mover un paso a la derecha.
  • Mover a (3, 6): Muévete en diagonal hacia abajo a la derecha, saltando los obstáculos y llegando a la penúltima columna de la tercera fila.

Mover a (4, 6): Bajar un paso para alcanzar la posición objetivo.


Conclusión

Esta guía proporciona una descripción general completa de la funcionalidad del algoritmo A* junto con la implementación del código.

El algoritmo A* es una herramienta valiosa que simplifica problemas complejos y ofrece un enfoque estratégico y eficiente para encontrar soluciones óptimas. Espero que este artículo le resulte útil para comprender este algoritmo de Python.

Vistas: 34