シャローブルー
シャローブルーは、可能な動きを網羅的にツリー検索することにより、将来的に何が起こるかを理解しようとしますが、残念ながら、次のターンより先に進むことはできません。彼は、次のターンの後に、可能な各ボードステートで半分の得点を平手打ちし、同様にばかげた公式で個々のブランチのスコアを計算します:理想的な動きはわかっています!
編集:元のコードの実行速度が遅すぎたため、可能なすべての動きのランダムサンプルのみを取得するように修正しました。可能な動きがほとんどない場合はほぼすべての動きを試み、より多くの動きが可能な場合は割合を小さくします。
import java.awt.Point;
public class ShallowBlue {
private static final int MAX_ROUNDS = 5, PLAYERS = 4;
static int me = 0;
public static void main(String[] args) {
if (args[0] == null) {
return;
}
me = Integer.parseInt(args[0].split(",", 2)[0]);
String board = args[0].split(",", 2)[1];
System.out.println(getBestMove(board, me, MAX_ROUNDS - 1));
}
private static String getBestMove(String board, int player, int rounds) {
String [] boards = new String[24];
int checkedBoards = 1;
char playerChar = Integer.toString(player).charAt(0);
String tempMove = getMove(0, 0, 0, 0);
String tempBoard = calculateMove(board, tempMove);
boards[0] = tempBoard;
String bestMove = tempMove;
double us = numberOfUs(board, playerChar);
double skip = (us*2.5/(us*2.5 + 1))/4 + 0.735;
if (rounds == MAX_ROUNDS - 2) {
skip = skip*skip;
}
float bestScore, worstScore, averageScore, tempScore;
int scores;
if (rounds == 0) {
tempScore = calculateScore(tempBoard, MAX_ROUNDS - rounds - 1);
} else {
tempScore = getScore(getBestMove(tempBoard, player%PLAYERS + 1, rounds - 1));
}
scores = 1;
bestScore = tempScore;
worstScore = tempScore;
averageScore = tempScore;
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
if (getCharAt(board, x, y) == playerChar) {
Point[] possibleMergers = getNeighboringMatches(board, new Point(x, y), playerChar);
if (possibleMergers[0] != null) {
tempMove = getMove(possibleMergers[0].x, possibleMergers[0].y, x, y);
tempBoard = calculateMove(board, tempMove);
if (addIfUnique(boards, tempBoard, checkedBoards)) {
checkedBoards++;
if ((rounds != MAX_ROUNDS - 1) && (rounds == 0 || Math.random() < skip)) {
tempScore = calculateScore(tempBoard, MAX_ROUNDS - rounds - 1);
} else {
tempScore = getScore(getBestMove(tempBoard, player%PLAYERS + 1, rounds - 1));
}
if (tempScore > bestScore) {
bestMove = tempMove;
}
bestScore = Math.max(tempScore, bestScore);
worstScore = Math.min(tempScore, worstScore);
scores++;
averageScore = (averageScore*(scores - 1) + tempScore)/scores;
}
}
} else if (getCharAt(board, x, y) == '.') {
Point[] possibleSpreaders = getNeighboringMatches(board, new Point(x, y), playerChar);
int i = 0;
while (i < possibleSpreaders.length && possibleSpreaders[i] != null) {
tempMove = getMove(possibleSpreaders[i].x, possibleSpreaders[i].y, x, y);
tempBoard = calculateMove(board, tempMove);
if ((rounds != MAX_ROUNDS - 1) && (rounds == 0 || Math.random() < skip)) {
tempScore = calculateScore(tempBoard, MAX_ROUNDS - rounds - 1);
} else {
tempScore = getScore(getBestMove(tempBoard, player%PLAYERS + 1, rounds - 1));
}
if (tempScore > bestScore) {
bestMove = tempMove;
}
bestScore = Math.max(tempScore, bestScore);
worstScore = Math.min(tempScore, worstScore);
scores++;
averageScore = (averageScore*(scores - 1) + tempScore)/scores;
i++;
}
Point[] possibleJumpers = getNextNeighboringMatches(board, new Point(x, y), playerChar);
i = 0;
while (i < possibleJumpers.length && possibleJumpers[i] != null) {
tempMove = getMove(possibleJumpers[i].x, possibleJumpers[i].y, x, y);
tempBoard = calculateMove(board, tempMove);
if ((rounds != MAX_ROUNDS - 1) && (rounds == 0 || Math.random() < skip)) {
tempScore = calculateScore(tempBoard, MAX_ROUNDS - rounds - 1);
} else {
tempScore = getScore(getBestMove(tempBoard, player%PLAYERS + 1, rounds - 1));
}
if (tempScore > bestScore) {
bestMove = tempMove;
}
bestScore = Math.max(tempScore, bestScore);
worstScore = Math.min(tempScore, worstScore);
scores++;
averageScore = (averageScore*(scores - 1) + tempScore)/scores;
i++;
}
}
}
}
if (rounds == MAX_ROUNDS - 1) {
return (bestMove);
} else {
return getScoreString(bestScore, worstScore, averageScore);
}
}
private static int numberOfUs(String board, char playerChar) {
int us = 0;
for (int i = 0; i < board.length(); i++ ) {
if (board.charAt(i) == playerChar) {
us++;
}
}
return us;
}
private static float calculateScore(String board, int roundsPassed) {
int empties = 0;
int us = 0;
int enemy1 = 0;
int enemy2 = 0;
int enemy3 = 0;
for (int i = 0; i < board.length(); i++ ) {
if (board.charAt(i) == '.') {
empties++;
} else if (board.charAt(i) == Integer.toString(me).charAt(0)) {
us++;
} else if (board.charAt(i) == Integer.toString(me%PLAYERS + 1).charAt(0)) {
enemy1++;
} else if (board.charAt(i) == Integer.toString(me%PLAYERS + 2).charAt(0)) {
enemy2++;
} else if (board.charAt(i) == Integer.toString(me%PLAYERS + 3).charAt(0)) {
enemy3++;
}
}
if (us != 0) {
us += roundsPassed;
}
if (enemy1 != 0) {
enemy1 = enemy1 + (roundsPassed + 3)%PLAYERS;
}
if (enemy2 != 0) {
enemy2 = enemy2 + (roundsPassed + 2)%PLAYERS;
}
if (enemy3 != 0) {
enemy3 = enemy3 + (roundsPassed + 1)%PLAYERS;
}
return us*(empties + 1)/(Math.max(Math.max(enemy1, enemy2), enemy3) + 1);
}
private static float getScore(String scoreString) {
float bestScore, worstScore, averageScore;
String[] scores = new String[3];
scores = scoreString.split(",");
bestScore = Float.parseFloat(scores[0]);
worstScore = Float.parseFloat(scores[1]);
averageScore = Float.parseFloat(scores[2]);
return (float) Math.sqrt(Math.sqrt(bestScore*averageScore*worstScore*worstScore));
}
private static String getScoreString(float bestScore, float worstScore, float averageScore) {
return Float.toString(bestScore) + ',' + Float.toString(worstScore) + ',' + Float.toString(averageScore);
}
private static boolean addIfUnique(String[] boards, String board, int checkedBoards) {
int i = 0;
while (i < boards.length && boards[i] != null) {
if (boards[i].equals(board)) {
return false;
}
i++;
}
if (i < boards.length) {
boards[i] = board;
} else {
boards[checkedBoards%boards.length] = board;
}
return true;
}
private static String calculateMove(String board, String move) {
int x1 = Integer.parseInt(Character.toString(move.charAt(0)));
int y1 = Integer.parseInt(Character.toString(move.charAt(2)));
int x2 = Integer.parseInt(Character.toString(move.charAt(4)));
int y2 = Integer.parseInt(Character.toString(move.charAt(6)));
if ((Math.abs(y1 - y2) == 2 || Math.abs(x1 - x2) == 2)
&& getCharAt(board, x2, y2) == '.') {
Point[] enemies = new Point[8];
enemies = getNeighboringEnemies(board, new Point(x1, y1), Integer.parseInt(Character.toString(getCharAt(board, x1, y1))));
board = replace(board, enemies, getCharAt(board, x1, y1));
Point[] middle = {new Point(x1, y1)};
board = replace(board, middle, '.');
}
if ((Math.abs(y1 - y2) == 1 || Math.abs(x1 - x2) == 1)) {
if (getCharAt(board, x2, y2) == '.' || getCharAt(board, x1, y1) == getCharAt(board, x2, y2)) {
boolean merge = true;
if (getCharAt(board, x2, y2) == '.') {
merge = false;
}
Point[] spaces = new Point[8];
spaces = getNeighboringMatches(board, new Point(x1, y1), '.');
board = replace(board, spaces, getCharAt(board, x1, y1));
if (merge) {
Point[] source = {new Point(x1, y1)};
board = replace(board, source, '.');
}
}
}
return board;
}
private static String replace(String board, Point[] targets, char source) {
int i = 0;
while (i < targets.length && targets[i] != null) {
if (targets[i].x == 7 && targets[i].y == 7) {
board = board.substring(0, getIndexAt(targets[i].x, targets[i].y)) + source;
} else if (targets[i].x == 0 && targets[i].y == 0) {
board = source + board.substring(getIndexAt(targets[i].x, targets[i].y) + 1);
} else {
board = board.substring(0, getIndexAt(targets[i].x, targets[i].y)) + source + board.substring(getIndexAt(targets[i].x, targets[i].y) + 1);
}
i++;
}
return board;
}
private static Point[] getNeighboringMatches(String board, Point coord, char match) {
Point[] matches = new Point[8];
int i = 0;
for (int x = coord.x - 1; x <= coord.x + 1; x++) {
for (int y = coord.y - 1; y <= coord.y + 1; y++) {
if ((y != coord.y || x != coord.x ) && getCharAt(board, x, y) == match){
matches[i] = new Point(x, y);
i++;
}
}
}
return matches;
}
private static Point[] getNeighboringEnemies(String board, Point coord, int player) {
Point[] enemies = new Point[8];
for (int i = 1; i <= PLAYERS; i++){
enemies = mergeArr(enemies, getNeighboringMatches(board, coord, Integer.toString((player + i - 1)%PLAYERS + 1).charAt(0)));
}
return enemies;
}
private static Point[] getNextNeighboringMatches(String board, Point coord, char match) {
Point[] matches = new Point[16];
int i = 0;
for (int x = coord.x - 2; x <= coord.x + 2; x++) {
for (int y = coord.y - 2; y <= coord.y + 2; y++) {
if ((Math.abs(y - coord.y) == 2 || Math.abs(x - coord.x) == 2) && getCharAt(board, x, y) == match){
matches[i] = new Point(x, y);
i++;
}
}
}
return matches;
}
private static char getCharAt(String board, int x, int y) {
if (x >= 0 && x < 8 && y >= 0 && y < 8) {
return board.charAt(9*x + y);
} else {
return '\0';
}
}
private static int getIndexAt(int x, int y) {
return 9*x + y;
}
private static Point[] mergeArr(Point[] arr1, Point[] arr2) {
int i = 0;
int j = 0;
while (i < arr1.length && arr1[i] != null) {
i++;
}
while (j < arr2.length && arr2[j] != null) {
arr1[i + j] = arr2[j];
j++;
}
return arr1;
}
private static String getMove(int x1, int y1, int x2, int y2) {
return Integer.toString(x1) + " " + Integer.toString(y1) + " " + Integer.toString(x2) + " " + Integer.toString(y2);
}
}