Episode 8: Overview of the Build Tool
Julien Truffaut
19 November 2025
In the previous episodes, I scraped a third-party API to gather the full list of available gear in Dofus. With that dataset finally in hand, I can start working on the main goal of this project: a tool that searches for the best character builds given user-defined constraints.
What’s a Character Build?
In Dofus, a character’s power comes from several sources:
- Base characteristics: Strength, Agility, Vitality, etc. (allocated with points per level)
- Equipment: Amulet, Belt, Boots, Weapon, etc.
- Pet or Mount
- Six Dofus or trophies
All these bonuses stack together to produce the final character stats you see in the character sheet.
To keep things manageable, my first version of the build optimizer will focus exclusively on the nine main gear slots:
- Amulet
- Belt
- Boots
- Cloak
- Hat
- Ring 1
- Ring 2
- Shield
- Weapon
This is the most complex part of a build, because some items belong to sets—equipping multiple pieces of the same set grants extra set bonuses.
Other sources of characteristics (pet, Dofus, trophies, stat points) are independent and can be tuned afterward to strengthen an already-good gear selection. That’s something players are familiar with, and it’s much simpler algorithmically.
Code Organisation
Before diving into build optimisation, the codebase needs a bit of structure. It’s time to split it into three crates:
- core — the shared library containing the gear model, validation, and JSON serialization
- dofus_db — a CLI that fetches data from the DofusDB API and converts it into the core model
- build — a CLI that performs the actual optimisation
With this setup, dofus_db and build both depend on core, but are otherwise completely independent modules.
Here’s the updated project layout:
Cargo.toml
core/
├── Cargo.toml
└── src/
├── lib.rs
└── …
dofus_db/
├── Cargo.toml
└── src/
├── main.rs
└── …
build/
├── Cargo.toml
└── src/
├── main.rs
└── … The top-level workspace Cargo.toml simply links the three crates:
[workspace]
members = [
"build",
"core",
"dofus_db",
]
resolver = "2" This structure lets each tool evolve independently while sharing the same underlying model.
Plan for the Build CLI
The Build CLI will take user-specified constraints, such as:
Vitality >= 3000Strength >= 800Level <= 198…and then output a handful of builds (if any exist) that satisfy these requirements.
The core challenge is implementing the algorithm that explores all viable gear combinations.
There are many possible algorithms but I like to start with the dumbest possible solution and see how far it gets.
The Naïve Approach: Nine Nested Loops
Since a build consists of exactly one item per slot, the simplest brute-force algorithm is a Cartesian product across all slots:
let constraints = ...
let all_gears = ...
let mut build = Build::empty();
for amulet in all_gears.get(Amulet)
build.set_gear(amulet)
for belt in all_gears.get(Belt)
build.set_gear(belt)
for hat in all_gears.get(Hat)
build.set_gear(hat)
...
if build.satisfy(constraints) {
println(build)
} This is straightforward but … very slow.
Why Brute Force Falls Apart
The total number of builds is:
|Amulet| × |Belt| × |Boots| × … × |Weapon| Some examples:
- 10 items per slot → 10⁹ = 1 billion builds
- 30 items per slot → 30⁹ ≈ 19 trillion builds
This approach is only feasible if we aggressively prune bad choices and order items so that promising builds appear early.
But it’s still a good starting point to reason about the problem.
Next Steps
In the next episode, I’ll focus on the Build data structure—how to represent a partially-filled build and how to update it efficiently.