Browse Source

tictactoe: hard ai sets first empy field if theres no better option

tictactoe
Tobias Krause 3 years ago
committed by Lorenz Hohmann
parent
commit
e305236728
  1. 66
      src/main/java/de/tims/tictactoe/ai/AIHard.java
  2. 11
      src/test/java/de/tims/tictactoe/ai/AIHardTest.java

66
src/main/java/de/tims/tictactoe/ai/AIHard.java

@ -19,13 +19,17 @@ public class AIHard implements TicTacToeAI {
@Override @Override
public void calculateNextMove() { public void calculateNextMove() {
char[][] board = gl.getBoard();
int row;
int col;
int charsInRow = 0; int charsInRow = 0;
int charsInCol = 0; int charsInCol = 0;
int charsInDiag = 0; int charsInDiag = 0;
char[][] board = gl.getBoard();
char actualChar;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
char actualChar = (i == 0) ? AI_CHAR : PLAYER_CHAR;
actualChar = (i == 0) ? AI_CHAR : PLAYER_CHAR;
for (int j = 0; j < BOARD_SIZE; j++) { for (int j = 0; j < BOARD_SIZE; j++) {
charsInRow = countCharsInRow(j, actualChar); charsInRow = countCharsInRow(j, actualChar);
@ -35,8 +39,11 @@ public class AIHard implements TicTacToeAI {
charsInDiag = countCharsInDiag(j, actualChar); charsInDiag = countCharsInDiag(j, actualChar);
if (charsInDiag == BOARD_SIZE - 1) { if (charsInDiag == BOARD_SIZE - 1) {
for (int k = 0; k < BOARD_SIZE; k++) { for (int k = 0; k < BOARD_SIZE; k++) {
if (board[k][(j == 0) ? k : BOARD_SIZE - 1 - k] == EMPTY_CHAR) {
gl.setField(k, (j == 0) ? k : BOARD_SIZE - 1 -k, AI_CHAR);
row = k;
col = (j == 0) ? k : BOARD_SIZE - 1 - k;
if (board[row][col] == EMPTY_CHAR) {
gl.setField(row, col, AI_CHAR);
return; return;
} }
} }
@ -45,8 +52,11 @@ public class AIHard implements TicTacToeAI {
if (charsInRow == BOARD_SIZE - 1 || charsInCol == BOARD_SIZE - 1) { if (charsInRow == BOARD_SIZE - 1 || charsInCol == BOARD_SIZE - 1) {
for (int k = 0; k < BOARD_SIZE; k++) { for (int k = 0; k < BOARD_SIZE; k++) {
if (board[(charsInRow == BOARD_SIZE - 1) ? j : k][(charsInRow == BOARD_SIZE - 1) ? k : j] == EMPTY_CHAR) {
gl.setField((charsInRow == BOARD_SIZE - 1) ? j : k, (charsInRow == BOARD_SIZE - 1) ? k : j, AI_CHAR);
row = (charsInRow == BOARD_SIZE - 1) ? j : k;
col = (charsInRow == BOARD_SIZE - 1) ? k : j;
if (board[row][col] == EMPTY_CHAR) {
gl.setField(row, col, AI_CHAR);
return; return;
} }
} }
@ -56,26 +66,37 @@ public class AIHard implements TicTacToeAI {
if (board[BOARD_SIZE / 2][BOARD_SIZE / 2] == EMPTY_CHAR) { if (board[BOARD_SIZE / 2][BOARD_SIZE / 2] == EMPTY_CHAR) {
gl.setField(BOARD_SIZE / 2, BOARD_SIZE / 2, AI_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)) { } 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 i = BOARD_SIZE - 2; i > 0; i--) {
for (int j = 0; j < BOARD_SIZE; j += BOARD_SIZE - 1) { for (int j = 0; j < BOARD_SIZE; j += BOARD_SIZE - 1) {
for (int k = 1; k < BOARD_SIZE - 1; k++) { for (int k = 1; k < BOARD_SIZE - 1; k++) {
if (countCharsInRow(j, AI_CHAR) == i && countCharsInCol(k, AI_CHAR) == i && countCharsInRow(j, EMPTY_CHAR) == BOARD_SIZE -i && countCharsInCol(k, EMPTY_CHAR) == BOARD_SIZE - i) {
gl.setField(j, k, AI_CHAR);
return;
}
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 (countCharsInRow(k, AI_CHAR) == i && countCharsInCol(j, AI_CHAR) == i && countCharsInRow(k, EMPTY_CHAR) == BOARD_SIZE -i && countCharsInCol(j, EMPTY_CHAR) == BOARD_SIZE - i) {
gl.setField(k, j, AI_CHAR);
if (onwCharsInRow >= i && ownCharsInCol >= i && emptyCharsInRow >= BOARD_SIZE - onwCharsInRow && emptyCharsInCol == BOARD_SIZE - ownCharsInCol) {
gl.setField(row, col, AI_CHAR);
return; return;
} }
} }
} }
} }
}
} else { } else {
boolean emptyEdgeFound = false; boolean emptyEdgeFound = false;
int row = -1;
int col = -1;
row = -1;
col = -1;
int prioRow = -1; int prioRow = -1;
int prioCol = -1; int prioCol = -1;
@ -99,7 +120,22 @@ public class AIHard implements TicTacToeAI {
} }
} }
gl.setField((prioRow != -1) ? prioRow : row, (prioCol != -1) ? prioCol : col, AI_CHAR);
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;
}
}
} }
} }

11
src/test/java/de/tims/tictactoe/ai/AIHardTest.java

@ -165,6 +165,17 @@ class AIHardTest {
verify(gl, times(1)).setField(1, 2, realChar); verify(gl, times(1)).setField(1, 2, realChar);
} }
@Test
void setFirstFreeFieldIfNoBetterOpportunities() {
char realChar = 'o';
doReturn(new char[][] { {'o', 'x', 'x'}, {'x', 'o', 'o'}, {'o', '-', 'x'} }).when(gl).getBoard();
TicTacToeAI ai = new AIHard(gl);
ai.calculateNextMove();
verify(gl, times(1)).setField(2, 1, realChar);
}
@ParameterizedTest @ParameterizedTest
@MethodSource("testCasesForCountCharsInRow") @MethodSource("testCasesForCountCharsInRow")
void countCharsInRowTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) { void countCharsInRowTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) {

Loading…
Cancel
Save