The Art and Science of Counting Pixels: Behind the Math of the game Figment

11 min read Original article ↗

“What’s the fastest and most accurate way to calculate the exact area of a pink in this design?”

That was the question my friend Alex Hague asked me when he was developing the game Figment for his tabletop company CMYK Games.

It’s a deceptively simple request, but answering it formally or even technically is quite difficult.

Before we try to answer it, here’s a little more on one of CMYK’s newest games: Figment is a brilliantly simple and fun game that challenges us to to estimate the area of shapes and then use those estimates to sort a set of cards. The twist is that when a card appears to have more one color than another, it is sometimes merely an optical illusion exploiting our visual system’s difficulty estimating the area of arbitrary shapes.

This is the perceptual challenge that makes Figment challenging (and therefore fun to play) but it also meant CMYK needed an objective “ground truth” for each color on every card in order to make the game fair. And with dozens of cards, that meant we need an automated way to calculate the exact percentages for each card’s answer key.

Alex explained to me that what had initially seemed like a straightforward design task and something easy to prototype had turned out to be a fiendishly annoying problem. He approached me because he knows I love these types of problems and wondered whether it could be solved with some computational creativity.

And indeed, as soon as he explained it to me, I jumped at the opportunity to start puzzling through how we might do it algorithmically.

The challenge behind the game

Before we get to the mathy stuff, let’s go over the rules for playing Figment. 

In each round of Figment, players are tasked with ranking cards based on one of the 4 main colors of the game – simply laying out 5 cards ranked by which ones have the “most” of the round’s arrow color.

Sounds simple, right? Well, it turns out it’s pretty tricky in practice which is what makes the game fun.

The back of each card reveals each color’s percentage relative to the entire surface area of the card including the white background. 

The task Alex and his design team were struggling with was systematically calculating the exact percentages of the card that each color occupies on the card face. This was crucial because the entire point of the game is to rank the cards based on their color percentages – if the numbers were wrong, the game wouldn’t be fair nor fun. 

Alex needed a method that was:

  • Accurate down to a couple decimal points: If a card were 25.51% blue and another was 25.49% blue, they need to be rounded properly
  • Consistent across all cards: Checking the values manually in Illustrator turned out to be a total chore and sometimes yielded different results. Online tools were no better.
  • Verifiable: We wanted the process to be data driven so we could easily audit the entire deck in a spreadsheet
  • Automated: Sometimes card designs changed, and being able to quickly process all 100 designs efficiently in one task would be ideal 

You’d think there would be good tools for this, but they’re harder to use than you’d expect.

Our first instinct was to look for existing tools that could batch process the color analysis. Adobe Illustrator offers one-off estimates for the area of vector shapes when a single color is selected but seeing as Figment ships with 100 distinct cards (some with hideously complex designs) we wanted to avoid the manual and error prone labor required with that approach, especially considering it would have involved manually compiling the results into a separate spreadsheet. Automating Illustrator to “pick” the color areas automatically also seemed like a nightmare if it was even possible.

A computational method would mean implementing an automated way to mathematically derive the surface area of each color. This approach would also have the added benefit that we could apply exactly the same algorithm to each card systematically.

If you try digging around the web for this kind of tool, you’ll find there are apps and online services that will analyze images for their color distribution, but we found them to be consistently unreliable when compared to Illustrator and not much more efficient either. Even more annoyingly, we found ourselves getting occasionally inconsistent results from the same tools with the same card, which was very frustrating.

This kind of thing actually really matters for a game like Figment.

Without a rigorously tested ground truth for each color on each card, we knew shipping the game would feel sketchy at best and dishonest at worst. In particular, it’d be problematic for the really close calls where players were forced to choose between two cards with 6% pink vs. 5% pink, for example. A rounding error of 0.5% could determine the entirety of a game’s outcome. 

If you’ve ever participated in a particularly competitive board game session, you’ll know how important it is to have a definitively, objectively correct outcome for a given rule. 

All this meant that I was very excited to see if I could figure out a comprehensive computational approach using mathematics.

I initially considered calculating the area of vector shapes directly. In theory, you could calculate the exact area of each shape based on its geometry using pure math (e.g. calculating the area of a circle is given by a simple algorithm A = π * r2 ). 

Sadly this approach quickly falls apart when dealing with complex, overlapping shapes.

The more I thought about it, the more I realized that this must be an established problem in mathematics, similar to the coastline paradox:

It’s not hard to see how the coastline paradox applies here: if the same shapes has different perimeters based on the units you measure them with, then you’ll end up with different areas!

The challenge with Figment is similar and it turns out this is a non-trivial problem in higher order math. There’s even a field dedicated to it called measurement theory! 

Here’s a relevant excerpt from the mathematics Stack Overflow discussing the difficulty in calculating the area of an arbitrary shape:

This happens to be a surprisingly difficult problem. In 1890 Karl Hermann Amandus Schwarz (1843-1921) published an example that showed the accepted definition of surface area gives an infinite area for a cylinder by showing there exists a sequence of inscribed polyhedra that converge uniformly to a cylinder such that the areas of the polyhedra diverge to infinity. 

