I wrote a quick program today that takes in a matrix of deck win percentages (along the lines of what e.g. Ryan Eberhart provides in his MTGO Power 9 analyses, middle-left chart) and computes the metagame breakdown that you would expect to see if the metagame is in equilibrium.
Overview
Suppose we have a metagame with two decks: for the sake of exposition, let’s call them Mardu Vehicles and Janky Rogue Brew (Replace Mardu Vehicles with CoCo, or CawBlade, or Bloodbraid Elf aggro, or Mono Black Devotion, etc etc, to discover why I never play Standard.)
Let’s say you are planning on attending a tournament, and are trying to decide which deck to bring. For each deck, let’s assume that you can calculate (based on historical data, playtesting, etc) the match win probability of that deck against the field.
Obviously, if you play a mirror match, your match win probability is 50%. The only additional data you need is how likely Mardu Vehicles is to beat the Janky Rogue Brew: if Vehicles is an 80% favorite, then you also know that the rogue deck has only a 20% chance of beating Vehicles.
We can summarize the probabilities in a matrix:
MarduVehicles | RogueBrew | |
---|---|---|
MarduVehicles | 0.5 | 0.8 |
RogueBrew | 0.2 | 0.5 |
The way to read this table is to find the deck you are considering playing on the left, then look up the column of the deck that you will be playing against. We can call this 2x2 matrix of win probabilities P.
The other piece of metagame information we need is how many people will be playing each deck. We can encode this information in a vector, say (0.9,0.1), representing a hypothetical metagame where 90% of people are currently playing Vehicles, and 10% are playing the Jank Brew. Let’s call this metagame breakdown vector m.
Finally we can calculate our expectation to win a game with each deck: w=Pm. In this case we will get (0.53, 0.23).
This makes sense: if we play Vehicles, we have a very high (90%) chance of playing a mirror match, and in that case, whether or not we win is a tossup. The other 10% of the time, we will playing the Jank deck, and win almost every time. This bumps our overall chance to win a random game up slightly above 50%.
Now if we want to pick a deck for the tournament, our choice is clear (assuming we are using no other considerations beyond maximizing our match win probability): play Vehicles.
Equilibrium Metagames
Of course, we are not the only players going through this exact exercise: others will observe the same facts we did (that it is far better, for maximizing win probability, to play Vehicles than the Jank deck). Thus two things will happen over time: first, players will switch decks, and m will change. Second, players will innovate, and modify their decks, or perhaps brew an entirely new deck to prey on both existing decks. In this section, we will analyze only the first effect: the change in the metagame composition, assuming that the deck contents stay fixed.
We will need a slew of assumptions about player behavior to make this analysis: for example, we will assume that
- players pick a deck purely based on its expected win probability in a single match
- all players play with equal skill
- all players have perfect information about the metagame and adapt instantly to changes in the metagame;
and of course there are many potential objections to each of these assumptions! But let us forge ahead anyway, since we need some reasonable starting point for making our analysis.
If players have perfect information about the metagame, they can look at the vector w and draw the following conclusions: if they are already playing Vehicles, they are already playing the best deck, and have no reason to change decks. If they are playing the Jank deck, they notice that they can strictly increase their win probability by dropping Jank and picking up Vehicles. Therefore over time, there will be a shift in players away from Jank and towards Vehicles. This shift will continue until either (i) all players are playing Vehicles, or (ii) both decks have the same match win probability, i.e., 1/2, in which case all players are happy with their deck choice and do not change.
Let us call a metagame (P,m) where all players are happy with their current deck an equilibrium metagame. We can characterize such a metagame mathematically as one where
The decks with m_i=0 are those that have been extirpated from the metagame due to being too poor against the rest of the field. Let us call such decks dominated. Every non-dominated deck must have a win probability of exactly 1/2, otherwise everyone would switch to a better deck with a higher win percentage. The last condition, that m_i >= 0, encodes the fact that the fraction of the metagame occupied by a deck cannot be negative.
Computing the equilibrium metagame is not so trivial (it is a type of quadratic programming problem called a linear complementarity problem (LCP), and as far as I can tell a nasty one at that, since the matrix P is not symmetric) but the code below does so, essentially by checking for every possible set of dominated decks and solving for a possible equilibrium with those decks dominated. If I run the code on the Vehicles, for example, it is obvious that Vehicles dominates the Jank brew, and indeed I get that the equilibrium metagame is
Equilibrium Metagame:
MarduVehicles 100%
RogueBrew 0%.
Perhaps more interesting is applying the code to the Vintage metagame described in Eberhart's P9 results. We get
Equilibrium Metagame:
Shops 24.9007%
Eldrazi 24.4953%
Dredge 8.3284%
Combo 20.9646%
Oath 6.50955%
BigBlue 10.6315%
Mentor 0%
BlueControl 0%
Other 4.16994%
which says that, according to the P9 win percentages, it is incorrect to play Mentor(!!!). Of course it is easy to explain away this conclusion: the win percentages in Eberhart's data are not very robust (Mentor doesn't really have a 0% win probability against Dredge and Combo, for instance), weaker players tend to play the most popular deck, depressing Mentor's win statistics, etc. But it's a starting point if you want to play around with how altering the win percentages of decks against each other alters the expected metagame balance. For instance, it is possible to observe several counterintuitive effects:
- Banning a card that weakens a deck (decreases its win percentage against the entire field) can increase the deck's prevalence in the metagame;
- Conversely, a new printing that strictly improves an existing deck can sometimes cause its presence in the metagame to decrease;
- Adding a new deck that is good against the current best deck, but weak against the rest of the field (which is the effect of printing more cards like Flusterstorm, Gush, Library of Alexandria, etc) often causes the rest of the field's metagame prevalence to increase at the cost of both the new deck and the old best deck.
Here is the code if you want to try yourself. You will need the Eigen linear algebra library. The code expects the first line of the input to be the number N of decks in the metagame, followed by N lines of N+1 columns each, where each line begins with the deck name (one word, no spaces) followed by N floating-point numbers listing the win percentage of the deck against the field (including itself).
#include <Eigen/Core>
#include <Eigen/Dense>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
bool hasEquilibrium(const Eigen::MatrixXd &P, int dominated, Eigen::VectorXd &result)
{
int ndecks = P.rows();
result.resize(ndecks);
int idx = 0;
vector<int> idxmap;
while (dominated > 0)
{
if (dominated % 2 == 1)
{
idxmap.push_back(idx);
}
idx++;
dominated /= 2;
}
int subdecks = idxmap.size();
Eigen::MatrixXd subP(subdecks, subdecks);
for (int i = 0; i < subdecks; i++)
{
for (int j = 0; j < subdecks; j++)
{
subP(i, j) = P(idxmap[i], idxmap[j]);
}
}
Eigen::VectorXd rhs(subdecks);
rhs.setConstant(0.5);
Eigen::FullPivHouseholderQR<Eigen::MatrixXd> solver(subP);
Eigen::VectorXd sol = solver.solve(rhs);
if ((subP*sol - rhs).norm() > 1e-8)
{
cerr << "Warning: linear solve failed on domination strategy " << dominated << endl;
}
for (int i = 0; i < subdecks; i++)
{
if (sol[i] < 1e-8)
return false;
}
result.setZero();
for (int i = 0; i < subdecks; i++)
{
result[idxmap[i]] = sol[i];
}
Eigen::VectorXd candidate = P*result;
for (int i = 0; i < ndecks; i++)
{
if (candidate[i] - 0.5 > 1e-8)
return false;
}
return true;
}
int main()
{
int ndecks;
cin >> ndecks;
if (ndecks < 1)
{
cerr << "Error: you must provide at least one deck win percentage to analyze" << endl;
return -1;
}
if (ndecks > 30)
{
cerr << "Error: too many decks" << endl;
return -1;
}
if (ndecks > 18)
{
cerr << "Warning: this analysis runs in exponential time. It may take quite a while to process a metagame with " << ndecks << " decks" << endl;
}
Eigen::MatrixXd P(ndecks, ndecks);
vector<string> names;
for (int i = 0; i < ndecks; i++)
{
string name;
cin >> name;
names.push_back(name);
for (int j = 0; j < ndecks; j++)
{
double winpercent;
cin >> winpercent;
P(i,j) = winpercent;
}
}
for (int i = 0; i < ndecks; i++)
{
for (int j = i; j < ndecks; j++)
{
if (fabs(P(i, j) + P(j, i) - 1.0) > 1e-8)
{
cerr << "Warning: entries (" << i+1 << ", " << j+1 << ") and (" << j+1 << ", " << i+1 << ") don't sum to one!" << endl;
}
}
}
// check for all possible sets of dominated decks
for (int dominated = 1; dominated < (1 << ndecks); dominated++)
{
Eigen::VectorXd breakdown;
if (hasEquilibrium(P, dominated, breakdown))
{
cout << "Equilibrium Metagame:" << endl;
for (int i = 0; i < ndecks; i++)
{
cout << names[i] << " " << 100*breakdown[i] << '%' << endl;
}
}
}
}
EDIT: A few words about the next steps:
-
More reliable data is needed to fill out the match win probability matrix for the current set of Vintage archetypes. I used the P9 data as quick way to get started, but a single-digit number of games is woefully inadequate for determining the match win probability of two decks against each other.
-
Now it is possible to play around with the data: you can simulate the effect of adding a new printing, or restricting a card, by adjusting the win probabilities between decks, and/or adding new decks to the metagame. Of course estimating the effect of restrictions etc. on match win percentage is not an exact science (unless somebody is willing to do a lot of playtesting), but what the program above will allow you to do is to quantify the exact and often counterintuitive relationship between changes in match win percentage and changes in metagame balance. "Restriction Gush will actually help Mentor" is the kind of claim that can be tested, for instance.