{"id":798,"date":"2014-07-04T15:37:01","date_gmt":"2014-07-04T07:37:01","guid":{"rendered":"http:\/\/www.gridsagegames.com\/blog\/?p=798"},"modified":"2014-09-09T21:52:56","modified_gmt":"2014-09-09T13:52:56","slug":"dungeon-metrics","status":"publish","type":"post","link":"https:\/\/www.gridsagegames.com\/blog\/2014\/07\/dungeon-metrics\/","title":{"rendered":"Dungeon Metrics"},"content":{"rendered":"<p>Rarely will an algorithm produce a perfect procedurally generated map, and even if it does, some degree of post-processing will still be necessary to analyze the layout. When we look at a map produced by a generator, we can determine pretty quickly whether or not the layout is sufficient for our purposes; we can also see likely bottlenecks where enemies might gather to stop the player, or areas considered &#8220;out of the way&#8221; that might hold more treasure. In the program, however, a map is nothing but coordinates telling us what each space represents, giving us no hint as to its overall composition and layout. How do we teach a game to understand and use the map as we do? We need &#8220;dungeon metrics.&#8221;<\/p>\n<h2>Requirements<\/h1>\n<p>First and foremost we have to check if we even <em>want<\/em> a given map. Without any constraints on the results, the same algorithm can produce a wide variety of layouts, some of which are either not what we expect or downright unplayable. In those cases we&#8217;ll want to throw out the map and try again.<\/p>\n<h3>Composition<\/h2>\n<p>The most basic requirement is the final amount of playable, or &#8220;open,&#8221; space. A lower bound ensures the map isn&#8217;t too sparse, while an upper bound keeps it from being too open.<\/p>\n<div id=\"attachment_800\" style=\"width: 410px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_openness.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-800\" class=\"size-full wp-image-800 \" title=\"Dungeon Metrics: Openness\" alt=\"map_metric_openness\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_openness.png\" width=\"400\" height=\"800\" \/><\/a><p id=\"caption-attachment-800\" class=\"wp-caption-text\">These two caves were generated using the exact same algorithm, differing by only one parameter: the amount of open space required (15~30% on top, 40~60% on bottom).<\/p><\/div>\n<p>Another important requirement to consider controlling for is the number of individual rooms\/caves of varying sizes.<\/p>\n<div id=\"attachment_801\" style=\"width: 410px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_roomcount.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-801\" class=\"size-full wp-image-801  \" title=\"Dungeon Metrics: Room Count\" alt=\"map_metric_roomcount\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_roomcount.png\" width=\"400\" height=\"810\" \/><\/a><p id=\"caption-attachment-801\" class=\"wp-caption-text\">These two maps were generated using the exact same algorithm, differing only by the number of rooms required (20 or more small rooms on top, at least 20 medium and 5 large on bottom).<\/p><\/div>\n<h3>Pathfinding<\/h2>\n<p>Some games use precalculated map data to optimize pathfinding, but that&#8217;s not what I&#8217;m referring to here (it&#8217;s also not too useful in Cogmind due to the completely destructible environment).<\/p>\n<p>Pathfinding is an important part of map analysis since you have to ensure it&#8217;s possible to reach one or more exits from the entrance of a map. This won&#8217;t be an issue for cellular automata assuming the final tunneling phase is doing its job, but tunneling algorithms constructing maps with more than one tunneler must confirm that the tunnelers did eventually meet and join their respective creations.<\/p>\n<p>Another possible requirement pathfinding can enforce is a minimum distance between entrances and exits. If too close together much of the map area remains unexplored, an especially relevant issue in Cogmind because there is no XP system--the best reward (&#8220;evolving&#8221;\/leveling up) comes when you find the exit. Having an exit too near the entrance would be poor design in this case since there&#8217;s little incentive to stick around.<\/p>\n<h3>Etc.<\/h2>\n<p>An alternative to automating the selection process is to use procedural generation but hand-pick the set of maps that are actually used in game. This works, but ultimately limits the pool of possibilities to the number of maps selected by the developer. (Nonetheless some games out there do use this method.)<\/p>\n<p>Whether selecting maps for final use or simply to trying to improve an algorithm, it can help to have multiple ways to look at the same map. For example a monochrome view is useful for checking available play space and overall layout without being distracted by a map&#8217;s individual parts.<\/p>\n<div id=\"attachment_802\" style=\"width: 593px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_monochrome.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-802\" class=\"wp-image-802 \" title=\"Dungeon Metrics: Monochrome\" alt=\"map_metric_monochrome\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_monochrome.png\" width=\"583\" height=\"300\" \/><\/a><p id=\"caption-attachment-802\" class=\"wp-caption-text\">The normal view on the left is nice for clearly identifying size and positioning of caves, but the monochrome view is the purest representation of playable vs. non-playable space, and is closer to what the player will see and experience.<\/p><\/div>\n<p>See the previous two posts for images showing individual highlighting of tunnels, caves, rooms, junctions, &#8220;halls,&#8221; etc. Those are not processed images--the debugging features of the map generator itself include many such views to aid development.<\/p>\n<p>Another tip for more efficiently addressing issues during development: Always have the generator output the random seed used to generate each map (I have mine added to an ongoing list). That way you can always feed the seed back into the generator to repeatedly generate the same map and find out what went wrong or how the algorithm could be improved.<\/p>\n<h2>Records<\/h1>\n<p>Once you&#8217;ve decided to keep a generated map, there&#8217;s still plenty to be done. It&#8217;s time to analyze the content and layout to record what useful info we can.<\/p>\n<p>The simplest component we&#8217;ll want to remember is where all the rooms\/caves are located. Rooms (and corridors) dug by tunnelers are easy since we built them in the first place--just record as you go. Caves are a different story since they were grown randomly. To find them we just scan the map with a standard floodfill.<\/p>\n<div id=\"attachment_804\" style=\"width: 410px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_floodfill.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-804\" class=\"size-full wp-image-804 \" title=\"Dungeon Metrics: Floodfill\" alt=\"map_metric_floodfill\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_floodfill.png\" width=\"400\" height=\"400\" \/><\/a><p id=\"caption-attachment-804\" class=\"wp-caption-text\">Locating caves in a map via floodfill before connecting them.<\/p><\/div>\n<p>Herein lies another advantage of allowing cellular automata to create many disconnected caves then reconnecting them during post-processing: The caves are naturally separated into discrete &#8220;rooms&#8221; for you by the algorithm! This means we&#8217;ll later be able to take advantage of any of the methods of analysis that work on normal room-and-corridor dungeons. More on that later.<\/p>\n<p>Location and size are not the only important information that could come in handy when deciding how to use different parts of the map. We can record doors and which direction they face (used for optimizing some types of pathfinding, or setting up ambushes), which rooms and corridors are attached to each junction, which tunnels are linked to which cave(s), and which caves are directly accessible from another cave. My favorite piece of data that I&#8217;ll be discussing further below is relative seclusion\/connectedness.<\/p>\n<p>General statistics collected from the final map may also affect what you decide to do with it as a whole, data like the percent composition by cell type, maximum and average seclusion of areas, the largest individual hall\/cave, etc. These could of course be used as additional requirements to filter out unwanted maps.<\/p>\n<h2>Analysis &amp; Application<\/h1>\n<p>So what do we do with all this collected data besides decide whether to throw away a map? The obvious application is object placement.<\/p>\n<p>Robots and parts in the 7DRL were spawned without regard for whether an area belonged to a room or corridor; you could find a stockpile of parts sitting anywhere out in the open. It would make more sense to store most of those in rooms, both for realism and from a gameplay point of view (&#8220;do I open that door to search for parts even though my scanners show robots on the other side that may or may not be hostile?&#8221;).<\/p>\n<p>As mentioned before, corridor junctions are likely to contain terminals, and large halls will contain bigger machines. Guards are more likely to patrol intersections. Choosing the best locations would be difficult without first recording details about the map layout.<\/p>\n<h3>Connectedness<\/h2>\n<p>My favorite analytical tool for cave systems is the relative connectedness of each cave.<\/p>\n<div id=\"attachment_812\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_connectedness.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-812\" class=\"size-full wp-image-812 \" title=\"Dungeon Metrics: Connectedness\" alt=\"map_metric_connectedness\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_connectedness.png\" width=\"300\" height=\"600\" \/><\/a><p id=\"caption-attachment-812\" class=\"wp-caption-text\">Visualization of cave connectedness, where brighter caves are better connected to the system.<\/p><\/div>\n<p>Because the number of direct cave connections alone is less meaningful in many scenarios, I define &#8220;connectedness&#8221; as the number of immediately connected caves <em>plus<\/em> the number of caves those are connected to as well. Notice in the above visualization that outlying caves are shaded darker, representing a lower connectedness value.<\/p>\n<p>Less connected caves in different parts of the map are likely positions for entrances\/exits, and others are good candidates for placing loot, secrets, or perhaps nastier surprises for nosy explorers.<\/p>\n<p>At the other end of the spectrum, well-connected caves are where most enemy activity will probably be concentrated.<\/p>\n<h3>Seclusion<\/h2>\n<p>For maps created by the tunneling algorithm, all rooms are rated by their &#8220;seclusion&#8221; value. Seclusion uses different calculation criteria than cave connectedness since map connectivity is much higher. Instead it&#8217;s based on the distance from the fastest path the player can take between an entrance and the exit(s).<\/p>\n<div id=\"attachment_813\" style=\"width: 810px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_seclusion.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-813\" class=\"size-full wp-image-813 \" title=\"Dungeon Metrics: Seclusion\" alt=\"map_metric_seclusion\" src=\"https:\/\/www.gridsagegames.com\/blog\/gsg-content\/uploads\/2014\/06\/map_metric_seclusion.png\" width=\"800\" height=\"800\" \/><\/a><p id=\"caption-attachment-813\" class=\"wp-caption-text\">Visualization of room seclusion, where darker red rooms are further from the quickest routes across the map.<\/p><\/div>\n<p>The four entrances\/exits (pink dots) are connected by the most direct paths between them (green lines), then the entrance to each room pathfinds to the closest point on any of those lines. Notice that the further a room is from a path the darker its shade of red. (For purposes of the visualization any room with below average relative seclusion, where &#8220;average&#8221; is based on the map values, is not shaded.) The more secluded a room, the more likely it will hold something of value or interest to the player. Of course this idea of &#8220;seclusion&#8221; assumes the player knows where they&#8217;re going when they may very well not! But that&#8217;s okay, because the player deserves a little something for having traveled so far out of their way, and having overcome whatever obstacles they had to in order to arrive there.<\/p>\n<p><em>This is the fourth in a five-part series on procedural maps:<\/em><\/p>\n<ul>\n<li><em>Part 1: <a title=\"Procedural Map Generation\" href=\"http:\/\/www.gridsagegames.com\/blog\/2014\/06\/procedural-map-generation\/\">Procedural Map Generation<\/a><\/em><\/li>\n<li><em>Part 2: <a title=\"Mapgen: Tunneling Algorithm\" href=\"http:\/\/www.gridsagegames.com\/blog\/2014\/06\/mapgen-tunneling-algorithm\/\">Tunneling Algorithm<\/a><em><\/em><\/em><\/li>\n<li><em>Part 3: <a title=\"Mapgen: Cellular Automata\" href=\"http:\/\/www.gridsagegames.com\/blog\/2014\/06\/mapgen-cellular-automata\/\"><em>Cellular Automata<\/em><\/a><\/em><\/li>\n<li><em>Part 5: <a title=\"Dungeon Prefabs\" href=\"http:\/\/www.gridsagegames.com\/blog\/2014\/07\/dungeon-prefabs\/\">Dungeon Prefabs<\/a><em><br \/>\n<\/em><\/em><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Rarely will an algorithm produce a perfect procedurally generated map, and even if it does, some degree of post-processing will still be necessary to analyze the layout. When we look at a map produced by a generator, we can determine pretty quickly whether or not the layout is sufficient for our purposes; we can also [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":812,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,92],"tags":[77,4,80,81,76,79],"class_list":["post-798","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-design","category-dev-series-procedural-maps","tag-cellular-automata","tag-cogmind","tag-dungeon-metrics","tag-map-analysis","tag-map-generation","tag-tunneling-algorithm"],"_links":{"self":[{"href":"https:\/\/www.gridsagegames.com\/blog\/wp-json\/wp\/v2\/posts\/798","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gridsagegames.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gridsagegames.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gridsagegames.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gridsagegames.com\/blog\/wp-json\/wp\/v2\/comments?post=798"}],"version-history":[{"count":13,"href":"https:\/\/www.gridsagegames.com\/blog\/wp-json\/wp\/v2\/posts\/798\/revisions"}],"predecessor-version":[{"id":861,"href":"https:\/\/www.gridsagegames.com\/blog\/wp-json\/wp\/v2\/posts\/798\/revisions\/861"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gridsagegames.com\/blog\/wp-json\/wp\/v2\/media\/812"}],"wp:attachment":[{"href":"https:\/\/www.gridsagegames.com\/blog\/wp-json\/wp\/v2\/media?parent=798"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gridsagegames.com\/blog\/wp-json\/wp\/v2\/categories?post=798"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gridsagegames.com\/blog\/wp-json\/wp\/v2\/tags?post=798"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}