/**
* Copyright 2014
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loon
* @author cping
* @email javachenpeng@yahoo.com
* @version 0.4.2
*/
package loon.action.map;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ArrayInt2DAStar {
public static interface TileFactory<T> {
public T create(int m, int n);
}
public static interface Map {
public int[][] adjacent(int[] position);
public boolean reachable(int[] position);
public int roughness(int[] position);
public int baseRoughness();
public int distance(int[] start, int[] end);
}
protected static class Node implements Comparable<Node> {
int[] position;
int f, g, h;
Node parent;
public Node(int[] position) {
this.position = position.clone();
}
public boolean equals(int[] position) {
return this.position[0] == position[0]
&& this.position[1] == position[1];
}
@Override
public int compareTo(Node another) {
int result = this.f - another.f;
if (result == 0) {
result = this.h - another.h;
;
}
return result;
}
}
protected static class NodeList extends ArrayList<Node> {
private static final long serialVersionUID = 1L;
public Node find(int[] position) {
for (int i = size() - 1; i >= 0; i--) {
Node node = get(i);
if (node.equals(position)) {
return node;
}
}
return null;
}
public void insert(Node node) {
for (int i = size(); i > 0; i--) {
Node n = get(i - 1);
if (node.compareTo(n) >= 0) {
add(i, node);
return;
}
}
add(0, node);
}
public void sort(Node node) {
for (int i = size() - 1; i >= 0; i--) {
Node n = get(i);
if (n == node) {
for (; i > 0; i--) {
n = get(i - 1);
if (node.compareTo(n) >= 0) {
return;
} else {
set(i, n);
set(i - 1, node);
}
}
}
}
}
}
public static class Path {
public List<int[]> positions;
public int cost;
}
public static Path findPath(ArrayInt2DAStar.Map map, int[] start, int[] end) {
return findPath(map, start, end, 0);
}
public static Path findPath(ArrayInt2DAStar.Map map, int[] start,
int[] end, int endRadius) {
NodeList openNodes = new NodeList();
NodeList closedNodes = new NodeList();
openNodes.add(new Node(start));
Node found = null;
for(;;) {
if (openNodes.isEmpty()) {
return null;
}
Node node = openNodes.remove(0);
int distance = map.distance(node.position, end);
if (distance <= endRadius) {
found = node;
break;
}
closedNodes.add(node);
int[][] positions = map.adjacent(node.position);
for (int[] position : positions) {
if (!map.reachable(position)) {
continue;
}
if (closedNodes.find(position) != null) {
continue;
}
Node openNode = openNodes.find(position);
if (openNode == null) {
Node newNode = new Node(position);
newNode.g = node.g + map.roughness(position);
newNode.h = map.distance(position, end)
* map.baseRoughness();
newNode.f = newNode.g + newNode.h;
newNode.parent = node;
openNodes.insert(newNode);
} else {
int g = node.g + map.roughness(position);
if (openNode.g > g) {
openNode.g = g;
openNode.f = openNode.g + openNode.h;
openNode.parent = node;
openNodes.sort(openNode);
}
}
}
}
if (found == null) {
return null;
}
Path path = new Path();
path.cost = found.g;
LinkedList<int[]> positions = new LinkedList<int[]>();
while (found != null) {
positions.addFirst(found.position.clone());
found = found.parent;
}
path.positions = positions;
return path;
}
}