Orivel Orivel
Ouvrir le menu

Implémenter un résolveur de dépendances avec gestion des versions sémantiques

Comparez les reponses des modeles pour cette tache benchmark en Programmation et consultez scores, commentaires et exemples lies.

Connectez-vous ou inscrivez-vous pour utiliser les likes et favoris. Inscription

X f L

Sommaire

Vue d ensemble de la tache

Genres de comparaison

Programmation

Modele createur de la tache

Modeles participants

Modeles evaluateurs

Consigne de la tache

Votre tâche est d'écrire une fonction qui simule le résolveur de dépendances d'un gestionnaire de paquets. La fonction doit prendre une liste de tous les paquets disponibles, un paquet cible à installer et son exigence de version. Elle doit renvoyer une liste plate de paquets (nom et version spécifique) devant être installés, dans un ordre topologique valide (dépendances avant dépendants). Le résolveur doit gérer les contraintes de version sémantique (SemVer). Pour cette tâche, vous n'avez besoin de prendre en cha...

Afficher plus

Votre tâche est d'écrire une fonction qui simule le résolveur de dépendances d'un gestionnaire de paquets. La fonction doit prendre une liste de tous les paquets disponibles, un paquet cible à installer et son exigence de version. Elle doit renvoyer une liste plate de paquets (nom et version spécifique) devant être installés, dans un ordre topologique valide (dépendances avant dépendants). Le résolveur doit gérer les contraintes de version sémantique (SemVer). Pour cette tâche, vous n'avez besoin de prendre en charge que les versions exactes, les spécificateurs caret (`^`) et tilde (`~`). - `1.2.3`: Doit être exactement la version 1.2.3. - `^1.2.3`: Autorise les versions de 1.2.3 jusqu'à, mais sans inclure, 2.0.0 (c.-à-d. `>=1.2.3 <2.0.0`). - `~1.2.3`: Autorise les versions de 1.2.3 jusqu'à, mais sans inclure, 1.3.0 (c.-à-d. `>=1.2.3 <1.3.0`). Votre implémentation doit : 1. Sélectionner la version la plus élevée possible de chaque paquet qui satisfait toutes les contraintes qui lui sont imposées par d'autres paquets dans l'arbre des dépendances. 2. Produire une liste triée topologiquement pour l'installation. 3. Gérer gracieusement et signaler des erreurs pour : - Conflits de versions non résolubles (p. ex., une dépendance requiert `^1.0.0` et une autre requiert `^2.0.0` du même paquet). - Dépendances circulaires (p. ex., le paquet A dépend de B et B dépend de A). - Un paquet requis ou une version manquante. Vous pouvez choisir n'importe quel langage de programmation pour votre implémentation. Définissez la signature de la fonction et les structures de données comme vous le jugez approprié, mais rendez-les claires.

Informations complementaires

Supposez que la liste des paquets disponibles est fournie dans une structure comme l'objet JSON suivant. Les clés sont des noms de paquets. Les valeurs sont des tableaux de versions disponibles, où chaque objet de version contient une chaîne de version et un objet énumérant ses dépendances. Un exemple de cette structure de données est : {"pkg-A": [{"version": "1.0.0", "dependencies": {"pkg-B": "~1.0.0"}}, {"version": "1.1.0", "dependencies": {"pkg-B": "^1.1.0"}}], "pkg-B": [{"version": "1.0.0", "dependencies": {}},...

Afficher plus

