Procedural Level Design
Procedural Level Design
20
it’s the number of hit points a typical player would lose placement (e.g. ܵ ൌ ሼǡǡ ǡሽ
when fighting the monster. Otherwise, it is zero. in the example above; multiple attributes could be used to
The path is then survivable if ݄ሺݒሻ Ͳ for all ݒalong allow rooms to contain multiple items) or room type (e.g.
the path; the level is survivable if every likely path is ܵ ൌ ሼǡ ǡ ǡሽ). Real-valued
survivable, or if at least some path is survivable, depending attributes can be used to represent general numeric
on the designer’s taste. The designer can also control properties of rooms, such as the amount of gold in the
difficulty by applying upper bounds to ݄ሺݒሻ. room. However, we will focus on using them to represent
We will show that this survivability test can be summary information about the other attributes of rooms
efficiently computed using dynamic programming, and and paths, such as expected health or health deltas.
efficiently integrated into a constraint propagation system A constraint is any relation that is required to hold on
to guide item placement. The survivability criterion is the values of attributes. For finite domain attributes, we
tunable, allowing designers to rebalance levels or games will focus on cardinality constraints, which limit the
to perform dynamic difficulty adjustment based on player number of nodes that can be labeled with a specific value
performance; by increasing or decreasing a monster’s (e.g. there must be exactly one boss, there should be 5-10
estimated damage, or by raising the lowering bounds on ݄, monsters), and point constraints (e.g. the last room must
we can make the level easier or harder. be a boss). For real-valued attributes, we will focus on
Health survivability is one example of a path interval constraints, which limit a single node or all nodes
constraint. The same mechanisms can be used to to lie in a certain range (or a single value, if the lower and
implement other path constraints. For example, we can upper bound are the same), and functional constraints,
define ammo survivability in direct analogy: we score where the value of one attribute is constrained to be some
rooms in terms of how they add to or remove from the function of the value of another attribute.
player’s ammo supply, and then test whether the ammo Finally, a scoring ݏǣ ܦ՜ ܴ is a mapping from some
expected ammo supply goes negative. finite domain ܦto a number. We will use scorings to
Lock and key problems (locked doors, special items derive real-valued attributes from finite domain attributes.
required to defeat bosses, etc.) can also be phrased as path Let ܽ be some node attribute, then by abuse of notation we
constraints (one per lock); the key has a score of 2, the lock will use ݏሺܽሻ to denote some real-valued attribute, ݂,
of -1, and the puzzle is solvable if the path function is non- subject to the functional constraint ݂ሺݒሻ ൌ ݏሺܽሺݒሻሻ for all
negative and has a value of 1 at the exit. Similarly, object ݒ. In the example above, the attribute ȟ was a scoring of
placement behind locked doors can be forced by defining the item placed in the room where:
a path function summing the number of locked doors that െ݇ଵ ǡ ݔൌ
have been passed through, and requiring that particular
ȟሺݔሻ ൌ ൝ ݇ଶ ݔൌ
types of objects only be placed in rooms of a given lock
Ͳǡ
depth.
Again, these path constraints can be used to drive object for some appropriate ݇ଵ ǡ ݇ଶ Ͳ chosen by the designer.
placement to guarantee that the desired properties are
satisfied, e.g. that the lock is solvable along some paths, or Path constraints
along all paths, if that is preferable. A path function is some summarization of an attribute
over a path. More formally, let ْ be some (associative,
monotone) operator. We will generally use addition for the
Formal definition operator, but others can be useful too, such as
Let ܩൌ ሺܸǡ ܧሻ be a connected, undirected graph multiplication or the max function, or potentially an
representing the level’s topology. Here ܸ is the set of operator over some other simply-ordered set. A path
rooms, corridors, or other spaces in the level, and ܧis the function ݂ is then any function of the form:
set of doors or other portals connecting them. An
݂ሺሻ ൌ ۩௩א ܽሺݒሻ
attribute ܽ ܸ ՜ ܵ is then a labeling of the nodes of the
graph, i.e. a function from nodes to some set, ܵ. where is some path in the graph and ܽ is some numeric
Populating a level is then a problem of solving for some set attribute. In the health example above, ݄ is a path function
of user-specified attributes, given another set of user- for which the summation operator is simply and the
specified constraints. attribute summed over is ȟ.
We will focus on two types of attributes. Attributes Standard paths
whose values are chosen from some small, finite sets, It’s difficult to make guarantees about truly arbitrary paths
called finite domains in the constraint-programming in arbitrary games. For example, if user insists on
literature, will be used to represent properties such as item repeatedly revisiting a trap that removes 10 hit points each
21
time, there is little the designer can do to make that optimization over paths to finding the value of a derived
survivable, short of removing the trap entirely. So we will attribute at a single vertex, it gives a constraint solver an
only consider paths in which the player is making some efficient way of determining whether a given partial
sort of forward progress, as specified by the designer (e.g. assignment of values to nodes potentially violates the
the notion of “flow distance” in Left 4 Dead (Booth 2009)). constraint, allowing early filtering of candidates in the
In particular, we will assume specific nodes are designated search (see below).
as the entrance and exit, and that expected directions of Handling general topologies
travel are provided for each edge in the graph, in the sense As stated before, standard path DAGs do not exist for
that players will “generally” go from room A to room B, many (in fact most) undirected graphs. The problem
rather than from B to A. A path is then a standard path, if comes from cul-de-sac topologies, such as the following:
it starts at the entrance, ends at the exit, and only follows
edges in their expected directions.
More formally, we will define a connected, directed a
subgraph ܩԦ of ( ܩthe undirected graph) to be a standard
path DAG if every vertex of ܩlies along a path in ܩԦ from
the entrance to the exit, or (equivalently), that ܩԦ is rooted start b end
at the entrance, and the exit is reachable from every node.
It should be noted that standard path DAGs are not No standard path can exist through ܽ because ܽ has only
unique, so the designer has some leeway in choosing the one edge. Since the edge can only be assigned one
directions of edges. It should also be noted that many direction, a path through ܽ must violate the edge’s
graphs have no standard path DAGs. We will discuss how direction either entering or exiting the node. More
to extend the method to handle these topologies shortly. generally, a cul-de-sac is any group of nodes not including
In PCG scenarios, standard path DAGs can be generated the entrance and exit, which is linked to the rest of the
as part of the topology generation process. When using the graph by only a single edge.
population algorithm as part of a designer-support tool, the There are two approaches to handling culs-de-sac when
designer may prefer to specify edge direction manually. computing path functions. The first is to assume the player
However, SPDs can also be generated fully automatically, never enters the cul-de-sac and simply remove them from
using the algorithm given in the appendix. the DAG entirely. This amounts to assuming the player is
Bounding path functions over standard paths on a speed run, bypassing any unnecessary nodes.
Given a path function ݂ and a standard path DAG ܩԦ , we Enforcing path constraints then amounts to enforcing
can compute the minimum of ݂over any standard path solvability on speed runs.
using dynamic programming. Let ݂ሺሻ ൌ ۩௩א ܽሺݒሻ for Alternatively, one may assume the player always enters
some ܽ and ْ, and let: culs-de-sac and fully explores them. We can then treat all
the cul-de-sac nodes as if they were part of the entrance to
ܽሺݒሻǡ ݒൌ the cul-de-sac. The entrance then looks like a normal node
݂ ሺݒሻ ൌ ቊ
ܽሺݒሻ ْ ൫௩ᇲ ǡ௩൯א ݂ ሺ ݒᇱ ሻ ǡ with a lot of items in it. We define the support of a node to
be the node, together with the nodes in the culs-de-sac to
That is, to find the value of ݂ ሺݒሻ, we first find its value which it is an entrance:
at all its predecessors in the standard path DAG ܩԦ . We
find its minimum over all the predecessors and add the ܵሺݒሻ ൌ ሼݒሽ ሼ ݒᇱ ȁ ݒᇱ ǦǦ ݒሽ
value of ܽ at the node ݒ. The path function ݂ is defined We then modify the definition of ݂ to sum over the
analogously, with mins changed to maxes. support of a node:
Proposition: For any vertex ݒ, the smallest and largest ܽሺݒሻǡ ݒൌ
values of ݂ over any path in ܩԦ from the entrance to ݒare ݂ ሺݒሻ ൌ ൝
ቀْ௩ ᇲאௌሺ௩ሻ ܽሺݒԢሻቁ ْ ݂ ሺ ݒᇱ ሻ ǡ
given by ݂ ሺݒሻ and ݂ ሺݒሻ, respectively. ᇲ
ሺ௩ ǡ௩ሻא
Proof: by induction on the depth of ( ݒi.e. its distance For this to be well-defined, ْ must be a commutative
from the entrance). operator, so that order doesn’t matter in the sum.
Corollary: The minimum and maximal values of ݂ over This approach has the weakness of ignoring the order in
all standard paths are given by ݂ ሺ ݒሻ and which the player encounters cul-de-sac nodes. That
݂ ሺ ݒሻ, respectively. weakness can be handled either by recursively forming a
DAG for the cul-de-sac and applying constraints along it,
This then gives us an efficient way of computing the or by imposing design constraints, e.g. that a cul-de-sac
minimal/maximal values of any path function over may contain either enemies or health packs, but not both.
standard paths. More importantly, by reducing an
22
Constraint solving definite ൌ ሼ࢞ ܺ אȁ࢞ ൌ ሼ݇ሽሽ
if (possible < minimum allowed || definite>maximum)
Constraint satisfaction problems (CSPs) involve finding throw failure
values for some set of variables given some set of if (possible = minimum) // make all possible definite
constraints. In our case, we have one variable for each for each ࢞ᇱ אpossible, Narrow(࢞Ԣ, ሼ݇ሽሻ
attribute/node pair. That is, a variable represents the value if (definite = maximum)
of a single variable on a single node of the graph. for each ࢞ᇱ אpossible // rule out remaining
We solve the CSP using constraint propagation, which if ࢞ᇱ בdefinite, Narrow(࢞Ԣ, ࢞ᇱ െ ሼ݇ሽ)
works by considering entire sets of candidate values for }
each variable. Each variable begins with the largest
possible set of candidates. The algorithm then narrows This requires linear time as written, but can be reduced to
those sets in search of specific solutions. Each time a constant amortized time (at the cost of complicating the
variable is narrowed, the values ruled out are propagated undo logic) by caching the possible and minimum counts.
through the constraints on the variable to rule out values of Constraint propagation requires that sets of possible
the other variables involved in the constraint. Those variable values be represented efficiently. Finite domain
narrowings may, in turn, lead to further narrowings, until variables have been highly studied in large part because
the process reaches fixed point. Then another variable is they can be represented efficiently as bitmasks. However,
chosen for narrowing, until all variables have been this forces finite-domain solvers to quantize numeric
narrowed to unique values. variables into a small set of possible values and operate on
The algorithm used here is a standard backtracking those values as a discrete set.
search, combined with a variant of Mackworth’s AC3 A better choice for numeric values is to approximate sets
algorithm (Mackworth 1977). Space precludes a detailed of reals as closed intervals (i.e. ሾݔǡ ݕሿ ؝ሼݖȁ ݔ ݖ ݕሽ).
presentation, but see (Rossi et al. 2006) for an extensive Real intervals are closed under addition, subtraction,
survey of constraint algorithms. The heart of the algorithm multiplication, and all monotone functions, and so are
is the three procedures, Solve, Narrow, and Propagate: precise when constraints are limited to these operations.
The propagate method for the constraint ࢞ଵ ൌ ࢞ଶ ࢞ଷ is
Solve( ) then simply
choose some variable ࢞ that is not already a singleton
for each ࢞ א ݔ // Choose some possible value PropagateAddition(ܿǡ ࢞ሻ {
create a new frame on the undo stack if ࢞ ് ࢞ଵ Narrow(࢞ଵ , ࢞ଶ ࢞ଷ )
try { Narrow(࢞, ሼݔሽ); Solve( ) } if ࢞ ് ࢞ଶ Narrow(࢞ଶ , ࢞ଵ െ ࢞ଷ )
catch (failure) { unwind undo stack frame } if ࢞ ് ࢞ଷ Narrow(࢞ଷ , ࢞ଵ െ ࢞ଶ )
}
Narrow(࢞, )ݏ // Narrow variable ࢞ to set ݏ
݊ ൌ࢞ݏת // New value of ࢞ Where arithmetic on interval-valued variables is defined by
if ݊ empty throw failure ሾܽǡ ܾሿ ሾܿǡ ݀ሿ ؝ሾܽ ܿǡ ܾ ݀ሿ and ሾܽǡ ܾሿ െ ሾܿǡ ݀ሿ ؝ሾܽ െ
if (݊ ് ࢞) ݀ǡ ܾ െ ܿሿ. Propagation for min and max are defined
save ࢞ on undo stack similarly. See (Benhamou and Granvilliers 2006) for a
old = ࢞ more detailed discussion of interval methods in constraint
࢞ؔ݊ processing.
for each constraint ܿ applied to ࢞
Propagate(ܿ, ࢞)
Experimentation
Propagate(ܿ, ࢞), called whenever some variable ࢞,
We implemented the system in C# and tested it on two
constrained by some constraint ܿ, is narrowed, narrows the
different graphs and four different constraint
other variables involved in ܿ, to rule out combinations that
configurations. The “mansion” topology is the west wing
violate the constraint. It dispatches to different methods,
of the first floor of the mansion from the original Resident
depending on the type of constraint. For example,
Evil. Like all RE levels, it is designed as a single, linear
cardinality constraints count the number of variables that
path, with the remaining nodes forming 4 culs-de-sac
could have some specified value ݇, and the number that
along the way. The “quad” topology consists of four
definitely have that value, then compare them to the
copies of the mansion, arranged in a diamond pattern,
minimum and maximum allowed occurrences:
allowing 2 different possible routes. Culs des sacs were
PropagateCardinality(ܿ, ࢞ǡ ݇) { handled using the support method (summation).
ܺ ൌset of variables constrained by ܿ Rooms were assigned contents, either empty, a large or
possible ൌ ሼ࢞ ܺ אȁ݇ ࢞ אሽ small health pack or large or small ammo supply, a
23
zombie, two zombies, a zombie dog, a boss, a trap, or a grounded input (based on Windows performance counters),
locked door. Tests varied depending on the bounds of and 1.5GB for doing the grounding itself.
different item types: That said, Clingo is a much more powerful solver; given
sufficient time, it can find solutions to very hard problem
H.Pack Ammo instances (instances that are almost but not quite
Config Zomb 2 Zomb Dog Trap
(S/L) (S/L)
unsolvable) where the interval solver will just thrash. So
Easy 0/1-7 n/a 1-5 1-3 n/a n/a
Med 0/1-40 0/1-40 1-40 1-40 1-2 1 the extra space is worthwhile for hard problems, although
Hard 0/1-40 3 2 2 1-2 1 they would have to be solved off-line.
Big 3-10/3-10 3-10/3-10 5 5 5 2
24
The choice of representation and solver do have a potential, but non-zero current flow. The cul-de-sac can
profound impact on performance, however. While not then be handled using either of the methods discussed
appropriate for all applications, interval methods offer an above.
easy to implement technology for Rogue-like games that
require fast, in-game solution of simple path constraints.
References
Ashmore, Calvin. 2007. “The quest in a generated world.” Proc.
Appendix: Computing a standard path DAG 2007 Digital Games Research Assoc. 503-509.
We can compute a standard path DAG by treating the Benhamou, Frédéric, and Laurent Granvilliers. 2006. Continuous
and interval constraints. In Handbook of Constraint
graph as a resistor network, connect the entrance and exit
Programming, ed. Francesca Rossi et al. Elsevier.
to a power source, and solving for the directions of the
Booth, Michael. 2009. The AI Systems of Left 4 Dead. In
resulting current flows using Kirchhoff’s and Ohm’s laws. Artificial Intelligence and Interactive Digital Entertainment 2009.
Due to space constraints, we will only sketch the Stanford, CA: AAAI Press.
algorithm, but the approach is conceptually Dormans, Joris. 2011. “Proceedings of the 2nd International
straightforward. Workshop on Procedural Content Generation in Games.”
We construct a linear system with one variable ܸ for Workshop on Procedural Content Generation in.
each node ݆, representing its potential (voltage), and one Gebser, Martin et al. 2009. Constraint Answer Set Solving. In
variable ܫǡ for each edge ሼ݆ǡ ݇ሽ representing the current ICLP ’09 Proceedings of the 25th International Conference on
flow through the edge. From Ohm’s law, we have that Logic Programming, 235 - 249. Pasadena, CA: Springer.
Gebser, Martin et al. 2010. A User ’ s Guide to gringo , clasp ,
ܴǡ ܫǡ ൌ ሺܸ െ ܸ ሻ clingo , and iclingo כ. Potsdam.
where ܴǡ Ͳ is an arbitrary constant. The simplest Hunicke, Robin, and Vernell Chapman. 2003. “AI for Dynamic
Difficulty Adjustment in Games.” Proceedings of the Challenges
choice is to set all ܴǡ to 1, but they can be chosen in Game AI Workshop, Nineteenth National Conference on
randomly or through any policy desired. Now, from Artificial Intelligence: 91–96.
Kirchhoff’s current law, we have that for each node ݆ other Jussien, Narendra et al. 2008. The CHOCO constraint
than the entrance and exit: programming solver. In CPAIOR08 workshop on OpenSource
Software for Integer and Contraint Programming OSSICP08.
ܫǡ ൌ Ͳ Mackworth, Alan K. 1977. “Consistency in networks of
ሼǡሽאா relations.” Artificial Intelligence 8: 99-118.
Nelson, Mark J. 2011. Game Metrics Without Players : Strategies
Since all current entering a node must also leave it.
for Understanding Game Artifacts. In Workshop for AI in the
Finally, we set: Game Design Process at AIIDE 2011, 14-18. Stanford, CA:
AAAI Press.
ܸ ൌ ͳ
ܸ ൌ Ͳ Rossi, F et al. 2006. Handbook of Constraint Programming. Ed. F
Rossi et al. Change. Vol. 35. Elsevier.
This gives us a system of ȁܸȁ ȁܧȁ equations and an equal Smith, Adam M, and Michael Mateas. 2010. Variations Forever :
number of unknowns. Solving linear systems generally Flexibly Generating Rulesets from a Sculptable Design Space of
takes cubic time; however very sparse systems such as this Mini-Games. In IEEE Conference on Computational Intelligence
and Games, 273-280. Copenhagen: IEEE Press.
can typically be solved by sparse solvers in linear time.
Having solved for the currentsǡ ܫǡ , we now simply set Smith, Adam M, and Michael Mateas. 2011. “Answer Set
Programming for Procedural Content Generation : A Design
the directions of the edges to the directions of the currents: Space Approach.” IEEE Transactions on Computational
the edge ሼ݆ǡ ݇ሽ goes from ݆ to ݇ if ܫǡ Ͳ, and ݇ to ݆, if Intelligence and AI in Games 3 (3): 187-200.
ܫǡ ൏ Ͳ. Smith, Adam M. et al. 2012. A Case Study of Expressively
The interesting case comes when ܫǡ ൌ Ͳ, i.e. where no Constrainable Level Design Automation Tools for a Puzzle
current flows between nodes ݆ and ݇. There are two cases. Game. In International Conference on the Foundations of Digital
If current flows through both nodes, just not between them, Games. Raleigh: ACM Press.
then we have a situation where the two nodes just happen Smith, Gillian et al. 2011. “Tanagra : Reactive Planning and
to have the same potential, and we can arbitrarily direct the Constraint Solving for Mixed-Initiative Level Design.” IEEE
Transactions on Computational Intelligence, AI and Computer
edge either way, or omit it entirely from the DAG. If one Games 3 (3): 201-215.
of the nodes has no current flowing through it at all, then it
Stout, Michael. 2012. “Learning From The Masters: Level Design
is part of a cul-de-sac. The cul-de-sac to which it belongs In The Legend Of Zelda.” Gamasutra.
will be precisely the connected set of nodes with equal Toy, Michael et al. 1980. Rogue. Computer Science Research
potential and zero current flow, and they will be connected Group, UC Berkeley.
to the main graph by exactly one node with the same
25