Assassin
Tries to kill enemies whenever possible, otherwise moves one field. It is pretty good in finding the path to an enemy, but doesn't do anything to hide from other bots.
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class Assassin {
private final Path dataPath = Paths.get("data");
private final Path mapPath = Paths.get("map");
private final Path statsPath = Paths.get("stats");
private final List<Player> players = new ArrayList<>();
private final int energy;
private Map map = null;
public Assassin(int energy) {
this.energy = energy;
}
private void doSomething() {
if (dataFileEmpty()) {
calculateTurn();
}
printStoredOutput();
}
private boolean dataFileEmpty() {
try {
return !Files.exists(dataPath) || Files.size(dataPath) == 0;
} catch (IOException e) {
return true;
}
}
private void printStoredOutput() {
try {
List<String> lines = Files.readAllLines(dataPath, StandardCharsets.UTF_8);
//print first line
System.out.println(lines.get(0));
//delete first line
lines.remove(0);
Files.write(dataPath, lines, StandardCharsets.UTF_8);
} catch (IOException e) {
System.out.println("PASS");
}
}
private void calculateTurn() {
try {
readStats();
readMap();
if (!tryKill()) {
sneakCloser();
}
} catch (IOException e) {}
}
private void readStats() throws IOException{
List<String> stats = Files.readAllLines(statsPath, StandardCharsets.UTF_8);
for (String stat : stats) {
String[] infos = stat.split(",");
int hp = Integer.parseInt(infos[1].replace("HP", ""));
players.add(new Player(stat.charAt(0), hp));
}
}
private void readMap() throws IOException{
List<String> lines = Files.readAllLines(mapPath, StandardCharsets.UTF_8);
Field[][] fields = new Field[lines.size()][lines.get(0).length()];
for (int row = 0; row < lines.size(); row++) {
String line = lines.get(row);
for (int col = 0; col < line.length(); col++) {
fields[row][col] = new Field(line.charAt(col), row, col);
}
}
map = new Map(fields);
}
private boolean tryKill() {
Field me = map.getMyField();
for (Field field : map.getEnemyFields()) {
for (Field surrField : map.surroundingFields(field)) {
List<Direction> dirs = map.path(me, surrField);
if (dirs != null) {
for (Player player : players) {
//can kill this player
int remainderEnergy = energy - dirs.size() - player.hp;
if (player.id == field.content && remainderEnergy >= 0) {
//save future moves
List<String> commands = new ArrayList<>();
for (Direction dir : dirs) {
commands.add("MOVE " + dir + " 1");
}
//attacking direction
Direction attDir = surrField.dirsTo(field).get(0);
for (int i = 0; i < player.hp; i++) {
commands.add("ATTACK " + attDir);
}
if (remainderEnergy > 0) {
commands.add("PASS");
}
try {
Files.write(dataPath, commands, StandardCharsets.UTF_8);
} catch (IOException e) {}
return true;
}
}
}
}
}
return false;
}
private void sneakCloser() {
Field me = map.getMyField();
for (Direction dir : Direction.values()) {
if (!map.move(me, dir).blocked()) {
List<String> commands = new ArrayList<>();
commands.add("MOVE " + dir + " 1");
commands.add("PASS");
try {
Files.write(dataPath, commands, StandardCharsets.UTF_8);
} catch (IOException e) {}
return;
}
}
}
public static void main(String[] args) {
try {
new Assassin(Integer.parseInt(args[0])).doSomething();
} catch (Exception e) {
System.out.println("PASS");
}
}
class Map {
private Field[][] fields;
public Map(Field[][] fields) {
this.fields = fields;
}
public Field getMyField() {
for (Field[] rows : fields) {
for (Field field : rows) {
if (field.isMyPos()) {
return field;
}
}
}
return null; //should never happen
}
public List<Field> getEnemyFields() {
List<Field> enemyFields = new ArrayList<>();
for (Field[] rows : fields) {
for (Field field : rows) {
if (field.hasEnemy()) {
enemyFields.add(field);
}
}
}
return enemyFields;
}
public List<Field> surroundingFields(Field field) {
List<Field> surrFields = new ArrayList<>();
for (Direction dir : Direction.values()) {
surrFields.add(move(field, dir));
}
return surrFields;
}
public Field move(Field field, Direction dir) {
return fields[field.row + dir.rowOffset][field.col + dir.colOffset];
}
public List<Direction> path(Field from, Field to) {
List<Direction> dirs = new ArrayList<>();
Field lastField = from;
boolean changed = false;
for (int i = 0; i < energy && lastField != to; i++) {
List<Direction> possibleDirs = lastField.dirsTo(to);
changed = false;
for (Direction dir : possibleDirs) {
Field nextField = move(lastField, dir);
if (!nextField.blocked()) {
lastField = nextField;
changed = true;
dirs.add(dir);
break;
}
}
if (!changed) {
return null; //not possible
}
}
if (lastField != to) {
return null; //not enough energy
}
return dirs;
}
}
class Field {
private char content;
private int row;
private int col;
public Field(char content, int row, int col) {
this.content = content;
this.row = row;
this.col = col;
}
public boolean hasEnemy() {
return content == '1' || content == '2' || content == '3' || content == '4';
}
public List<Direction> dirsTo(Field field) {
List<Direction> dirs = new ArrayList<>();
int distance = Math.abs(row - field.row) + Math.abs(col - field.col);
for (Direction dir : Direction.values()) {
int dirDistance = Math.abs(row - field.row + dir.rowOffset) +
Math.abs(col - field.col + dir.colOffset);
if (dirDistance < distance) {
dirs.add(dir);
}
}
if (dirs.size() == 1) { //add near directions
for (Direction dir : dirs.get(0).nearDirections()) {
dirs.add(dir);
}
}
return dirs;
}
public boolean isMyPos() {
return content == '@';
}
public boolean blocked() {
return content != ' ';
}
}
class Player {
private char id;
private int hp;
public Player(char id, int hp) {
this.id = id;
this.hp = hp;
}
}
enum Direction {
N(-1, 0),S(1, 0),E(0, 1),W(0, -1);
private final int rowOffset;
private final int colOffset;
Direction(int rowOffset, int colOffset) {
this.rowOffset = rowOffset;
this.colOffset = colOffset;
}
public Direction[] nearDirections() {
Direction[] dirs = new Direction[2];
for (int i = 0; i < Direction.values().length; i++) {
Direction currentDir = Direction.values()[i];
if (Math.abs(currentDir.rowOffset) != Math.abs(this.rowOffset)) {
dirs[i%2] = currentDir;
}
}
return dirs;
}
}
}