Thankfully I didn’t need a PhD in mathematics to get any further – some basic problem solving landed me with a really solid solution. 

The Pixel-Counting Solution

The original designs of Figment’s cards, created and stored as vector graphics in Adobe Illustrator, are the closest to pure shapes inside a computer’s mind. But remember, because virtually all of these shapes are irregular they don’t have easily computable areas, so while the computer can render them, it doesn’t actually know their area initially! 

How would you estimate the area of the pink line?

That’s the beguiling paradox that’s at the heart of the Figment game mechanic: we can perceive the boundaries and edges of these shapes both digitally and visually, but neither our minds nor our computers have a precise way to determine their area. 

However, I realized that the key to computing their areas could rely on rasterization, the process of turning a vector image into a pixel-based raster image. 

In order for a shape to be displayed on your computer’s LCD screen or static raster image, it must follow a transformation from its theoretical representation consisting of lines, curves, and fills, into individual pixels. So whether your computer is displaying a vector shape on an LCD screen, saving it as a PNG, or printing it out on an inkjet printer, the same underlying process is at work: fill up a grid of pixels in such a way that it resembles the underlying shape defined in the vector file and let our eyes do the rest. The original information of the vector image defined by splines and shapes gets discarded in lieu of a finite set of pixels on a grid that has a limited resolution. 

I realized that we could piggyback off this foundational process in computer science to solve the problem for Figment, as once we had a pixel representation of each card, we could merely count the number of pixels per color, something standard image processing libraries can all do. 

Just count the pixels per color, then you’ll your answer, right? 


Unfortunately, while this was the right path to the correct solution, it turned out to be a more difficult problem than meets the eye.

Here’s why: while vector images offer a ton of value to designers, they must eventually always go through a rasterization process to make them look appealing to human eyes and not just computer systems. This rasterization step introduces a whole set of ambiguous colors via something anti-aliasing.

Anti-aliasing is its own topic in computer graphics but here’s a quick explanation:

Anti-aliasing smooths jagged edges by creating intermediate colors between shapes, making edges look smoother to the human eye but creating a gradient of ‘in-between’ colors that complicate pixel counting.

Anti-aliasing initially became a huge problem for this approach as it results in a bunch of “in between” colors on the border of edges:

How would you count the pixels in this cropped portion of a card? Inevitably, you’d end up with some tough calls when it comes to these edge pixels – they’re essentially indeterminate colors for the purposes of playing Figment. 

This posed a problem for the naive pixel counting approach as we’d end up with a lot of colors that were similar to the main colors, but not actually the game’s primary colors. These indeterminate lost pixels ended up adding up to single digit percentages, which in a game that comes down to small differences, could be a huge issue.

Put another way, if you had to look at each of these pixels and answer the question: which pixels “belong” to Figment’s pink color, you’d have a hell of a time.

However, thinking about it this way gave me the clue I needed for the solution: I could use a simple distance metric to chart a line in RGB color space between each indeterminate pixel and one of our 5 colors.

The Figment color that was closest (e.g. the shortest line) to the ambiguous pixel would yield the color that the pixel “belonged to”. 

Here’s how I did it in code – it’s an algorithm that effectively forces each pixel to the closest of our four target colors using Euclidean distance in RGB space:

def get_color_name(rgb_triplet, target_colors):
    min_distance = float('inf')
    closest_color = None
    for color_name, target_rgb in target_colors.items():
    # Calculate Euclidean distance between the pixel and target color   
    # in 3D RGB space (treating R, G, B as x, y, z coordinates)
        dist = sum([(a - b) ** 2 for a, b in zip(rgb_triplet, target_rgb)])
        if dist < min_distance:
            min_distance = dist
            closest_color = color_name
    return closest_color

This ensured that light pink pixels were counted as pink, slightly off-green pixels were counted as green, and so on.

It also meant that there were no pixels left behind – every pixel would get assigned into one and only one of the five main colors. 

Put really simply, you can think of this algorithm as “rounding” the pixels to their nearest Figment color by using geometry in a 3D color cube. Neat!

The Results

The algorithm performed perfectly. For each card, we derived precise percentages that we could verify visually and mathematically. The whole deck was processed in under a minute, generating a spreadsheet with color percentages accurate to two decimal places.

We were even able to use these percentages to rank cards by difficulty, with cards having more evenly distributed colors being harder to guess than those dominated by one color.

Open-Sourcing the Tool

I’m excited to open-source my pixel counting tool for others to use and modify. Whether you’re developing a game, analyzing designs, or just curious about color distribution in images, the core algorithm is now available on GitHub.

Feel free to adapt it to your needs—maybe you need to analyze more colors, process different file types, or integrate it into a larger workflow.

All the pixels that are fit to count

Sometimes the simplest approach is the most effective but it can take a while to whittle down a problem to it’s core before you get there. 

This project also reminded me that game design is often as much about solving technical problems as it is about creating engaging gameplay. The pixel-counting algorithm might be invisible to players, but it’s woven into every guess they make and every point they score.

If you’re curious about the algorithm or want to try it yourself, check out the code on GitHub.

And if you’re interested in seeing the results in action, grab a copy of Figment and start guessing those color percentages!