The best kittens, technology, and video games blog in the world.

Sunday, June 24, 2012

Game Theory proves that UW Delver deserves a banhammer

Ragnificent Ragdolls - Mushu as a kitten by DirtBikeDBA (Mike) from flickr (CC-NC-ND)
On June 20th none of UW Delver cards have been banned. This was a horrible decision, but I'm not going to say one word about specifics of UW Delver in this post, since that has been discussed ad nauseam in other places. The entire post is about DCI's reasoning for lack of bans, and how it shows total lack of understanding of basic statistics and game theory. Let me quote the decision:

The DCI looked at the results of competitive Standard events. We found that while a high percentage of the participants played White-Blue Delver decks, that the win rate of those decks was very close to par. For instance, in a recent MTGO PTQ, the win rate of White-Blue Delver decks against non-Delver decks was a bit under 51%. In general there are decks that the Delver deck is strong against, and decks that it is weak against, but on average the deck tends to get results close to average
Additionally the number of people playing high level Standard events is the highest ever. Looking at the Magic 2013 card set, it appears that there may be more tools for other decks than for the White-Blue Delver deck, though time will tell if this bears out. The DCI will continue to observe how this plays out, but is taking no action.
I know nothing of tournament attendance, and as for new M13 cards I'll just quote this as a cautionary tale:
We tried to enable a few specific anti-Jace weapons in Mirrodin Besieged with Phyrexian Revoker, Hero of Oxid Ridge, and Thrun, the Last Troll, but the metagame solved those cards pretty quickly with Squadron Hawks and Swords.
New Phyrexia brought with it Despise and Hex Parasite, but those cards just aren't powerful or versatile enough.
Anyway, the biggest argument is "on average the deck tends to get results close to average". I'll show you in simple mathematical terms why this is not only wrong, it's completely backwards.

Simplifying assumptions

None of these assumptions are essential to the argument, they just make the math simpler. If you have time, you can redo the proof in a more complicated variant.

