package greymerk.roguelike.util.mst;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import greymerk.roguelike.util.graph.Edge;
import greymerk.roguelike.util.graph.Graph;
import greymerk.roguelike.worldgen.Cardinal;
import greymerk.roguelike.worldgen.Coord;
import greymerk.roguelike.worldgen.IBlockFactory;
import greymerk.roguelike.worldgen.IWorldEditor;
import greymerk.roguelike.worldgen.shapes.RectHollow;
public class MinimumSpanningTree{
List<MSTPoint> points;
Set<Edge<MSTPoint>> mstEdges;
public MinimumSpanningTree(Random rand, int size, int edgeLength){
this(rand, size, edgeLength, new Coord(0, 0, 0));
}
public MinimumSpanningTree(Random rand, int size, int edgeLength, Coord origin){
points = new ArrayList<MSTPoint>();
mstEdges = new HashSet<Edge<MSTPoint>>();
int offset = size / 2 * edgeLength;
for(int i = 0; i < size; ++i){
Coord temp = new Coord(origin);
temp.add(Cardinal.NORTH, offset);
temp.add(Cardinal.WEST, offset);
temp.add(Cardinal.SOUTH, edgeLength * i);
for(int j = 0; j < size; ++j){
points.add(new MSTPoint(new Coord(temp), rand));
temp.add(Cardinal.EAST, edgeLength);
}
}
ArrayList<Edge<MSTPoint>> edges = new ArrayList<Edge<MSTPoint>>();
for(MSTPoint p : points){
for(MSTPoint o : points){
if(p.equals(o)) continue;
edges.add(new Edge<MSTPoint>(p,o, p.distance(o)));
}
}
Collections.sort(edges);
for(Edge<MSTPoint> e : edges){
MSTPoint start = e.getStart();
MSTPoint end = e.getEnd();
if(find(start) == find(end)) continue;
union(start, end);
mstEdges.add(e);
}
}
private void union(MSTPoint a, MSTPoint b){
MSTPoint root1 = find(a);
MSTPoint root2 = find(b);
if(root1 == root2) return;
if(root1.getRank() > root2.getRank()){
root2.setParent(root1);
} else {
root1.setParent(root2);
if(root1.getRank() == root2.getRank()){
root2.incRank();
}
}
}
private MSTPoint find(MSTPoint p){
if(p.getParent() == p) return p;
p.setParent(find(p.getParent()));
return p.getParent();
}
public void generate(IWorldEditor editor, Random rand, IBlockFactory blocks, Coord pos){
for(Edge<MSTPoint> e : this.mstEdges){
Coord start = e.getStart().getPosition();
start.add(pos);
Coord end = e.getEnd().getPosition();
end.add(pos);
RectHollow.fill(editor, rand, start, end, blocks);
}
}
public List<Edge<MSTPoint>> getEdges(){
List<Edge<MSTPoint>> toReturn = new ArrayList<Edge<MSTPoint>>();
toReturn.addAll(this.mstEdges);
return toReturn;
}
public Graph<Coord> getGraph(){
Graph<Coord> layout = new Graph<Coord>();
for(Edge<MSTPoint> e : this.mstEdges){
Coord start = e.getStart().getPosition();
Coord end = e.getEnd().getPosition();
layout.addEdge(new Edge<Coord>(start, end, start.distance(end)));
}
return layout;
}
}