package propra2012.gruppe33.bomberman.ai.ninja; import java.awt.Point; /** * This class is a utility abstract data type and uses the Dijkstra algorithm to * get the closest path to all other pathfinders in the grid from a certain * start parthfinder. * * @author Malte * */ public class Pathfinder extends Point { /** * Is now serializable. */ private static final long serialVersionUID = 1L; /** * This variable points at another pathfinder. If the dijkstra algorithm has * checked all pathfinders one simply can follow the path that is pointed by * the "goal pathfinder" to the "start pathfinder". */ private Pathfinder predecessor; /** * The distance from the "start pathfinder" to this. May be not correct if * dijkstra has not completely run jet. Mainly used in dijkstra. */ private float distance; /** * The number of pathfinders that are needed to reach this from the * "start pathfinder". Like distance it may be not correct if dijkstra is * not complete. */ private int count; /** * Used in dijkstra to check whether the pathfinder already were checked by * dijkstra. */ private boolean visited; /** * Simply indicates what speed is used. It get's accommodated by * lowestUncheckedConnection and is used by dijkstra. Thus it does not need * Getter and Setter. */ private char indicator; /* * The following variables are used to connect the grid and point on another * pathfinder or determine the speed in the given direction. If their is no * pathfinder in the given direction, this points on itself and the speed is * 0. in the further documentary i will refer to them as connections. */ private Pathfinder north; private float speedNorth = java.lang.Float.MAX_VALUE; private Pathfinder east; private float speedEast = java.lang.Float.MAX_VALUE; private Pathfinder south; private float speedSouth = java.lang.Float.MAX_VALUE; private Pathfinder west; private float speedWest = java.lang.Float.MAX_VALUE; /** * Default constructor. Sets the Distance to 1000, because this value should * never be reached in the game and is therefore used as a default value. * Before running dijkstra distance should always be set to 1000. */ public Pathfinder(int x, int y) { this.distance = 1000; this.x = x; this.y = y; this.count = 0; } /** * Just a lot of if-checks whether their is an unchecked Connection to * another pathfinder. Used in dijkstra. * * @return this if their is no unchecked connection. Else return the * connection with the lowest speed. */ public Pathfinder lowestUncheckedConnection() { // System.out.println(speedNorth); // System.out.println(speedEast); // System.out.println(speedSouth); // System.out.println(speedWest); if ((north != this) && (!north.isVisited()) && (speedNorth <= speedEast) && (speedNorth <= speedSouth) && (speedNorth <= speedWest)) { indicator = 'n'; return north; } else if ((east != this) && (!east.isVisited()) && (speedEast <= speedNorth) && (speedEast <= speedSouth) && (speedEast <= speedWest)) { indicator = 'e'; return east; } else if ((south != this) && (!south.isVisited()) && (speedSouth <= speedNorth) && (speedSouth <= speedEast) && (speedSouth <= speedWest)) { indicator = 's'; return south; } else if ((west != this) && (!west.isVisited()) && (speedWest <= speedNorth) && (speedWest <= speedEast) && (speedWest <= speedSouth)) { indicator = 'w'; return west; } else { return this; } } /** * This method is a recursive implementation of the dijkstra algorithm. It * checks all connections of this, whether their distance to this plus the * distance from the "start pathfinder" is lower than their current * distance. If thats the case it, changes their predecessor to this and * accommodates the speed. * * @param wayTillHere * describes the distance of the "start pathfinder" till the * pathfinder from where dijkstra is started. Dijkstra may be * started with the value of wayTillHere=0. */ public void dijkstra(float wayTillHere) { // First: Set visited to true. Otherwise lowestUncheckedConnection could // find this by mistake. visited = true; // Checks all connections. Up to four times. if (north != this) { checkUp(north, wayTillHere + speedNorth); } if (east != this) { checkUp(east, wayTillHere + speedEast); } if (south != this) { checkUp(south, wayTillHere + speedSouth); } if (west != this) { checkUp(west, wayTillHere + speedWest); } // The Pathfinder that will be the next for dijkstra. Pathfinder next = this.lowestUncheckedConnection(); float speed = 0; // what speed will be used next? while (next != this) { switch (indicator) { case 'n': speed = wayTillHere + speedNorth; break; case 'e': speed = wayTillHere + speedEast; break; case 's': speed = wayTillHere + speedSouth; break; case 'w': speed = wayTillHere + speedWest; break; } next.dijkstra(speed); next = this.lowestUncheckedConnection(); } } /** * Part of the dijkstra algorithm. Needs to be checked in all directions to * get the shortest path. * * @param target * The connection in which direction is currently checked. * @param speed * The speed of the current checked connection. */ private void checkUp(Pathfinder target, float speed) { // speed += this.distance; if (target.getDistance() > speed) { target.setDistance(speed); target.setPredecessor(this); target.setCount(count + 1); } } /* * __________________________________________________________________________________________ * From here on only Getters and Setters for variables. */ public Pathfinder getPredecessor() { return predecessor; } public void setPredecessor(Pathfinder predecessor) { this.predecessor = predecessor; } public float getDistance() { return distance; } public void setDistance(float distance) { this.distance = distance; } public boolean isVisited() { return visited; } public void setVisited(boolean visited) { this.visited = visited; } public Pathfinder getNorth() { return north; } public void setNorth(Pathfinder north) { this.north = north; } public float getSpeedNorth() { return speedNorth; } public void setSpeedNorth(float speedNorth) { this.speedNorth = speedNorth; } public Pathfinder getEast() { return east; } public void setEast(Pathfinder east) { this.east = east; } public float getSpeedEast() { return speedEast; } public void setSpeedEast(float speedEast) { this.speedEast = speedEast; } public Pathfinder getSouth() { return south; } public void setSouth(Pathfinder south) { this.south = south; } public float getSpeedSouth() { return speedSouth; } public void setSpeedSouth(float speedSouth) { this.speedSouth = speedSouth; } public Pathfinder getWest() { return west; } public void setWest(Pathfinder west) { this.west = west; } public float getSpeedWest() { return speedWest; } public void setSpeedWest(float speedWest) { this.speedWest = speedWest; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } }