Playgroup cEDH
Esta skill mantém um registro pequeno e editável manualmente de um playgroup de cEDH e o combina com dados de torneios do TopDeck.gg. Ela tem quatro tarefas principais, além de publicar seus resultados no Discord do grupo:
- Jogadores: adicionar pessoas pelo ID do perfil do TopDeck, junto com os decks que possuem.
- Meta: o que está sendo jogado e o que está vencendo, últimos 30 dias por padrão.
- Entrada: resultados de prática, decks atuais, notas do meta, disponibilidade.
- Pods: montar uma noite de prática para que o grupo tenha repetições úteis.
Toda a aritmética reside em scripts Python em scripts/ (apenas stdlib). Seu trabalho é executá-los, ler a saída e transformá-la em conselhos que o grupo possa usar. Não recalcule estatísticas manualmente. Os scripts lidam com os casos extremos (nomes de parceiros, empates, amostras pequenas), e fazer duas vezes corre o risco de obter duas respostas diferentes.
Configuração e onde as coisas ficam
- Scripts:
scripts/ao lado deste arquivo. Execute comopython <diretório-da-skill>/scripts/<nome>.py .... - Dados:
~/cedh-playgroup/(substitua com a variável de ambienteCEDH_PLAYGROUP_DIR).roster.json,games.json,notes.json,availability.json, ecache/tournaments.json(a extração do TopDeck). São JSON simples, então é permitido mostrá-los ao usuário ou deixá-los editar manualmente. - Chave da API do TopDeck: variável de ambiente
TOPDECK_API_KEY. É gratuita em https://topdeck.gg/account. Se estiver faltando, informe e explique como configurá-la. Não peça ao usuário para colar a chave no chat.
A atribuição é uma condição da API do TopDeck. Toda resposta que usar dados de torneios termina com: Dados de torneio do TopDeck.gg (https://topdeck.gg). Os scripts a imprimem. Mantenha-a ao resumir.
Atualização: sincronize primeiro
O TopDeck não tem um endpoint de "resultados para o jogador X". sync.py extrai todos os torneios EDH concluídos em uma janela de datas, e todas as estatísticas de jogadores e meta vêm desse cache. Antes de um relatório de meta, estatísticas de jogadores ou pods, verifique a idade do cache (a lista synced em cache/tournaments.json). Se for mais antigo que cerca de um dia, ou não cobrir a janela necessária, sincronize:
python scripts/sync.py # últimos 30 dias, buscado uma semana de cada vez
python scripts/sync.py --days 60 # também necessário para a coluna de tendência "Δ share" do meta
python scripts/sync.py --import saved_response.json # offline / teste
O endpoint em massa tem limitação de taxa. O script faz backoff em HTTP 429 sozinho, então deixe-o executar. Uma sincronização de 30 dias pode levar um ou dois minutos.
1. Jogadores
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 # adicionar sem substituir
python scripts/playgroup.py set-decks "Jo" --deck glarb --gauntlet-pilot sim
python scripts/playgroup.py remove-player "Max"
python scripts/analyze.py players # todos; ou: players Eric Sam
--topdeckaceita um link de perfil, em qualquer forma (topdeck.gg/profile/<id>outopdeck.gg/profile/%40handle), um@handle, ou um ID simples. As classificações de torneios só conhecem o ID bruto do jogador, então o script abre a página do perfil e lê o ID de sua meta tagplayer-id. Ele imprime o nome de exibição do TopDeck que encontrou. Se esse nome não parecer com a pessoa que o usuário quis dizer, informe. Se a consulta falhar (offline), armazena o que foi fornecido e avisa. Re-adicione o jogador mais tarde para que suas estatísticas correspondam. Se o usuário fornecer apenas um nome, peça o link do perfil do TopDeck. A correspondência por nome de exibição pode pegar estranhos com o mesmo nome.- Nomes de comandantes são correspondidos de forma difusa à grafia do TopDeck ("tymna kraum" →
"Tymna the Weaver / Kraum, Ludevic's Opus"). O script imprime a correspondência que escolheu.
Se listar alternativas, confirme com o usuário.
playgroup.py resolve <nome>verifica um nome sem salvar nada. - Um piloto de gauntlet está disposto a jogar um dos decks compartilhados do grupo em vez do seu próprio. É assim que decks de topo de meta que ninguém possui acabam nos pods.
- Um jogador com zero eventos no TopDeck na janela não é um erro. Ele simplesmente não jogou um
evento rastreado recentemente. Ofereça
sync.py --days 90para mais histórico.
Ao relatar jogadores, liderar com o que é útil para a prática: deck atual, forma recente (registro e colocações), e o que o log de prática deles diz. Não apenas reimprima a tabela.
2. Relatório de meta
python scripts/analyze.py meta # 30 dias, eventos de 16+ jogadores, top 25
python scripts/analyze.py meta --days 14 --min-players 32 --top 15
python scripts/analyze.py matchups "kinnan" # contra quem este deck ganha e perde
python scripts/analyze.py matchups --player Eric # o mesmo, das mesas do próprio jogador
Colunas: entradas, participação no meta, Δ participação em relação à janela igual anterior, taxa de vitórias, taxa de empates, conversão em top-cut e melhor colocação.
Três lentes para o meta. Escolha aquela sobre a qual a pergunta é, ou mostre local e grande lado a lado quando o usuário apenas perguntar "qual é o meta":
| Lente | Comando | Respostas |
|---|---|---|
| Local | meta --local | O que nosso grupo realmente enfrentará: eventos dentro do raio salvo de casa, todos os tamanhos, últimos 30 dias |
| Grandes eventos | meta --big | O que vence em grandes torneios: mais de 100 jogadores, em qualquer lugar, últimos 90 dias (são raros) |
| Global | meta | Tudo no TopDeck com 16+ jogadores |
Defina a área de casa e o limite "grande" uma vez com
playgroup.py home --zip 18201 --miles 100 --big-min 101, ou use um único
--zip Z --miles M. A visão local usa as coordenadas de evento do TopDeck. Eventos online e eventos sem localização não podem ser colocados, e o relatório diz quantos estão faltando. Amostras locais são pequenas, então chame as participações de "quem aparece" e as taxas de vitórias de dicas. Onde local e grande discordam, essa é a parte útil: um deck popular localmente, mas fraco em grandes eventos, ou um que vence grandes eventos, mas ninguém perto de você ainda o joga. pods.py --local ou --big faz "enfrentar o topo do meta" usar essa lente.
Ler bem importa mais do que imprimir:
- Taxas de vitórias são números de quatro jogadores. Cerca de 25% é a média, e menor uma vez que os empates são contados. O relatório imprime a média observada na janela. Um deck de 30% é muito forte. Nunca leia taxas de vitórias contra 50%.
- Amostras pequenas mentem. Abaixo de cerca de 20 entradas, ou cerca de 10 mesas compartilhadas em
matchups, chame um número de dica, não de conclusão. - Popularidade (participação) e força (taxa de vitórias, conversão) são perguntas diferentes. Aponte decks que superam sua participação e decks populares que convertem mal.
--min-players 16mantém pequenos locais fora da visão do meta. Se o usuário perguntar sobre sua cena local, abaixe-o.- Traga o
notes.jsondo próprio grupo onde for relevante ("você notou muitos Magda na LGS, e também subiu 2% globalmente").
Molde a resposta como: 3-5 pontos principais em bullets, depois a tabela (corte para o que importa), depois o que significa para a prática deste grupo (por exemplo, "ninguém aqui tem um Najeela, e é #3; vale uma cópia de gauntlet").
3. Entrada: resultados, decks, notas, disponibilidade
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; adicione --no-order se a ordem de turnos for desconhecida
python scripts/playgroup.py note "Muitos Magda na LGS ultimamente" --author Eric --tag meta
python scripts/playgroup.py avail 2026-11-08 Eric Sam Lee Kim Jo # --replace para sobrescrever
python scripts/playgroup.py gauntlet-deck add "Najeela" --list <url>
python scripts/playgroup.py show games # roster | games | notes | avail
As pessoas relatam resultados casualmente ("sam venceu com najeela, eu lee e kim com kinnan tymna yuriko, depois um empate"). Transforme cada jogo em uma chamada log-game.
A ordem dos assentos é a ordem dos turnos, e isso importa: nas mesas de 4 jogadores do TopDeck, o assento 1 vence cerca de 23% e o assento 4 cerca de 14%. Liste os --seats na ordem dos turnos (assento 1 primeiro). Se o relatório não deixar a ordem dos turnos clara, pergunte uma vez ("quem foi primeiro?"). Se eles não souberem, registre com --no-order. O jogo ainda conta para registros e matchups, apenas não para estatísticas de assento. Diga ao grupo o melhor formato de relatório, porque alimenta o perfil de assento de todos:
G1 (ordem de turnos): Eric Kinnan, Sam Najeela, Lee Tymna/Kraum, Kim Yuriko. Vencedor Sam.
Se algo que altere as estatísticas for ambíguo, como quem venceu ou com qual deck alguém estava, pergunte antes de registrar. Depois, leia de volta o que foi registrado em uma linha por jogo para que erros sejam detectados.
Se o usuário colar vários jogos, registre todos, depois resuma a noite: quem venceu o quê e quaisquer sequências em andamento.
4. Pods de prática
Quem está jogando nesta sessão
A presença muda toda semana, então defina quem está dentro antes de construir pods. Em ordem de preferência:
- O usuário nomeia as pessoas ("todos menos Jeff", "Eric, Ryan, Saige, Alex").
- Uma lista já salva para aquela data (
playgroup.py show avail). - Pergunte. Se seu cliente tiver uma ferramenta de pergunta de múltipla escolha, liste o roster como caixas de seleção, dividindo-o em várias perguntas se houver mais nomes do que uma pergunta permite, e pergunte a data também. Caso contrário, pergunte em uma linha.
Salve a resposta para que pods, postagem no Discord e relatórios posteriores concordem:
python scripts/playgroup.py avail 2026-11-08 --all --remove Jeff Saige # todos exceto
python scripts/playgroup.py avail 2026-11-08 Ishmael # adicionar um sim tardio
python scripts/playgroup.py avail 2026-11-08 --remove Ryan # remover um não tardio
python scripts/pods.py --date 2026-11-08 # construir a partir da lista salva
python scripts/pods.py --all --except Jeff # único, sem salvar
Se a lista mudar depois que os pods foram publicados, reconstrua e diga quem mudou. Não reassente silenciosamente pessoas que já viram seu pod.
python scripts/pods.py --date 2026-11-08 # usa a disponibilidade daquela noite
python scripts/pods.py --players Eric Sam Lee Kim Jo Ana Max
python scripts/pods.py --date 2026-11-08 --focus Eric # matchups fracos de Eric contam 4x
python scripts/pods.py --date 2026-11-08 --deck "Sam=Tymna Kraum" --w-repeat 0
O construtor pesquisa assentos e escolhas de deck e os pontua em quatro objetivos, todos ativados por padrão. Desative um objetivo com seu peso definido como 0, ou aumente-o para enfatizá-lo:
| Objetivo | Flag | O que recompensa |
|---|---|---|
| Enfrentar o topo do meta | --w-meta | Decks do topo do meta em cada mesa (--top-meta 15) |
| Pods equilibrados | --w-balance | Força média semelhante (registro do jogador + taxa de vitórias do deck) por pod |
| Evitar repetições | --w-repeat | Não reassentar pares que ficaram juntos em jogos registrados recentemente |
| Focar em matchups fracos | --w-matchup | Assentar um jogador contra decks com os quais eles perdem (veja abaixo) |
De quem são os maus matchups? "Trabalhar meus maus matchups" é sobre a pessoa, não o deck. O construtor estima a taxa de vitórias de cada jogador contra cada comandante oponente a partir de suas próprias mesas do TopDeck e jogos de prática. Essas são amostras pequenas, então ele as reduz em direção a como aquele deck se sai no campo geral na mesma combinação. Um piloto que está 1/11 contra Rograkh/Thrasios ainda conta como fraco ali, mesmo que jogadores de Kinnan se saiam bem contra isso no geral. Antes de construir pods para alguém que perguntou sobre seus matchups, olhe para a evidência você mesmo:
python scripts/analyze.py matchups --player Eric --days 90 # mesas do próprio Eric, todos os tamanhos de evento
python scripts/analyze.py matchups kinnan # o deck no campo geral, para contraste
Quando os dois discordam, diga claramente ("Kinnan é ok contra Najeela em geral, mas você está 0/3 contra o de Sam"). É um treinamento útil: a lacuna está nas linhas do jogador, não no deck.
Assentos. O construtor também define a ordem de turnos de cada pod. Com --seat-mode practice (o padrão), cada jogador vai no assento onde seu registro é mais fraco em relação ao que aquele assento normalmente vence. Estar 0/6 no assento 2 é ruim. Estar 2/10 no assento 4 é dentro do esperado. --seat-mode best ensaia seus melhores assentos, por exemplo antes de um torneio, e random apenas embaralha. Evidência de assento e matchup por jogador:
python scripts/analyze.py profile # todos; ou: profile Eric Ryan
Explicando os pods: este é o ponto. Para cada assento, o script imprime a contagem de evidências do jogador, leitura do assento (pior, melhor, ou nenhuma leitura ainda, com registro e pontos contra a média do assento), os matchups nesta mesa ("precisa de prática contra …" e "favorecido contra …", com seu registro e a taxa de campo), e matchups fracos não nesta mesa. Transforme isso em um breve "porquê" baseado em dados por jogador, por exemplo:
Assento 1: Alex com Tayam. O assento 1 é o pior assento de Alex (1/10, cerca de 7 pts abaixo do que o assento 1 normalmente vence), então ele o pratica aqui. Ele também está 0/7 contra Sisay em torneios, e o Sisay do Darison está nesta mesa. Ele é favorecido contra Ob Nixilis, então esse é um que ele deveria vencer.
Regras para essas explicações:
- Cite os registros reais (1/10, 0/7). Eles são o que torna isso crível.
- Diga "amostra pequena" quando se basear em menos de ~6 jogos. Não superestime um 0/2.
- Se um jogador não tiver dados (sem link do TopDeck, sem jogos registrados), diga que seu assento é um espaço reservado e que os relatórios de prática o preencherão. Não invente uma razão.
- Termine com o que mais dados de prática aprimorariam. Cada jogo registrado em ordem de turnos melhora as leituras de assento e matchup.
Os tamanhos dos pods são de quatro, com trios absorvendo o restante. Com 5 jogadores, um fica de fora e rotaciona. Se o usuário preferir jogar um pod de 5, diga que é uma escolha deles e assente todos. A linha "Sentando fora" da saída nomeia quem rotacionar.
Apresente cada pod com por que foi construído dessa forma, em linguagem simples: quais decks do meta eles verão, qual matchup fraco cada jogador está lá para praticar e qualquer par repetido que não pôde ser evitado. As notas do script são matéria-prima. Escolha um ou dois que importam por pod e não cole todos eles. Se um deck de gauntlet foi atribuído, certifique-se de que o piloto saiba.