squidpony.squidai.AreaUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of squidlib-util Show documentation
Show all versions of squidlib-util Show documentation
SquidLib platform-independent logic and utility code. Please refer to
https://github.com/SquidPony/SquidLib .
package squidpony.squidai;
import squidpony.squidmath.Coord;
import squidpony.squidmath.OrderedMap;
/**
* Static utilities for use in AOE and anything else that might need HashMaps of Coord keys to Double values.
* Created by Tommy Ettinger on 7/13/2015.
*/
public class AreaUtils {
/**
* This takes a 2D boolean array and returns a HashMap of Coord keys to Double values, but will only use the value
* 1.0, and only for positions in map that have as their boolean element true.
* @param map width by height, commonly generated by FOV methods
* @return a HashMap of Coord keys to Double values, but the only value used is 1.0
*/
public static OrderedMap arrayToHashMap(boolean[][] map)
{
OrderedMap ret = new OrderedMap<>();
for(int i = 0; i < map.length; i++)
{
for(int j = 0; j < map[i].length; j++)
{
if(map[i][j])
ret.put(Coord.get(i, j), 1.0);
}
}
return ret;
}
/**
* This takes a 2D double array called map and returns a HashMap of Coord keys to Double values, and will have a key
* for every position in map that is greater than 0.0, with values equal to those in map.
* @param map width by height, commonly generated by FOV methods
* @return a HashMap of Coord keys to Double values, with values all greater than 0.0
*/
public static OrderedMap arrayToHashMap(double[][] map)
{
OrderedMap ret = new OrderedMap<>();
for(int i = 0; i < map.length; i++)
{
for(int j = 0; j < map[i].length; j++)
{
if(map[i][j] > 0.0)
ret.put(Coord.get(i, j), map[i][j]);
}
}
return ret;
}
/**
* This takes a 2D double array and returns a HashMap of Coord keys to Double values, but will only use the value
* 1.0, and only does this if the passed double[][] has a value at that position that is greater than cutoff.
* For example, a cutoff of 0.3 will make all elements in the 2D array that are 0.3 or less be ignored and not put
* into the HashMap, but all elements that are greater than 0.3 will be placed in as 1.0.
* @param map width by height, commonly generated by FOV methods
* @param cutoff any elements greater than this will be 1.0 in the return, anything else will be ignored
* @return a HashMap of Coord keys to Double values, but the only value used is 1.0
*/
public static OrderedMap arrayToHashMap(double[][] map, double cutoff)
{
OrderedMap ret = new OrderedMap<>();
for(int i = 0; i < map.length; i++)
{
for(int j = 0; j < map[i].length; j++)
{
if(map[i][j] > cutoff)
ret.put(Coord.get(i, j), 1.0);
}
}
return ret;
}
/**
* This takes a DijkstraMap that has already completed a scan() and returns a HashMap of Coord keys to Double
* values, and will have a key for every position that was reached in the DijkstraMap, with 1.0 as the only value.
* @param map a double[][] returned by a DijkstraMap running its scan()
* @return a HashMap of Coord keys to Double values, with values of 1.0 only
*/
public static OrderedMap dijkstraToHashMap(double[][] map)
{
OrderedMap ret = new OrderedMap<>();
for(int i = 0; i < map.length; i++)
{
for(int j = 0; j < map[i].length; j++)
{
if(map[i][j] < DijkstraMap.WALL)
ret.put(Coord.get(i, j), 1.0);
}
}
return ret;
}
/**
* Checks that the given end Coord can be targeted from the given origin Coord given the directional targeting
* rules specified by limit. If any of the arguments are null, returns true (it assumes that any limits are not
* valid and don't restrict anything). The following AimLimit enum values for limit have the following meanings:
*
*
* - AimLimit.FREE makes no restrictions; it is equivalent here to passing null for limit.
* - AimLimit.EIGHT_WAY will only consider Points to be valid targets
* if they are along a straight line with an angle that is a multiple of 45 degrees, relative to the positive x
* axis. Essentially, this limits the points to those a queen could move to in chess.
* - AimLimit.ORTHOGONAL will cause the AOE to only consider Points to be valid targets if
* they are along a straight line with an angle that is a multiple of 90 degrees, relative to the positive x
* axis. Essentially, this limits the points to those a rook could move to in chess.
* - AimLimit.DIAGONAL will cause the AOE to only consider Points to be valid targets if they are along a
* straight line with an angle that is 45 degrees greater than a multiple of 90 degrees, relative to the
* positive x axis. Essentially, this limits the points to those a bishop could move to in chess.
*
*
* @param limit an AimLimit enum that restricts valid points unless it is AimLimit.FREE or null
* @param origin where the user is
* @param end where the point we want to verify is
* @return true if the point is a valid target or if the limits are invalid (non-restricting), false otherwise
*/
public static boolean verifyLimit(AimLimit limit, Coord origin, Coord end)
{
if (limit != null && origin != null && end != null) {
switch (limit) {
case EIGHT_WAY:
if(Math.abs(end.x - origin.x) == Math.abs(end.y - origin.y) ||
end.x == origin.x || end.y == origin.y)
{
return true;
}
break;
case DIAGONAL:
if(Math.abs(end.x - origin.x) == Math.abs(end.y - origin.y))
{
return true;
}
break;
case ORTHOGONAL:
if(end.x == origin.x || end.y == origin.y)
{
return true;
}
break;
case FREE: return true;
}
return false;
}
return true;
}
/**
* Checks that the given end Coord can be targeted from the given origin Coord given the complete targeting rules
* specified by reach. If any of the arguments are null, returns true (it assumes that any limits are not
* valid and don't restrict anything). If reach.limit is null, it treats it as equivalent to {@link AimLimit#FREE}.
* Otherwise, it uses the metric, minDistance, and maxDistance from reach to calculate if end is target-able from
* origin assuming an unobstructed playing field.
*
* @param reach a Reach object that, if non-null, gives limits for how targeting can proceed.
* @param origin where the user is
* @param end where the point we want to verify is
* @return true if the point is a valid target or if the limits are invalid (non-restricting), false otherwise
*/
public static boolean verifyReach(Reach reach, Coord origin, Coord end)
{
if(reach == null)
return true;
AimLimit limit = reach.limit;
if(limit == null) limit = AimLimit.FREE;
if (origin != null && end != null) {
switch (limit) {
case EIGHT_WAY:
if(Math.abs(end.x - origin.x) == Math.abs(end.y - origin.y) ||
end.x == origin.x || end.y == origin.y)
{
return reach.metric.inRange(origin.x, origin.y, end.x, end.y,
reach.minDistance, reach.maxDistance);
}
break;
case DIAGONAL:
if(Math.abs(end.x - origin.x) == Math.abs(end.y - origin.y))
{
return reach.metric.inRange(origin.x, origin.y, end.x, end.y,
reach.minDistance, reach.maxDistance);
}
break;
case ORTHOGONAL:
if(end.x == origin.x || end.y == origin.y)
{
return reach.metric.inRange(origin.x, origin.y, end.x, end.y,
reach.minDistance, reach.maxDistance);
}
break;
case FREE: return reach.metric.inRange(origin.x, origin.y, end.x, end.y,
reach.minDistance, reach.maxDistance);
}
return false;
}
return true;
}
}