package it.paspiz85.nanobot.attack;
import it.paspiz85.nanobot.exception.BotBadBaseException;
import it.paspiz85.nanobot.game.AttackScreen;
import it.paspiz85.nanobot.game.EnemyInfo;
import it.paspiz85.nanobot.game.Screen;
import it.paspiz85.nanobot.game.TroopsInfo;
import it.paspiz85.nanobot.platform.Platform;
import it.paspiz85.nanobot.util.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* Base attack strategy.
*
* @author paspiz85
*
*/
public abstract class Attack {
private static AttackScreen attackScreenParser = Screen.getInstance(AttackScreen.class);
private static List<Attack> attacks;
protected static final Point BOTTOM_LEFT = new Point(300, 536);
protected static final Point BOTTOM_RIGHT = new Point(537, 538);
protected static final Point LEFT = new Point(19, 307);
private static ManualAttack manualAttack;
protected static final int PAUSE_BETWEEN_UNIT_DROP = 61;
protected static final Point RIGHT = new Point(836, 307);
protected static final Point TOP = new Point(429, 18);
private static int diffLoot(final Integer prevLoot, final Integer currLoot) {
return zeroIfNull(prevLoot) > zeroIfNull(currLoot) ? zeroIfNull(prevLoot) - zeroIfNull(currLoot) : 0;
}
private static List<Attack> getAttacks() {
if (attacks == null) {
final List<Attack> list = new ArrayList<>();
list.add(manualAttack());
list.add(new Attack2Side());
list.add(new Attack4Side());
list.add(new Attack4SideParallel());
list.add(new Attack4SideParallelHalf2Wave());
list.add(new Attack4SideParallelFull2Wave());
attacks = list;
}
return attacks;
}
public static List<String> getAvailableStrategies() {
return getAttacks().stream().map(Attack::getName).collect(Collectors.toList());
}
protected static Point getButtonAttackUnit(final int x) {
return attackScreenParser.getButtonAttackUnit(x);
}
public static final Attack getByName(final String name) {
for (final Attack attack : Attack.getAttacks()) {
if (attack.getName().equals(name)) {
return attack;
}
}
throw new IllegalArgumentException(name);
}
private static Attack manualAttack() {
if (manualAttack == null) {
manualAttack = new ManualAttack();
}
return manualAttack;
}
public static String manualStrategy() {
return manualAttack().getName();
}
public static String noStrategy() {
return "NoAttack";
}
private static int zeroIfNull(final Integer n) {
return n == null ? 0 : n;
}
protected final Logger logger = Logger.getLogger(getClass().getName());
protected final Platform platform = Platform.instance();
Attack() {
}
public final void attack(final EnemyInfo loot, final TroopsInfo troopsInfo) throws InterruptedException {
platform.zoomUp();
logger.log(Level.CONFIG, getDescription());
doDropUnits(troopsInfo);
sleepUntilLootDoesNotChange(loot);
logger.log(Level.INFO, "No more loot");
}
protected abstract void doDropUnits(TroopsInfo troopsInfo) throws InterruptedException;
protected abstract String getDescription();
public final String getName() {
return getClass().getSimpleName();
}
protected final Point[] pointsBetweenFromToInclusive(final Point from, final Point to, final int count) {
Point[] result;
if (count <= 0) {
result = new Point[0];
} else if (count == 1) {
result = new Point[] { new Point((to.x() + from.x()) / 2, (to.y() + from.y()) / 2) };
} else {
result = new Point[count];
final double deltaX = (to.x() - from.x()) / (count - 1);
final double deltaY = (to.y() - from.y()) / (count - 1);
for (int i = 0; i < count; i++) {
result[i] = new Point((int) (from.x() + deltaX * i), (int) (from.y() + deltaY * i));
}
}
return result;
}
private void sleepUntilLootDoesNotChange(final EnemyInfo loot) throws InterruptedException {
Thread.sleep(10000);
EnemyInfo prevLoot = loot;
int diff = Integer.MAX_VALUE;
final int delta = 5;
while (diff > delta) {
Thread.sleep(15000);
EnemyInfo currLoot;
try {
currLoot = Screen.getInstance(AttackScreen.class).parseEnemyInfo();
} catch (final BotBadBaseException e) {
Thread.sleep(2000);
// in case of 100% win/no troops left, attack screen will end
// prematurely.
return;
}
diff = 0;
diff += diffLoot(prevLoot.getGold(), currLoot.getGold());
diff += diffLoot(prevLoot.getElixir(), currLoot.getElixir());
diff += diffLoot(prevLoot.getDarkElixir(), currLoot.getDarkElixir());
prevLoot = currLoot;
}
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}