package myai;
import static java.lang.Math.abs;
import static java.lang.Math.random;
import static myai.Tuples.T;
import java.awt.Dimension;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import myai.Tuples.Tuple2;
import myai.Tuples.Tuple3;
import rts.GameState;
import rts.units.Unit;
public class MapModule {
private MapTile[][] map;
public Dimension mapDim;
public Point center;
public static final int NAV_THRESH = 1000;
/*
* UNITS + ELEMENTS
*/
LinkedHashMap<Point, Unit> pointRef_US = new LinkedHashMap<Point, Unit>();
LinkedHashMap<Point, Unit> pointRef_THEM = new LinkedHashMap<Point, Unit>();
public LinkedHashSet<Unit> resources = new LinkedHashSet<Unit>(),
stockpile = new LinkedHashSet<Unit>(),
soldierOffices = new LinkedHashSet<Unit>();
/**
* Update everything!
*
* @param state
*/
public void update(GameState state, UnitGeneral dudes) {
for (int i = 0; i < state.getMap().length; i++) {
if ((state.getMap()[i] & GameState.MAP_WALL) != 0)
map[i % mapDim.width][i / mapDim.width].isWall = true;
}
pointRef_US.clear();
pointRef_THEM.clear();
stockpile.clear();
soldierOffices.clear();
for (Unit u : state.getOtherUnits()) {
pointRef_THEM.put(P(u), u);
}
for (Unit u : state.getMyUnits()) {
pointRef_US.put(P(u), u);
addUnit(u);
}
for (Unit u : state.getNeutralUnits()) {
if (u.isResources()) {
pointRef_US.put(P(u), u);
addUnit(u);
}
}
Iterator<Unit> ite = resources.iterator();
while (ite.hasNext()) {
Unit rec = ite.next();
if ((state.getMap()[rec.getY() * mapDim.width + rec.getX()] & GameState.MAP_FOG) == 0) {
if ((state.getMap()[rec.getY() * mapDim.width + rec.getX()] & GameState.MAP_NEUTRAL) == 0) {
ite.remove();
}
}
}
}
public void init(GameState state) {
mapDim = new Dimension(state.getMapWidth(), state.getMapHeight());
map = new MapTile[mapDim.width][mapDim.height];
for (int x = 0; x < mapDim.width; x++) {
for (int y = 0; y < mapDim.height; y++) {
map[x][y] = new MapTile(P(x, y));
}
}
// SET UP NEIGHBORS
for (int x = 0; x < mapDim.width; x++) {
for (int y = 0; y < mapDim.height; y++) {
List<MapTile> tiles = new ArrayList<MapTile>();
if (y != 0)
tiles.add(map[x][y - 1]);
if (y != mapDim.height - 1)
tiles.add(map[x][y + 1]);
if (x != mapDim.width - 1)
tiles.add(map[x + 1][y]);
if (x != 0)
tiles.add(map[x - 1][y]);
map[x][y].neighbors = tiles.toArray(new MapTile[0]);
}
}
center = P(mapDim.width / 2, mapDim.height / 2);
}
public Tuple3<Boolean, Double, List<Point>> findPath(Point s, Point t, boolean all, boolean ignoreWalls) {
return findPath(s, t, all, NAV_THRESH * 2 ,ignoreWalls);
}
int pAcc = 2;
public Tuple3<Boolean, Double, List<Point>> findPath(Point s, Point t, boolean all, int maxCost, boolean ignoreWalls) {
if (manhattan(s, t) > 10) {
t = P((s.x * pAcc + t.x) / (pAcc + 1), (s.y * pAcc + t.y) / (pAcc + 1));
}
Set<Point> open = new HashSet<Point>(), closed = new HashSet<Point>();
PathN[][] pathNodes = new PathN[mapDim.width][mapDim.height];
open.add(s);
pathNodes[s.x][s.y] = new PathN();
boolean found = false;
while (!open.isEmpty() && !found) {
Point best = lowestCost(open, t, all, ignoreWalls);
if (pathNodes[best.x][best.y].walkCost > maxCost) {
t = best;
found = true;
}
closed.add(best);
open.remove(best);
if (best.equals(t)) {
found = true;
} else {
for (MapTile tile : MT(best).neighbors) {
Point p = tile.pos;
if (!open.contains(p) && !closed.contains(p)) {
pathNodes[p.x][p.y] = new PathN(best, 1 + pathNodes[best.x][best.y].walkCost);
open.add(p);
} else if (open.contains(p)) {
double potentialCost = 1 + pathNodes[best.x][best.y].walkCost;
if (potentialCost < pathNodes[p.x][p.y].walkCost) {
pathNodes[p.x][p.y].parent = best;
pathNodes[p.x][p.y].walkCost = potentialCost;
}
}
}
}
}
if (!found) {
return T(false, 0D, null);
}
List<Point> path = new LinkedList<Point>();
Double cost = pathNodes[t.x][t.y].walkCost;
Point next = t;
while (next != null) {
path.add(0, next);
next = pathNodes[next.x][next.y].parent;
}
return T(true, cost, path);
}
private class PathN {
Point parent;
double walkCost = 0;
public PathN() {
}
public PathN(Point parent, double walkCost) {
this.parent = parent;
this.walkCost = walkCost;
}
}
private Point lowestCost(Set<Point> open, Point target, boolean all, boolean ignoreWalls) {
Point bestPoint = null;
double lowestCost = Double.MAX_VALUE;
for (Point current : open) {
double cost = cost(current, target, all, ignoreWalls);
if (cost < lowestCost || (cost == lowestCost && random() < .5)) {
bestPoint = current;
lowestCost = cost;
}
}
return bestPoint;
}
private double cost(Point s, Point t, boolean all, boolean ignoreWalls) {
return map[s.x][s.y].getDynamicCost(all, ignoreWalls) + manhattan(s, t);
}
public Point indexToPoint(int i) {
return P(i % mapDim.width, i / mapDim.width);
}
public static Point P(int... xs) {
int x = 0, y = 0;
if (xs.length == 1)
x = y = xs[0];
else if (xs.length >= 2) {
x = xs[0];
y = xs[1];
}
return new Point(x, y);
}
public static Point P(Unit a) {
if (a == null) return P();
return P(a.getX(), a.getY());
}
public static double manhattan(Point a, Point b) {
return abs(a.x - b.x) + abs(a.y - b.y);
}
class MapTile {
boolean isWall = false;
double cost = 0;
MapTile[] neighbors;
final Point pos;
public MapTile(Point pos) {
this.pos = pos;
}
boolean occupied(boolean all) {
return pointRef_US.containsKey(pos) || (all && pointRef_THEM.containsKey(pos));
};
double getDynamicCost(boolean all, boolean ignoreWalls) {
return cost + (occupied(all) ? NAV_THRESH : 0) + (isWall && !ignoreWalls ? NAV_THRESH : 0);
};
}
public MapTile MT(Point p) {
return map[p.x][p.y];
}
public void addUnit(Unit u) {
if (u.isStockpile()) {
stockpile.add(u);
} else if (u.isResources()) {
resources.add(u);
} else if (u.isBuilding()) {
soldierOffices.add(u);
}
}
public Tuple2<Boolean, Unit> findClosest(Unit unit, Collection<Unit> things) {
double b = Double.MAX_VALUE;
Unit closest = null;
for (Unit thing : things) {
// VALID TARGET FOUND
double dist = manhattan(P(unit), P(thing));
if (dist < b || (dist == b && .5 < random())) {
b = dist;
closest = thing;
}
}
return T(closest != null, closest);
}
}