From 9111545ec3a0e84a741c6a0d3d94beba2632c085 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Wed, 2 Feb 2022 20:11:29 +0100 Subject: [PATCH] tictactoe: hard ai checks for own opportunity to win first --- .../java/de/tims/tictactoe/ai/AIHard.java | 70 ++++++------------- .../java/de/tims/tictactoe/ai/AIHardTest.java | 11 +++ 2 files changed, 33 insertions(+), 48 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index b6a6d6e..5146369 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -19,60 +19,34 @@ public class AIHard implements TicTacToeAI { @Override public void calculateNextMove() { - int ownCharsInRow = 0; - int ownCharsInCol = 0; - int ownCharsInDiag = 0; - int charsOfOpponentInRow = 0; - int charsOfOpponentInCol = 0; - int charsOfOpponentInDiag = 0; + int charsInRow = 0; + int charsInCol = 0; + int charsInDiag = 0; char[][] board = gl.getBoard(); - for (int i = 0; i < BOARD_SIZE; i++) { - ownCharsInRow = countCharsInRow(i, AI_CHAR); - ownCharsInCol = countCharsInCol(i, AI_CHAR); - charsOfOpponentInRow = countCharsInRow(i, PLAYER_CHAR); - charsOfOpponentInCol = countCharsInCol(i, PLAYER_CHAR); - if (i < 2) { - ownCharsInDiag = countCharsInDiag(i, AI_CHAR); - charsOfOpponentInDiag = countCharsInDiag(i, PLAYER_CHAR); - } + for (int i = 0; i < 2; i++) { + char actualChar = (i == 0) ? AI_CHAR : PLAYER_CHAR; - if (ownCharsInRow == BOARD_SIZE - 1 || ownCharsInCol == BOARD_SIZE - 1) { - for (int j = 0; j < BOARD_SIZE; j++) { - if (ownCharsInRow == BOARD_SIZE - 1) { - if (board[i][j] == EMPTY_CHAR) { - gl.setField(i, j, AI_CHAR); - return; - } - } else if (ownCharsInCol == BOARD_SIZE - 1) { - if (board[j][i] == EMPTY_CHAR) { - gl.setField(j, i, AI_CHAR); - return; - } - } else if (ownCharsInDiag == BOARD_SIZE - 1) { - if (board[j][(i == 1) ? i : BOARD_SIZE - 1 - j] == EMPTY_CHAR) { - gl.setField(j, (i == 1) ? j : BOARD_SIZE - 1 - j, AI_CHAR); - return; + 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++) { + if (board[k][(j == 0) ? k : BOARD_SIZE - 1 - k] == EMPTY_CHAR) { + gl.setField(k, (j == 0) ? k : BOARD_SIZE - 1 -k, AI_CHAR); + return; + } } } } - } - - if (charsOfOpponentInRow == BOARD_SIZE - 1 || charsOfOpponentInCol == BOARD_SIZE - 1 || charsOfOpponentInDiag == BOARD_SIZE - 1) { - for (int j = 0; j < BOARD_SIZE; j++) { - if (charsOfOpponentInRow == BOARD_SIZE - 1) { - if (board[i][j] == EMPTY_CHAR) { - gl.setField(i, j, AI_CHAR); - return; - } - } else if (charsOfOpponentInCol == BOARD_SIZE - 1) { - if (board[j][i] == EMPTY_CHAR) { - gl.setField(j, i, AI_CHAR); - return; - } - } else if (charsOfOpponentInDiag == BOARD_SIZE - 1) { - if (board[j][(i == 0) ? j : BOARD_SIZE - 1 - j] == EMPTY_CHAR) { - gl.setField(j, (i == 0) ? j : BOARD_SIZE - 1 - j, AI_CHAR); + + if (charsInRow == BOARD_SIZE - 1 || charsInCol == BOARD_SIZE - 1) { + 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); return; } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index db84c3f..53af626 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -132,6 +132,17 @@ class AIHardTest { verify(gl, times(1)).setField(2, 2, realChar); } + @Test + void opportunityToWinIsMoreImportantThanPreventingOpponentsWinInNextRound() { + char realChar = 'o'; + doReturn(new char[][] { {'x', '-', 'o'}, {'-', 'o', '-'}, {'x', 'x', 'o'} }).when(gl).getBoard(); + + TicTacToeAI ai = new AIHard(gl); + ai.calculateNextMove(); + + verify(gl, times(1)).setField(1, 2, realChar); + } + @ParameterizedTest @MethodSource("testCasesForCountCharsInRow") void countCharsInRowTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) {