Community编程与开发github.com

cEDH 玩组管理

基于 TopDeck.gg 的赛事数据管理一个 cEDH(竞争性指挥官)玩组。支持添加玩家及其套牌、拉取赛事记录、汇报环境统计、记录对局练习、设置可用日期,以及自动生成和发布平衡的对局小组到 Discord。

cEDH 玩组管理 是什么?

本 AI Agent 技能旨在服务一个特定的 cEDH 玩组,通过整合本地记录和 TopDeck.gg 的赛事数据,实现四项核心任务:玩家管理、环境评估、练习记录和自动编组。技能会定期调取赛事缓存数据以确保新鲜度,并利用多个 Python 脚本(位于 `scripts/` 目录下)处理所有计算逻辑,包括套牌胜率、对位分析和座位顺序优化。用户可以通过自然语言指令触发各种操作,如添加玩家及其 TopDeck ID、查询环境报告(支持全局或本地视角)、记录对局结果、管理可用日期,以及自动生成平衡的练习小组。该技能特别强调对局小组的解释:为每个玩家提供数据驱动的座位建议、弱点对位分析和改进方向。最终结果可以自动发布到玩组的 Discord 频道。支持所有主流的 AI Agent 平台(如 Claude Code、Cursor、Codex 等),并严格遵守 TopDeck API 的归因要求。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ejw179/cedh-playgroup/tree/main/cedh-playgroup

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

cEDH 玩组管理 是做什么的?

本技能维护一个小型、可手动编辑的 cEDH 玩组记录,并结合 TopDeck.gg 的赛事数据。它有四大任务,外加将结果发布到玩组的 Discord:

  1. 玩家:通过 TopDeck 个人资料 ID 添加成员,并录入其拥有的套牌。
  2. 环境:默认统计过去 30 天的出场情况和胜率。
  3. 记录:记录练习结果、当前套牌、环境笔记和可用日期。
  4. 编组:安排练习对局,使玩组获得有效训练。

所有计算逻辑均由 scripts/ 目录下的 Python 脚本(仅限 Python 标准库)完成。您的任务是运行这些脚本、读取输出,并将其转化为玩组可用的建议。请勿手动重新计算统计数据。脚本会处理边缘情况(拍档名称、平局、小样本),重复计算可能导致不同结果。

设置与文件位置

  • 脚本:scripts/ 目录与本文件同级。运行方式为 python <技能目录>/scripts/<名称>.py ...。
  • 数据:~/cedh-playgroup/(可通过环境变量 CEDH_PLAYGROUP_DIR 覆盖)。包含 roster.json、games.json、notes.json、availability.json 以及 cache/tournaments.json(TopDeck 缓存)。这些均为纯 JSON 格式,因此可向用户展示或允许手动编辑。
  • TopDeck API 密钥:环境变量 TOPDECK_API_KEY。可免费在 https://topdeck.gg/account 获取。如果缺失,请告知用户并说明如何设置。请勿要求用户将密钥粘贴到对话中。

