package myai; import static java.lang.Math.random; import static myai.MapModule.P; import static myai.MapModule.manhattan; import static myai.Tuples.T; 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.Map.Entry; import java.util.Random; import java.util.Set; import myai.Tuples.Tuple2; import myai.Tuples.Tuple3; import rts.GameState; import rts.units.Unit; import rts.units.UnitAction; import rts.units.UnitDefinition; public class WorkerManager { private LinkedHashMap<Long, TaskedUnit> myWorkers = new LinkedHashMap<Long, TaskedUnit>(); private Set<Long> resourceMap = new HashSet<Long>(); private LinkedHashSet<Farm> farms = new LinkedHashSet<Farm>(); private static final int WITHIN_FARM_DIST = 5; private double CHANCE_PREFER_WAR = .1; public static Random random = new Random(); public void init(GameState state) { //BANK for(int i = 0; i < state.getResourceTypes(); i++) { moneyOwed.add(0); } } public void preUnitLogic(MapModule map, GameState state) { for (Unit resource : map.resources) { if (!resourceMap.contains(resource.getID())) { // Resource is not associated with a farm Farm farmPick = null; for (Farm farm : farms) { if (manhattan(P(resource), farm.p) < WITHIN_FARM_DIST) { farmPick = farm; break; } } // Add resource to farm list if (farmPick != null) { resourceMap.add(resource.getID()); } else { // Build new farm Farm farm = new Farm(); farm.p = P(resource); farms.add(farm); } } } // Prune dead workers List<Long> aliveWorkers = new LinkedList<Long>(); for (Unit unit : state.getMyUnits()) { if (unit.isWorker()) { aliveWorkers.add(unit.getID()); } } // Prune dead workers Iterator<Entry<Long, TaskedUnit>> ite = myWorkers.entrySet().iterator(); while (ite.hasNext()) { Entry<Long, TaskedUnit> s = ite.next(); if (!aliveWorkers.contains(s.getValue().unit.getID())) { ite.remove(); if (s.getValue().farm != null) { s.getValue().farm.workers--; s.getValue().farm.buildLock = false; } if (s.getValue().getLoan() != null) { //Unit died while in debt s.getValue().getLoan().payBackLoan(); } } } } public void commandUnit(Unit unit, GameState state, MapModule map, UnitGeneral men) { // ASSIGN DEFAULT TASK if (!myWorkers.containsKey(unit.getID())) { myWorkers.put(unit.getID(), new TaskedUnit(unit, TaskType.SCOUT)); } // FETCH CURRENT TASK boolean isPoor = unit.getResources() == 0; TaskedUnit UNIT = myWorkers.get(unit.getID()); //System.out.println(UNIT.task); switch (UNIT.task) { case BUILD_NEW_AIRPORT:{ //See below } case BUILD_NEW_STOCKPILE: { // See below } case BUILD_NEW_SOLDIER_OFFICE: { if (UNIT.goalPos != null) { // PATHFIND THERE AND BUILD Tuple3<Boolean, Double, List<Point>> path = map.findPath(P(unit), UNIT.goalPos, true, false); if (path.a && path.b < MapModule.NAV_THRESH) { // IF FAR, MOVE if (path.c.size() > 2) { men.findAndSetAction(unit, path.c.get(1), UnitAction.MOVE, true); } else { // IF CLOSE, DO UnitAction s = null; if (UNIT.task == TaskType.BUILD_NEW_STOCKPILE) { s = men.action_buildStockpile(unit.getActions(), path.c.get(1)); } else if (UNIT.task == TaskType.BUILD_NEW_SOLDIER_OFFICE) { s = men.action_buildSoldierOffice(unit.getActions(), path.c.get(1)); } if (UNIT.task == TaskType.BUILD_NEW_AIRPORT) { s = men.action_buildAirport(unit.getActions(), path.c.get(1)); } if (s != null) { unit.setAction(s); // Clear task setTask(unit, TaskType.HARVEST); UNIT.getLoan().payBackLoan(); UNIT.clearBuildGoals(); } } } } else { System.err.println("Worker told to build office but not given location!"); setTask(unit, TaskType.HARVEST); } break; } case SCOUT: { if (findClosestOpenFarm(unit, farms).a) { UNIT.clearScoutGoals(); setTask(unit, isPoor ? TaskType.HARVEST : TaskType.RETURN); } else { if (UNIT.goalPos == null) { UNIT.goalPos = P(random.nextInt(map.mapDim.width), random.nextInt(map.mapDim.height)); } Tuple3<Boolean, Double, List<Point>> g = map.findPath(P(unit), UNIT.goalPos, true, unit.isFlying()); if (g.a && g.c.size() > 2) { // MOVE men.findAndSetAction(unit, g.c.get(1), UnitAction.MOVE, true); } else { UNIT.clearScoutGoals(); } } break; } case HARVEST: { // See Return thing below if (!isPoor || map.stockpile.isEmpty()) { setTask(unit, TaskType.RETURN); } // ASSIGN FARM IF DOESN'T HAVE ONE if (UNIT.farm == null) { // FIND A WILLING FARM Tuple2<Boolean, Farm> result = findClosestOpenFarm(unit, farms); if (result.a) { Farm mejorGranja = result.b; mejorGranja.workers++; UNIT.farm = mejorGranja; } else { // NO MORE FARMS setTask(unit, TaskType.SCOUT); } } if (UNIT.farm != null) { Farm farm = UNIT.farm; // Go to assigned farm if too far away boolean inFarm = manhattan(P(unit), farm.p) <= WITHIN_FARM_DIST; Point target = null; if (!inFarm) { target = farm.p; } else { Tuple2<Boolean, Unit> searchResult = map.findClosest(unit, map.resources); if (searchResult.a) { target = P(searchResult.b); if (manhattan(P(unit), target) > WITHIN_FARM_DIST) { // FARM IS A QUACK, REMOVE! farms.remove(farm); UNIT.farm = null; target = null; } } } if (target != null) { Tuple3<Boolean, Double, List<Point>> path = map.findPath(P(unit), target, true, unit.isFlying()); if (path.a && path.b < MapModule.NAV_THRESH && path.c.size() > 1) { // IF FAR, MOVE if (path.c.size() > 2) { men.findAndSetAction(unit, path.c.get(1), UnitAction.MOVE, true); } else { // IF CLOSE, DO men.findAndSetAction(unit, path.c.get(1), UnitAction.HARVEST, false); // Check if there is a stockpile anywhere near // here. // POSSIBLY build a soldier office. Tuple2<Boolean, Unit> nearestStock = map.findClosest(unit, map.stockpile); if (!UNIT.farm.buildLock && nearestStock.b != null && manhattan(UNIT.farm.p, P(nearestStock.b)) > WITHIN_FARM_DIST) { // Assign somebody to build farm UnitDefinition ss = state.getBuildingList().get(men.STOCKPILE_BUILD_ID); if (ss.is_stockpile_building && canAfford(ss.cost, state)) { Tuple3<Boolean, Double, List<Point>> newPath = map.findPath(UNIT.farm.p, P(random.nextInt(map.mapDim.width), random.nextInt(map.mapDim.height)), true, 6, unit.isFlying()); UNIT.goalFarm = UNIT.farm; UNIT.task = TaskType.BUILD_NEW_STOCKPILE; UNIT.goalPos = newPath.c.get(newPath.c.size() - 1); UNIT.farm.buildLock = true; UNIT.setLoan(new ConstructionLoan(ss.cost)); UNIT.getLoan().takeOutLoan(); } } } } } } break; } case RETURN: { if (isPoor) { setTask(unit, TaskType.HARVEST); } if (map.stockpile.isEmpty()) { setTask(unit, TaskType.SCOUT); } // GO TO NEAREST THING Tuple2<Boolean, Unit> searchResult = map.findClosest(unit, map.stockpile); if (searchResult.a) { Tuple3<Boolean, Double, List<Point>> path = map.findPath(P(unit), P(searchResult.b), true, unit.isFlying()); if (path.a && path.b < MapModule.NAV_THRESH) { // IF FAR, MOVE if (path.c.size() > 2) { men.findAndSetAction(unit, path.c.get(1), UnitAction.MOVE, false); } else { // IF CLOSE, DO men.findAndSetAction(unit, path.c.get(1), UnitAction.RETURN, false); // POSSIBLY build a soldier office. Tuple2<Boolean, Unit> nearestOffice = map.findClosest(unit, map.soldierOffices); if (UNIT.farm != null && (nearestOffice.b == null || manhattan(UNIT.farm.p, P(nearestOffice.b)) > WITHIN_FARM_DIST)) { // Assign somebody to build farm UnitDefinition ss = state.getBuildingList().get(men.SOLDIER_OFFICE_BUILD_ID); if (canAfford(ss.cost, state) && random() < CHANCE_PREFER_WAR) { Tuple3<Boolean, Double, List<Point>> newPath = map.findPath(UNIT.farm.p, P(random.nextInt(map.mapDim.width), random.nextInt(map.mapDim.height)), true, 6, unit.isFlying()); UNIT.goalFarm = UNIT.farm; UNIT.task = Math.random() < .60 ? TaskType.BUILD_NEW_SOLDIER_OFFICE : TaskType.BUILD_NEW_AIRPORT; UNIT.goalPos = newPath.c.get(newPath.c.size() - 1); UNIT.farm.buildLock = true; UNIT.setLoan(new ConstructionLoan(ss.cost)); UNIT.getLoan().takeOutLoan(); } } } } } break; } default: System.err.println("Unit " + unit + " is in a bad state!"); break; } } enum TaskType { HARVEST, SCOUT, RETURN, BUILD_NEW_STOCKPILE, BUILD_NEW_SOLDIER_OFFICE, BUILD_NEW_AIRPORT; } private void setTask(Unit unit, TaskType type) { myWorkers.get(unit.getID()).task = type; } public class Farm { Point p = null; int workers = 0; int workerLimit = 4; boolean buildLock = false; } public Tuple2<Boolean, Farm> findClosestOpenFarm(Unit unit, Collection<Farm> farms) { double b = Double.MAX_VALUE; Farm closest = null; for (Farm farm : farms) { // VALID TARGET FOUND double dist = manhattan(P(unit), farm.p); if (farm.workers < farm.workerLimit && (dist < b || (dist == b && .5 < random()))) { b = dist; closest = farm; } } return T(closest != null, closest); } public class TaskedUnit { Farm farm; TaskType task; Point goalPos; Farm goalFarm; final Unit unit; private ConstructionLoan loan; public TaskedUnit(Unit unit, TaskType task) { this.unit = unit; this.task = task; } public void clearBuildGoals() { goalPos = null; goalFarm.buildLock = false; goalFarm = null; loan = null; } public void clearScoutGoals() { goalPos = null; } public ConstructionLoan getLoan() { return loan; } public void setLoan(ConstructionLoan loasn) { this.loan = loasn; } } class ConstructionLoan { private final List<Integer> cost; public ConstructionLoan(List<Integer> cost) { this.cost = cost; } public void takeOutLoan() { for (int o = 0; o < cost.size(); o++){ moneyOwed.set(o, moneyOwed.get(o) + cost.get(o)); } //System.err.println("Loan taken"); } public void payBackLoan() { for (int o = 0; o < cost.size(); o++){ moneyOwed.set(o, moneyOwed.get(o) - cost.get(o)); } //System.err.println("Loan returned"); } } private final List<Integer> moneyOwed = new ArrayList<Integer>(); private boolean canAfford(ArrayList<Integer> cost, GameState state) { for (int i = 0; i < state.getResourceTypes(); i++) { if (cost.get(i) + moneyOwed.get(i)> state.getResources(i)) { return false; } } return true; } }