package com.game.libgdx.roguelikeengine.pathing;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import com.game.libgdx.roguelikeengine.Chest;
import com.game.libgdx.roguelikeengine.Map;
import com.game.libgdx.roguelikeengine.MovingTileOccupier;
import com.game.libgdx.roguelikeengine.ObjectTileOccupier;
import com.game.libgdx.roguelikeengine.Tile;
import com.game.libgdx.roguelikeengine.WrapperEngine;
public class AStar<T extends MovingTileOccupier> implements Path<T> {
protected static final LinkedList<Long> times = new LinkedList<Long>();
protected LinkedHashSet<Tile> opened = new LinkedHashSet<Tile>();
protected LinkedHashSet<Tile> closed = new LinkedHashSet<Tile>();
protected HashMap<Tile, Tile> parentRecord = new HashMap<Tile, Tile>();
protected LinkedList<Tile> result = new LinkedList<Tile>();
protected int currentIndex = 0;
protected Tile current;
protected Map map;
protected Tile start;
protected Tile end;
protected boolean pathFound = false;
protected long timeSearchStarted = 0l;
public AStar(Map map, Tile start, Tile end) {
this.map = map;
this.start = start;
this.end = end;
}
public void search() {
parentRecord.clear();
result.clear();
opened.clear();
closed.clear();
open(start);
Tile current = null;
timeSearchStarted = System.currentTimeMillis();
long tooLong = Math.max(100L, AStar.getAverageSearchTime() * 2L);
List<Tile> neighbors = null;
while(opened.size() > 0) {
current = getLowestCost();
if(current == end) {
close(current);
break;
}
neighbors = map.getmooreneighbors(current);
for(Tile tile : neighbors) {
if((tile.isbloqued() && tile != end) || tile == current) continue;
if(tile != end && map.isAccessPoint(tile.getcolumn(), tile.getrow())) continue;
if(closed.contains(tile)) {
} else if(opened.contains(tile)) {
} else {
this.setParent(tile, current);
open(tile);
}
}
close(current);
if(System.currentTimeMillis() - timeSearchStarted > tooLong) {
return;
}
}
if(current == end) {
while(current != null) {
result.add(current);
current = getParent(current);
}
Collections.reverse(result);
}
if(result.size() > 0) {
this.times.add(System.currentTimeMillis() - timeSearchStarted);
this.pathFound = true;
currentIndex = 0;
}
}
public void open(Tile tile) {
closed.remove(tile);
opened.add(tile);
}
public void close(Tile tile) {
closed.add(tile);
opened.remove(tile);
}
public Tile getParent(Tile tile) {
return parentRecord.get(tile);
}
public void setParent(Tile child, Tile parent) {
parentRecord.put(child, parent);
}
public Tile getLowestCost() {
Tile result = null;
Iterator<Tile> iter = opened.iterator();
Tile current = null;
float lowest = Float.MAX_VALUE;
while(iter.hasNext() && (current = iter.next()) != null) {
if(result == null || getCost(current) < lowest) {
lowest = getCost(current);
result = current;
}
}
return result;
}
public float getCost(Tile tile) { // basic manhatten
float xDiff = tile.getcolumn() - end.getcolumn();
float yDiff = tile.getrow() - end.getrow();
float cost = 0.5f * (xDiff * xDiff + yDiff * yDiff);
return cost;
}
@Override
public Tile getNext() {
Tile current = result.get(currentIndex++);
Tile next = null;
if(currentIndex < result.size()) {
next = result.get(currentIndex);
} else {
currentIndex--;
}
return next != null ? next : current;
}
@Override
public Tile getCurrent() {
return current;
}
@Override
public Tile getStart() {
return start;
}
@Override
public Tile getEnd() {
return end;
}
@Override
public boolean isCompletePath() {
return pathFound;
}
public static long getAverageSearchTime() {
long accum = 0L;
for(Long value : times) {
accum += value;
}
return times.size() > 0 ? accum / times.size() : 0L;
}
}