roam/20220209144915-tutor.org
2023-02-24 23:00:28 -05:00

53 KiB
Raw Blame History

Tutor

A Python application backed by a SQLite database for tracking my Magic: The Gathering card collection.

https://git.phoenixinquis.net/correlr/tutor

Finding cards for a deck

Decklist Alive Shared via TopDecked MTG Main (100) 1 Serra Ascendant 1 Soul's Attendant 1 Ajani's Pridemate 1 Alabaster Mage 1 Grateful Apparition 1 Suture Priest 1 Trelasarra, Moon Dancer 1 Angel of Vitality 1 Celestial Unicorn 1 Evolution Sage 1 Lurking Roper 1 Spike Feeder 1 Splendor Mare 1 Armorcraft Judge 1 Bloom Hulk 1 Core Prowler 1 Lathiel, the Bounteous Dawn 1 Lightkeeper of Emeria 1 Hamza, Guardian of Arashin 1 Ajani Goldmane 1 The Wanderer 1 Blossoming Wreath 1 Condemn 1 Fortifying Draught 1 Healing Salve 1 Light of Hope 1 Divine Offering 1 Revitalize 1 Abuna's Chant 1 Angel's Mercy 1 Blunt the Assault 1 Congregate 1 Refreshing Rain 1 War Report 1 Corrosive Gale 1 Bond of Flourishing 1 Courage in Crisis 1 Survival Cache 1 Hunters' Feast 1 Primal Command 1 Wanderer's Strike 1 Planewide Celebration 1 Fountain of Youth 1 Elixir of Immortality 1 Golden Urn 1 Sol Ring 1 Soul Net 1 The Ozolith 1 Contagion Clasp 1 Throne of Geth 1 Marble Chalice 1 Staff of Domination 1 Soul Conduit 1 Lifelink 1 Spirit Link 1 Ajani's Mantra 1 Inner Sanctum 1 Luminous Wake 1 Faith's Fetters 1 First Response 1 Vigil for the Lost 1 Noble Purpose 1 Noble Stand 1 Celestial Mantle 1 Blossoming Sands 1 Command Tower 14 Forest 1 Karn's Bastion 16 Plains 1 Razorverge Thicket 1 Sunpetal Grove 1 Yavimaya Hollow

Shared via TopDecked MTG

https://www.topdecked.com/decks/alive/833c308f-219f-4624-8b32-1adedcb477f0

  INSERT INTO decks (deck_id, name) VALUES (2, 'Alive');

  INSERT INTO deck_cards (deck_id, oracle_id)
  SELECT DISTINCT 2, oracle_id FROM cards WHERE name IN
  (
  'Serra Ascendant',
  'Soul''s Attendant',
  'Ajani''s Pridemate',
  'Alabaster Mage',
  'Grateful Apparition',
  'Suture Priest',
  'Trelasarra, Moon Dancer',
  'Angel of Vitality',
  'Celestial Unicorn',
  'Evolution Sage',
  'Lurking Roper',
  'Spike Feeder',
  'Splendor Mare',
  'Armorcraft Judge',
  'Bloom Hulk',
  'Core Prowler',
  'Lathiel, the Bounteous Dawn',
  'Lightkeeper of Emeria',
  'Hamza, Guardian of Arashin',
  'Ajani Goldmane',
  'The Wanderer',
  'Blossoming Wreath',
  'Condemn',
  'Fortifying Draught',
  'Healing Salve',
  'Light of Hope',
  'Divine Offering',
  'Revitalize',
  'Abuna''s Chant',
  'Angel''s Mercy',
  'Blunt the Assault',
  'Congregate',
  'Refreshing Rain',
  'War Report',
  'Corrosive Gale',
  'Bond of Flourishing',
  'Courage in Crisis',
  'Survival Cache',
  'Hunters'' Feast',
  'Primal Command',
  'Wanderer''s Strike',
  'Planewide Celebration',
  'Fountain of Youth',
  'Elixir of Immortality',
  'Golden Urn',
  'Sol Ring',
  'Soul Net',
  'The Ozolith',
  'Contagion Clasp',
  'Throne of Geth',
  'Marble Chalice',
  'Staff of Domination',
  'Soul Conduit',
  'Lifelink',
  'Spirit Link',
  'Ajani''s Mantra',
  'Inner Sanctum',
  'Luminous Wake',
  'Faith''s Fetters',
  'First Response',
  'Vigil for the Lost',
  'Noble Purpose',
  'Noble Stand',
  'Celestial Mantle',
  'Blossoming Sands',
  'Command Tower',
  'Forest',
  'Karn''s Bastion',
  'Plains',
  'Razorverge Thicket',
  'Sunpetal Grove',
  'Yavimaya Hollow'
  );
