Castle Anthrax: Dungeon Generation Techniques by James King

D21717ea76044d31115c573d368e6ff4?s=47 PyCon 2014
April 11, 2014
330

Castle Anthrax: Dungeon Generation Techniques by James King

D21717ea76044d31115c573d368e6ff4?s=128

PyCon 2014

April 11, 2014
Tweet

Transcript

  1. James King @agentultra james@agentultra.com

  2. Dungeon Generation Techniques

  3. http://goo.gl/INm3W9

  4. [[0 for x in range(5)] for y in range(5)]

  5. [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0],

    [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
  6. [0 for _ in range(5 * 5)]

  7. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  8. Row Major Order offset = (row * num_cols) + column

  9. g = Grid(5, 5) g[1, 2] = 3 g[1, 2]

    # 3
  10. Mazes

  11. None
  12. def generate_maze(): grid = Grid(MAZE_ROWS, MAZE_COLS, value=default_cell) stack = []

    current_cell = random.choice(grid.coordinates) grid[current_cell]['visited'] = True stack.append(current_cell) ! while stack: ns = unvisited_neighbours(grid, current_cell) if ns: n = random.choice(ns) remove_wall_between(current_cell, n, grid) stack.append(current_cell) current_cell = n grid[current_cell]['visited'] = True else: current_cell = stack.pop() ! return grid
  13. None
  14. def generate_maze(): grid = Grid(MAZE_ROWS, MAZE_COLS, default_cell) frontier = []

    start_cell = random.choice(grid.coordinates) grid[start_cell]['set'] = INTERIOR ns = neighbours(grid, start_cell, is_unvisited) for n in ns: grid[n]['set'] = FRONTIER frontier.extend(ns) ! while frontier: frontier_cell = frontier.pop(random.randrange(len(frontier))) interior_cell = random.choice( neighbours(grid, frontier_cell, is_interior)) remove_wall_between(interior_cell, frontier_cell, grid) grid[frontier_cell]['set'] = INTERIOR new_frontier_cells = neighbours(grid, frontier_cell, is_unvisited) for nfc in new_frontier_cells: grid[nfc]['set'] = FRONTIER frontier.append(nfc) ! return grid
  15. http://goo.gl/teGL8D

  16. http://goo.gl/vZ0EH1

  17. None
  18. None
  19. None
  20. None
  21. None
  22. None
  23. None
  24. • Poisson Disks • Cellular Automata • Perlin Noise

  25. None
  26. class Variable(object): ! def __init__(self, values): self.values = set(values) !

    ...
  27. class Variable(object): ! ... ! def narrow(self, values): new_values =

    self.values & values if not new_values: return False ! if self.values != new_values: if self._last_save_frame != self._current_save_frame: self._save(new_values) ! for constraint in self.constraints: constraint.propagate(self)
  28. import abc ! ! class Constraint(object): __metaclass__ = abc.ABCMeta !

    @abc.abstractproperty def variables(self): """ The variables involved in the constraint.""" ! @abc.abstractmethod def propagate(self, variable): """ Propagate the values in `variable` to each of the variables involved in this constraint. """
  29. # from a hypothetical InequalityConstraint … def propagate(self, variable): if

    variable.is_unique: for v in self.variables: v.narrow(v.values - variable.values)
  30. def solve(): if all(v.is_unique for v in variables): return (v.values[0]

    for v in variables) ! # some undo-stack management code here... ! variable = random.choice(v for v in variables if v.values > 1) for value in variable.values: if not variable.narrow(value) return ! if not any(v.is_empty for v in variables): if not solve(): return ! # more undo stack management
  31. Optimize! • Represent sets as bitmasks • Undo-stack • Use

    as few variables as possible stay in the discrete/finite domain as much as possible
  32. Thanks!

  33. • Rogue Basin http://goo.gl/UTlwFU • How to Build a Contraint

    Propagator in a Weekend http://goo.gl/sdrbkJ • Poisson Disk Sampling http://goo.gl/71OzY • Artificial Intelligence: A Modern Approach http://goo.gl/CCCel8 • The Art of Computer Programming http://goo.gl/EUhZ8M
  34. • Doryen Library http://goo.gl/71EpZx • Horton http://goo.gl/xpLTFB • Pygame http://goo.gl/1hv6DK

    • PyAngband http://goo.gl/mr5MMD