Prolog Basics Explained with Pokémon
Prolog Basics Explained with Pokémon
January 05, 2026
The project that inspired this post is a little silly—I am about to describe the mechanics of a children’s video game in great detail—but this particular problem is what finally made Prolog click for me, an epiphany I’ve been hunting for ever since reading Bruce Tate’s “Seven Languages in Seven Weeks.”
This exercise has taught me a lot about the kinds of interfaces I’m trying to build in somewhat more practical domains.<br>For certain kinds of relationships, logic programming is by far the most concise and expressive programming system I’ve ever used.
To understand why, let’s talk about Pokémon.
Pokémon basics
Pokémon is a video game series/multimedia franchise/lifestyle brand set in a world where humans live alongside a menagerie of colorful animal characters.
“Pokémon” is both the name of the franchise and the generic term for the animal characters themselves, which all have their own individual species names.<br>There are over a thousand distinct species of Pokémon, from Bulbasaur (#1) to Pecharunt (#1025).
Popular Pokémon include (from left to right):
Pikachu (#25), Archeops<br>(#567)<br>, and Dipplin (#1101).
I rarely include images on this blog and I am very excited that this post warrants them.<br>There are all sorts of Pokémon games now, but the main series has always been about catching and battling them.<br>During a battle, your team of six Pokémon faces off against another team.<br>Each Pokémon is equipped with four moves that it can choose to (usually) do damage to their opponent.<br>You need to reduce the HP (Hit Points) of all your opponent’s Pokémon to zero before they are able to do so to you.
Each Pokémon has unique traits that affects how it battles.<br>They have a set of base stats, a large pool of possible moves, a handful of abilities, and a typing.<br>As you will see in a moment, the immense number of combinations here is the motivation for trying to track this with software.
Scizor is a Bug/Steel type with high Attack and low Speed (via Smogon)
Speed controls which move will go first;<br>Attack and Special Attack affect how much damage they do with Physical and Special moves, respectively;<br>Defense and Special Defense affect how much damage they take.
Typing is especially important.<br>Moves have a type, like Fire or Rock, and Pokémon can have up to two types.<br>A move with a type that is Super Effective against the opposing Pokémon will do double damage; a move that is Not Very Effective will do half damage.
It’s a little more intuitive with examples.<br>The Fire-type move Flamethrower will do 2x to Grass-type Pokémon, because Grass is weak to Fire, but the Water-type move Surf will only do ½ damage to them, because Grass resists Water.
Lunatone is a Rock/Psychic Type. Rock is weak to Water, and Psychic is neutral to it, so Surf will do 2x damage.
Type modifiers can stack.<br>Scizor is a Bug/Steel type, and both Bug and Steel are weak to Fire, so Fire moves will do 4x damage to Scizor.<br>Electric is weak to Water, but Ground is immune, so if you use an Electric type move against Water/Ground Swampert, you’ll do zero damage, since 0×2 is still 0.
Naturally, there is a chart to help you keep track.
Pokémon Type Chart (via Wikimedia)
Those are effectively the mechanics of the Pokémon video games as I understood them when I was 8.<br>Click moves to do damage, try to click moves with good type matchups.<br>These games are for children and, at the surface level, they’re not very hard.
Prolog basics
Before I explain how wonky the Pokémon mechanics can get under the hood, I first need to explain how logic programming works.<br>Pokémon is a great fit for logic programming because Pokémon battles are essentially an extremely intricate rules engine.
Let’s start by creating a file with a bunch of facts.
pokemon(bulbasaur).<br>pokemon(ivysaur).<br>pokemon(venusaur).<br>pokemon(charmander).<br>pokemon(charmeleon).<br>pokemon(charizard).<br>pokemon(squirtle).<br>pokemon(wartortle).<br>pokemon(blastoise).<br>In Prolog, we declare “predicates.”<br>Predicates define relationships: bulbasaur is a pokemon, charmander is a pokemon, and so on.<br>We refer to this predicate as pokemon/1, because the name of the predicate is pokemon and it has one argument.
These facts are loaded into an interactive prompt called the “top-level.”<br>You query the top-level by typing a statement into the prompt;<br>Prolog tries to find all the ways to make that statement true.<br>When there’s more than one possible solution, the top-level displays the first solution and then awaits user input.<br>You can then have it display one more solution, all the solutions, or stop entirely.
In this first example, we type pokemon(squirtle). and hit Enter.<br>The top-level replies true.<br>Squirtle is, in fact, a Pokémon.
?- pokemon(squirtle).<br>true.<br>If you want to follow along at home, check out the repo, which has quick setup instructions.
Not all things are Pokémon.
?- pokemon(alex).<br>false.<br>Let’s add Pokémon types in...