a swirl of green, pink, blue, yellow, and orange

graham builds

Pokemon Phonetic Pangram

posted by graham on January 2, 2026

As a follow-up to my previous post, I have uploaded the data and my previous solution to codeberg. Last time, I learned that Slither Wing is the only pokemon across all current generations to contain the ð phoneme, which meant that only datasets that included gen-9 could form true phonetic pangrams for General American English. With this in mind, I scraped the rest of the generations and compiled them into one unified dataset for all pokemon. As expected, I was able to find several 11-pokemon pangrams1 by simply using the new dataset, but it made me wonder if there existed any pangrams with even fewer pokemon. I tried running the 10-mon pangram attempt across all gens and found that nothing happened for a while, even with the caching I had explained in the previous post.

Technical Hurdles

After discussing this with some of my friends on Discord, it became clear that the size of the problem-space being explored had grown very quickly with the size of the dataset of pokemon, just as predicted. For gen-1, there were at most (151 choose 10) combinations of pokemon to find a set that covered all 37 represented phonemes in that set. For all gens, it was more like (1025 choose 10) combinations, which is roughly 269 million times more. Despite this, I tried to simply run the program and wait. I was rewarded with a new problem:

$ bun run main.ts
136 |           if (!cache.has(cacheKey)) {
137 |             if (solution.names.size < SetCoverSizeToBeat - 1) {
138 |               const idx = queue.findIndex(s => s.phones.size <= solution.phones.size)
139 |               queue.splice(idx, 0, solution)
140 |             }
141 |             cache.add(cacheKey)
                        ^
RangeError: Out of memory
      at <anonymous> (/Users/g/Documents/programming/pokemon/phonetic_pangram/main.ts:141:19)
      at forEach (1:11)
      at <anonymous> (/Users/g/Documents/programming/pokemon/phonetic_pangram/main.ts:133:17)
      at forEach (1:11)
      at main (/Users/g/Documents/programming/pokemon/phonetic_pangram/main.ts:132:22)
      at /Users/g/Documents/programming/pokemon/phonetic_pangram/main.ts:153:1
      at loadAndEvaluateModule (2:1)

Bun v1.3.3

It makes sense that this program would run out of memory because the cache is adding new paths that have been visited constantly until the program finishes. In the past, this was a small enough problem space to avoid memory issues, but now the problem space had simply ballooned too much for the cache to handle. I looked into how I could make the size of what I was storing smaller. For one, I was storing the cache key as a set of strings that contained all the letters of the pokemon being represented in the path. By replacing a given pokemon with a single character, I was able to shorten this from an average of 7.6 characters per pokemon name to 1, which reduced the cache size by a factor of ~7x. This did not solve my out of memory issue.

Googling around, I learned that Typescript has a hard-limit on the number of members in a set or a map. It turns out that this limit is far below the number of possible solutions to explore, even with the reduced dataset size. Similar to one of the suggestions on stackoverflow, I implemented a BigSet class that just created a new set every time the old one was about to be full. This allowed the program to run without hitting javascript memory limits. But it meant that it quickly used up 13GB of RAM on my computer, even when no other programs were running.

Next, I tried seeing if any of the pokemon I was considering had phonemes that were a subset of any other pokemon pronunciations. For example Kadabra clearly contains all the phonemes that Abra does. It’s reasonable to skip Abra if the goal is just to find the existence of any phonetic pangram, since any one that would use Abra could instead use Kadabra. Continuing this pattern reduced the number of pokemon from 1025 down to 789, which reduced the problem space by a factor of about 13x. This also did not solve my out of memory issue.2

To try to limit the remaining unknowns about the full pokemon dataset, I separately tried looking up pangrams for 1, 2, …, 7, and 8 pokemon. I knew from size-10 and size-11 ones that even a single answer could come in much faster than my computer hitting its memory limits. I found that I was successfully able to exhaust the problem space for all 1-to-8-sized phonetic pangrams. This left just 9 and its memory issues as the only remaining hurdle.

It was clear I needed to try something else. My friends suggested a bloom filter, since those are really good at telling if a given thing (list of pokemon) is either “definitely not” or “maybe is” in a given collect. For a problem like this that has a lot of “wrong answers” relative to the number of “correct answers,” it seemed like a well-tuned bloom filter could work great. That said, I had plans for New Years Eve, so I uploaded what I had to codeberg and let my friends try to nerdsnipe anybody else into solving it a different way.

The Same Sort of Algorithm, but in Rust

Micolous was able to make a number of algorithmic optimizations to what I had contributed so far:

With these and a little fine-tuning for data-labelling issues from the pokemonlp wiki, it was finally possible to find the first valid 9-pokemon phonetic pangram for General American English:

Slither Wing
Heatmor
Typhlosion
Noibat
Vulpix
Growlithe
Poochyena
Shedinja
Illumise

As expected, it had Slither Wing. Unlike the previous post, Typhlosion took the place of Persian, undoubtedly because of how many more phonemes it contains (8 total versus 5). I was excited to see this news and have a new, clearer goal to work towards. Surely implementing all of the same optimizations in my own code would allow me to get similar results.

Hoisted by my Own Petard

I spent the better part of New Year’s Day rewriting the set logic I used for determining which phonemes a given solution had so far to instead use bitmasking like Micolous’s. It took some time, but I was happy once it was working. I had the thought that I could stop writing code on my laptop and instead practice with my new split keyboard3 on my desktop by pushing what I had to codeberg again and then pulling it down from the cloud.4

Upon pulling the latest from main and getting the script set up to run, I ran my version on the 9-gram, and found that I got an answer too! This was exhilarating compared to my machine turning on its fans and maxing out RAM for hours with no results. But of course, this had to be because of the optimizations I had spent all day implementing, right?

I tried rewinding the code to what I had days prior when I had been trying to overcome the technical hurdles on my own. That also ran flawlessly on my desktop computer. It turns out that having similar but not exactly the same specs across a laptop and a desktop can lead to wildly different experiences when it comes to problems like this one. I’m embarrassed that I didn’t try this sooner.

Conclusion

I have yet to get every 9-pokeon phonetic pangram across all generations, because I did eventually run into memory-hog issues and didn’t want to keep working on optimizations for a problem with so many solutions.

Below are the first 205 that my algorithm found:

Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Basculegion
Shaymin
Charizard
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Exeggcute
Shaymin
Jirachi
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Chi-Yu
Aegislash
Blaziken
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Chi-Yu
Aegislash
Rayquaza
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Chi-Yu
Shedinja
Blaziken
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Chi-Yu
Shedinja
Rayquaza
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Poochyena
Aegislash
Blaziken
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Poochyena
Aegislash
Rayquaza
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Poochyena
Shedinja
Blaziken
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Poochyena
Shedinja
Rayquaza
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Charmeleon
Aegislash
Blaziken
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Charmeleon
Aegislash
Rayquaza
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Charmeleon
Shedinja
Blaziken
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Houndoom
Charmeleon
Shedinja
Rayquaza
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Gouging Fire
Exeggcute
Hawlucha
Shaymin
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Gouging Fire
Exeggcute
Honchkrow
Shaymin
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Gouging Fire
Exeggcute
Hitmonchan
Shaymin
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Gouging Fire
Exeggcute
Shaymin
Hitmonchan
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Gouging Fire
Exeggcute
Shaymin
Honchkrow
Slither Wing
Typhlosion
Noibat
Dragapult
Venomoth
Gouging Fire
Exeggcute
Shaymin
Hawlucha

Obviously, as mentioned before, every answer necessarily had to have Slither Wing. Additionally, every answer my program found contained Typhlosion and Noibat. While these 20 above all included Dragapult, there were eventually others like these following two that broke that pattern:

Slither Wing
Typhlosion
Noibat
Clobbopus
Meowth
Hariyama
Shedinja
Ninetales
Galvantula
Slither Wing
Typhlosion
Noibat
Rookidee
Venomoth
Gouging Fire
Poochyena
Iron Hands
Shaymin

Now that every pokemon generation has been included, now that the minimum-length phonetic pangram for General American English has been discovered, and now that we know several of the minimum-length one in particular, it seems like this problem is ready to be put away for a little while. Maybe when one of those things changes in the future, I’ll unearth this problem again.

After all, when it comes to the world of pokemon pronunciation set-covering optimization problems:

I want to be the very best.

Footnotes

  1. Any of the sets from gen 1 listed at the end of the previous post, plus Slither Wing, for example.

  2. However, I did learn that the phonemes in Arceus are a subset of the phonemes contained within Cofagrigous, which was surprising to me!

  3. A Moonlander that my job paid for, which I have yet to bring into the office because I’m still getting used to the layout.

  4. Decades ago, it used to be the case that transferring files between computers was most quickly done over USBs. These days, that feels like so much effort compared to pushing to a git repo, at least for small code repos like this that are already being stored in the cloud.

  5. By the time I stopped the program, I had found 933 9-pokemon pangrams. While this technically only represents a lower-limit, it seemed good enough to stop searching/optimizing for now.