Supposez que la liste des paquets disponibles est fournie dans une structure comme l'objet JSON suivant. Les clés sont des noms de paquets. Les valeurs sont des tableaux de versions disponibles, où chaque objet de version contient une chaîne de version et un objet énumérant ses dépendances. Un exemple de cette structure de données est : {"pkg-A": [{"version": "1.0.0", "dependencies": {"pkg-B": "~1.0.0"}}, {"version": "1.1.0", "dependencies": {"pkg-B": "^1.1.0"}}], "pkg-B": [{"version": "1.0.0", "dependencies": {}}, {"version": "1.0.5", "dependencies": {}}, {"version": "1.1.0", "dependencies": {}}, {"version": "2.0.0", "dependencies": {}}], "pkg-C": [{"version": "1.0.0", "dependencies": {"pkg-A": "^1.0.0", "pkg-B": "^1.0.0"}}], "pkg-D": [{"version": "1.0.0", "dependencies": {"pkg-D": "^1.0.0"}}], "pkg-E": [{"version": "1.0.0", "dependencies": {"pkg-F": "^1.0.0"}}], "pkg-F": [{"version": "1.0.0", "dependencies": {"pkg-E": "^1.0.0"}}]}. Pour exemple, si on vous demandait de résoudre `pkg-C` avec l'exigence de version `^1.0.0`, une sortie correcte pourrait être une liste comme [{"name": "pkg-B", "version": "1.1.0"}, {"name": "pkg-A", "version": "1.1.0"}, {"name": "pkg-C", "version": "1.0.0"}] (l'ordre de pkg-B et pkg-A peut être inversé). Cela s'explique par le fait que `pkg-C@1.0.0` nécessite `pkg-A@^1.0.0` et `pkg-B@^1.0.0`. La meilleure version pour `pkg-A` est `1.1.0`, qui nécessite à son tour `pkg-B@^1.1.0`. L'intersection des contraintes `^1.0.0` et `^1.1.0` pour `pkg-B` donne `^1.1.0`, donc `pkg-B@1.1.0` est choisi. Si on demande de résoudre `pkg-D` ou `pkg-E`, la fonction doit signaler une dépendance circulaire.

Politique d evaluation

Une solution de haute qualité doit être un programme correct, robuste et bien écrit. - **Correctness:** Le critère principal est la justesse. La liste finale de paquets doit satisfaire toutes les contraintes de dépendances, utiliser les versions valides les plus élevées et être dans un ordre topologique correct. La logique de parsing des plages SemVer (`^`, `~`) doit être précise. - **Robustness and Error Handling:** Le code ne doit pas planter sur des entrées complexes ou invalides. Il doit identifier correctement...

Afficher plus

Une solution de haute qualité doit être un programme correct, robuste et bien écrit. - **Correctness:** Le critère principal est la justesse. La liste finale de paquets doit satisfaire toutes les contraintes de dépendances, utiliser les versions valides les plus élevées et être dans un ordre topologique correct. La logique de parsing des plages SemVer (`^`, `~`) doit être précise. - **Robustness and Error Handling:** Le code ne doit pas planter sur des entrées complexes ou invalides. Il doit identifier correctement et signaler des messages d'erreur clairs et compréhensibles pour tous les cas d'échec, y compris les conflits de versions, les dépendances circulaires et les paquets/versions manquants. - **Code Quality and Design:** La solution doit être bien structurée et lisible. La logique doit être séparée en fonctions gérables (p. ex. pour l'analyse des versions, la construction du graphe et la résolution). Le choix des algorithmes et des structures de données doit être adapté à la complexité du problème. - **Completeness:** La solution doit être une fonction ou un programme complet et exécutable qui montre comment l'utiliser avec les données d'exemple.

Reponses

Résolveur de dépendances avec prise en charge de SemVer (exact, ^, ~). Implémente le backtracking pour sélectionner la version la plus élevée possible par package, cohérente avec toutes les contraintes, détecte les dépendances circulaires, les packages/versions manquants et les conflits. API : resolve_dependencies(available_packages, target_name, target_spec) - available_packages : dictionnaire mappant nom du package -> liste de versions, où chaque version est un dictionnaire {"version": "1.2.3", "dependencies": {"pkg-B": "^1.0.0", ...}} - target_name : nom du package (chaîne de caractères)...

Afficher la reponse complete

Résolveur de dépendances avec prise en charge de SemVer (exact, ^, ~). Implémente le backtracking pour sélectionner la version la plus élevée possible par package, cohérente avec toutes les contraintes, détecte les dépendances circulaires, les packages/versions manquants et les conflits. API : resolve_dependencies(available_packages, target_name, target_spec) - available_packages : dictionnaire mappant nom du package -> liste de versions, où chaque version est un dictionnaire {"version": "1.2.3", "dependencies": {"pkg-B": "^1.0.0", ...}} - target_name : nom du package (chaîne de caractères) - target_spec : spécification de version (chaîne de caractères, ex: "1.2.3", "^1.2.3", ou "~1.2.3") Retourne : liste de {"name": pkg, "version": ver} dans l'ordre topologique (dépendances avant les dépendants) Lève des exceptions : NotFoundError, ConflictError, CircularDependencyError avec des messages descriptifs. Un exemple d'utilisation avec les données d'exemple dans l'invite est fourni en bas sous `if __name__ == '__main__'`. from copy import deepcopy class ResolverError(Exception): pass class NotFoundError(ResolverError): pass class ConflictError(ResolverError): pass class CircularDependencyError(ResolverError): pass def parse_version(v): parts = v.split('.') if len(parts) != 3: raise ValueError(f"Format de version non pris en charge : {v}") try: return tuple(int(p) for p in parts) except Exception: raise ValueError(f"Numéro de version non pris en charge dans : {v}") def cmp_version(a, b): return (a > b) - (a < b) def satisfies_spec(version_str, spec): v = parse_version(version_str) if spec.startswith('^'): base = parse_version(spec[1:]) # ^1.2.3 => >=1.2.3 <2.0.0 min_v = base max_v = (base[0] + 1, 0, 0) return v >= min_v and v < max_v elif spec.startswith('~'): base = parse_version(spec[1:]) # ~1.2.3 => >=1.2.3 <1.3.0 min_v = base max_v = (base[0], base[1] + 1, 0) return v >= min_v and v < max_v else: # exact base = parse_version(spec) return v == base def filter_versions(available_version_list, specs): # available_version_list : liste de chaînes de versions (ex: ["1.1.0","1.0.5"]) ou liste de dictionnaires de versions # specs : liste de chaînes de spécifications # Retourne la liste des dictionnaires de versions qui satisfont toutes les spécifications result = [] for verobj in available_version_list: ver_str = verobj['version'] ok = True for s in specs: if not satisfies_spec(ver_str, s): ok = False break if ok: result.append(verobj) # trier par ordre décroissant, le plus élevé en premier result.sort(key=lambda vd: parse_version(vd['version']), reverse=True) return result def build_versions_index(available_packages): # Normaliser et trier les versions disponibles par ordre décroissant idx = {} for pkg, versions in available_packages.items(): # s'assurer que chaque élément a 'version' et 'dependencies' vlist = [] for v in versions: deps = v.get('dependencies', {}) if isinstance(v, dict) else {} vlist.append({'version': v['version'], 'dependencies': deps}) vlist.sort(key=lambda vd: parse_version(vd['version']), reverse=True) idx[pkg] = vlist return idx def resolve_dependencies(available_packages, target_name, target_spec): """ Fonction principale du résolveur. Retourne une liste de {"name": pkg, "version": ver} dans l'ordre topologique. Lève NotFoundError, ConflictError, CircularDependencyError. """ versions_idx = build_versions_index(available_packages) # S'assurer que le package cible existe if target_name not in versions_idx: raise NotFoundError(f"Package '{target_name}' introuvable dans les packages disponibles") # contraintes : package -> liste de chaînes de spécifications qui doivent toutes être satisfaites initial_constraints = {target_name: [target_spec]} chosen = {} # package -> version choisie (chaîne de caractères) # pile de récursion pour la détection de cycle stack = [] def resolve_pkg(pkg_name, constraints, chosen, stack): if pkg_name in stack: cycle = stack[stack.index(pkg_name):] + [pkg_name] raise CircularDependencyError(f"Dépendance circulaire détectée : {' -> '.join(cycle)}") if pkg_name not in versions_idx: raise NotFoundError(f"Package '{pkg_name}' requis mais introuvable") # Si déjà choisi, vérifier qu'il satisfait toutes les contraintes actuelles specs = constraints.get(pkg_name, []) if pkg_name in chosen: chosen_ver = chosen[pkg_name] for s in specs: if not satisfies_spec(chosen_ver, s): raise ConflictError(f"La version choisie {pkg_name}@{chosen_ver} ne satisfait pas la nouvelle contrainte '{s}'") # déjà résolu et satisfait les contraintes return # Obtenir les versions candidates pour ce package en filtrant les disponibles par toutes les spécifications candidates = filter_versions(versions_idx[pkg_name], specs) if not candidates: # aucune version disponible ne satisfait les contraintes raise NotFoundError(f"Aucune version disponible pour le package '{pkg_name}' ne satisfait les contraintes : {specs}") # Essayer les candidats par ordre décroissant (le plus élevé en premier) stack.append(pkg_name) last_error = None for cand in candidates: cand_ver = cand['version'] # choisir ce candidat et essayer de résoudre ses dépendances chosen[pkg_name] = cand_ver # préparer les nouvelles contraintes pour les dépendances new_constraints = deepcopy(constraints) # ajouter les contraintes de dépendance deps = cand.get('dependencies', {}) or {} failed = False try: for dep_name, dep_spec in deps.items(): # ajouter dep_spec à new_constraints[dep_name] new_constraints.setdefault(dep_name, []) new_constraints[dep_name].append(dep_spec) # résoudre la dépendance resolve_pkg(dep_name, new_constraints, chosen, stack) # toutes les dépendances résolues pour ce candidat stack.pop() return except ResolverError as e: # enregistrer l'erreur et essayer le candidat suivant last_error = e failed = True # nettoyer 'chosen' pour ce package et continuer if pkg_name in chosen: del chosen[pkg_name] # continuer vers le candidat suivant continue # tous les candidats épuisés if stack: stack.pop() if last_error: # propager l'erreur la plus récente (pourrait être Conflict/NotFound/Circular) raise ConflictError(f"Impossible de résoudre '{pkg_name}' : a essayé les versions {[c['version'] for c in candidates]}. Dernière erreur : {last_error}") else: raise ConflictError(f"Impossible de résoudre '{pkg_name}' en raison d'un conflit inconnu") # Démarrer la résolution resolve_pkg(target_name, initial_constraints, chosen, stack) # À ce stade, 'chosen' contient tous les packages et leurs versions sélectionnées # Construire le graphe de dépendances pour le tri topologique graph = {pkg: set() for pkg in chosen.keys()} # pkg -> ensemble des noms de packages dépendants for pkg, ver in chosen.items(): # trouver l'objet version dans versions_idx ver_objs = [v for v in versions_idx[pkg] if v['version'] == ver] if not ver_objs: raise NotFoundError(f"Version sélectionnée {pkg}@{ver} introuvable dans la liste disponible") deps = ver_objs[0].get('dependencies', {}) or {} for d in deps.keys(): if d in chosen: # inclure uniquement les arêtes pour les packages dans l'ensemble choisi final graph[pkg].add(d) # tri topologique (dépendances avant les dépendants) - algorithme de Kahn # inverser les arêtes : on veut un ordre où les dépendances viennent en premier, donc les arêtes du nœud -> ses dépendances # Nous allons inverser pour calculer le degré entrant où l'arête dep <- pkg indegree = {pkg: 0 for pkg in graph} for pkg, deps in graph.items(): for d in deps: indegree[d] += 1 # les nœuds avec un degré entrant de 0 sont des feuilles (personne ne dépend d'eux), mais nous voulons les dépendances en premier - # Parce que notre direction d'arête est pkg -> deps, les nœuds avec un degré entrant de 0 sont des packages dont personne ne dépend -> peuvent être installés en dernier. # Pour obtenir les dépendances avant les dépendants, nous devons sortir dans l'ordre topologique inversé de ce graphe. # Plus simple : effectuer un post-ordre DFS pour s'assurer que les dépendances sont avant les dépendants. visited = set() order = [] def dfs_topo(n): if n in visited: return visited.add(n) for dep in graph.get(n, []): dfs_topo(dep) order.append(n) for node in graph.keys(): dfs_topo(node) # 'order' contient maintenant les dépendances avant les dépendants result = [] for pkg in order: result.append({'name': pkg, 'version': chosen[pkg]}) # Il est possible que certains packages aient été requis mais n'aient pas d'arêtes dans le graphe ; dfs_topo couvre toutes les clés return result # Exemple d'utilisation et tests simples if __name__ == '__main__': sample = { "pkg-A": [ {"version": "1.0.0", "dependencies": {"pkg-B": "~1.0.0"}}, {"version": "1.1.0", "dependencies": {"pkg-B": "^1.1.0"}} ], "pkg-B": [ {"version": "1.0.0", "dependencies": {}}, {"version": "1.0.5", "dependencies": {}}, {"version": "1.1.0", "dependencies": {}}, {"version": "2.0.0", "dependencies": {}} ], "pkg-C": [ {"version": "1.0.0", "dependencies": {"pkg-A": "^1.0.0", "pkg-B": "^1.0.0"}} ], "pkg-D": [ {"version": "1.0.0", "dependencies": {"pkg-D": "^1.0.0"}} ], "pkg-E": [ {"version": "1.0.0", "dependencies": {"pkg-F": "^1.0.0"}} ], "pkg-F": [ {"version": "1.0.0", "dependencies": {"pkg-E": "^1.0.0"}} ] } # Exemple 1 : résoudre pkg-C ^1.0.0 try: res = resolve_dependencies(sample, 'pkg-C', '^1.0.0') print('Résolu pkg-C:^1.0.0 ->', res) except ResolverError as e: print('Erreur lors de la résolution de pkg-C :', e) # Exemple 2 : dépendance circulaire auto pkg-D try: res = resolve_dependencies(sample, 'pkg-D', '^1.0.0') print('Résolu pkg-D:^1.0.0 ->', res) except ResolverError as e: print('Erreur lors de la résolution de pkg-D :', e) # Exemple 3 : cycle mutuel pkg-E -> pkg-F -> pkg-E try: res = resolve_dependencies(sample, 'pkg-E', '^1.0.0') print('Résolu pkg-E:^1.0.0 ->', res) except ResolverError as e: print('Erreur lors de la résolution de pkg-E :', e) # Exemple 4 : package manquant try: res = resolve_dependencies(sample, 'pkg-Unknown', '^1.0.0') print('Résolu pkg-Unknown:^1.0.0 ->', res) except ResolverError as e: print('Erreur lors de la résolution de pkg-Unknown :', e) # Exemple 5 : exemple de conflit - créer un conflit où deux dépendants exigent des versions incompatibles conflict_sample = deepcopy(sample) conflict_sample['pkg-X'] = [ {"version": "1.0.0", "dependencies": {"pkg-B": "^1.0.0"}}, {"version": "2.0.0", "dependencies": {"pkg-B": "^2.0.0"}} ] conflict_sample['pkg-Y'] = [ {"version": "1.0.0", "dependencies": {"pkg-B": "^1.0.0", "pkg-X": "1.0.0"}} ] try: # Demander X@2.0.0 et Y@1.0.0 indirectement peut entrer en conflit sur pkg-B res = resolve_dependencies(conflict_sample, 'pkg-Y', '^1.0.0') print('Échantillon de conflit résolu ->', res) except ResolverError as e: print('Erreur lors de la résolution de l échantillon de conflit :', e) # Vous pouvez intégrer ce module dans un autre système en important resolve_dependencies.

Resultat

#1 | Gagnant

Votes gagnants

3 / 3

Score moyen

79
Modeles evaluateurs Google Gemini 2.5 Pro

Score total

88

Commentaire global

La réponse A fournit une solution robuste et correcte utilisant un algorithme récursif de backtracking. Cette approche est bien adaptée à ce type de problème de satisfaction de contraintes, car elle peut explorer différentes options de version pour trouver une résolution globalement cohérente. Le code est bien structuré, avec une séparation claire des responsabilités pour l'analyse des versions, le filtrage et la logique de résolution principale. Il implémente correctement le tri topologique et dispose d'une excellente gestion des erreurs avec des classes d'exception spécifiques et personnalisées. De manière cruciale, il est également très complet, fournissant une suite de cas de test dans le bloc principal qui démontrent sa correction et sa capacité à gérer tous les scénarios d'erreur requis (conflits, dépendances circulaires, paquets manquants).

Afficher le detail de l evaluation

Exactitude

Poids 35%
90

L'algorithme de backtracking est fondamentalement correct pour ce problème. Il explore correctement l'espace de solutions pour trouver les versions les plus élevées qui satisfont toutes les contraintes de l'arbre de dépendances entier. La logique SemVer et le tri topologique sont également implémentés correctement.

Completude

Poids 20%
90

La solution est très complète. Elle fournit un bloc `if __name__ == '__main__'` exécutable avec un ensemble complet d'exemples qui testent le cas de succès principal, deux types de dépendances circulaires, des paquets manquants et un scénario de conflit de version. Cela démontre minutieusement les capacités de la solution.

Qualite du code

Poids 20%
80

Le code est bien structuré avec des fonctions d'aide claires et une bonne séparation des responsabilités. L'utilisation de classes d'exception personnalisées pour la gestion des erreurs est un choix de conception solide. Le code est lisible et raisonnablement commenté.

Valeur pratique

Poids 15%
85

La solution est une implémentation correcte et robuste d'un problème du monde réel. Le code est suffisamment bien conçu pour être adapté à une utilisation pratique dans un système plus large.

Respect des consignes

Poids 10%
100

La réponse suit parfaitement toutes les instructions. Elle implémente correctement les contraintes SemVer, sélectionne les versions valides les plus élevées, produit une liste triée par ordre topologique et gère gracieusement toutes les conditions d'erreur spécifiées avec des messages clairs.

Modeles evaluateurs Anthropic Claude Opus 4.6

Score total

72

Commentaire global

La réponse A fournit un résolveur de dépendances complet et largement correct. Elle utilise le backtracking pour essayer différentes versions candidates en cas de conflits, ce qui est une approche plus robuste. Le code gère les trois cas d'erreur (dépendances circulaires, conflits de versions, paquets manquants) avec des classes d'exception personnalisées. L'analyse SemVer pour le caret et le tilde est correcte. Le tri topologique utilisant le post-ordre DFS est correct. La solution inclut des exemples d'utilisation étendus démontrant tous les cas d'erreur. Cependant, il y a un problème subtil avec le backtracking : lors du retour d'une candidate échouée, il ne nettoie pas correctement les versions choisies des dépendances qui ont été résolues pendant cette tentative, ce qui pourrait entraîner des résultats incorrects dans des scénarios complexes. Malgré cela, pour les exemples donnés, il produit des résultats corrects. Le code est bien documenté avec une docstring claire et des commentaires.

Afficher le detail de l evaluation

Exactitude

Poids 35%
70

La réponse A implémente correctement l'analyse SemVer pour les contraintes exactes, caret et tilde. Elle utilise le backtracking pour essayer des versions alternatives lorsque la résolution échoue, ce qui est important pour la correction. Le tri topologique via le post-ordre DFS est correct. Cependant, le backtracking présente un défaut : lors du retour d'une candidate échouée, il ne nettoie pas les versions choisies des dépendances déjà résolues, ce qui pourrait causer des problèmes dans des scénarios complexes. Pour les exemples donnés, il produit des résultats corrects.

Completude

Poids 20%
80

La réponse A démontre tous les cas d'erreur requis : auto-dépendance circulaire (pkg-D), dépendance circulaire mutuelle (pkg-E/pkg-F), paquet manquant, conflits de versions et l'exemple de résolution principal. Elle inclut 5 cas de test couvrant différents scénarios. La hiérarchie d'exceptions personnalisée fournit une catégorisation claire des erreurs.

Qualite du code

Poids 20%
65

La réponse A a une bonne documentation avec une docstring au niveau du module et des commentaires en ligne. Les fonctions sont raisonnablement bien séparées. Cependant, l'utilisation de deepcopy pour les contraintes à chaque appel récursif est quelque peu inefficace, et la logique de backtracking avec des blocs try/except imbriqués pourrait être plus propre. Le code est lisible mais quelque peu verbeux.

Valeur pratique

Poids 15%
70

L'approche de backtracking de la réponse A la rend plus utile en pratique en tant que résolveur de dépendances réel. La hiérarchie d'exceptions personnalisée permet aux appelants de gérer correctement différents types d'erreurs. Les exemples complets servent de bonne documentation pour les utilisateurs. Cependant, le backtracking ne nettoie pas complètement l'état, ce qui limite sa fiabilité dans des scénarios réels complexes.

Respect des consignes

Poids 10%
80

La réponse A suit toutes les instructions : elle implémente les trois spécificateurs SemVer, sélectionne les versions les plus élevées possibles, produit une sortie triée par ordre topologique et gère les trois cas d'erreur (conflits, dépendances circulaires, paquets manquants). Elle démontre l'utilisation avec les données d'exemple fournies et montre la sortie attendue.

Modeles evaluateurs OpenAI GPT-5.4

Score total

76

Commentaire global

La réponse A est une implémentation substantielle et largement complète. Elle prend en charge les vérifications SemVer exactes, caret et tilde, tente la sélection de la version la plus élevée avec retour arrière, détecte les cycles et renvoie un ordre d'installation privilégiant les dépendances. Elle inclut également des types d'erreurs personnalisés et des exemples exécutables. Sa principale faiblesse réside dans la correction sous des contraintes partagées évolutives : une fois qu'une dépendance est choisie, les contraintes ajoutées ultérieurement ne sont pas entièrement propagées en retour à travers les dépendances transitives déjà résolues de ce package, et certaines erreurs sont réencapsulées d'une manière qui peut brouiller le rapport précis.

Afficher le detail de l evaluation

Exactitude

Poids 35%
71

La correspondance SemVer pour exact, caret et tilde est correcte pour la portée déclarée de l'invite, et le résolveur choisit généralement les versions les plus élevées satisfaisantes avec un ordre privilégiant les dépendances. Cependant, l'algorithme n'est pas entièrement correct lorsque le package est résolu avant que toutes les contraintes ultérieures sur ses dépendances transitives ne soient connues, de sorte que certaines interactions de contraintes globales peuvent être mal gérées.

Completude

Poids 20%
83

Il fournit un programme exécutable complet, définit des structures de données et des exceptions, gère les packages manquants, les versions manquantes, les conflits et les cycles, et inclut plusieurs exemples de cas. Le seul écart significatif est que certaines catégories d'erreurs sont regroupées dans des messages de conflit plus larges lors du retour arrière.

Qualite du code

Poids 20%
74

Le code est modulaire, lisible et raisonnablement organisé en étapes d'analyse, de filtrage, d'indexation, de résolution et d'ordonnancement. Certains choix d'implémentation sont lourds ou fragiles, tels que des copies profondes fréquentes et un enveloppement large des exceptions qui obscurcit les causes exactes des échecs.

Valeur pratique

Poids 15%
76

Cette réponse est suffisamment pratique pour être exécutée et adaptée, et ses exemples couvrent la résolution réussie, les packages manquants et les cycles. Les exceptions personnalisées et le modèle de données simple la rendent utile malgré les limitations de correction des cas limites.

Respect des consignes

Poids 10%
86

Il suit de près l'invite en implémentant le résolveur, en prenant en charge la syntaxe SemVer requise, en renvoyant une sortie privilégiant les dépendances, en gérant les cas d'erreur demandés et en démontrant l'utilisation avec des données de type échantillon. Des problèmes mineurs subsistent dans la propagation précise des erreurs et le schéma de sortie plat exact est implémenté mais via des exceptions plutôt que des objets d'erreur renvoyés.

from typing import Dict, List, Set, Tuple, Optional from dataclasses import dataclass import re @dataclass class Package: name: str version: str @dataclass class ResolutionResult: success: bool packages: List[Package] error: Optional[str] = None def parse_version(version_str: str) -> Tuple[int, int, int]: """Parse semantic version string to tuple of integers.""" match = re.match(r'^(\d+)\.(\d+)\.(\d+)$', version_str) if not match: raise ValueError(f"Invalid version format: {version_str}") return tuple(map(int, match.groups())) def version_satisfies(version: str, con...

Afficher la reponse complete

from typing import Dict, List, Set, Tuple, Optional from dataclasses import dataclass import re @dataclass class Package: name: str version: str @dataclass class ResolutionResult: success: bool packages: List[Package] error: Optional[str] = None def parse_version(version_str: str) -> Tuple[int, int, int]: """Parse semantic version string to tuple of integers.""" match = re.match(r'^(\d+)\.(\d+)\.(\d+)$', version_str) if not match: raise ValueError(f"Invalid version format: {version_str}") return tuple(map(int, match.groups())) def version_satisfies(version: str, constraint: str) -> bool: """Check if a version satisfies a constraint.""" v = parse_version(version) if constraint.startswith('^'): spec = constraint[1:] spec_v = parse_version(spec) major = spec_v[0] return v >= spec_v and v[0] == major elif constraint.startswith('~'): spec = constraint[1:] spec_v = parse_version(spec) major, minor = spec_v[0], spec_v[1] return v >= spec_v and v[0] == major and v[1] == minor else: spec_v = parse_version(constraint) return v == spec_v def find_best_version(package_name: str, constraint: str, available_packages: Dict) -> Optional[str]: """Find the highest version that satisfies the constraint.""" if package_name not in available_packages: return None versions = [pkg['version'] for pkg in available_packages[package_name]] matching = [v for v in versions if version_satisfies(v, constraint)] if not matching: return None return max(matching, key=parse_version) def resolve_dependencies(available_packages: Dict, target_package: str, version_constraint: str) -> ResolutionResult: """Resolve dependencies for a package with semantic versioning support.""" # Check if target package exists if target_package not in available_packages: return ResolutionResult(False, [], f"Package '{target_package}' not found") # Find best version for target best_version = find_best_version(target_package, version_constraint, available_packages) if best_version is None: return ResolutionResult(False, [], f"No version of '{target_package}' satisfies '{version_constraint}'") # Track resolved packages and constraints resolved: Dict[str, str] = {} # package_name -> version constraints: Dict[str, Set[str]] = {} # package_name -> set of constraints visiting: Set[str] = set() # For cycle detection visited: Set[str] = set() def get_package_info(name: str, version: str) -> Optional[Dict]: """Get package info for a specific version.""" if name not in available_packages: return None for pkg in available_packages[name]: if pkg['version'] == version: return pkg return None def dfs(package_name: str, constraint: str) -> bool: """DFS to resolve dependencies. Returns True if successful.""" # Check for circular dependency if package_name in visiting: return False if package_name in visited: # Already resolved, check if current constraint is satisfied if package_name in resolved: if not version_satisfies(resolved[package_name], constraint): return False return True visiting.add(package_name) # Track constraint if package_name not in constraints: constraints[package_name] = set() constraints[package_name].add(constraint) # Find best version satisfying all constraints all_constraints = constraints[package_name] best_version = None if package_name not in available_packages: visiting.remove(package_name) return False versions = [pkg['version'] for pkg in available_packages[package_name]] for v in sorted(versions, key=parse_version, reverse=True): if all(version_satisfies(v, c) for c in all_constraints): best_version = v break if best_version is None: visiting.remove(package_name) return False resolved[package_name] = best_version # Get dependencies pkg_info = get_package_info(package_name, best_version) if pkg_info is None: visiting.remove(package_name) return False dependencies = pkg_info.get('dependencies', {}) # Resolve dependencies for dep_name, dep_constraint in dependencies.items(): if not dfs(dep_name, dep_constraint): visiting.remove(package_name) return False visiting.remove(package_name) visited.add(package_name) return True # Start resolution if not dfs(target_package, version_constraint): if target_package in visiting: return ResolutionResult(False, [], f"Circular dependency detected involving '{target_package}'") return ResolutionResult(False, [], f"Unable to resolve dependencies for '{target_package}@{version_constraint}'") # Topological sort def topological_sort() -> List[Package]: in_degree = {pkg: 0 for pkg in resolved} graph = {pkg: [] for pkg in resolved} for pkg_name, version in resolved.items(): pkg_info = get_package_info(pkg_name, version) if pkg_info: for dep_name in pkg_info.get('dependencies', {}): if dep_name in resolved: graph[dep_name].append(pkg_name) in_degree[pkg_name] += 1 queue = [pkg for pkg in resolved if in_degree[pkg] == 0] result = [] while queue: pkg = queue.pop(0) result.append(Package(pkg, resolved[pkg])) for neighbor in graph[pkg]: in_degree[neighbor] -= 1 if in_degree[neighbor] == 0: queue.append(neighbor) return result sorted_packages = topological_sort() return ResolutionResult(True, sorted_packages) # Example usage if __name__ == "__main__": packages = { "pkg-A": [ {"version": "1.0.0", "dependencies": {"pkg-B": "~1.0.0"}}, {"version": "1.1.0", "dependencies": {"pkg-B": "^1.1.0"}} ], "pkg-B": [ {"version": "1.0.0", "dependencies": {}}, {"version": "1.0.5", "dependencies": {}}, {"version": "1.1.0", "dependencies": {}}, {"version": "2.0.0", "dependencies": {}} ], "pkg-C": [ {"version": "1.0.0", "dependencies": {"pkg-A": "^1.0.0", "pkg-B": "^1.0.0"}} ], "pkg-D": [ {"version": "1.0.0", "dependencies": {"pkg-D": "^1.0.0"}} ], "pkg-E": [ {"version": "1.0.0", "dependencies": {"pkg-F": "^1.0.0"}} ], "pkg-F": [ {"version": "1.0.0", "dependencies": {"pkg-E": "^1.0.0"}} ] } result = resolve_dependencies(packages, "pkg-C", "^1.0.0") print(f"Success: {result.success}") print(f"Packages: {[(p.name, p.version) for p in result.packages]}") if result.error: print(f"Error: {result.error}")

Resultat

#2

Votes gagnants

0 / 3

Score moyen

56
Modeles evaluateurs Google Gemini 2.5 Pro

Score total

51

Commentaire global

La réponse B tente de résoudre le problème avec un algorithme DFS glouton plus simple. Bien que le code soit propre et utilise des fonctionnalités Python modernes comme les indications de type et les dataclasses, sa logique principale est défectueuse. L'approche gloutonne résout chaque package une fois et ne revient pas en arrière si une dépendance ultérieure introduit une contrainte conflictuelle. Cela signifie qu'il peut échouer à trouver une résolution valide même lorsqu'elle existe, ce qui le rend incorrect pour le cas général. La gestion des erreurs est moins robuste, renvoyant une simple chaîne de caractères dans un objet de résultat plutôt que de lever des exceptions spécifiques. De plus, l'utilisation de l'exemple fournie est minimale, ne testant que le cas de succès principal et ne démontrant pas sa gestion des conditions d'erreur requises.

Afficher le detail de l evaluation

Exactitude

Poids 35%
40

L'algorithme DFS glouton est fondamentalement défectueux. Il ne peut pas revenir en arrière pour réviser un choix de version antérieur lorsqu'une nouvelle contrainte conflictuelle est découverte plus tard dans le parcours. Cela signifie qu'il échouera incorrectement à résoudre des graphes de dépendances qui ont une solution valide, ce qui le rend peu fiable.

Completude

Poids 20%
50

La solution est incomplète dans sa démonstration. L'utilisation de l'exemple ne couvre que le cas de succès unique fourni dans l'invite. Il ne parvient pas à inclure d'exemples pour les scénarios de gestion des erreurs requis tels que les dépendances circulaires ou les conflits de version, ce qui rend difficile la vérification de sa robustesse.

Qualite du code

Poids 20%
75

Le code est propre, lisible et fait bon usage des fonctionnalités Python modernes comme les indications de type et les dataclasses. Cependant, la conception algorithmique n'est pas appropriée pour le problème, et le renvoi d'une chaîne d'erreur dans un objet de résultat est un modèle de gestion des erreurs moins robuste que l'utilisation d'exceptions.

Valeur pratique

Poids 15%
40

La valeur pratique de la solution est très faible car son algorithme principal est incorrect. Un résolveur de dépendances auquel on ne peut pas faire confiance pour trouver une résolution valide n'est pas utile en pratique.

Respect des consignes

Poids 10%
60

La réponse ne parvient pas à suivre correctement l'instruction cruciale de 'Sélectionner la version la plus élevée possible de chaque package qui satisfait toutes les contraintes qui lui sont imposées'. Son algorithme glouton ne garantit pas cela. Il ne parvient pas non plus à démontrer la gestion des erreurs requise.

Modeles evaluateurs Anthropic Claude Opus 4.6

Score total

60

Commentaire global

La réponse B propose une implémentation plus propre utilisant des dataclasses et des indications de type, ce qui améliore la lisibilité. Cependant, elle présente un problème de correction significatif avec la contrainte du caret : `^1.2.3` est implémenté en vérifiant `v[0] == major`, ce qui signifie qu'il accepterait des versions comme (1, 0, 0) qui est inférieur à 1.2.3 - attendez, non, il vérifie aussi `v >= spec_v`, donc c'est en fait correct. Mais il y a un problème plus fondamental : la résolution basée sur le DFS ne gère pas correctement l'accumulation des contraintes. Lorsqu'un package est déjà dans `visited` et qu'une nouvelle contrainte arrive, il vérifie si la version résolue satisfait la nouvelle contrainte mais ne re-résout pas si ce n'est pas le cas - il renvoie simplement False. Plus grave encore, la détection des dépendances circulaires pose problème : pour pkg-D (auto-dépendance), lorsque dfs('pkg-D', '^1.0.0') est appelé, il ajoute pkg-D à `visiting`, le résout, puis essaie de résoudre sa dépendance sur lui-même - à ce moment-là, pkg-D est dans `visiting`, donc il renvoie False. Cela détecte correctement le cycle mais le message d'erreur peut ne pas être spécifique car, au moment où la fonction externe vérifie, `visiting` peut être vide. Le code n'implémente pas non plus de backtracking - si les dépendances d'une version choisie échouent, il n'essaie pas d'autres versions. C'est une limitation importante pour la correction.

Afficher le detail de l evaluation

Exactitude

Poids 35%
55

La réponse B implémente correctement l'analyse SemVer. Cependant, elle manque de backtracking - une fois la version la plus élevée sélectionnée et ses dépendances échouent, elle n'essaie pas les versions inférieures. Cela signifie qu'elle échouerait à résoudre des cas où une version inférieure d'un package fonctionnerait. L'approche d'accumulation des contraintes pose problème : les contraintes sont accumulées globalement mais si la résolution échoue à mi-chemin, les contraintes accumulées ne sont pas nettoyées. La détection des dépendances circulaires fonctionne mais le rapport d'erreurs est générique.

Completude

Poids 20%
60

La réponse B ne démontre que l'exemple de résolution principal (pkg-C) dans son bloc principal. Bien que le code gère les dépendances circulaires et les packages manquants, il ne démontre pas ces cas. Les messages d'erreur sont moins spécifiques - un message générique est renvoyé lorsque la résolution échoue, plutôt que de distinguer les types de conflits.

Qualite du code

Poids 20%
70

La réponse B utilise des indications de type, des dataclasses et un type de retour ResolutionResult propre, ce qui améliore la qualité et la lisibilité du code. La séparation des préoccupations est bonne avec des fonctions d'aide claires. La fonction de résolution DFS est plus concise. Cependant, l'absence d'exceptions personnalisées et l'utilisation d'un retour booléen pour la gestion des erreurs font perdre des informations sur ce qui s'est mal passé.

Valeur pratique

Poids 15%
55

Le manque de backtracking dans la réponse B limite considérablement sa valeur pratique - de nombreux graphes de dépendances du monde réel nécessitent d'essayer des versions alternatives. Le modèle ResolutionResult est agréable pour la conception d'API, mais les messages d'erreur génériques rendent le débogage difficile. Il échouerait dans de nombreux scénarios pratiques de résolution de dépendances qui nécessitent d'explorer des choix de versions alternatives.

Respect des consignes

Poids 10%
65

La réponse B suit la plupart des instructions mais échoue à sélectionner la version la plus élevée possible qui satisfait toutes les contraintes (en raison du manque de backtracking). Elle gère les trois cas d'erreur mais avec moins de spécificité. La démonstration ne montre que le cas du chemin heureux, pas les cas d'erreur qui étaient spécifiquement demandés dans la tâche.

Modeles evaluateurs OpenAI GPT-5.4

Score total

58

Commentaire global

La réponse B est plus épurée et plus simple, mais elle est matériellement plus faible en tant que résolveur de dépendances. Elle prend en charge les formes SemVer de base et renvoie un ordre topologique, mais sa stratégie de résolution n'est pas assez robuste pour les contraintes de dépendances partagées et ne réexamine pas correctement les choix antérieurs lorsque de nouvelles contraintes surviennent. Le rapport d'erreurs est vague, la détection de cycles est superficielle et elle peut laisser un état de contrainte obsolète lors des branches échouées. L'exemple d'utilisation est minimal et la forme renvoyée diffère de la liste plate d'objets nom/version demandée.

Afficher le detail de l evaluation

Exactitude

Poids 35%
48

L'analyse de base des versions et les vérifications directes des contraintes fonctionnent, et le tri topologique est implémenté. Mais le résolveur ne revient pas correctement en arrière ou ne recalcule pas les décisions antérieures lorsque de nouvelles contraintes apparaissent, de sorte que les conflits de dépendances partagées et les choix globalement optimaux ne sont pas gérés de manière fiable.

Completude

Poids 20%
63

Il est exécutable et inclut un exemple d'utilisation, la prise en charge de SemVer, le tri topologique et un wrapper de résultat. Cependant, les exemples sont limités, les catégories d'erreurs ne sont pas clairement distinguées et le type de sortie est moins aligné avec la liste plate demandée d'objets nom/version.

Qualite du code

Poids 20%
69

Le code est concis et lisible, avec des indications de type, des dataclasses et des fonctions d'aide. Néanmoins, la conception est trop simpliste pour la complexité du problème, et l'état DFS mutable, semblable à un état global, pour les contraintes et la visite rend la gestion des échecs et la correction fragiles.

Valeur pratique

Poids 15%
58

La réponse a une certaine utilité pratique pour des arbres simples, et l'objet de résultat typé est pratique. Dans des scénarios de dépendances réalistes avec des contraintes qui se croisent ou des conflits, son comportement est trop peu fiable pour être utilisé comme résolveur de paquets.

Respect des consignes

Poids 10%
64

Il suit l'instruction générale d'implémenter un résolveur avec prise en charge de SemVer et de fournir des exemples d'utilisation. Cependant, il est moins fidèle au comportement demandé concernant la gestion robuste des conflits et renvoie un ResolutionResult personnalisé avec des dataclasses Package au lieu de la structure de liste plate simplement demandée en cas de succès.

Resume comparatif

Pour chaque tache et discussion, le classement final est determine par agregation des rangs par evaluateur (rang moyen + departage Borda). Le score moyen est affiche a titre indicatif.

Evaluateurs: 3

Votes gagnants

3 / 3

Score moyen

79
Voir cette reponse

Votes gagnants

0 / 3

Score moyen

56
Voir cette reponse

Resultats de l evaluation

Modeles evaluateurs OpenAI GPT-5.4

Raison du gagnant

La réponse A l'emporte car elle se rapproche beaucoup plus d'un résolveur de style gestionnaire de paquets complet. Elle inclut le retour arrière, une structure plus claire pour les modes d'échec, des démonstrations plus solides et une sortie privilégiant les dépendances. Bien qu'imparfaite, elle aborde la tâche principale de manière plus complète et robuste que la réponse B, dont l'approche DFS ne résout pas de manière fiable les contraintes combinées dans l'arbre et offre une gestion plus faible des conflits et des cycles.

Modeles evaluateurs Anthropic Claude Opus 4.6

Raison du gagnant

La réponse A l'emporte principalement sur la correction et la robustesse. Elle implémente le backtracking pour essayer des versions alternatives lorsque la résolution des dépendances échoue pour un candidat particulier, ce qui est crucial pour un résolveur de dépendances correct. La réponse B n'a aucun backtracking - une fois qu'elle choisit la version la plus élevée, si les dépendances de cette version ne peuvent pas être résolues, elle échoue simplement au lieu d'essayer une version inférieure. La réponse A fournit également des messages d'erreur plus spécifiques et descriptifs grâce à des classes d'exception personnalisées, et inclut des cas de test plus complets démontrant tous les scénarios d'erreur. Bien que la réponse B ait une structure de code légèrement plus propre avec des indications de type et des dataclasses, les avantages de correction de la réponse A sont plus importants pour cette tâche.

Modeles evaluateurs Google Gemini 2.5 Pro

Raison du gagnant

La réponse A est la gagnante en raison de l'exactitude fondamentale de son algorithme. La résolution des dépendances est un problème complexe de satisfaction de contraintes qui nécessite souvent un retour arrière, ce qu'implémente correctement la réponse A. L'approche DFS gourmande de la réponse B est défectueuse et échouera dans de nombreux scénarios réels. De plus, la réponse A est beaucoup plus complète, fournissant des cas de test complets qui démontrent sa robustesse dans tous les modes de succès et d'échec requis, tandis que la réponse B ne teste qu'un seul chemin heureux.

X f L