Minecraft Enchantment Calculator
Optimal anvil order calculator (Java 1.20+). Two optimization modes, full vanilla rules, sub-20ms plans.
Tech: Python, JavaScript, HTML, TailwindCSS
I built this to answer a deceptively tricky question Minecraft players hit all the time: “What’s the cheapest way to put *this exact set* of enchantments on *this* item?” The app models Mojang’s anvil math (merge costs, level caps, incompatibilities, prior-work penalty, 39-level hard cap) and searches the space of possible book+item merge orders to find an optimal plan. No front-end frameworks—just one HTML file with vanilla JS and a tiny Flask backend. Typical plans compute in ≲20 ms thanks to heavy memoization.
There are two optimization modes: minimize **total levels** (XP you actually pay across the whole sequence) or minimize final **prior-work penalty** (useful when you care about keeping the item “cheap” for the next upgrade). In both modes, ties fall back to the other metric, giving stable, sensible plans.
# Quickstart
git clone https://github.com/BrianKYildirim/minecraft-enchantment-order.git
cd minecraft-enchantment-order
python -m venv .venv
# Windows
.venv\Scripts\activate.bat
# macOS/Linux
# source .venv/bin/activate
pip install -r requirements.txt
python run.py
# Open http://127.0.0.1:5000All 1.20 items and enchantments are encoded with weights, level caps, and incompatibilities. The UI live-validates: incompatible picks are greyed out, impossible states can’t be selected, and you can enter an existing prior-work penalty (0–39) which is included in the optimization.
Under the hood, the core search is a recursive, memoized bipartition over the set (base + books). For each split, sub-solutions are merged, enforcing anvil rules in a single place (the model). Results are memoized by the multiset of inputs (as an immutable tuple), dramatically pruning identical subproblems.
# calculator.py (excerpt)
@lru_cache(maxsize=None)
def _cheapest_single(work_tuple: Tuple[EnchantedItem, ...]):
if len(work_tuple) == 1:
item = work_tuple[0]
return {item.anvil_uses: ([], 0, 0, item)} # steps, total_levels, total_xp, final
best = {}
for i in range(1, len(work_tuple)):
for left_idx in itertools.combinations(range(len(work_tuple)), i):
right_idx = tuple(sorted(set(range(len(work_tuple))) - set(left_idx)))
lefts = tuple(work_tuple[j] for j in left_idx)
rights = tuple(work_tuple[j] for j in right_idx)
for lw, (lsteps, llv, lxp, litem) in _cheapest_single(lefts).items():
for rw, (rsteps, rlv, rxp, ritem) in _cheapest_single(rights).items():
try:
merged, cost_lv, cost_xp = litem.merge(ritem) # anvil rules & 39 cap
except (InvalidTarget, MergeTooExpensive):
continue
w = merged.anvil_uses
cand = (lsteps + rsteps + [Step(litem, ritem, cost_lv, cost_xp, merged.prior_penalty())],
llv + rlv + cost_lv, lxp + rxp + cost_xp, merged)
if w not in best or best[w][1] > cand[1]: # minimize total_levels
best[w] = cand
return bestModels are immutable. `EnchantedItem.merge(...)` returns a new item plus both cost views (levels & XP), applies level stacking, enforces incompatibilities, and clamps at the 39-level limit. A thin planner (`plan_enchants`) builds missing books from desired targets, runs the search, and picks the best solution per the chosen mode.
# Example usage
from enchant.models import EnchantedItem
from enchant.calculator import plan_enchants
base = EnchantedItem("netherite_sword", enchants={"mending":1}, anvil_uses=2)
desired = {"sharpness":5, "looting":3, "sweeping_edge":3}
plan = plan_enchants(base, desired, mode="levels")
print(plan.total_levels, plan.total_xp, plan.final_prior_work)
for step in plan.steps:
print(f"{step.left} + {step.right} -> +{step.cost_levels}L (PW={step.result_prior})")SEO & distribution: I tuned metadata and internal links so the app could be discovered by queries like “minecraft anvil order calculator.” Over the first three months it reached ~110k impressions at ~5.5 average position, then stabilized. The app is intentionally fast (single HTML, no client deps) which helps both UX and Core Web Vitals.
Why it’s interesting technically: (1) the search explores an exponential space but remains snappy due to memoization and canonicalization; (2) encoding all anvil rules in one pure function keeps correctness tractable; (3) the UI prevents invalid states rather than surfacing errors late; (4) the two optimization modes align with real player goals without complicating the UI.