GreedyAutopilot.java
package me.schawe.multijsnake.snake.ai;
import me.schawe.multijsnake.snake.GameState;
import me.schawe.multijsnake.snake.Move;
import me.schawe.multijsnake.snake.Snake;
import java.util.List;
import java.util.Optional;
import java.util.Random;
public class GreedyAutopilot implements Autopilot {
private enum Strategy {
horizontal,
vertical,
diagonal;
public static Strategy random() {
double r = 3. * Math.random();
if(r < 1) {
return Strategy.horizontal;
} else if (r < 2) {
return Strategy.vertical;
} else if (r < 3) {
return Strategy.diagonal;
}
// this will not happen
return Strategy.diagonal;
}
}
private final Random random;
private final Strategy strategy;
public GreedyAutopilot() {
random = new Random();
strategy = Strategy.random();
}
private Optional<Move> horizontalDirection(int sourceX, int targetX) {
if (sourceX < targetX)
return Optional.of(Move.right);
else if (sourceX > targetX)
return Optional.of(Move.left);
else
return Optional.empty();
}
private Optional<Move> verticalDirection(int sourceY, int targetY) {
if (sourceY < targetY)
return Optional.of(Move.down);
else if (sourceY > targetY)
return Optional.of(Move.up);
else
return Optional.empty();
}
private Move shortestWay(GameState gameState, Snake snake) {
switch (strategy) {
case horizontal:
return horizontalDirection(snake.getHead().getX(), gameState.getFood().getX())
.orElse(
verticalDirection(snake.getHead().getY(), gameState.getFood().getY())
.orElse(snake.getHeadDirection())
);
case vertical:
return verticalDirection(snake.getHead().getY(), gameState.getFood().getY())
.orElse(
horizontalDirection(snake.getHead().getX(), gameState.getFood().getX())
.orElse(snake.getHeadDirection())
);
case diagonal:
if (Math.abs(snake.getHead().getY() - gameState.getFood().getY()) > Math.abs(snake.getHead().getX() - gameState.getFood().getX())) {
return verticalDirection(snake.getHead().getY(), gameState.getFood().getY()).orElse(snake.getHeadDirection());
} else {
return horizontalDirection(snake.getHead().getX(), gameState.getFood().getX()).orElse(snake.getHeadDirection());
}
}
// this will not happen
throw new RuntimeException("unreachable!");
}
@Override
public Move suggest(GameState gameState, Snake snake) {
Move bestMove = shortestWay(gameState, snake);
if(isSafeMove(gameState, snake, bestMove)) {
return bestMove;
} else {
List<Move> moves = possibleMoves(gameState, snake);
if (moves.size() <= 0) {
return snake.getHeadDirection();
}
int r = random.nextInt(moves.size());
return moves.get(r);
}
}
@Override
public String generateName() {
String[] names = {
"Rhombus", "Trapezoid", "Trapezium", "Hexagon", "Pentagon", "Octagon",
"Heptagon", "Nonagon", "Decagon", "Octahedron", "Dodecahedron", "Icosahedron",
"Oloid", "Sphericon", "Hyperboloid", "Isochrone", "Horopter", "Syntractrix",
"Trochoid", "Nephroid"
};
int r = random.nextInt(names.length);
return names[r];
}
}