Sistema de IA Híbrido
Desafío: Crear enemigos inteligentes que sean desafiantes pero predecibles.
Solución de IA: Sistema híbrido que combina lógica basada en reglas con validación Q-Learning.
def barrel_movement(self, platforms, player_rect=None):
"""IA Híbrida: Decisiones primarias basadas en reglas con validación Q-Learning"""
if not player_rect or not platforms:
self.velocity_x = self.speed * self.direction
return
# PASO 1: Decisión primaria basada en reglas
dx = player_rect.centerx - self.rect.centerx
dy = player_rect.centery - self.rect.centery
primary_action = self.decide_primary_action(dx, dy, current_platform, player_platform)
# PASO 2: Validación y mejora con Q-Learning
if hasattr(self, 'ai_agent'):
state = self.get_state(player_rect)
q_action = self.ai_agent.choose_action(state)
# Anular solo en situaciones específicas
if self.should_override_action(primary_action, q_action, dx, dy):
primary_action = q_action
# Aprender de la acción tomada
reward = self.calculate_reward(player_rect)
next_state = self.get_state(player_rect)
self.ai_agent.learn(state, primary_action, reward, next_state, not self.active)
# PASO 3: Ejecutar la acción decidida
self.execute_action_decision(primary_action, current_platform, dx)
Por qué esto es Innovador:
- Lo mejor de ambos mundos: Comportamiento base predecible con mejoras adaptativas
- Aprendizaje contextual: Q-Learning solo anula cuando tiene alta confianza
- Experiencia del jugador: Mantiene la sensación del juego mientras agrega inteligencia
- Amigable para debugging: El núcleo basado en reglas es fácil de entender y modificar
Carga Dinámica de Assets
Desafío: Assets que no cargan en ejecutables empaquetados debido a diferencias de rutas.
Solución de IA: Resolución dinámica de rutas que funciona tanto en desarrollo como en producción.
def load_sprites(self):
"""Carga dinámica de assets para desarrollo y ejecutables empaquetados"""
sprites = {'idle': [], 'jump': []}
# PASO 1: Determinar la ruta base correcta
if hasattr(sys, '_MEIPASS'):
# Ejecutable empaquetado con PyInstaller
base_path = sys._MEIPASS
print("Cargando assets desde ejecutable empaquetado")
else:
# Entorno de desarrollo
base_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
print("Cargando assets desde directorio de desarrollo")
# PASO 2: Cargar sprites con manejo comprensivo de errores
for i in range(1, 12):
sprite_path = os.path.join(base_path, 'assets', 'player', f'sprite_{i:02d}.png')
if os.path.exists(sprite_path):
try:
sprite = pygame.image.load(sprite_path)
sprite = pygame.transform.scale(sprite, (self.rect.width, self.rect.height))
sprites['jump'].append(sprite)
print(f"✓ Sprite cargado: sprite_{i:02d}.png")
except Exception as e:
print(f"✗ Error cargando sprite {sprite_path}: {e}")
# Continuar cargando otros sprites
else:
print(f"⚠ Sprite no encontrado: {sprite_path}")
return sprites if any(sprites.values()) else None
def load_asset_safely(self, asset_path, default_size=(32, 32)):
"""Carga segura de assets con fallback"""
try:
if os.path.exists(asset_path):
asset = pygame.image.load(asset_path)
return pygame.transform.scale(asset, default_size)
except Exception as e:
print(f"Falló la carga de asset para {asset_path}: {e}")
# Retornar rectángulo coloreado como fallback
surface = pygame.Surface(default_size)
surface.fill((255, 0, 255)) # Magenta para assets faltantes
return surface
Por qué esto es Innovador:
- Compatibilidad universal: Funciona en desarrollo y ejecutables empaquetados
- Degradación elegante: Continúa funcionando incluso con assets faltantes
- Logging detallado: Proporciona retroalimentación clara sobre el estado de carga de assets
- Sistema de fallback: Nunca crashea debido a assets faltantes
Spawn Inteligente de Enemigos
Desafío: Equilibrar la dificultad de enemigos sin abrumar al jugador.
Solución de IA: Sistema de spawn adaptativo que escala con el tiempo y rendimiento del jugador.
def spawn_entities(self):
"""Spawn inteligente de entidades con dificultad adaptativa"""
self.spawn_timer += 1
# SPAWN ADAPTATIVO DE BARRILES
self.spawn_barrels_adaptively()
# SPAWN GRADUAL DE MONSTRUOS
self.spawn_monsters_gradually()
def spawn_barrels_adaptively(self):
"""Spawn de barriles con dificultad creciente en el tiempo"""
barrel_count = len([e for e in self.enemies if e.enemy_type == "barrel"])
# Calcular máximo de barriles basado en tiempo jugado
time_factor = self.spawn_timer // 3600 # Cada 60 segundos
max_barrels = min(1 + time_factor, 3) # Máximo 3 barriles
# Calcular tasa de spawn (aumenta con el tiempo)
current_spawn_rate = min(
self.base_spawn_rate + (time_factor * self.spawn_rate_increase),
self.max_spawn_rate
)
# Spawn si está bajo el límite y pasa la verificación de probabilidad
if barrel_count < max_barrels and random.random() < current_spawn_rate:
self.spawn_barrel()
print(f"Barril spawneado (Tasa: {current_spawn_rate:.3f}, Cantidad: {barrel_count + 1}/{max_barrels})")
Por qué esto es Innovador:
- Dificultad adaptativa: La tasa de spawn aumenta con el tiempo jugado
- Posicionamiento estratégico: Los enemigos aparecen lejos del jugador para mejor desafío
- Progresión equilibrada: El aumento gradual previene abrumar
- Monitoreo de rendimiento: Estadísticas integradas para ajustes
Q-Learning sin NumPy
Desafío: Conflictos de PyInstaller con NumPy causando errores de empaquetado.
Solución de IA: Implementación de Q-Learning usando solo Python estándar.
class SimpleArray:
"""Reemplazo simple de NumPy para empaquetado"""
def __init__(self, data):
self.data = data if isinstance(data, list) else [data]
def argmax(self):
"""Encuentra el índice del valor máximo"""
if not self.data:
return 0
max_val = max(self.data)
return self.data.index(max_val)
def zeros(self, shape):
"""Crea array de ceros"""
if isinstance(shape, int):
return [0.0] * shape
return [[0.0] * shape[1] for _ in range(shape[0])]
class QLearningAgent:
def __init__(self, state_size, action_size, learning_rate=0.1):
self.state_size = state_size
self.action_size = action_size
self.learning_rate = learning_rate
self.discount_factor = 0.95
self.epsilon = 0.1
self.q_table = {}
def choose_action(self, state):
"""Selección de acción epsilon-greedy sin NumPy"""
state_key = self.get_state_key(state)
if random.random() < self.epsilon:
return random.randint(0, self.action_size - 1)
if state_key not in self.q_table:
self.q_table[state_key] = [0.0] * self.action_size
# Usar implementación manual de argmax
q_values = self.q_table[state_key]
max_value = max(q_values)
return q_values.index(max_value)
Por qué esto es Innovador:
- Solución de compatibilidad: Elimina conflictos de dependencias de PyInstaller
- Rendimiento mantenido: Funcionalidad completa sin bibliotecas externas
- Simplicidad: Más fácil de debuggear y entender
- Portabilidad: Funciona en cualquier instalación de Python
Conclusión
Estos ejemplos demuestran cómo la IA puede generar código sofisticado y listo para producción que maneja la complejidad del mundo real y casos edge de manera efectiva. Las soluciones van más allá de la funcionalidad básica para incluir:
- Manejo robusto de errores
- Degradación elegante
- Adaptabilidad inteligente
- Compatibilidad multiplataforma
- Experiencia de usuario optimizada
La clave está en proporcionar contexto rico y requerimientos específicos a la IA, permitiéndole generar soluciones que no solo funcionan, sino que son mantenibles, extensibles y profesionales.