Thanks again to TheBestOne, I copied his core methods too ; )
This is my first time playing a KingOfTheHill-CodeGame, so I hope I did everything right.
I proudly present the Sehtimianers :D
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Sehtimianer {
private static final String FILENAME = "Sehtimianer.txt";
private static final int AGGRESSIVE_ROUND_BORDER = 80;
int round;
int playerID;
int thisTownID;
List<Town> towns = new ArrayList<Town>();
List<Town> myTowns = new ArrayList<Town>();
List<Town> playerTowns = new ArrayList<Town>();
List<Town> neutralTowns = new ArrayList<Town>();
Map<Integer, Integer> townToPlayerMapping = new HashMap<Integer, Integer>();
boolean isAllowedToWriteMapping = true;
Town thisTown;
public static void main(String[] args) {
if (args.length == 0) {
// new File(FILENAME).delete();
System.out.println("100 100 100");
return;
}
new Sehtimianer().decide(args[0].split(";"));
}
private void decide(String[] args) {
// final long start = System.currentTimeMillis();
round = Integer.parseInt(args[0]);
playerID = Integer.parseInt(args[1]);
thisTownID = Integer.parseInt(args[2]);
for (int i = 3; i < args.length; i++) {
towns.add(new Town(args[i]));
}
for (Town town : towns) {
if (town.isMine()) {
myTowns.add(town);
if (town.isThisTown()) {
thisTown = town;
}
} else {
if (town.getOwner() == -1) {
neutralTowns.add(town);
} else {
playerTowns.add(town);
}
}
}
if (new File(FILENAME).exists()) {
try {
BufferedReader reader = new BufferedReader(new FileReader(FILENAME));
String inputLine;
String[] ids;
while ((inputLine = reader.readLine()) != null) {
ids = inputLine.split(";");
if (ids.length == 1) {
Integer writingTownID = Integer.valueOf(ids[0]);
boolean townIsLost = true;
for (Town town : myTowns) {
if (town.getId() == writingTownID) {
townIsLost = false;
break;
}
}
isAllowedToWriteMapping = townIsLost || thisTownID == writingTownID;
continue;
}
townToPlayerMapping.put(Integer.valueOf(ids[0]), Integer.valueOf(ids[1]));
}
reader.close();
for (Town town : towns) {
if (!townToPlayerMapping.get(town.getId()).equals(town.getOwner())) {
town.setDefenseBonus(false);
}
}
} catch (IOException e) {
// Dont worry : )
}
}
if (round == 1) {
int maxKnights = 0;
int maxKnightTownID = thisTownID;
for (Town town : myTowns) {
if (town == thisTown) {
continue;
}
if (town.knightCount() > maxKnights) {
maxKnights = town.knightCount();
maxKnightTownID = town.getId();
}
}
if (maxKnightTownID != thisTownID) {
System.out.println("S " + maxKnightTownID + " " + thisTown.knightCount());
}
} else if (round % 3 == 2) {
int myKnightIncome = 0;
for (Town town : myTowns) {
myKnightIncome += town.lowbornCount() / 2;
}
Map<Integer, Integer> playerKnightIncomeMap = new HashMap<Integer, Integer>();
Map<Integer, Integer> playerTownCountMap = new HashMap<Integer, Integer>();
List<Integer> nextRoundKnights = new ArrayList<Integer>();
Map<Integer, Town> nextRoundKnightsToTownMapping = new HashMap<Integer, Town>();
for (Town town : playerTowns) {
fillDescisionMaps(town, nextRoundKnights, nextRoundKnightsToTownMapping, playerKnightIncomeMap, playerTownCountMap);
}
for (Town town : neutralTowns) {
fillDescisionMaps(town, nextRoundKnights, nextRoundKnightsToTownMapping, playerKnightIncomeMap, playerTownCountMap);
}
Integer maxEnemyKnightIncome = 0;
for (Integer knightIncome : playerKnightIncomeMap.values()) {
if (knightIncome > maxEnemyKnightIncome) {
maxEnemyKnightIncome = knightIncome;
}
}
Integer maxEnemyTownCount = 0;
for (Integer townCount : playerTownCountMap.values()) {
if (townCount > maxEnemyTownCount) {
maxEnemyTownCount = townCount;
}
}
if (maxEnemyKnightIncome > myKnightIncome || (round > AGGRESSIVE_ROUND_BORDER && maxEnemyTownCount >= myTowns.size())) {
Collections.sort(nextRoundKnights);
int possibleHighest = 0;
Town enemyTown;
int enemyTownUpkeep;
for (int i = nextRoundKnights.size() - 1; i >= 0; i--) {
possibleHighest = nextRoundKnights.get(i);
enemyTown = nextRoundKnightsToTownMapping.get(possibleHighest);
enemyTownUpkeep = enemyTown.lowbornCount() / 2;
if (enemyTownUpkeep > (possibleHighest - enemyTownUpkeep)) { // Substract the calculated Income for the next Turn
// Town will be lost because of revolution after captured -> Bad target
possibleHighest = 0;
continue;
}
if (round > AGGRESSIVE_ROUND_BORDER || enemyTown.lowbornCount() > 0) {
break;
}
}
if (possibleHighest > 0) {
Town attackedTown = nextRoundKnightsToTownMapping.get(possibleHighest);
System.out.println("A " + attackedTown.getId() + " " + calcHowMuchKnightsShouldAttack(attackedTown, possibleHighest));
}
}
}
if (isAllowedToWriteMapping) {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(FILENAME));
writer.write(thisTownID + "\n");
for (Town town : towns) {
writer.write(town.getId() + ";" + town.getOwner() + "\n");
}
writer.close();
} catch (IOException e) {
// Dont worry : )
}
}
System.out.println("W");
// long duration = System.currentTimeMillis() - start;
// if (duration > 1000) {
// throw new RuntimeException();
// }
}
private void fillDescisionMaps(Town town, List<Integer> nextRoundKnights, Map<Integer, Town> nextRoundKnightsToTownMapping, Map<Integer, Integer> playerKnightIncomeMap,
Map<Integer, Integer> playerTownCountMap) {
int calculatedKnights = calcKnightsInNextRound(town);
nextRoundKnights.add(calculatedKnights);
nextRoundKnightsToTownMapping.put(calculatedKnights, town);
Integer enemyKnightIncome = playerKnightIncomeMap.get(town.getOwner());
if (enemyKnightIncome == null) {
enemyKnightIncome = town.lowbornCount() / 2;
} else {
enemyKnightIncome = enemyKnightIncome + (town.lowbornCount() / 2);
}
playerKnightIncomeMap.put(town.getOwner(), enemyKnightIncome);
Integer enemyTownCount = playerTownCountMap.get(town.getOwner());
if (enemyTownCount == null) {
enemyTownCount = Integer.valueOf(1);
} else {
enemyTownCount = enemyTownCount + 1;
}
playerTownCountMap.put(town.getOwner(), enemyTownCount);
}
private int calcKnightsInNextRound(Town enemyTown) {
int knights = (int) ((double) enemyTown.knightCount() * (enemyTown.isDefenseBonus() ? 1.2 : 1));
knights = thisTown.getFreeKnights() - knights;
if (knights > 0) {
knights += enemyTown.lowbornCount() / 2;
} else {
knights = 0;
}
return knights;
}
private int calcHowMuchKnightsShouldAttack(Town enemyTown, int possibleHighest) {
if (round < AGGRESSIVE_ROUND_BORDER && thisTown.lowbornCount() == 0) {
return thisTown.knightCount();
}
int spareKnights = possibleHighest - enemyTown.lowbornCount(); // Correct -> div 2 and mul 2
int minShouldSend = thisTown.getFreeKnights() - (spareKnights / 2);
return Math.max(minShouldSend, thisTown.knightCount() / 2);
}
private class Town {
private final int ownerId;
private final int id;
private final int knights;
private final int lowborns;
private boolean defenseBonus;
public Town(String string) {
String[] args = string.split("_");
ownerId = Integer.parseInt(args[0]);
id = Integer.parseInt(args[1]);
knights = Integer.parseInt(args[2]);
lowborns = Integer.parseInt(args[3]);
defenseBonus = true;
}
public boolean isDefenseBonus() {
return defenseBonus;
}
public void setDefenseBonus(boolean defenseBonus) {
this.defenseBonus = defenseBonus;
}
public int getId() {
return id;
}
public int getOwner() {
return ownerId;
}
public int knightCount() {
return knights;
}
public int lowbornCount() {
return lowborns;
}
public boolean isMine() {
return ownerId == playerID;
}
public boolean isThisTown() {
return id == thisTownID;
}
private int getFreeKnights() {
return knights - lowborns / 2 - 1;
}
}
}
The Sehtimianers try to be superior the whole game and finish it at the end.
I hope my bot won't do too bad : )