Advertisement
Guest User

Pathfinder

a guest
Dec 30th, 2015
352
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5.49 KB | None | 0 0
  1. import java.util.ArrayList;
  2. import java.util.Iterator;
  3. import java.util.List;
  4.  
  5. import com.gpg.forest.game.Level;
  6. import com.gpg.forest.util.Vector2;
  7.  
  8. /*
  9.  * Pathfinder inspired by post by Rayvolution on java-gaming.org
  10.  * http://www.java-gaming.org/topics/slick2d-retro-pixel-castles/33101/view.html
  11.  */
  12.  
  13. public class Pathfinder {
  14.  
  15.     private final byte UNCHECKED = 0;
  16.     private final byte CHECKED = 1;
  17.    
  18.     public enum Direction{
  19.        
  20.         N(0, -1, 0x96E5FF),
  21.         S(0, 1, 0xA2F536),
  22.         E(1, 0, 0x363636),
  23.         W(-1, 0, 0xDBDBDB),
  24.         NE(1, -1, 0xEA4AFF),
  25.         SE(1, 1, 0xFF0000),
  26.         SW(-1, 1, 0x005EFF),
  27.         NW(-1, -1, 0xFFE100);
  28.        
  29.         public int xo, yo;
  30.         public int color; //Used for visualising direction
  31.        
  32.         Direction(int xo, int yo, int color){
  33.             this.xo = xo;
  34.             this.yo = yo;
  35.             this.color = color;
  36.         }
  37.     }
  38.    
  39.     private Level level;
  40.    
  41.     private byte[][] tileStatus;
  42.    
  43.     private List<TileInfo> masterArray;
  44.     private List<TileInfo> tempArray;
  45.     private boolean routeBlocked;
  46.    
  47.     private double startTime;
  48.    
  49.     public Pathfinder(Level level){
  50.         this.level = level;
  51.        
  52.         tileStatus = new byte[level.getWidth()][level.getHeight()];
  53.         masterArray = new ArrayList<TileInfo>();
  54.         tempArray = new ArrayList<TileInfo>();
  55.         routeBlocked = true;
  56.        
  57.         startTime = 0;
  58.  
  59.         for(int y = 0; y < level.getHeight(); y++){
  60.             for(int x = 0; x < level.getWidth(); x++){
  61.                 if(level.getTile(x, y).isSolid()) tileStatus[x][y] = CHECKED;
  62.                 else tileStatus[x][y] = UNCHECKED;
  63.             }
  64.         }
  65.     }
  66.    
  67.     public class TileInfo{
  68.         public Vector2 pos;
  69.         public TileInfo parentInfo;
  70.         public Direction dirToParent;
  71.        
  72.         public TileInfo(Vector2 pos, TileInfo parentInfo, Direction dirToParent){
  73.             this.pos = pos;
  74.             this.parentInfo = parentInfo;
  75.             this.dirToParent = dirToParent;
  76.         }
  77.        
  78.         @Override
  79.         public String toString(){
  80.             return "(" + pos.toString() + ") ParentDir: " + dirToParent.name();
  81.         }
  82.     }
  83.    
  84.     public List<TileInfo> findPath(Vector2 start, Vector2 target){
  85.         System.out.println("Finding path between: " + start.toString() + " and " + target.toString());
  86.        
  87.         //Add the target tile to the master array to be checked.
  88.         TileInfo destInfo =  new TileInfo(new Vector2(target.x, target.y), null, null);
  89.         checkTile(target, destInfo, null);
  90.         masterArray.remove(destInfo);
  91.        
  92.         startTime = System.nanoTime();
  93.         int tries = 0;
  94.        
  95.         //Loop over master array, keep checking tiles till start has been reached
  96.         while(true){
  97.             tries++;
  98.             routeBlocked = true;
  99.             //Use an iterator to loop master array so objects can be removed
  100.             Iterator<TileInfo> i = masterArray.iterator();
  101.             while(i.hasNext()){
  102.                 TileInfo info = i.next();
  103.                 checkTile(info.pos, info, i);
  104.                
  105.                 //If start is reached, return the route from start to target
  106.                 if(info.pos.x == start.x && info.pos.y == start.y){
  107.                     return getShortestRoute(info);
  108.                 }
  109.             }
  110.            
  111.             //The route is blocked, cannot find path.
  112.             if(routeBlocked && tries > 1){
  113.                 System.out.println("Route is blocked, took " + tries + " tries in " + ((System.nanoTime() - startTime) / 1000000) + "ms");
  114.                 clearArrays();
  115.                 return null;
  116.             }
  117.            
  118.             //Add TileInfo objects from temp array into master array, clear the temp array
  119.             masterArray.clear();
  120.             masterArray.addAll(tempArray);
  121.             tempArray.clear();
  122.            
  123.             //Return null if its taken too long
  124.             if(tries > 10000){
  125.                 System.out.println("Could not find short enough path");
  126.                 clearArrays();
  127.                 return null;
  128.             }
  129.         }
  130.     }
  131.    
  132.     private List<TileInfo> getShortestRoute(TileInfo info){
  133.         List<TileInfo> shortestRoute = new ArrayList<TileInfo>();
  134.  
  135.         shortestRoute.add(info);
  136.        
  137.         while(true){
  138.             TileInfo parentInfo = shortestRoute.get(shortestRoute.size() - 1).parentInfo;
  139.             if(parentInfo != null){
  140.                 shortestRoute.add(parentInfo);
  141.             }else{
  142.                 System.out.println("Found path in " + ((System.nanoTime() - startTime) / 1000000) + "ms");
  143.                 System.out.println("Array Size: " + masterArray.size() + " to find path length " + shortestRoute.size());
  144.                 clearArrays();
  145.                 return shortestRoute;
  146.             }  
  147.         }                  
  148.     }
  149.  
  150.     //Check the tiles around a parent tile
  151.     private void checkTile(Vector2 pos, TileInfo parentInfo, Iterator<TileInfo> i){
  152.         //Check tiles around parent tile
  153.         for(Direction dir : Direction.values()) checkNeighbour(pos.x + dir.xo, pos.y + dir.yo, dir, parentInfo);
  154.        
  155.         //Parent tile has been checked can be removed from master array (through Iterator) to save looping over previously checked tiles.
  156.         tileStatus[pos.x][pos.y] = CHECKED;
  157.         if(i != null) i.remove();
  158.     }
  159.    
  160.    
  161.     private void checkNeighbour(int x, int y, Direction dir, TileInfo parentInfo){
  162.         //Check if out of bounds or previously checked
  163.         if(checkBounds(x, y)) return;
  164.         if(tileStatus[x][y] == CHECKED) return;
  165.        
  166.         //A new traversable has been found, therefore the route can't be blocked yet
  167.         routeBlocked = false;  
  168.        
  169.         //Add the TileInfo to the temp array. Tile is now checked
  170.         tempArray.add(new TileInfo(new Vector2(x, y), parentInfo, findOppositeDir(dir)));
  171.         tileStatus[x][y] = CHECKED;
  172.     }
  173.    
  174.     //Get the opposite of a direction
  175.     private Direction findOppositeDir(Direction dir){
  176.         for(Direction d : Direction.values()) if(dir.xo * -1 == d.xo && dir.yo * -1 == d.yo) return d;
  177.         return null;
  178.     }
  179.        
  180.     private boolean checkBounds(int x, int y){
  181.         return checkBounds(new Vector2(x, y));
  182.     }
  183.    
  184.     private boolean checkBounds(Vector2 pos){
  185.         return pos.x < 0 || pos.y < 0 || pos.x >= level.getWidth() || pos.y >= level.getHeight();
  186.     }
  187.    
  188.     private void clearArrays(){
  189.         masterArray.clear();
  190.         tempArray.clear();
  191.     }
  192. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement