Added a target coordinate finder.
Implemented DFS name changes.
This commit is contained in:
parent
cf6a371428
commit
f5e3435d8b
@ -0,0 +1,11 @@
|
||||
package ca.recrown.islandsurvivalcraft.pathfinding;
|
||||
|
||||
public interface CoordinateTargetValidatable {
|
||||
/**
|
||||
* Is the current coordinate the objective?
|
||||
* @param x the x of the coordinate.
|
||||
* @param y the y of the coordinate.
|
||||
* @return true if this is the objective coordinate.
|
||||
*/
|
||||
public boolean isCoordinateTarget(int x, int y);
|
||||
}
|
@ -1,35 +1,44 @@
|
||||
package ca.recrown.islandsurvivalcraft.pathfinding;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
|
||||
public class DepthFirstSearch {
|
||||
private PriorityQueue<Node> queue;
|
||||
private Queue<Node> queue;
|
||||
private CoordinateValidatable validatable;
|
||||
private Node startNode;
|
||||
private Node endNode;
|
||||
private ArrayList<Node> checkedNodes;
|
||||
|
||||
public DepthFirstSearch(CoordinateValidatable validatable) {
|
||||
queue = new PriorityQueue<>();
|
||||
this.validatable = validatable;
|
||||
public DepthFirstSearch() {
|
||||
checkedNodes = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void Setup(int xGoal, int yGoal, int x, int y) {
|
||||
startNode = new Node(null, xGoal, yGoal, x, y);
|
||||
|
||||
public DepthFirstSearch(CoordinateValidatable validatable) {
|
||||
this();
|
||||
this.validatable = validatable;
|
||||
}
|
||||
|
||||
public Node getTree() {
|
||||
return startNode;
|
||||
public void setValidatable(CoordinateValidatable validatable) {
|
||||
this.validatable = validatable;
|
||||
}
|
||||
|
||||
public void setStartPosition(int x, int y) {
|
||||
startNode = new Node(null, x, y);
|
||||
}
|
||||
|
||||
public Node getEndNode() {
|
||||
return endNode;
|
||||
public void setEndPosition(int x, int y) {
|
||||
endNode = new Node(null, x, y);
|
||||
}
|
||||
|
||||
public Node getParentOfNode(Node node) {
|
||||
return node.parent;
|
||||
public int getEndX() {
|
||||
return endNode.x;
|
||||
}
|
||||
|
||||
public int getEndY() {
|
||||
return endNode.y;
|
||||
}
|
||||
|
||||
public void deleteTree() {
|
||||
@ -37,14 +46,49 @@ public class DepthFirstSearch {
|
||||
endNode = null;
|
||||
}
|
||||
|
||||
public boolean buildTree() {
|
||||
public boolean buildPathToEndNode() {
|
||||
queue = new PriorityQueue<>();
|
||||
checkedNodes.clear();
|
||||
queue.clear();
|
||||
Node begin = startNode;
|
||||
queue.add(begin);
|
||||
while (!queue.isEmpty()) {
|
||||
Node n = queue.poll();
|
||||
if (!(n.x == n.xGoal && n.y == n.yGoal)) {
|
||||
if (!n.equals(endNode)) {
|
||||
n.child[0] = new Node(n, n.x + 1, n.y);
|
||||
n.child[1] = new Node(n, n.x - 1, n.y);
|
||||
n.child[2] = new Node(n, n.x, n.y + 1);
|
||||
n.child[3] = new Node(n, n.x, n.y - 1);
|
||||
} else {
|
||||
n.shallowCopyTo(endNode);
|
||||
return true;
|
||||
}
|
||||
if (!n.check()) {
|
||||
for (int i = 0; i < n.child.length; i++) {
|
||||
Node child = n.child[i];
|
||||
if (validatable.validate(child.x, child.y)) {
|
||||
queue.add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the end node.
|
||||
* Will not set end node if one wasn't found,
|
||||
* therefore, previous end node data is kept.
|
||||
* @param targetValidator
|
||||
* @return
|
||||
*/
|
||||
public boolean findEndNode(CoordinateTargetValidatable targetValidator) {
|
||||
queue = new LinkedList<>();
|
||||
checkedNodes.clear();
|
||||
Node begin = startNode;
|
||||
queue.add(begin);
|
||||
while (!queue.isEmpty()) {
|
||||
Node n = queue.poll();
|
||||
if (!targetValidator.isCoordinateTarget(n.x, n.y)) {
|
||||
n.child[0] = new Node(n, n.x + 1, n.y);
|
||||
n.child[1] = new Node(n, n.x - 1, n.y);
|
||||
n.child[2] = new Node(n, n.x, n.y + 1);
|
||||
@ -55,8 +99,9 @@ public class DepthFirstSearch {
|
||||
}
|
||||
if (!n.check()) {
|
||||
for (int i = 0; i < n.child.length; i++) {
|
||||
if (validatable.validate(n.child[i].x, n.child[i].y)) {
|
||||
queue.add(n.child[i]);
|
||||
Node child = n.child[i];
|
||||
if (validatable.validate(child.x, child.y)) {
|
||||
queue.add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,49 +111,35 @@ public class DepthFirstSearch {
|
||||
|
||||
private class Node implements Comparable<Node> {
|
||||
public Node[] child;
|
||||
public final Node parent;
|
||||
public Node parent;
|
||||
public int x;
|
||||
public int y;
|
||||
|
||||
private boolean checked = false;
|
||||
private final int xGoal;
|
||||
private final int yGoal;
|
||||
|
||||
public Node(Node parent, int xGoal, int yGoal, int x, int y) {
|
||||
public Node(Node parent, int x, int y) {
|
||||
this.parent = parent;
|
||||
child = new Node[4];
|
||||
this.xGoal = xGoal;
|
||||
this.yGoal = yGoal;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public Node(Node parent, int x, int y) {
|
||||
this(parent, parent.xGoal, parent.yGoal, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Node o) {
|
||||
return Math.round(distanceToGoal() - o.distanceToGoal());
|
||||
return Math.round(distanceToGoal(endNode) - o.distanceToGoal(endNode));
|
||||
}
|
||||
|
||||
public float distanceToGoal() {
|
||||
float distanceX = xGoal - this.x;
|
||||
float distanceY = yGoal - this.y;
|
||||
public float distanceToGoal(Node goal) {
|
||||
float distanceX = goal.x - this.x;
|
||||
float distanceY = goal.y - this.y;
|
||||
float distance = (float) Math.sqrt(distanceX * distanceX + distanceY * distanceY);
|
||||
return distance;
|
||||
}
|
||||
|
||||
public boolean check() {
|
||||
if (!checked) {
|
||||
checked = true;
|
||||
if (checkedNodes.contains(this)) {
|
||||
return true;
|
||||
}
|
||||
checkedNodes.add(this);
|
||||
return false;
|
||||
if (checkedNodes.contains(this)) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
checkedNodes.add(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -121,5 +152,12 @@ public class DepthFirstSearch {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void shallowCopyTo(Node node) {
|
||||
node.child = this.child;
|
||||
node.parent = this.parent;
|
||||
node.x = this.x;
|
||||
node.y = this.y;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package ca.recrown.islandsurvivalcraft.worldgeneration;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
@ -9,12 +10,13 @@ import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandOwnerMetadata;
|
||||
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandShoreBiomeMetadata;
|
||||
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandTUIDMetadata;
|
||||
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandTemperatureMetadata;
|
||||
import ca.recrown.islandsurvivalcraft.pathfinding.CoordinateTargetValidatable;
|
||||
import ca.recrown.islandsurvivalcraft.IslandSurvivalCraft;
|
||||
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandBedrockMetadataHelper;
|
||||
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandMainBiomeMetadata;
|
||||
import ca.recrown.islandsurvivalcraft.islandbedrockmetadata.IslandMetadataPack;
|
||||
|
||||
public class BiomePerIslandGenerator implements IslandBiomeGenerator {
|
||||
public class BiomePerIslandGenerator implements IslandBiomeGenerator, CoordinateTargetValidatable {
|
||||
private IslandMapGenerator mapGenerator;
|
||||
private Biome currentIslandBiome;
|
||||
private float currentIslandTemperature;
|
||||
@ -42,7 +44,7 @@ public class BiomePerIslandGenerator implements IslandBiomeGenerator {
|
||||
int worldZ = chunkZ * 16 + localZ;
|
||||
|
||||
if (mapGenerator.isIsland(worldX, worldZ)) {
|
||||
IslandMetadataPack sameIslandPack = getSurroundingIslandData(world, worldX, worldZ);
|
||||
IslandMetadataPack sameIslandPack = getSurroundingIslandData(worldX, worldZ);
|
||||
if (sameIslandPack != null) {
|
||||
//Old island
|
||||
currentIslandBiome = sameIslandPack.mainBiomeMetadata.getMainBiome();
|
||||
@ -50,6 +52,8 @@ public class BiomePerIslandGenerator implements IslandBiomeGenerator {
|
||||
currentIslandTemperature = sameIslandPack.temperatureMetadata.getTemperature();
|
||||
currentTUID = sameIslandPack.islandTIUDMetadata.getIUID();
|
||||
} else {
|
||||
|
||||
|
||||
//New island
|
||||
currentIslandTemperature = temperatureMapGenerator.getTemperature(worldX, worldZ);
|
||||
currentIslandBiome = biomeSelector.getLandBiome(currentIslandTemperature);
|
||||
@ -67,16 +71,46 @@ public class BiomePerIslandGenerator implements IslandBiomeGenerator {
|
||||
current.setTUID(currentTUID, plugin);
|
||||
metadataHelper.setIslandBedrockMetadataPack(worldX, worldZ, current);
|
||||
|
||||
//Set the biome information for the chunk
|
||||
if (mapGenerator.isShore(worldX, worldZ)) {
|
||||
setBiome(localX, localZ, biome, currentIslandShoreBiome);
|
||||
} else {
|
||||
setBiome(localX, localZ, biome, currentIslandBiome);
|
||||
}
|
||||
|
||||
//Check if island besides this one need to be generated.
|
||||
if (localX == 0 && mapGenerator.isSameIsland(worldX, worldZ, worldX - 1, worldZ)) {
|
||||
if (!world.isChunkGenerated(chunkX - 1, chunkZ)) {
|
||||
Chunk chunk = world.getChunkAt(chunkX - 1, chunkZ);
|
||||
chunk.load(true);
|
||||
chunk.unload(true);
|
||||
}
|
||||
} else if (localX == 15 && mapGenerator.isSameIsland(worldX, worldZ, worldX + 1, worldZ)) {
|
||||
if (!world.isChunkGenerated(chunkX + 1, chunkZ)) {
|
||||
Chunk chunk = world.getChunkAt(chunkX + 1, chunkZ);
|
||||
chunk.load(true);
|
||||
chunk.unload(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (localZ == 0 && mapGenerator.isSameIsland(worldX, worldZ, worldX, worldZ - 1)) {
|
||||
if (!world.isChunkGenerated(chunkX, chunkZ - 1)) {
|
||||
Chunk chunk = world.getChunkAt(chunkX, chunkZ - 1);
|
||||
chunk.load(true);
|
||||
chunk.unload(true);
|
||||
}
|
||||
} else if (localZ == 15 && mapGenerator.isSameIsland(worldX, worldZ, worldX, worldZ + 1)) {
|
||||
if (!world.isChunkGenerated(chunkX, chunkZ + 1)) {
|
||||
Chunk chunk = world.getChunkAt(chunkX, chunkZ + 1);
|
||||
chunk.load(true);
|
||||
chunk.unload(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private IslandMetadataPack getSurroundingIslandData(World world, int worldX, int worldZ) {
|
||||
private IslandMetadataPack getSurroundingIslandData(int worldX, int worldZ) {
|
||||
IslandMetadataPack data = null;
|
||||
if (mapGenerator.isSameIsland(worldX, worldZ, worldX + 1, worldZ)) {
|
||||
data = getMetadataPackAt(worldX + 1, worldZ, world);
|
||||
@ -114,4 +148,10 @@ public class BiomePerIslandGenerator implements IslandBiomeGenerator {
|
||||
biomeGrid.setBiome(localX, y, localZ, biome);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCoordinateTarget(int x, int y) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -140,8 +140,9 @@ public class IslandMapGenerator implements CoordinateValidatable {
|
||||
public boolean isSameIsland(int firstBlockX, int firstBlockZ, int secondBlockX, int secondBlockZ) {
|
||||
if (!isIsland(firstBlockX, firstBlockZ)) return false;
|
||||
if (!isIsland(secondBlockX, secondBlockZ)) return false;
|
||||
dfs.Setup(secondBlockX, secondBlockZ, firstBlockX, firstBlockZ);
|
||||
boolean res = dfs.buildTree();
|
||||
dfs.setStartPosition(firstBlockX, firstBlockZ);
|
||||
dfs.setEndPosition(secondBlockX, secondBlockZ);
|
||||
boolean res = dfs.buildPathToEndNode();
|
||||
dfs.deleteTree();
|
||||
return res;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package ca.recrown.islandsurvivalcraft.pathfinding;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ -15,96 +16,143 @@ import org.junit.jupiter.api.TestInstance.Lifecycle;
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
public class DepthFirstSearchTest {
|
||||
|
||||
private class Validator implements CoordinateValidatable {
|
||||
private boolean[][] map;
|
||||
private class Validator implements CoordinateValidatable, CoordinateTargetValidatable {
|
||||
private byte[][] map;
|
||||
|
||||
public Validator(boolean[][] map) {
|
||||
public Validator(byte[][] map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(int x, int y) {
|
||||
try {
|
||||
return map[y][x];
|
||||
return map[y][x] >= 1;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCoordinateTarget(int x, int y) {
|
||||
try {
|
||||
return map[y][x] == 2;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
private DepthFirstSearch dfs;
|
||||
|
||||
private boolean[][] mapA = new boolean[][] {
|
||||
{true, true},
|
||||
{true, false},
|
||||
{true, true}
|
||||
private byte[][] mapA = new byte[][] {
|
||||
{1, 1},
|
||||
{1, 0},
|
||||
{1, 1}
|
||||
};
|
||||
|
||||
private boolean[][] mapB = new boolean[][] {
|
||||
{true, true, true, true},
|
||||
{true, false, false, false},
|
||||
{true, true, true, true}
|
||||
private byte[][] mapB = new byte[][] {
|
||||
{1, 1, 1, 1},
|
||||
{1, 0, 0, 0},
|
||||
{1, 2, 1, 1}
|
||||
};
|
||||
|
||||
private boolean[][] mapC = new boolean[][] {
|
||||
{true, true, true, true},
|
||||
{false, false, false, false},
|
||||
{true, true, true, true}
|
||||
private byte[][] mapC = new byte[][] {
|
||||
{1, 1, 1, 1},
|
||||
{0, 0, 0, 0},
|
||||
{1, 1, 1, 1}
|
||||
};
|
||||
|
||||
private boolean[][] mapD = new boolean[][] {
|
||||
{true, true, true, true},
|
||||
{false, false, false, true},
|
||||
{true, true, true, true},
|
||||
{true, false, false, false},
|
||||
private byte[][] mapD = new byte[][] {
|
||||
{1, 1, 1, 1},
|
||||
{0, 0, 0, 1},
|
||||
{1, 1, 1, 1},
|
||||
{2, 0, 0, 0},
|
||||
};
|
||||
|
||||
private boolean[][] mapE = new boolean[][] {
|
||||
{true, true, true, true},
|
||||
{false, false, false, false},
|
||||
{true, true, true, true},
|
||||
{true, false, false, false},
|
||||
private byte[][] mapE = new byte[][] {
|
||||
{1, 1, 1, 1},
|
||||
{0, 0, 0, 0},
|
||||
{1, 1, 1, 1},
|
||||
{1, 0, 2, 0},
|
||||
};
|
||||
|
||||
@BeforeAll
|
||||
protected void setUp() {
|
||||
dfs = new DepthFirstSearch();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDFSMapAValid()
|
||||
public void testDFSBuildPathToEndNodeMapAValid()
|
||||
{
|
||||
DepthFirstSearch dfs = new DepthFirstSearch(new Validator(mapA));
|
||||
dfs.Setup(1, 0, 1, 2);
|
||||
assertTrue(dfs.buildTree());
|
||||
dfs.setValidatable(new Validator(mapA));
|
||||
dfs.setStartPosition(1, 2);
|
||||
dfs.setEndPosition(1, 0);
|
||||
assertTrue(dfs.buildPathToEndNode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDFSMapBValid()
|
||||
public void testDFSBuildPathToEndNodeMapBValid()
|
||||
{
|
||||
DepthFirstSearch dfs = new DepthFirstSearch(new Validator(mapB));
|
||||
dfs.Setup(3, 2, 3, 0);
|
||||
assertTrue(dfs.buildTree());
|
||||
dfs.setValidatable(new Validator(mapB));
|
||||
dfs.setStartPosition(3, 0);
|
||||
dfs.setEndPosition(3, 2);
|
||||
assertTrue(dfs.buildPathToEndNode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDFSMapDValid()
|
||||
public void testDFSBuildPathToEndNodeMapDValid()
|
||||
{
|
||||
DepthFirstSearch dfs = new DepthFirstSearch(new Validator(mapD));
|
||||
dfs.Setup(0, 3, 0, 0);
|
||||
assertTrue(dfs.buildTree());
|
||||
dfs.setValidatable(new Validator(mapD));
|
||||
dfs.setStartPosition(0, 0);
|
||||
dfs.setEndPosition(0, 3);
|
||||
assertTrue(dfs.buildPathToEndNode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDFSMapCInvalid()
|
||||
public void testDFSBuildPathToEndNodeMapCInvalid()
|
||||
{
|
||||
DepthFirstSearch dfs = new DepthFirstSearch(new Validator(mapC));
|
||||
dfs.Setup(3, 2, 3, 0);
|
||||
assertFalse(dfs.buildTree());
|
||||
dfs.setValidatable(new Validator(mapC));
|
||||
dfs.setStartPosition(3, 0);
|
||||
dfs.setEndPosition(3, 2);
|
||||
assertFalse(dfs.buildPathToEndNode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDFSMapEInvalid()
|
||||
public void testDFSBuildPathToEndNodeMapEInvalid()
|
||||
{
|
||||
DepthFirstSearch dfs = new DepthFirstSearch(new Validator(mapE));
|
||||
dfs.Setup(3, 2, 3, 0);
|
||||
assertFalse(dfs.buildTree());
|
||||
dfs.setValidatable(new Validator(mapE));
|
||||
dfs.setStartPosition(3, 0);
|
||||
dfs.setEndPosition(3, 2);
|
||||
assertFalse(dfs.buildPathToEndNode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDFSFindEndNodeMapBValid() {
|
||||
Validator validator = new Validator(mapB);
|
||||
dfs.setValidatable(validator);
|
||||
dfs.setStartPosition(3, 0);
|
||||
|
||||
assertTrue(dfs.findEndNode(validator));
|
||||
assertEquals(1, dfs.getEndX());
|
||||
assertEquals(2, dfs.getEndY());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDFSFindEndNodeMapDValid() {
|
||||
Validator validator = new Validator(mapD);
|
||||
dfs.setValidatable(validator);
|
||||
dfs.setStartPosition(0, 0);
|
||||
|
||||
assertTrue(dfs.findEndNode(validator));
|
||||
assertEquals(0, dfs.getEndX());
|
||||
assertEquals(3, dfs.getEndY());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDFSFindEndNodeMapEInvalid() {
|
||||
Validator validator = new Validator(mapE);
|
||||
dfs.setValidatable(validator);
|
||||
dfs.setStartPosition(0, 0);
|
||||
|
||||
assertFalse(dfs.findEndNode(validator));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user