Adding the deck list to the database
  SELECT set_code
       , release_date
       , color_identity
       , cards.name
       , type_line
       , sets.name
       , rarity
       , collection
    FROM deck_list
  JOIN cards USING(oracle_id)
  JOIN copies USING (scryfall_id)
  JOIN sets USING(set_code)
  WHERE deck_id = 13 AND type_line not like 'Basic Land%'
  GROUP BY set_code
       , release_date
       , color_identity
       , cards.name
       , type_line
       , sets.name
       , rarity
       , collection
  ORDER BY CASE WHEN rarity >= 'rare'::rarity THEN 0 ELSE 1 END   -- Is it in a binder?
         , CASE WHEN LENGTH(color_identity) > 1 THEN 0 ELSE 1 END -- Sort gold cards before mono-colored
         , color_identity
         , CASE WHEN rarity > 'rare'::rarity THEN 0 ELSE 1 END    -- Mythics are separated from rares in binders
         , release_date ASC, set_code                             -- Older cards are better organized in boxes
         , cards.name
Finding cards in the collection

Questions

  • Where are the cards in my collection I need to build a deck?
  • Which cards do I want in one deck that are currently in another?
  • Which cards do I need more copies of?
  • Which cards do I need that would improve specific decks?

Types

import Text -> (ValidCardNames, InvalidCardNames)
import Text -> (ValidCards, InvalidCards)
PreferredCard = PreferredCard { name: ValidCardName, card: Maybe ValidCard }
import Text -> ([PreferredCard], [InvalidCardNames])
decklist DeckName -> ValidCardNames -> DeckList
commanderDeckList -> DeckList -> Either InvalidCommanderDeck CommanderDecklist
Deck = Deck [PreferredCard]

Collection stats

  SELECT COUNT("copies"."id") AS cards
       , SUM(
             CASE WHEN "copies"."isFoil"
             THEN "card_prices"."usd_foil"
             ELSE "card_prices"."usd"
             END
         ) AS value
       , COUNT(DISTINCT cards.set_code) AS sets
  FROM "copies"
  JOIN "cards" USING ("scryfall_id")
  LEFT JOIN "card_prices" USING ("scryfall_id")
  WHERE "card_prices"."date" = (SELECT "value" FROM "vars" where "key" = 'last_update')
cards value sets
12871 7289.44 161
  SELECT COUNT("copies"."id") AS cards
  FROM "copies"
  JOIN "cards" USING ("scryfall_id")
  LEFT JOIN "card_prices" USING ("scryfall_id")
  WHERE "card_prices"."date" = (SELECT "value" FROM "vars" where "key" = 'last_update')
cards
12871
  select count(*) from copies
count
12871

Identifying and ordering sets

    SELECT s.set_code
         , s.name
         , COUNT(co.id) AS cards
         , MIN(c.release_date) AS release_date
      FROM sets AS s
      JOIN cards AS c USING (set_code)
      JOIN copies AS co USING (scryfall_id)
  GROUP BY s.set_code, s.name
  ORDER BY min(c.release_date) DESC