Let's assume that each player plays to win (more on that later), knows meta, players playing each archetype are equally good on average (this doesn't preclude some players being better, as long as they're either few of such superstars or they're not particularly attached to any archetypes, or both), and has no budget constraints (that's a reasonable assumption in Standard, where competitive deck prices are similar, less so in Vintage).

Let's assume there are N possibly tournament-viable archetypes in a format, and disregard issues like minor variants within each archetype, sideboarding strategies etc.

For each pair of such archetypen I and J, p(I,J) is probability that first player (playing I) wins the match. We don't need pre-sideboard and post-sideboard win probabilities, since if α and β are pre and post sideboard probabilities respectively, then:
p = αβ + α(1 - β)β + (1 - α)ββ
And by similar reasoning all kinds of on-play vs on-draw chances can be folded into a single number. There will be slight inaccuracy if some games are best-of-3 and others are best-of-5, if some games have unusually high chance of being drawn unintentionally due to timeouts (like control mirrors vs aggro mirrors) and if people decide to do intentional draw or not depending on what their opponent is playing, but we'll just fold as much of these as we can into a single "match win %" number, and won't be too concerned with that cannot be simulated this way.

How players decide what to play

There are many ways to simulate this, and they all lead to very similar outcomes. Since we assumed N archetypes, let's start with each of them having 1/N of the field. To make all these long lists of numbers look less dreadful I'll call the decks by randomly assigned 2 and 3 color combinations (but they're actually just labels).

Then people are paired randomly with another player, and each match loss makes a player change their deck with some low probability to a deck randomly chosen from current meta (so if 20% of people are playing archetype X, a player which wants to change their deck will pick X with 20% probability; if they already play X they have 20% chance of picking another decklist within the same archetype for simplicity).

Now this isn't particularly realistic - someone who lost 5/5 games is more than 5x more likely to change their deck than someone who lost just 1/5 on mana screw - but almost any such procedure for evolving meta will lead to very similar outcomes. Got it so far? Now let's create a fresh format with 20 archetypes, generate random matrix of match probabilities within 25%..75% range (except mirror match is always 50% by definition), set decklist-change-after-loss to 1% and simulate some rounds. What will be archetypes' meta shares and their average win percentages? Let's see one such random meta!

Random Fair Meta

It's time to run some simulations. At the beginning meta looks really balanced, no deck has particularly high or particularly low chance against the field (it is honestly just a coincidence that UW got on top):
  • UW - 5.0 (55.4)
  • Bant - 5.0 (52.7)
  • WR - 5.0 (52.5)
  • GB - 5.0 (52.5)
  • WB - 5.0 (52.3)
  • UR - 5.0 (51.9)
  • RUG - 5.0 (51.1)
  • Grixis - 5.0 (50.8)
  • BUG - 5.0 (50.6)
  • Kaalia - 5.0 (50.4)
  • Jund - 5.0 (49.5)
  • Junk - 5.0 (48.9)
  • Naya - 5.0 (48.9)
  • Esper - 5.0 (48.6)
  • GU - 5.0 (48.2)
  • GR - 5.0 (48.1)
  • BR - 5.0 (47.4)
  • UB - 5.0 (47.2)
  • WUR - 5.0 (47.1)
  • WG - 5.0 (46.0)
After 2000 rounds we start to see meta forming, but no deck is particularly bad:
  • UW - 13.7 (54.1)
  • Bant - 8.6 (52.5)
  • WB - 7.2 (50.6)
  • Grixis - 6.9 (52.7)
  • GB - 6.6 (50.4)
  • WR - 6.3 (49.5)
  • UR - 5.5 (48.8)
  • RUG - 4.9 (48.4)
  • Esper - 4.5 (50.4)
  • Kaalia - 4.3 (48.5)
  • Jund - 4.1 (49.0)
  • GU - 3.7 (49.3)
  • BUG - 3.4 (45.5)
  • Junk - 3.3 (47.2)
  • Naya - 3.3 (46.9)
  • UB - 3.1 (48.5)
  • GR - 3.1 (47.0)
  • BR - 3.0 (47.6)
  • WUR - 2.8 (47.4)
  • WG - 1.8 (43.7)
4000 rounds, UW is top deck, but Grixis has highest win percentage, so it goes up:
  • UW - 21.1 (50.0)
  • Grixis - 14.4 (54.0)
  • Bant - 11.5 (50.0)
  • GB - 7.0 (50.7)
  • WB - 6.1 (48.5)
  • Esper - 5.0 (49.9)
  • WR - 4.4 (47.8)
  • GU - 4.0 (51.4)
  • Jund - 3.9 (50.7)
  • Kaalia - 3.6 (50.5)
  • UR - 3.2 (46.1)
  • UB - 3.1 (51.7)
  • RUG - 2.7 (45.7)
  • Junk - 1.9 (47.8)
  • BR - 1.9 (47.7)
  • WUR - 1.7 (46.8)
  • GR - 1.6 (46.9)
  • Naya - 1.6 (46.5)
  • BUG - 1.0 (42.7)
  • WG - 0.4 (41.4)
10000 rounds, a lot of decks are seeing no play, Grixis was even briefly top deck, but then falls down in popularity, a lot of rearrangement in top 5:
  • UW - 20.1 (52.2)
  • WB - 14.5 (48.7)
  • Bant - 12.0 (53.2)
  • GB - 11.7 (48.4)
  • Kaalia - 10.1 (47.9)
  • Grixis - 7.5 (48.8)
  • GU - 5.6 (50.1)
  • Jund - 4.9 (49.8)
  • UB - 3.3 (48.7)
  • WR - 2.9 (46.8)
  • Esper - 2.3 (52.0)
  • Junk - 2.1 (49.6)
  • BR - 1.4 (50.6)
  • Naya - 0.5 (45.8)
  • RUG - 0.5 (49.0)
  • UR - 0.4 (46.6)
  • GR - 0.1 (42.5)
  • WUR - 0.1 (45.8)
  • BUG - 0.0 (43.6)
  • WG - 0.0 (42.1)
After 20000 rounds:
  • Bant - 25.7 (50.7)
  • UW - 17.4 (50.0)
  • Kaalia - 10.7 (47.7)
  • Jund - 9.8 (51.1)
  • GB - 7.9 (48.5)
  • WB - 7.7 (46.7)
  • Grixis - 6.4 (52.6)
  • UB - 5.0 (53.2)
  • Esper - 2.4 (52.4)
  • Junk - 2.1 (49.6)
  • GU - 1.7 (48.6)
  • BR - 1.7 (50.6)
  • RUG - 0.9 (50.7)
  • WR - 0.5 (47.1)
  • UR - 0.1 (49.1)
  • Naya - 0.0 (43.7)
  • BUG - 0.0 (45.6)
  • WUR - 0.0 (43.9)
  • GR - 0.0 (41.9)
  • WG - 0.0 (40.6)
50000 rounds:
  • UW - 27.3 (51.2)
  • Bant - 15.8 (52.2)
  • Kaalia - 12.9 (47.1)
  • Junk - 11.1 (48.4)
  • GB - 9.2 (49.7)
  • Grixis - 8.5 (51.9)
  • WB - 6.3 (46.8)
  • UB - 4.5 (48.9)
  • RUG - 2.1 (50.0)
  • Jund - 0.7 (49.3)
  • BR - 0.6 (49.5)
  • GU - 0.3 (49.3)
  • UR - 0.3 (48.3)
  • Esper - 0.2 (53.1)
  • WR - 0.2 (46.2)
  • Naya - 0.0 (45.2)
  • WUR - 0.0 (47.8)
  • BUG - 0.0 (43.2)
  • GR - 0.0 (40.7)
  • WG - 0.0 (38.3)
75000 rounds:
  • Bant - 24.4 (49.9)
  • UW - 18.5 (49.2)
  • Grixis - 13.5 (52.5)
  • Kaalia - 12.0 (47.7)
  • WB - 10.9 (47.1)
  • UB - 6.5 (54.7)
  • GB - 4.5 (48.8)
  • Esper - 3.6 (53.3)
  • Junk - 2.7 (51.1)
  • Jund - 1.3 (51.0)
  • BR - 1.1 (52.3)
  • RUG - 0.9 (48.0)
  • GU - 0.1 (51.3)
  • WR - 0.0 (46.2)
  • UR - 0.0 (46.1)
  • Naya - 0.0 (46.3)
  • WUR - 0.0 (43.2)
  • BUG - 0.0 (41.9)
  • GR - 0.0 (41.9)
  • WG - 0.0 (39.8)
100000 rounds:
  • UW - 27.1 (48.0)
  • Grixis - 21.4 (51.1)
  • GB - 13.1 (51.4)
  • Kaalia - 11.2 (52.2)
  • UB - 7.8 (52.1)
  • Bant - 6.9 (48.1)
  • RUG - 3.9 (45.7)
  • WB - 3.3 (51.8)
  • Junk - 2.7 (49.4)
  • BR - 1.3 (47.6)
  • Esper - 0.7 (47.8)
  • Jund - 0.7 (49.8)
  • GU - 0.0 (51.1)
  • WR - 0.0 (49.4)
  • UR - 0.0 (45.1)
  • Naya - 0.0 (47.9)
  • WUR - 0.0 (47.6)
  • BUG - 0.0 (41.6)
  • GR - 0.0 (44.3)
  • WG - 0.0 (37.6)
OK, let's stop there. This randomly generated meta was actually fairly healthy, with multiple decks being playable, and frequent rearrangement.

But did you notice something interesting about win chances (they're against whole field including mirrors)? At no point did any deck have a chance far higher than 52%, while worst decks were really low like <40% bad. Shouldn't average of win rates be exactly 50%?

Actually, no! Average win rate against random field (round 0) is 50% - but once meta establishes win chances are calculated against other good decks (so they're close to 50%), white bad deck changes are also calculated against good decks (so they're much worse than 50%). It doesn't matter how hard any deck crushes bad decks, since they're not in meta in any appreciable amounts, and so they're not counted.

Let me restate this:
Average win rates of decks in any meta are always lower than 50%, since better decks are played more than bad decks. It is difficult for any deck to have much higher win rate than 50%.
Abby - cat loaf 1 by DirtBikeDBA (Mike) from flickr (CC-NC-ND)

Random Unfair Metas

Now that was a reasonably healthy meta. What about metas which are totally unbalanced and unfair? Let's simulate one.

Now let's pick one deck - let's say UW (for no particular reason, it just happened to be the first in my list of labels, honest...) - for which win probabilities are taken from 0.45..0.75 range, while all other decks have to use 0.25..0.75 range. That's right - this UW doesn't have particularly high chances against any deck, it simply never has particularly low chances against any deck.

Let's give it a try. After 0 rounds:
  • UW - 5.0 (all 61.7 / no mirror 62.3 / against UW 50.0 / except UW and mirror 62.3)
  • Junk - 5.0 (all 55.9 / no mirror 56.2 / against UW 26.5 / except UW and mirror 57.9)
  • BUG - 5.0 (all 53.7 / no mirror 53.9 / against UW 37.4 / except UW and mirror 54.8)
  • Grixis - 5.0 (all 52.2 / no mirror 52.3 / against UW 47.3 / except UW and mirror 52.5)
  • Naya - 5.0 (all 50.9 / no mirror 51.0 / against UW 30.9 / except UW and mirror 52.1)
  • Kaalia - 5.0 (all 50.5 / no mirror 50.5 / against UW 41.0 / except UW and mirror 51.1)
  • RUG - 5.0 (all 50.3 / no mirror 50.4 / against UW 46.5 / except UW and mirror 50.6)
  • GB - 5.0 (all 50.2 / no mirror 50.2 / against UW 27.3 / except UW and mirror 51.5)
  • GU - 5.0 (all 50.1 / no mirror 50.1 / against UW 50.8 / except UW and mirror 50.0)
  • WUR - 5.0 (all 49.8 / no mirror 49.8 / against UW 38.4 / except UW and mirror 50.5)
  • UB - 5.0 (all 49.7 / no mirror 49.7 / against UW 39.7 / except UW and mirror 50.3)
  • BR - 5.0 (all 49.2 / no mirror 49.2 / against UW 31.6 / except UW and mirror 50.2)
  • Jund - 5.0 (all 48.8 / no mirror 48.8 / against UW 34.7 / except UW and mirror 49.6)
  • Bant - 5.0 (all 48.6 / no mirror 48.5 / against UW 35.5 / except UW and mirror 49.2)
  • Esper - 5.0 (all 47.3 / no mirror 47.1 / against UW 51.3 / except UW and mirror 46.9)
  • WB - 5.0 (all 47.1 / no mirror 47.0 / against UW 39.6 / except UW and mirror 47.4)
  • WG - 5.0 (all 47.1 / no mirror 46.9 / against UW 25.2 / except UW and mirror 48.1)
  • WR - 5.0 (all 47.0 / no mirror 46.8 / against UW 37.1 / except UW and mirror 47.4)
  • UR - 5.0 (all 46.0 / no mirror 45.8 / against UW 29.1 / except UW and mirror 46.8)
  • GR - 5.0 (all 43.9 / no mirror 43.6 / against UW 46.6 / except UW and mirror 43.4)
After 100000 rounds:
  • UW - 68.7 (all 49.6 / no mirror 48.7 / against UW 50.0 / except UW and mirror 48.7)
  • Esper - 30.8 (all 50.9 / no mirror 51.3 / against UW 51.3 / except UW and mirror 51.1)
  • GU - 0.5 (all 50.2 / no mirror 50.2 / against UW 50.8 / except UW and mirror 48.9)
  • Grixis - 0.0 (all 49.6 / no mirror 49.6 / against UW 47.3 / except UW and mirror 54.6)
  • WUR - 0.0 (all 49.5 / no mirror 49.5 / against UW 38.4 / except UW and mirror 73.7)
  • BUG - 0.0 (all 48.2 / no mirror 48.2 / against UW 37.4 / except UW and mirror 71.9)
  • WR - 0.0 (all 46.5 / no mirror 46.5 / against UW 37.1 / except UW and mirror 67.3)
  • Bant - 0.0 (all 43.9 / no mirror 43.9 / against UW 35.5 / except UW and mirror 62.3)
  • RUG - 0.0 (all 43.0 / no mirror 43.0 / against UW 46.5 / except UW and mirror 35.2)
  • BR - 0.0 (all 43.9 / no mirror 43.9 / against UW 31.6 / except UW and mirror 70.9)
  • Naya - 0.0 (all 42.8 / no mirror 42.8 / against UW 30.9 / except UW and mirror 69.0)
  • GR - 0.0 (all 42.5 / no mirror 42.5 / against UW 46.6 / except UW and mirror 33.4)
  • Kaalia - 0.0 (all 40.5 / no mirror 40.5 / against UW 41.0 / except UW and mirror 39.5)
  • Junk - 0.0 (all 40.3 / no mirror 40.3 / against UW 26.5 / except UW and mirror 70.5)
  • WB - 0.0 (all 37.8 / no mirror 37.8 / against UW 39.6 / except UW and mirror 34.0)
  • UB - 0.0 (all 38.4 / no mirror 38.4 / against UW 39.7 / except UW and mirror 35.5)
  • Jund - 0.0 (all 35.3 / no mirror 35.3 / against UW 34.7 / except UW and mirror 36.6)
  • GB - 0.0 (all 36.5 / no mirror 36.5 / against UW 27.3 / except UW and mirror 56.7)
  • UR - 0.0 (all 33.1 / no mirror 33.1 / against UW 29.1 / except UW and mirror 41.8)
  • WG - 0.0 (all 33.9 / no mirror 33.9 / against UW 25.2 / except UW and mirror 52.8)
This meta is about as degenerate as they ever get. It's 68.7% top deck, 30.8% deck designed to beat the top deck (and it barely does so), and 0.5% third deck. And do you see? Top deck's win percentage is below 50%!

Degenerate meta simply showed in high meta share, and total absence of almost all possible decks (in fair simulation 12 of 20 archetypes had some play, now it's only 3 of 20). What typically shows in simulations is that first all decks that lose to top deck get down to 0%, then top deck establishes ridiculous meta shares (often >90%), then sometimes decks which are good against it get significant share.

Here's second simulation. After 0 rounds:
  • UW - 5.0 (all 58.9 / no mirror 59.4 / against UW 50.0 / except UW and mirror 59.4)
  • GU - 5.0 (all 55.7 / no mirror 56.0 / against UW 36.8 / except UW and mirror 57.1)
  • RUG - 5.0 (all 53.2 / no mirror 53.3 / against UW 43.3 / except UW and mirror 53.9)
  • WB - 5.0 (all 53.0 / no mirror 53.2 / against UW 40.5 / except UW and mirror 53.9)
  • GR - 5.0 (all 52.6 / no mirror 52.8 / against UW 27.7 / except UW and mirror 54.2)
  • Bant - 5.0 (all 52.5 / no mirror 52.7 / against UW 49.0 / except UW and mirror 52.9)
  • WG - 5.0 (all 52.5 / no mirror 52.6 / against UW 45.9 / except UW and mirror 53.0)
  • Esper - 5.0 (all 51.1 / no mirror 51.1 / against UW 47.5 / except UW and mirror 51.3)
  • WUR - 5.0 (all 50.3 / no mirror 50.3 / against UW 43.2 / except UW and mirror 50.7)
  • UR - 5.0 (all 49.7 / no mirror 49.7 / against UW 40.7 / except UW and mirror 50.2)
  • Grixis - 5.0 (all 49.2 / no mirror 49.2 / against UW 46.1 / except UW and mirror 49.4)
  • Junk - 5.0 (all 48.8 / no mirror 48.7 / against UW 51.8 / except UW and mirror 48.6)
  • UB - 5.0 (all 48.4 / no mirror 48.3 / against UW 40.3 / except UW and mirror 48.7)
  • Naya - 5.0 (all 48.2 / no mirror 48.1 / against UW 28.8 / except UW and mirror 49.2)
  • BUG - 5.0 (all 47.5 / no mirror 47.4 / against UW 33.0 / except UW and mirror 48.2)
  • GB - 5.0 (all 47.1 / no mirror 47.0 / against UW 52.3 / except UW and mirror 46.7)
  • Jund - 5.0 (all 47.1 / no mirror 46.9 / against UW 41.9 / except UW and mirror 47.2)
  • WR - 5.0 (all 46.2 / no mirror 46.0 / against UW 33.7 / except UW and mirror 46.6)
  • Kaalia - 5.0 (all 45.1 / no mirror 44.8 / against UW 41.1 / except UW and mirror 45.1)
  • BR - 5.0 (all 42.8 / no mirror 42.4 / against UW 28.0 / except UW and mirror 43.2)
After 100000 rounds:
  • UW - 91.8 (all 50.1 / no mirror 50.7 / against UW 50.0 / except UW and mirror 50.7)
  • Esper - 5.1 (all 48.3 / no mirror 48.2 / against UW 47.5 / except UW and mirror 70.0)
  • GB - 3.1 (all 51.1 / no mirror 51.1 / against UW 52.3 / except UW and mirror 29.8)
  • Grixis - 0.0 (all 47.8 / no mirror 47.8 / against UW 46.1 / except UW and mirror 67.3)
  • Junk - 0.0 (all 50.8 / no mirror 50.8 / against UW 51.8 / except UW and mirror 39.6)
  • Bant - 0.0 (all 48.7 / no mirror 48.7 / against UW 49.0 / except UW and mirror 45.9)
  • RUG - 0.0 (all 45.2 / no mirror 45.2 / against UW 43.3 / except UW and mirror 66.7)
  • WG - 0.0 (all 45.7 / no mirror 45.7 / against UW 45.9 / except UW and mirror 43.6)
  • WUR - 0.0 (all 44.4 / no mirror 44.4 / against UW 43.2 / except UW and mirror 57.2)
  • UR - 0.0 (all 42.9 / no mirror 42.9 / against UW 40.7 / except UW and mirror 67.8)
  • Kaalia - 0.0 (all 42.8 / no mirror 42.8 / against UW 41.1 / except UW and mirror 62.2)
  • UB - 0.0 (all 40.9 / no mirror 40.9 / against UW 40.3 / except UW and mirror 47.7)
  • WB - 0.0 (all 40.6 / no mirror 40.6 / against UW 40.5 / except UW and mirror 42.4)
  • Jund - 0.0 (all 42.0 / no mirror 42.0 / against UW 41.9 / except UW and mirror 42.3)
  • GU - 0.0 (all 39.0 / no mirror 39.0 / against UW 36.8 / except UW and mirror 63.2)
  • WR - 0.0 (all 34.9 / no mirror 34.9 / against UW 33.7 / except UW and mirror 48.1)
  • BUG - 0.0 (all 33.5 / no mirror 33.5 / against UW 33.0 / except UW and mirror 39.3)
  • Naya - 0.0 (all 30.0 / no mirror 30.0 / against UW 28.8 / except UW and mirror 43.2)
  • GR - 0.0 (all 29.2 / no mirror 29.2 / against UW 27.7 / except UW and mirror 45.5)
  • BR - 0.0 (all 29.0 / no mirror 29.0 / against UW 28.0 / except UW and mirror 40.5)
This one is even worse - GB has decent matchup against UW, but since Esper is really brutal against GB (70% win rate), it makes GB totally nonviable, and UW has 91.8% meta share. So we have top deck (UW), meta deck (GB), and meta-meta deck (Esper).

Third unfair meta. After 0 rounds:
  • BR - 5.0 (all 58.4 / no mirror 58.9 / against UW 50.7 / except UW and mirror 59.3)
  • UW - 5.0 (all 56.8 / no mirror 57.2 / against UW 50.0 / except UW and mirror 57.2)
  • Esper - 5.0 (all 53.3 / no mirror 53.4 / against UW 39.3 / except UW and mirror 54.2)
  • WR - 5.0 (all 52.7 / no mirror 52.9 / against UW 54.5 / except UW and mirror 52.8)
  • RUG - 5.0 (all 52.3 / no mirror 52.4 / against UW 53.3 / except UW and mirror 52.4)
  • WB - 5.0 (all 52.2 / no mirror 52.3 / against UW 37.9 / except UW and mirror 53.1)
  • GR - 5.0 (all 51.8 / no mirror 51.9 / against UW 51.4 / except UW and mirror 51.9)
  • UB - 5.0 (all 50.6 / no mirror 50.7 / against UW 48.8 / except UW and mirror 50.8)
  • Bant - 5.0 (all 50.5 / no mirror 50.5 / against UW 33.0 / except UW and mirror 51.5)
  • Kaalia - 5.0 (all 50.0 / no mirror 50.0 / against UW 41.0 / except UW and mirror 50.5)
  • GU - 5.0 (all 48.9 / no mirror 48.9 / against UW 46.2 / except UW and mirror 49.0)
  • Junk - 5.0 (all 48.6 / no mirror 48.6 / against UW 29.7 / except UW and mirror 49.6)
  • Jund - 5.0 (all 48.4 / no mirror 48.4 / against UW 29.9 / except UW and mirror 49.4)
  • BUG - 5.0 (all 48.1 / no mirror 48.0 / against UW 46.7 / except UW and mirror 48.1)
  • GB - 5.0 (all 47.6 / no mirror 47.5 / against UW 43.3 / except UW and mirror 47.7)
  • Grixis - 5.0 (all 46.7 / no mirror 46.5 / against UW 41.8 / except UW and mirror 46.8)
  • UR - 5.0 (all 46.2 / no mirror 46.0 / against UW 26.9 / except UW and mirror 47.1)
  • WG - 5.0 (all 46.0 / no mirror 45.8 / against UW 53.6 / except UW and mirror 45.3)
  • WUR - 5.0 (all 45.7 / no mirror 45.5 / against UW 40.5 / except UW and mirror 45.7)
  • Naya - 5.0 (all 44.9 / no mirror 44.6 / against UW 44.8 / except UW and mirror 44.6)
Now BR is actually better than UW in vacuum! But since UW has no particularly awful matches, and BR presumably does, after 100000 rounds it degenerates to:
  • UW - 42.9 (all 50.6 / no mirror 51.0 / against UW 50.0 / except UW and mirror 51.0)
  • BR - 26.7 (all 50.6 / no mirror 50.9 / against UW 50.7 / except UW and mirror 51.1)
  • RUG - 14.4 (all 51.3 / no mirror 51.6 / against UW 53.3 / except UW and mirror 49.8)
  • Kaalia - 10.6 (all 46.0 / no mirror 45.5 / against UW 41.0 / except UW and mirror 49.7)
  • GU - 3.2 (all 46.4 / no mirror 46.3 / against UW 46.2 / except UW and mirror 46.4)
  • GB - 2.2 (all 47.0 / no mirror 47.0 / against UW 43.3 / except UW and mirror 49.8)
  • Naya - 0.0 (all 48.2 / no mirror 48.2 / against UW 44.8 / except UW and mirror 50.7)
  • UB - 0.0 (all 51.2 / no mirror 51.2 / against UW 48.8 / except UW and mirror 52.9)
  • WR - 0.0 (all 49.8 / no mirror 49.8 / against UW 54.5 / except UW and mirror 46.2)
  • Esper - 0.0 (all 44.3 / no mirror 44.3 / against UW 39.3 / except UW and mirror 48.1)
  • WB - 0.0 (all 42.1 / no mirror 42.1 / against UW 37.9 / except UW and mirror 45.3)
  • GR - 0.0 (all 44.8 / no mirror 44.8 / against UW 51.4 / except UW and mirror 39.9)
  • WUR - 0.0 (all 43.3 / no mirror 43.3 / against UW 40.5 / except UW and mirror 45.4)
  • Junk - 0.0 (all 40.5 / no mirror 40.5 / against UW 29.7 / except UW and mirror 48.6)
  • Bant - 0.0 (all 36.5 / no mirror 36.5 / against UW 33.0 / except UW and mirror 39.2)
  • WG - 0.0 (all 44.7 / no mirror 44.7 / against UW 53.6 / except UW and mirror 38.1)
  • BUG - 0.0 (all 41.2 / no mirror 41.2 / against UW 46.7 / except UW and mirror 37.0)
  • Grixis - 0.0 (all 39.6 / no mirror 39.6 / against UW 41.8 / except UW and mirror 38.0)
  • UR - 0.0 (all 37.5 / no mirror 37.5 / against UW 26.9 / except UW and mirror 45.4)
  • Jund - 0.0 (all 35.8 / no mirror 35.8 / against UW 29.9 / except UW and mirror 40.3)
billy and zena. by ☼Ourania2005 from flickr (CC-NC-SA)

Conclusions

I could keep rerunning these simulations, and there are some interesting and nonobvious points there, like having fewer bad matchup being more important than having any amazing matchups. The big thing which should be obvious in retrospect is:
In any stable meta top deck's win percentage will always be close to 50%. If it was much different than that people would switch to the top deck or away from it. Degeneracy can only be seen in meta share %. It never shows in win percentages.
So if win percentage doesn't show which deck is the best, what does it show?
High average win percentage of certain decks means meta didn't adapt to these decks yet. Flat win percentages of top decks near 50% mean meta is stable, not that it's balanced.
That's right - statistics show that current Standard meta is both degenerate (Delver's very high % of the field), and stale (top decks very close to 50% win rate) without much chance of evolving. I thought this should be obvious to anyone with a clue about statistics and game theory (to learn start here) - it's basic result from first chapter of any game theory textbook that results of all strategies will converge to the same average. But apparently from both DCI announcement and ensuing discussion it seems that very few people understand this and the awful argument gets repeated over and over again.

Now this post is concerned only with statistics. Maybe M13 will fix it. Maybe someone will come up with brilliant anti-Delver deck out of nowhere. Maybe people enjoy playing Delver mirrors so much they'll keep coming to tournaments regardless of how many Delver decks are played. It's all possible, and I don't really have any evidence for that. But arguments from win percentages are wrong, and mathematics is very clear about that. It's too late to fix it, but let's hope the next time DCI faces similarly degenerate meta they'll look at numbers that matter (meta share of top deck) not numbers that show something completely different (win rates of top deck).

If you want the simulation script, email me (it's fairly straightforward Ruby code).

Tuesday, June 05, 2012

Skyrim review

I finished playing Skyrim just a couple of days ago, and it deserves a proper review, not just a quickie of the type I usually write on my Google+. By the way, if you use Google+, feel free to follow me there to get all my brilliant ideas which were too long to fit 140 characters. Or on any other non-Facebook social network you can find me.

Anyway, Skyrim. I played Oblivion a few years back, and for all its flaws I really loved it. At least up to the point where I made myself 100% chameleon gear. Then the game got a bit boring, but I was 90% done anyway by then so it's not a big deal.

And I loved Skyrim even more than Oblivion, but before we get too enthusiastic about it...

Dragons

The main theme of Skyrim is dragon stuff, and it's one massive spectacular miss.

Dragons are spectacularly weak if you have any kind of distance weapon - either a bow or a lightning bolt. They just fly around pointlessly, taking damage, and every time they actually hurt you they'll fly away to let your health regenerate - even without bothering with taking cover or using health potions.

By the end of the game I was able to kill weaker dragons with a single sneak shot from my Daedric Bow, and the tougher dragons just needed a few lighting bolts on top of that to convince them to die and let me eat their souls.

Even the final boss - who's some sort of a god and used to rule the entire world some time ago - is less threatening than an average bear. Stephen Colbert was right.

Now not only dragons are awfully weak - dragon shouts - your special spell-like ability which supposedly separates you from the common masses - is even weaker. Even highest level shouts are worthless compared with low level weapons or spells, and there's no way to upgrade them - the best you can do is somewhat lower cooldown period between shouts, but even with Amulet of Talos and Blessing of Talos that's still way too slow. Meanwhile 1-shot sneak-kill-nearly-anything bows and 0-mana top level fireballs are all within your reach on mid to higher levels.

Maybe some mods fix it. But I doubt it - dragon shouts look entirely unfixable because every player character has full access to them for quest reasons - so if they were made very strong you wouldn't have archers, and warriors, and mages, and thieves, and everything else you could be - you'd have just one dragon shouter character class instead. But they could be made at least somewhat less useless.

The entire dragon-related main quest is pretty mediocre compared with many far more awesome side quests. I think I cared far more about the Civil War, and just about any guild quests than about the dragon stuff.

Character Customization

This is modern equivalent of grown adults playing with dolls. You can even choose makeup for your character! Oh sorry, it's called "war paint", since we're playing a serious game, not a Japanese RPG.

So I just have two questions:

  • Why cannot I choose hair in blue or pink or another cute color
  • Why even bother if pretty much just about every single armor covers your character completely and you'll only see eyes, or not even that. I even did some questing without any helmets so I can see my character, but then since my helmet and cowl both had archery bonuses, it was prudent to put it back on once fighting started.


Both issues sound like something mods should be able to fix with ease.


Game Balance

Game balance in Elder Scrolls? Of course there is none. You can make totally broken character with infinity+1 swords etc. in many different ways. That's part of the charm of the series I suppose. If you want more balanced game look for mods.

The best build seems to be to max out enchanting, smithing, and some alchemy, since that's how you'll make infinity+1 gear for everything, but it's sort of balanced out by this kind of play being boring as hell.

Other than for the first 10 or so levels of game, there's never any reason to care about money, which is great, since looting and trading systems are just awful.

Bows are brutally murderous. You can sneak into a room and 1-shot sneak-murder 2-3 people before anybody even realized that you're there and you lose your 3x sneak bonus. Since 2-3 people is how many opponents a typical room has at most, it means with a bit of caution you can clear out entire dungeons without anybody getting into your melee range. Not that getting into melee range would hurt you - you can literally slow down time with your bow, outrun everyone even in your heaviest armor (for some reason everyone else is really slow, even without any perks etc. Skyrim has no Athleticism skill so it's puzzling), and only huge mobs of high level monsters can seriously hurt you.

Fighting magic is fairly weak. Fire magic is fairly decent, but even if you get casting cost down to 0 mana with some gear and get all the perks and Destruction up to 100, it's hard to match damage per second your bow does. Lightning magic is OK against dragons, but dragons are so awfully weak it doesn't really matter. Frost is just worthless since 2/3 of all enemies (including all Nords and all undead) are 50% or more frost resistant.

Melee builds are OK, sadly even the best armor can only reduce damage you take by 80%, so that's one thing which cannot be broken even by infinite+1 smithing and enchanting.

Sneaking and backstabbing (as opposed to sneaking and bow kills) is not a viable combat strategy, but it's fun as hell for assassinations.

There are also other unbalanced areas - lockpicking which happens with a minigame is super-simple from level one, but pickpocketing which happens by chance is extremely difficult until very late.

Anyway, the game is not particularly difficult so don't bother yourself with optimizing your build on default difficulty level.
source



Leveling

Probably the worst aspect of Oblivion was its leveling system - there was a very complicated system for determining your level, so you were better off consulting Internet guides before even creating your characters to make sure the game won't be too unfair - and then all enemies automatically matched your level, making any kind of progress pointless, and progress in noncombat skills made the game literally more difficult. Oh and if your character had high level, all quest items (level-independent) were total crap compared with what you could find on just about any random bandit. Oblivion was pretty much unplayable without a mod to fix leveling system.

Skyrim largely fixes that, but not completely. You level in easy to understand way based on your skill progression. Enemies become somewhat better as you level, but not as ridiculously as in Oblivion, and their gear in particular doesn't improve that quickly.

With just a few exceptions (Ancient Shrouded Armor, Oghma Infinium, either version of Azura's Star), unique quest items are still worthless junk. A mod that would simply make them x2 better or so would improve the game greatly, without actually affecting balance all that much (yes, they're so bad).


Quests and Followers



Many of the questlines are totally awesome, and radiant quest system ensures you can fill the game with as much or as little random dungeon exploration and bandit killing as you want.

The main quest is relatively weak, but I'm sure if a mod could fix power level of dragons and dragon shouts, it would improve greatly.

One thing I particularly loved about Skyrim is the moral choice system - namely that you have a ton of moral choice but without anybody keeping any artificial score:


  • I started as a proper adventurer, who wouldn't even steal anything
  • Then I joined Thieves Guild, and my respect for other people's property waned somewhat
  • Then I joined Dark Brotherhood - and unlike in Oblivion you cannot do in by accident, it's a very much conscious choice to murder an at least more or less innocent person in cold blood. Then you get more murder contracts.
  • I thought that was about as low as I could get, then after some events in Markarth (I'll spare you the spoiler) I moved to freelance mass assassination sprees, mostly of town guards and Thalmor agents.
  • There was also a fun ending of Dark Brotherhood questline, which involved more and more morally dubious murders.
  • And then I got invited to join a cannibalistic ritual sacrifice to Daedric Prince Namira. How did I even get here?
  • In the end I sold my soul to just about every single Daedric Prince. I'm sure they'll figure some way to divide it once I die. (by the way hero of Oblivion became a Daedric Prince at the end of the expansion pack)
  • The only thing you cannot do is kill children, but there's a mod for that.


All of this is purely optional. You can play a morally upright character, defender of all that is holy, destroyer of Dark Brotherhood, and all Daedra worshipers etc. It's just much more fun to be bad.

The second most important questline after the main quest is the Civil War, where you can join the Empire, the Rebellion (there's also a second minor rebellion, with arguments shockingly similar to Ulfric's rebellion), or even manage to get them to agree to a truce. Of course the Rebels are a bunch of racist morons, just about every single one of them, and unless you're roleplaying a Nord fanatic I cannot think why anybody would not want to crush them for greater glory of the Empire. Ulfric is also obviously a Thalmor agent paid to destroy the Empire from within, and don't let lack of clear evidence in-game convince you otherwise.


Followers

In Oblivion you could have followers in some quests - they were mostly pain in the ass since they had constant level, but enemies leveled with you, and your followers could die very easily.

In Skyrim you have some of them too - but after you finish some quests you can ask an NPC to join you in your questing. They are all either unkillable (the quest ones) or harder to kill (your regular non-quest followers) - when their health drops below some level all enemies leave them to regenerate their health and go after you instead. They can still die especially if you throw fireballs all over the place.

As far as I can tell followers have whichever level they had when you first met them, so at first they're pretty decent, but as you level up (and the enemies with you) they get progressively worse. Their gear is pretty consistently awful though. Another thing for modders to fix.

You can also buy a horse, but between fast travel system, no ability to fight from the horse, and the fact your horse is not any faster than you are on foot they're pretty useless. The only horse worth getting is one you get in Dark Brotherhood questline - that's one murderous beast, it even killed a somewhat wounded dragon once.


Bugs

You might be a bit curious why I'm reviewing Skyrim now since it was released so long ago, but I follow consistent rule of not playing new games ever.

A lot of games - including entire Elder Scroll series, Total War series, Witcher series etc. - consistently have gameplay-killing bugs in their first releases, and only a few months later these were patched to the point where you could comfortably play without thinking too much about the bugs.

Unfortunately even so long after the release, Skyrim is about as buggy as Oblivion - and I really should have installed some kind of unofficial patch mod. Many of the bugs are easily fixable with console and quick Internet search, but a few minor issues weren't, or at least I couldn't figure out how. Quick-save often, since crashes will happen.

Not technically bugs but everything related to looting, trading, encumbrance, and managing equipment is one huge pile of fail. It's a case of them trying to use interface meant for console controllers (where it simply has to suck by basic laws of physics) on PC which has keyboard and mouses, and could easily have an interface which doesn't suck. Once again, console are the cancer killing gaming.

Do yourself a favour, start console (~), then type player.modav CarryWeight 9000, so at least you won't have to deal with this mess all the time during dungeon exploring, only once in a while when you're trying to sell the stuff you looted.


Skyrim vs Oblivion

Other that things I mentioned, how does it compare with Oblivion?

There are still fewer mods - and these games really need to be played highly modded - but zero-mod Skyrim is much better than zero-mod Oblivion (which was pretty much unbearable due to leveling system).

Since I played Oblivion wikis got really awesome. These days every time you have a problem, or the game has bugs it's just a moment to alt-tab to a browser and find a solution.

They finally hired enough voice actors to make it not feel totally ridiculous. Dialogs make somewhat more sense, usually. Of course you get zero respect from guards and other NPCs even if you're hero of the Civil War, slayer of countless dragons, Archmage, Thane of all cities, wearing full Daedric Armor, and running the entire Skyrim from the shadows. I shouldn't complain too much because it just reminds me how awful it was in Oblivion at times.

One thing which got really worse is that other than a few special locations which look really lovely, Skyrim is all bleak, and gray/white, and snowy. It's worse than even modern shooters and their gray and brown color palettes. IIRC Oblivion had much more graphically diverse locations. Yes, special locations in Skyrim look different, but all the snow gets really tedious after a while.

Another thing which got a bit worse is moving around the map. There are far too many non-passable mountains in many places, the map doesn't indicate them in any way, and Clairvoyance spell broke in the middle of the game (damn bugs...) so it was extremely frustrating to get to some places the first time even when you had them on your map. The second time you'll be fast traveling of course.

I cannot compare it with Morrowind, since I still haven't figured out which mods I need to install for it, and every website claims something different.

Anyway, even with all its problems it's an easy 10/10, and I'm very rarely so enthusiastic about game, or anything else for that matter.

Ask ahead if you have any questions.

Sunday, May 13, 2012

New jrpg packages available

I am sleepy... by black_eyes from flickr (CC-NC-ND)
jrpg is an awesome game, but it suffered from a bit of software rot - I didn't update it for years and libraries used by it worked less and less well with new graphics drivers etc.

I did some minor updates and repackaged Windows version for Python 2.7.3 and Pygame 1.9.1. You can now download fresh packages from jrpg's website.

Please test it and if you have any problems please report them.

py2exe replaced by pyInstaller

Unfortunately since the time I last updated jrpg, py2exe got pretty much abandoned - they still don't have Python 2.7 packages.

I searched for replacements, and the one that seemed most promising was pyInstaller - it even had an added bonus of working under both Windows and OSX (and even Linux, not that Linux users actually need that, or I'm going to bother packaging 20 different versions of jrpg for each distribution).

It just suffered from two problems:
  • It crashed on OSX
  • It crashed on Windows
Which made it sort of not as useful as it might otherwise be.

I finally managed to fix source of the Windows crash, so there are now new packages for you, but still no OSX version.

It was a fairly classic case of "Python people don't write unit tests", since any kind of unit testing, even "run program with no arguments, see that it doesn't crash" kind would find this bug. The biggest difference between Ruby and Python is not technology, it's Python's pathological culture of One True Way To Do Things Even When The One Way Is Fucking Wrong.

So happy about fixing the bug, I tried to submit the patch, and then:
  • pyInstaller's bug tracking server crashed on me (and I tried a few times)
  • pyInstaller's mailing list bounced emails saying it doesn't exist
The fuck is wrong with this program? It just doesn't want to be fixed. Hopefully email I sent to one of maintainers directly worked better.

OSX support

Since OSX doesn't have real packaging system, people have to use crap like FailPorts, and of course jrpg does not work with Python and PyGame installed with FailPorts. At least not for me. With FailPorts you never know, you might be more lucky.

If you want to use jrpg on OSX please download Python and PyGame packages from their respective websites, install them, extract jrpg's source package and run that (jrpg.py that is).

I'll give making one click OSX package another try sometime later, but with track record of Python packaging programs so far, I wouldn't be holding my breath.

Friday, May 11, 2012

Polish Dvorak keyboard layout for OSX

ctrl++elfie by djenvert from flickr (CC-NC-ND)
This is something I should have done like three years ago, but better late than never.

I created Polish Dvorak keyboard layout for OSX and I put it on github repository with installation instructions.

Unlike with Linux Polish Dvorak layout, where altgr-bindings exist only for Polish characters, in this layout pretty much all keys have altgr-bindings. They are mostly mathematical symbols I copied over from standard OSX Dvorak layout. I have no idea if they are actually useful, so if you have a good reason why they should be something else go ahead and message me.

There could also be bugs, so please report them. And since I have a nice repository going, feel free to send me any other custom keyboard layouts you've made.

The process wasn't that bad - it's XML file and there's even an usable third party editor application for them - Ukelele. I remember back when I used Windows and such things required hexediting binaries. These were the days...

Tuesday, May 08, 2012

How to setup Google Chrome

Just like operating systems, web browsers are close to useless out of the box. In fact web browsers are even worse since web comes with adware all over the place, and you need to take active steps to remove it, while operating systems only get adware if you accidentally forget to deselect some checkboxes while installing software.

By the way Steve Jobs wanted to change it - and have ads displayed by the operating system when computer starts - fortunately he got cancer and died before he could follow it through. There's justice in the world sometimes.

Get rid of ads

This step is more difficult in Chrome than in Firefox. First you need to go to Chrome settings: chrome://flags, select enable "Experimental Extensions APIs" and restart Chrome. That's the only restart you'll ever need - unlike with Firefox you won't be restarting after every single extension is added or removed. (oh by the way, Chrome doesn't like you clicking on chrome:// links from "untrusted" websites, so copy and paste them or something)

Now go get development build of Adblock Plus, click confirm a few times. You're still not done yet.

Now go to Extensions page (chrome://extensions), select options for Adblock Plus, and make sure "Disable inline text ads" is enabled as well.

And hurray, Chrome is finally usable!

Making websites less awful

Even without ads, many websites are ugly as hell, or awfully designed, or both (like Google everything after Google+ forced redesign). It's a good idea to go to what Chrome calls "chrome web store" and check if there are any extensions for websites you're frequently using.

Usually there will be more than one, but here's good news - you don't need to restart Chrome to test them, just install them all, open Extensions settings in a new tab, and selectively enable/disable them and try their options. Once you're happy with your choices, uninstall all you don't like completely. Oh, and as a service to others please review extensions you're using as well.

Here are a few recommendations:
  • Reddit Enhancement Suite. It's not on web store for some reason, and requires a bit of customization, but it's such a huge improvement over default reddit you'll never go back (unless you're quitting reddit to have time for everything else in life that is, yeah that's a good idea as well).
  • soup.io bookmarklet - pretty much a must-have if you want to post things on soup, nobody does it via website.
  • 4chan Plus - a lot of nice minor fixes.
  • Google Reader - old Google Reader was just fine, but they had to break it. This extension sets up neat minimalist design where you can focus on reading stuff, not on Bullshit+. (by the way once you install it right click on "gr" button in toolbar and select "Hide button" since it serves no useful function)
Now a very interesting extension is Stylebot. It lets you easily and conveniently do website-specific CSS fixes.

Now conspicuously missing from this list are other Google services. For Gmail there aren't any good extensions, but here's a guide how to make it a bit less awful from Gmail settings (works in any browser). For Google+ there is no hope. Some extensions tried to make it slightly less awful, but since Google CSS and HTML is auto-generated from some Java bullshit and not human or machine readable, it's really hard to write anything that makes it anything but atrocious. At least it's not Facebook.
SDC19275 by Mr Thinktank from flickr (CC-BY)

Everything else

One feature nobody knows they need but to which you'll get used really quickly is endless scrolling (like on soup) on every single website. (well, >95% of them) To get it install FastestChrome extension, then go to its options and disable everything except "Enable Endless Pages" (and perhaps "Linkify text urls" and "Add related articles to Wikipedia" if you wish).

If you do any kind of web development, you'll want Firebug Lite. It's nowhere near as good as one for Firefox, so even if you do most of your browsing in Chrome you'll probably keep using Firefox as your main development platform, but you'll have Chrome-specific issues to fix, and it's pretty much necessary for it.

If you use Gmail you'll probably want Gmail notifier - there's ton of them with extra features (and not one which handles Important email differently from other email without entirely ignoring non-Important email altogether, for fuck's sake, that's like the best feature of Gmail...).

This one seems to be pretty decent. But you need to go to options, Notifications panel, select "Disable notification sound" and deselect "Show desktop notifications". Number of unread emails is notification enough and you can click on the icon for email snippets. And while you're at it pick some better looking icons.

There's an interesting extension StayFocusd if you have trouble focusing because you spend way too much time on certain websites. It works until you figure out it takes 5 seconds to open extensions tab and disable it. At least that's one thing where Firefox is better - in Firefox you'd need to restart your browser.

The final thing you may want to try is Ghostery - it removes various tracking cookies to give you better (illusion of) privacy. I'm pretty sure Chinese Military Intelligence had my computer bugged so I don't really care all that much anymore, but you may feel different, and it's pretty easy.

Oh, and I'd almost forget. Go to DuckDuckGo so Chrome reads its search information, then go to Settings for Search Engines and give it a try as your default search engine. I'll write a post later explaining why it's a good idea. And if you don't like it, you can always switch back to Ask Jeeves or whatever you've been using before.

Coming soon

My guide to setting up Firefox stopped just before they switch to dick size version numbering. An updated guide to Firefox BiggerNumberThanOtherBrowsers.0 is coming soon.

Friday, April 27, 2012

How to install Windows 7

SPEAKER OF THE HOUSE by aJ GAZMEN ツ GucciBeaR from flickr (CC-NC-ND)

Every couple of years I have to go through the painful process of installing whichever version of Windows is the most sensible. Currently that would be Windows 7 (don't touch Vista or Windows 8 unless you have to). Even if you got a computer with operating system preinstalled, nobody sells computers with operating systems preinstalled well, so that's something one has to do.

Getting started

  • First, get some Windows 7 DVD. The version you most likely want is 64-bit Ultimate edition, but if you have something else it's most likely not a big deal.
  • Gather all driver DVDs that were included with your computer. It's much easier than searching for driver online.
  • Since you will be doing dual boot, partition your disks sensibly. DO NOT CREATE SWAP PARTITION FOR LINUX !!! I'll elaborate in another post, let me just say that swap partitions - and swap in general - are an awful idea for every single kind of system these days - servers, desktops, laptops, phones - all of them work infinitely better without swap. We don't live in 1980s any more.
  • If you have a small SSD plus a second bigger disk like my machine, you'll need to consider this at a few points along the installation.
  • Now install Windows 7.
  • Get all driver dvds and install them one by one (usually in order - motherboard, gpu, the rest). Try to avoid installing any toolbars, antivirus software trials, and other bundled crap. It might be a good idea to download the most up to date drivers, especially for GPU.
  • And we're done. Nothing like a quick post. Oh wait, we're not? It turns out installing operating system is only step 1 of installing an operating system.

Installing software with Ninite

Funny thing, Windows comes without almost any software - and every time Microsoft tries to include anything like a video player or a web browser they have to fight antitrust trials, so no wonder they'd give up eventually. Meanwhile OSX and Linux typically come with huge amount of software for various tasks (and of various quality) included.

Now here's the trick. Do not download these programs individually. Double click Internet Explorer icon (you know you cannot go wrong with a sentence which starts like this), and go to  http://ninite.com/ website. There select all software you want to install, download a single installer, and run it. It will fetch and install everything you selected.

A few hints:
  • Skip everything by Adobe, use any other PDF reader.
  • Do not use winzip. Use 7zip.
  • No point installing trial versions of anything like Microsoft Office.
  • You don't need Silverlight, Air, QuickTime, iTunes and such crap. Trust me on that.
  • Between Pidgin and Skype all your IM needs will be covered, no need to install 10 different programs.
  • If you have multiple partitions, do not install Steam and similar program which are likely to take gigabytes of space via Ninite - it will install them on your root (I mean C:) partition without asking any questions, and you probably don't want that.
  • If you have any other special needs, you'll also need to install software manually.
Now a few things are not available from ninite. The most obvious one is probably virtual DVD drive software for running backups - something every other operating system has builtin.

snow day! by Cory Schmitz from flickr (CC-BY)

Optional SSD step

If you use multiple partitions (usually because of SSD) make sure you configure all programs likely to use too much diskspace to use your secondary disk.

That includes most obviously Steam (and similar software like Origin) - which you need to install to your secondary disk, and download managers like uTorrent (where you only need to change download folder in preferences). If you're planning to do big downloads with your browser, consider changing its default download location as well - for small short-lived things like PDFs and such it doesn't really make much difference.

Then turn off swap and other things that use ton of your diskspace for no good reason, or to slow your computer down. This is especially necessary if you use SSDs, but it's a good idea on just about any machine.
  • Right click on Computer > Properties > System Protection > Delete all restore points, then Turn off system protection and OK.
  • Computer > Properties > Advanced System Settings > Advanced > Performance > Advanced > Virtual Memory > No paging file
  • Start menu > type "cmd" > Right click "cmd" > Run as administrator > Type "powercfg -h off"
This will save you a ton of diskspace - usually somewhat more than your RAM - and in all likelihood make your computer a lot faster.

Settings

I've never seen any operating system with defaults which weren't totally insane, and Windows 7 is no exception. Here are just a few things I had to change before it reached more or less usable state.
  • Change keyboard setting to something sane in case your defaults (like in UK) are retarded.
  • Start menu > type "Folder options" > unselect "Hide extensions for known file types", "Hide protected operating system files"
  • Power Options > Put computer to sleep > Never
  • Start menu > type "Keyboard" > Repeat delay - "short"
  • Configure either Firefox or Chrome with all the relevant plugins and extensions. (I'll hopefully post about this soon)
  • Disable Windows security nonsense. If you have any clue what you're doing, it's just annoyance not protection. Start Menu > type "uac" > select "Never"
  • Right click on Taskbar: Taskbar buttons "Combine when taskbar is full"
  • Start menu > type "change system sounds" > No Sounds
I could probably go on, but that should deal with the most common issues.

At this point if you have Steam, and it's configured to use the right drive, feel free to start download of all the games you'll want to play. It will take some time.

Cleaning up

Once we're done it's time to clean up.

Now Ninite automatically refuses all toolbars, adware and related crap, and you're probably clueful enough to do the same, but something might have gotten through. Go to "Add or remove programs", and check that everything installed is something you wanted to install, not any bundled crap.

Then the last issue is every single program which starts automatically - in virtually every single case this is not what we want. Now you could try to do this manually in each program's configuration but it's much simpler and more reliable to run msconfig (Start menu > type "msconfig").

In msconfig turn off everything in "Startup" and everything in "Services" that's not by either Microsoft or driver manufacturers (and some of the stuff by driver manufacturers deserves to be turned off as well). This will cover about 95% of annoying autostarting programs and I've never had any problems with this.

Have fun with your Windows 7. In upcoming posts I'll coves Chrome, Firefox, and Kubuntu 12.04.

Avacyn Restored Sealed Simulator

wizard_hat_outtake_ by CapesTreasures.com from flickr (CC-NC-ND)

All the usual websites will get that functionality eventually, but I got a little impatient and decided to write a little Sealed Simulator for Avacyn Restored before the prerelease.

The programming is pretty straightforward - it's a bit of jQuery plus a ton of code which every single language other than Javascript has in its Standard library already. If you want to see what some quick and dirty code I write looks like, help yourself.

Writing this simulator made me realize how little we know about what actually gets into boosters. We know there will be:
  • 1 card from rare sheet (7/8 rare, 1/8 mythic)
  • 3 uncommons
  • either 10 commons, or 9 commons and 1 foil
  • 1 basic land
Do we know what percentage of time there's a foil card in the booster? And what are rarity ratios of foil cards? That's what I've been told - I have no way to verify it, but it sounds plausible enough. And that's about it.

Things we don't know about boosters

One much more important thing is which commons and uncommons we're going to get.
If cards were chosen independently random, 55% of boosters in small set and 37% of boosters in large sets would contain duplicate common cards by birthday paradox. This happens almost 0% of the time.

Software simulators always use explicit deduplication to deal with this particular issue, and that's where they all stop (as far as I know, my simulator definitely does), but that's not how actual paper cards are printed.

Real world cards are printed into sheets in some specified order (the same card can appear on the sheet more than once, in different context, so it's not that regular - for example on the rare sheet each rare occurs twice and each mythic occurs once), cut into individual cards, and then mixed into boosters by some predefined method.

People attempt to figure out these "print runs" mostly so they can figure out how rares are printed - then they can buy a few boxes, open a few boosters which will have money rares and mythics in them (plus a few more boosters needed to figure that out) - and then sell the rest on ebay to unsuspecting players who will than receive various junk rares.

For Limited simulators rares don't matter all that much. Actually it does in that Limited played by taking completely random boosters, and Limited played by taking consecutive boosters from a box will have different statistics - but simulators can faithfully have the same distribution of rares as you'd get in Limited if you used truly random boosters, so it's close enough.

What matters the most for Limited is print runs of commons and uncommons. By taking commons entirely at random, the way all simulators do (except for deduplicating step) you get highly non-uniform distribution of colors - you'll very likely get ton of commons in some colors and very few in some other colors. This means that in simulated Sealed pools it's usually really easy to make very high quality deck with two colors which just happen to be most numerous, and some other colors are pretty much impossible to include other than as splash for a bomb.

Real paper Sealed tends to have more equal rates, so you're not so railroaded into colors. Maybe you can make about equally good RG werewolves and UW fliers deck from the same pool? This ambiguity is pretty common in paper and much less common on simulators.

How important it is? Honestly, I have no idea. I'd love to be able to do some math, and it's possible to model the method used by the simulators (we have the source code), but I don't have enough information to model paper boosters. I find it strange that WotC never wrote any articles about it (I duckduckwent them - there were really none), except mentioning a few major related screw ups they've done in remote past. Have they been secretive, or is there just not enough interest?

Another interesting question - and one which should be much easier to answer - does MTGO use print runs? We have tons of MTGO drafts recorded, if someone could simply get them together, and run simple statistics like % of commons by color in each booster we should be able to at least determine if they select them by uniform random methods or some other way, even if we don't know the particulars of that other way.

EDIT: I thought this only matters for Sealed not Draft (since you're getting 1-2 card from 8 different boosters anyway in each round, not 14 cards from 1 booster, so it should even out), but I've been told by people who draft Cube (which generally doesn't use print runs) that uniform randomness makes any kind of color signaling pretty much impossible. So it matters a hue deal, just for a different reason.

Thursday, March 29, 2012

ESF - Empire Total War Object Serialization Format

Princess Sophia (R.I.P. babygirl!) by Shandi-lee from flickr (CC-NC-ND)
ESF is the primary data format used by Total War series games starting from Empire, and then Napoleon, Shogun 2, and whatever comes next.

It was reverse engineered from partial documentation by various people including your truly, but so far there's no complete documentation available anywhere. This post is meant to be such documentation.

Obvious data types


Most of data types used in ESFs are straightforward - almost everything is little endian unless noted otherwise, data sizes are standard powers of two, negative numbers are two's-complement, character set is Unicode, floating point numbers are IEEE 754 etc.

  • int8, int16, int32, int64 - little-endian signed integers
  • uint8, uint16, uint32, uint64 - little endian unsigned integers
  • float32, float64 - single and double precission IEEE 754 floating point numbers
  • char8 - ASCII character
  • char16 - little-endian UTF-18 codepoint
  • bool8 - boolean (00 false, 01 true, other values never observed)

Strings


There are two kinds of strings used in ESF files - ASCII strings (used mostly for internal identifiers), and Unicode strings (used mostly for displayable text).

Both are prefixed by character count as uint16, for ASCII strings (ca_ascii):

  • uint16 count, char8[count] characters

For Unicode strings (ca_unicode):

  • uint16 count, char16[count] codepoints

There are no observed instances of ASCII strings having high bit set - so it's not possible to tell if that's meant as ISO-Latin-1, UTF-8, an error, or something else.

There are no observed instances of Unicode planes other than Basic Multilingual Plane being used.

There are no observed instances of 0 character/codepoint being present in either of them.

Neither string format is ever zero-terminated.

Exotic encodings for numbers


Before I get to the format itself, there are a few exotic encodings used in ESFs.

int24be and uint24be are big-endian (that is reversed) 24 bit (3 byte) signed and unsigned integer. So sequence of bytes 01 00 00 means 65536.

uintvar is a variable length encoding for unsigned integers, with following rules:

result = 0;
  while(data[i] & 0x80) {
    result = (result << 7) | (data[i] & 0x7f);
    i += 1;
  }
Or in diagrams:
  • 0XXXXXXX → 0bXXXXXXX
  • 1YYYYYYY 0XXXXXXX → 0bYYYYYYYXXXXXXX
  • 1ZZZZZZZ 1YYYYYYY 0XXXXXXX → 0bZZZZZZZYYYYYYYXXXXXXX
  • 1WWWWWWW 1ZZZZZZZ 1YYYYYYY 0XXXXXXX → 0bWWWWWWWZZZZZZZYYYYYYYXXXXXXX
  • 1VVVVVVV 1WWWWWWW 1ZZZZZZZ 1YYYYYYY 0XXXXXXX → 0bVVVVVVVWWWWWWWZZZZZZZYYYYYYYXXXXXXX
Or in examples:
  • 0 is encoded as 00
  • 1 is encoded as 01
  • 127 is encoded as 7f
  • 128 is encoded as 81 00
  • 255 is encoded as 81 7f
This format is somewhat analogous to UTF-8. In theory you could encode arbitrarily long numbers this way, but it's never longer than 5 bytes. And for that matter encoded numbers are never longer than 32 bits (even though 5 bytes would fit 35 bits in this encoding). There are many observed cases where encoding different than the shortest possible encoding is used - as far as I know it's typically 5 bytes used when 4 would suffice, but I haven't investigated it any deeper than that. For example - 80 80 80 80 01, 80 80 80 01, 80 80 01, 80 01, and 01 are all valid encodings for number 1.

Format variants

There are 4 variants of ESF format, usually referred to by their magic number:
  • ABCD - used in Empire Total War and Napoleon Total War
  • ABCE - used in Empire Total War and Napoleon Total War
  • ABCF - used in Shogun 2 Total War
  • ABCA - used in Shogun 2 Total War

Header

ESF files start with the following header:
  • uint32 - magic number (0xABCD, 0xABCE, 0xABCF, 0xABCA)
  • uint32 - 4 bytes, always zeros - not present in ABCD format
  • uint32 - 4 bytes, look like Unix timestamp - not present in ABCD format
  • uint32 - offset where footer starts
Lack of these two fields in the header is the only difference between ABCD and ABCE formats. Following header is a single root node (usually with more nodes nested within). Following that is footer, and possibly zero padding.

Footer

ESF format consists of nodes similar to XML tags. The first thing in the footer is a lookup table for names of these tags:
  • uint16 number of tag types
  • ca_ascii name of tag 0
  • ca_ascii name of tag 1
  • ca_ascii name of tag 2
  • ...
For example tag table containing nodes "kittens" and "pandas" would be:
  • 02 00 - size of tag name table as uint16
  • 07 00 - size of string "kittens" as uint16
  • 6b 69 74 74 65 6e 73 - ASCII encoding of "kittens"
  • 06 00 - size of string "pandas" as uint16
  • 70 61 6e 64 61 73 - ASCII encoding of "pandas"
For formats ABCD and ABCE that's the entire footer. Formats ABCF and ABCA contain two more data structures - lookup tables for Unicode strings and ASCII strings. ABCD/ABCE formats kept all strings other than node names within main data. The main change in ABCF/ABCA formats was moving the strings to the footer, and only using indexes to footer tables in main data, resulting in much smaller files. Footer for ABCF/ABCA continues as:
  • uint32 size of Unicode string lookup table
  • ca_unicode string A
  • uint32 index of string A
  • ca_unicode string B
  • uint32 index of string B
  • ...
  • uint32 size of ASCII string lookup table
  • ca_ascii string A
  • uint32 index of string A
  • ca_ascii string B
  • uint32 index of string B
  • ...
The main difference between tag name lookup table and these tables is that tag name lookup table simply used positions on the list as indexes, and these tables use explicit indexes (it's like Array vs Hash). There have been no observed cases of multiple entries having the same ID, or any other such irregularities. Following footer in some ABCA format files there are some 00 bytes. These as far as I know do nothing at all and are ignored.

Data nodes - numbers

Presenting His Royal Highness King Milo the First! by Malingering from flickr (CC-NC-ND)
Between header and footer there are data nodes - or to be more precise exactly one data node, which may contain nested nodes - very much like XML has one root element. Node type can be determined by its first byte. Numbers nodes have very simple correspondence between encoding and encoded data:
  • 01 bool8 - boolean
  • 02 int8 - int8 (never observed in practice)
  • 03 int16 - int16
  • 04 int32 - int32
  • 05 int64 - int64 (rarely observed in practice)
  • 06 uint8 - uint8
  • 07 uint16 - uint16
  • 08 uint32 - uint32
  • 09 uint64 - uint64 (rarely observed in practice)
  • 0a float32 - float32
  • 0b float64 - float64 (never observed in practice)
A few further node types are only a bit more complicated:
  • 0c float32 float32 - XY coordinates
  • 0d float32 float32 float32 - XYZ coordinates
  • 10 uint16 - angle from 0 to almost-360 degrees
Choice of numerical node types is not data dependent - if certain object has uint32 with value 1, it will always be encoded as 08 01 00 00 00 in ABCD/ABCE/ABCF formats. Most numerical data in ESF files is uint32, int32, and float32 - so there's plenty of zeroes there. As an optimization ABCA format introduced further node types not present in ABCD/ABCE/ABCF formats:
  • 12 - boolean true
  • 13 - boolean false
  • 14 - uint32 zero
  • 15 - uint32 one
  • 16 uint8 - uint32
  • 17 uint16 - uint32
  • 18 uint24be - uint32
  • 19 - int32 zero
  • 1a int8 - int32
  • 1b int16 - int32
  • 1c int24be - int32
  • 1d - float32 zero
So uint32 node with value 5 might be< encoded as 08 05 00 00 00, 16 05, 17 05 00, or 18 00 00 05. As far as I can tell the most compact possible representation is always used (16 05 in this case), but I haven't strictly verified that.

String nodes

In formats ABCD/ABCE string nodes are encoded as follows:
  • 0e ca_unicode - unicode string node
  • 0f ca_ascii - ASCII string node
In formats ABCF/ABCA instead of string they only contain an index to appropriate lookup table in the footer
  • 0e uint32 - unicode string node
  • 0f uint32 - ASCII string node

Array nodes

There are array nodes types corresponding to basic node types, their code is 40 + code of basic data type:
  • 41 boolean array
  • 42 int8 array
  • 43 int16 array
  • etc.
In ABCD/ABCE/ABCF formats arrays are encoded as:
  • uint8 node-type-code (40..5f)
  • uint32 offset of first byte after end of array (this is a weird way of encoding size)
  • element 0
  • element 1
  • ...
In ABCA format it's:
  • uint8 node-type-code (40..5f)
  • uintvar number of bytes in the array
  • element 0
  • element 1
  • ...
So for example if we have array of two uint32s - [100, 200] starting at offset 0x6000 in file, it will be encoded like this in ABCD/ABCE/ABCF:
  • [offset 0x6000] 48 - since 08 is node type code for uint32, 48 is node type code for array of uint32s
  • [offset 0x6001..0x6004] 0c 60 00 00 - offset of first byte after end of array
  • [offset 0x6005..0x6008] 64 00 00 00 - 100 encoded as uint32
  • [offset 0x6009..0x600b] c8 00 00 00 - 200 encoded as uint32
In ABCA format array encoding doesn't depend on offset, so it's:
  • 48 - code for array of uint32s
  • 08 - size of the array as uintvar
  • 64 00 00 00 - 100 encoded as uint32
  • c8 00 00 00 - 200 encoded as uint32
However the same way numbers in ABCA format can be encoded with shorter encodings if they fit, entire arrays can as well, if every one of their elements does:
  • 56 - since 16 is code of uint32-encoded-as-uint8
  • 02 - size of the array as uintvar
  • 64 - 100 encoded as uint8
  • c8 - 200 encoded as uint8
There's no way to mix encodings within the array. Array of [0, 1, 1000] would be encoded as:
  • 57 - since 17 is code of uint32-encoded-as-uint16
  • 06 - size of array as uintvar
  • 00 00 - 0 encoded as uint16
  • 01 00 - 1 encoded as uint16
  • e8 03 - 1000 encoded as uint16
Now since arrays encode their size as either byte count (ABCA) or file offset (ABCD/ABCE/ABCF) and not as number of elements, they never use 0-size encodings like 52, 53, 54, 55, 59, 5d. In ABCF/ABCA formats there are arrays of ASCII and Unicode strings, and they cause no complications since "string" there is just uint32 index to a separate lookup table. There are no such arrays in ABCD/ABCE formats, where strings are encoded directly in the data using variable number of bytes.

Record node

Prince Levi by geckoam from flickr (CC-NC-ND)
The most important node type in ESF is record type, vaguely corresponding to tags in XML, or non-basic object types in Java. The root of ESF files is always a record type, and since records can contain any number of nodes in them, they provide basic structure to ESF files. For ABCD/ABCE/ABCF format record nodes are encoded as follows:
  • uint8 80 - record node code
  • uint16 tag name - it's index to table of tags in the footer
  • uint8 version - version number - starts with 0, updated every time object format changes
  • uint32 offset of first byte after end of record
  • node 0
  • node 1
  • ...
In ABCA situation is much more complicated, since there are actually three formats of records. Root node - and root node only - is encoded as:
  • uint8 80
  • uint16 tag name
  • uint8 version
  • uintvar size of data within record in bytes
  • node 0
  • node 1
  • ...
Other nodes can either use traditional encoding, except with different node type code:
  • uint8 a0
  • uint16 tag name
  • uint8 version
  • uintvar size of data within record in bytes
  • node 0
  • node 1
  • ...
Or a new compact encoding. In compact encoding first two bytes are better considered as a bitfield:
  • 100vvvvt tttttttt - That's 4 bits for version number and 9 bits for node type.
  • uintvar size of data within record in bytes
  • node 0
  • node 1
  • ...
So node type byte can be anything between 80 and 9f.

Array of records node

The last type is arrays of records. All records in the array are the same type and version. For ABCD/ABCE/ABCF format it's encoded as follows:
  • uint8 81 - array of records node code
  • uint16 tag name - it's index to table of tags in the footer
  • uint8 version - version number
  • uint32 offset of first byte after end of array
  • uint32 number of elements
  • uint32 offset of first byte after end of record #0
  • contents of record 0
  • uint32 offset of first byte after end of record #1
  • contents of record 1
  • ...
ABCA format has two encodings. Traditional encoding:
  • uint8 e0 - array of records node code
  • uint16 tag name - it's index to table of tags in the footer
  • uint8 version - version number
  • uintvar size of array contents in bytes
  • uintvar number of elements
  • uintvar size of record 0 in bytes
  • contents of record 0
  • uintvar size of record 1 in bytes
  • contents of record 1
  • ...
And compact encoding very similar to one used for records:
  • 110vvvvt tttttttt - That's 4 bits for version number and 9 bits for node type.
  • uintvar size of array contents in bytes
  • uintvar number of elements
  • uintvar size of record 0 in bytes
  • contents of record 0
  • uintvar size of record 1 in bytes
  • contents of record 1
  • ...
So array node type is either c0..df for compact encoding, or e0 for traditional encoding.

Putting it all together

So to put it all together ESF files consist of:
  • uint32 - magic number (0xABCD, 0xABCE, 0xABCF, 0xABCA)
  • uint32 - 4 bytes, always zeros - not present in ABCD format
  • uint32 - 4 bytes, look like Unix timestamp - not present in ABCD format
  • uint32 - offset where footer starts
  • root node (and more nodes within it)
  • array table of tag name
  • hash table for Unicode string lookup
  • hash table for ASCII string lookup
  • optional and completely ignored zero padding
If you want to play with ESF files, the best way is to download esf-xml converter from etwng repository.

Monday, March 19, 2012

Software Triage

Muffin // Our new kitten by Merlijn Hoek from flickr (CC-NC-ND)

Hi!

For variety of complicated personal reasons I haven't been updating my blog in ages.

If you want to follow me, I've been a lot more active on Twitter and Google+. And on soup, but that's very different kind of activity. If social networking nonsense ever stabilizes, we might end up in a flow where things start as a single sentence on something Twitter-like, then some of them get elaborated into a couple of paragraphs on something Google+-like, and eventually a few become full blog posts on something - uhm - blog-like. And the stupid masses are kept away from it all on something Facebook-like, and recruiters keep spamming people on something LinkedIn-like etc.

Anyway, I'm sort of back, I hopefully your deliveries of kittens and technology will resume on a more frequent basis.

Since my software (at least the kind I published) has seen very little activity, I want to start with triage of everything I published as Open Source (and still remember), and quick decisions what I'm planning to do about it all. And by the way I'll probably be switching from OSX to Ubuntu seriously this time, which is also somewhat relevant to these decisions.

The Morgue

First, some truly ancient software I mention mostly to make sure I don't miss anything important.

I have 4 projects on sourceforge. Three of them - FreeTable,
Gtk+/CLI IDP Interface, and
Joystick Mouse Emulation (funny story that, I fried mouse port on my computer and had to do this as a hack, then it turned out it got some legitimate users) are like 12 years old, back from good old days when people still believed in Linux on desktop. They're of course dead, have been dead for ages, and won't see any development ever. I vaguely recall that FreeTable actually got some uses, and people even packaged it for a few distros, and if they did so, good for them!

My fourth sourceforge project is MediaWiki, which is doing perfectly well without me. texvc was one of the big features that let Wikipedia become what it is, but it's pretty much done and doesn't need any extra work.

Another project which is pretty much dead is iPod-last.fm bridge, which died together with my iPod. Sansa Clip is an MP3 player superior is every possible way, except it doesn't keep logs of what you've played, but then I can live without last.fm knowing everything about me (especially since its recommendation-based radio is a pile of fail anyway). I don't play to get any new iPods, so it's unlikely it will get resurrected ever. Feel free to take over the project if you need it.

Art Projects

I apparently published quite a few programs which are entirely useless for anything other than providing 15 minutes of amusement tops. They won't see any more development not because they're "dead" - they're just "complete". Death of the Author and such pomo stuff (a small fraction of pomo stuff is actually not total bullshit, and that's one of these rare things).

Amethyst - Ruby syntax for Perl - was full of win, but it doesn't need or want any more work on it. Successor to Perl 5 arrived some time ago and it's called Ruby.

My attempts at building a CPU out of TTLs are also unlikely to be resurrected. I sort of vaguely plan to go back to hardware hacking some day, but if it happens, it will more likely be Arduino or something else higher level, not TTLs. Raspberry Pi looks interesting as well, other than the horrible name.

Does anybody use these things?

Back when I was on Wikipedia I wrote tawbot, which was a small program for doing various admin tasks on Wikipedia. It used to have quite a few users, but I haven't heard from them ever since. Is it still in use? I don't think so, and since I'm not really editing Wikipedia past fixing typos and dead links and such trivial things, there's probably no reason to unabandon it. If I'm wrong, definitely tell me.

XSS Shield for Rails was a revolutionary system (the revolutionary part is that anybody cared at all about security in the Rails world) for protecting Rails against XSS attacks. Rails 1.x. These days Rails supposedly has builtin XSS protection system (and ton of other security screwups, hi there github!), so unless you're forced to use some ancient version of Rails, my XSS Shield can be allowed to rest in peace.

I have a bunch of cool local patches for acts_as_solr, but I had trouble even finding upstream. Is anybody interested? I could put the patched version on github or something.

Update urgently needed

One thing I really need to do something with, and sooner rather than later, is jrpg. I don't plan to do any serious development, but it's suffering from software rot - every new version of Python, Windows, or graphics drivers causes more and more problems. Upgrading it to some new Python (not sure if 3.x would be necessary or if 2.7 would be enough), and building new packages for Windows and OSX should be about enough. My bad that I left it not done for so long.

I have a bunch of Ruby libraries - magic/help, magic/xml, and libgmp-ruby which are not in gems for a simple reason that they're older than gems. All three could still see some use, except of course nobody will ever bother to manually build them in 2012, we're too lazy these days. So an evening or two of modernizing them, putting them on github, packaging them into gems, and possibly making them Ruby 1.9.x (or 1.8.7 for all I know, they still remember Ruby 1.6 era) compatible would be a huge improvement.

Total War

One thing I have been doing a lot - and I never wrote one word about it on this blog - are development tools for Total War series. A big problem with video game modding is that people lack good Open Source practices - they don't put their software in publicly accessible repositories, often get into drama on who can do what (I wrote a mod but don't you dare reuse my files in your mod!). I've been trying to change that and all my Total War related stuff is on github in etwng repository.

I have tons of converters for various formats, scripts for common modding tasks, even Linux and OSX filesystem drivers (FUSE FTW! I just feel dirty for using C++ for it) for their custom package format. This is still active and well, and people have even written third party GUI frontends for my tools etc.

It might be a good idea to take some time and gather links to everything Total War related that's not there, find all abandoned tools and give them new home (like I did with alpaca's ui coverter), and maybe put my old Rome Total War / Medieval 2 Total war stuff there just for completeness, but none of these are really high priority issues.

RLisp

RLisp was something between an art project and a "serious" Ruby/Lisp hybrid language - where "serious" means something like CoffeeScript-serious or HAML-serious, which isn't really all that serious when you think about it.

The thing is - VM for Ruby 1.8 really didn't let me do everything I wanted to do with it for just boring practical reasons. I even tried to compile it to C linked with libruby. I'd like to at least take a look at Ruby 1.9 and JRuby VMs (VM inception) if they are any better. If not, tough luck, it was loads of fun anyway.

Did I mention I'm switching to Linux?

You won't hear me bitch about OSX any more, how awesome is that? Unfortunately, there are two huge things missing on Linux - TextMate and OmniFocus.

TextMate has a sort of replacement in redcar, which I'm not really too happy with. I've complained about it, and even made some minor patches, the truth is I will pretty much have to spend a lot of time on redcar to make it more like TextMate if I want to stay OSX-free for long. I just hope I won't even reach the desperation necessary to switch to Emacs.

The other thing that Linux misses is OmniFocus - pretty much the only GTD app which isn't made of suck. This doesn't sound too complicated (compared with let's say a text editor or packaging system - things people keep failing at all the time), so I might end up writing one if I'm unhappy with everything. If you know of a good offline GTD app I can try, do tell me.

And that's about it

That's it for today. I'm surprised my kitten-pic-finding scripts even worked after all that time. Did I miss any software I wrote that you care about?

Hopefully it will take less than a year for the next post.

Sunday, May 01, 2011

Friday Night Magic - Red Deck Wins


On Friday (that would be 2011-04-29) I took part in my first Magic: The Gathering tournament ever, and I ended up winning it. I never drafted before so I made some notes afterwards and here they are.

Draft


The draft was one Mirrodin Besieged booster, and two Scars of Mirrodin boosters.

In case you haven't been following Magic, both sets are full of artifacts, almost purely monocolor, have moderate amount of infect, and use metalcraft mechanic, where various cards get significant bonuses if you control 3 or more artifacts.

In three boosters you'll see - 3 rares/mythics, 9 uncommons, 30 commons, plus as many basic lands as you want, so the deck of 40 cards you need to build will be based on mostly crap commons and crap uncommons. This is far worse than even 100% common Pauper format - there you at least get to choose any commons you want. In booster draft it's mostly commons others didn't want.

Power creep took place primarily on rare and mythic rare levels, so unlike with constructed, limited's power levels are very low. Majority of the cards will be stuff considered unplayable elsewhere, and the few "playable" cards will lack any consistency or synergy you'd normally expect if you could build the deck from larger set of cards.

The way draft works, everybody opens one booster, picks one card, then passes the rest to the person on the left, and it continues until all cards have been used. Then second booster goes to the right, and finally third again to the left.

This introduces a lot of luck into the process. Obviously people will take the best cards in their first few picks, so the first few cards are the most important. The only reason they would not take a great card if it was incompatible (most likely of wrong color) with the deck they got so far.

So if you're trying to build a deck very similar to what people next to you are making, they'll take all the good cards, and you're screwed.  On the other hand if they build something in a completely different color, you'll get a lot of great
cards you can use. Where you sit decides a lot.

In Mirrodin Besieged booster draft you get to make three big decisions:
  • which colors to use
  • use a lot of artifacts and try to get metalcraft bonuses or not?
  • use infect or not?

My constructed experience of playing multicolor decks without dual lands and other solid mana fixing told me to never do that again. In constructed, multicolor requires expensive mana base, and that's the end of it.

I was quite strongly determined to go monocolor even with crap cards, or at worst mainly monocolor with just a splash of a second color but only if I really really have to. At least due to lack of any dual lands whatsoever it wouldn't matter if it's ally or enemy color.

Because I wanted monocolor and I couldn't really count on having enough cards of one color - artifact-heavy metalcraft deck was a totally obvious choice. I didn't want to use infect as infect is an all or nothing choice - and with red having so few decent infect cards that wasn't even much of a choice.

By the way after the tournament I found out I had the only monocolored deck of all players.

Deck


So here's my deck:

1x Memnite
1x Iron Myr
1x Blisterstick Shaman
1x Koth's Courier
2x Snapsail Glider
2x Blade-Tribe Berserkers
2x Ogre Resister
1x Oxidda Scrapmelter
1x Flameborn Hellion
1x Galvanic Blast
1x Rally the Forces
2x Assault Strobe
1x Metallic Mastery
1x Slagstorm
1x Golden Urn
1x Infiltration Lens
1x Panic Spellbomb
1x Golem's Heart
1x Trigon of Rage
1x Necrogen Censer
1x Semblance Anvil
15x Mountain

At first, I even wanted to go with 14 lands - 1/3 lands is entirely reasonable in constructed, right? Especially monocolor. Double especially monored.

But such low land counts rely purely on abundance of 1-drops and 2-drops, and here there are very few. Most people had 16-18 lands as far as I can tell and that's far more reasonable.

Very early I got rid of one card - Semblance Anvil - and replaced it with 16th mountain. Together with Iron Myr that increased count of mana sources to 17, which was totally reasonable.

I had no idea how bad Semblance Anvil would be. I had it three times in my hand, and every single time it was a dead card. It costs you two cards (a huge cost) for some mana savings, and it is only useful if vast majority of your spells have the same type. Mostly artifacts, or mostly creatures, or maybe some tribal tricks. This just never ever happens in draft. Even if I had two creatures and Semblance Anvil in my hand, I would have to exile one of them and waste a turn just to cast the second one more cheaply the next turn. In almost every case an extra Mountain instead would let me cast it turn earlier, and without wasting the other guy. Usually it was even worse.

I didn't do any other sideboarding - I simply had no red left, nor artifact cards that weren't total garbage.

Games


There were four rounds. My record was:
  • 2-0 against Blue-Black
  • 2-0 against Red-Green-Blue
  • 2-1 against Green-White
  • 2-0 against Red-White

I also played two more games outside the tournament with this deck, losing one and winning the other. I only had to mulligan in one game, down to 5 cards. I had some not terribly good cards, but I went ahead with them as draft doesn't need to worry about opponent winning on turn 3-4 the way constructed has.

Many of the games were very close.

Some of the decks I played against had much better cards, whet considered individually. Sword of Body and Mind and Thrun, the Last Troll have hit the board, but in both cases their timing was too late and they couldn't do much. Even many less powerful card were simply better than anything I had.

I think all decks I played against - and probably most of those I haven't - suffered from more or less serious consistency problems. Many times I won thanks to my opponent being color screwed. Quite a few times they were mana screwed or mana flooded, and their curve didn't work too well with what they got.

Many people have splashed some infect. I understand why they did it, as individually they were good cards, and there's only so much you get to work with, but most cards which are good in infect decks, are bad in decks which just splash infect.

In all games I wasn't countered even once, I had my cards removed in various ways quite often. Some of my opponents tried to get metalcraft as well, but they seemed to have harder time doing this, probably they simply had fewer artifacts.

At least that's my theory. It's entirely possible that I'm wrong and I simply got lucky this time ;-)

Cards


Now I'll talk about all cards individually. I'll order the cards from the best to the worst.

The best card was my only rare Slagstorm. It saved the game when I used it to clean the board when I was behind. Once I attacked with everything, the opponent let some damage through, and then I cleaned the board of everything. It won the game a few times - people defend their last point of life with everything they got but it's much easier to get them down to 3, and then it's over.

Oxidda Scrapmelter was really awesome in this deck, as pretty much everyone played with some artifacts. And 3/3 for 4 mana in this format is good.

Iron Myr generates mana, metalcrafts, and has 1/1 body which can be surprisingly useful.

Infiltration Lens is normally a really good card, but when it doubles as metalcraft pumper it's just amazing.

Blisterstick Shaman was usually 2-for-1, but at the very least it damaged the opponent one life.

Flameborn Hellion - 5/4 with haste and totally irrelevant downside for 6cmc - was my most common wincon. It often got 5 damage the turn it entered the battlefield, and then the opponent would get desperate, stop their attacks, and squandered their resources on chump blocking while my side of the board got bigger and bigger. When I managed to equip it with Infiltration Lens it was game over same turn.

Koth's Courier was just amazing as long as my opponent played green. 2 damage per turn means 10 turn clock, and it doesn't really matter on its own. But its presence on the board made every other threat at least twice as thretening, and the opponent would desperately throw all their resources at doing something at least about the other one - even at very unfavourable exchange, and that loss of resources would lose them the game.

Blade-Tribe Berserkers were really awesome as long as I had metalcraft - but more often than not I was out of luck here and I missed an artifact or two. With metalcraft it's essentially 4cmc 3/3, opponent sacrifices a creature or gets 6 damage. Almost as good as Oxidda Scrapmelter if it was only more consistent.

Golem's Heart was very good. As both me and the opponent had plenty of artifacts, it would usually get me enough life to win aggro race while pumping metalcraft. It was the target of opponent's removal spells more often than any other card, including my biggest threats.

Galvanic Blast was able to get rid of pretty big creatures if I had metalcraft. I had to use it without metalcraft once, but then the creature I wanted to get rid of was something small, so it didn't really matter.

Necrogen Censer is 4 damage to player for 3 mana. Normally it would be somewhat too slow, but here it helps with metalcraft.

Ogre Resister was a decent early fattie, unplayable in constructed but pretty good in draft.

Memnite mostly pumped metalcraft, I didn't have many other uses for it, and I rarely even wanted to exchange it for another 1/1 or I'd lose metalcraft bonus.

Snapsail Glider was only OK because it pumped its metalcraft, so its chances of gaining flying were higher than usual. In constructed it would be a crap card - even 2/2 unconditional flier for 3cmc would be highly unimpressive.

Metallic Mastery is an artifact version of Act of Treason, but I'd rather have Act of Treason. I only used it once to steal Myr Propagator for a turn and use it to make
myself a copy. For the rest of the game we kept creating and wasting Myr Propagators. There aren't really that many non-creature artifacts I could steal, and those I could for example sac for good effect would get prematurely sacced in response to my Metallic Mastery anyway, so it would be a waste.

Trigon of Rage was very hard to use well. Mostly metalcraft pumping.

Golden Urn was slower lifegain than Golem's Heart. Mostly metalcraft pumping.

Rally the Forces looks like a very nice card, but in all my games I never had a good opportunity to use it.

Panic Spellbomb only served to boost metalcraft, or as emergency card draw.

Assault Strobe was so often almost what I needed, except I couldn't use it because of its sorcery speed.

The single biggest disappointment was Semblance Anvil, as I mentioned before.

Future


Is my booster draft experience normal? I'd have expected a lot more monocolored decks, but I had the only one. We just had two sets with plenty of artifacts, now we'll get one with easily splashable phyrexian mana. Shouldn't more people try to build consistent monocolor decks?