Attempting to Play Tron With Python

Cole Kepford
6 min readApr 12, 2021

Quick Recap

This is a continuation of a project and the first part can be found here. https://cole-kepford.medium.com/learning-python-to-play-magic-the-gathering-7bee3930ed70
For a quick recap I went over the surface level differences between the programming languages Java and Python. The purpose of this was to use learning Python as an excuse to attempt solving a problem I’ve wanted to figure out for a long time. The problem was to play the Magic the Gathering (MTG) deck Tron. This article will go over the further knowledge I’ve gained about Python, the script I wrote to play Tron without an opponent, and the troubles I encountered.

Taming the Python

I finally discovered something in Python that I heavily dislike and prefer Java/earlier languages for. In Python you get super fancy and easy enhanced for loops. However, there is no actual standardized for loop you’d be used to from third generation languages.

for(int i = 0; i < arr.length; i++) {
}

If you want the ability to have any Boolean values besides reaching the end of what you’re iterating over you’re going to have to go through all the work of setting up a clunky while loop.

while removedcards < 7 - handsize and i < len(hand):  if(hand[i] == "tower" or hand[i] == "mine" or hand[i] == "pp"):    deck.append(hand.pop(i))    removedcards += 1  i += 1

Look at that thing, makes me nauseous, and definitely not because I often write spaghetti code. One more thing I learned is that methods behave the same way that variables to in Python. Their return value is dynamically determined at runtime by whatever piece of data it returns in it’s definition.

def onetronland(hand):  if("tower" in hand or "mine" in hand or "pp" in hand):    return Truereturn False

While I feel a little anxious not declaring datatypes for methods it certainly makes writing code in general a lot faster. If I had to write this script in a language besides Python it would have taken me considerably longer just based off typing speed alone.

Assembling Tron

It would be ridiculous to go over every line of code in the script so I’ll be summarizing sections with examples. If you want to see the whole thing, it can be found here https://github.com/ColeKepford/Tron_Goldfish

To quickly recap the combo, Tron earns its name when it assembles three different lands, Urza’s Tower, Urza’s Mine, and Urza’s Powerplant. These lands allow the Tron player to cast spells with far more mana than you’re supposed to have on turn three. The purpose of the deck and script is to assemble the combo and efficiently as possible and see if you have a payoff for it.

Mulliganing

The first task to accomplish with playing a game of MTG is to decide if you’re going to keep or mulligan your hand. The way the current mulligan rules work in MTG is you draw a hand of seven cards and if you mulligan you draw a new hand of seven. If you keep the hand you put cards on the bottom equal to how many times you’ve mulliganed. To solve this, I set up varying conditions for keeping a hand based off how many mulligans you’ve taken.

  • All hands with ≥3 cards and the combo in it are kept
  • Any hand with two Tron lands and a way to search for them on turn two are kept
  • Hands not meeting the above two conditions are mulled to at least five
  • Once at five cars simply have two Tron pieces and a “star” is a keep
    (link to card) https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=489912
  • On four cards one Tron land and star or tutor effect is a keep
  • Three card hands have the same conditions
  • Once on two or less cards simply having a Tron land in it is a keep

One of the big challenges of this project was once a hand is kept if it was mulliganed to, in what order do you remove cards from it and put them on the bottom? My solution was to first filter through the filler or named “trash” cards that don't facilitate the combo.

Since duplicate lands aren’t helpful in assembling the combo I determined those would be the next best cards to bottom. In the same vein duplicate search effects such as Expedition map or Sylvan Scrying aren’t very useful either so they were the next cards sent to the bottom. After that the next set of cards to send away are the payoffs. They win you the game, but if you can’t cast them they’re useless. The next cards to bottom would be the enablers themselves such as Ancient Stirrings which can’t be cast efficiently without a “star” effect in hand.

If they’re are still cards that need to be bottomed Chromatic Stars and Spheres will be bottomed, followed finally by the Tron lands themselves.

Playing the Deck

Once a hand has been kept it’s time to see if it can combo. The first thing that’s checked for is if you have any lands in play to produce mana. This is followed by determining if you have any unique Tron lands you can play from your hand. Then the script checks if you’ve assembled Tron in play, if so the script ends on that turn. Then the script checks if you have certain cards in play and what to do with them in the following order.

  • Is a Star effect in play? If so, crack it
  • Do you not have the combo and have a search effect you can use. If yes, use them
  • Do you have an Ancient Stirrings and can you cast it?
  • Do you have any star effects you can cast and then use?
  • Have you drawn any Tron lands and not played a land yet?
  • Have you drawn any non-Tron lands and not played a land yet?

There are a few more intricacies than that, but that’s the basic order and premise. After the above process runs through if Tron hasn’t been put into play a new turn starts and the loop starts again.

Doesn’t Totally Work

Unfortunately I’ve been having some issues that are preventing it from being fully functional. If running it through a client or through the console it assembles the combo and doesn’t go through the turn cycle. However, when going through it step by step in a debugger it runs correctly. With some tinkering and proper break points I’ll be able to determine where it’s breaking, but currently it won’t work without some finagling.

Conclusion

Overall, it’s been a really fun time getting to screw around in a new user-friendly language to try and solve a problem I found interesting. This was a problem that became significantly harder to solve than I initially thought it would. Figuring out the proper order to bottom cards definitely took a lot longer than I expected it to. I’ll echo my opinion from the last post. If you’re new to programming or want to limit how many characters you need to type to solve a problem, Python is certainly a very good choice.

--

--