package de.stealmycode.beehive.model.world; import java.util.Collection; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.PriorityQueue; import de.stealmycode.beehive.model.world.animals.AbstractMovableObject; import de.stealmycode.beehive.utils.Position; public class Pathfinder { private class Item { public Item(Position position, int priority) { this.position = position; this.priority = priority; } int g; Item predecessor = null; Position position; int priority; // // private boolean equals(Item item) { // if (g != item.g) return false; // if (priority != item.priority) return false; // if (!predecessor.equals(item.predecessor)) return false; // if (!position.equals(item.position)) return false; // return true; // } // // // @Override // public boolean equals(Object obj) { // if (obj instanceof Item) { // return equals((Item)obj); // } else if (obj instanceof Position) { // return position.equals(obj); // } // return false; // } } private class ItemComparator implements Comparator<Item> { @Override public int compare(Item o1, Item o2) { return o1.priority - o2.priority; } } private World world; private AbstractMovableObject object; private PriorityQueue<Item> openList = new PriorityQueue<>(11, new ItemComparator()); private List<Item> closedList = new LinkedList<Item>(); /** * * @param world * @param object */ public Pathfinder(World world, AbstractMovableObject object) { this.world = world; this.object = object; } /** * Calculate the distance between source and target position and use this * as prediction for the path length * * @param source source position * @param target target position * @return */ private static int predictDistance(Position source, Position target) { int x = source.getX() - target.getX(); int y = source.getY() - target.getY(); int c = (int)Math.ceil(Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))); return c; } /** * * @param start * @param end * @return */ public List<Position> calculate(Position start, Position end) { openList.add(new Item(start, 0)); do { Item current = openList.remove(); if (current.position.equals(end)) { return getPath(current); } expandNode(current, end); closedList.add(current); if (current.g > 1000) return null; } while (!openList.isEmpty()); return null; } /** * * @param currentItem */ private void expandNode(Item currentItem, Position end) { Field currentField = world.getField(currentItem.position); for (Field field : world.getNeighbourFields(currentField)) { if (!object.canStepOn(field)) { continue; } Position position = field.getPosition(); if (containsPosition(closedList, position)) { continue; } int temp_g = currentItem.g + 1; if(containsPosition(openList, position) && temp_g >= currentItem.g){ continue; } int f = temp_g + predictDistance(position, end); Item item = new Item(position, f); item.predecessor = currentItem; item.g = temp_g; Item i = getItem(openList, position); if (i != null) { openList.remove(i); openList.add(item); } else { openList.add(item); } } } /** * Check whether a collection of items contains a position * * @param c * @param p * @return */ private boolean containsPosition(Collection<Item> c, Position p) { return getItem(c, p) != null; } /** * Get the item containing the specified position * * @param c * @param p * @return */ private Item getItem(Collection<Item> c, Position p) { for (Item i : c) { if (i.position.equals(p)) return i; } return null; } /** * * @param i * @return */ private List<Position> getPath(Item i) { List<Position> result = new LinkedList<Position>(); while (i.predecessor != null) { result.add(i.position); i = i.predecessor; } return result; } }