Automated Commander Power Level Evaluation

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

MrMystery314 wrote:
4 years ago
What I'm surprised by is that the main game plan being Worldgorger combo isn't something relevant by the ranking system (Grusilda is partially the commander because it wins off a full graveyard and infinite mana from the command zone without needing anything extra in hand), or Kiki-Jiki being counted as a value piece and not because it's part of the combo win from a single Buried Alive. Recognizing some of those combos (Kiki-Jiki without a way to combo is far weaker) could result in a more effective ranking system. Personally, I'd rank the deck as a strong 8 or a weak 9, effectively being cEDH if not solely optimized for being a combo deck.

Any ranking system is going to excel at spotting generally good cards, but without lots of effort won't recognize synergies and that sort of thing, which players looking at a deck may use to rank it either higher or lower than any automated system.
So the dataset is pretty weak at the moment. I am currently working on the data model for synergies. It's very complicated to do in a way that is somewhat future proof; what I want is for a synergy to be of any two of something. Those somethings could be:

1) Card types and subtypes (ex. an instance of Enchantment may modify Verduran Enchantress of Tuvasa as a commander)
2) Card tags (ex. ramp cards or tutors)
3) Card as a commander (ex. thrasios)
4) List of Card(s) in deck (ex. kiki-jiki) (

This is probably a weekend project to finish up, but my basic thinking is basically a 3 column row of:
criteria 1, criteria 2, points

With criteria being prefixed by something to identify the type of criteria, which would allow me to add new criteria in the future with additional prefixes. e.g.
cards:["Kiki-Jiki, Mirror Breaker"]
cards:["Dramatic reversal", "Isochron Scepter"]
commander:"Thrasios, Triton Hero"
tag:"Ramp"
type:"enchantment"
subtype:"elf"

Your point value is then per instance; for example:
tag:"Ramp" + tag:"Bomb" = 1 point (this could be say 100 points pretty easily if you have 10 ramp spells and 10 bombs)
card:"Serra's Sanctum" + "type:"enchantment"" = 2 points (so 2 points per enchantment in your deck if you have serra's sanctum)


There are a lot of gaps in this approach. Mainly that it doesn't allow you to do gradients or whatever you want to call it, where the more ramp you add the more your bombs count -- so 10 pieces of ramp makes bombs worth 5, and 20 pieces of ramp makes bombs worth 10, or whatever.

But so far it feels like the best combination of simple to maintain and effective.

One thing I am seeing is the need for a form front end for all this nonsense too, since Excel/Sheets is going to get messy with people typing; really need a front end with some intelligence and a card selector at minimum for mass consumption. But I don't want to do that :P

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

We have a synergy parser and a synergy spreadsheet that should work for everything I can think of - both commander synergies and otherwise. I have not ported any of the commander synergies over there.



edit: Excel cleaned up a bit and a bit easier to use

Anyway here's what the synergy objects wind up looking like for those nerdy and interested:
{'synergy': {'card': ['isohcron cepter']}, 'target': {'card': ['dramatic reversal']}, 'points': '30', 'category': 'combo', 'tags': ''}
{'synergy': {'card': ['cephalid illustionist']}, 'target': {'card': ['nomads en-kor']}, 'points': '20', 'category': 'combo', 'tags': ''}
{'synergy': {'card': ['cephalid illustionist']}, 'target': {'card': ['shaman en-Kor']}, 'points': '20', 'category': 'combo', 'tags': ''}
{'synergy': {'card': ['cephalid illustionist']}, 'target': {'card': ['warrior en-Kor']}, 'points': '20', 'category': 'combo', 'tags': ''}
{'synergy': {'card': ['cephalid illustionist']}, 'target': {'card': ['outrider en-Kor']}, 'points': '10', 'category': 'combo', 'tags': ''}
{'synergy': {'card': ['reveillark', 'body double']}, 'target': {'card': ['altar of dementia']}, 'points': '5', 'category': 'combo', 'tags': ''}
{'synergy': {'card': ['reveillark', 'karmic guide']}, 'target': {'card': ['altar of dementia']}, 'points': '5', 'category': 'combo', 'tags': ''}
{'synergy': {'card': ['karmic guide', 'body double']}, 'target': {'card': ['altar of dementia']}, 'points': '5', 'category': 'combo', 'tags': ''}
Last edited by pokken 4 years ago, edited 1 time in total.

User avatar
Rumpy5897
Tuner of Jank
Posts: 1859
Joined: 4 years ago
Pronoun: he / him

Post by Rumpy5897 » 4 years ago

Awesome system to ingest things in!

Just so I fully grok card vs. target - swapping scepter and reversal in their respective combo line wouldn't change anything, would it? But it's worded this way so target can be broader, as shown with serra's sanctum and enchantments?
 
EDH Primers (click me!)
Deck is Kill Club
Show
Hide

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

Rumpy5897 wrote:
4 years ago
Awesome system to ingest things in!

Just so I fully grok card vs. target - swapping scepter and reversal in their respective combo line wouldn't change anything, would it? But it's worded this way so target can be broader, as shown with serra's sanctum and enchantments?
Yeah changing the order would not matter I don't think at least the way I am envisioning it. I cleaned up the data entry quite a bit as well but unfortunately because magic cards have weird characters in them we have to manually enter quotes around everything.

If the dataset gets too big I may have to write some sort of "kick duplicates" logic that merges/consolidates rules, but for now I am not going to do that :P

Longer term I think it might be a good idea to put a google form in front for capturing data, but I'm just not that ambitious yet, rather focus on the back end than the data collection for now.

next step: write logic that parses some lists with this info and reports on the synergy scores. Figuring out how to present that in a meaningful way is going to be annoying :)

User avatar
Dragoon
Posts: 417
Joined: 4 years ago
Pronoun: Unlisted

Post by Dragoon » 4 years ago

Well, I don't understand everything but keep up the good work, man! :)
If you need more lists, here's a mono-red tribal dragon and an atraxa +1/+1 counters synergy, maybe it might help spotting new synergies?

User avatar
darrenhabib
Posts: 1845
Joined: 4 years ago
Pronoun: Unlisted

Post by darrenhabib » 4 years ago

I've mentioned that I had started working on a thread for infinite combos, but got overwhelmed and put it on hiatus.

But here is an example of my approach, this is for colorless section:

Colorless

Colorless
Show
Hide



Card 1Card 2Card 3Result
  • Infinite colorless mana












  • Infinite mana




Card 1Card 2Card 3Result
  • Infinite mana












  • Infinite mana and draw












  • Infinite mana and untap of any artifacts

Card 1Card 2Card 3Result
  • Infinite mana

Card 1Card 2Card 3Result
  • Infinite mana

Card 1Card 2Card 3Result
  • Destroy each other player's permanents

Card 1Card 2Result
  • Opponents can't activate abilities, including lands









  • Players can't activate abilities, including lands

Card 1Card 2Card 3Card 4Card 5Result
  • Infinite damage


















  • Infinite mana


















  • Any artifact creature
  • Infinite sacrifices


















  • Infinite mana

Card 1Card 2Card 3Card 4Card 5Result
  • Infinite mana


















  • Artifact mana
  • Artifact
  • Artifact
  • Infinite mana

Card 1Card 2Card 3Card 4Result
  • Infinite mana















  • Infinite tokens















  • Any artifact mana
  • Infinite damage















  • Infinite sacrifices















  • Infinite mana















  • Infinite sacrifices

Card 1Card 2Card 3Result
  • Infinite destroy creatures

Card 1Card 2Card 3Card 4Result
  • Infinite mana















  • Infinite mana















  • Infinite mana

Card 1Card 2Card 3Result
  • Two artifacts in hand
  • Infinite mana












  • Three artifacts in hand
  • Infinite mana












  • Infinite mana

Card 1Card 2Card 3Result
  • Infinite sacrifices












  • Infinite mana












  • Infinite mana












  • Infinite mana

Card 1Card 2Card 3Card 4Result
  • Infinite turns












  • Infinite turns

Card 1Card 2Card 3Card 4Result
  • Infinite turns












  • Infinite turns

Card 1Card 2Card 3Result
  • Infinite mana

Card 1Card 2Card 3Result
  • Infinite tokens

Card 1Card 2Card 3Result
  • Infinite tokens

Card 1Card 2Card 3Result
  • Metalworker
    Show
    Hide
    Metalworker with at least four artifacts in hand
  • Infinite mana and tokens












  • Infinite mana and tokens

Card 1Card 2Card 3Card 4Card 5Result
  • Any artifact mana
  • Infinite mana and tokens

Card 1Card 2Result
  • Mill target players library









  • Repeatable exile of lands each turn

Card 1Card 2Card 3Card 4Result
  • Infinite mana















  • Metalworker
    Show
    Hide
    Metalworker with at least three artifacts in hand
  • Infinite mana















  • Infinite mana















  • Infinite mana















  • Any artifact mana
  • Infinte mana

Card 1Card 2Card 3Card 4Result
  • Infinte mana















  • Infinte mana















  • Infinte mana
Ultimately I was just using the pipes tag to organize it into a spreadsheet way for the website.
Obviously this is still just a dataset, and doubling up doing these types of entries twice would be a mistake.
I could see just entering combos into a spreadsheet (say your one) and making some code to spit out formatting for the forums (this would actually be pretty trivial).
Ultimately the hard part I found was coming up with the combos themselves. What I found after working on this for many weeks, is that to actually cover all the combos in Magic the Gathering, I needed to take a more programmatic way of dealing with covering them all. The perfectionist (OCD) in me can't leave a stone unturned, and this sent me down a rabbit hole.
I found patterns emerging. I won't get into the details, but lets just say that there are formulas for coming up with infinite combos and really the way to approach the task is by creating a spreadsheet matrix. But that is not for you to be concerned about, only that it would take me time, but I feel once I put myself to the task again, could come up with 100% complete infinite combo dataset.
This would still take me months as I wouldn't won't to burn out and just have fun with it when I get an hour spare here and there. What I'm saying is that we'd need to be patient with getting this data.

Alright so the first thing is that you've stated you are only doing two card combinations. Obviously most combos are more than that. Could you code it to include any amounts of combinations, as long as I fill in the entries eventually?
Last edited by darrenhabib 4 years ago, edited 1 time in total.

User avatar
Rumpy5897
Tuner of Jank
Posts: 1859
Joined: 4 years ago
Pronoun: he / him

Post by Rumpy5897 » 4 years ago

Yes, as evidenced by this entry that requires Reveillark, Body Double and Altar of Dementia:
{'synergy': {'card': ['reveillark', 'body double']}, 'target': {'card': ['altar of dementia']}, 'points': '5', 'category': 'combo', 'tags': ''}
 
EDH Primers (click me!)
Deck is Kill Club
Show
Hide

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

I finished the first cut at the parsing of synergies, including counting various types. It's not perfect and not fully integrated into scoring, but it's really coming along. It was quite tricky to get the logic right on all of it.

Here's a CEDH deck with some of the various synergies.
+-----------------------------------------------------------------------------+
| CEDH_consult-scepter-thrasios Raw:1794 Adj:1519.22 Tut_Mult:1.0 Curve_mult:0.85 |
+------------------------------------------+-------------------+--------------+
| Card Name                                | Commander         |       Points |
+------------------------------------------+-------------------+--------------+
| TYMNA THE WEAVER                         | Yes               |          200 |
| THRASIOS, TRITON HERO                    | Yes               |          175 |
| MANA CRYPT                               | No                |          100 |
| SOL RING                                 | No                |           85 |
| DARK RITUAL                              | No                |           60 |
| DEMONIC TUTOR                            | No                |           60 |
| MANA VAULT                               | No                |           60 |
| VAMPIRIC TUTOR                           | No                |           60 |
| MOX DIAMOND                              | No                |           40 |
| CHROME MOX                               | No                |           35 |
| MYSTICAL TUTOR                           | No                |           35 |
| AD NAUSEAM                               | No                |           30 |
| GRIM MONOLITH                            | No                |           30 |
| MYSTIC REMORA                            | No                |           30 |
| TIMETWISTER                              | No                |           30 |
| YAWGMOTH'S WILL                          | No                |           30 |
| CARPET OF FLOWERS                        | No                |           25 |
| IMPERIAL SEAL                            | No                |           25 |
| ANCIENT TOMB                             | No                |           20 |
| ARCANE SIGNET                            | No                |           20 |
| DEATHRITE SHAMAN                         | No                |           20 |
| DEMONIC CONSULTATION                     | No                |           20 |
| LIM-DÛL'S VAULT                          | No                |           20 |
| LOTUS PETAL                              | No                |           20 |
| NOBLE HIERARCH                           | No                |           20 |
| RHYSTIC STUDY                            | No                |           20 |
| SYLVAN LIBRARY                           | No                |           20 |
| THASSA'S ORACLE                          | No                |           20 |
| WINDFALL                                 | No                |           20 |
| FELLWAR STONE                            | No                |           18 |
| AVACYN'S PILGRIM                         | No                |           15 |
| BIRDS OF PARADISE                        | No                |           15 |
| BLOOM TENDER                             | No                |           15 |
| BRAINSTORM                               | No                |           15 |
| DARK CONFIDANT                           | No                |           15 |
| ELVES OF DEEP SHADOW                     | No                |           15 |
| FORCE OF WILL                            | No                |           15 |
| ISOCHRON SCEPTER                         | No                |           15 |
| TAINTED PACT                             | No                |           15 |
| COMMAND TOWER                            | No                |           14 |
| CITY OF BRASS                            | No                |           12 |
| MANA CONFLUENCE                          | No                |           12 |
| PONDER                                   | No                |           12 |
| CHAIN OF VAPOR                           | No                |           10 |
| CYCLONIC RIFT                            | No                |           10 |
| DRAMATIC REVERSAL                        | No                |           10 |
| FLOODED STRAND                           | No                |           10 |
| FORBIDDEN ORCHARD                        | No                |           10 |
| GEMSTONE CAVERNS                         | No                |           10 |
| GILDED DRAKE                             | No                |           10 |
| MANA DRAIN                               | No                |           10 |
| MISTY RAINFOREST                         | No                |           10 |
| NOTION THIEF                             | No                |           10 |
| PACT OF NEGATION                         | No                |           10 |
| POLLUTED DELTA                           | No                |           10 |
| PREORDAIN                                | No                |           10 |
| SCALDING TARN                            | No                |           10 |
| SENSEI'S DIVINING TOP                    | No                |           10 |
| SMOTHERING TITHE                         | No                |           10 |
| BLOODSTAINED MIRE                        | No                |            8 |
| MARSH FLATS                              | No                |            8 |
| VERDANT CATACOMBS                        | No                |            8 |
| WINDSWEPT HEATH                          | No                |            8 |
| WOODED FOOTHILLS                         | No                |            8 |
| ABRUPT DECAY                             | No                |            5 |
| FLUSTERSTORM                             | No                |            5 |
| MENTAL MISSTEP                           | No                |            5 |
| NOXIOUS REVIVAL                          | No                |            5 |
| SILENCE                                  | No                |            5 |
| TOXIC DELUGE                             | No                |            5 |
| TROPICAL ISLAND                          | No                |            5 |
| TUNDRA                                   | No                |            5 |
| UNDERGROUND SEA                          | No                |            5 |
| VEIL OF SUMMER                           | No                |            5 |
| ASSASSIN'S TROPHY                        | No                |            3 |
| BAYOU                                    | No                |            3 |
| SAVANNAH                                 | No                |            3 |
| MORPHIC POOL                             | No                |            2 |
+------------------------------------------+-------------------+--------------+
+------------------------------------------------------------------------+
|              CEDH_consult-scepter-thrasios synergy report              |
+---------------------------------------------------------------+--------+
| Synergy                                                       | Points |
+---------------------------------------------------------------+--------+
| isochron scepter,dramatic reversal with ramp,dork             | 18     |
| isochron scepter,dramatic reversal with rock,ramp             | 16     |
| isochron scepter,dramatic reversal with thrasios, triton hero | 20     |
| isochron scepter with dramatic reversal                       | 30     |
| demonic consultation with thassa's oracle                     | 50     |
| tainted pact with thassa's oracle                             | 35     |
+---------------------------------------------------------------+--------+
And here is a Tuvasa deck to demonstrate the type searching synergies for serra's sanctum and herself.
+--------------------------------------------------------------------------+
| cedh-tuvasa-bantchantress Raw:686 Adj:513.39 Tut_Mult:1.0 Curve_mult:0.75 |
+-------------------------------------------+-----------------+------------+
| Card Name                                 | Commander       |     Points |
+-------------------------------------------+-----------------+------------+
| TUVASA THE SUNLIT                         | Yes             |          0 |
| MANA CRYPT                                | No              |        100 |
| SOL RING                                  | No              |         85 |
| MANA VAULT                                | No              |         60 |
| MOX DIAMOND                               | No              |         40 |
| CHROME MOX                                | No              |         35 |
| MYSTICAL TUTOR                            | No              |         35 |
| MYSTIC REMORA                             | No              |         30 |
| NOBLE HIERARCH                            | No              |         20 |
| RHYSTIC STUDY                             | No              |         20 |
| SERRA'S SANCTUM                           | No              |         20 |
| SYLVAN LIBRARY                            | No              |         20 |
| WILD GROWTH                               | No              |         20 |
| BIRDS OF PARADISE                         | No              |         15 |
| FORCE OF WILL                             | No              |         15 |
| WORLDLY TUTOR                             | No              |         15 |
| COMMAND TOWER                             | No              |         14 |
| MANA CONFLUENCE                           | No              |         12 |
| CYCLONIC RIFT                             | No              |         10 |
| ELADAMRI'S CALL                           | No              |         10 |
| FLOODED STRAND                            | No              |         10 |
| FYNDHORN ELVES                            | No              |         10 |
| MANA DRAIN                                | No              |         10 |
| MISTY RAINFOREST                          | No              |         10 |
| POLLUTED DELTA                            | No              |         10 |
| MARSH FLATS                               | No              |          8 |
| SWORD OF FEAST AND FAMINE                 | No              |          8 |
| TEFERI'S PROTECTION                       | No              |          8 |
| WINDSWEPT HEATH                           | No              |          8 |
| WOODED FOOTHILLS                          | No              |          8 |
| BEAST WITHIN                              | No              |          5 |
| MIRRI'S GUILE                             | No              |          5 |
| PATH TO EXILE                             | No              |          5 |
| SWORDS TO PLOWSHARES                      | No              |          5 |
+-------------------------------------------+-----------------+------------+
+---------------------------------------------+
|   cedh-tuvasa-bantchantress synergy report  |
+------------------------------------+--------+
| Synergy                            | Points |
+------------------------------------+--------+
| serra's sanctum with enchantment   | 28     |
| tuvasa the sunlit with enchantment | 56     |
+------------------------------------+--------+

MrMystery314
Posts: 64
Joined: 4 years ago
Pronoun: he / him

Post by MrMystery314 » 4 years ago

How much would you value Worldgorger combo at? The issue is obviously that the ways it wins vary significantly between decks and games, but it's certainly something.

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

MrMystery314 wrote:
4 years ago
How much would you value Worldgorger combo at? The issue is obviously that the ways it wins vary significantly between decks and games, but it's certainly something.
It's very efficient but also extremely high risk. I'd probably put it in the 30 point range, somewhere around the value of Kiki+Deceiver exarch. More efficient but riskier and requires a third piece. I'd value it a lot higher in Anje or a commander that is an infinite mana outlet.

But points are really super loosey goosey right now so I dunno.

Tomorrow! if I have time!

* Finish code that merges the synergy totals into deck points and try to reformat the report so that it's one report. The commander column can go in favor of a spacer row I think to indicate who the commanders are.

* Work on the Ramp stuff. One thought I have is to simply create a "ramp" + "ramp" synergy that makes your ramp score exponential. Essentially if I made "Ramp + ramp" a synergy with 1 point, you'd get (I think?) (ramp_count)^2 points, with the likely peak being around 400 points from 20 pieces of ramp. I think that's probably close enough to fair to be not unreasonable with how decks are generally constructed.

Another option would be to make a ramp+rock with ramp+rock synergy, and a ramp+dork with ramp+dork synergy that would probably compress the range a little, and allow for a similar ramp+landfall synergy.

Overall I am starting to think that most things of value can be pretty well expressed with the synergy system as long as enough data is collected.

And one final note: I would absolutely adore handing off data collection to an interested and motivated party or group of parties. I will write whatever you guys want but entering all that data is just beyond my knowledge - we really need something like a concerted effort of primer writer level people for the big synergy commanders, for example.

User avatar
Rumpy5897
Tuner of Jank
Posts: 1859
Joined: 4 years ago
Pronoun: he / him

Post by Rumpy5897 » 4 years ago

Need to get all the constituents interacting somehow, in the long run. Ramp benefits from card advantage, and in reverse too.

I'll happily volunteer to carry Feather through this, JSON and all, as a demonstration example to get others involved. I feel my initial list hits the primary commander synergies pretty well, but there's more to making the deck pop off under the hood. Young Pyromancer and Monastery Mentor need type-based synergy counters, and it'd be good to get oracle text sponged into the cards so that the flickers could get auto-synergy with creatures with "enters the battlefield" (this one feels like a decent approximation without mincing the query too hard).

It would also be good to account for the potential repeated appearances of the instants, but this feels like it transcends the scope of the individual cards. As such, probably a flat synergy score for stuff like Fishbowl, but an extra typed bonus for Mentor and whatnot. Need to figure out how to model Zada here.

If this sounds like a reasonable level of breakdown of the deck to you, I am happy to proceed.
 
EDH Primers (click me!)
Deck is Kill Club
Show
Hide

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

Rumpy5897 wrote:
4 years ago
Need to get all the constituents interacting somehow, in the long run. Ramp benefits from card advantage, and in reverse too.

I'll happily volunteer to carry Feather through this, JSON and all, as a demonstration example to get others involved. I feel my initial list hits the primary commander synergies pretty well, but there's more to making the deck pop off under the hood. Young Pyromancer and Monastery Mentor need type-based synergy counters, and it'd be good to get oracle text sponged into the cards so that the flickers could get auto-synergy with creatures with "enters the battlefield" (this one feels like a decent approximation without mincing the query too hard).

It would also be good to account for the potential repeated appearances of the instants, but this feels like it transcends the scope of the individual cards. As such, probably a flat synergy score for stuff like Fishbowl, but an extra typed bonus for Mentor and whatnot. Need to figure out how to model Zada here.

If this sounds like a reasonable level of breakdown of the deck to you, I am happy to proceed.
So do what you can with what we've got now and I'll noodle on ways to automatically tag cards. That's ultimately the thing we need to do for my model.

If every card has a tag instead of just the ones in the cards sheet it makes all the formulas way more powerful.

Instants and sorceries are super easy with the current system however. Create a 1 point synergy between card:monastery mentor and type:instant (and all the other types individually sadly).

I need to add a not modifier to the types, so if you want to use !creature to represent.that while i.work on it, should be easy enough to implement.

And yes having a complete sample dataset for a commander would be sweet. I'll do one for ephara once I get the next gen of code fixed with:
Subtype support
Exclusion support (!)
Fix the scoring report


As is we can do ramp times draw synergy pretty easy by tagging things.with draw then doing a ramp draw synergy. :)

