Hagen Fritz
← Blog

Which Pokémon Matches Your Volleyball Game?

pokemonpythonlab

I wrote a script that takes a person’s volleyball stat breakdown and tells them which Pokémon they are. The idea came to me while brainstorming for a PowerPoint night I was having with friends. I wanted to fuse three things about me: my research-y / quantitative side, Pokemon knowledge, and programming skills.

The stat to skill mapping

Pokémon have six base stats: HP, Attack, Defense, Special Atk, Special Def, and Speed. I mapped each of these stats to different beach volleyball dimensions:

🩺 HP
Sustained energy during a rally
Ability to play many games
🗡️ ATK
Serve pressure
Hitting with power
🛡️ DEF
Digging ability
Blocking; pressing and hands
🪄 SPA
Cutting/shooting
Pokies/cobras
Tooling
🧿 SPD
Running down shots
Setting
💨 SPE
Speed
Strategy

Assigning the stats

My method for assigning points followed these general considerations:

  1. The person’s strongest dimension gets 100.
  2. Every other stat is assigned relative to that, within that one person’s kit.
  3. The six stats sum to 420.

The 420 budget was chosen by happenstance. The first two players I assigned points to both happened to sum to 420 so I decided to stick with that to keep everyone on the same scale. The key is that I was not measuring a person against an absolute standard, but describing the shape of their game relative to itself.

That leads to two important notes:

A low stat does not mean “bad.” A low stat means that dimension isn’t a comparative advantage within your own kit. The stats describe where your game lives, not what you’re incapable of.

You cannot compare numbers between players. The numbers describe shape, not magnitude. My 100 and your 100 are not the same amount of anything.

The matching process

I chose to measure shape instead of size. Otherwise, a person scored on a 420 budget would never match to a legendary Pokemon which typically have high base stat totals (500+). Also… it would require me to make comparative judgements between my friends’ abilities which I was not going to do.

Instead, the process normalizes each stat breakdown into ratios where each stat is a fraction of the total. Then I used cosine similarity to compare the ratios between people and Pokemon. Cosine similarity measures the angle between two vectors and ignores their length entirely. Two stat breakdowns point the same direction when they emphasize the same things in the same proportions, regardless of how big the underlying numbers are.

This process led to some interesting (and surprising) results.

A worked example

Take one of my teammates. Let’s call him Devin. He’s a great defender, both digging hard-driven hits and chasing down cut/line shots. For that reason, I rated his defense and special defense the highest. If he is good at running shots down, his speed is also naturally high. So I rated his kit the following way:

HP
65
ATK
50
DEF
100
SPA
60
SPD
80
SPE
65

Defense is his max stat: 100. ATK is his floor at 50, because power hitting isn’t where his game lives (not to say he can’t bounce a ball here and there).

Feed that into the script and the top match comes back at 0.9935 similarity with:

#1  Suicune
    Type:       Water
    Stats:      100 / 75 / 115 / 90 / 115 / 85  (Total: 580)
    Similarity: 0.993502

Suicune. A divine, graceful Pokémon said to embody the compassion of a pure spring and the north wind. It races across the world purifying fouled water wherever it appears.

Animated Suicune sprite

A popular, strong legendary Pokemon! Nice! However… the next best match was:

#3  Burmy (Plant Cloak)
    Type:       Bug
    Stats:      40 / 29 / 45 / 29 / 45 / 36  (Total: 224)
    Similarity: 0.993192

Burmy. To shelter itself from cold, wintry winds, it covers itself with a cloak made of twigs and leaves.

Animated Burmy sprite

A first-stage bug Pokémon with a 224 base-stat total which is less than half of Suicune’s total. The two ranked similarly because they share the same silhouette. Both are tanky in both defenses (in their own right), but weaker on offense. Different sized numbers, but identical shape. That’s the intent, not a bug (well, I guess it is a bug in this case 😜).

The graphics below hopefully make things more concrete. On the left, the three stat lines are drawn as vectors. They have wildly different lengths (Suicune’s 580 down to Burmy’s 224), but only a few degrees of angle separating them. Cosine similarity only cares about the tiny spread, not the length. On the right, are the same three breakdowns drawn as ratios on stat axes. The hexagons land almost on top of each other.

SAME DIRECTION, ANY LENGTH Suicune (580) Devin (420) Burmy (224) ALL THREE, SAME SHAPE HP ATK DEF SPA SPD SPE

Try it yourself

Claude and I ported the matcher from Python to JS to run right in the browser. Drag the bars to set your six stats and see which Pokémon matches your beach volleyball stat shape:

Pokemon Stat Matcher

And if you land on a Burmy, remember: somewhere out there is a Suicune with the exact same shape.