Respuesta A: Anthropic Claude Fable 5
Planificador de tareas basado en dependencias.
Produce un plan de ejecución como una lista de lotes (listas de IDs de tareas),
donde cada tarea en un lote puede ejecutarse de forma concurrente, y los lotes deben ejecutarse secuencialmente.
Utiliza el algoritmo de Kahn (ordenación topológica nivel por nivel).
Genera ValueError en caso de:
- IDs de tareas duplicados,
- dependencias que hagan referencia a IDs de tareas desconocidos,
- dependencias circulares (con las tareas infractoras listadas).
from collections import deque
from typing import Dict, List
class TaskScheduler:
"""Planifica tareas en lo...
Mostrar respuesta completa ▼
Planificador de tareas basado en dependencias.
Produce un plan de ejecución como una lista de lotes (listas de IDs de tareas),
donde cada tarea en un lote puede ejecutarse de forma concurrente, y los lotes deben ejecutarse secuencialmente.
Utiliza el algoritmo de Kahn (ordenación topológica nivel por nivel).
Genera ValueError en caso de:
- IDs de tareas duplicados,
- dependencias que hagan referencia a IDs de tareas desconocidos,
- dependencias circulares (con las tareas infractoras listadas).
from collections import deque
from typing import Dict, List
class TaskScheduler:
"""Planifica tareas en lotes paralelizados basándose en dependencias."""
def __init__(self, tasks: List[dict]):
self.tasks = tasks
self._validate_and_build_graph()
def _validate_and_build_graph(self) -> None:
# Recopila todos los IDs de tareas y comprueba duplicados.
self.task_ids = set()
for task in self.tasks:
if 'id' not in task:
raise ValueError(f"La tarea carece de la clave 'id' requerida: {task!r}")
task_id = task['id']
if task_id in self.task_ids:
raise ValueError(f"Se encontró un ID de tarea duplicado: '{task_id}'")
self.task_ids.add(task_id)
# Construye la lista de adyacencia (dependencia -> dependientes) y el mapa de grado de entrada.
self.dependents: Dict[str, List[str]] = {tid: [] for tid in self.task_ids}
self.in_degree: Dict[str, int] = {tid: 0 for tid in self.task_ids}
for task in self.tasks:
task_id = task['id']
for dep in task.get('dependencies') or []:
if dep not in self.task_ids:
raise ValueError(
f"La tarea '{task_id}' depende de un ID de tarea desconocido '{dep}'"
)
if dep == task_id:
raise ValueError(
f"La tarea '{task_id}' depende de sí misma (dependencia circular)"
)
self.dependents[dep].append(task_id)
self.in_degree[task_id] += 1
def schedule(self) -> List[List[str]]:
"""
Devuelve el plan de ejecución como una lista de lotes.
Cada lote es una lista de IDs de tareas que se pueden ejecutar de forma concurrente.
Los lotes deben ejecutarse en el orden devuelto.
"""
in_degree = dict(self.in_degree) # trabaja sobre una copia
current_batch = deque(
tid for tid in in_degree if in_degree[tid] == 0
)
plan: List[List[str]] = []
scheduled_count = 0
while current_batch:
batch = sorted(current_batch) # salida determinista (el orden es arbitrario)
plan.append(batch)
scheduled_count += len(batch)
next_batch = deque()
for task_id in batch:
for dependent in self.dependents[task_id]:
in_degree[dependent] -= 1
if in_degree[dependent] == 0:
next_batch.append(dependent)
current_batch = next_batch
if scheduled_count != len(self.task_ids):
unresolved = sorted(
tid for tid in in_degree if in_degree[tid] > 0
)
raise ValueError(
"Se detectó una dependencia circular que involucra a las tareas: "
+ ", ".join(f"'{t}'" for t in unresolved)
)
return plan
def schedule_tasks(tasks: List[dict]) -> List[List[str]]:
"""
Función de conveniencia: planifica una lista de diccionarios de tareas.
Args:
tasks: Lista de diccionarios, cada uno con las claves 'id' (str),
opcionalmente 'name' (str), y 'dependencies' (lista de strings de IDs de tareas).
Returns:
Una lista de listas de IDs de tareas. Cada lista interna es un lote de tareas
que se pueden ejecutar en paralelo; los lotes se ejecutan secuencialmente en orden.
Raises:
ValueError: Si una dependencia hace referencia a un ID de tarea inexistente, si
existe una dependencia circular, o si los IDs de las tareas están duplicados.
"""
return TaskScheduler(tasks).schedule()
if name == 'main':
# Ejemplo 1
tasks = [
{'id': 'A', 'name': 'Data Ingestion', 'dependencies': []},
{'id': 'B', 'name': 'Data Cleaning', 'dependencies': ['A']},
{'id': 'C', 'name': 'Feature Engineering', 'dependencies': ['A']},
{'id': 'D', 'name': 'Model Training', 'dependencies': ['B', 'C']},
{'id': 'E', 'name': 'Setup Logging', 'dependencies': []},
{'id': 'F', 'name': 'Model Deployment', 'dependencies': ['D']},
]
print(schedule_tasks(tasks))
# -> [['A', 'E'], ['B', 'C'], ['D'], ['F']]
# Ejemplo 2
pipeline = [
{'id': 'checkout', 'dependencies': []},
{'id': 'build', 'dependencies': ['checkout']},
{'id': 'unit_test', 'dependencies': ['build']},
{'id': 'integration_test', 'dependencies': ['build']},
{'id': 'deploy', 'dependencies': ['unit_test', 'integration_test']},
]
print(schedule_tasks(pipeline))
# -> [['checkout'], ['build'], ['integration_test', 'unit_test'], ['deploy']]
# Ejemplo 3: dependencia circular genera ValueError
cyclic = [
{'id': 'X', 'dependencies': ['Y']},
{'id': 'Y', 'dependencies': ['X']},
]
try:
schedule_tasks(cyclic)
except ValueError as e:
print(f"ValueError: {e}")
# Ejemplo 4: dependencia desconocida genera ValueError
broken = [
{'id': 'A', 'dependencies': ['missing_task']},
]
try:
schedule_tasks(broken)
except ValueError as e:
print(f"ValueError: {e}")
Resultado
Votos ganadores
2 / 3
Puntuacion media
Puntuacion total
Comentario general
La respuesta A es funcionalmente correcta, utiliza el algoritmo de Kahn con una ordenación topológica limpia nivel por nivel (por lotes). Valida IDs duplicados, dependencias desconocidas y bucles de auto-dependencia, y detecta ciclos mediante la comprobación del recuento de tareas programadas, generando `ValueError` descriptivos que incluso listan las tareas problemáticas. Puntos fuertes notables: construye el grafo en tiempo de construcción (por lo que los errores de dependencia desconocida se detectan de forma temprana), produce resultados deterministas mediante la ordenación, incluye docstrings exhaustivos, anotaciones de tipo y un conjunto completo de ejemplos ejecutables que cubren casos válidos e inválidos (ciclo y dependencia desconocida). También ofrece tanto una API de clase como una función de conveniencia, coincidiendo con la flexibilidad de la solicitud. Puntos débiles menores: ordenar cada lote es una pequeña sobrecarga (y no solicitada), y la comprobación explícita de auto-dependencia es ligeramente redundante dado el detector de ciclos, pero ninguna de las dos es perjudicial.
Ver detalle de evaluacion ▼
Correccion
Peso 35%Implementa correctamente el algoritmo de Kahn nivel por nivel; los horarios válidos coinciden con los resultados esperados, los ciclos y las dependencias desconocidas generan `ValueError`, y la comprobación de ciclos mediante `scheduled_count` es sólida. Los lotes ordenados garantizan resultados correctos y deterministas.
Integridad
Peso 20%Maneja duplicados, dependencias desconocidas, bucles de auto-dependencia y ciclos; proporciona APIs de clase y función; e incluye cuatro ejemplos ejecutables que cubren horarios válidos más ambos tipos de error, demostrando una cobertura completa.
Calidad del codigo
Peso 20%Estructura de clase limpia con clara separación de validación y programación, buenos docstrings, anotaciones de tipo y mensajes de error informativos. Ligera redundancia en la comprobación explícita de auto-dependencia.
Valor practico
Peso 15%La salida determinista y la validación temprana en la construcción la hacen fiable y fácil de integrar; los ejemplos ejecutables para todas las rutas de código ayudan a la adopción práctica.
Seguimiento de instrucciones
Peso 10%Coincide con el formato de salida requerido, genera `ValueError` para ambos casos de error requeridos con mensajes descriptivos y proporciona una función según lo solicitado; se alinea completamente con la solicitud.
Puntuacion total
Comentario general
La respuesta A es una implementación sólida y mayormente correcta que utiliza el algoritmo de Kahn nivel por nivel, y devuelve lotes paralelizados de forma limpia. Maneja dependencias desconocidas, IDs duplicados y ciclos con errores claros, y el código es legible y está bien estructurado. Su principal debilidad es que realiza menos validación de entrada que la Respuesta B y es ligeramente menos robusta para entradas malformadas más allá de los requisitos centrales del prompt.
Ver detalle de evaluacion ▼
Correccion
Peso 35%Implementa correctamente la ordenación topológica por lotes y detecta dependencias desconocidas y ciclos. También detecta explícitamente la autodependencia. Una limitación menor es que los tipos de campo de dependencia malformados no se validan y podrían llevar a un comportamiento no deseado en lugar de un error claro que preserve el contrato.
Integridad
Peso 20%Cubre todos los comportamientos requeridos e incluso añade manejo de IDs duplicados y ejemplos. Sin embargo, es menos completo en cuanto a la validación de entradas malformadas, como dependencias no listas o IDs no string más allá de la falta de 'id'.
Calidad del codigo
Peso 20%Bien organizado con un diseño de clase claro, método auxiliar, type hints, docstrings y lotes ordenados determinísticamente. La estructura es fácil de seguir y mantener.
Valor practico
Peso 15%Útil en la práctica, especialmente con la ordenación determinista de lotes y errores descriptivos. Es algo menos defensivo contra entradas malformadas, lo que reduce la robustez en contextos de producción.
Seguimiento de instrucciones
Peso 10%Sigue el prompt de cerca: acepta diccionarios de tareas, devuelve lotes de lista de listas y eleva ValueError para ciclos y dependencias faltantes. La implementación y los ejemplos se alinean bien con el tipo de respuesta requerida.
Puntuacion total
Comentario general
La respuesta A proporciona una solución excelente y de calidad profesional. Utiliza un diseño basado en clases bien estructurado que separa limpiamente la construcción y validación del grafo de la lógica de planificación. La implementación del algoritmo de Kahn es correcta y eficiente. El manejo de errores es robusto, cubriendo todos los casos especificados además de otros como IDs de tareas duplicadas. El código está limpio, bien documentado con anotaciones de tipo, e incluye un bloque `if __name__ == '__main__'` completo que sirve como un conjunto de mini-pruebas, demostrando tanto la ejecución exitosa como el manejo de errores.
Ver detalle de evaluacion ▼
Correccion
Peso 35%La implementación del algoritmo de Kahn es impecable. Identifica correctamente lotes de tareas paralelizable y respeta todas las dependencias, produciendo la salida correcta para los ejemplos dados.
Integridad
Peso 20%La solución maneja correctamente todos los requisitos especificados, incluida la detección de dependencias circulares y dependencias inexistentes. También añade comprobaciones útiles para IDs de tareas duplicadas y auto-dependencias.
Calidad del codigo
Peso 20%La calidad del código es excelente. El diseño basado en clases proporciona una gran estructura y separación de responsabilidades. El código está limpio, es legible, está bien documentado y utiliza anotaciones de tipo de manera efectiva. El bloque `if __name__ == '__main__'` es completo y demuestra la funcionalidad completa del código.
Valor practico
Peso 15%La solución es muy práctica. El diseño basado en clases facilita su reutilización y extensión. Se podría crear una instancia del planificador y su grafo podría ser inspeccionado o reutilizado, lo cual es un requisito común en aplicaciones del mundo real.
Seguimiento de instrucciones
Peso 10%La respuesta sigue perfectamente todas las instrucciones, incluido el formato de entrada/salida, la elección de una función o clase, y los requisitos específicos de manejo de errores.