You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

190 lines
4.8 KiB

package de.tims.tictactoe.ai;
import de.tims.tictactoe.GameLogic;
public class AIHard implements TicTacToeAI {
private static final char AI_CHAR = 'o';
private static final char EMPTY_CHAR = '-';
private static final char PLAYER_CHAR = 'x';
private static final int BOARD_SIZE = 3;
private GameLogic gl;
public AIHard(GameLogic gl) throws IllegalArgumentException {
if (gl.getBoard().length != BOARD_SIZE) {
throw new IllegalArgumentException("Hard AI only supports 3x3 boards!");
}
this.gl = gl;
}
@Override
public void calculateNextMove() {
char[][] board = gl.getBoard();
int row;
int col;
int charsInRow = 0;
int charsInCol = 0;
int charsInDiag = 0;
char actualChar;
for (int i = 0; i < 2; i++) {
actualChar = (i == 0) ? AI_CHAR : PLAYER_CHAR;
for (int j = 0; j < BOARD_SIZE; j++) {
charsInRow = countCharsInRow(j, actualChar);
charsInCol = countCharsInCol(j, actualChar);
if (j < 2) {
charsInDiag = countCharsInDiag(j, actualChar);
if (charsInDiag == BOARD_SIZE - 1) {
for (int k = 0; k < BOARD_SIZE; k++) {
row = k;
col = (j == 0) ? k : BOARD_SIZE - 1 - k;
if (board[row][col] == EMPTY_CHAR) {
gl.setField(row, col, AI_CHAR);
return;
}
}
}
}
if (charsInRow == BOARD_SIZE - 1 || charsInCol == BOARD_SIZE - 1) {
for (int k = 0; k < BOARD_SIZE; k++) {
if (charsInRow == BOARD_SIZE - 1) {
row = j;
col = k;
if (board[row][col] == EMPTY_CHAR) {
gl.setField(row, col, AI_CHAR);
return;
}
}
if (charsInCol == BOARD_SIZE - 1) {
row = k;
col = j;
if (board[row][col] == EMPTY_CHAR) {
gl.setField(row, col, AI_CHAR);
return;
}
}
}
}
}
}
if (board[BOARD_SIZE / 2][BOARD_SIZE / 2] == EMPTY_CHAR) {
gl.setField(BOARD_SIZE / 2, BOARD_SIZE / 2, AI_CHAR);
return;
} else if (board[BOARD_SIZE / 2][BOARD_SIZE / 2] == AI_CHAR && (board[0][0] == AI_CHAR || board[0][BOARD_SIZE - 1] == AI_CHAR || board[BOARD_SIZE - 1][0] == AI_CHAR || board[BOARD_SIZE - 1][BOARD_SIZE - 1] == AI_CHAR)) {
int onwCharsInRow = 0;
int ownCharsInCol = 0;
int emptyCharsInRow = 0;
int emptyCharsInCol = 0;
for (int i = BOARD_SIZE - 2; i > 0; i--) {
for (int j = 0; j < BOARD_SIZE; j += BOARD_SIZE - 1) {
for (int k = 1; k < BOARD_SIZE - 1; k++) {
for (int l = 0; l < 2; l++) {
row = (l == 0) ? j : k;
col = (l == 0) ? k : j;
onwCharsInRow = countCharsInRow(row, AI_CHAR);
ownCharsInCol = countCharsInCol(col, AI_CHAR);
emptyCharsInRow = countCharsInRow(row, EMPTY_CHAR);
emptyCharsInCol = countCharsInCol(col, EMPTY_CHAR);
if (onwCharsInRow >= i && ownCharsInCol >= i && emptyCharsInRow >= BOARD_SIZE - onwCharsInRow && emptyCharsInCol == BOARD_SIZE - ownCharsInCol) {
gl.setField(row, col, AI_CHAR);
return;
}
}
}
}
}
} else {
boolean emptyEdgeFound = false;
row = -1;
col = -1;
int prioRow = -1;
int prioCol = -1;
for (int i = 0; i < BOARD_SIZE; i = i + BOARD_SIZE - 1) {
for (int j = 0; j < BOARD_SIZE; j = j + BOARD_SIZE - 1) {
if (board[i][j] == EMPTY_CHAR) {
row = (row == -1) ? i : row;
col = (col == -1) ? j : col;
if (countCharsInRow(i, PLAYER_CHAR) != 0 || countCharsInCol(j, PLAYER_CHAR) != 0) {
prioRow = i;
prioCol = j;
emptyEdgeFound = true;
break;
}
}
}
if (emptyEdgeFound) {
break;
}
}
if (row != -1 && col != -1) {
row = (prioRow != -1) ? prioRow : row;
col = (prioCol != -1) ? prioCol : col;
gl.setField(row, col, AI_CHAR);
return;
}
}
for (row = 0; row < BOARD_SIZE; row++) {
for (col = 0; col < BOARD_SIZE; col++) {
if (board[row][col] == EMPTY_CHAR) {
gl.setField(row, col, AI_CHAR);
return;
}
}
}
}
public int countCharsInRow(int index, char charToCount) {
int count = 0;
char[][] board = gl.getBoard();
for (int i = 0; i < BOARD_SIZE; i++) {
count += (board[index][i] == charToCount) ? 1 : 0;
}
return count;
}
public int countCharsInCol(int index, char charToCount) {
int count = 0;
char[][] board = gl.getBoard();
for (int i = 0; i < BOARD_SIZE; i++) {
count += (board[i][index] == charToCount) ? 1 : 0;
}
return count;
}
public int countCharsInDiag(int index, char charToCount) throws IndexOutOfBoundsException {
if (index < 0 || index > 1) {
throw new IndexOutOfBoundsException("Only 0 and 1 are allowed values for index!");
}
int count = 0;
char[][] board = gl.getBoard();
for (int i = 0; i < BOARD_SIZE; i++) {
count += (board[i][(index == 0) ? i : BOARD_SIZE - 1 - i] == charToCount) ? 1 : 0;
}
return count;
}
}