Computing Millions of Team Compositions for TFT

TL;DR: it cool? yes. it epic? ദ്ദി˙ ᴗ ˙ )

What is TFT?

Teamfight Tactics (TFT) is an auto-battler strategy game where players draft and position champions on a grid. Champions have traits and synergies that combine to form powerful team compositions. Each round, teams automatically fight opponents, and success depends on strategic selection, positioning, and synergy optimization. The game emphasizes combinatorial strategy and adaptive decision-making.”

What is TFT Comp Creator?

It’s a program designed to generate mathematically optimized TFT compositions using an “n choose k” combinatorial algorithm combined with a node-based prioritization system.

Users can define a depth value to explore the most promising combinations, while filters allow inclusion/exclusion of specific champions or traits. This lets players explore non-meta strategies, test creative team setups, and discover synergies that would be difficult to find manually.

The need for an algorithm

While the pandemic was active we were all at home, and so with a bunch of friends on Discord we were reunited to play games, one of those was TFT.

It was simple and didn’t require me to be competitive, in fact I loved going against the “meta”, and I’ve noticed a youtuber in particular that made very different comps. By “different” I mean, instead of ensuring every unit had different roles (eg. a support unit healing in the back while also dealing some damage) this person focused on a single unit and the whole idea was to maximize that unit’s power.

Back then there was a champion called Leona, this champion is known to be tanky and usually has support potential. But damage was weak and so many people labelled that unit as not strong. The YouTuber found found a way to maximize that power and it was incredibly OP.

The idea of exploring possibilities and diversity was always something that I was attracted to, and so, I asked myself: “How can I find similar comps?

The plan

Create a new project, obtain all champions data with their stats and traits, then figure out a way to score how good a composition is based on traits and champion contributions.

Luckily for me there’s a dedicated community that releases the data that we need called CDRAGON.

Next step is to build a simple GUI that allows me to set some parameters.

I could specify the comp size, number of nodes, how I would score the result (stats or active traits) and the most important part was the algorithm.

The original algorithm was called Pet, the idea behind it was to select an initial “owner” champion, then iterate through the next best “dog” or “cat” (aka champion) so at this point we would have two, then repeat till comp size was reached.

This way I would always get a solution, even though it wasn’t the best. If this sounds familiar to you, then you are correct! The approach was similar to greedy path expansion algorithms (conceptually close to Dijkstra-style exploration). (ᵕ—ᴗ—)

But that’s cool! Because it means I’m learning.

Adding new features

Now that I had a stable and working program, I could finally implement new features and improve some of them.

Nodes: Given an initial set of champions, it would retrieve the top n most active traits in a composition and return all champions sharing those traits.

Hashmaps: With the new node list, the program would brute force all possible combinations within the node list, checking if a node list was already seen and if false it would add it to a hashmap, else the loop would continue. This process taught me about recursion.

Scoring system: Now the program would calculate a “synergy” score, meaning it would compute how much each champion would contribute to the final composition, rather than computing at each step.

I was making huge improvements to my program and would find many ways to optimize memory usage thanks to the built-in profiler in Visual Studio.

Fixing the big problems

As you can imagine, even though I had made improvements, there were many flaws that rose after implementing the new features.

  1. Hashmaps could use tens of gigabytes of RAM per run, starting from a node depth of 5 (around 20 nodes)
  2. There was still a brute force that acted on lists of strings

The solution? One night I was watching a video from 3blue1brown a popular youtuber and mathematician that explains math in such a beautiful and elegant way.

He asks: “how many distinct pairs of points are there?” and I was like “Dude. That is exactly what I’m trying to achieve

This is the video with the timing (volume warning)

Important note: If you haven’t played TFT, a team is composed of champions that contribute to the overall active traits, but two or more units/champions that are identical won’t increase the overall score. By doing so you are effectively wasting a slot that could have been filled by any other champion.

After that I started researching how all of that worked, the logic behind and I quickly understood that it was too much for me. There were lots of notions that I was never taught at school. This made me a bit sad but I still wanted to tackle the problem I had, with the solution proposed. So I went and explained my issue and gave ChatGPT my code for a better solution that even included parallelization, something that I’ve never touched before and only heard about it being used in complex projects that required intense computation.

And oh my. The software started outputting hundreds if not thousands of valid combinations in a matter of seconds. I had to separate the GUI and the rest of the computation in its own thread, otherwise my GUI would freeze (lots of prints).

The conclusion

Although I received help designing the optimized solution, implementing, integrating, and maintaining it still required significant changes to the architecture of the program. I knew I was on the right track since the beginning and seeing the upgraded outcome made me improve the program even further. I did not reach the initial goal of “let’s find a weird comp” because that requires deeper knowledge of each unit’s ability, which would be insane to code for a game that I don’t even play that much. But I did get a very nice program that gives out mathematically strong outcomes and that is enough for me 🙂

Final observations

I did lots of testing, friends of mine that are way better than me at this game, helped me test the outcomes and give new inputs on how to improve the software. To the point that the program tends to surface compositions aligned with future metas.

At the beginning of a set, nobody knows which comp is stronger and Riot tries its best to balance the game, nothing is perfect and there will always be a tendency towards what survives the most, and synergy is one way to detect that vector.

 

Project repository: https://github.com/dragitz/TFT-Comp-Creator