From a786eb7496cc9199099e22045bd2afd6368c2c1c Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 11:58:53 +0100 Subject: [PATCH] tictactoe: added easy AI --- .../java/de/tims/tictactoe/ai/AIEasy.java | 28 +++++++++++++ .../de/tims/tictactoe/ai/TicTacToeAI.java | 5 +++ .../java/de/tims/tictactoe/ai/AIEasyTest.java | 41 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 src/main/java/de/tims/tictactoe/ai/AIEasy.java create mode 100644 src/main/java/de/tims/tictactoe/ai/TicTacToeAI.java create mode 100644 src/test/java/de/tims/tictactoe/ai/AIEasyTest.java diff --git a/src/main/java/de/tims/tictactoe/ai/AIEasy.java b/src/main/java/de/tims/tictactoe/ai/AIEasy.java new file mode 100644 index 0000000..308eaf1 --- /dev/null +++ b/src/main/java/de/tims/tictactoe/ai/AIEasy.java @@ -0,0 +1,28 @@ +package de.tims.tictactoe.ai; + +import de.tims.tictactoe.GameLogic; + +import java.util.Random; + +public class AIEasy implements TicTacToeAI { + private static final char AI_CHAR = 'o'; + + private Random rand; + private GameLogic gl; + private int boardSize; + + public AIEasy(GameLogic gl) { + this.gl = gl; + boardSize = gl.getBoard().length; + rand = new Random(gl.getBoard().hashCode()); + } + + @Override + public void calculateNextMove() { + char[][] board = gl.getBoard(); + int row = rand.nextInt(boardSize); + int col = rand.nextInt(boardSize); + gl.setField(row, col, AI_CHAR); + } + +} diff --git a/src/main/java/de/tims/tictactoe/ai/TicTacToeAI.java b/src/main/java/de/tims/tictactoe/ai/TicTacToeAI.java new file mode 100644 index 0000000..f0f357a --- /dev/null +++ b/src/main/java/de/tims/tictactoe/ai/TicTacToeAI.java @@ -0,0 +1,5 @@ +package de.tims.tictactoe.ai; + +public interface TicTacToeAI { + void calculateNextMove(); +} diff --git a/src/test/java/de/tims/tictactoe/ai/AIEasyTest.java b/src/test/java/de/tims/tictactoe/ai/AIEasyTest.java new file mode 100644 index 0000000..5c169ba --- /dev/null +++ b/src/test/java/de/tims/tictactoe/ai/AIEasyTest.java @@ -0,0 +1,41 @@ +package de.tims.tictactoe.ai; + +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatcher; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import de.tims.tictactoe.GameLogic; + +@ExtendWith(MockitoExtension.class) +class AIEasyTest { + static int size = 3; + + @Mock + private GameLogic gl; + + @Test + void emptyBoardChooseRandomField() { + char realChar = 'o'; + doReturn(new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} }).when(gl).getBoard(); + + TicTacToeAI ai = new AIEasy(gl); + + //run method 100 times, because of random generator + for (int i = 0; i < 100; i++) { + ai.calculateNextMove(); + } + + verify(gl, times(100)).setField(intThat(new ChooseRandomFieldMatcher()), intThat(new ChooseRandomFieldMatcher()), eq(realChar)); + } + + private static class ChooseRandomFieldMatcher implements ArgumentMatcher { + @Override + public boolean matches(Integer argument) { + return argument.intValue() >= 0 && argument.intValue() < size; + } + } +}