import random
import json
from textwrap import dedent
# =========================
# Core data structures
# =========================
class Player:
def __init__(self, name="Delver"):
[Link] = name
[Link] = 100
self.max_hp = 100
[Link] = 0
[Link] = 1
[Link] = 50
[Link] = {"Potion": 2}
[Link] = {"Weapon": None, "Armor": None}
[Link] = []
[Link] = (0, 0)
[Link] = 0
def is_alive(self):
return [Link] > 0
def heal(self, amount):
[Link] = min(self.max_hp, [Link] + amount)
def take_damage(self, amount):
[Link] = max(0, [Link] - amount)
def add_item(self, item, qty=1):
[Link][item] = [Link](item, 0) + qty
def remove_item(self, item, qty=1):
if [Link](item, 0) >= qty:
[Link][item] -= qty
if [Link][item] == 0:
del [Link][item]
return True
return False
def gain_xp(self, amount):
[Link] += amount
while [Link] >= [Link] * 100:
[Link] -= [Link] * 100
[Link] += 1
self.max_hp += 10
[Link] = self.max_hp
print(f"Level up! You are now level {[Link]} with {self.max_hp}
HP.")
def damage_output(self):
base = 6 + [Link]
weapon_bonus = 0
w = [Link]["Weapon"]
if w == "Short Sword":
weapon_bonus = 4
elif w == "War Axe":
weapon_bonus = 8
elif w == "Arcane Wand":
weapon_bonus = 5
focus = 3 if "Battle Focus" in [Link] else 0
return base + weapon_bonus + focus
def defense(self):
base = 2 + [Link] // 2
armor_bonus = 0
a = [Link]["Armor"]
if a == "Leather Armor":
armor_bonus = 2
elif a == "Iron Armor":
armor_bonus = 5
elif a == "Runed Plate":
armor_bonus = 9
return base + armor_bonus
class Enemy:
def __init__(self, name, hp, damage, xp_reward, gold=0, loot=None):
[Link] = name
[Link] = hp
[Link] = damage
self.xp_reward = xp_reward
[Link] = gold
[Link] = loot or {}
def is_alive(self):
return [Link] > 0
class Merchant:
def __init__(self, stock):
[Link] = stock # item -> price
class Tile:
def __init__(self, kind="floor", revealed=False, enemy=None, merchant=None,
item=None, locked=False):
[Link] = kind # floor, wall, exit, shrine, vault
[Link] = revealed
[Link] = enemy
[Link] = merchant
[Link] = item
[Link] = locked
# =========================
# Dungeon generation
# =========================
class Dungeon:
def __init__(self, width=10, height=10, seed=None):
[Link] = width
[Link] = height
[Link] = [[Tile(kind="wall") for _ in range(width)] for _ in
range(height)]
[Link] = seed or [Link](1, 10_000)
[Link]([Link])
self._generate()
def _generate(self):
# Carve a simple maze using randomized DFS
stack = [(0, 0)]
[Link][0][0].kind = "floor"
visited = set([(0, 0)])
def neighbors(x, y):
dirs = [(1,0),(-1,0),(0,1),(0,-1)]
[Link](dirs)
for dx, dy in dirs:
nx, ny = x + dx*2, y + dy*2
if 0 <= nx < [Link] and 0 <= ny < [Link] and (nx, ny) not
in visited:
yield (dx, dy, nx, ny)
while stack:
x, y = stack[-1]
choices = list(neighbors(x, y))
if choices:
dx, dy, nx, ny = [Link](choices)
[Link][y + dy][x + dx].kind = "floor"
[Link][ny][nx].kind = "floor"
[Link]((nx, ny))
[Link]((nx, ny))
else:
[Link]()
# Sprinkle special tiles, merchants, enemies, items
floors = [(x, y) for y in range([Link]) for x in range([Link]) if
[Link][y][x].kind == "floor"]
# Exit
ex_x, ex_y = [Link](floors)
[Link][ex_y][ex_x].kind = "exit"
# Shrine (free heal)
sh_x, sh_y = [Link](floors)
[Link][sh_y][sh_x].kind = "shrine"
# Vault (locked)
v_x, v_y = [Link](floors)
[Link][v_y][v_x].kind = "vault"
[Link][v_y][v_x].locked = True
# Merchant
m_x, m_y = [Link](floors)
[Link][m_y][m_x].merchant = Merchant({
"Potion": 12,
"Elixir": 40,
"Short Sword": 30,
"War Axe": 65,
"Leather Armor": 25,
"Iron Armor": 55,
"Focus Tonic": 28
})
# Place random enemies and items
enemy_names = ["Goblin", "Skeleton", "Cultist", "Orc Brute", "Shade"]
for _ in range(int(len(floors)*0.25)):
x, y = [Link](floors)
if [Link][y][x].enemy or [Link][y][x].merchant or [Link][y]
[x].kind in ("exit","shrine","vault"):
continue
hp = [Link](25, 60)
dmg = [Link](6, 12)
xp = [Link](25, 60)
gold = [Link](5, 20)
[Link][y][x].enemy = Enemy([Link](enemy_names), hp, dmg, xp,
gold, loot={"Key": 1} if [Link]() < 0.15 else {})
for _ in range(int(len(floors)*0.15)):
x, y = [Link](floors)
if [Link][y][x].item or [Link][y][x].enemy or [Link][y]
[x].kind in ("exit","vault","shrine"):
continue
[Link][y][x].item = [Link](["Potion","Elixir","Leather
Armor","Short Sword","Focus Tonic","Gold Pouch"])
def in_bounds(self, x, y):
return 0 <= x < [Link] and 0 <= y < [Link]
# =========================
# Game mechanics
# =========================
class Game:
def __init__(self):
[Link] = Player()
[Link] = Dungeon(width=13, height=11)
[Link] = 0
[Link] = False
# Find a starting floor tile
for y in range([Link]):
for x in range([Link]):
if [Link][y][x].kind == "floor":
[Link] = (x, y)
return
def save(self, filename="crawler_save.json"):
data = {
"player": {
"name": [Link],
"hp": [Link],
"max_hp": [Link].max_hp,
"xp": [Link],
"level": [Link],
"gold": [Link],
"inventory": [Link],
"equipped": [Link],
"effects": [Link],
"position": [Link],
"keys": [Link]
},
"turn": [Link],
"win": [Link],
"dungeon": {
"width": [Link],
"height": [Link],
"seed": [Link],
"grid": [[{
"kind": [Link],
"revealed": [Link],
"locked": [Link],
"enemy": None if not [Link] else {
"name": [Link],
"hp": [Link],
"damage": [Link],
"xp_reward": [Link].xp_reward,
"gold": [Link],
"loot": [Link]
},
"merchant": None if not [Link] else {"stock":
[Link]},
"item": [Link]
} for t in row] for row in [Link]]
}
}
with open(filename, "w", encoding="utf-8") as f:
[Link](data, f, indent=2)
print("Game saved.")
def load(self, filename="crawler_save.json"):
try:
with open(filename, "r", encoding="utf-8") as f:
data = [Link](f)
except Exception as e:
print(f"Failed to load: {e}")
return
p = data["player"]
[Link] = p["name"]
[Link] = p["hp"]
[Link].max_hp = p["max_hp"]
[Link] = p["xp"]
[Link] = p["level"]
[Link] = p["gold"]
[Link] = p["inventory"]
[Link] = p["equipped"]
[Link] = p["effects"]
[Link] = tuple(p["position"])
[Link] = p["keys"]
[Link] = data["turn"]
[Link] = data["win"]
# Rebuild dungeon
d = data["dungeon"]
[Link] = Dungeon(width=d["width"], height=d["height"],
seed=d["seed"])
for y in range([Link]):
for x in range([Link]):
meta = d["grid"][y][x]
tile = [Link][y][x]
[Link] = meta["kind"]
[Link] = meta["revealed"]
[Link] = meta["locked"]
[Link] = meta["item"]
[Link] = None
if meta["enemy"]:
em = meta["enemy"]
[Link] = Enemy(em["name"], em["hp"], em["damage"],
em["xp_reward"], em["gold"], em["loot"])
[Link] = None
if meta["merchant"]:
[Link] = Merchant(meta["merchant"]["stock"])
print("Game loaded.")
def draw(self):
px, py = [Link]
# Reveal current tile
[Link][py][px].revealed = True
print(f"\nTurn {[Link]} | {[Link]} HP
{[Link]}/{[Link].max_hp} | Lvl {[Link]} | Gold
{[Link]} | Keys {[Link]}")
for y in range([Link]):
row = ""
for x in range([Link]):
t = [Link][y][x]
if (x, y) == (px, py):
row += "@"
elif not [Link]:
row += "?"
elif [Link] == "wall":
row += "#"
elif [Link] == "floor":
row += "."
elif [Link] == "exit":
row += "E"
elif [Link] == "shrine":
row += "S"
elif [Link] == "vault":
row += "V"
else:
row += "."
print(row)
def look(self):
x, y = [Link]
t = [Link][y][x]
[Link] = True
print("\nYou look around:")
desc = {
"wall": "A solid wall blocks your way.",
"floor": "A dusty stone floor stretches onward.",
"exit": "A staircase leading out of the dungeon!",
"shrine": "A quiet shrine glows softly. You feel peace here.",
"vault": "A heavy vault door with intricate runes. It appears locked."
}
print([Link]([Link], ""))
if [Link]:
print(f"You see an item on the ground: {[Link]}")
if [Link] and [Link].is_alive():
print(f"An enemy lurks here: {[Link]} (HP {[Link]})")
if [Link]:
print("A robed merchant hums a tune, ready to trade.")
if [Link]:
print("The mechanism is locked. Perhaps a key would help.")
def move(self, direction):
dx, dy = {"north": (0, -1), "south": (0, 1), "west": (-1, 0), "east": (1,
0)}.get(direction, (0, 0))
x, y = [Link]
nx, ny = x + dx, y + dy
if not [Link].in_bounds(nx, ny):
print("You bump into the edge of the world.")
return
if [Link][ny][nx].kind == "wall":
print("A wall bars your path.")
return
[Link] = (nx, ny)
[Link] += 1
self.enter_tile()
def enter_tile(self):
x, y = [Link]
t = [Link][y][x]
[Link] = True
if [Link] == "exit":
[Link] = True
print("You found the exit. Climbing the stairs, you breathe fresh air.
Victory!")
return
if [Link] == "shrine":
heal = min([Link].max_hp - [Link], 50)
[Link](heal)
print(f"At the shrine, serenity mends your wounds. Restored {heal}
HP.")
if [Link] == "vault":
if [Link]:
print("The vault is locked. You need a key to open it.")
else:
print("The vault yawns open. A trove of gold lies within!")
reward = [Link](100, 200)
[Link] += reward
print(f"You scoop up {reward} gold.")
[Link] = "floor"
if [Link]:
print(f"You spot something: {[Link]}. Use 'take {[Link]}' to pick it
up.")
if [Link] and [Link].is_alive():
print(f"A {[Link]} steps from the shadows!")
def take(self, item):
x, y = [Link]
t = [Link][y][x]
if [Link] == item:
[Link] = None
if item == "Gold Pouch":
g = [Link](20, 50)
[Link] += g
print(f"You found a pouch with {g} gold.")
elif item == "Elixir":
[Link].add_item("Elixir")
print("You pick up an Elixir.")
elif item in ("Potion","Leather Armor","Short Sword","Focus Tonic"):
[Link].add_item(item)
print(f"You pick up {item}.")
else:
print(f"You take {item}.")
else:
print("No such item here.")
def use_item(self, item):
if item not in [Link]:
print("You don't have that.")
return
if item == "Potion":
if [Link].remove_item("Potion"):
[Link](30)
print("You drink a Potion and restore 30 HP.")
elif item == "Elixir":
if [Link].remove_item("Elixir"):
[Link] = [Link].max_hp
print("Elixir restores you fully.")
elif item == "Focus Tonic":
if [Link].remove_item("Focus Tonic"):
[Link]("Battle Focus")
print("Your mind sharpens: Battle Focus for the next fight.")
else:
print("You can't use that right now.")
def equip_item(self, item):
if item in ("Short Sword","War Axe","Arcane Wand"):
if item in [Link]:
[Link]["Weapon"] = item
print(f"You equip {item}.")
else:
print("You don't own that.")
elif item in ("Leather Armor","Iron Armor","Runed Plate"):
if item in [Link]:
bonus = {"Leather Armor": 0, "Iron Armor": 15, "Runed Plate": 30}
[item] if item in ("Iron Armor","Runed Plate") else 0
[Link].max_hp = 100 + bonus
[Link] = min([Link], [Link].max_hp)
[Link]["Armor"] = item
print(f"You don {item}. Max HP may change.")
else:
print("You don't own that.")
else:
print("Not equippable.")
def talk(self):
x, y = [Link]
t = [Link][y][x]
if not [Link]:
print("No one to trade with here.")
return
print("Merchant offers:")
for item, price in [Link]():
print(f"- {item} for {price} gold")
def buy(self, item):
x, y = [Link]
t = [Link][y][x]
if not [Link]:
print("No merchant here.")
return
if item not in [Link]:
print("They don't sell that.")
return
price = [Link][item]
if [Link] < price:
print("Not enough gold.")
return
[Link] -= price
[Link].add_item(item)
print(f"Purchased {item} for {price} gold.")
def sell(self, item):
x, y = [Link]
t = [Link][y][x]
if not [Link]:
print("No merchant here.")
return
if item not in [Link]:
print("You don't own that.")
return
base_price = [Link](item, 10)
sell_price = max(1, base_price // 2)
[Link].remove_item(item)
[Link] += sell_price
print(f"Sold {item} for {sell_price} gold.")
def unlock(self):
x, y = [Link]
t = [Link][y][x]
if [Link] != "vault":
print("Nothing to unlock here.")
return
if not [Link]:
print("Already unlocked.")
return
if [Link] > 0:
[Link] = False
[Link] -= 1
print("You turn the key. The vault unlocks.")
else:
print("You need a key.")
def fight(self):
x, y = [Link]
t = [Link][y][x]
if not [Link] or not [Link].is_alive():
print("No enemy to fight here.")
return
enemy = [Link]
print(f"You engage the {[Link]}!")
focus_used = ("Battle Focus" in [Link])
while [Link].is_alive() and enemy.is_alive():
dmg = max(0, [Link].damage_output() - [Link](0, 2))
[Link] -= dmg
print(f"You strike for {dmg}. Enemy HP: {max(0, [Link])}")
if not enemy.is_alive():
break
incoming = max(0, [Link] - [Link]() +
[Link](0, 2))
[Link].take_damage(incoming)
print(f"{[Link]} hits for {incoming}. Your HP: {[Link]}")
if not [Link].is_alive():
break
if focus_used and "Battle Focus" in [Link]:
[Link]("Battle Focus")
if enemy.is_alive():
print("You were defeated...")
return
print(f"You defeated the {[Link]}!")
[Link].gain_xp(enemy.xp_reward)
[Link] += [Link]
if [Link]:
print(f"You gain {[Link]} gold.")
for k, v in [Link]():
if k == "Key":
[Link] += v
print(f"You obtain a key (x{v}).")
else:
[Link].add_item(k, v)
print(f"You obtain: {k} x{v}")
[Link] = None
def help(self):
print(dedent("""
Commands:
- map: draw the dungeon map
- look: describe current tile
- go <north|south|east|west>: move
- fight: battle if an enemy is present
- take <item>: pick up an item
- use <item>: Potion, Elixir, Focus Tonic
- equip <item>: weapons/armor
- talk: see merchant stock if present
- buy <item>, sell <item>: trade
- unlock: unlock the vault using a key
- stats: show HP, level, gear
- inv: show inventory and gold
- save, load: persist your progress
- quit: exit the game
"""))
def stats(self):
print(f"{[Link]} | HP {[Link]}/{[Link].max_hp} | Lvl
{[Link]} | XP {[Link]} | Gold {[Link]}")
w = [Link]["Weapon"] or "None"
a = [Link]["Armor"] or "None"
print(f"Weapon: {w} | Armor: {a} | Effects: {', '.join([Link])
if [Link] else 'None'}")
def inventory(self):
print("Inventory:")
for item, qty in [Link]():
print(f"- {item} x{qty}")
print(f"Keys: {[Link]} | Gold: {[Link]}")
def run(self):
print(dedent(f"""
Welcome, {[Link]}, to the Procedural Dungeon!
Escape via the 'E' exit, or unlock treasures in vaults.
Beware monsters, trade with merchants, and manage your resources.
Type 'help' for commands.
"""))
[Link]()
while True:
if [Link]:
print("Thanks for playing!")
break
if not [Link].is_alive():
print("You fall. The dungeon claims another soul.")
break
cmd = input("\n> ").strip()
if not cmd:
continue
parts = [Link]()
action = parts[0].lower()
arg = " ".join(parts[1:]) if len(parts) > 1 else ""
if action == "help":
[Link]()
elif action == "map":
[Link]()
elif action == "look":
[Link]()
elif action == "go":
[Link](arg)
elif action == "fight":
[Link]()
elif action == "take":
[Link](arg)
elif action == "use":
self.use_item(arg)
elif action == "equip":
self.equip_item(arg)
elif action == "talk":
[Link]()
elif action == "buy":
[Link](arg)
elif action == "sell":
[Link](arg)
elif action == "unlock":
[Link]()
elif action == "stats":
[Link]()
elif action == "inv":
[Link]()
elif action == "save":
[Link]()
elif action == "load":
[Link]()
elif action == "quit":
print("Farewell, delver.")
break
else:
print("Unknown command. Type 'help' for guidance.")
if __name__ == "__main__":
name = input("Enter your delver's name (or press Enter for 'Delver'):
").strip() or "Delver"
g = Game()
[Link] = name
[Link]()