Groupe de jeu cEDH
Cette compétence conserve un petit fichier modifiable à la main des données d'un groupe de jeu cEDH et les combine avec les données de tournois de TopDeck.gg. Elle remplit quatre fonctions, plus la publication de leurs résultats sur le canal Discord du groupe :
- Joueurs : ajouter des personnes via leur ID de profil TopDeck, ainsi que les decks qu'elles possèdent.
- Méta : ce qui est joué et ce qui gagne, par défaut les 30 derniers jours.
- Saisie : résultats d'entraînement, decks actuels, notes sur le méta, disponibilités.
- Pods : organiser une soirée d'entraînement pour que le groupe obtienne des parties utiles.
Tous les calculs sont dans des scripts Python dans scripts/ (stdlib uniquement). Votre travail consiste à les exécuter, lire leurs sorties et les transformer en conseils exploitables pour le groupe. Ne recalculez pas les statistiques manuellement. Les scripts gèrent les cas particuliers (noms de partenaires, égalités, petits échantillons), et le faire deux fois risque de donner deux réponses différentes.
Configuration et emplacement des fichiers
- Scripts :
scripts/à côté de ce fichier. Exécutez-les avecpython <skill-dir>/scripts/<name>.py .... - Données :
~/cedh-playgroup/(remplacez avec la variable d'environnementCEDH_PLAYGROUP_DIR).roster.json,games.json,notes.json,availability.jsonetcache/tournaments.json(le cache TopDeck). Ce sont du JSON simple, vous pouvez donc les montrer à l'utilisateur ou les laisser modifier à la main. - Clé API TopDeck : variable d'environnement
TOPDECK_API_KEY. Elle est gratuite sur https://topdeck.gg/account. Si elle est absente, dites-le et expliquez comment la configurer. Ne demandez pas à l'utilisateur de coller la clé dans le chat.
L'attribution est une condition de l'API TopDeck. Chaque réponse qui utilise des données de tournoi se termine par : Données de tournoi provenant de TopDeck.gg (https://topdeck.gg). Les scripts l'affichent. Gardez-la lorsque vous résumez.
Fraîcheur : synchronisation d'abord
TopDeck n'a pas de point de terminaison « résultats pour le joueur X ». sync.py récupère tous les tournois EDH terminés dans une fenêtre de dates, et toutes les statistiques de joueurs et de méta proviennent de ce cache. Avant un rapport de méta, des statistiques de joueurs ou des pods, vérifiez l'âge du cache (la liste synced dans cache/tournaments.json). S'il a plus d'environ un jour, ou ne couvre pas la fenêtre dont vous avez besoin, synchronisez :
python scripts/sync.py # 30 derniers jours, récupéré semaine par semaine
python scripts/sync.py --days 60 # également nécessaire pour la colonne de tendance « Δ share » du méta
python scripts/sync.py --import saved_response.json # hors ligne / test
Le point de terminaison en masse est limité en débit. Le script gère lui-même le backoff sur HTTP 429, laissez-le donc s'exécuter. Une synchronisation de 30 jours peut prendre une minute ou deux.
1. Joueurs
python scripts/playgroup.py add-player "Eric" --topdeck https://topdeck.gg/profile/<id> --deck kinnan
python scripts/playgroup.py set-decks "Sam" --deck najeela --deck "tymna kraum" --primary najeela
python scripts/playgroup.py set-decks "Lee" --deck "magda" --add # ajouter sans remplacer
python scripts/playgroup.py set-decks "Jo" --deck glarb --gauntlet-pilot yes
python scripts/playgroup.py remove-player "Max"
python scripts/analyze.py players # tout le monde ; ou : players Eric Sam
--topdeckprend un lien de profil, sous forme (topdeck.gg/profile/<id>outopdeck.gg/profile/%40handle), un@handle, ou un identifiant brut. Les classements de tournois ne connaissent que l'ID brut du joueur, donc le script ouvre la page de profil et lit l'ID à partir de sa balise metaplayer-id. Il imprime le nom d'affichage TopDeck qu'il a trouvé. Si ce nom ne ressemble pas à la personne que l'utilisateur voulait, dites-le. Si la recherche échoue (hors ligne), il stocke ce qui a été donné et émet un avertissement. Ré-ajoutez le joueur plus tard pour que ses statistiques correspondent. Si l'utilisateur ne donne qu'un nom, demandez le lien de son profil TopDeck. La correspondance par nom d'affichage peut sélectionner des inconnus portant le même nom.- Les noms de commandants sont mis en correspondance floue avec l'orthographe de TopDeck (« tymna kraum » → « Tymna the Weaver / Kraum, Ludevic's Opus »). Le script imprime la correspondance choisie. S'il liste des alternatives, confirmez avec l'utilisateur.
playgroup.py resolve <nom>vérifie un nom sans rien sauvegarder. - Un pilote de gauntlet est prêt à jouer l'un des decks partagés du groupe au lieu du sien. C'est ainsi que les decks du haut du méta que personne ne possède se retrouvent dans les pods.
- Un joueur avec zéro événement TopDeck dans la fenêtre n'est pas une erreur. Il n'a simplement pas joué d'événement suivi récemment. Proposez
sync.py --days 90pour plus d'historique.
Lorsque vous signalez les joueurs, commencez par ce qui est utile pour l'entraînement : deck actuel, forme récente (score et classements), et ce que dit leur journal d'entraînement. Ne vous contentez pas de réimprimer le tableau.
2. Rapport de méta
python scripts/analyze.py meta # 30 jours, événements de 16+ joueurs, top 25
python scripts/analyze.py meta --days 14 --min-players 32 --top 15
python scripts/analyze.py matchups "kinnan" # contre qui ce deck gagne et perd
python scripts/analyze.py matchups --player Eric # la même chose, des propres tables d'Eric
Colonnes : entrées, part de méta, Δ part par rapport à la fenêtre égale précédente, taux de victoire, taux de match nul, conversion en top cut, et meilleur classement.
Trois perspectives sur le méta. Choisissez celle à laquelle la question se rapporte, ou montrez les perspectives locale et grande côte à côte lorsque l'utilisateur demande simplement « quel est le méta » :
| Perspective | Commande | Répond à |
|---|---|---|
| Locale | meta --local | Ce à quoi notre groupe sera réellement confronté : événements dans le rayon enregistré du domicile, toutes tailles, 30 derniers jours |
| Grands événements | meta --big | Ce qui gagne dans les grands tournois : plus de 100 joueurs, n'importe où, 90 derniers jours (ils sont rares) |
| Globale | meta | Tout sur TopDeck avec 16+ joueurs |
Définissez la zone de domicile et le seuil « grand » une fois avec playgroup.py home --zip 18201 --miles 100 --big-min 101, ou utilisez un --zip Z --miles M ponctuel. La vue locale utilise les coordonnées des événements TopDeck. Les événements en ligne et les événements sans localisation ne peuvent pas être placés, et le rapport indique combien manquent. Les échantillons locaux sont petits, alors parlez de parts comme de « qui se présente » et de taux de victoire comme d'indices. Là où les perspectives locale et grande divergent, c'est la partie utile : un deck populaire localement mais faible dans les grands événements, ou un deck qui gagne de grands événements mais que personne près de chez vous ne joue encore. pods.py --local ou --big fait en sorte que « faire face au haut du méta » utilise cette perspective.
Bien lire le rapport est plus important que l'imprimer :
- Les taux de victoire sont des chiffres à quatre joueurs. Environ 25 % est la moyenne, et plus basse une fois les matchs nuls comptés. Le rapport imprime la moyenne observée de la fenêtre. Un deck à 30 % est très fort. Ne lisez jamais les taux de victoire par rapport à 50 %.
- Les petits échantillons mentent. En dessous d'environ 20 entrées, ou environ 10 tables partagées dans
matchups, qualifiez un nombre d'indice, pas de résultat. - La popularité (part) et la force (taux de victoire, conversion) sont des questions différentes. Signalez les decks qui surperforment leur part, et les decks populaires qui convertissent mal.
--min-players 16garde les petits locaux hors de la vue du méta. Si l'utilisateur pose des questions sur sa scène locale, abaissez-le.- Intégrez les
notes.jsondu groupe lorsque c'est pertinent (« vous avez noté beaucoup de Magda à la boutique, et c'est aussi en hausse de 2 % au niveau mondial »).
Formulez la réponse comme suit : 3 à 5 points clés, puis le tableau (réduit à l'essentiel), puis ce que cela signifie pour l'entraînement de ce groupe (par exemple, « personne ici ne possède de Najeela, et c'est le n°3 ; cela vaut la peine d'en avoir une copie pour le gauntlet »).
3. Saisie : résultats, decks, notes, disponibilités
python scripts/playgroup.py log-game --date 2026-11-08 \
--seat "Eric=Kinnan" --seat "Sam=Najeela" --seat "Lee=Tymna Kraum" --seat "Kim=Yuriko" \
--winner Sam # ou --winner draw ; ajoutez --no-order si l'ordre de tour est inconnu
python scripts/playgroup.py note "Beaucoup de Magda à la boutique dernièrement" --author Eric --tag meta
python scripts/playgroup.py avail 2026-11-08 Eric Sam Lee Kim Jo # --replace pour écraser
python scripts/playgroup.py gauntlet-deck add "Najeela" --list <url>
python scripts/playgroup.py show games # roster | games | notes | avail
Les gens rapportent les résultats de manière informelle (« sam a gagné sur najeela, moi lee et kim sur kinnan tymna yuriko, puis un match nul »). Transformez chaque partie en un appel log-game.
L'ordre des sièges est l'ordre des tours, et il compte : sur les tables à 4 joueurs de TopDeck, le siège 1 gagne environ 23 % et le siège 4 environ 14 %. Listez les --seats dans l'ordre des tours (siège 1 en premier). Si le rapport ne clarifie pas l'ordre des tours, demandez une fois (« qui a joué en premier ? »). S'ils ne le savent pas, enregistrez avec --no-order. La partie compte toujours pour les scores et les matchs, mais pas pour les statistiques de siège. Dites au groupe le meilleur format de rapport, car il alimente le profil de siège de chacun : G1 (ordre de tour) : Eric Kinnan, Sam Najeela, Lee Tymna/Kraum, Kim Yuriko. Gagnant Sam. Si quoi que ce soit qui modifie les statistiques est ambigu, comme qui a gagné ou sur quel deck quelqu'un était, demandez avant d'enregistrer. Ensuite, relisez ce qui a été enregistré en une ligne par partie pour que les erreurs soient détectées.
Si l'utilisateur colle plusieurs parties, enregistrez-les toutes, puis résumez la soirée : qui a gagné quoi, et les éventuelles séries en cours.
4. Pods d'entraînement
Qui joue cette session
La participation change chaque semaine, alors établissez qui est présent avant de constituer les pods. Par ordre de préférence :
- L'utilisateur nomme des personnes (« tout le monde sauf Jeff », « Eric, Ryan, Saige, Alex »).
- Une liste déjà sauvegardée pour cette date (
playgroup.py show avail). - Demandez. Si votre client dispose d'un outil de question à choix multiples, listez le roster sous forme de cases à cocher, répartissez-le en plusieurs questions si les noms sont plus nombreux que ce qu'une question permet, et demandez aussi la date. Sinon, demandez en une ligne.
Sauvegardez la réponse pour que les pods, le post Discord et les rapports ultérieurs soient cohérents :
python scripts/playgroup.py avail 2026-11-08 --all --remove Jeff Saige # tout le monde sauf
python scripts/playgroup.py avail 2026-11-08 Ishmael # ajouter un oui tardif
python scripts/playgroup.py avail 2026-11-08 --remove Ryan # retirer un non tardif
python scripts/pods.py --date 2026-11-08 # construire depuis la liste sauvegardée
python scripts/pods.py --all --except Jeff # ponctuel, sans sauvegarder
Si la liste change après la publication des pods, reconstruisez et dites qui a été déplacé. Ne réattribuez pas silencieusement des places à des personnes qui ont déjà vu leur pod.
python scripts/pods.py --date 2026-11-08 # utilise la disponibilité de cette soirée
python scripts/pods.py --players Eric Sam Lee Kim Jo Ana Max
python scripts/pods.py --date 2026-11-08 --focus Eric # les matchs faibles d'Eric comptent 4x
python scripts/pods.py --date 2026-11-08 --deck "Sam=Tymna Kraum" --w-repeat 0
Le constructeur explore les attributions de sièges et les choix de decks et les évalue selon quatre objectifs, tous activés par défaut. Désactivez un objectif avec son poids à 0, ou augmentez-le pour le mettre en valeur :
| Objectif | Drapeau | Ce qu'il récompense |
|---|---|---|
| Faire face au haut du méta | --w-meta | decks du top-N du méta à chaque table (--top-meta 15) |
| Pods équilibrés | --w-balance | force moyenne similaire (score du joueur + taux de victoire du deck) par pod |
| Éviter les répétitions | --w-repeat | ne pas réattribuer les paires qui se sont assises ensemble dans des parties récentes enregistrées |
| Cibler les matchs faibles | --w-matchup | placer un joueur face à des decks contre lesquels il perd (voir ci-dessous) |
Les mauvais matchs de qui ? « Travailler mes mauvais matchs » concerne la personne, pas le deck. Le constructeur estime le taux de victoire de chaque joueur contre chaque commandant adverse à partir de ses propres tables TopDeck et de ses parties d'entraînement. Ce sont de petits échantillons, donc il les réduit vers la performance de ce deck sur l'ensemble du terrain dans le même appariement. Un pilote qui est 1/11 contre Rograkh/Thrasios est toujours considéré comme faible là-bas, même si les joueurs de Kinnan s'en sortent bien en général. Avant de constituer des pods pour quelqu'un qui a posé des questions sur ses matchs, regardez vous-même les preuves :
python scripts/analyze.py matchups --player Eric --days 90 # les propres tables d'Eric, toutes tailles d'événements
python scripts/analyze.py matchups kinnan # le deck sur l'ensemble du terrain, pour comparaison
Quand les deux divergent, dites-le clairement (« Kinnan va bien contre Najeela en général, mais vous êtes 0/3 contre celui de Sam »). C'est un coaching utile : l'écart vient des choix du joueur, pas du deck.
Sièges. Le constructeur définit également l'ordre des tours de chaque pod. Avec --seat-mode practice (par défaut), chaque joueur va dans le siège où son score est le plus faible par rapport à ce que ce siège gagne normalement. Être 0/6 au siège 2 est mauvais. Être 2/10 au siège 4 est à peu près dans la norme. --seat-mode best répète leurs meilleurs sièges, par exemple avant un tournoi, et random mélange simplement. Preuves de siège et de matchs par joueur :
python scripts/analyze.py profile # tout le monde ; ou : profile Eric Ryan
Expliquer les pods : c'est l'essentiel. Pour chaque siège, le script imprime le nombre de preuves du joueur, la lecture du siège (pire, meilleur, ou pas encore de lecture, avec le score et les points par rapport à la moyenne du siège), les matchs à cette table (« a besoin de pratique contre … » et « favorisé contre … », avec son propre score et le taux général), et les matchs faibles absents de cette table. Transformez cela en un court « pourquoi » basé sur les données par joueur, par exemple :
Siège 1 : Alex sur Tayam. Le siège 1 est le pire siège d'Alex (1/10, environ 7 points en dessous de ce que le siège 1 gagne habituellement), donc il s'entraîne ici. Il est également 0/7 contre Sisay en tournoi, et le Sisay de Darison est à cette table. Il est favorisé contre Ob Nixilis, donc c'est un match qu'il devrait gagner.
Règles pour ces explications :
- Citez les scores réels (1/10, 0/7). C'est ce qui les rend crédibles.
- Dites « échantillon léger » quand cela repose sur moins d'environ 6 parties. Ne vendez pas un 0/2 comme une certitude.
- Si un joueur n'a pas de données (pas de lien TopDeck, pas de parties enregistrées), dites que son siège est un espace réservé et que les rapports d'entraînement le rempliront. N'inventez pas de raison.
- Terminez avec ce que des données d'entraînement supplémentaires pourraient affiner. Chaque partie enregistrée dans l'ordre des tours améliore les lectures de siège et de matchs.
La taille des pods est de quatre, avec des trios absorbant le reste. Avec 5 joueurs, un reste sur la touche et tourne. Si l'utilisateur préfère jouer un pod de 5, dites que c'est son choix et placez tout le monde. La ligne « Sur la touche » de la sortie nomme qui doit tourner.
Présentez chaque pod avec pourquoi il est construit de cette façon, en langage clair : quels decks du méta ils verront, quel match faible chaque joueur est là pour pratiquer, et tout appariement répété qui n'a pas pu être évité. Les notes du script sont des matières premières. Choisissez le ou les deux qui comptent par pod, et ne les collez pas tous. Si un deck de gauntlet a été attribué, assurez-vous que le pilote le sait.