使用 TopDeck API 必须注明出处。 每个引用赛事数据的回答均需以以下内容结尾:*赛事数据来自 TopDeck.gg (https://topdeck.gg)*。脚本会打印该信息,汇总时请保留。

数据新鲜度:先同步

TopDeck 没有“某个玩家的结果”端点。sync.py 会拉取指定时间窗口内所有已完成的 EDH 赛事,所有玩家和环境统计数据均来自该缓存。在进行环境报告、玩家统计或编组之前,请检查缓存的新鲜度(cache/tournaments.json 中的 synced 列表)。如果缓存超过约一天,或未涵盖所需时间窗口,请运行同步:

python scripts/sync.py              # 最近 30 天,按周分批拉取
python scripts/sync.py --days 60    # 环境趋势列“Δ 占比”也需要此范围
python scripts/sync.py --import saved_response.json   # 离线/测试模式

批量端点有速率限制。脚本会在收到 HTTP 429 时自动退避,因此请让它运行完成。30 天同步可能需要一两分钟。

1. 玩家

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      # 追加,不替换
python scripts/playgroup.py set-decks "Jo" --deck glarb --gauntlet-pilot yes
python scripts/playgroup.py remove-player "Max"
python scripts/analyze.py players            # 显示所有人;或指定:players Eric Sam
  • --topdeck 接受个人资料链接(topdeck.gg/profile/<id> 或 topdeck.gg/profile/%40handle)、@handle 格式或纯 ID。赛事排名仅显示原始玩家 ID,因此脚本会打开个人资料页面并从其 player-id meta 标签中读取 ID。它会打印找到的 TopDeck 显示名称。如果该名称与用户所指的人不符,请说明。如果查找失败(离线),它会存储所提供的内容并发出警告。稍后请重新添加该玩家,以便其统计数据匹配。如果用户仅提供姓名,请询问其 TopDeck 个人资料链接。按显示名称匹配可能会匹配到同名陌生人。
  • 指挥官名称会模糊匹配至 TopDeck 的拼写(“tymna kraum” → “Tymna the Weaver / Kraum, Ludevic's Opus”)。脚本会打印它选择的匹配项。如果列出的备选项,请与用户确认。playgroup.py resolve <name> 可检查名称而不保存任何内容。
  • 高难模式驾驶员愿意使用玩组共享套牌之一,而非自己的套牌。这样,无人拥有的顶级环境套牌也能出现在对局中。
  • 某玩家在时间窗口内无 TopDeck 赛事记录并非错误。他们只是近期未参加可追踪的比赛。如需更多历史数据,建议运行 sync.py --days 90。

报告玩家时,应优先展示对练习有用的信息:当前套牌、近期状态(战绩和名次)以及练习记录的内容。请勿仅重印表格。

2. 环境报告

python scripts/analyze.py meta                       # 30 天,16+ 人赛事,前 25
python scripts/analyze.py meta --days 14 --min-players 32 --top 15
python scripts/analyze.py matchups "kinnan"          # 该套牌的优劣势对位
python scripts/analyze.py matchups --player Eric     # 仅基于 Eric 个人对局的同一分析

列项:参赛数、环境占比、与上一等长窗口的占比变化、胜率、平局率、顶尖轮次晋级率、最佳名次。

三种环境视角。 根据问题选择其一,或当用户仅询问“当前环境”时,并列展示本地与大环境:

视角命令解答
本地meta --local玩组实际面对的环境:家附近半径内的事件,所有规模,最近 30 天
大赛meta --big大型赛事中的胜出套牌:超过 100 人,任何地点,最近 90 天(因此类赛事较少)
全局metaTopDeck 上所有 16 人以上的事件

一次性设置本地区域和“大赛”阈值:playgroup.py home --zip 18201 --miles 100 --big-min 101,或使用一次性 --zip Z --miles M。本地视角使用 TopDeck 的事件坐标。线上事件和未标注地点的事件无法定位,报告会注明缺失数量。本地样本较小,因此将占比称为“谁出现了”,胜率称为线索。当本地与大环境数据不一致时,这恰恰是价值所在:某套牌本地流行但大赛表现弱,或某套牌在大赛中胜出但本地无人使用。pods.py --local 或 --big 可使“面对顶级环境”使用相应视角。

正确解读比打印更重要:

  • 胜率是四人局数字。 约 25% 为平均水平,计入平局后会更低。报告会打印窗口内观察到的平均值。30% 胜率的套牌非常强。切勿将胜率与 50% 比较。
  • 小样本不可信。 低于约 20 条参赛记录,或 matchups 中少于约 10 个共享对局时,应将数字视为线索而非结论。
  • 热度(占比)和强度(胜率、晋级率)是不同问题。指出超出占比表现的套牌,以及热度高但晋级率低的套牌。
  • --min-players 16 将小型本地赛事排除出环境视图。如果用户询问本地环境,可降低该值。
  • 在相关时引用玩组自己的 notes.json(例如“您注意到本地牌店 Magda 很多,它全球占比也上升了 2%”)。

将答案组织为:3-5 条要点总结,然后是表格(精简至重点),最后说明对玩组练习的意义(例如“没人拥有 Najeela,但它是第三名;值得准备一套高难模式套牌”)。

3. 记录:结果、套牌、笔记、可用日期

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                     # 或 --winner draw;若座位顺序未知则添加 --no-order
python scripts/playgroup.py note "Lots of Magda at the LGS lately" --author Eric --tag meta
python scripts/playgroup.py avail 2026-11-08 Eric Sam Lee Kim Jo      # 使用 --replace 覆盖
python scripts/playgroup.py gauntlet-deck add "Najeela" --list <url>
python scripts/playgroup.py show games      # roster | games | notes | avail

玩家会随意报告结果(“sam 用 najeela 赢了,我和 lee 和 kim 分别用 kinnan、tymna、yuriko,然后有一局平局”)。请将每局转换为一次 log-game 调用。

座位顺序即行动顺序,这很重要:根据 TopDeck 的四人对局数据,座位 1 胜率约 23%,座位 4 约 14%。请按行动顺序列出 --seat(座位 1 优先)。如果报告未明确行动顺序,一次询问“谁先手?”。如果玩家不知道,使用 --no-order 记录。该对局仍会计入战绩和对位,但不计入座位统计。请告知玩组最佳报告格式,因为它会影响每个人的座位档案:G1 (行动顺序): Eric Kinnan, Sam Najeela, Lee Tymna/Kraum, Kim Yuriko. Winner Sam。如果任何影响统计的信息不明确(例如谁赢了或某人使用的套牌),请在记录前询问。记录后,按每对局一行回读已记录的内容,以便发现错误。

如果用户粘贴了多局比赛,全部记录后总结当晚情况:谁赢了什么局,以及任何连胜记录。

4. 练习对局

本次练习的参与者

每周出勤情况不同,因此在组建对局前确定参与者。优先顺序:

  1. 用户指定人员(“除了 Jeff”、“Eric, Ryan, Saige, Alex”)。
  2. 已为该日期保存的列表(playgroup.py show avail)。
  3. 询问。如果您的客户端有选择题工具,请将成员列表显示为复选框(若名单超过单次问题允许的数量则拆分),并同时询问日期。否则,请用一行文字询问。

保存答案,以便对局安排、Discord 帖子和后续报告保持一致:

python scripts/playgroup.py avail 2026-11-08 --all --remove Jeff Saige   # 除指定人员外全部参加
python scripts/playgroup.py avail 2026-11-08 Ishmael                      # 添加迟到确认的“是”
python scripts/playgroup.py avail 2026-11-08 --remove Ryan                # 取消迟到确认的“否”
python scripts/pods.py --date 2026-11-08                                  # 基于已保存列表编组
python scripts/pods.py --all --except Jeff                                # 一次性编组,不保存

如果名单在对局发布后发生变化,请重新编组并说明谁被调整了。不要悄无声息地重新安排已经看到自己对局的玩家。

python scripts/pods.py --date 2026-11-08               # 使用当晚的可用性
python scripts/pods.py --players Eric Sam Lee Kim Jo Ana Max
python scripts/pods.py --date 2026-11-08 --focus Eric  # Eric 的弱势对位权重乘以 4
python scripts/pods.py --date 2026-11-08 --deck "Sam=Tymna Kraum" --w-repeat 0

编组器会搜索座位安排和套牌选择,并根据四个目标进行评分(默认全部启用)。将某目标的权重设为 0 可禁用,提高权重可强调该目标:

目标参数奖励条件
面对顶级环境--w-meta每张桌上安排顶级环境套牌(--top-meta 15)
平衡对局--w-balance每桌平均强度(玩家战绩 + 套牌胜率)相近
避免重复--w-repeat避免在最近对局记录中坐在一起过的两人再次同坐
针对弱势对位--w-matchup安排玩家与他们输过的套牌对坐(见下文)

针对谁的弱势对位? “练习我的弱势对位”是针对个人而非套牌。编组器根据每位玩家自己的 TopDeck 对局和练习对局,估算其面对每个对手指挥官的胜率。样本较小,因此会向该对位在整个环境中该套牌的表现收缩。即使 Kinnan 玩家整体上对 Rograkh/Thrasios 表现尚可,某位玩家若在该对位中 1/11 战绩,仍会被视为弱势。在为询问自己对位问题的玩家编组前,请亲自查看证据:

python scripts/analyze.py matchups --player Eric --days 90   # Eric 个人的对局,所有赛事规模
python scripts/analyze.py matchups kinnan                    # 该套牌在环境中的整体表现,作为对比

当两者不一致时,请直说(“Kinnan 整体对付 Najeela 不差,但你对 Sam 的战绩是 0/3”)。这是有用的指导:差距在于玩家的操作,而非套牌本身。

座位安排。 编组器还会设置每桌的行动顺序。使用 --seat-mode practice(默认)时,每位玩家会被安排在其战绩相对于该位置正常胜率最弱的座位上。座位 2 的战绩为 0/6 很差。座位 4 的战绩为 2/10 则属于正常。--seat-mode best 用于演练其最佳座位(例如赛前),random 则随机安排。每位玩家的座位和对位证据:

python scripts/analyze.py profile            # 所有人;或:profile Eric Ryan

解释对局安排:这是关键。 对于每个座位,脚本会打印玩家的证据数量、座位分析(最差、最佳或尚无结论,附战绩和与座位平均值的偏差)、本桌对位(“需练习 vs …”和“优势 vs …”,附个人战绩和环境数据),以及未出现在本桌的弱势对位。请将其转化为每位玩家的简短、数据驱动的“为什么”,例如:

座位 1: Alex 使用 Tayam。 座位 1 是 Alex 最差的座位(1/10,比座位 1 正常胜率低约 7 点),因此他在这里练习。他在赛事中面对 Sisay 的战绩为 0/7,而 Darison 的 Sisay 就在本桌。他对 Ob Nixilis 有优势,这是理应赢的对局。

解释规则:

  • 引用实际战绩(1/10, 0/7)。这是可信度的来源。
  • 当依据少于约 6 局时,说明“样本量较小”。不要夸大 0/2 的战绩。
  • 如果某玩家没有数据(无 TopDeck 链接,无练习对局记录),说明该座位为占位符,后续练习报告会填充。不要编造理由。
  • 以更多练习数据能优化什么作为结尾。每场记录了行动顺序的练习都能改善座位和对位分析。

成组规模为四人桌,剩余人数组成三人桌。若有 5 人,一人轮空并轮流替换。如果用户更愿意玩五人局,告知由他们决定并安排所有人就坐。输出中的“轮空”行会标明该轮空的人。

用通俗语言说明每个对局的构建理由:他们将面对哪些环境套牌、每位玩家在此练习哪个弱势对位、以及任何无法避免的重复配对。脚本的注释是原始素材,请为每桌挑选一两个重点,不要全部粘贴。如果分配了高难模式套牌,请确保驾驶员知晓。

…

[翻译内容已截断]

相关技能