Procedural loot. 10 bases x 6 rarities x 12 affinities.
Level x Rarity x Affinity = Item. Deterministic. Seedable. Same seed = same item. Drop tables for any game genre.
The lattice is a Python dict. Lookup is a hash table operation. Input keys, output values. That's the entire pattern.
Unity: Call from C# via the embedded Python interpreter, or export the lattice to JSON and load it with JsonUtility.
Unreal: Use the Python plugin, or convert the Python dict to a TMap in C++.
Godot: GDScript can import Python directly, or use JSON.parse_string on the exported lattice.
Web/WASM: Pyodide runs the Python file directly in the browser. This demo page demonstrates that approach.
Add new entries to the lattice dictionary. The lookup function is generic: it takes any key and returns the corresponding value, or a default. The more entries you add, the more coverage you get. Performance stays O(1) regardless of size.
Every game logic problem that's hard-coded with if/else chains is actually a lookup table in disguise. (state, event) -> action is the universal pattern. The lattice just makes that pattern explicit and O(1).
#!/usr/bin/env python3
"""
LootForge: Procedural loot generation.
Level x Rarity x Affinity = Item. Deterministic. Seedable. O(1).
No dependencies. Pure Python.
"""
import random
import time
# === THE LATTICE: loot tables ===
RARITY_TIERS = {
"common": {"weight": 50, "color": "\033[90m", "stat_mult": 1.0},
"uncommon": {"weight": 25, "color": "\033[92m", "stat_mult": 1.5},
"rare": {"weight": 15, "color": "\033[96m", "stat_mult": 2.5},
"epic": {"weight": 7, "color": "\033[95m", "stat_mult": 4.0},
"legendary": {"weight": 2, "color": "\033[93m", "stat_mult": 7.0},
"mythic": {"weight": 1, "color": "\033[91m", "stat_mult": 12.0}
}
ITEM_BASES = {
"sword": {"base_dmg": 10, "base_spd": 5, "affinity": ["fire", "ice", "lightning", "holy", "dark"]},
"axe": {"base_dmg": 15, "base_spd": 2, "affinity": ["earth", "fire", "blood"]},
"bow": {"base_dmg": 8, "base_spd": 8, "affinity": ["wind", "ice", "poison"]},
"staff": {"base_dmg": 12, "base_spd": 4, "affinity": ["arcane", "fire", "nature", "holy", "dark"]},
"dagger": {"base_dmg": 6, "base_spd": 10,"affinity": ["poison", "shadow", "blood"]},
"mace": {"base_dmg": 14, "base_spd": 3, "affinity": ["holy", "earth", "lightning"]},
"spear": {"base_dmg": 11, "base_spd": 5, "affinity": ["wind", "earth", "ice"]},
"hammer": {"base_dmg": 18, "base_spd": 1, "affinity": ["earth", "fire", "lightning"]},
"scythe": {"base_dmg": 13, "base_spd": 4, "affinity": ["dark", "blood", "shadow"]},
"wand": {"base_dmg": 5, "base_spd": 12,"affinity": ["arcane", "nature", "ice"]}
}
PREFIXES = {
"fire": {"name": "Flame", "stat": "dmg", "mult": 1.3, "desc": "burns foes"},
"ice": {"name": "Frost", "stat": "spd", "mult": 1.2, "desc": "freezes foes"},
"lightning":{"name": "Thunder", "stat": "spd", "mult": 1.4, "desc": "shocks foes"},
"holy": {"name": "Divine", "stat": "dmg", "mult": 1.2, "desc": "blesses wielder"},
"dark": {"name": "Shadow", "stat": "dmg", "mult": 1.3, "desc": "curses foes"},
"earth": {"name": "Stone", "stat": "dmg", "mult": 1.4, "desc": "crushes armor"},
"wind": {"name": "Gale", "stat": "spd", "mult": 1.3, "desc": "swift strikes"},
"poison": {"name": "Venom", "stat": "dmg", "mult": 1.1, "desc": "poisons foes"},
"blood": {"name": "Bloodletting","stat":"dmg", "mult": 1.5, "desc": "drains life"},
"arcane": {"name": "Arcane", "stat": "dmg", "mult": 1.2, "desc": "mana flows"},
"nature": {"name": "Verdant", "stat": "spd", "mult": 1.1, "desc": "nature aids"},
"shadow": {"name": "Umbral", "stat": "spd", "mult": 1.2, "desc": "strikes from shadow"}
}
AFFINITY_PREFIX_LOOKUP = {}
for base, info in ITEM_BASES.items():
for aff in info["affinity"]:
AFFINITY_PREFIX_LOOKUP[(base, aff)] = aff
def roll_rarity(rng: random.Random) -> str:
"""O(1) rarity roll weighted by tier."""
tiers = list(RARITY_TIERS.keys())
weights = [RARITY_TIERS[t]["weight"] for t in tiers]
return rng.choices(tiers, weights=weights, k=1)[0]
def roll_base(rng: random.Random) -> str:
"""O(1) base weapon roll."""
return rng.choice(list(ITEM_BASES.keys()))
def roll_affinity(rng: random.Random, base: str) -> str:
"""O(1) affinity roll for the base."""
affinities = ITEM_BASES[base]["affinity"]
return rng.choice(affinities)
def generate_item(level: int, seed: int = None) -> dict:
"""O(1) item generation. Deterministic with seed."""
rng = random.Random(seed) if seed is not None else random.Random()
base = roll_base(rng)
rarity = roll_rarity(rng)
affinity = roll_affinity(rng, base)
base_stats = ITEM_BASES[base]
rarity_mult = RARITY_TIERS[rarity]["stat_mult"]
level_mult = 1.0 + (level - 1) * 0.1
prefix = PREFIXES[affinity]
if prefix["stat"] == "dmg":
damage = int(base_stats["base_dmg"] * rarity_mult * level_mult * prefix["mult"])
speed = base_stats["base_spd"]
else:
damage = int(base_stats["base_dmg"] * rarity_mult * level_mult)
speed = int(base_stats["base_spd"] * rarity_mult * level_mult * prefix["mult"])
return {
"name": f"{prefix['name']} {base.title()}",
"rarity": rarity,
"affinity": affinity,
"level": level,
"damage": damage,
"speed": speed,
"effect": prefix["desc"],
"seed": seed
}
# === DEMO ===
def demo():
print("=" * 50)
print(" LootForge: Procedural loot, O(1) generation")
print("=" * 50)
print()
print(" Dropping 10 items at level 15...")
print()
for i in range(10):
start = time.perf_counter_ns()
item = generate_item(level=15, seed=42+i)
elapsed = time.perf_counter_ns() - start
rarity_color = RARITY_TIERS[item["rarity"]]["color"]
reset = "\033[0m"
print(f" [{item['seed']}] {rarity_color}{item['rarity'].upper():10s}{reset} {item['name']:25s} "
f"DMG:{item['damage']:4d} SPD:{item['speed']:3d} [{elapsed}ns]")
print()
print("=" * 50)
print(" Same seed = same item. Deterministic. O(1).")
print("=" * 50)
if __name__ == "__main__":
demo()