Introduction
Une petite ludothèque cherche des alternatives pour ce soir. Un jeu peut ressembler à votre favori tout en étant indisponible ou inadapté au groupe. Vous séparerez deux questions : quels jeux sont utilisables et comment comparer leurs caractéristiques numériques.
Vous produirez un programme de sélection reproductible et un véritable résultat JSON. Prérequis : fonctions et dictionnaires Python, tableaux NumPy élémentaires et lecture de tables. Connaître la classification par plus proches voisins aide, mais aucun label n'est prédit ici. Python et NumPy sont prêts ; scikit-learn n'est pas nécessaire. Les 45 minutes sont une estimation de l'auteur incluant lecture et corrections ordinaires.
Déterminez les jeux utilisables ce soir
Dans cette étape, vous examinerez le véritable catalogue de la ludothèque, puis implémenterez les règles d’admissibilité de ce soir dans une région d’une fonction préparée.
Ouvrez l’onglet Terminal. Toutes les commandes s’y exécutent, y compris le lecteur de fichiers enregistrés. Ouvrir ou reconnecter Terminal ne réinstalle ni ne réinitialise votre espace de travail. cd change le répertoire courant de ce terminal ; un autre terminal possède son propre répertoire.
cd /home/labex/project/board-games
Commencez par l’entrée réelle. CSV comporte un en-tête suivi de lignes séparées par des virgules. cat affiche le fichier sans le modifier. C’est le catalogue complet, non filtré, pas une liste de jeux déjà admissibles ce soir.
cat catalog.csv
Chaque ligne représente une édition de jeu distincte. Son game_id unique et non vide est la clé permettant de retrouver et d’associer cette édition. title est du texte d’affichage : plusieurs éditions de Harbor ont des ID différents et doivent rester distinctes. minutes est une estimation positive du temps de jeu ; complexity est une note synthétique de 1 à 5, une valeur plus grande indiquant un jeu plus compliqué. Les entiers min_players et max_players incluent les deux bornes. L’entrée synthétique est complète et comporte une ligne par ID ; nettoyer des données mal formées sort du cadre de cet exercice.
cat availability.csv
La table d’emprunts séparée comporte une ligne pour chaque ID du catalogue, dans un autre ordre. Son texte CSV true/false devient les booléens Python True/False dans le lecteur préparé. Associer par clé signifie retrouver le même game_id, pas rattacher la ligne 1 à la ligne 1. Des clés uniques et une ligne d’état d’emprunt par ID empêchent les correspondances ambiguës ou absentes. Vous implémenterez cette recherche.
JSON stocke des valeurs nommées, des listes et des objets. Lisez la requête de ce soir :
cat night.json
reference_id est l’exemple auquel ressembler, players la taille du groupe et k le nombre d’alternatives proches demandé, utilisé au laboratoire suivant. La référence est un exemple de requête et peut elle-même être indisponible ou inadaptée ; seules les alternatives renvoyées doivent être admissibles ce soir. Excluez uniquement son ID exact, pas tous les jeux de même titre ou de caractéristiques identiques. L’aperçu des entrées brutes n’a pas appliqué ces règles ni produit de résultat d’admissibilité.
Considérez trois jeux disponibles pour quatre joueurs : Harbor dure 60 minutes avec une complexité de 3, Quay 61 minutes avec une complexité de 5, et Bridge 90 minutes avec une complexité de 3. Les écarts en unités originales valent candidat moins référence : Quay dure une minute de plus et ajoute deux points de complexité ; Bridge dure trente minutes de plus avec la même complexité. L’option Python -c exécute le calcul entre guillemets comme un seul argument. Le point-virgule sépare deux instructions Python.
python3 -c "print('Quay minutes:', 61 - 60); print('Bridge minutes:', 90 - 60)"
Vous devez obtenir 1 et 30. La distance euclidienne brute élève les écarts des caractéristiques au carré, les additionne, puis prend la racine carrée. Trente minutes peuvent dominer deux points de complexité si ces unités sont mélangées directement. Vous définirez une échelle commune ensuite ; décidez d’abord qui est autorisé à participer.
Vous pouvez modifier suitability.py, ranking.py, vos fichiers de résultats et vos propres sauvegardes de scripts. Préservez toutes les entrées CSV/JSON fournies, planner.py, coursekit.py, show_results.py et les deux copies de récupération starter-*.py. planner.py sélectionne une fonction publique et délègue la lecture des fichiers, la conversion des types et l’écriture JSON à coursekit.py ; aucun des deux ne prend la décision métier. Laissez ranking.py inachevé dans ce laboratoire.
Lisez le module préparé :
cat suitability.py
choose_games(catalog, availability, request) reçoit les listes de dictionnaires chargées et le dictionnaire de requête. Ses deux régions étiquetées commencent par eligible = [] et scale = {}. Ce sont des éléments provisoires inachevés, pas l’affirmation qu’aucun jeu ne convient. Le retour final regroupe les ID et l’échelle pour le lanceur. Vous remplacerez maintenant la région d’admissibilité et garderez la région provisoire d’échelle pour l’étape 2. La préparation et l’aperçu des entrées ne créent aucun résultat évalué.
Sauvegardez ce module. cp SOURCE DESTINATION copie uniquement le fichier nommé ; .bak est un suffixe de sauvegarde. N’écrasez pas cette sauvegarde après une erreur.
cp suitability.py suitability.py.bak
nano modifie un fichier existant dans Terminal. Le LC_ALL=C.UTF-8 limité à la commande sélectionne UTF-8 pour cet éditeur uniquement, sans modifier les réglages globaux du shell. Dans la barre de raccourcis de nano, ^ signifie maintenir Ctrl. Les flèches déplacent le curseur ; saisir insère du texte. Ctrl+W, un texte recherché, puis Entrée permettent de trouver du texte. Home place le curseur au début de la ligne ; Ctrl+K coupe cette ligne entière. Python utilise l’indentation : les lignes ci-dessous commencent par quatre espaces dans la fonction, avec davantage d’indentation dans la boucle et la condition.
LC_ALL=C.UTF-8 nano suitability.py
Exercez-vous d’abord à abandonner une modification non voulue. Trouvez ## Candidate identities avec Ctrl+W et Entrée, appuyez sur End et ajoutez temporary à ce commentaire. Appuyez sur Ctrl+X, puis N à la question d’enregistrement. Vous quittez sans modifier le fichier. Ouvrez-le à nouveau :
LC_ALL=C.UTF-8 nano suitability.py
Trouvez eligible = [], appuyez sur Home, puis une fois sur Ctrl+K pour retirer uniquement cette ligne provisoire. Gardez l’en-tête de fonction, la région d’échelle et le retour final. Insérez les lignes indentées suivantes à cet endroit. La compréhension de dictionnaire construit une recherche ID-disponibilité. La boucle utilise and pour trois exigences indépendantes ; les comparaisons chaînées <= incluent les deux bornes de joueurs. append ajoute l’ID correspondant, pas le titre affiché.
status = {row['game_id']: row['available'] for row in availability}
eligible = []
for game in catalog:
different_id = game['game_id'] != request['reference_id']
fits_group = game['min_players'] <= request['players'] <= game['max_players']
if different_id and fits_group and status[game['game_id']]:
eligible.append(game['game_id'])
Enregistrez avec Ctrl+O, appuyez sur Entrée pour confirmer le nom inchangé, puis sur Ctrl+X pour quitter. Enregistrer n’exécute pas la fonction. Son retour existant utilise sorted(eligible) pour produire une liste alphabétique d’identités, indépendamment de l’ordre des lignes d’entrée, et laisse scale comme objet vide.
Le --mode suitable du lanceur sélectionne choose_games ; --output suitable.json, obligatoire, nomme son résultat enregistré. Les valeurs par défaut sont catalog.csv, availability.csv et night.json dans ce répertoire. --catalog, --availability et --request peuvent sélectionner d’autres chemins. Ces entrées restent en lecture seule.
python3 planner.py --mode suitable --output suitable.json
Le lecteur fourni ouvre uniquement ce JSON enregistré. Il ne génère pas un fichier manquant et ne calcule rien depuis le catalogue.
python3 show_results.py suitable.json
Vous devez obtenir Scale: {} et les ID left, near, raw, right, same, zero. same et zero sont d’autres éditions de Harbor ; zero a même des caractéristiques numériques identiques à la référence. blocked est indisponible, small n’accueille pas quatre joueurs et ref est la référence exacte. Comparez ces identités aux deux tables d’entrée. L’admissibilité est maintenant complète, mais l’échelle n’est délibérément pas encore implémentée.
L’échec suivant dû à un mauvais répertoire est intentionnel. Remontez d’un répertoire :
cd /home/labex/project
python3 planner.py --mode suitable --output suitable.json
Python signale can't open file et No such file or directory : il ne trouve pas le lanceur ici. Votre programme et votre résultat existants n’ont pas été réinitialisés. pwd révèle le répertoire de ce terminal ; revenez à l’espace de travail et relancez la vraie commande.
pwd
cd /home/labex/project/board-games
python3 planner.py --mode suitable --output suitable.json
python3 show_results.py suitable.json
Pour une erreur d’édition, lisez le nom de fichier et le numéro de ligne de Python, rouvrez le module dans nano et corrigez uniquement la région concernée. Un SyntaxError indique souvent un deux-points ou un guillemet manquant ; un IndentationError signifie que les espaces initiaux méritent attention. Enregistrez, quittez et relancez. Ctrl+X, N abandonne les modifications non enregistrées. Si nécessaire, cp suitability.py.bak suitability.py restaure uniquement cette base inachevée ; vous devez donc réappliquer ensuite la région d’admissibilité. Ni une sauvegarde ni le starter-suitability.py protégé ne sont votre solution terminée. Ne relancez pas la préparation et ne modifiez pas les entrées pour récupérer une erreur.
Gardez une échelle pour tout le catalogue
Dans cette étape, vous implémenterez la région d’échelle en préservant votre logique d’admissibilité terminée.
Continuez dans l’onglet Terminal. Précisez le répertoire pour fonctionner aussi dans un nouveau terminal.
cd /home/labex/project/board-games
Une caractéristique est une propriété numérique de comparaison. L'ordre est toujours minutes, puis complexity ; disponibilité et limites de joueurs sont des critères d'admissibilité, pas de distance. Cherchez minimum et maximum sur tout le catalogue, référence et jeux indisponibles ou inadaptés compris. L'étendue est maximum moins minimum. MinMax transforme x en (x - minimum) / range : chaque différence représente une fraction de l'étendue de sa caractéristique.
Les minima complets sont [10, 1], les étendues [100, 4]. Quay donne [1/100, 2/4], Bridge [30/100, 0/4]. La distance mise à l'échelle de Quay vaut environ 0.5001, celle de Bridge 0.3. La métrique modifie le classement ; aucune unité ne révèle les goûts personnels. Pondérer également les deux caractéristiques normalisées est un choix explicite de l'exercice.
Le catalogue sert à définir cette métrique, pas à entraîner une prédiction supervisée. Sans cible future, aucune séparation entraînement/test. Modifier seulement les emprunts ne doit changer ni l'échelle ni les distances des candidats conservés. Réajuster après filtrage déplacerait la règle à chaque prêt.
Une caractéristique constante a une étendue nulle. Sauvegardez la vraie étendue 0, mais utilisez un diviseur 1 dans la distance ultérieure. La référence appartenant au catalogue, toutes les différences de cette caractéristique sont nulles : sa contribution est zéro. Cela évite la division par zéro sans inventer d'information.
Gardez une nouvelle sauvegarde de votre étape d’admissibilité fonctionnelle, en laissant intacte la sauvegarde de la base initiale :
cp suitability.py suitability-ids.py.bak
LC_ALL=C.UTF-8 nano suitability.py
Trouvez scale = {} avec Ctrl+W et Entrée, appuyez sur Home et coupez uniquement cette ligne provisoire avec Ctrl+K. Laissez inchangées la recherche d’ID et la boucle terminées au-dessus. Insérez les quatre lignes indentées ci-dessous. np.array construit une table numérique à deux colonnes dans l’ordre publié des caractéristiques ; axis=0 trouve les minima et maxima le long de chaque colonne. tolist() convertit les tableaux en listes ordinaires que JSON peut enregistrer.
features = np.array([[game['minutes'], game['complexity']] for game in catalog])
minimum = features.min(axis=0)
ranges = features.max(axis=0) - minimum
scale = {'min': minimum.tolist(), 'range': ranges.tolist()}
Le retour existant inclut maintenant ce scale calculé et vos mêmes ID triés. Enregistrez avec Ctrl+O, Entrée, puis Ctrl+X. Vous avez ajouté une région au lieu de remplacer le travail précédent ou d’ajouter un autre programme.
Le résultat exige chaque ID admissible une fois, alphabétiquement, ainsi que deux valeurs numériques dans chaque liste scale.min et scale.range.
Sauvegardez des nombres, pas des chaînes d'affichage. Des explications supplémentaires inoffensives sont permises. Les tolérances absolue et relative d'évaluation sont 1e-8 : elles couvrent l'arithmétique flottante ordinaire, pas une autre métrique.
Régénérez le résultat réel depuis les entrées intactes, en remplaçant seulement votre sortie.
python3 planner.py --mode suitable --output suitable.json
python3 show_results.py suitable.json
Vous devez lire les minima 10 et 1, les étendues 100 et 4, et les mêmes six ID admissibles. Le lecteur peut afficher 10.0 plutôt que 10 ; les deux désignent le nombre dix. Examinez directement la structure enregistrée :
cat suitable.json
Si une modification endommage la région d’admissibilité, cp suitability-ids.py.bak suitability.py restaure uniquement cette étape fonctionnelle. Rouvrez nano et implémentez à nouveau la région d’échelle. cp starter-suitability.py suitability.py restaure au contraire la base inachevée et fait perdre les deux régions ; utilisez-le uniquement pour recommencer intentionnellement. Les corrections ordinaires doivent réparer les lignes concernées, enregistrer, quitter et relancer. Préservez les deux fichiers starter fournis et toutes les entrées. Reconnecter Terminal ne lance jamais la préparation et ne restaure pas une sauvegarde à votre place.
Autovérification : l’admissibilité de ce soir peut changer sans changer cette règle définie par le catalogue entier. Dans le laboratoire indépendant suivant, la fonction complète d’admissibilité est fournie pour vous concentrer sur les distances et la sélection.
Résumé
Vous avez séparé l'admissibilité de la similarité, associé des enregistrements indépendants par identifiant stable, conservé les alternatives légitimes de même titre ou de différence nulle et défini une échelle MinMax fixe sur le catalogue entier. suitable.json est un résultat réel et régénérable. Le prochain laboratoire utilise ces acquis pour mesurer et expliquer les candidats, dans son propre environnement indépendant.