set_code name cards release_date
ONC Phyrexia: All Will Be One Commander 4 2023-02-03
ONE Phyrexia: All Will Be One 387 2023-02-03
DMR Dominaria Remastered 255 2023-01-13
J22 Jumpstart 2022 1 2022-12-02
BOT Transformers 14 2022-11-18
TBOT Transformers Tokens 1 2022-11-18
BRR The Brothers' War Retro Artifacts 58 2022-11-18
BRO The Brothers' War 203 2022-11-18
BRC The Brothers' War Commander 210 2022-11-18
UNF Unfinity 42 2022-10-07
DMU Dominaria United 218 2022-09-09
DMC Dominaria United Commander 35 2022-09-09
P30A 30th Anniversary Play Promos 2 2022-09-02
2X2 Double Masters 2022 459 2022-07-08
CLB Commander Legends: Battle for Baldur's Gate 94 2022-06-10
NCC New Capenna Commander 2 2022-04-29
SNC Streets of New Capenna 203 2022-04-29
SLX Universes Within 3 2022-03-03
NEC Neon Dynasty Commander 14 2022-02-18
NEO Kamigawa: Neon Dynasty 857 2022-02-18
VOW Innistrad: Crimson Vow 105 2021-11-19
VOC Crimson Vow Commander 1 2021-11-19
MID Innistrad: Midnight Hunt 15 2021-09-24
CMB2 Mystery Booster Playtest Cards 2021 3 2021-08-20
OAFC Forgotten Realms Commander Display Commanders 1 2021-07-23
AAFR Adventures in the Forgotten Realms Art Series 3 2021-07-23
AFC Forgotten Realms Commander 70 2021-07-23
AFR Adventures in the Forgotten Realms 214 2021-07-23
PLG21 Love Your LGS 2021 1 2021-06-22
MH2 Modern Horizons 2 27 2021-06-18
STX Strixhaven: School of Mages 383 2021-04-23
TSTX Strixhaven: School of Mages Tokens 6 2021-04-23
STA Strixhaven Mystical Archive 30 2021-04-23
C21 Commander 2021 75 2021-04-23
OC21 Commander 2021 Display Commanders 1 2021-04-23
TSR Time Spiral Remastered 3 2021-03-19
TKHM Kaldheim Tokens 1 2021-02-05
KHC Kaldheim Commander 59 2021-02-05
KHM Kaldheim 174 2021-02-05
CMR Commander Legends 481 2020-11-20
PLIST The List 8 2020-09-26
ZNC Zendikar Rising Commander 77 2020-09-25
ZNR Zendikar Rising 54 2020-09-25
2XM Double Masters 2 2020-08-07
JMP Jumpstart 2 2020-07-17
M21 Core Set 2021 5 2020-07-03
PLG20 Love Your LGS 2020 1 2020-05-18
IKO Ikoria: Lair of Behemoths 560 2020-04-24
C20 Commander 2020 1 2020-04-17
TTHB Theros Beyond Death Tokens 1 2020-01-24
THB Theros Beyond Death 96 2020-01-24
SLD Secret Lair Drop 10 2019-12-16
MB1 Mystery Booster 42 2019-11-07
ELD Throne of Eldraine 148 2019-10-04
C19 Commander 2019 101 2019-08-23
PM20 Core Set 2020 Promos 1 2019-07-12
M20 Core Set 2020 600 2019-07-12
SS2 Signature Spellbook: Gideon 2 2019-06-28
WAR War of the Spark 544 2019-05-03
TWAR War of the Spark Tokens 36 2019-05-03
RNA Ravnica Allegiance 17 2019-01-25
PRNA Ravnica Allegiance Promos 1 2019-01-25
GRN Guilds of Ravnica 127 2018-10-05
C18 Commander 2018 3 2018-08-09
M19 Core Set 2019 2 2018-07-13
BBD Battlebond 1 2018-06-08
TDOM Dominaria Tokens 1 2018-04-27
DOM Dominaria 18 2018-04-27
TRIX Rivals of Ixalan Tokens 1 2018-01-19
RIX Rivals of Ixalan 29 2018-01-19
UST Unstable 119 2017-12-08
E02 Explorers of Ixalan 1 2017-11-24
IMA Iconic Masters 1 2017-11-17
XLN Ixalan 2 2017-09-29
C17 Commander 2017 2 2017-08-25
THOU Hour of Devastation Tokens 1 2017-07-14
HOU Hour of Devastation 29 2017-07-14
E01 Archenemy: Nicol Bolas 1 2017-06-16
CMA Commander Anthology 1 2017-06-09
MM3 Modern Masters 2017 3 2017-03-17
AER Aether Revolt 3 2017-01-20
C16 Commander 2016 2 2016-11-11
PKLD Kaladesh Promos 1 2016-09-30
KLD Kaladesh 68 2016-09-30
EMN Eldritch Moon 1 2016-07-22
SOI Shadows over Innistrad 1 2016-04-08
C15 Commander 2015 1 2015-11-13
ORI Magic Origins 1 2015-07-17
C14 Commander 2014 1 2014-11-07
M15 Magic 2015 44 2014-07-18
BNG Born of the Gods 1 2014-02-07
C13 Commander 2013 1 2013-11-01
THS Theros 30 2013-09-27
M14 Magic 2014 2 2013-07-19
GTC Gatecrash 1 2013-02-01
RTR Return to Ravnica 30 2012-10-05
M13 Magic 2013 91 2012-07-13
AVR Avacyn Restored 48 2012-05-04
DKA Dark Ascension 52 2012-02-03
ISD Innistrad 355 2011-09-30
V11 From the Vault: Legends 1 2011-08-26
M12 Magic 2012 244 2011-07-15
NPH New Phyrexia 245 2011-05-13
MBS Mirrodin Besieged 371 2011-02-04
PMBS Mirrodin Besieged Promos 1 2011-02-03
SOM Scars of Mirrodin 325 2010-10-01
PSOM Scars of Mirrodin Promos 1 2010-09-30
M11 Magic 2011 320 2010-07-16
ROE Rise of the Eldrazi 329 2010-04-23
PWWK Worldwake Promos 2 2010-02-05
WWK Worldwake 149 2010-02-05
F10 Friday Night Magic 2010 1 2010-01-01
ZEN Zendikar 76 2009-10-02
HOP Planechase 17 2009-09-04
M10 Magic 2010 89 2009-07-17
CON Conflux 14 2009-02-06
PCON Conflux Promos 1 2009-01-31
PW09 Wizards Play Network 2009 1 2009-01-01
DD2 Duel Decks: Jace vs. Chandra 120 2008-11-07
ALA Shards of Alara 22 2008-10-03
MOR Morningtide 1 2008-02-01
LRW Lorwyn 1 2007-10-12
10E Tenth Edition 2 2007-07-13
PLC Planar Chaos 2 2007-02-02
CSP Coldsnap 2 2006-07-21
RAV Ravnica: City of Guilds 2 2005-10-07
9ED Ninth Edition 1 2005-07-29
BOK Betrayers of Kamigawa 1 2005-02-04
CHK Champions of Kamigawa 5 2004-10-01
5DN Fifth Dawn 46 2004-06-04
DST Darksteel 49 2004-02-06
MRD Mirrodin 102 2003-10-02
8ED Eighth Edition 2 2003-07-28
SCG Scourge 53 2003-05-26
LGN Legions 37 2003-02-03
ONS Onslaught 32 2002-10-07
TOR Torment 29 2002-02-04
ODY Odyssey 230 2001-10-01
APC Apocalypse 672 2001-06-04
PAPC Apocalypse Promos 1 2001-05-26
7ED Seventh Edition 196 2001-04-11
PLS Planeshift 42 2001-02-05
INV Invasion 141 2000-10-02
PCY Prophecy 32 2000-06-05
S00 Starter 2000 6 2000-04-01
NEM Nemesis 98 2000-02-14
MMQ Mercadian Masques 165 1999-10-04
S99 Starter 1999 3 1999-07-01
UDS Urza's Destiny 39 1999-06-07
6ED Classic Sixth Edition 118 1999-04-21
ULG Urza's Legacy 38 1999-02-15
USG Urza's Saga 155 1998-10-12
EXO Exodus 21 1998-06-15
STH Stronghold 37 1998-03-02
TMP Tempest 35 1997-10-14
WTH Weatherlight 81 1997-06-09
5ED Fifth Edition 73 1997-03-24
VIS Visions 4 1997-02-03
MIR Mirage 221 1996-10-08
ALL Alliances 13 1996-06-10
HML Homelands 45 1995-10-01
CHR Chronicles 2 1995-07-01
ICE Ice Age 116 1995-06-03
4ED Fourth Edition 128 1995-04-01
FEM Fallen Empires 16 1994-11-01
DRK The Dark 3 1994-08-01
LEG Legends 2 1994-06-01
3ED Revised Edition 43 1994-04-01
ATQ Antiquities 1 1994-03-04

