얕은 파랑
진한 파란색 은 가능한 움직임에 대한 철저한 트리 검색을 통해 미래에 어떤 일이 일어날 지 알아 내려고 하지만 불행히도 다음 차례보다 더 이상 얻지 못합니다. 그는 다음 턴 후 가능한 각 보드 스테이트에서 반 반점을 치고 똑같이 어리석은 공식으로 각 지점에 대한 점수를 계산합니다.
편집 : 원래 코드가 너무 느리게 실행되어 가능한 모든 이동의 무작위 샘플 만 가져 오도록 수정했습니다. 가능한 움직임이 거의 없을 때 거의 모든 움직임을 시도하고 가능한 움직임이 많을 때 더 적은 비율을 시도합니다.
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);
}
}