Skip to content
Permalink
Browse files

Release 1.4.5.2 (#79)

* #77: Drag path does not seem to be working correctly.

	* Tweaked the A* algorithm for more natural/straighter moves though
open spaces for both square and hex grids
	* Tweaked the A* algorithm to find shortest path more consistently

Task-Url: #77

Signed-off-by: Jamz <Jamz@Nerps.net>

* #77: Drag path does not seem to be working correctly.

 * Change log amended
 * Spotless applied

Task-Url: #77

Signed-off-by: Jamz <Jamz@Nerps.net>
  • Loading branch information...
JamzTheMan committed Jun 24, 2018
1 parent fd9a03b commit 5555ef501f16eb8182f0471717fd22f50dd4d474
@@ -27,7 +27,7 @@ apply plugin: 'eclipse'
apply plugin: 'com.diffplug.gradle.spotless'

// Current Build version
version = '1.4.5.1'
version = '1.4.5.2'

// Definitions
defaultTasks 'clean', 'build'
@@ -1,3 +1,16 @@
MapTool 1.4.5.2 - _Infused with Nerps!_
=====
This is a minor enhancement release that tweaks the AI Pathfinding to produce better results in some cases.

___

Enhancements
-----
* [#77][i77] - Tweaked the A* algorithm for a more natural and straighter move though open spaces for both square and hex grids. Also tweaked the A* algorithm to find the shortest path more consistently.

[i77]: https://github.com/JamzTheMan/MapTool/issues/77

___
MapTool 1.4.5.1 - _Infused with Nerps!_
=====
This release is a patch to fix a critical bug seen under Linux & MacOS. It also fixes yet another bug launching the JAR using the JRE vs full JDK.
@@ -46,8 +46,8 @@ public AStarCellPoint(CellPoint p, double mod) {
terrainModifier = mod;
}

public double cost() {
return h + getG();
public double fCost() {
return h + gCost();
}

public Point2D toPoint() {
@@ -115,6 +115,6 @@ public Shape getValidMoveShape(Zone zone) {

@Override
public int compareTo(AStarCellPoint other) {
return Double.compare(f, other.f);
return Double.compare(fCost(), other.fCost());
}
}
@@ -71,11 +71,12 @@ protected double getDiagonalMultiplier(int[] neighborArray) {
return 1;
}

private double metricDistance(CellPoint node, CellPoint goal) {
int xDist = node.x - goal.x;
int yDist = node.y - goal.y;
private double metricDistance(CellPoint current, CellPoint goal) {
int xDist = current.x - goal.x;
int yDist = current.y - goal.y;

final double distance;
double distance;
int crossProductTieBreaker = 0;

switch (metric) {
case MANHATTAN:
@@ -84,31 +85,34 @@ private double metricDistance(CellPoint node, CellPoint goal) {
break;
default:
case ONE_TWO_ONE:
xDist = Math.abs(node.x - goal.x);
yDist = Math.abs(node.y - goal.y);
if (xDist > yDist)
xDist = Math.abs(current.x - goal.x);
yDist = Math.abs(current.y - goal.y);
if (xDist > yDist) {
distance = Math.floor(diagonalMultiplier * yDist) + (xDist - yDist);
else
} else {
distance = Math.floor(diagonalMultiplier * xDist) + (yDist - xDist);
}
break;
case ONE_ONE_ONE:
distance = Math.max(Math.abs(xDist), Math.abs(yDist));
break;
}

return distance;
// break ties to prefer better looking paths that are along the straight line from the starting point to the goal
if ((goal.x > current.x && goal.y > current.y) || (goal.x < current.x && goal.y < current.y)) {
crossProductTieBreaker = Math.abs(xDist * crossY - crossX * yDist);
} else {
crossProductTieBreaker = Math.abs(xDist * crossY + crossX * yDist);
}

return distance += crossProductTieBreaker * 0.001;
}

@Override
public int[][] getNeighborMap(int x, int y) {
return neighborMap;
}

@Override
protected double gScore(CellPoint p1, CellPoint p2) {
return metricDistance(p1, p2);
}

@Override
protected double hScore(CellPoint p1, CellPoint p2) {
return metricDistance(p1, p2);
@@ -23,21 +23,24 @@ public AbstractAStarHexEuclideanWalker(Zone zone) {

protected abstract int[][] getNeighborMap(int x, int y);

@Override
protected double gScore(CellPoint p1, CellPoint p2) {
return euclideanDistance(p1, p2);
}

@Override
protected double hScore(CellPoint p1, CellPoint p2) {
return euclideanDistance(p1, p2);
}

private double euclideanDistance(CellPoint p1, CellPoint p2) {
int a = p1.x - p2.x;
int b = p1.y - p2.y;
// Adjusted math per: https://www.redblobgames.com/grids/hexagons/#distances
private double euclideanDistance(CellPoint current, CellPoint goal) {
// Using Axial coordinates q & r to match hex coordinate conventions
int aq = current.x;
int bq = goal.x;
int ar = current.y;
int br = goal.y;

// break ties to prefer better looking paths that are along the straight line from the starting point to the goal
int crossProductTieBreaker = Math.abs((aq - bq) * crossY - crossX * (ar - br));
double heuristic = ((Math.abs(aq - bq) + Math.abs(aq + ar - bq - br) + Math.abs(ar - br)) / 2) + crossProductTieBreaker * 0.001;

return Math.sqrt(a * a + b * b);
return heuristic;
}

protected double getDiagonalMultiplier(int[] neighborArray) {
@@ -62,6 +62,9 @@
private long retrievalCount;
private long testCount;

protected int crossX = 0;
protected int crossY = 0;

private List<AStarCellPoint> terrainCells = new ArrayList<AStarCellPoint>();

public AbstractAStarWalker(Zone zone) {
@@ -85,8 +88,6 @@ public AbstractAStarWalker(Zone zone) {
*/
protected abstract int[][] getNeighborMap(int x, int y);

protected abstract double gScore(CellPoint p1, CellPoint p2);

protected abstract double hScore(CellPoint p1, CellPoint p2);

protected abstract double getDiagonalMultiplier(int[] neighborArray);
@@ -108,7 +109,10 @@ public void setFootprint(TokenFootprint footprint) {
}

@Override
protected List<CellPoint> calculatePath(CellPoint start, CellPoint end) {
protected List<CellPoint> calculatePath(CellPoint start, CellPoint goal) {
crossX = start.x - goal.x;
crossY = start.y - goal.y;

List<AStarCellPoint> openList = new ArrayList<AStarCellPoint>();
Map<AStarCellPoint, AStarCellPoint> openSet = new HashMap<AStarCellPoint, AStarCellPoint>(); // For faster lookups
Set<AStarCellPoint> closedSet = new HashSet<AStarCellPoint>();
@@ -165,27 +169,27 @@ public void setFootprint(TokenFootprint footprint) {

currentNode = openList.remove(0);
openSet.remove(currentNode);
if (currentNode.equals(end)) {
if (currentNode.equals(goal)) {
break;
}

for (AStarCellPoint neighborNode : getNeighbors(currentNode, closedSet)) {
neighborNode.h = hScore(neighborNode, end);
showDebugInfo(neighborNode);
for (AStarCellPoint currentNeighbor : getNeighbors(currentNode, closedSet)) {
currentNeighbor.h = hScore(currentNeighbor, goal);
showDebugInfo(currentNeighbor);

if (openSet.containsKey(neighborNode)) {
if (openSet.containsKey(currentNeighbor)) {
// check if it is cheaper to get here the way that we just came, versus the previous path
AStarCellPoint oldNode = openSet.get(neighborNode);
if (neighborNode.getG() < oldNode.getG()) {
oldNode.replaceG(neighborNode);
neighborNode = oldNode;
neighborNode.parent = currentNode;
AStarCellPoint oldNode = openSet.get(currentNeighbor);
if (currentNeighbor.gCost() < oldNode.gCost()) {
oldNode.replaceG(currentNeighbor);
currentNeighbor = oldNode;
currentNeighbor.parent = currentNode;
}
continue;
}

pushNode(openList, neighborNode);
openSet.put(neighborNode, neighborNode);
pushNode(openList, currentNeighbor);
openSet.put(currentNeighbor, currentNeighbor);
}

closedSet.add(currentNode);
@@ -230,17 +234,17 @@ void pushNode(List<AStarCellPoint> list, AStarCellPoint node) {
list.add(node);
return;
}
if (node.cost() < list.get(0).cost()) {
if (node.fCost() < list.get(0).fCost()) {
list.add(0, node);
return;
}
if (node.cost() > list.get(list.size() - 1).cost()) {
if (node.fCost() > list.get(list.size() - 1).fCost()) {
list.add(node);
return;
}
for (ListIterator<AStarCellPoint> iter = list.listIterator(); iter.hasNext();) {
AStarCellPoint listNode = iter.next();
if (listNode.cost() > node.cost()) {
if (listNode.fCost() >= node.fCost()) {
iter.previous();
iter.add(node);
return;
@@ -383,15 +387,15 @@ protected void showDebugInfo(AStarCellPoint node) {
Label hScore = new Label();
Label fScore = new Label();

gScore.setLabel(f.format(node.getG()));
gScore.setLabel(f.format(node.gCost()));
gScore.setX(cellBounds.x + 10);
gScore.setY(cellBounds.y + 10);

hScore.setLabel(f.format(node.h));
hScore.setX(cellBounds.x + 35);
hScore.setY(cellBounds.y + 10);

fScore.setLabel(f.format(node.cost()));
fScore.setLabel(f.format(node.fCost()));
fScore.setX(cellBounds.x + 25);
fScore.setY(cellBounds.y + 25);
fScore.setForegroundColor(Color.RED);
@@ -79,7 +79,7 @@ public double getDistanceTraveled(Zone zone) {
return Math.floor(distanceTraveled) * zone.getUnitsPerCell();
}

public double getG() {
public double gCost() {
return g;
}

0 comments on commit 5555ef5

Please sign in to comment.
You can’t perform that action at this time.