Respuesta A: OpenAI GPT-5 mini
def resolve(requirements, package_index): """ Resuelve las versiones de los paquetes dadas las dependencias iniciales y un índice de paquetes. requirements: lista de cadenas de requisitos como "A>=1.2.0" o "B" package_index: diccionario de paquete -> { version_str: [cadenas de requisitos de dependencia] } Devuelve: diccionario que mapea paquete -> cadena de versión resuelta Lanza ValueError en caso de conflicto con explicación. """ import copy import re OPS = ["==", "!=", ">=", "<=", ">", "<"] def parse_version(v): # Analiza la versión semántica en una tupla...
Mostrar respuesta completa ▼
def resolve(requirements, package_index): """ Resuelve las versiones de los paquetes dadas las dependencias iniciales y un índice de paquetes. requirements: lista de cadenas de requisitos como "A>=1.2.0" o "B" package_index: diccionario de paquete -> { version_str: [cadenas de requisitos de dependencia] } Devuelve: diccionario que mapea paquete -> cadena de versión resuelta Lanza ValueError en caso de conflicto con explicación. """ import copy import re OPS = ["==", "!=", ">=", "<=", ">", "<"] def parse_version(v): # Analiza la versión semántica en una tupla de enteros (mayor, menor, parche, ...) parts = tuple(int(p) for p in v.split('.')) return parts def version_cmp_key(v): return parse_version(v) def parse_requirement(req): req = req.strip() # Busca el operador si está presente for op in OPS: if op in req: name, ver = req.split(op, 1) name = name.strip() ver = ver.strip() return name, op, ver # Sin operador significa cualquier versión name = req return name.strip(), None, None def satisfies_one(ver_str, op, ver_req_str): if op is None: return True left = parse_version(ver_str) right = parse_version(ver_req_str) if op == '==': return left == right if op == '!=': return left != right if op == '>=': return left >= right if op == '<=': return left <= right if op == '>': return left > right if op == '<': return left < right return False def satisfies_all(ver_str, constraints): # constraints: lista de (op, ver_str) donde op puede ser None return all(satisfies_one(ver_str, op, vreq) for (op, vreq) in constraints) # Construye el diccionario de restricciones inicial: paquete -> lista de (op, ver) constraints = {} def add_constraint(constraints_map, pkg, op, ver): if pkg not in constraints_map: constraints_map[pkg] = [] # Evita restricciones idénticas duplicadas if (op, ver) not in constraints_map[pkg]: constraints_map[pkg].append((op, ver)) # Inicializa desde los requisitos de nivel superior for req in requirements: name, op, ver = parse_requirement(req) if name not in package_index: raise ValueError(f"Paquete '{name}' requerido pero no encontrado en el índice de paquetes") add_constraint(constraints, name, op, ver) # Ayudante para calcular la lista de versiones permitidas para un paquete bajo sus restricciones def allowed_versions(pkg, constraints_map): if pkg not in package_index: raise ValueError(f"Paquete '{pkg}' no encontrado en el índice de paquetes") cons = constraints_map.get(pkg, []) versions = list(package_index[pkg].keys()) # Filtra filtered = [v for v in versions if satisfies_all(v, cons)] # Ordena descendente por versión (la más reciente primero) filtered.sort(key=version_cmp_key, reverse=True) return filtered # Búsqueda con retroceso (backtracking) def search(resolved, constraints_map): # Si cada paquete con restricciones está resuelto, hemos terminado to_resolve = [p for p in constraints_map.keys() if p not in resolved] if not to_resolve: return resolved # Elige el paquete con menos candidatos para minimizar la ramificación candidate_info = [] # lista de (paquete, candidatos) for pkg in to_resolve: try: cand = allowed_versions(pkg, constraints_map) except ValueError as e: # Paquete faltante raise if not cand: # Conflicto: ninguna versión satisface las restricciones para este paquete # Construye una cadena de restricción legible cons = constraints_map.get(pkg, []) cons_str = ", ".join([(op + v) if op else "any" for (op, v) in cons]) raise ValueError(f"Ninguna versión del paquete '{pkg}' satisface las restricciones: {cons_str}") candidate_info.append((pkg, cand)) # ordena por número de candidatos ascendente candidate_info.sort(key=lambda x: len(x[1])) pkg, candidates = candidate_info[0] # Prueba cada candidato (ya el más reciente primero) for ver in candidates: new_resolved = dict(resolved) new_resolved[pkg] = ver # Clona las restricciones para el siguiente nivel new_constraints = copy.deepcopy(constraints_map) # Al establecer pkg=ver, debemos asegurarnos de que las restricciones existentes para pkg se satisfagan if not satisfies_all(ver, new_constraints.get(pkg, [])): # No debería suceder ya que los candidatos fueron filtrados, pero mantenemos la comprobación continue # Agrega sus dependencias a las restricciones deps = package_index[pkg].get(ver, []) conflict = False conflict_msg = None for dep_req in deps: dep_name, dep_op, dep_ver = parse_requirement(dep_req) if dep_name not in package_index: conflict = True conflict_msg = f
Resultado
Votos ganadores
2 / 3
Puntuacion media
Puntuacion total
Comentario general
Implementa un sólido resolvedor de dependencias de backtracking que acumula restricciones por paquete, selecciona las últimas versiones que satisfacen y utiliza una heurística de dominio más pequeño para reducir la ramificación. Maneja dependencias transitivas, paquetes faltantes y muchos conflictos con mensajes razonablemente claros. Las principales debilidades son un análisis de requisitos algo simplista (la detección de operadores mediante búsqueda de subcadenas podría analizar incorrectamente nombres inusuales) y la falta de manejo explícito de ciclos/memoización (aunque aún termina porque resuelve cada paquete una vez).
Ver detalle de evaluacion ▼
Correccion
Peso 35%Resuelve correctamente las dependencias transitivas mediante backtracking mientras acumula todas las restricciones por paquete, y prefiere las últimas versiones ordenando los candidatos de forma descendente. Generalmente detecta restricciones insatisfaciables. Riesgos menores: análisis simplista de requisitos y falta de poda/memoización explícita.
Integridad
Peso 20%Cubre los operadores especificados, dependencias transitivas, paquetes faltantes y requisitos vacíos (devuelve {}). No implementa características avanzadas como memoización o detección explícita de ciclos, pero aún así evita bucles infinitos al resolver cada paquete una vez.
Calidad del codigo
Peso 20%Estructura razonablemente legible con funciones auxiliares y elección heurística del siguiente paquete. Algunas importaciones innecesarias (re sin usar) y el uso de deep-copy pueden ser pesados; la construcción del mensaje de error tiene pequeños detalles por pulir.
Valor practico
Peso 15%Más prácticamente utilizable porque maneja restricciones en evolución y puede encontrar soluciones en casos que requieren backtracking a través de elecciones de paquetes anteriores. Todavía limitado en comparación con los resolvedores de producción (sin memoización, análisis simplista).
Seguimiento de instrucciones
Peso 10%Coincide con la firma de función solicitada, devuelve un diccionario de lockfile, prefiere las últimas versiones y genera ValueError en conflictos con mensajes razonablemente claros.
Puntuacion total
Comentario general
La respuesta A proporciona una solución correcta y bien estructurada utilizando un algoritmo de backtracking. Analiza correctamente los requisitos, maneja las comparaciones de versiones y prioriza las versiones más recientes. Se incluye el manejo de errores para conflictos y paquetes faltantes. Sin embargo, el uso de `copy.deepcopy` para el `constraints_map` en cada llamada recursiva puede generar una sobrecarga de rendimiento significativa para grafos de dependencia complejos, lo que podría limitar su escalabilidad práctica. La función `parse_requirement` también es ligeramente menos robusta que un enfoque basado en expresiones regulares.
Ver detalle de evaluacion ▼
Correccion
Peso 35%La lógica central para resolver dependencias, manejar comparaciones de versiones e identificar conflictos es correcta. Prioriza correctamente las versiones más recientes. El método `parse_requirement` es funcional pero menos robusto que un enfoque basado en expresiones regulares.
Integridad
Peso 20%La solución maneja todos los requisitos especificados, incluidas las dependencias transitivas, los conflictos de versiones y los paquetes faltantes. Genera correctamente `ValueError` para escenarios irresolubles. El mecanismo `deepcopy`, aunque correcto, podría limitar su completitud para grafos de dependencia extremadamente grandes y profundos debido al rendimiento.
Calidad del codigo
Peso 20%El código está generalmente bien estructurado con funciones auxiliares y comentarios claros. Sin embargo, el uso de `copy.deepcopy` para la gestión del estado es una elección de diseño significativa que afecta la eficiencia. `parse_requirement` podría ser más elegante.
Valor practico
Peso 15%La solución proporciona un resolvedor de dependencias funcional. Sin embargo, las implicaciones de rendimiento de `deepcopy` podrían hacerlo menos práctico para escenarios del mundo real con árboles de dependencia muy grandes o complejos, donde la eficiencia es crucial.
Seguimiento de instrucciones
Peso 10%Se siguen todas las instrucciones, incluida la firma de la función, el tipo de retorno, el manejo de errores y el manejo de varios especificadores. Se cumple el requisito de apuntar a un algoritmo eficiente, pero `deepcopy` podría considerarse una ligera desviación de la eficiencia óptima para casos complejos.
Puntuacion total
Comentario general
La respuesta A proporciona un sólido resolvedor de dependencias de backtracking con buena estructura. Utiliza propagación de restricciones manteniendo un mapa de restricciones, implementa la heurística MRV (valores restantes mínimos) para la ordenación de variables que mejora la eficiencia, maneja paquetes faltantes y proporciona mensajes de error informativos. El código utiliza deepcopy para los mapas de restricciones, lo cual es correcto pero ligeramente costoso. Maneja dependencias circulares implícitamente a través del conjunto resuelto. El código está bien documentado con comentarios y tiene una separación limpia de responsabilidades. Un problema menor es que no maneja explícitamente dependencias circulares con un conjunto visitado, pero el diccionario resuelto evita bucles infinitos en la práctica, ya que un paquete una vez resuelto no se volverá a resolver.
Ver detalle de evaluacion ▼
Correccion
Peso 35%La respuesta A resuelve correctamente el ejemplo dado (A>=1.1.0 -> A=1.2.0, C=1.0.0, B=2.5.0) y maneja conflictos mediante backtracking. El enfoque de acumulación de restricciones garantiza que todas las restricciones se comprueben al seleccionar versiones. Genera correctamente ValueError para casos irresolubles y paquetes faltantes.
Integridad
Peso 20%La respuesta A maneja paquetes faltantes, conflictos de versiones, dependencias transitivas y entradas vacías. No maneja explícitamente dependencias circulares con un conjunto visitado, pero evita bucles infinitos a través del diccionario resuelto. Cubre todos los operadores especificados.
Calidad del codigo
Peso 20%La respuesta A tiene una separación limpia de responsabilidades con funciones auxiliares bien nombradas. El enfoque del mapa de restricciones es elegante y la heurística MRV muestra sofisticación algorítmica. Los comentarios son útiles. El uso de deepcopy es correcto pero podría optimizarse. El código está bien estructurado en general.
Valor practico
Peso 15%La heurística MRV de la respuesta A y el enfoque de propagación de restricciones funcionarían mejor en grafos de dependencias del mundo real con muchos paquetes. El modelo de acumulación de restricciones está más cerca de cómo funcionan los resolvedores de dependencias reales. El sobrecoste de deepcopy podría ser una preocupación para árboles de dependencias muy grandes.
Seguimiento de instrucciones
Peso 10%La respuesta A sigue todas las instrucciones: devuelve un diccionario que mapea nombres de paquetes a versiones, genera ValueError con mensajes claros, maneja todos los operadores especificados, apunta a las últimas versiones (ordena descendente) y maneja dependencias transitivas.