User avatar
Rumpy5897
Tuner of Jank
Posts: 1859
Joined: 4 years ago
Pronoun: he / him

Post by Rumpy5897 » 4 years ago

I went into the innards of your code, and managed to get synergies scored as part of the score, and after some mild debugging also subtypes.

Here's my initial garbage Feather support, and then me noodling with stuff for Stoneforge Mystic purposes.
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""bandage""","{""card"":[""bandage""]}",10,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""crimson wisps""","{""card"":[""crimson wisps""]}",10,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""defiant strike""","{""card"":[""defiant strike""]}",10,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""expedite""","{""card"":[""expedite""]}",10,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""heal""","{""card"":[""heal""]}",10,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""niveous wisps""","{""card"":[""niveous wisps""]}",10,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""panic""","{""card"":[""panic""]}",10,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""shelter""","{""card"":[""shelter""]}",10,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""eerie interlude""","{""card"":[""eerie interlude""]}",7,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""fists of flame""","{""card"":[""fists of flame""]}",7,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""gods willing""","{""card"":[""gods willing""]}",7,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""sheltering light""","{""card"":[""sheltering light""]}",7,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""stand firm""","{""card"":[""stand firm""]}",7,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""apostle's blessing""","{""card"":[""apostle's blessing""]}",4,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""cloudshift""","{""card"":[""cloudshift""]}",4,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""ephemerate""","{""card"":[""ephemerate""]}",4,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""faith's shield""","{""card"":[""faith's shield""]}",4,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""liberate""","{""card"":[""liberate""]}",4,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""long road home""","{""card"":[""long road home""]}",4,,
commander,"""feather, the redeemed""","{""commander"":[""feather, the redeemed""]}",card,"""otherworldly journey""","{""card"":[""otherworldly journey""]}",4,,
card,"""stoneforge mystic""","{""card"":[""stoneforge mystic""]}",subtype,"""equipment""","{""subtype"":[""equipment""]}",2,,
Here's my subtype snippet. It's like your type snippet, but I added self. before cards and commanders as this way it yields the correct stuff :P
# next, test Subtypes. Essentially repeat Types but in a different field
type_matches = []
if criteria.get('SUBTYPE') is not None:
	# merge the lists since for this it doesn't matter
	for card in self.cards + self.commanders:
		type_match = True
		# for each type
		for card_type in criteria.get('SUBTYPE'):
			if card_type.upper() not in card.subtypes:
				# break if we find a type that is not in the card
				type_match = False # if any types don't match we're out of here
				break
		## only append after we have checked all types
		if type_match:
			type_matches.append(card) # if we don't break by a nonmatching type, add it!

	if len(type_matches) > 0:
		#print("Returned " + str(len(type_matches)) + " type matches.")
		return type_matches
	else:
		return False
 
EDH Primers (click me!)
Deck is Kill Club
Show
Hide

User avatar
Rumpy5897
Tuner of Jank
Posts: 1859
Joined: 4 years ago
Pronoun: he / him

Post by Rumpy5897 » 4 years ago

I got thinking - how in the hell would this system handle Sunforger? It would have trouble, as the existing code base currently checks one field at a time. So I figured out how to work AND/OR in your querying system, replacing the existing type/tag code bits:
        # if it's not a card or commander criterion, then it's a type, subtype, tag or something
        # nevertheless, it can be complicated. evaluate one card at a time for the full set of criteria
        matches = []
        # create a helper translation dictionary for easy iteration over complex queries
        meta = {'TYPE':'types', 'SUBTYPE':'subtypes', 'COLOR':'colors', 'CMC':'cmc', 'TAG':'tags', 'TEXT':'oracle_text'}
        for card in self.cards + self.commanders:
            match = True
            # loop over the defined criteria
            for field in criteria.keys():
                # loop over all the AND criteria that have to be fulfilled
                for query in criteria.get(field):
                    # check for any OR stuff in the individual query, denoted via |
                    query = query.split('|')
                    # any hits on the OR will be fine.
                    local_hit = False
                    for single_query in query:
                        if field == 'CMC':
                            # CMC is screwy and needs to be processed differently
                            # the first character is <, > or =, denoting the direction of thresholding
                            # the rest is the actual value
                            single_value = int(single_query[1:])
                            # check the appropriate thresholding for the local_hit
                            if single_query[0] == '<':
                                if getattr(card, meta[field]) < single_value:
                                    local_hit = True
                                    break
                            elif single_query[0] == '>':
                                if getattr(card, meta[field]) > single_value:
                                    local_hit = True
                                    break
                            else:
                                if getattr(card, meta[field]) == single_value:
                                    local_hit = True
                                    break
                        else:
                            # not CMC? easy life
                            if single_query.upper() in getattr(card, meta[field]):
                                # we have a score on one of the ORs, good enough
                                local_hit = True
                                break
                    if not local_hit:
                        # none of the ORs did what they had to, match is kill
                        match = False
                        break
                if not match:
                    # we have hit a snag on the matching, abort
                    break
            # so, did we match?
            if match:
                # we did!
                matches.append(card)
        # now that we've looped over all the cards, do we have any hits? report appropriately
        if len(matches) > 0:
            return matches
        else:
            return False
So essentially what this does is as follows:
  • It loops through the cards once, checking all the conditions and saving the cards that clear all the hurdles.
  • The conditions in the provided dictionary are evaluated sequentially, with all the individual queries required to hit. This includes the lists for a single field. You can ask this for {'TEXT': ['draw', 'card'], 'TYPE': ['instant']}, and it finds all the instants with "draw" and "card" in the text.
  • CMC is assumed to have the first character be <, > or =, followed by the actual CMC integer. This sets the direction of the thresholding.
  • As mentioned, there is OR support though. This comes into effect deep in the innards of the query, where alternate matches can be supplied separated by |. Kinda faffy, but necessary for stuff like Sunforger to correctly identify its things. Speaking of Sunforger: {'TYPE': ['instant'], 'CMC': ['<5'], 'COLOR': ['R|W']}.
Worth to redo card logic into something vaguely similar for collapsing stuff like the Feather synergies in the document? I'm not fully sure how you parse the CSV, come to think of it. What do the non-dictionary fields actually do? :P

Sunforger CSV:
card,"""sunforger""","{""card"":[""sunforger""]}",type,"""instant""","{""type"":[""instant""],""cmc"":[""<5""],""color"":[""r|w""]}",2,,
 
EDH Primers (click me!)
Deck is Kill Club
Show
Hide

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

I added your stuff to the sheet and will try to get the code merged later on. thanks for catching that bug :) It seemed to be working despite it which makes little sense to me, might be some kind of a quirk of something. lol, python is so weird sometimes.

User avatar
Rumpy5897
Tuner of Jank
Posts: 1859
Joined: 4 years ago
Pronoun: he / him

Post by Rumpy5897 » 4 years ago

I should probably set up a bitbucket account and contribute directly, might make things easier. I'm shockingly git illiterate though, as evidenced by me getting anxious every time I'd work with a related group's repositories with their elaborate tangle of branches, pull requests and whatnot. Brrr. :P
 
EDH Primers (click me!)
Deck is Kill Club
Show
Hide

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

Rumpy5897 wrote:
4 years ago
I got thinking - how in the hell would this system handle Sunforger? It would have trouble, as the existing code base currently checks one field at a time. So I figured out how to work AND/OR in your querying system, replacing the existing type/tag code bits:
        # if it's not a card or commander criterion, then it's a type, subtype, tag or something
        # nevertheless, it can be complicated. evaluate one card at a time for the full set of criteria
        matches = []
        # create a helper translation dictionary for easy iteration over complex queries
        meta = {'TYPE':'types', 'SUBTYPE':'subtypes', 'COLOR':'colors', 'CMC':'cmc', 'TAG':'tags', 'TEXT':'oracle_text'}
        for card in self.cards + self.commanders:
            match = True
            # loop over the defined criteria
            for field in criteria.keys():
                # loop over all the AND criteria that have to be fulfilled
                for query in criteria.get(field):
                    # check for any OR stuff in the individual query, denoted via |
                    query = query.split('|')
                    # any hits on the OR will be fine.
                    local_hit = False
                    for single_query in query:
                        if field == 'CMC':
                            # CMC is screwy and needs to be processed differently
                            # the first character is <, > or =, denoting the direction of thresholding
                            # the rest is the actual value
                            single_value = int(single_query[1:])
                            # check the appropriate thresholding for the local_hit
                            if single_query[0] == '<':
                                if getattr(card, meta[field]) < single_value:
                                    local_hit = True
                                    break
                            elif single_query[0] == '>':
                                if getattr(card, meta[field]) > single_value:
                                    local_hit = True
                                    break
                            else:
                                if getattr(card, meta[field]) == single_value:
                                    local_hit = True
                                    break
                        else:
                            # not CMC? easy life
                            if single_query.upper() in getattr(card, meta[field]):
                                # we have a score on one of the ORs, good enough
                                local_hit = True
                                break
                    if not local_hit:
                        # none of the ORs did what they had to, match is kill
                        match = False
                        break
                if not match:
                    # we have hit a snag on the matching, abort
                    break
            # so, did we match?
            if match:
                # we did!
                matches.append(card)
        # now that we've looped over all the cards, do we have any hits? report appropriately
        if len(matches) > 0:
            return matches
        else:
            return False
So essentially what this does is as follows:
  • It loops through the cards once, checking all the conditions and saving the cards that clear all the hurdles.
  • The conditions in the provided dictionary are evaluated sequentially, with all the individual queries required to hit. This includes the lists for a single field. You can ask this for {'TEXT': ['draw', 'card'], 'TYPE': ['instant']}, and it finds all the instants with "draw" and "card" in the text.
  • CMC is assumed to have the first character be <, > or =, followed by the actual CMC integer. This sets the direction of the thresholding.
  • As mentioned, there is OR support though. This comes into effect deep in the innards of the query, where alternate matches can be supplied separated by |. Kinda faffy, but necessary for stuff like Sunforger to correctly identify its things. Speaking of Sunforger: {'TYPE': ['instant'], 'CMC': ['<5'], 'COLOR': ['R|W']}.
Worth to redo card logic into something vaguely similar for collapsing stuff like the Feather synergies in the document? I'm not fully sure how you parse the CSV, come to think of it. What do the non-dictionary fields actually do? :P

Sunforger CSV:
card,"""sunforger""","{""card"":[""sunforger""]}",type,"""instant""","{""type"":[""instant""],""cmc"":[""<5""],""color"":[""r|w""]}",2,,
I was thinking about that pretty hard as I went along. I constantly wish Python had a Switch statement, it's probably one of the things about it that annoys me the most. Your code does that basically, and is quite cool. I kinda brute-forced it up front, lol. I'll need to digest yours entirely I think before commenting, but it looks good.

My gut assessment is that cards like recruiter of the guard and sunforger are simplistic enough that they can probably be encompassed just by the strength of the card at least at this stage.

The non-dictionary fields in the general_synergy tab do nothing at the moment except for points. The section where the csv is parsed is:
     with open(self.data_file, encoding='utf-8') as custom_data_file:
            # instantiate a dictreader based on the csv file of synergy data
            reader = csv.DictReader(custom_data_file, delimiter=',', quotechar='"')
            ## create a dictionary of dictionaries of card point data, indexed
            ## by the card's name
            for entry in reader:
                ## identify commander cards
                synergy = self.parse_synergy(entry.get(synergy_field))
                target = self.parse_synergy(entry.get(target_field))
                points = int(entry.get(points_field))
                category = entry.get(category_field)
                tags = entry.get(tags_field)
                self.synergies.append(
                    Synergy(
                        synergy,
                        target,
                        points,
                        category,
                        tags

                    )
                )
What it does basically is get all the various fields and make a synergy object out of them. in theory a synergy could be tagged or categorized in a useful way and you could add multipliers based on that I guess, like a sliding scale based on total points of combo synergies. That's the idea anyway.

The fields that it uses are synergy, target, points, category and tags (as in the code). The parse_synergy function uses json.loads and a little transformation to turn the field text into dictionaries.

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

Rumpy5897 wrote:
4 years ago
I should probably set up a bitbucket account and contribute directly, might make things easier. I'm shockingly git illiterate though, as evidenced by me getting anxious every time I'd work with a related group's repositories with their elaborate tangle of branches, pull requests and whatnot. Brrr. :P
Git is annoying as hell sometimes and it's a good reason to chop things into different files. If you have interest in working on it together, I can commit my latest and you can update the algorithm for evaluating a single criteria with yours.

The key is not working on the same file at the same time, and using informative commit messages. Right now I have done a pretty OK job of making sure the dependencies cascade (That is I don't think synergy_data or card_data have any dependencies on analyze_decks) so should be easy enough to add an additional file for stuff too if needed.

I fixed the tutor and curve calculations that I had broken, and am going to try to get the reporting + scoring updated before I head back to work :)

User avatar
Rumpy5897
Tuner of Jank
Posts: 1859
Joined: 4 years ago
Pronoun: he / him

Post by Rumpy5897 » 4 years ago

Yeah, it makes sense to have taggable synergies. All those cantrips are card draw for Feather.

I'd still include scaling terms for those. They are toolbox tutors after all, and don't take monstrous queries to set up.

As for scoring, I added this to your get_raw_score()
        for synergy in self.synergies:
            if isinstance(synergy[1], bool):
                self.score += synergy[0].points
            else:
                self.score += synergy[0].points * len(synergy[1])
 
EDH Primers (click me!)
Deck is Kill Club
Show
Hide

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

Rumpy5897 wrote:
4 years ago
Yeah, it makes sense to have taggable synergies. All those cantrips are card draw for Feather.

I'd still include scaling terms for those. They are toolbox tutors after all, and don't take monstrous queries to set up.

As for scoring, I added this to your get_raw_score()
        for synergy in self.synergies:
            if isinstance(synergy[1], bool):
                self.score += synergy[0].points
            else:
                self.score += synergy[0].points * len(synergy[1])
Very similar, I decided to separate synergies so they could be scored independently in the get_score() function if we want to.
    ## return a score of synergies to add in
    def get_synergy_score(self):
        synergy_points = 0
        for synergy, result in self.synergies:
            if type(result) is list:
                synergy_points += ( len(result) * synergy.points )
            else:
                synergy_points += synergy.points

        #print("Synergy point total: " + str(synergy_points))
        return synergy_points # return the total!

    def get_score(self):
        ## score calculation sequence 
        total_score = self.get_raw_score() # raw
        total_score = total_score + self.get_synergy_score() # add synergy
        total_score = total_score * self.get_curve_mult_logistic() # multiply by curve
        total_score = total_score * self.get_tutor_mult() # multiply by tutors
        return total_score


User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

Alright I finished cleaning up the various reports and all the existing bugs I am aware of. One thing I need to do is go through and set up logging so I don't have to manually add print statements, it's getting to about that size of codebase :P


New report format:
+-------------------------------------+
|    CEDH_consult-scepter-thrasios    |
+----------------+--------------------+
|   Raw Score    |        1794        |
|   Tutor Mult   |        1.38        |
|   Curve Mult   |        0.77        |
| Synergy Score  |        169         |
| Adjusted Score | 2087.8988941194825 |
+----------------+--------------------+
+------------------------------------+-----------------------+--------+
| Point Source                       | Factor                | Points |
+------------------------------------+-----------------------+--------+
| TYMNA THE WEAVER                   | Commander             |    200 |
| THRASIOS, TRITON HERO              | Commander             |    175 |
| isochron scepter,dramatic reversal | ramp,dork             |     18 |
| isochron scepter,dramatic reversal | rock,ramp             |     16 |
| isochron scepter,dramatic reversal | thrasios, triton hero |     20 |
| isochron scepter                   | dramatic reversal     |     30 |
| demonic consultation               | thassa's oracle       |     50 |
| tainted pact                       | thassa's oracle       |     35 |
| MANA CRYPT                         | Card                  |    100 |
| SOL RING                           | Card                  |     85 |
| DARK RITUAL                        | Card                  |     60 |
| DEMONIC TUTOR                      | Card                  |     60 |
| MANA VAULT                         | Card                  |     60 |
| VAMPIRIC TUTOR                     | Card                  |     60 |
| MOX DIAMOND                        | Card                  |     40 |
| CHROME MOX                         | Card                  |     35 |
| MYSTICAL TUTOR                     | Card                  |     35 |
| AD NAUSEAM                         | Card                  |     30 |
| GRIM MONOLITH                      | Card                  |     30 |
| MYSTIC REMORA                      | Card                  |     30 |
| TIMETWISTER                        | Card                  |     30 |
| YAWGMOTH'S WILL                    | Card                  |     30 |
| CARPET OF FLOWERS                  | Card                  |     25 |
| IMPERIAL SEAL                      | Card                  |     25 |
| ANCIENT TOMB                       | Card                  |     20 |
| ARCANE SIGNET                      | Card                  |     20 |
| DEATHRITE SHAMAN                   | Card                  |     20 |
| DEMONIC CONSULTATION               | Card                  |     20 |
| LIM-DÛL'S VAULT                    | Card                  |     20 |
| LOTUS PETAL                        | Card                  |     20 |
| NOBLE HIERARCH                     | Card                  |     20 |
| RHYSTIC STUDY                      | Card                  |     20 |
| SYLVAN LIBRARY                     | Card                  |     20 |
| THASSA'S ORACLE                    | Card                  |     20 |
| WINDFALL                           | Card                  |     20 |
| FELLWAR STONE                      | Card                  |     18 |
| AVACYN'S PILGRIM                   | Card                  |     15 |
| BIRDS OF PARADISE                  | Card                  |     15 |
| BLOOM TENDER                       | Card                  |     15 |
| BRAINSTORM                         | Card                  |     15 |
| DARK CONFIDANT                     | Card                  |     15 |
| ELVES OF DEEP SHADOW               | Card                  |     15 |
| FORCE OF WILL                      | Card                  |     15 |
| ISOCHRON SCEPTER                   | Card                  |     15 |
| TAINTED PACT                       | Card                  |     15 |
| COMMAND TOWER                      | Card                  |     14 |
| CITY OF BRASS                      | Card                  |     12 |
| MANA CONFLUENCE                    | Card                  |     12 |
| PONDER                             | Card                  |     12 |
| CHAIN OF VAPOR                     | Card                  |     10 |
| CYCLONIC RIFT                      | Card                  |     10 |
| DRAMATIC REVERSAL                  | Card                  |     10 |
| FLOODED STRAND                     | Card                  |     10 |
| FORBIDDEN ORCHARD                  | Card                  |     10 |
| GEMSTONE CAVERNS                   | Card                  |     10 |
| GILDED DRAKE                       | Card                  |     10 |
| MANA DRAIN                         | Card                  |     10 |
| MISTY RAINFOREST                   | Card                  |     10 |
| NOTION THIEF                       | Card                  |     10 |
| PACT OF NEGATION                   | Card                  |     10 |
| POLLUTED DELTA                     | Card                  |     10 |
| PREORDAIN                          | Card                  |     10 |
| SCALDING TARN                      | Card                  |     10 |
| SENSEI'S DIVINING TOP              | Card                  |     10 |
| SMOTHERING TITHE                   | Card                  |     10 |
| BLOODSTAINED MIRE                  | Card                  |      8 |
| MARSH FLATS                        | Card                  |      8 |
| VERDANT CATACOMBS                  | Card                  |      8 |
| WINDSWEPT HEATH                    | Card                  |      8 |
| WOODED FOOTHILLS                   | Card                  |      8 |
| ABRUPT DECAY                       | Card                  |      5 |
| FLUSTERSTORM                       | Card                  |      5 |
| MENTAL MISSTEP                     | Card                  |      5 |
| NOXIOUS REVIVAL                    | Card                  |      5 |
| SILENCE                            | Card                  |      5 |
| TOXIC DELUGE                       | Card                  |      5 |
| TROPICAL ISLAND                    | Card                  |      5 |
| TUNDRA                             | Card                  |      5 |
| UNDERGROUND SEA                    | Card                  |      5 |
| VEIL OF SUMMER                     | Card                  |      5 |
| ASSASSIN'S TROPHY                  | Card                  |      3 |
| BAYOU                              | Card                  |      3 |
| SAVANNAH                           | Card                  |      3 |
| MORPHIC POOL                       | Card                  |      2 |
+------------------------------------+-----------------------+--------+

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

And here's Feather too since that has some of the most comprehensive synergy data:
+------------------------------------+
|         RUMPY5897_feather          |
+----------------+-------------------+
|   Raw Score    |        505        |
|   Tutor Mult   |        1.0        |
|   Curve Mult   |        0.71       |
| Synergy Score  |        143        |
| Adjusted Score | 458.0207992686318 |
+----------------+-------------------+
+---------------------------+----------------------+--------+
| Point Source              | Factor               | Points |
+---------------------------+----------------------+--------+
| FEATHER, THE REDEEMED     | Commander            |     60 |
| feather, the redeemed     | bandage              |     10 |
| feather, the redeemed     | crimson wisps        |     10 |
| feather, the redeemed     | defiant strike       |     10 |
| feather, the redeemed     | expedite             |     10 |
| feather, the redeemed     | heal                 |     10 |
| feather, the redeemed     | niveous wisps        |     10 |
| feather, the redeemed     | panic                |     10 |
| feather, the redeemed     | shelter              |     10 |
| feather, the redeemed     | eerie interlude      |      7 |
| feather, the redeemed     | fists of flame       |      7 |
| feather, the redeemed     | gods willing         |      7 |
| feather, the redeemed     | sheltering light     |      7 |
| feather, the redeemed     | stand firm           |      7 |
| feather, the redeemed     | apostle's blessing   |      4 |
| feather, the redeemed     | cloudshift           |      4 |
| feather, the redeemed     | ephemerate           |      4 |
| feather, the redeemed     | faith's shield       |      4 |
| feather, the redeemed     | liberate             |      4 |
| feather, the redeemed     | long road home       |      4 |
| feather, the redeemed     | otherworldly journey |      4 |
| MANA CRYPT                | Card                 |    100 |
| SOL RING                  | Card                 |     85 |
| MOX DIAMOND               | Card                 |     40 |
| CHROME MOX                | Card                 |     35 |
| DOCKSIDE EXTORTIONIST     | Card                 |     25 |
| ARCANE SIGNET             | Card                 |     20 |
| COMMAND TOWER             | Card                 |     14 |
| CITY OF BRASS             | Card                 |     12 |
| MANA CONFLUENCE           | Card                 |     12 |
| FLOODED STRAND            | Card                 |     10 |
| SCALDING TARN             | Card                 |     10 |
| TALISMAN OF CONVICTION    | Card                 |      9 |
| SWORD OF FEAST AND FAMINE | Card                 |      8 |
| ARID MESA                 | Card                 |      8 |
| BLOODSTAINED MIRE         | Card                 |      8 |
| MARSH FLATS               | Card                 |      8 |
| WINDSWEPT HEATH           | Card                 |      8 |
| WOODED FOOTHILLS          | Card                 |      8 |
| BOROS SIGNET              | Card                 |      7 |
| PATH TO EXILE             | Card                 |      5 |
| SWORDS TO PLOWSHARES      | Card                 |      5 |
| GENEROUS GIFT             | Card                 |      5 |
| PLATEAU                   | Card                 |      3 |
+---------------------------+----------------------+--------+

User avatar
Rumpy5897
Tuner of Jank
Posts: 1859
Joined: 4 years ago
Pronoun: he / him

Post by Rumpy5897 » 4 years ago

So I've flagged down pokken on Discord, and he gave me the power to commit to the repository. That likely marks the end of random code snippets plain dumped into the thread :P

The point files have been streamlined and converted to TSV (tab-separated values) to make them easier to add stuff to. No need to worry about screwy quotes to get things working, but instead there may be some invisible trailing tabs at the end. This should make it easier to contribute to. This is a thinly veiled doubling down on pokken's invitation for people to contribute :P For reference, the Sunforger entry now looks a lot more legible like so:
{"card":["sunforger"]}	{"type":["instant"],"cmc":["<5"],"color":["r|w"]}	2		
Final form of query enhancement
Show
Hide
The query system got integrated into the code, along with new negation functionality. Negation is denoted by a ! at the start of the query, and has to be done separately for each part of an OR if relevant. For example, Monastery Mentor's synergy set is defined as {"type":["!creature","!land"]}. The bulk of the query handled logic is handled by this function:

https://bitbucket.org/pokken/cmdrdeckra ... ines-27:79

Actually evaluating the queries inside the object becomes easier then, as you can just feed it the entire deck object (for card/commander queries) or the relevant card in a loop (for everything else). A little ugly, but both forms have the requisite attributes accessible at the same level so it works.

https://bitbucket.org/pokken/cmdrdeckra ... es-150:168
 
EDH Primers (click me!)
Deck is Kill Club
Show
Hide

User avatar
pokken
Posts: 6388
Joined: 4 years ago
Answers: 2
Pronoun: he / him

Post by pokken » 4 years ago

Rumpy5897 wrote:
4 years ago
So I've flagged down pokken on Discord, and he gave me the power to commit to the repository. That likely marks the end of random code snippets plain dumped into the thread :P

The point files have been streamlined and converted to TSV (tab-separated values) to make them easier to add stuff to. No need to worry about screwy quotes to get things working, but instead there may be some invisible trailing tabs at the end. This should make it easier to contribute to. This is a thinly veiled doubling down on pokken's invitation for people to contribute :P For reference, the Sunforger entry now looks a lot more legible like so:
{"card":["sunforger"]}	{"type":["instant"],"cmc":["<5"],"color":["r|w"]}	2		
Final form of query enhancement
Show
Hide
The query system got integrated into the code, along with new negation functionality. Negation is denoted by a ! at the start of the query, and has to be done separately for each part of an OR if relevant. For example, Monastery Mentor's synergy set is defined as {"type":["!creature","!land"]}. The bulk of the query handled logic is handled by this function:

https://bitbucket.org/pokken/cmdrdeckra ... ines-27:79

Actually evaluating the queries inside the object becomes easier then, as you can just feed it the entire deck object (for card/commander queries) or the relevant card in a loop (for everything else). A little ugly, but both forms have the requisite attributes accessible at the same level so it works.

https://bitbucket.org/pokken/cmdrdeckra ... es-150:168
Dude you killed it :)

how sweet is this:
{"card":["monastery mentor"]}	{"type":["!creature","!land"]}	1
I'm not sure how much more terse and beautiful that could be. I'm extremely excited!

I feel like this is at the point where we could gather data and have it be pretty meaningful -- Feather is really solid.
Feather synergy points
Show
Hide
+---------------------------+----------------------+--------+
| Point Source              | Factor               | Points |
+---------------------------+----------------------+--------+
| FEATHER, THE REDEEMED     | Commander            |     60 |
| feather, the redeemed     | bandage              |     10 |
| feather, the redeemed     | crimson wisps        |     10 |
| feather, the redeemed     | defiant strike       |     10 |
| feather, the redeemed     | expedite             |     10 |
| feather, the redeemed     | heal                 |     10 |
| feather, the redeemed     | niveous wisps        |     10 |
| feather, the redeemed     | panic                |     10 |
| feather, the redeemed     | shelter              |     10 |
| feather, the redeemed     | eerie interlude      |      7 |
| feather, the redeemed     | fists of flame       |      7 |
| feather, the redeemed     | gods willing         |      7 |
| feather, the redeemed     | sheltering light     |      7 |
| feather, the redeemed     | stand firm           |      7 |
| feather, the redeemed     | apostle's blessing   |      4 |
| feather, the redeemed     | cloudshift           |      4 |
| feather, the redeemed     | ephemerate           |      4 |
| feather, the redeemed     | faith's shield       |      4 |
| feather, the redeemed     | liberate             |      4 |
| feather, the redeemed     | long road home       |      4 |
| feather, the redeemed     | otherworldly journey |      4 |
| stoneforge mystic         | equipment            |      6 |
| sunforger                 | instant              |     58 |
| young pyromancer          | instant|sorcery      |     30 |
| monastery mentor          | !creature,!land      |     48 |

User avatar
Feyd_Ruin
Elder Vampire
Posts: 5410
Joined: 5 years ago
Answers: 3
Pronoun: he / him
Contact:

Post by Feyd_Ruin » 4 years ago

I've created [PULLCODE] so you all can more easily link to specific lines, etc, as Rumpy requested.
It's a normall bbcode with line=LINE_NUMBER and the url inside.

Right now it only works with bitbucket since that's what you're using, but I can add github/etc later if need be.

Usage:

Code: Select all

[pullcode line=150]https://bitbucket.org/pokken/cmdrdeckrank/src/b95ccdb32e4f1ddf30cb36d36d8c2af6b12da90b/analyze_decks.py[/pullcode]
Result:
To the beaten, the broken, or the damned; the lost, and the wayward: wherever I may be, you will have a home.

Post Reply Previous topicNext topic

Return to “Commander”