/correlr/roam/media/commit/dd63cedbba2e3da3264b9f536a35b86c93fa7484/tutor-sets.png

Identifying default cards for oracle entries

  SELECT oracle.oracle_id
       , oracle.name
       , scryfall.scryfall_id
       , scryfall.set_code
       , scryfall.collector_number
  FROM oracle
  JOIN (
       SELECT DISTINCT ON (oracle_id) *
       FROM scryfall
       ORDER BY oracle_id, release_date DESC
  ) scryfall USING (oracle_id)
  WHERE oracle.name IN ('Rampant Growth', 'Counterspell', 'Demonic Tutor', 'Jin-Gitaxias, Progress Tyrant')
oracle_id name scryfall_id set_code collector_number
82004860-e589-4e38-8d61-8c0210e4ea39 Demonic Tutor 085ed548-a8c8-40b3-8183-51c060bc95cb 30A 398
8539f295-5d58-4436-a73a-b9277c4c7795 Rampant Growth ba3026d2-334d-41bd-8c6b-7de7d78e54e0 40K 220
cc187110-1148-4090-bbb8-e205694a39f5 Counterspell d14d5ff3-40c0-4f22-91ad-d6c8447cb9e0 DMR 281
f5daadc1-98ff-480a-82bb-fe7bfaa7b60e Jin-Gitaxias, Progress Tyrant 9a5ffb0d-1fc3-40da-ac1f-19465aa8412b NEO 514

Defining Decks

Basic Deck List

The minimum card requirements for defining a deck are its unique name or equivalent identifier, and a quantity.

Quantity vs individual records

In order to refine card selection, it would be more straightforward to have one record per card instance associated with a deck, leaving quantity bundling as an exercise for the UI to streamline deck construction.

Refining selected cards

Card selections may be narrowed by assigning the following qualities, the sum of which should restrict the selection to a specific printing:

  • Set
  • Collector Number
  • Language
  • Foil or Non-Foil
Property Default
Set Latest
Collector Number Lowest
Language English
Foil or Non-Foil Non-Foil if available

Availability of cards in the collection

Marking cards as proxied

Any card in a deck may be marked as proxied. Proxied cards will not reduce the available number of matching cards in the collection for deckbuilding.