Los árboles de decisión son una herramienta poderosa en la inteligencia artificial para la toma de decisiones. Se utilizan para modelar decisiones y sus posibles consecuencias, incluyendo resultados, costos y utilidades. En el contexto de los videojuegos, los árboles de decisión pueden ser utilizados para determinar el comportamiento de los personajes no jugables (NPCs), permitiendo que reaccionen de manera lógica y coherente a diferentes situaciones del juego.

Conceptos Básicos

¿Qué es un Árbol de Decisión?

Un árbol de decisión es una estructura de datos en forma de árbol donde cada nodo representa una decisión o una condición, y cada rama representa el resultado de esa decisión o condición. Los nodos terminales, también conocidos como hojas, representan las acciones finales o resultados.

Componentes de un Árbol de Decisión

  1. Nodo Raíz: El nodo inicial del árbol, donde comienza la toma de decisiones.
  2. Nodos Internos: Representan las decisiones o condiciones a evaluar.
  3. Ramas: Conectan los nodos y representan los posibles resultados de las decisiones.
  4. Hojas: Representan las acciones finales o resultados de la secuencia de decisiones.

Ejemplo Básico

Consideremos un ejemplo sencillo de un árbol de decisión para un NPC en un juego de aventuras que decide si atacar, defenderse o huir:

            ¿Enemigo cerca?
               /       \
             Sí         No
            /            \
    ¿Salud > 50%?       Patrullar
       /     \
     Sí       No
    /          \
Atacar       Huir

En este ejemplo:

  • El nodo raíz es "¿Enemigo cerca?".
  • Los nodos internos son "¿Salud > 50%?".
  • Las hojas son "Atacar", "Huir" y "Patrullar".

Implementación de Árboles de Decisión

Estructura de Datos

Para implementar un árbol de decisión en un lenguaje de programación como Python, podemos utilizar clases para representar los nodos y el árbol en su conjunto.

class NodoDecision:
    def __init__(self, pregunta, verdadero_rama=None, falso_rama=None):
        self.pregunta = pregunta
        self.verdadero_rama = verdadero_rama
        self.falso_rama = falso_rama

class Hoja:
    def __init__(self, accion):
        self.accion = accion

Ejemplo de Implementación

Vamos a implementar el árbol de decisión del ejemplo anterior en Python:

class NodoDecision:
    def __init__(self, pregunta, verdadero_rama=None, falso_rama=None):
        self.pregunta = pregunta
        self.verdadero_rama = verdadero_rama
        self.falso_rama = falso_rama

class Hoja:
    def __init__(self, accion):
        self.accion = accion

def construir_arbol():
    # Hojas
    atacar = Hoja("Atacar")
    huir = Hoja("Huir")
    patrullar = Hoja("Patrullar")
    
    # Nodos internos
    salud_nodo = NodoDecision("¿Salud > 50%?", atacar, huir)
    enemigo_nodo = NodoDecision("¿Enemigo cerca?", salud_nodo, patrullar)
    
    return enemigo_nodo

def decidir(nodo, contexto):
    if isinstance(nodo, Hoja):
        return nodo.accion
    
    pregunta = nodo.pregunta
    if evaluar_pregunta(pregunta, contexto):
        return decidir(nodo.verdadero_rama, contexto)
    else:
        return decidir(nodo.falso_rama, contexto)

def evaluar_pregunta(pregunta, contexto):
    if pregunta == "¿Enemigo cerca?":
        return contexto["enemigo_cerca"]
    elif pregunta == "¿Salud > 50%?":
        return contexto["salud"] > 50
    return False

# Construir el árbol de decisión
arbol = construir_arbol()

# Contexto del juego
contexto = {
    "enemigo_cerca": True,
    "salud": 60
}

# Decidir la acción del NPC
accion = decidir(arbol, contexto)
print(f"Acción del NPC: {accion}")

Explicación del Código

  1. Definición de Clases: NodoDecision y Hoja representan los nodos de decisión y las hojas del árbol, respectivamente.
  2. Construcción del Árbol: La función construir_arbol crea el árbol de decisión basado en el ejemplo.
  3. Función de Decisión: La función decidir recorre el árbol de decisión basado en el contexto del juego y devuelve la acción correspondiente.
  4. Evaluación de Preguntas: La función evaluar_pregunta evalúa las condiciones basadas en el contexto del juego.

Ejercicio Práctico

Ejercicio

Implementa un árbol de decisión para un NPC en un juego de carreras que decide si acelerar, frenar o mantener la velocidad según las siguientes condiciones:

  • Si hay una curva cerrada adelante, frenar.
  • Si la velocidad actual es menor que la velocidad máxima permitida, acelerar.
  • En cualquier otro caso, mantener la velocidad.

Solución

class NodoDecision:
    def __init__(self, pregunta, verdadero_rama=None, falso_rama=None):
        self.pregunta = pregunta
        self.verdadero_rama = verdadero_rama
        self.falso_rama = falso_rama

class Hoja:
    def __init__(self, accion):
        self.accion = accion

def construir_arbol():
    # Hojas
    acelerar = Hoja("Acelerar")
    frenar = Hoja("Frenar")
    mantener_velocidad = Hoja("Mantener Velocidad")
    
    # Nodos internos
    velocidad_nodo = NodoDecision("¿Velocidad < Velocidad Máxima?", acelerar, mantener_velocidad)
    curva_nodo = NodoDecision("¿Curva Cerrada Adelante?", frenar, velocidad_nodo)
    
    return curva_nodo

def decidir(nodo, contexto):
    if isinstance(nodo, Hoja):
        return nodo.accion
    
    pregunta = nodo.pregunta
    if evaluar_pregunta(pregunta, contexto):
        return decidir(nodo.verdadero_rama, contexto)
    else:
        return decidir(nodo.falso_rama, contexto)

def evaluar_pregunta(pregunta, contexto):
    if pregunta == "¿Curva Cerrada Adelante?":
        return contexto["curva_cerrada"]
    elif pregunta == "¿Velocidad < Velocidad Máxima?":
        return contexto["velocidad"] < contexto["velocidad_maxima"]
    return False

# Construir el árbol de decisión
arbol = construir_arbol()

# Contexto del juego
contexto = {
    "curva_cerrada": False,
    "velocidad": 80,
    "velocidad_maxima": 100
}

# Decidir la acción del NPC
accion = decidir(arbol, contexto)
print(f"Acción del NPC: {accion}")

Explicación del Código

  1. Definición de Clases: NodoDecision y Hoja representan los nodos de decisión y las hojas del árbol, respectivamente.
  2. Construcción del Árbol: La función construir_arbol crea el árbol de decisión basado en las condiciones del ejercicio.
  3. Función de Decisión: La función decidir recorre el árbol de decisión basado en el contexto del juego y devuelve la acción correspondiente.
  4. Evaluación de Preguntas: La función evaluar_pregunta evalúa las condiciones basadas en el contexto del juego.

Conclusión

Los árboles de decisión son una herramienta esencial para la toma de decisiones en la inteligencia artificial de los videojuegos. Permiten modelar comportamientos complejos de manera estructurada y lógica. En esta sección, hemos aprendido los conceptos básicos de los árboles de decisión, cómo implementarlos y cómo utilizarlos para determinar las acciones de los NPCs en diferentes contextos del juego.

En la próxima sección, exploraremos los Behavior Trees, una técnica más avanzada y flexible para la toma de decisiones en videojuegos.

© Copyright 2024. Todos los derechos reservados