From 70ae2fd407461332a6a84060966cdc6c04fb1288 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 30 Dec 2013 03:21:42 -0400 Subject: [PATCH] Improved Doorway Placement Changed MazeDesigner to prune out some unnecessary doorways at random by removing edges from the room graph. Previous mazes allowed all side paths to exist, which resulted in a kind of circular layout. Although that was disorienting to people at first, if you realized it was a circle, it became simple to navigate through the maze. This update makes branching paths more common. --- .../experimental/DisjointSet.java | 5 +++ .../experimental/MazeDesigner.java | 44 ++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/experimental/DisjointSet.java b/src/main/java/StevenDimDoors/experimental/DisjointSet.java index fc15269..4b4150f 100644 --- a/src/main/java/StevenDimDoors/experimental/DisjointSet.java +++ b/src/main/java/StevenDimDoors/experimental/DisjointSet.java @@ -126,4 +126,9 @@ public class DisjointSet return (firstRoot == secondRoot); } } + + public void clear() + { + mapping.clear(); + } } diff --git a/src/main/java/StevenDimDoors/experimental/MazeDesigner.java b/src/main/java/StevenDimDoors/experimental/MazeDesigner.java index 09c6df4..6fb89b9 100644 --- a/src/main/java/StevenDimDoors/experimental/MazeDesigner.java +++ b/src/main/java/StevenDimDoors/experimental/MazeDesigner.java @@ -39,10 +39,10 @@ public class MazeDesigner // Cut out random subgraphs from the adjacency graph ArrayList> cores = createMazeSections(rooms, random); - // Remove unnecessary passages through floors/ceilings + // Remove unnecessary passages through floors/ceilings and some from the walls for (IGraphNode core : cores) { - minimizeVerticalPassages(core, rooms, random); + pruneDoorways(core, rooms, random); } return new MazeDesign(root, rooms, cores); @@ -459,7 +459,7 @@ public class MazeDesigner return cores; } - private static void minimizeVerticalPassages(IGraphNode core, + private static void pruneDoorways(IGraphNode core, DirectedGraph rooms, Random random) { // We receive a node for one of the rooms in a section of the maze @@ -467,13 +467,15 @@ public class MazeDesigner // still allowing any room to be reachable from any other room. // In technical terms, we receive a node from a connected subgraph // and we need to remove as many Y_AXIS-type edges as possible while - // preserving connectedness. + // preserving connectedness. We also want to randomly remove some of + // the other doorways without breaking connectedness. // An efficient solution is to assign nodes to disjoint sets based // on their components, ignoring all Y_AXIS edges, then iterate over // a list of those edges and remove them if they connect two nodes // in the same set. Otherwise, merge their sets and keep the edge. - // This is similar to algorithms for spanning trees. + // This is similar to algorithms for spanning trees. The same + // idea applies for the other doorways with some chance added. // First, list all nodes in the subgraph IGraphNode current; @@ -540,6 +542,38 @@ public class MazeDesigner rooms.removeEdge(passage); } } + + // Repeat the pruning process with X_AXIS and Z_AXIS doorways + // In this case, unnecessary edges might be kept at random + components.clear(); + targets.clear(); + + for (IGraphNode room : subgraph) + { + components.makeSet(room); + } + for (IGraphNode room : subgraph) + { + for (IEdge passage : room.outbound()) + { + if (passage.data().axis() == DoorwayData.Y_AXIS) + { + components.mergeSets(passage.head(), passage.tail()); + } + else + { + targets.add(passage); + } + } + } + Collections.shuffle(targets, random); + for (IEdge passage : targets) + { + if (!components.mergeSets(passage.head(), passage.tail()) && random.nextBoolean()) + { + rooms.removeEdge(passage); + } + } } }