Refactored Maze Generation to use RoomData
Rewrote portions of our maze generation code to use RoomData. This provides an object that unifies all room data instead of having it spread across various data structures and linked loosely by hash maps. We'll need this to implement the remaining generation features.
This commit is contained in:
@@ -18,8 +18,8 @@ public class MazeBuilder
|
|||||||
Point3D offset = new Point3D(x - design.width() / 2, y - design.height() - 1, z - design.length() / 2);
|
Point3D offset = new Point3D(x - design.width() / 2, y - design.height() - 1, z - design.length() / 2);
|
||||||
SphereDecayOperation decay = new SphereDecayOperation(random, 0, 0, Block.stoneBrick.blockID, 2);
|
SphereDecayOperation decay = new SphereDecayOperation(random, 0, 0, Block.stoneBrick.blockID, 2);
|
||||||
|
|
||||||
buildRooms(design.getRoomGraph(), world, offset);
|
buildRooms(design.getLayout(), world, offset);
|
||||||
carveDoorways(design.getRoomGraph(), world, offset, decay, random);
|
carveDoorways(design.getLayout(), world, offset, decay, random);
|
||||||
|
|
||||||
//placeDoors(design, world, offset);
|
//placeDoors(design, world, offset);
|
||||||
|
|
||||||
@@ -32,25 +32,25 @@ public class MazeBuilder
|
|||||||
//final int DECAY_BOX_SIZE = 8
|
//final int DECAY_BOX_SIZE = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void buildRooms(DirectedGraph<PartitionNode, DoorwayData> roomGraph, World world, Point3D offset)
|
private static void buildRooms(DirectedGraph<RoomData, DoorwayData> layout, World world, Point3D offset)
|
||||||
{
|
{
|
||||||
for (IGraphNode<PartitionNode, DoorwayData> node : roomGraph.nodes())
|
for (IGraphNode<RoomData, DoorwayData> node : layout.nodes())
|
||||||
{
|
{
|
||||||
PartitionNode room = node.data();
|
PartitionNode room = node.data().getPartitionNode();
|
||||||
buildBox(world, offset, room.minCorner(), room.maxCorner(), Block.stoneBrick.blockID, 0);
|
buildBox(world, offset, room.minCorner(), room.maxCorner(), Block.stoneBrick.blockID, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void carveDoorways(DirectedGraph<PartitionNode, DoorwayData> roomGraph, World world,
|
private static void carveDoorways(DirectedGraph<RoomData, DoorwayData> layout, World world,
|
||||||
Point3D offset, SphereDecayOperation decay, Random random)
|
Point3D offset, SphereDecayOperation decay, Random random)
|
||||||
{
|
{
|
||||||
char axis;
|
char axis;
|
||||||
Point3D lower;
|
Point3D lower;
|
||||||
DoorwayData doorway;
|
DoorwayData doorway;
|
||||||
|
|
||||||
for (IGraphNode<PartitionNode, DoorwayData> node : roomGraph.nodes())
|
for (IGraphNode<RoomData, DoorwayData> node : layout.nodes())
|
||||||
{
|
{
|
||||||
for (IEdge<PartitionNode, DoorwayData> passage : node.outbound())
|
for (IEdge<RoomData, DoorwayData> passage : node.outbound())
|
||||||
{
|
{
|
||||||
doorway = passage.data();
|
doorway = passage.data();
|
||||||
axis = doorway.axis();
|
axis = doorway.axis();
|
||||||
@@ -165,7 +165,6 @@ public class MazeBuilder
|
|||||||
setBlockDirectly(world, x, y, z, 0, 0);
|
setBlockDirectly(world, x, y, z, 0, 0);
|
||||||
setBlockDirectly(world, x, y + 1, z, 0, 0);
|
setBlockDirectly(world, x, y + 1, z, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void buildBox(World world, Point3D offset, Point3D minCorner, Point3D maxCorner, int blockID, int metadata)
|
private static void buildBox(World world, Point3D offset, Point3D minCorner, Point3D maxCorner, int blockID, int metadata)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,16 +5,12 @@ import java.util.ArrayList;
|
|||||||
public class MazeDesign
|
public class MazeDesign
|
||||||
{
|
{
|
||||||
private PartitionNode root;
|
private PartitionNode root;
|
||||||
private DirectedGraph<PartitionNode, DoorwayData> rooms;
|
private DirectedGraph<RoomData, DoorwayData> layout;
|
||||||
private ArrayList<IGraphNode<PartitionNode, DoorwayData>> cores;
|
|
||||||
private ArrayList<BoundingBox> protectedAreas;
|
|
||||||
|
|
||||||
public MazeDesign(PartitionNode root, DirectedGraph<PartitionNode, DoorwayData> rooms,
|
public MazeDesign(PartitionNode root, DirectedGraph<RoomData, DoorwayData> layout)
|
||||||
ArrayList<IGraphNode<PartitionNode, DoorwayData>> cores)
|
|
||||||
{
|
{
|
||||||
this.root = root;
|
this.root = root;
|
||||||
this.rooms = rooms;
|
this.layout = layout;
|
||||||
this.cores = cores;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PartitionNode getRootPartition()
|
public PartitionNode getRootPartition()
|
||||||
@@ -22,19 +18,9 @@ public class MazeDesign
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DirectedGraph<PartitionNode, DoorwayData> getRoomGraph()
|
public DirectedGraph<RoomData, DoorwayData> getLayout()
|
||||||
{
|
{
|
||||||
return rooms;
|
return layout;
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<IGraphNode<PartitionNode, DoorwayData>> getCoreNodes()
|
|
||||||
{
|
|
||||||
return cores;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<BoundingBox> getProtectedAreas()
|
|
||||||
{
|
|
||||||
return protectedAreas;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int width()
|
public int width()
|
||||||
|
|||||||
@@ -25,55 +25,66 @@ public class MazeDesigner
|
|||||||
public static MazeDesign generate(Random random)
|
public static MazeDesign generate(Random random)
|
||||||
{
|
{
|
||||||
// Construct a random binary space partitioning of our maze volume
|
// Construct a random binary space partitioning of our maze volume
|
||||||
PartitionNode root = partitionRooms(MAZE_WIDTH, MAZE_HEIGHT, MAZE_LENGTH, SPLIT_COUNT, random);
|
PartitionNode<RoomData> root = partitionRooms(MAZE_WIDTH, MAZE_HEIGHT, MAZE_LENGTH, SPLIT_COUNT, random);
|
||||||
|
|
||||||
// List all the leaf nodes of the partition tree, which denote individual rooms
|
// Attach rooms to all the leaf nodes of the partition tree
|
||||||
ArrayList<PartitionNode> partitions = new ArrayList<PartitionNode>(1 << SPLIT_COUNT);
|
ArrayList<RoomData> rooms = new ArrayList<RoomData>(1 << SPLIT_COUNT);
|
||||||
listRoomPartitions(root, partitions);
|
attachRooms(root, rooms);
|
||||||
|
|
||||||
|
// Shuffle the list of rooms so that they're not listed in any ordered way in the room graph
|
||||||
|
// This is the only convenient way of randomizing the maze sections generated later
|
||||||
|
Collections.shuffle(rooms, random);
|
||||||
|
|
||||||
// Construct an adjacency graph of the rooms we've carved out. Two rooms are
|
// Construct an adjacency graph of the rooms we've carved out. Two rooms are
|
||||||
// considered adjacent if and only if a doorway could connect them. Their
|
// considered adjacent if and only if a doorway could connect them. Their
|
||||||
// common boundary must be large enough for a doorway.
|
// common boundary must be large enough for a doorway.
|
||||||
DirectedGraph<PartitionNode, DoorwayData> rooms = createRoomGraph(root, partitions, random);
|
DirectedGraph<RoomData, DoorwayData> layout = createRoomGraph(root, rooms, random);
|
||||||
|
|
||||||
// Cut out random subgraphs from the adjacency graph
|
// Cut out random subgraphs from the adjacency graph
|
||||||
ArrayList<IGraphNode<PartitionNode, DoorwayData>> cores = createMazeSections(rooms, random);
|
ArrayList<RoomData> cores = createMazeSections(layout, random);
|
||||||
|
|
||||||
// Remove unnecessary passages through floors/ceilings and some from the walls
|
// Remove unnecessary passages through floors/ceilings and some from the walls
|
||||||
for (IGraphNode<PartitionNode, DoorwayData> core : cores)
|
for (RoomData core : cores)
|
||||||
{
|
{
|
||||||
pruneDoorways(core, rooms, random);
|
pruneDoorways(core.getLayoutNode(), layout, random);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MazeDesign(root, rooms, cores);
|
return new MazeDesign(root, layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void listRoomPartitions(PartitionNode node, ArrayList<PartitionNode> partitions)
|
private static void attachRooms(PartitionNode<RoomData> node, ArrayList<RoomData> partitions)
|
||||||
{
|
{
|
||||||
if (node.isLeaf())
|
if (node.isLeaf())
|
||||||
{
|
{
|
||||||
partitions.add(node);
|
partitions.add(new RoomData(node));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
listRoomPartitions(node.leftChild(), partitions);
|
attachRooms(node.leftChild(), partitions);
|
||||||
listRoomPartitions(node.rightChild(), partitions);
|
attachRooms(node.rightChild(), partitions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void removeRoomPartitions(PartitionNode node)
|
private static void removeRoom(RoomData room, DirectedGraph<RoomData, DoorwayData> layout)
|
||||||
{
|
{
|
||||||
// Remove a node and any of its ancestors that become leaf nodes
|
// Remove the room from the partition tree and from the layout graph.
|
||||||
|
// Also remove any ancestors that become leaf nodes.
|
||||||
PartitionNode parent;
|
PartitionNode parent;
|
||||||
PartitionNode current;
|
PartitionNode current;
|
||||||
|
|
||||||
current = node;
|
current = room.getPartitionNode();
|
||||||
while (current != null && current.isLeaf())
|
while (current != null && current.isLeaf())
|
||||||
{
|
{
|
||||||
parent = current.parent();
|
parent = current.parent();
|
||||||
current.remove();
|
current.remove();
|
||||||
current = parent;
|
current = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the room from the layout graph
|
||||||
|
layout.removeNode(room.getLayoutNode());
|
||||||
|
|
||||||
|
// Wipe the room's data, as a precaution.
|
||||||
|
room.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PartitionNode partitionRooms(int width, int height, int length, int maxLevels, Random random)
|
private static PartitionNode partitionRooms(int width, int height, int length, int maxLevels, Random random)
|
||||||
@@ -140,35 +151,25 @@ public class MazeDesigner
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DirectedGraph<PartitionNode, DoorwayData> createRoomGraph(PartitionNode root, ArrayList<PartitionNode> partitions, Random random)
|
private static DirectedGraph<RoomData, DoorwayData> createRoomGraph(PartitionNode<RoomData> root, ArrayList<RoomData> rooms, Random random)
|
||||||
{
|
{
|
||||||
DirectedGraph<PartitionNode, DoorwayData> roomGraph = new DirectedGraph<PartitionNode, DoorwayData>();
|
DirectedGraph<RoomData, DoorwayData> layout = new DirectedGraph<RoomData, DoorwayData>();
|
||||||
HashMap<PartitionNode, IGraphNode<PartitionNode, DoorwayData>> roomsToGraph = new HashMap<PartitionNode, IGraphNode<PartitionNode, DoorwayData>>(2 * partitions.size());
|
|
||||||
|
|
||||||
// Shuffle the list of rooms so that they're not listed in any ordered way in the room graph
|
|
||||||
// This is the only convenient way of randomizing the maze sections generated later
|
|
||||||
Collections.shuffle(partitions, random);
|
|
||||||
|
|
||||||
// Add all rooms to a graph
|
// Add all rooms to a graph
|
||||||
// Also add them to a map so we can associate rooms with their graph nodes
|
for (RoomData room : rooms)
|
||||||
// The map is needed for linking graph nodes based on adjacent partitions
|
|
||||||
for (PartitionNode partition : partitions)
|
|
||||||
{
|
{
|
||||||
roomsToGraph.put(partition, roomGraph.addNode(partition));
|
room.addToLayout(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add edges for each room
|
// Add edges for each room
|
||||||
for (IGraphNode<PartitionNode, DoorwayData> node : roomGraph.nodes())
|
for (IGraphNode<RoomData, DoorwayData> node : layout.nodes())
|
||||||
{
|
{
|
||||||
findDoorways(node, root, roomsToGraph, roomGraph);
|
findDoorways(node.data(), root, layout);
|
||||||
}
|
}
|
||||||
|
return layout;
|
||||||
return roomGraph;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void findDoorways(IGraphNode<PartitionNode, DoorwayData> roomNode, PartitionNode root,
|
private static void findDoorways(RoomData room, PartitionNode<RoomData> root,
|
||||||
HashMap<PartitionNode, IGraphNode<PartitionNode, DoorwayData>> roomsToGraph,
|
DirectedGraph<RoomData, DoorwayData> layout)
|
||||||
DirectedGraph<PartitionNode, DoorwayData> roomGraph)
|
|
||||||
{
|
{
|
||||||
// This function finds rooms adjacent to a specified room that could be connected
|
// This function finds rooms adjacent to a specified room that could be connected
|
||||||
// to it through a doorway. Edges are added to the room graph to denote rooms that
|
// to it through a doorway. Edges are added to the room graph to denote rooms that
|
||||||
@@ -186,7 +187,7 @@ public class MazeDesigner
|
|||||||
// there will always be a way to walk from any room to any other room.
|
// there will always be a way to walk from any room to any other room.
|
||||||
|
|
||||||
boolean[][] detected;
|
boolean[][] detected;
|
||||||
PartitionNode adjacent;
|
PartitionNode<RoomData> adjacent;
|
||||||
|
|
||||||
int a, b, c;
|
int a, b, c;
|
||||||
int p, q, r;
|
int p, q, r;
|
||||||
@@ -195,11 +196,10 @@ public class MazeDesigner
|
|||||||
Point3D otherMin;
|
Point3D otherMin;
|
||||||
Point3D otherMax;
|
Point3D otherMax;
|
||||||
DoorwayData doorway;
|
DoorwayData doorway;
|
||||||
IGraphNode<PartitionNode, DoorwayData> adjacentNode;
|
|
||||||
|
|
||||||
PartitionNode room = roomNode.data();
|
PartitionNode partition = room.getPartitionNode();
|
||||||
Point3D minCorner = room.minCorner();
|
Point3D minCorner = partition.minCorner();
|
||||||
Point3D maxCorner = room.maxCorner();
|
Point3D maxCorner = partition.maxCorner();
|
||||||
|
|
||||||
int minX = minCorner.getX();
|
int minX = minCorner.getX();
|
||||||
int minY = minCorner.getY();
|
int minY = minCorner.getY();
|
||||||
@@ -209,9 +209,9 @@ public class MazeDesigner
|
|||||||
int maxY = maxCorner.getY();
|
int maxY = maxCorner.getY();
|
||||||
int maxZ = maxCorner.getZ();
|
int maxZ = maxCorner.getZ();
|
||||||
|
|
||||||
int width = room.width();
|
int width = partition.width();
|
||||||
int height = room.height();
|
int height = partition.height();
|
||||||
int length = room.length();
|
int length = partition.length();
|
||||||
|
|
||||||
if (maxZ < root.maxCorner().getZ())
|
if (maxZ < root.maxCorner().getZ())
|
||||||
{
|
{
|
||||||
@@ -247,8 +247,7 @@ public class MazeDesigner
|
|||||||
otherMin = new Point3D(minXI, minYI, maxZ);
|
otherMin = new Point3D(minXI, minYI, maxZ);
|
||||||
otherMax = new Point3D(maxXI, maxYI, maxZ + 1);
|
otherMax = new Point3D(maxXI, maxYI, maxZ + 1);
|
||||||
doorway = new DoorwayData(otherMin, otherMax, DoorwayData.Z_AXIS);
|
doorway = new DoorwayData(otherMin, otherMax, DoorwayData.Z_AXIS);
|
||||||
adjacentNode = roomsToGraph.get(adjacent);
|
layout.addEdge(room.getLayoutNode(), adjacent.getData().getLayoutNode(), doorway);
|
||||||
roomGraph.addEdge(roomNode, adjacentNode, doorway);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -295,8 +294,7 @@ public class MazeDesigner
|
|||||||
otherMin = new Point3D(maxX, minYI, minZI);
|
otherMin = new Point3D(maxX, minYI, minZI);
|
||||||
otherMax = new Point3D(maxX + 1, maxYI, maxZI);
|
otherMax = new Point3D(maxX + 1, maxYI, maxZI);
|
||||||
doorway = new DoorwayData(otherMin, otherMax, DoorwayData.X_AXIS);
|
doorway = new DoorwayData(otherMin, otherMax, DoorwayData.X_AXIS);
|
||||||
adjacentNode = roomsToGraph.get(adjacent);
|
layout.addEdge(room.getLayoutNode(), adjacent.getData().getLayoutNode(), doorway);
|
||||||
roomGraph.addEdge(roomNode, adjacentNode, doorway);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -343,8 +341,7 @@ public class MazeDesigner
|
|||||||
otherMin = new Point3D(minXI, maxY, minZI);
|
otherMin = new Point3D(minXI, maxY, minZI);
|
||||||
otherMax = new Point3D(maxXI, maxY + 1, maxZI);
|
otherMax = new Point3D(maxXI, maxY + 1, maxZI);
|
||||||
doorway = new DoorwayData(otherMin, otherMax, DoorwayData.Y_AXIS);
|
doorway = new DoorwayData(otherMin, otherMax, DoorwayData.Y_AXIS);
|
||||||
adjacentNode = roomsToGraph.get(adjacent);
|
layout.addEdge(room.getLayoutNode(), adjacent.getData().getLayoutNode(), doorway);
|
||||||
roomGraph.addEdge(roomNode, adjacentNode, doorway);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -359,7 +356,7 @@ public class MazeDesigner
|
|||||||
//Done!
|
//Done!
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArrayList<IGraphNode<PartitionNode, DoorwayData>> createMazeSections(DirectedGraph<PartitionNode, DoorwayData> roomGraph, Random random)
|
private static ArrayList<RoomData> createMazeSections(DirectedGraph<RoomData, DoorwayData> layout, Random random)
|
||||||
{
|
{
|
||||||
// The randomness of the sections generated here hinges on
|
// The randomness of the sections generated here hinges on
|
||||||
// the nodes in the graph being in a random order. We assume
|
// the nodes in the graph being in a random order. We assume
|
||||||
@@ -369,66 +366,68 @@ public class MazeDesigner
|
|||||||
final int MIN_SECTION_ROOMS = 5;
|
final int MIN_SECTION_ROOMS = 5;
|
||||||
|
|
||||||
int distance;
|
int distance;
|
||||||
IGraphNode<PartitionNode, DoorwayData> current;
|
RoomData room;
|
||||||
IGraphNode<PartitionNode, DoorwayData> neighbor;
|
RoomData neighbor;
|
||||||
|
IGraphNode<RoomData, DoorwayData> current;
|
||||||
|
|
||||||
ArrayList<IGraphNode<PartitionNode, DoorwayData>> cores = new ArrayList<IGraphNode<PartitionNode, DoorwayData>>();
|
ArrayList<RoomData> cores = new ArrayList<RoomData>();
|
||||||
ArrayList<IGraphNode<PartitionNode, DoorwayData>> removals = new ArrayList<IGraphNode<PartitionNode, DoorwayData>>();
|
ArrayList<RoomData> removals = new ArrayList<RoomData>();
|
||||||
ArrayList<IGraphNode<PartitionNode, DoorwayData>> section = new ArrayList<IGraphNode<PartitionNode, DoorwayData>>();
|
ArrayList<RoomData> section = new ArrayList<RoomData>();
|
||||||
|
|
||||||
Queue<IGraphNode<PartitionNode, DoorwayData>> ordering = new LinkedList<IGraphNode<PartitionNode, DoorwayData>>();
|
Queue<RoomData> ordering = new LinkedList<RoomData>();
|
||||||
HashMap<IGraphNode<PartitionNode, DoorwayData>, Integer> distances = new HashMap<IGraphNode<PartitionNode, DoorwayData>, Integer>();
|
|
||||||
|
|
||||||
// Repeatedly generate sections until all nodes have been visited
|
// Repeatedly generate sections until all nodes have been visited
|
||||||
for (IGraphNode<PartitionNode, DoorwayData> node : roomGraph.nodes())
|
for (IGraphNode<RoomData, DoorwayData> node : layout.nodes())
|
||||||
{
|
{
|
||||||
// If this node hasn't been visited, then use it as the core of a new section
|
// If this room hasn't been visited (distance = -1), then use it as the core of a new section
|
||||||
// Otherwise, ignore it, since it was already processed
|
// Otherwise, ignore it, since it was already processed
|
||||||
if (!distances.containsKey(node))
|
room = node.data();
|
||||||
|
if (room.getDistance() < 0)
|
||||||
{
|
{
|
||||||
// Perform a breadth-first search to tag surrounding nodes with distances
|
// Perform a breadth-first search to tag surrounding nodes with distances
|
||||||
distances.put(node, 0);
|
room.setDistance(0);
|
||||||
ordering.add(node);
|
ordering.add(room);
|
||||||
section.clear();
|
section.clear();
|
||||||
|
|
||||||
while (!ordering.isEmpty())
|
while (!ordering.isEmpty())
|
||||||
{
|
{
|
||||||
current = ordering.remove();
|
room = ordering.remove();
|
||||||
distance = distances.get(current) + 1;
|
distance = room.getDistance() + 1;
|
||||||
|
|
||||||
if (distance <= MAX_DISTANCE + 1)
|
if (distance <= MAX_DISTANCE + 1)
|
||||||
{
|
{
|
||||||
section.add(current);
|
section.add(room);
|
||||||
|
current = room.getLayoutNode();
|
||||||
|
|
||||||
// Visit neighboring nodes and assign them distances, if they don't
|
// Visit neighboring rooms and assign them distances, if they don't
|
||||||
// have a distance assigned already
|
// have a proper distance assigned already
|
||||||
for (IEdge<PartitionNode, DoorwayData> edge : current.inbound())
|
for (IEdge<RoomData, DoorwayData> edge : current.inbound())
|
||||||
{
|
{
|
||||||
neighbor = edge.head();
|
neighbor = edge.head().data();
|
||||||
if (!distances.containsKey(neighbor))
|
if (neighbor.getDistance() < 0)
|
||||||
{
|
{
|
||||||
distances.put(neighbor, distance);
|
neighbor.setDistance(distance);
|
||||||
ordering.add(neighbor);
|
ordering.add(neighbor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (IEdge<PartitionNode, DoorwayData> edge : current.outbound())
|
for (IEdge<RoomData, DoorwayData> edge : current.outbound())
|
||||||
{
|
{
|
||||||
neighbor = edge.tail();
|
neighbor = edge.tail().data();
|
||||||
if (!distances.containsKey(neighbor))
|
if (neighbor.getDistance() < 0)
|
||||||
{
|
{
|
||||||
distances.put(neighbor, distance);
|
neighbor.setDistance(distance);
|
||||||
ordering.add(neighbor);
|
ordering.add(neighbor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
removals.add(current);
|
removals.add(room);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// List nodes that have a distance of exactly MAX_DISTANCE + 1
|
// List rooms that have a distance of exactly MAX_DISTANCE + 1
|
||||||
// Those are precisely the nodes that remain in the queue
|
// Those are precisely the nodes that remain in the queue
|
||||||
// We can't remove them immediately because that could break
|
// We can't remove them immediately because that could break
|
||||||
// the iterator for the graph.
|
// the iterator for the graph.
|
||||||
@@ -440,7 +439,7 @@ public class MazeDesigner
|
|||||||
// Check if this section contains enough rooms
|
// Check if this section contains enough rooms
|
||||||
if (section.size() >= MIN_SECTION_ROOMS)
|
if (section.size() >= MIN_SECTION_ROOMS)
|
||||||
{
|
{
|
||||||
cores.add(node);
|
cores.add(node.data());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -449,18 +448,17 @@ public class MazeDesigner
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all the nodes that were listed for removal
|
// Remove all the rooms that were listed for removal
|
||||||
// Also remove unused partitions from the partition tree
|
// Also remove unused partitions from the partition tree
|
||||||
for (IGraphNode<PartitionNode, DoorwayData> node : removals)
|
for (RoomData target : removals)
|
||||||
{
|
{
|
||||||
removeRoomPartitions(node.data());
|
removeRoom(target, layout);
|
||||||
roomGraph.removeNode(node);
|
|
||||||
}
|
}
|
||||||
return cores;
|
return cores;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void pruneDoorways(IGraphNode<PartitionNode, DoorwayData> core,
|
private static void pruneDoorways(IGraphNode<RoomData, DoorwayData> core,
|
||||||
DirectedGraph<PartitionNode, DoorwayData> rooms, Random random)
|
DirectedGraph<RoomData, DoorwayData> layout, Random random)
|
||||||
{
|
{
|
||||||
// We receive a node for one of the rooms in a section of the maze
|
// We receive a node for one of the rooms in a section of the maze
|
||||||
// and we need to remove as many floor doorways as possible while
|
// and we need to remove as many floor doorways as possible while
|
||||||
@@ -478,12 +476,12 @@ public class MazeDesigner
|
|||||||
// idea applies for the other doorways, plus some randomness.
|
// idea applies for the other doorways, plus some randomness.
|
||||||
|
|
||||||
// First, list all nodes in the subgraph
|
// First, list all nodes in the subgraph
|
||||||
IGraphNode<PartitionNode, DoorwayData> current;
|
IGraphNode<RoomData, DoorwayData> current;
|
||||||
IGraphNode<PartitionNode, DoorwayData> neighbor;
|
IGraphNode<RoomData, DoorwayData> neighbor;
|
||||||
|
|
||||||
Stack<IGraphNode<PartitionNode, DoorwayData>> ordering = new Stack<IGraphNode<PartitionNode, DoorwayData>>();
|
Stack<IGraphNode<RoomData, DoorwayData>> ordering = new Stack<IGraphNode<RoomData, DoorwayData>>();
|
||||||
ArrayList<IGraphNode<PartitionNode, DoorwayData>> subgraph = new ArrayList<IGraphNode<PartitionNode, DoorwayData>>(64);
|
ArrayList<IGraphNode<RoomData, DoorwayData>> subgraph = new ArrayList<IGraphNode<RoomData, DoorwayData>>(64);
|
||||||
DisjointSet<IGraphNode<PartitionNode, DoorwayData>> components = new DisjointSet<IGraphNode<PartitionNode, DoorwayData>>(128);
|
DisjointSet<IGraphNode<RoomData, DoorwayData>> components = new DisjointSet<IGraphNode<RoomData, DoorwayData>>(128);
|
||||||
|
|
||||||
ordering.add(core);
|
ordering.add(core);
|
||||||
components.makeSet(core);
|
components.makeSet(core);
|
||||||
@@ -492,7 +490,7 @@ public class MazeDesigner
|
|||||||
current = ordering.pop();
|
current = ordering.pop();
|
||||||
subgraph.add(current);
|
subgraph.add(current);
|
||||||
|
|
||||||
for (IEdge<PartitionNode, DoorwayData> edge : current.inbound())
|
for (IEdge<RoomData, DoorwayData> edge : current.inbound())
|
||||||
{
|
{
|
||||||
neighbor = edge.head();
|
neighbor = edge.head();
|
||||||
if (components.makeSet(neighbor))
|
if (components.makeSet(neighbor))
|
||||||
@@ -500,7 +498,7 @@ public class MazeDesigner
|
|||||||
ordering.add(neighbor);
|
ordering.add(neighbor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (IEdge<PartitionNode, DoorwayData> edge : current.outbound())
|
for (IEdge<RoomData, DoorwayData> edge : current.outbound())
|
||||||
{
|
{
|
||||||
neighbor = edge.tail();
|
neighbor = edge.tail();
|
||||||
if (components.makeSet(neighbor))
|
if (components.makeSet(neighbor))
|
||||||
@@ -513,12 +511,12 @@ public class MazeDesigner
|
|||||||
// Now iterate over the list of nodes and merge their sets
|
// Now iterate over the list of nodes and merge their sets
|
||||||
// We only have to look at outbound edges since inbound edges mirror them
|
// We only have to look at outbound edges since inbound edges mirror them
|
||||||
// Also list any Y_AXIS doorways we come across
|
// Also list any Y_AXIS doorways we come across
|
||||||
ArrayList<IEdge<PartitionNode, DoorwayData>> targets =
|
ArrayList<IEdge<RoomData, DoorwayData>> targets =
|
||||||
new ArrayList<IEdge<PartitionNode, DoorwayData>>();
|
new ArrayList<IEdge<RoomData, DoorwayData>>();
|
||||||
|
|
||||||
for (IGraphNode<PartitionNode, DoorwayData> room : subgraph)
|
for (IGraphNode<RoomData, DoorwayData> room : subgraph)
|
||||||
{
|
{
|
||||||
for (IEdge<PartitionNode, DoorwayData> passage : room.outbound())
|
for (IEdge<RoomData, DoorwayData> passage : room.outbound())
|
||||||
{
|
{
|
||||||
if (passage.data().axis() != DoorwayData.Y_AXIS)
|
if (passage.data().axis() != DoorwayData.Y_AXIS)
|
||||||
{
|
{
|
||||||
@@ -535,11 +533,11 @@ public class MazeDesigner
|
|||||||
Collections.shuffle(targets, random);
|
Collections.shuffle(targets, random);
|
||||||
|
|
||||||
// Merge sets together and remove unnecessary doorways
|
// Merge sets together and remove unnecessary doorways
|
||||||
for (IEdge<PartitionNode, DoorwayData> passage : targets)
|
for (IEdge<RoomData, DoorwayData> passage : targets)
|
||||||
{
|
{
|
||||||
if (!components.mergeSets(passage.head(), passage.tail()))
|
if (!components.mergeSets(passage.head(), passage.tail()))
|
||||||
{
|
{
|
||||||
rooms.removeEdge(passage);
|
layout.removeEdge(passage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,13 +546,13 @@ public class MazeDesigner
|
|||||||
components.clear();
|
components.clear();
|
||||||
targets.clear();
|
targets.clear();
|
||||||
|
|
||||||
for (IGraphNode<PartitionNode, DoorwayData> room : subgraph)
|
for (IGraphNode<RoomData, DoorwayData> room : subgraph)
|
||||||
{
|
{
|
||||||
components.makeSet(room);
|
components.makeSet(room);
|
||||||
}
|
}
|
||||||
for (IGraphNode<PartitionNode, DoorwayData> room : subgraph)
|
for (IGraphNode<RoomData, DoorwayData> room : subgraph)
|
||||||
{
|
{
|
||||||
for (IEdge<PartitionNode, DoorwayData> passage : room.outbound())
|
for (IEdge<RoomData, DoorwayData> passage : room.outbound())
|
||||||
{
|
{
|
||||||
if (passage.data().axis() == DoorwayData.Y_AXIS)
|
if (passage.data().axis() == DoorwayData.Y_AXIS)
|
||||||
{
|
{
|
||||||
@@ -567,11 +565,11 @@ public class MazeDesigner
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.shuffle(targets, random);
|
Collections.shuffle(targets, random);
|
||||||
for (IEdge<PartitionNode, DoorwayData> passage : targets)
|
for (IEdge<RoomData, DoorwayData> passage : targets)
|
||||||
{
|
{
|
||||||
if (!components.mergeSets(passage.head(), passage.tail()) && random.nextBoolean())
|
if (!components.mergeSets(passage.head(), passage.tail()) && random.nextBoolean())
|
||||||
{
|
{
|
||||||
rooms.removeEdge(passage);
|
layout.removeEdge(passage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package StevenDimDoors.experimental;
|
||||||
|
|
||||||
|
public class MazeLinkData
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,11 +2,12 @@ package StevenDimDoors.experimental;
|
|||||||
|
|
||||||
import StevenDimDoors.mod_pocketDim.Point3D;
|
import StevenDimDoors.mod_pocketDim.Point3D;
|
||||||
|
|
||||||
public class PartitionNode extends BoundingBox
|
public class PartitionNode<T> extends BoundingBox
|
||||||
{
|
{
|
||||||
private PartitionNode parent;
|
private PartitionNode parent;
|
||||||
private PartitionNode leftChild = null;
|
private PartitionNode leftChild = null;
|
||||||
private PartitionNode rightChild = null;
|
private PartitionNode rightChild = null;
|
||||||
|
private T data = null;
|
||||||
|
|
||||||
public PartitionNode(int width, int height, int length)
|
public PartitionNode(int width, int height, int length)
|
||||||
{
|
{
|
||||||
@@ -122,4 +123,14 @@ public class PartitionNode extends BoundingBox
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setData(T value)
|
||||||
|
{
|
||||||
|
this.data = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getData()
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
75
src/main/java/StevenDimDoors/experimental/RoomData.java
Normal file
75
src/main/java/StevenDimDoors/experimental/RoomData.java
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package StevenDimDoors.experimental;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class RoomData
|
||||||
|
{
|
||||||
|
private int distance;
|
||||||
|
private boolean decayed;
|
||||||
|
private PartitionNode partitionNode;
|
||||||
|
private ArrayList<MazeLinkData> inboundLinks;
|
||||||
|
private ArrayList<MazeLinkData> outboundLinks;
|
||||||
|
private IGraphNode<RoomData, DoorwayData> layoutNode;
|
||||||
|
|
||||||
|
public RoomData(PartitionNode partitionNode)
|
||||||
|
{
|
||||||
|
this.partitionNode = partitionNode;
|
||||||
|
this.inboundLinks = new ArrayList<MazeLinkData>();
|
||||||
|
this.outboundLinks = new ArrayList<MazeLinkData>();
|
||||||
|
this.layoutNode = null;
|
||||||
|
this.distance = -1;
|
||||||
|
this.decayed = false;
|
||||||
|
partitionNode.setData(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PartitionNode getPartitionNode()
|
||||||
|
{
|
||||||
|
return this.partitionNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IGraphNode<RoomData, DoorwayData> getLayoutNode()
|
||||||
|
{
|
||||||
|
return this.layoutNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToLayout(DirectedGraph<RoomData, DoorwayData> layout)
|
||||||
|
{
|
||||||
|
this.layoutNode = layout.addNode(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDecayed()
|
||||||
|
{
|
||||||
|
return decayed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDecayed(boolean value)
|
||||||
|
{
|
||||||
|
this.decayed = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<MazeLinkData> getInboundLinks()
|
||||||
|
{
|
||||||
|
return this.inboundLinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<MazeLinkData> getOutboundLinks()
|
||||||
|
{
|
||||||
|
return this.outboundLinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDistance()
|
||||||
|
{
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDistance(int value)
|
||||||
|
{
|
||||||
|
distance = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
partitionNode = null;
|
||||||
|
layoutNode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user