{"id":867,"date":"2018-10-14T17:08:48","date_gmt":"2018-10-14T15:08:48","guid":{"rendered":"http:\/\/hudecekpetr.cz\/?p=867"},"modified":"2018-10-14T17:08:52","modified_gmt":"2018-10-14T15:08:52","slug":"a-formal-grammar-for-magic-the-gathering","status":"publish","type":"post","link":"https:\/\/hudecekpetr.cz\/cs\/a-formal-grammar-for-magic-the-gathering\/","title":{"rendered":"A formal grammar for Magic: the Gathering"},"content":{"rendered":"<p class=\"qtranxs-available-languages-message qtranxs-available-languages-message-cs\"> <\/p><p>I wrote an ANTLR4 formal grammar for Magic: the Gathering cards.<\/p>\n<p>It turns this<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-868\" src=\"http:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/HatcherySpider.jpg\" alt=\"A Magic: the Gathering card\" width=\"300\" height=\"418\" srcset=\"https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/HatcherySpider.jpg 672w, https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/HatcherySpider-215x300.jpg 215w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>Or, more specifically, it turns this<\/p>\n<p><em>Reach<\/em><br \/>\n<em> Undergrowth \u2014 When you cast this spell, reveal the top X cards of your library, where X is the number of creature cards in your graveyard. You may put a green permanent card with converted mana cost X or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order.<\/em><\/p>\n<p>Into this:<\/p>\n<p><a href=\"http:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/HatcherySpiderGrammar.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-869 size-large\" src=\"http:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/HatcherySpiderGrammar-1024x560.png\" alt=\"\" width=\"1024\" height=\"560\" srcset=\"https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/HatcherySpiderGrammar-1024x560.png 1024w, https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/HatcherySpiderGrammar-300x164.png 300w, https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/HatcherySpiderGrammar-768x420.png 768w, https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/HatcherySpiderGrammar.png 1382w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>You can try it out here:\u00a0<strong><a href=\"https:\/\/soothsilver.github.io\/mtg-grammar\/\">https:\/\/soothsilver.github.io\/mtg-grammar\/<\/a><\/strong>\u00a0and you can download the grammar and the source code from\u00a0<a href=\"https:\/\/github.com\/Soothsilver\/mtg-grammar\">https:\/\/github.com\/Soothsilver\/mtg-grammar<\/a>.<\/p>\n<p><!--more--><\/p>\n<p>It handles all 273 cards of\u00a0<em>Guilds of Ravnica<\/em>, the most recent Standard set as of now.<\/p>\n<p>What&#8217;s it good for? For nothing, because the <a href=\"https:\/\/company.wizards.com\/fancontentpolicy\">Wizards Fan Content Policy<\/a> prohibits fans from using Wizards&#8216; &#8222;gameplay&#8220; in their content, which, I suspect, includes Magic: the Gathering rules.<\/p>\n<p>But suppose we weren&#8217;t limited by the policy. The <a href=\"https:\/\/magic.wizards.com\/en\/mtgarena\">Magic Arena<\/a> team isn&#8217;t. They are using a parser, similar to the one I created, to generate code from rules text.<\/p>\n<p>Traditionally in video games, game components such as cards, spells, and abilities are scripted. Here&#8217;s Affectionate Indrik:<\/p>\n<p><a href=\"http:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/AffectionateIndrik.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-872\" src=\"http:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/AffectionateIndrik-215x300.jpg\" alt=\"\" width=\"215\" height=\"300\" srcset=\"https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/AffectionateIndrik-215x300.jpg 215w, https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/AffectionateIndrik.jpg 672w\" sizes=\"auto, (max-width: 215px) 100vw, 215px\" \/><\/a><\/p>\n<p>Here&#8217;s how the code for Affectionate Indrik&#8217;s ability looks like in an unnamed Magic: the Gathering game:<\/p>\n<p><span style=\"font-family: 'Courier New';\">Ability ability = new EntersBattlefieldTriggeredAbility(<br \/>\nnew FightTargetSourceEffect()<br \/>\n.setText(&#8222;you may have it fight target creature you don&#8217;t control&#8220;),<br \/>\ntrue<br \/>\n);<br \/>\nability.addTarget(new TargetCreaturePermanent(filter));<br \/>\nthis.addAbility(ability);<\/span><\/p>\n<p>And here&#8217;s how it looks like after parsing from rules text:<\/p>\n<p><a href=\"http:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/Indrik.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-873 size-full\" src=\"http:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/Indrik.png\" alt=\"\" width=\"862\" height=\"753\" srcset=\"https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/Indrik.png 862w, https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/Indrik-300x262.png 300w, https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/Indrik-768x671.png 768w\" sizes=\"auto, (max-width: 862px) 100vw, 862px\" \/><\/a><\/p>\n<p>The idea is that, from this syntax tree, you can generate the code above automatically. A syntax tree is no longer arbitrary English text incomprehensible to a rules engine, it&#8217;s an object that can be, in theory, unambiguously converted into code. The hope is that this way, it will be easier to add new cards (because nobody needs to script them) and that there will be less bugs (because nobody can make bugs in the scripts because the code is created automatically). There could be &#8222;bugs&#8220; in the rules text, but that&#8217;s unlikely. Wizards of the Coast pays attention to editing. I&#8217;ve only encountered a single editing error in the entire <em>Guilds of Ravnica<\/em> set (there&#8217;s a missing space between the end of the rules text and the reminder text for surveil in the card <a href=\"http:\/\/gatherer.wizards.com\/Pages\/Card\/Details.aspx?multiverseid=452794\">Mission Briefing<\/a>).<\/p>\n<p>But of course, the rub is that there could be bugs in the parser or the semantic analysis or the code generation. That has already happened. Look at Beamsplitter Mage:<\/p>\n<p><a href=\"http:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/Beamsplitter.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-875\" src=\"http:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/Beamsplitter-215x300.jpg\" alt=\"\" width=\"215\" height=\"300\" srcset=\"https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/Beamsplitter-215x300.jpg 215w, https:\/\/hudecekpetr.cz\/wp-content\/uploads\/2018\/10\/Beamsplitter.jpg 672w\" sizes=\"auto, (max-width: 215px) 100vw, 215px\" \/><\/a><\/p>\n<p>It reads, in part,\u00a0&#8222;Whenever [..], if you control one or more other creatures that spell could target, choose one of those creatures. [&#8230;]&#8220;<\/p>\n<p>So the parser sees the phrase &#8222;those creatures&#8220;. Well, asks the parser, I wonder what those creatures are, I should look at the preceding sentence to figure that out. It does and it\u00a0reads &#8222;one or more other creatures that spell could target&#8220; and joyfully presents to the player as possible choices all creatures that spell could target.<\/p>\n<p>What the parser failed to\u00a0notice are the words &#8222;if you control&#8220;: &#8222;those creatures&#8220; actually refers to &#8222;one or more other creatures under your control that the spell could target&#8220;. Here&#8217;s a Benjamin Finkel, a Magic Arena developer, explaining it:<\/p>\n<div class=\"reddit-embed\" data-embed-media=\"www.redditmedia.com\" data-embed-parent=\"false\" data-embed-live=\"false\" data-embed-uuid=\"df2f50d3-4459-437c-93d5-f006d60f22d9\" data-embed-created=\"2018-10-14T11:49:11.278Z\"><a href=\"https:\/\/www.reddit.com\/r\/MagicArena\/comments\/9kdabj\/beamsplitter_mage_incorrect_on_mtga\/e6zooml\/\">Comment<\/a> from discussion <a href=\"https:\/\/www.reddit.com\/r\/MagicArena\/comments\/9kdabj\/beamsplitter_mage_incorrect_on_mtga\/\">Beamsplitter mage incorrect on mtga<\/a>.<\/div>\n<p><script async src=\"https:\/\/www.redditstatic.com\/comment-embed.js\"><\/script><br \/>\nWhat about the mentioned unnamed program with scripted cards? Its code (slightly modified) looks like this:<\/p>\n<p><span style=\"font-family: 'Courier New';\">@Override<br \/>\npublic boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) {<br \/>\nreturn permanent.getController().equals(controllerId) \/\/ you control<br \/>\n&amp;&amp; permanent.isCreature()\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\/\/ creatures<br \/>\n&amp;&amp; !permanent.getId().equals(notId)\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\/\/ other<br \/>\n&amp;&amp; target.canTarget(permanent.getId(), game);\u00a0 \u00a0 \u00a0\/\/ that spell could target<br \/>\n}<\/span><\/p>\n<p>That&#8217;s a small part of the script needed to make Beamsplitter Mage work. Obviously, it&#8217;s error-prone. But I&#8217;m still on the fence. Magic Arena developers managed to make all cards in Standard work under a reasonable approximation of the Magic rules system, so this idea of generating code from rules text has merit. But while I was writing the grammar, it always felt so brittle. When you script individual cards, new cards you create don&#8217;t often have an effect on old cards. But with a grammar, any change you make may produce a different syntax tree, with different meaning.<\/p>\n<p>Maybe there are safeguards a developer can use to make those errors less likely. I would be interested in those. And I will be watching Magic Arena as it evolves, especially if developers continue to share behind-the-scenes details.<\/p>\n<p>I have a couple of cave-ats before I end here. I said the grammar handles all cards in\u00a0<em>Guilds of Ravnica<\/em>, which is true &#8212; to an extent. Here&#8217;s the cave-ats:<\/p>\n<p><strong>Flower<\/strong><\/p>\n<p><em>Flower<\/em> reads, in part, &#8222;Search your library for a basic Forest or Plains card&#8220;. The parser interprets it as &#8222;a basic Forest&#8220; or &#8222;Plains card&#8220;, as opposed to the correct &#8222;a basic card that&#8217;s a Forest or that&#8217;s a Plains&#8220;. This happens because it considers the words &#8222;basic Forest&#8220; and &#8222;Plains&#8220; to be of the same kind, when in fact one&#8217;s already a compound of a supertype and a subtype and the other is a subtype only.<\/p>\n<p><strong>Thief of Sanity<\/strong><\/p>\n<p>Thief of Sanity received undocumented, zero-day errata to its text which I noticed too late, and it&#8217;s a pretty unique card, so the parser still works with the text as printed and not the Oracle text.<\/p>\n<p><strong>Aurelia, Exemplar of Justice<\/strong><\/p>\n<p>Aurelia parses, but incorrectly. It reads, in part, &#8222;that creature gets +2\/+0, gains trample if it\u2019s red, and gains vigilance if it\u2019s white.&#8220; Which the parser interprets as &#8222;if it&#8217;s white, it gains vigilance&#8220; and &#8222;if it&#8217;s white and red, it gains trample and +2\/+0&#8220; as opposed to the correct &#8222;+2\/+0 always&#8220;, &#8222;vigilance if white&#8220;, and &#8222;trample if red&#8220;.<\/p>\n<p><strong>Pelt Collector<\/strong><\/p>\n<p>Pelt Collector reads, in part, &#8222;if that creature\u2019s power is greater than Pelt Collector\u2019s,&#8220; which makes sense in English but is difficult to parse because the adjective-like &#8218;Peltr Collector&#8217;s&#8216; doesn&#8217;t qualify anything. It would parse correctly if it said &#8222;greater than Pelt Collector&#8217;s power&#8220;.<\/p>\n<p><strong>Ral, Vraska<\/strong><\/p>\n<p>I added an extra full stop (.) at the end of their ultimate abilities, because as printed, the full stop is\u00a0<em>inside<\/em> the double quotes, which is, of course, proper style, just not easy to handle.<\/p>\n<p><strong>Chance for Glory<\/strong><\/p>\n<p>I thought that the template &#8222;[object] gains [abilities] until [something happens]&#8220; would work for all ability-gaining abilities, but Chance for Glory\u00a0reads, &#8222;Creatures you control gain indestructible.&#8220; There&#8217;s no &#8222;until&#8220;, not after, not in front. They gain indestructible indefinitely. Oh well.<\/p>\n<p><strong>Gruesome Menagerie<\/strong><\/p>\n<p>I cheated a little on this one. The effect is very unique so I basically wrote a term that can only ever apply to Gruesome Menagerie.<\/p>","protected":false},"excerpt":{"rendered":"<p>I wrote an ANTLR4 formal grammar for Magic: the Gathering cards. It turns this Or, more specifically, it turns this Reach Undergrowth \u2014 When you cast this spell, reveal the top X cards of your library, where X is the number of creature cards in your graveyard. You may put a green permanent card with [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,1],"tags":[],"class_list":["post-867","post","type-post","status-publish","format-standard","hentry","category-blog","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/hudecekpetr.cz\/cs\/wp-json\/wp\/v2\/posts\/867","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hudecekpetr.cz\/cs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hudecekpetr.cz\/cs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hudecekpetr.cz\/cs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hudecekpetr.cz\/cs\/wp-json\/wp\/v2\/comments?post=867"}],"version-history":[{"count":8,"href":"https:\/\/hudecekpetr.cz\/cs\/wp-json\/wp\/v2\/posts\/867\/revisions"}],"predecessor-version":[{"id":880,"href":"https:\/\/hudecekpetr.cz\/cs\/wp-json\/wp\/v2\/posts\/867\/revisions\/880"}],"wp:attachment":[{"href":"https:\/\/hudecekpetr.cz\/cs\/wp-json\/wp\/v2\/media?parent=867"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hudecekpetr.cz\/cs\/wp-json\/wp\/v2\/categories?post=867"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hudecekpetr.cz\/cs\/wp-json\/wp\/v2\/tags?post=867"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}