v1.0: Always holds. Optimal attack pattern: 75% survival vs L, 50% vs W, 100% otherwise (CamoWolf notwithstanding).
v2.0: Included some move logic to improve lone survival. Estimates survival chances for each potential move. As you can see by commented out code, I was going to try and guess the moves of a neighbour 'W', but my attempts did not yield better results than assuming equal distribution.
Originally I wasn't going to update this, as it is clearly just a fun entry. But I thought I could do better than 60% survival rate (although that is still better than some...)
package animals; import java.util.ArrayList; import java.util.List; import java.util.Random; public class LoneWolf extends Animal { private final static Attack[] attacks = Attack.values(); private final static Move[] moves = Move.values(); private final static Random random = new Random(); private static boolean highlander = false; private boolean lionDown = false; public LoneWolf() throws InstantiationException { super('W'); if (!highlander) { highlander = true; } else { throw new InstantiationException("There can only be one!"); } } @Override public Attack fight(char c) { switch (c) { case 'B': case 'L': return Attack.SCISSORS; case 'S': return Attack.PAPER; case 'W': default: return attacks[random.nextInt(3)]; } } @Override public Move move() { return// Lions are deterministic. lionDown = !lionDown; // Wolves are not... double[] spaceSurvival = new double[5]; // up, right, down, left, hold double[] enemyMoves = new double[5]; for (int i = 0; i < 5; ++i) { spaceSurvival[i] = 1.0; enemyMoves[i] = 0.2; // ... assume equal chance. } switch (surroundings[0][0]) { // top left case 'L': if (lionDown) { spaceSurvival[Move.LEFT.ordinal()] *= 0.75; } else { spaceSurvival[Move.UP.ordinal()] *= 0.75; } break; case 'W': //enemyMoves = PredictWolfMoves(0,0); spaceSurvival[Move.LEFT.ordinal()] *= ((1.0 - enemyMoves[Move.DOWN.ordinal()]) * 0.5); spaceSurvival[Move.UP.ordinal()] *= ((1.0 - enemyMoves[Move.RIGHT.ordinal()]) * 0.5); break; } switch (surroundings[0][1]) { // top case 'L': if (lionDown) { spaceSurvival[Move.HOLD.ordinal()] *= 0.75; } break; case 'W': //enemyMoves = PredictWolfMoves(0,1); spaceSurvival[Move.HOLD.ordinal()] *= ((1.0 - enemyMoves[Move.DOWN.ordinal()]) * 0.5); spaceSurvival[Move.UP.ordinal()] *= ((1.0 - enemyMoves[Move.HOLD.ordinal()]) * 0.5); break; } switch (surroundings[0][2]) { // top right case 'L': if (lionDown) { spaceSurvival[Move.RIGHT.ordinal()] *= 0.75; } break; case 'W': //enemyMoves = PredictWolfMoves(0,2); spaceSurvival[Move.RIGHT.ordinal()] *= ((1.0 - enemyMoves[Move.DOWN.ordinal()]) * 0.5); spaceSurvival[Move.UP.ordinal()] *= ((1.0 - enemyMoves[Move.LEFT.ordinal()]) * 0.5); break; } switch (surroundings[1][0]) { // left case 'L': if (!lionDown) { spaceSurvival[Move.HOLD.ordinal()] *= 0.75; } break; case 'W': //enemyMoves = PredictWolfMoves(1,0); spaceSurvival[Move.LEFT.ordinal()] *= ((1.0 - enemyMoves[Move.HOLD.ordinal()]) * 0.5); spaceSurvival[Move.HOLD.ordinal()] *= ((1.0 - enemyMoves[Move.RIGHT.ordinal()]) * 0.5); break; } switch (surroundings[1][2]) { // right case 'W': //enemyMoves = PredictWolfMoves(1,2); spaceSurvival[Move.RIGHT.ordinal()] *= ((1.0 - enemyMoves[Move.HOLD.ordinal()]) * 0.5); spaceSurvival[Move.HOLD.ordinal()] *= ((1.0 - enemyMoves[Move.LEFT.ordinal()]) * 0.5); break; } switch (surroundings[2][0]) { // bottom left case 'L': if (!lionDown) { spaceSurvival[Move.DOWN.ordinal()] *= 0.75; } break; case 'W': //enemyMoves = PredictWolfMoves(2,0); spaceSurvival[Move.LEFT.ordinal()] *= ((1.0 - enemyMoves[Move.UP.ordinal()]) * 0.5); spaceSurvival[Move.DOWN.ordinal()] *= ((1.0 - enemyMoves[Move.RIGHT.ordinal()]) * 0.5); break; } switch (surroundings[2][1]) { // bottom case 'W': //enemyMoves = PredictWolfMoves(2,1); spaceSurvival[Move.HOLD.ordinal()] *= ((1.0 - enemyMoves[Move.UP.ordinal()]) * 0.5); spaceSurvival[Move.DOWN.ordinal()] *= ((1.0 - enemyMoves[Move.HOLD.ordinal()]) * 0.5); break; } switch (surroundings[2][2]) { // bottom right case 'W': //enemyMoves = PredictWolfMoves(2,2); spaceSurvival[Move.RIGHT.ordinal()] *= ((1.0 - enemyMoves[Move.UP.ordinal()]) * 0.5); spaceSurvival[Move.DOWN.ordinal()] *= ((1.0 - enemyMoves[Move.LEFT.ordinal()]) * 0.5); break; } Move bestMove = Move.HOLD; for (int i = 0; i < spaceSurvival.length; ++i) { if (spaceSurvival[i] > spaceSurvival[bestMove.ordinal()]) { bestMove = moves[i]; } } return bestMove; } }