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.
262 lines
7.6 KiB
262 lines
7.6 KiB
package de.tims.tictactoe.ai;
|
|
|
|
import static org.assertj.core.api.Assertions.*;
|
|
import static org.mockito.Mockito.*;
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.api.extension.ExtendWith;
|
|
import org.junit.jupiter.params.ParameterizedTest;
|
|
import org.junit.jupiter.params.provider.Arguments;
|
|
import org.junit.jupiter.params.provider.MethodSource;
|
|
import org.mockito.Mock;
|
|
import org.mockito.junit.jupiter.MockitoExtension;
|
|
|
|
import de.tims.tictactoe.GameLogic;
|
|
|
|
@ExtendWith(MockitoExtension.class)
|
|
class AIHardTest {
|
|
static int size = 3;
|
|
|
|
@Mock
|
|
private GameLogic gl;
|
|
|
|
@Test
|
|
void emptyBoardChooseMiddleField() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
verify(gl, times(1)).setField(1, 1, realChar);
|
|
}
|
|
|
|
@Test
|
|
void middleFieldAlreadySetChooseEdgeField() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'-', '-', '-'}, {'-', 'x', '-'}, {'-', '-', '-'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
verify(gl, times(1)).setField(0, 0, realChar);
|
|
}
|
|
|
|
@Test
|
|
void opponentDidntChooseMiddleFieldSoAIDoes() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'-', '-', 'x'}, {'-', '-', '-'}, {'-', '-', '-'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
verify(gl, times(1)).setField(1, 1, realChar);
|
|
}
|
|
|
|
@Test
|
|
void setEdgeFieldInSecondMove() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'x', '-', '-'}, {'-', 'o', '-'}, {'-', '-', '-'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
verify(gl, times(1)).setField(0, 2, realChar);
|
|
}
|
|
|
|
@Test
|
|
void preventOpponentsWinInRow() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'o', '-', '-'}, {'x', 'x', '-'}, {'-', '-', '-'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
verify(gl, times(1)).setField(1, 2, realChar);
|
|
}
|
|
|
|
@Test
|
|
void preventOpponentsWinInCol() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'o', 'x', '-'}, {'-', 'x', '-'}, {'-', '-', '-'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
verify(gl, times(1)).setField(2, 1, realChar);
|
|
}
|
|
|
|
@Test
|
|
void preventOpponentsWinInDiag() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'x', '-', 'o'}, {'-', 'x', '-'}, {'-', '-', '-'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
verify(gl, times(1)).setField(2, 2, realChar);
|
|
}
|
|
|
|
@Test
|
|
void when2InRowSetThird() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'o', '-', 'o'}, {'-', 'x', '-'}, {'x', 'x', '-'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
verify(gl, times(1)).setField(0, 1, realChar);
|
|
}
|
|
|
|
@Test
|
|
void when2InColSetThird() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'o', '-', 'x'}, {'-', 'x', '-'}, {'o', '-', 'x'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
verify(gl, times(1)).setField(1, 0, realChar);
|
|
}
|
|
|
|
@Test
|
|
void when2inDiagSetThird() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'o', '-', 'x'}, {'-', 'o', 'x'}, {'-', '-', '-'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
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);
|
|
}
|
|
|
|
@Test
|
|
void alwaysSetInTheNearestEdgeToOpponentsX() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'-', '-', '-'}, {'-', 'o', 'x'}, {'-', '-', '-'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
verify(gl, times(1)).setField(0, 2, realChar);
|
|
}
|
|
|
|
@Test
|
|
void chooseFieldWhichCreatesMostOpportunitiesToWin() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'-', 'x', 'o'}, {'-', 'o', '-'}, {'x', '-', '-'} }).when(gl).getBoard();
|
|
|
|
TicTacToeAI ai = new AIHard(gl);
|
|
ai.calculateNextMove();
|
|
|
|
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);
|
|
}
|
|
|
|
@Test
|
|
void ifRowAndColWithSameNumberContainEachContainTwoCharsDontIgnoreCol() {
|
|
char realChar = 'o';
|
|
doReturn(new char[][] { {'x', 'o', 'x'}, {'-', 'o', '-'}, {'o', 'x', 'x'} }).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) {
|
|
doReturn(board).when(gl).getBoard();
|
|
|
|
AIHard ai = new AIHard(gl);
|
|
int realResult = ai.countCharsInRow(rowNum, charToCount);
|
|
|
|
assertThat(realResult).describedAs(testName).isEqualTo(expectedResult);
|
|
}
|
|
|
|
private static Stream<Arguments> testCasesForCountCharsInRow() {
|
|
return Stream.of(Arguments.of("EmptyFieldReturns0",
|
|
new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} },
|
|
0, 'o', 0),
|
|
Arguments.of("TwoCharsInRowReturnsTwo",
|
|
new char[][] { {'-', '-', '-'}, {'o', 'o', '-'}, {'-', '-', '-'} },
|
|
1, 'o', 2));
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@MethodSource("testCasesForCountCharsInCol")
|
|
void countCharsInColTest(String testName, char[][] board, int colNum, char charToCount, int expectedResult) {
|
|
doReturn(board).when(gl).getBoard();
|
|
|
|
AIHard ai = new AIHard(gl);
|
|
int realResult = ai.countCharsInCol(colNum, charToCount);
|
|
|
|
assertThat(realResult).describedAs(testName).isEqualTo(expectedResult);
|
|
}
|
|
|
|
private static Stream<Arguments> testCasesForCountCharsInCol() {
|
|
return Stream.of(Arguments.of("EmptyFieldReturns0",
|
|
new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} },
|
|
0, 'o', 0),
|
|
Arguments.of("TwoCharsInRowReturnsTwo",
|
|
new char[][] { {'-', '-', '-'}, {'o', 'o', '-'}, {'-', '-', '-'} },
|
|
1, 'o', 1));
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@MethodSource("testCasesForCountCharsInDiag")
|
|
void countCharsInDiagTest(String testName, char[][] board, int diagNum, char charToCount, int expectedResult) {
|
|
doReturn(board).when(gl).getBoard();
|
|
|
|
AIHard ai = new AIHard(gl);
|
|
int realResult = ai.countCharsInDiag(diagNum, charToCount);
|
|
|
|
assertThat(realResult).describedAs(testName).isEqualTo(expectedResult);
|
|
}
|
|
|
|
private static Stream<Arguments> testCasesForCountCharsInDiag() {
|
|
return Stream.of(Arguments.of("EmptyFieldReturns0",
|
|
new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} },
|
|
0, 'o', 0),
|
|
Arguments.of("TwoCharsInRowReturnsTwo",
|
|
new char[][] { {'-', '-', 'o'}, {'o', 'o', '-'}, {'-', '-', '-'} },
|
|
1, 'o', 2));
|
|
}
|
|
|
|
@Test
|
|
void invalidIndexCausesIndexOutOfBoundsException() {
|
|
int index = 2;
|
|
char charToCount = 'o';
|
|
String msg = "Only 0 and 1 are allowed values for index!";
|
|
doReturn(new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} }).when(gl).getBoard();
|
|
|
|
AIHard ai = new AIHard(gl);
|
|
|
|
assertThatThrownBy(() -> {ai.countCharsInDiag(index, charToCount);}).isInstanceOf(IndexOutOfBoundsException.class).hasMessage(msg);
|
|
}
|
|
|
|
}
|