ChoiceCat
For every possible new cat positions we check its goodness and choose the best one. Goodness is the function of the two best neighbour cells who are further away from the cat position than the position whose score we calculate. We use only two cells because one can be blocked and the cat only needs one more to get away. Our function prefers two fairly good cells than one great and one bad. Positions with buckets have a score of 0 and the furthest free cells have a score of 1.
ChoiceCat seems to score better than the current cats.
package players; /** * @author randomra */ import java.util.Arrays; import main.Field; public class ChoiceCat implements Cat { private class Values { public final int size; private double[][] f; Values(int size) { this.size = size; f = new double[size][size]; } public double read(int[] p) { int i = p[0]; int j = p[1]; i = (i % size + size) % size; j = (j % size + size) % size; return f[i][j]; } private double write(int[] p, double v) { int i = p[0]; int j = p[1]; i = (i % size + size) % size; j = (j % size + size) % size; return f[i][j] = v; } } final int[][] turns = { { -1, 1 }, { 0, 1 }, { 1, 0 }, { 1, -1 }, { 0, -1 }, { -1, 0 } };// all valid moves CW order final int stepCheck = 5; public String getName() { return "ChoiceCat"; } public int[] takeTurn(Field f) { int[] pos = f.findCat(); int[] bestMove = { 0, 1 }; double bestMoveValue = -1; for (int[] t : turns) { int[] currPos = { pos[0] + t[0], pos[1] + t[1] }; double moveValue = movePosValue(currPos, f); if (moveValue > bestMoveValue) { bestMoveValue = moveValue; bestMove = t; } } return bestMove; } private double movePosValue(int[] pos, Field f) { Values v = new Values(f.SIZE); for (int ring = stepCheck; ring >= 0; ring--) { for (int phase = 0; phase < 2; phase++) { for (int sidepos = 0; sidepos < Math.max(1, ring); sidepos++) { for (int side = 0; side < 6; side++) { int[] evalPos = new int[2]; for (int coord = 0; coord < 2; coord++) { evalPos[coord] = pos[coord] + turns[side][coord] * sidepos + turns[(side + 1) % 6][coord] * (ring - sidepos); } if (phase == 0) { if (ring == stepCheck) { // on outmost ring, init value v.write(evalPos, -1); } else { v.write(evalPos, posValue(evalPos, v, f)); } } else { // finalize position value for next turn v.write(evalPos, -v.read(evalPos)); } } } } } return -v.read(pos); } private double posValue(int[] pos, Values v, Field f) { if (f.read(pos[0], pos[1]) == Field.BUCKET) { return 0; } int count = 0; double[] product = new double[6]; for (int[] t : turns) { int[] tPos = new int[] { pos[0] + t[0], pos[1] + t[1] }; if (v.read(tPos) > 0) { product[count] = 1 - 1 / (v.read(tPos) + 1); count++; } } Arrays.sort(product); double fp = 1; for (int i = 0; i < Math.min(count,2); i++) { fp *= product[5-i]; } double retValue = Math.min(count,2) + fp; return -retValue; } }