From 2c299f689ab1adbb617026731eccca44a4e14ca0 Mon Sep 17 00:00:00 2001 From: Lorenz Hohmann Date: Wed, 12 Jan 2022 11:41:14 +0100 Subject: [PATCH 01/79] Added GameManager and check if GameState is correct after start function call --- .../java/de/tims/fleetstorm/GameManager.java | 19 +++++++++++++++++ .../de/tims/fleetstorm/GameManagerTest.java | 21 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/main/java/de/tims/fleetstorm/GameManager.java create mode 100644 src/test/java/de/tims/fleetstorm/GameManagerTest.java diff --git a/src/main/java/de/tims/fleetstorm/GameManager.java b/src/main/java/de/tims/fleetstorm/GameManager.java new file mode 100644 index 0000000..8f682cc --- /dev/null +++ b/src/main/java/de/tims/fleetstorm/GameManager.java @@ -0,0 +1,19 @@ +package de.tims.fleetstorm; + +public class GameManager { + + private int gameState; + + public static final int PREPARATION = 1; + public static final int RUNNING = 2; + public static final int OVER = 3; + + public void start() { + this.gameState = GameManager.PREPARATION; + } + + public int getGameState() { + return gameState; + } + +} diff --git a/src/test/java/de/tims/fleetstorm/GameManagerTest.java b/src/test/java/de/tims/fleetstorm/GameManagerTest.java new file mode 100644 index 0000000..d90e85f --- /dev/null +++ b/src/test/java/de/tims/fleetstorm/GameManagerTest.java @@ -0,0 +1,21 @@ +package de.tims.fleetstorm; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class GameManagerTest { + + GameManager gameManager = new GameManager(); + + @Test + void testIfGameStateIsPreparationAfterStart() { + gameManager.start(); + int expectedState = GameManager.PREPARATION; + + int calculatedState = gameManager.getGameState(); + + assertEquals(expectedState, calculatedState); + } + +} From 4e743e694e30bb8a742989bebe352155fdf2676c Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Sun, 30 Jan 2022 13:26:44 +0100 Subject: [PATCH 02/79] tictactoe: added class for gamelogic --- .../java/de/tims/tictactoe/GameLogic.java | 5 ++++ .../java/de/tims/tictactoe/GameLogicTest.java | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/main/java/de/tims/tictactoe/GameLogic.java create mode 100644 src/test/java/de/tims/tictactoe/GameLogicTest.java diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java new file mode 100644 index 0000000..5980f54 --- /dev/null +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -0,0 +1,5 @@ +package de.tims.tictactoe; + +public class GameLogic { + +} diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java new file mode 100644 index 0000000..a33d7bb --- /dev/null +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -0,0 +1,29 @@ +package de.tims.tictactoe; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class GameLogicTest { + + private GameLogic game = new GameLogic(); + + @BeforeAll + static void setUpBeforeClass() throws Exception { + } + + @BeforeEach + void setUp() throws Exception { + } + + @Test + void createGameLogicTest() { + GameLogic expectedResult = game; + GameLogic realResult = new GameLogic(); + + assertEquals(expectedResult.getClass(), realResult.getClass()); + } + +} From d6b015349158700e307e29b008a5510fbfbc9692 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Sun, 30 Jan 2022 13:38:43 +0100 Subject: [PATCH 03/79] tictactoe: added getter for game board --- src/main/java/de/tims/tictactoe/GameLogic.java | 6 ++++++ src/test/java/de/tims/tictactoe/GameLogicTest.java | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 5980f54..4e0c81a 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -1,5 +1,11 @@ package de.tims.tictactoe; public class GameLogic { + + private int[][] board = new int[3][3]; + + public int[][] getBoard() { + return this.board; + } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index a33d7bb..ecfafb9 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -26,4 +26,12 @@ class GameLogicTest { assertEquals(expectedResult.getClass(), realResult.getClass()); } + @Test + void getBoardTest() { + int[][] expectedResult = new int[3][3]; + int[][] realResult = game.getBoard(); + + assertArrayEquals(expectedResult, realResult); + } + } From 068bed8357c9eca954f32ce1772ae80273cff624 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Sun, 30 Jan 2022 13:53:21 +0100 Subject: [PATCH 04/79] tictactoe: added method to count playing fields --- src/main/java/de/tims/tictactoe/GameLogic.java | 5 +++++ src/test/java/de/tims/tictactoe/GameLogicTest.java | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 4e0c81a..07e2998 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -8,4 +8,9 @@ public class GameLogic { return this.board; } + public int countFields() { + // TODO Auto-generated method stub + return 9; + } + } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index ecfafb9..ac43308 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -33,5 +33,13 @@ class GameLogicTest { assertArrayEquals(expectedResult, realResult); } + + @Test + void fieldCountTest() { + int expectedResult = 9; + int realResult = game.countFields(); + + assertEquals(expectedResult, realResult); + } } From 60ec15241bec0e3b035ab75c2d372f177c0571a8 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Sun, 30 Jan 2022 13:59:45 +0100 Subject: [PATCH 05/79] tictactoe: refactored board management and added constructor to handle different playfield sizes --- src/main/java/de/tims/tictactoe/GameLogic.java | 6 +++++- src/test/java/de/tims/tictactoe/GameLogicTest.java | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 07e2998..a449fdb 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -2,7 +2,11 @@ package de.tims.tictactoe; public class GameLogic { - private int[][] board = new int[3][3]; + private int[][] board; + + public GameLogic(int size) { + this.board = new int[size][size]; + } public int[][] getBoard() { return this.board; diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index ac43308..d6d7176 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -8,7 +8,8 @@ import org.junit.jupiter.api.Test; class GameLogicTest { - private GameLogic game = new GameLogic(); + private int size = 3; + private GameLogic game = new GameLogic(size); @BeforeAll static void setUpBeforeClass() throws Exception { @@ -21,7 +22,7 @@ class GameLogicTest { @Test void createGameLogicTest() { GameLogic expectedResult = game; - GameLogic realResult = new GameLogic(); + GameLogic realResult = new GameLogic(size); assertEquals(expectedResult.getClass(), realResult.getClass()); } From edbbefc7ff420948a721896dff16b2fed6231302 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Sun, 30 Jan 2022 14:08:26 +0100 Subject: [PATCH 06/79] tictactoe: fixed fieldCountTest. Now works with different playfield sizes --- .../java/de/tims/tictactoe/GameLogic.java | 2 +- .../java/de/tims/tictactoe/GameLogicTest.java | 31 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index a449fdb..1e7d6a8 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -14,7 +14,7 @@ public class GameLogic { public int countFields() { // TODO Auto-generated method stub - return 9; + return this.board[0].length * this.board.length; } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index d6d7176..0f0335b 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -1,10 +1,16 @@ package de.tims.tictactoe; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.Stream; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; class GameLogicTest { @@ -35,12 +41,21 @@ class GameLogicTest { assertArrayEquals(expectedResult, realResult); } - @Test - void fieldCountTest() { - int expectedResult = 9; - int realResult = game.countFields(); - - assertEquals(expectedResult, realResult); - } + @ParameterizedTest(name = "[{index}] {0} -> {1}") + @MethodSource("testCasesForCountPlayfields") + void fieldCountTest(String testName, int size, int expectedResult) { + GameLogic game = new GameLogic(size); + int realResult = game.countFields(); + + assertEquals(expectedResult, realResult); + } + + private static Stream testCasesForCountPlayfields() { + return Stream.of( + Arguments.of("3x3 board with 9 playfields", 3, 9), + Arguments.of("4x4 board with 16 playfields", 4, 16), + Arguments.of("5x5 board with 25 playfields", 5,25) + ); + } } From 4e425ff54b9913570e1fc9547b461088c945d1c3 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Sun, 30 Jan 2022 14:15:56 +0100 Subject: [PATCH 07/79] tictactoe: added restriction for board sizes below three --- src/main/java/de/tims/tictactoe/GameLogic.java | 4 +++- src/test/java/de/tims/tictactoe/GameLogicTest.java | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 1e7d6a8..f63da53 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -5,6 +5,9 @@ public class GameLogic { private int[][] board; public GameLogic(int size) { + if (size < 3) { + size = 3; + } this.board = new int[size][size]; } @@ -13,7 +16,6 @@ public class GameLogic { } public int countFields() { - // TODO Auto-generated method stub return this.board[0].length * this.board.length; } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 0f0335b..f37fdb0 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -52,6 +52,8 @@ class GameLogicTest { private static Stream testCasesForCountPlayfields() { return Stream.of( + Arguments.of("1x1 board with too few fields", 1, 9), + Arguments.of("2x2 board with too few fields", 2, 9), Arguments.of("3x3 board with 9 playfields", 3, 9), Arguments.of("4x4 board with 16 playfields", 4, 16), Arguments.of("5x5 board with 25 playfields", 5,25) From 27cadc409799cfcecc9c04f18322f6f26e0c0c3d Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Sun, 30 Jan 2022 14:18:15 +0100 Subject: [PATCH 08/79] tictactoe: refactored test code --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index f37fdb0..1c4cf18 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -27,7 +27,7 @@ class GameLogicTest { @Test void createGameLogicTest() { - GameLogic expectedResult = game; + GameLogic expectedResult = this.game; GameLogic realResult = new GameLogic(size); assertEquals(expectedResult.getClass(), realResult.getClass()); @@ -36,12 +36,12 @@ class GameLogicTest { @Test void getBoardTest() { int[][] expectedResult = new int[3][3]; - int[][] realResult = game.getBoard(); + int[][] realResult = this.game.getBoard(); assertArrayEquals(expectedResult, realResult); } - @ParameterizedTest(name = "[{index}] {0} -> {1}") + @ParameterizedTest(name = "[{index}] {0} -> {2} fields") @MethodSource("testCasesForCountPlayfields") void fieldCountTest(String testName, int size, int expectedResult) { GameLogic game = new GameLogic(size); From 972fcd97a6067093cded11ebd3c376eba56db13c Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Sun, 30 Jan 2022 14:36:15 +0100 Subject: [PATCH 09/79] tictactoe: added setter for playfield and changed internal board datatype to char --- .../java/de/tims/tictactoe/GameLogic.java | 16 ++++++++--- .../java/de/tims/tictactoe/GameLogicTest.java | 27 ++++++++++++++++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index f63da53..91d3e36 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -2,16 +2,22 @@ package de.tims.tictactoe; public class GameLogic { - private int[][] board; + private char[][] board; public GameLogic(int size) { if (size < 3) { size = 3; } - this.board = new int[size][size]; + this.board = new char[size][size]; + + for (int i = 0; i < this.board.length; i++) { + for (int j = 0; j < this.board[0].length; j++) { + this.setField(i, j, '-'); + } + } } - public int[][] getBoard() { + public char[][] getBoard() { return this.board; } @@ -19,4 +25,8 @@ public class GameLogic { return this.board[0].length * this.board.length; } + public void setField(int row, int column, char player) { + this.board[row][column] = player; + } + } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 1c4cf18..6810b9a 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -3,6 +3,7 @@ package de.tims.tictactoe; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.Arrays; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeAll; @@ -35,9 +36,11 @@ class GameLogicTest { @Test void getBoardTest() { - int[][] expectedResult = new int[3][3]; - int[][] realResult = this.game.getBoard(); - + char[][] expectedResult = new char[][]{{'-', '-', '-'}, + {'-', '-', '-'}, + {'-', '-', '-'}}; + char[][] realResult = this.game.getBoard(); + assertArrayEquals(expectedResult, realResult); } @@ -50,6 +53,15 @@ class GameLogicTest { assertEquals(expectedResult, realResult); } + @ParameterizedTest(name = "[{index}] {0}") + @MethodSource("testCasesForSetField") + void setFieldTest(String testName, int row, int column, char player, char[][] expectedResult) { + this.game.setField(row, column, player); + char[][] realResult = this.game.getBoard(); + + assertArrayEquals(expectedResult, realResult); + } + private static Stream testCasesForCountPlayfields() { return Stream.of( Arguments.of("1x1 board with too few fields", 1, 9), @@ -59,5 +71,14 @@ class GameLogicTest { Arguments.of("5x5 board with 25 playfields", 5,25) ); } + + private static Stream testCasesForSetField() { + return Stream.of( + Arguments.of("set field [0][0] for player 1", 0, 0, 'x', new char[][] + {{'x', '-', '-'}, + {'-', '-', '-'}, + {'-', '-', '-'}}) + ); + } } From a786eb7496cc9199099e22045bd2afd6368c2c1c Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 11:58:53 +0100 Subject: [PATCH 10/79] 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; + } + } +} From bd561b7024740bee322d81841bb8c9de4d6e5b52 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 12:07:27 +0100 Subject: [PATCH 11/79] tictactoe: AIEasy never sets a field which was already set --- .../java/de/tims/tictactoe/ai/AIEasy.java | 12 ++++++++--- .../java/de/tims/tictactoe/ai/AIEasyTest.java | 21 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIEasy.java b/src/main/java/de/tims/tictactoe/ai/AIEasy.java index 308eaf1..d838bbf 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIEasy.java +++ b/src/main/java/de/tims/tictactoe/ai/AIEasy.java @@ -6,6 +6,7 @@ import java.util.Random; public class AIEasy implements TicTacToeAI { private static final char AI_CHAR = 'o'; + private static final char EMPTY_CHAR = '-'; private Random rand; private GameLogic gl; @@ -14,14 +15,19 @@ public class AIEasy implements TicTacToeAI { public AIEasy(GameLogic gl) { this.gl = gl; boardSize = gl.getBoard().length; - rand = new Random(gl.getBoard().hashCode()); + rand = new Random(); } @Override public void calculateNextMove() { char[][] board = gl.getBoard(); - int row = rand.nextInt(boardSize); - int col = rand.nextInt(boardSize); + int row; + int col; + do { + row = rand.nextInt(boardSize); + col = rand.nextInt(boardSize); + } while (board[row][col] != '-'); + gl.setField(row, col, AI_CHAR); } diff --git a/src/test/java/de/tims/tictactoe/ai/AIEasyTest.java b/src/test/java/de/tims/tictactoe/ai/AIEasyTest.java index 5c169ba..181577e 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIEasyTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIEasyTest.java @@ -32,6 +32,27 @@ class AIEasyTest { verify(gl, times(100)).setField(intThat(new ChooseRandomFieldMatcher()), intThat(new ChooseRandomFieldMatcher()), eq(realChar)); } + @Test + void notEmptyBoardChooseRandomFreeField() { + char realChar = 'o'; + doReturn(new char[][] { {'x', '-', 'o'}, {'-', 'o', '-'}, {'-', 'x', 'x'} }).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)); + //verify that the method is never called with a field which was already set + verify(gl, never()).setField(0, 0, realChar); + verify(gl, never()).setField(0, 2, realChar); + verify(gl, never()).setField(1, 1, realChar); + verify(gl, never()).setField(2, 1, realChar); + verify(gl, never()).setField(2, 2, realChar); + } + private static class ChooseRandomFieldMatcher implements ArgumentMatcher { @Override public boolean matches(Integer argument) { From 88d559c6c9a46f36f7c5d3f4a05ef91ab6c1bb7a Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 12:21:54 +0100 Subject: [PATCH 12/79] tictactoe: added hard AI --- .../java/de/tims/tictactoe/ai/AIHard.java | 22 ++++++++++++++ .../java/de/tims/tictactoe/ai/AIHardTest.java | 30 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/main/java/de/tims/tictactoe/ai/AIHard.java create mode 100644 src/test/java/de/tims/tictactoe/ai/AIHardTest.java diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java new file mode 100644 index 0000000..2165b1d --- /dev/null +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -0,0 +1,22 @@ +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 GameLogic gl; + + public AIHard(GameLogic gl) throws IllegalArgumentException { + if (gl.getBoard().length != 3) { + throw new IllegalArgumentException("Hard AI only supports 3x3 boards!"); + } + this.gl = gl; + } + + @Override + public void calculateNextMove() { + gl.setField(1, 1, AI_CHAR); + } +} diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java new file mode 100644 index 0000000..c52ac3f --- /dev/null +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -0,0 +1,30 @@ +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.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); + } + +} From 93591f47c0d2690b43fb671738bc44cf47425d5e Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 13:02:08 +0100 Subject: [PATCH 13/79] tictactoe: hard AI chooses edge field if field in the middle was already set --- src/main/java/de/tims/tictactoe/ai/AIHard.java | 13 ++++++++++++- src/test/java/de/tims/tictactoe/ai/AIHardTest.java | 11 +++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 2165b1d..ae1e7cb 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -17,6 +17,17 @@ public class AIHard implements TicTacToeAI { @Override public void calculateNextMove() { - gl.setField(1, 1, AI_CHAR); + boolean emptyBoard = true; + char[][] board = gl.getBoard(); + for (char[] row : board) { + for (char field : row) { + emptyBoard &= field == '-'; + } + } + if (emptyBoard) { + gl.setField(1, 1, AI_CHAR); + } else { + gl.setField(0, 0, AI_CHAR); + } } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index c52ac3f..dddb7d2 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -26,5 +26,16 @@ class AIHardTest { 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); + } } From 7c7e134ad9e874f5c625c2867f4233a00dcc7c24 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 13:06:34 +0100 Subject: [PATCH 14/79] tictactoe: hard AI sets middle field if it hasnt been set yet --- src/main/java/de/tims/tictactoe/ai/AIHard.java | 4 ++-- src/test/java/de/tims/tictactoe/ai/AIHardTest.java | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index ae1e7cb..146101a 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -21,10 +21,10 @@ public class AIHard implements TicTacToeAI { char[][] board = gl.getBoard(); for (char[] row : board) { for (char field : row) { - emptyBoard &= field == '-'; + emptyBoard &= field == EMPTY_CHAR; } } - if (emptyBoard) { + if (emptyBoard || board[1][1] == EMPTY_CHAR) { gl.setField(1, 1, AI_CHAR); } else { gl.setField(0, 0, AI_CHAR); diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index dddb7d2..856c1a7 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -37,5 +37,16 @@ class AIHardTest { 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); + } } From 4456251b07d1a9e8d0aecc5f86a8b933b2929ed5 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 13:31:53 +0100 Subject: [PATCH 15/79] tictactoe: hard AI sets edge in second move --- .../java/de/tims/tictactoe/ai/AIEasy.java | 2 +- .../java/de/tims/tictactoe/ai/AIHard.java | 29 +++++++++++++++++-- .../java/de/tims/tictactoe/ai/AIHardTest.java | 11 +++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIEasy.java b/src/main/java/de/tims/tictactoe/ai/AIEasy.java index d838bbf..6b61ffa 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIEasy.java +++ b/src/main/java/de/tims/tictactoe/ai/AIEasy.java @@ -26,7 +26,7 @@ public class AIEasy implements TicTacToeAI { do { row = rand.nextInt(boardSize); col = rand.nextInt(boardSize); - } while (board[row][col] != '-'); + } while (board[row][col] != EMPTY_CHAR); gl.setField(row, col, AI_CHAR); } diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 146101a..8aae93e 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -5,11 +5,12 @@ 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 int BOARD_SIZE = 3; private GameLogic gl; public AIHard(GameLogic gl) throws IllegalArgumentException { - if (gl.getBoard().length != 3) { + if (gl.getBoard().length != BOARD_SIZE) { throw new IllegalArgumentException("Hard AI only supports 3x3 boards!"); } this.gl = gl; @@ -19,15 +20,39 @@ public class AIHard implements TicTacToeAI { public void calculateNextMove() { boolean emptyBoard = true; char[][] board = gl.getBoard(); + for (char[] row : board) { for (char field : row) { emptyBoard &= field == EMPTY_CHAR; } } + if (emptyBoard || board[1][1] == EMPTY_CHAR) { gl.setField(1, 1, AI_CHAR); } else { - gl.setField(0, 0, AI_CHAR); + boolean emptyEdgeFound = false; + int row = 0; + int col = 0; + + for (int i = 0; i < BOARD_SIZE; i = i + BOARD_SIZE - 1) { + for (int j = 0; j < BOARD_SIZE; j = j + BOARD_SIZE - 1) { + row = i; + col = j; + + if (board[i][j] == EMPTY_CHAR) { + row = i; + col = j; + emptyEdgeFound = true; + break; + } + } + + if (emptyEdgeFound) { + break; + } + } + + gl.setField(row, col, AI_CHAR); } } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index 856c1a7..215a5a4 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -48,5 +48,16 @@ class AIHardTest { 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); + } } From ddf9aebb8fbaf952a309a873367711a619f50f4b Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 14:01:42 +0100 Subject: [PATCH 16/79] tictactoe: added method countCharsInRow --- .../java/de/tims/tictactoe/ai/AIHard.java | 4 ++++ .../java/de/tims/tictactoe/ai/AIHardTest.java | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 8aae93e..6891e94 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -55,4 +55,8 @@ public class AIHard implements TicTacToeAI { gl.setField(row, col, AI_CHAR); } } + + public int countCharsInRow(int index, char charToCount) { + return 0; + } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index 215a5a4..049e093 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -1,9 +1,15 @@ 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; @@ -59,5 +65,22 @@ class AIHardTest { verify(gl, times(1)).setField(0, 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 testCasesForCountCharsInRow() { + return Stream.of(Arguments.of("EmptyFieldReturns0", + new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} }, + 0, 'o', 0)); + } } From 9029de6c126ac7f07138666d583bdd9b227d5cd8 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 14:08:11 +0100 Subject: [PATCH 17/79] tictactoe: countCharsInRow counts number of given char in specific row --- src/main/java/de/tims/tictactoe/ai/AIHard.java | 8 +++++++- src/test/java/de/tims/tictactoe/ai/AIHardTest.java | 7 +++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 6891e94..48e7d1b 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -57,6 +57,12 @@ public class AIHard implements TicTacToeAI { } public int countCharsInRow(int index, char charToCount) { - return 0; + int count = 0; + char[][] board = gl.getBoard(); + for (int i = 0; i < BOARD_SIZE; i++) { + count += (board[index][i] == charToCount) ? 1 : 0; + } + + return count; } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index 049e093..a35614b 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -79,8 +79,11 @@ class AIHardTest { private static Stream testCasesForCountCharsInRow() { return Stream.of(Arguments.of("EmptyFieldReturns0", - new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} }, - 0, 'o', 0)); + new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} }, + 0, 'o', 0), + Arguments.of("TwoCharsInRowReturnsTwo", + new char[][] { {'-', '-', '-'}, {'o', 'o', '-'}, {'-', '-', '-'} }, + 1, 'o', 2)); } } From 8c89d0edd650963f8a89fb210c1f3ce5c985e23d Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 14:13:28 +0100 Subject: [PATCH 18/79] tictactoe: added method countCharsInCol --- src/main/java/de/tims/tictactoe/ai/AIHard.java | 5 +++++ .../java/de/tims/tictactoe/ai/AIHardTest.java | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 48e7d1b..ac70681 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -59,10 +59,15 @@ public class AIHard implements TicTacToeAI { 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) { + return 0; + } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index a35614b..76a81f5 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -85,5 +85,22 @@ class AIHardTest { new char[][] { {'-', '-', '-'}, {'o', 'o', '-'}, {'-', '-', '-'} }, 1, 'o', 2)); } + + @ParameterizedTest + @MethodSource("testCasesForCountCharsInCol") + void countCharsInColTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) { + doReturn(board).when(gl).getBoard(); + + AIHard ai = new AIHard(gl); + int realResult = ai.countCharsInCol(rowNum, charToCount); + + assertThat(realResult).describedAs(testName).isEqualTo(expectedResult); + } + + private static Stream testCasesForCountCharsInCol() { + return Stream.of(Arguments.of("EmptyFieldReturns0", + new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} }, + 0, 'o', 0)); + } } From 36b8cdfcacf918476b4bb41b02be0e2d758a48db Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 14:15:01 +0100 Subject: [PATCH 19/79] tictactoe: countCharsInCol counts number of given char in specific col --- src/main/java/de/tims/tictactoe/ai/AIHard.java | 9 ++++++++- src/test/java/de/tims/tictactoe/ai/AIHardTest.java | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index ac70681..56ff489 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -68,6 +68,13 @@ public class AIHard implements TicTacToeAI { } public int countCharsInCol(int index, char charToCount) { - return 0; + int count = 0; + char[][] board = gl.getBoard(); + + for (int i = 0; i < BOARD_SIZE; i++) { + count += (board[i][index] == charToCount) ? 1 : 0; + } + + return count; } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index 76a81f5..f764772 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -100,7 +100,10 @@ class AIHardTest { private static Stream testCasesForCountCharsInCol() { return Stream.of(Arguments.of("EmptyFieldReturns0", new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} }, - 0, 'o', 0)); + 0, 'o', 0), + Arguments.of("TwoCharsInRowReturnsTwo", + new char[][] { {'-', '-', '-'}, {'o', 'o', '-'}, {'-', '-', '-'} }, + 1, 'o', 1)); } } From 525754409a68925405fd9c56f185eef1898a2fad Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 14:45:06 +0100 Subject: [PATCH 20/79] tictactoe: added method countCharsInDiag --- .../java/de/tims/tictactoe/ai/AIHard.java | 4 ++++ .../java/de/tims/tictactoe/ai/AIHardTest.java | 21 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 56ff489..df3c16a 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -77,4 +77,8 @@ public class AIHard implements TicTacToeAI { return count; } + + public int countCharsInDiag(int index, char charToCount) { + return 0; + } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index f764772..5fdd8d6 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -88,11 +88,11 @@ class AIHardTest { @ParameterizedTest @MethodSource("testCasesForCountCharsInCol") - void countCharsInColTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) { + 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(rowNum, charToCount); + int realResult = ai.countCharsInCol(colNum, charToCount); assertThat(realResult).describedAs(testName).isEqualTo(expectedResult); } @@ -105,5 +105,22 @@ class AIHardTest { 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 testCasesForCountCharsInDiag() { + return Stream.of(Arguments.of("EmptyFieldReturns0", + new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} }, + 0, 'o', 0)); + } } From cce28aacd088b4020a0967816ef1bd593b646680 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 15:21:02 +0100 Subject: [PATCH 21/79] tictactoe: countCharsInDiag counts number of given char in specific diagonal --- src/main/java/de/tims/tictactoe/ai/AIHard.java | 9 ++++++++- src/test/java/de/tims/tictactoe/ai/AIHardTest.java | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index df3c16a..6ea1d35 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -79,6 +79,13 @@ public class AIHard implements TicTacToeAI { } public int countCharsInDiag(int index, char charToCount) { - return 0; + 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; } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index 5fdd8d6..d04e720 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -120,7 +120,10 @@ class AIHardTest { private static Stream testCasesForCountCharsInDiag() { return Stream.of(Arguments.of("EmptyFieldReturns0", new char[][] { {'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'} }, - 0, 'o', 0)); + 0, 'o', 0), + Arguments.of("TwoCharsInRowReturnsTwo", + new char[][] { {'-', '-', 'o'}, {'o', 'o', '-'}, {'-', '-', '-'} }, + 1, 'o', 2)); } } From 01f94e31986ea171edd8ccd5dac7ffadc4ebc8d0 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 15:40:17 +0100 Subject: [PATCH 22/79] tictactoe: countCharsInDiag throws IndexOutOfBoundsException for invalid index --- src/main/java/de/tims/tictactoe/ai/AIHard.java | 6 +++++- src/test/java/de/tims/tictactoe/ai/AIHardTest.java | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 6ea1d35..3e802c2 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -78,7 +78,11 @@ public class AIHard implements TicTacToeAI { return count; } - public int countCharsInDiag(int index, char charToCount) { + 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(); diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index d04e720..72934b6 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -125,5 +125,17 @@ class AIHardTest { 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); + } } From c6e0d83d70a6fa8b659f35a9cbf9d0bbc72034ae Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 16:17:51 +0100 Subject: [PATCH 23/79] tictactoe: hard AI prevents opponents win in row --- src/main/java/de/tims/tictactoe/ai/AIHard.java | 17 ++++++++++++----- .../java/de/tims/tictactoe/ai/AIHardTest.java | 11 +++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 3e802c2..a821485 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -5,6 +5,7 @@ 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; @@ -18,16 +19,22 @@ public class AIHard implements TicTacToeAI { @Override public void calculateNextMove() { - boolean emptyBoard = true; + int charsOfOpponent = 0; char[][] board = gl.getBoard(); - for (char[] row : board) { - for (char field : row) { - emptyBoard &= field == EMPTY_CHAR; + for (int i = 0; i < BOARD_SIZE; i++) { + charsOfOpponent = countCharsInRow(i, PLAYER_CHAR); + if (charsOfOpponent == BOARD_SIZE - 1) { + for (int j = 0; j < BOARD_SIZE; j++) { + if (board[i][j] == EMPTY_CHAR) { + gl.setField(i, j, AI_CHAR); + return; + } + } } } - if (emptyBoard || board[1][1] == EMPTY_CHAR) { + if (board[1][1] == EMPTY_CHAR) { gl.setField(1, 1, AI_CHAR); } else { boolean emptyEdgeFound = false; diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index 72934b6..e99dbf9 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -66,6 +66,17 @@ class AIHardTest { 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); + } + @ParameterizedTest @MethodSource("testCasesForCountCharsInRow") void countCharsInRowTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) { From 7115050d60ed38d90142149e03e72eed9600f54f Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 16:22:32 +0100 Subject: [PATCH 24/79] tictactoe: hard AI prevents opponents win in col --- src/main/java/de/tims/tictactoe/ai/AIHard.java | 12 +++++++----- src/test/java/de/tims/tictactoe/ai/AIHardTest.java | 11 +++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index a821485..99aee69 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -19,15 +19,17 @@ public class AIHard implements TicTacToeAI { @Override public void calculateNextMove() { - int charsOfOpponent = 0; + int charsOfOpponentInRow = 0; + int charsOfOpponentInCol = 0; char[][] board = gl.getBoard(); for (int i = 0; i < BOARD_SIZE; i++) { - charsOfOpponent = countCharsInRow(i, PLAYER_CHAR); - if (charsOfOpponent == BOARD_SIZE - 1) { + charsOfOpponentInRow = countCharsInRow(i, PLAYER_CHAR); + charsOfOpponentInCol = countCharsInCol(i, PLAYER_CHAR); + if (charsOfOpponentInRow == BOARD_SIZE - 1 || charsOfOpponentInCol == BOARD_SIZE - 1) { for (int j = 0; j < BOARD_SIZE; j++) { - if (board[i][j] == EMPTY_CHAR) { - gl.setField(i, j, AI_CHAR); + if (board[(charsOfOpponentInRow == BOARD_SIZE - 1) ? i : j][(charsOfOpponentInRow == BOARD_SIZE - 1) ? j : i] == EMPTY_CHAR) { + gl.setField((charsOfOpponentInRow == BOARD_SIZE - 1) ? i : j, (charsOfOpponentInRow == BOARD_SIZE - 1) ? j : i, 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 e99dbf9..ecede92 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -77,6 +77,17 @@ class AIHardTest { 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); + } + @ParameterizedTest @MethodSource("testCasesForCountCharsInRow") void countCharsInRowTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) { From b29b7ee9d7e34f66645db78b7844082cb9b58d9b Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Mon, 31 Jan 2022 17:03:33 +0100 Subject: [PATCH 25/79] tictactoe: hard AI prevents opponents win in diagonal --- .../java/de/tims/tictactoe/ai/AIHard.java | 25 ++++++++++++++++--- .../java/de/tims/tictactoe/ai/AIHardTest.java | 11 ++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 99aee69..9768677 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -21,16 +21,33 @@ public class AIHard implements TicTacToeAI { public void calculateNextMove() { int charsOfOpponentInRow = 0; int charsOfOpponentInCol = 0; + int charsOfOpponentInDiag = 0; char[][] board = gl.getBoard(); for (int i = 0; i < BOARD_SIZE; i++) { charsOfOpponentInRow = countCharsInRow(i, PLAYER_CHAR); charsOfOpponentInCol = countCharsInCol(i, PLAYER_CHAR); - if (charsOfOpponentInRow == BOARD_SIZE - 1 || charsOfOpponentInCol == BOARD_SIZE - 1) { + if (i < 2) { + charsOfOpponentInDiag = countCharsInDiag(i, PLAYER_CHAR); + } + + if (charsOfOpponentInRow == BOARD_SIZE - 1 || charsOfOpponentInCol == BOARD_SIZE - 1 || charsOfOpponentInDiag == BOARD_SIZE - 1) { for (int j = 0; j < BOARD_SIZE; j++) { - if (board[(charsOfOpponentInRow == BOARD_SIZE - 1) ? i : j][(charsOfOpponentInRow == BOARD_SIZE - 1) ? j : i] == EMPTY_CHAR) { - gl.setField((charsOfOpponentInRow == BOARD_SIZE - 1) ? i : j, (charsOfOpponentInRow == BOARD_SIZE - 1) ? j : i, AI_CHAR); - return; + 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); + return; + } } } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index ecede92..dbadc8b 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -87,6 +87,17 @@ class AIHardTest { 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); + } @ParameterizedTest @MethodSource("testCasesForCountCharsInRow") From 360870072ef6155cb75bb1172cdf725fba1af117 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Wed, 2 Feb 2022 16:01:40 +0100 Subject: [PATCH 26/79] tictactoe: hard ai uses chance to win in row --- src/main/java/de/tims/tictactoe/ai/AIHard.java | 11 +++++++++++ src/test/java/de/tims/tictactoe/ai/AIHardTest.java | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 9768677..60bf53c 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -19,18 +19,29 @@ public class AIHard implements TicTacToeAI { @Override public void calculateNextMove() { + int ownCharsInRow = 0; int charsOfOpponentInRow = 0; int charsOfOpponentInCol = 0; int charsOfOpponentInDiag = 0; char[][] board = gl.getBoard(); for (int i = 0; i < BOARD_SIZE; i++) { + ownCharsInRow = countCharsInRow(i, AI_CHAR); charsOfOpponentInRow = countCharsInRow(i, PLAYER_CHAR); charsOfOpponentInCol = countCharsInCol(i, PLAYER_CHAR); if (i < 2) { charsOfOpponentInDiag = countCharsInDiag(i, PLAYER_CHAR); } + if (ownCharsInRow == BOARD_SIZE - 1) { + for (int j = 0; j < BOARD_SIZE; j++) { + if (board[i][j] == EMPTY_CHAR) { + gl.setField(i, j, 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) { diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index dbadc8b..15ae318 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -99,6 +99,17 @@ class AIHardTest { 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); + } + @ParameterizedTest @MethodSource("testCasesForCountCharsInRow") void countCharsInRowTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) { From 7f1b801c93d8b10efd294530b93af84d9d1d5ec8 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Wed, 2 Feb 2022 18:45:08 +0100 Subject: [PATCH 27/79] tictactoe: hard ai uses chance to win in cols --- src/main/java/de/tims/tictactoe/ai/AIHard.java | 8 +++++--- src/test/java/de/tims/tictactoe/ai/AIHardTest.java | 11 +++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 60bf53c..472e918 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -20,6 +20,7 @@ public class AIHard implements TicTacToeAI { @Override public void calculateNextMove() { int ownCharsInRow = 0; + int ownCharsInCol = 0; int charsOfOpponentInRow = 0; int charsOfOpponentInCol = 0; int charsOfOpponentInDiag = 0; @@ -27,16 +28,17 @@ public class AIHard implements TicTacToeAI { 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) { charsOfOpponentInDiag = countCharsInDiag(i, PLAYER_CHAR); } - if (ownCharsInRow == BOARD_SIZE - 1) { + if (ownCharsInRow == BOARD_SIZE - 1 || ownCharsInCol == BOARD_SIZE - 1) { for (int j = 0; j < BOARD_SIZE; j++) { - if (board[i][j] == EMPTY_CHAR) { - gl.setField(i, j, AI_CHAR); + if (board[(ownCharsInRow == BOARD_SIZE - 1) ? i : j][(ownCharsInRow == BOARD_SIZE - 1) ? j : i] == EMPTY_CHAR) { + gl.setField((ownCharsInRow == BOARD_SIZE - 1) ? i : j, (ownCharsInRow == BOARD_SIZE - 1) ? j : i, 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 15ae318..5410f64 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -110,6 +110,17 @@ class AIHardTest { 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); + } + @ParameterizedTest @MethodSource("testCasesForCountCharsInRow") void countCharsInRowTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) { From c0310d8ed63d6091bf7e102be8f6fc0becc2f64b Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Wed, 2 Feb 2022 19:02:05 +0100 Subject: [PATCH 28/79] tictactoe: hard ai uses chance to win in diagonal --- .../java/de/tims/tictactoe/ai/AIHard.java | 20 ++++++++++++++++--- .../java/de/tims/tictactoe/ai/AIHardTest.java | 11 ++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 472e918..b6a6d6e 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -21,6 +21,7 @@ public class AIHard implements TicTacToeAI { public void calculateNextMove() { int ownCharsInRow = 0; int ownCharsInCol = 0; + int ownCharsInDiag = 0; int charsOfOpponentInRow = 0; int charsOfOpponentInCol = 0; int charsOfOpponentInDiag = 0; @@ -32,14 +33,27 @@ public class AIHard implements TicTacToeAI { charsOfOpponentInRow = countCharsInRow(i, PLAYER_CHAR); charsOfOpponentInCol = countCharsInCol(i, PLAYER_CHAR); if (i < 2) { + ownCharsInDiag = countCharsInDiag(i, AI_CHAR); charsOfOpponentInDiag = countCharsInDiag(i, PLAYER_CHAR); } if (ownCharsInRow == BOARD_SIZE - 1 || ownCharsInCol == BOARD_SIZE - 1) { for (int j = 0; j < BOARD_SIZE; j++) { - if (board[(ownCharsInRow == BOARD_SIZE - 1) ? i : j][(ownCharsInRow == BOARD_SIZE - 1) ? j : i] == EMPTY_CHAR) { - gl.setField((ownCharsInRow == BOARD_SIZE - 1) ? i : j, (ownCharsInRow == BOARD_SIZE - 1) ? j : i, AI_CHAR); - return; + 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; + } } } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index 5410f64..db84c3f 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -121,6 +121,17 @@ class AIHardTest { 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); + } + @ParameterizedTest @MethodSource("testCasesForCountCharsInRow") void countCharsInRowTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) { From 9111545ec3a0e84a741c6a0d3d94beba2632c085 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Wed, 2 Feb 2022 20:11:29 +0100 Subject: [PATCH 29/79] 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) { From f44e9e6eb26979cc30f85b379f9ac5cb328f4fec Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Wed, 2 Feb 2022 20:27:44 +0100 Subject: [PATCH 30/79] tictactoe: hard ai sets always in the nearest edge to opponents field --- .../java/de/tims/tictactoe/ai/AIHard.java | 24 +++++++++++-------- .../java/de/tims/tictactoe/ai/AIHardTest.java | 11 +++++++++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 5146369..c8e1de6 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -58,19 +58,23 @@ public class AIHard implements TicTacToeAI { gl.setField(1, 1, AI_CHAR); } else { boolean emptyEdgeFound = false; - int row = 0; - int col = 0; + int row = -1; + int 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) { - row = i; - col = j; - if (board[i][j] == EMPTY_CHAR) { - row = i; - col = j; - emptyEdgeFound = true; - break; + 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; + } } } @@ -79,7 +83,7 @@ public class AIHard implements TicTacToeAI { } } - gl.setField(row, col, AI_CHAR); + gl.setField((prioRow != -1) ? prioRow : row, (prioCol != -1) ? prioCol : col, AI_CHAR); } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index 53af626..07ac838 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -143,6 +143,17 @@ class AIHardTest { 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); + } + @ParameterizedTest @MethodSource("testCasesForCountCharsInRow") void countCharsInRowTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) { From 412558578c40ed028a74afbd233056c531dbaf69 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Wed, 2 Feb 2022 21:03:33 +0100 Subject: [PATCH 31/79] tictactoe: hard ai sets always in the nearest edge to opponents field --- .../java/de/tims/tictactoe/ai/AIHard.java | 20 +++++++++++++++++-- .../java/de/tims/tictactoe/ai/AIHardTest.java | 11 ++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index c8e1de6..5c29316 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -54,8 +54,24 @@ public class AIHard implements TicTacToeAI { } } - if (board[1][1] == EMPTY_CHAR) { - gl.setField(1, 1, AI_CHAR); + if (board[BOARD_SIZE / 2][BOARD_SIZE / 2] == EMPTY_CHAR) { + gl.setField(BOARD_SIZE / 2, BOARD_SIZE / 2, 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)) { + 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++) { + 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; + } + + 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); + return; + } + } + } + } } else { boolean emptyEdgeFound = false; int row = -1; diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index 07ac838..8c21419 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -154,6 +154,17 @@ class AIHardTest { 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); + } + @ParameterizedTest @MethodSource("testCasesForCountCharsInRow") void countCharsInRowTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) { From e30523672889ce19a781f16a402994f9e51793c0 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Wed, 2 Feb 2022 21:37:10 +0100 Subject: [PATCH 32/79] tictactoe: hard ai sets first empy field if theres no better option --- .../java/de/tims/tictactoe/ai/AIHard.java | 70 ++++++++++++++----- .../java/de/tims/tictactoe/ai/AIHardTest.java | 11 +++ 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 5c29316..34e1c26 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -19,13 +19,17 @@ public class AIHard implements TicTacToeAI { @Override public void calculateNextMove() { + char[][] board = gl.getBoard(); + int row; + int col; + int charsInRow = 0; int charsInCol = 0; int charsInDiag = 0; - char[][] board = gl.getBoard(); + char actualChar; 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++) { charsInRow = countCharsInRow(j, actualChar); @@ -35,8 +39,11 @@ public class AIHard implements TicTacToeAI { 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); + row = k; + col = (j == 0) ? k : BOARD_SIZE - 1 - k; + + if (board[row][col] == EMPTY_CHAR) { + gl.setField(row, col, AI_CHAR); return; } } @@ -45,8 +52,11 @@ public class AIHard implements TicTacToeAI { 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); + 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; } } @@ -56,26 +66,37 @@ public class AIHard implements TicTacToeAI { 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++) { - 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; - } - - 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); - 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 (onwCharsInRow >= i && ownCharsInCol >= i && emptyCharsInRow >= BOARD_SIZE - onwCharsInRow && emptyCharsInCol == BOARD_SIZE - ownCharsInCol) { + gl.setField(row, col, AI_CHAR); + return; + } } } } } } else { boolean emptyEdgeFound = false; - int row = -1; - int col = -1; + row = -1; + col = -1; int prioRow = -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; + } + } } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index 8c21419..fc9b48d 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -165,6 +165,17 @@ class AIHardTest { 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 @MethodSource("testCasesForCountCharsInRow") void countCharsInRowTest(String testName, char[][] board, int rowNum, char charToCount, int expectedResult) { From 332a74df86aa218cdc3127f61872be0b59fd20e8 Mon Sep 17 00:00:00 2001 From: Tobias Krause Date: Wed, 2 Feb 2022 22:21:11 +0100 Subject: [PATCH 33/79] tictactoe: bugfix: if row and col with same number each contain two chars of same player, col isnt ignored anymore --- .../java/de/tims/tictactoe/ai/AIHard.java | 22 ++++++++++++++----- .../java/de/tims/tictactoe/ai/AIHardTest.java | 11 ++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/ai/AIHard.java b/src/main/java/de/tims/tictactoe/ai/AIHard.java index 34e1c26..d3cd174 100644 --- a/src/main/java/de/tims/tictactoe/ai/AIHard.java +++ b/src/main/java/de/tims/tictactoe/ai/AIHard.java @@ -52,12 +52,24 @@ public class AIHard implements TicTacToeAI { if (charsInRow == BOARD_SIZE - 1 || charsInCol == BOARD_SIZE - 1) { for (int k = 0; k < BOARD_SIZE; k++) { - row = (charsInRow == BOARD_SIZE - 1) ? j : k; - col = (charsInRow == BOARD_SIZE - 1) ? k : j; + if (charsInRow == BOARD_SIZE - 1) { + row = j; + col = k; + + if (board[row][col] == EMPTY_CHAR) { + gl.setField(row, col, AI_CHAR); + return; + } + } - 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; + } } } } diff --git a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java index fc9b48d..57fc4f5 100644 --- a/src/test/java/de/tims/tictactoe/ai/AIHardTest.java +++ b/src/test/java/de/tims/tictactoe/ai/AIHardTest.java @@ -176,6 +176,17 @@ class AIHardTest { 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) { From 8b31b76e696a382faf8e9e8fa75ed882a4ad7be9 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 15:25:43 +0100 Subject: [PATCH 34/79] tictactoe: added test case for player 2 in playfield setter --- src/main/java/de/tims/tictactoe/GameLogic.java | 4 ++-- src/test/java/de/tims/tictactoe/GameLogicTest.java | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 91d3e36..5bd2a48 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -25,8 +25,8 @@ public class GameLogic { return this.board[0].length * this.board.length; } - public void setField(int row, int column, char player) { - this.board[row][column] = player; + public void setField(int column, int row, char player) { + this.board[column][row] = player; } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 6810b9a..8a22db9 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -55,8 +55,8 @@ class GameLogicTest { @ParameterizedTest(name = "[{index}] {0}") @MethodSource("testCasesForSetField") - void setFieldTest(String testName, int row, int column, char player, char[][] expectedResult) { - this.game.setField(row, column, player); + void setFieldTest(String testName, int column, int row, char player, char[][] expectedResult) { + this.game.setField(column, row, player); char[][] realResult = this.game.getBoard(); assertArrayEquals(expectedResult, realResult); @@ -77,7 +77,11 @@ class GameLogicTest { Arguments.of("set field [0][0] for player 1", 0, 0, 'x', new char[][] {{'x', '-', '-'}, {'-', '-', '-'}, - {'-', '-', '-'}}) + {'-', '-', '-'}}), + Arguments.of("set field [1][0] for player 2", 1, 0, 'o', new char[][] + {{'-', '-', '-'}, + {'o', '-', '-'}, + {'-', '-', '-'}}) ); } From 46b1605e31c540004fe33c003f1a96c0a7708607 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 15:42:29 +0100 Subject: [PATCH 35/79] tictactoe: refactored test code to use one game instance object for all test cases --- .../java/de/tims/tictactoe/GameLogicTest.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 8a22db9..e6f93a6 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -3,33 +3,31 @@ package de.tims.tictactoe; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; -import java.util.Arrays; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(Lifecycle.PER_CLASS) class GameLogicTest { - private int size = 3; - private GameLogic game = new GameLogic(size); + private final int SIZE = 3; + private GameLogic game; @BeforeAll - static void setUpBeforeClass() throws Exception { - } - - @BeforeEach - void setUp() throws Exception { + void setUpBeforeClass() throws Exception { + this.game = new GameLogic(SIZE); } @Test void createGameLogicTest() { GameLogic expectedResult = this.game; - GameLogic realResult = new GameLogic(size); + GameLogic realResult = new GameLogic(SIZE); assertEquals(expectedResult.getClass(), realResult.getClass()); } @@ -79,7 +77,7 @@ class GameLogicTest { {'-', '-', '-'}, {'-', '-', '-'}}), Arguments.of("set field [1][0] for player 2", 1, 0, 'o', new char[][] - {{'-', '-', '-'}, + {{'x', '-', '-'}, {'o', '-', '-'}, {'-', '-', '-'}}) ); From cc16fd3389b6ae439e33b3e3bdd6d9c2d5f91fff Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 16:01:42 +0100 Subject: [PATCH 36/79] tictactoe: added method to check if field is not set --- src/main/java/de/tims/tictactoe/GameLogic.java | 8 +++++++- .../java/de/tims/tictactoe/GameLogicTest.java | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 5bd2a48..ffa8b21 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -3,6 +3,7 @@ package de.tims.tictactoe; public class GameLogic { private char[][] board; + private final char emptyField = '-'; public GameLogic(int size) { if (size < 3) { @@ -26,7 +27,12 @@ public class GameLogic { } public void setField(int column, int row, char player) { - this.board[column][row] = player; + this.board[column][row] = player; + } + + public boolean fieldIsEmpty(int column, int row) { + // TODO Auto-generated method stub + return true; } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index e6f93a6..bd2593b 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -60,6 +60,14 @@ class GameLogicTest { assertArrayEquals(expectedResult, realResult); } + @ParameterizedTest(name = "[{index}] {0}") + @MethodSource("testCasesForCheckEmptyField") + void fieldIsEmptyTest(String testName, int columnToCheck, int rowToCheck, boolean expectedResult, char[][] board) { + boolean realResult = this.game.fieldIsEmpty(columnToCheck, rowToCheck); + + assertEquals(expectedResult, realResult); + } + private static Stream testCasesForCountPlayfields() { return Stream.of( Arguments.of("1x1 board with too few fields", 1, 9), @@ -82,5 +90,14 @@ class GameLogicTest { {'-', '-', '-'}}) ); } + + private static Stream testCasesForCheckEmptyField() { + return Stream.of( + Arguments.of("check an empty field", 0, 0, true, new char[][] + {{'-', '-', '-'}, + {'-', '-', '-'}, + {'-', '-', '-'}}) + ); + } } From 58f7647ce8c680d56e018223cc9ddac21d8a0f8e Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 16:11:23 +0100 Subject: [PATCH 37/79] tictactoe: added test cases for fieldIsEmpty method and created constructor with gameboard as parameter --- src/main/java/de/tims/tictactoe/GameLogic.java | 14 ++++++++++++-- .../java/de/tims/tictactoe/GameLogicTest.java | 17 +++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index ffa8b21..8c40bdb 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -1,5 +1,7 @@ package de.tims.tictactoe; +import java.util.Arrays; + public class GameLogic { private char[][] board; @@ -18,6 +20,10 @@ public class GameLogic { } } + public GameLogic(char[][] board) { + this.board = board; + } + public char[][] getBoard() { return this.board; } @@ -31,8 +37,12 @@ public class GameLogic { } public boolean fieldIsEmpty(int column, int row) { - // TODO Auto-generated method stub - return true; + if (this.board[column][row] == emptyField) { + System.out.println(Arrays.toString(this.board)); + return true; + } else { + return false; + } } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index bd2593b..bc324bb 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -63,7 +63,8 @@ class GameLogicTest { @ParameterizedTest(name = "[{index}] {0}") @MethodSource("testCasesForCheckEmptyField") void fieldIsEmptyTest(String testName, int columnToCheck, int rowToCheck, boolean expectedResult, char[][] board) { - boolean realResult = this.game.fieldIsEmpty(columnToCheck, rowToCheck); + GameLogic game = new GameLogic(board); + boolean realResult = game.fieldIsEmpty(columnToCheck, rowToCheck); assertEquals(expectedResult, realResult); } @@ -94,9 +95,17 @@ class GameLogicTest { private static Stream testCasesForCheckEmptyField() { return Stream.of( Arguments.of("check an empty field", 0, 0, true, new char[][] - {{'-', '-', '-'}, - {'-', '-', '-'}, - {'-', '-', '-'}}) + {{'-', '-', '-'}, + {'-', '-', '-'}, + {'-', '-', '-'}}), + Arguments.of("check a field set by player 1", 0, 0, false, new char[][] + {{'x', '-', '-'}, + {'-', '-', '-'}, + {'-', '-', '-'}}), + Arguments.of("check a field set by player 2", 0, 0, false, new char[][] + {{'o', '-', '-'}, + {'-', '-', '-'}, + {'-', '-', '-'}}) ); } From 85e8867e06e7d7250e65c406ab53b0cc9b039544 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 16:12:35 +0100 Subject: [PATCH 38/79] tictactoe: refactored fieldIsEmpty method --- src/main/java/de/tims/tictactoe/GameLogic.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 8c40bdb..7beb042 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -37,12 +37,7 @@ public class GameLogic { } public boolean fieldIsEmpty(int column, int row) { - if (this.board[column][row] == emptyField) { - System.out.println(Arrays.toString(this.board)); - return true; - } else { - return false; - } + return (this.board[column][row] == emptyField) ? true : false; } } From 56da63b0e6947edfd2b6d84a7edca09feac9799d Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 16:27:48 +0100 Subject: [PATCH 39/79] tictactoe: added test case for trying to set a field again --- src/main/java/de/tims/tictactoe/GameLogic.java | 9 ++++++--- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 7beb042..0790cb3 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -5,7 +5,7 @@ import java.util.Arrays; public class GameLogic { private char[][] board; - private final char emptyField = '-'; + private final char[] occupiedFields = { 'x', 'o' }; public GameLogic(int size) { if (size < 3) { @@ -33,11 +33,14 @@ public class GameLogic { } public void setField(int column, int row, char player) { - this.board[column][row] = player; + if(fieldIsEmpty(column, row)) this.board[column][row] = player; } public boolean fieldIsEmpty(int column, int row) { - return (this.board[column][row] == emptyField) ? true : false; + for (char field : this.occupiedFields) { + if (this.board[column][row] == field) return false; + } + return true; } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index bc324bb..9e08172 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -88,7 +88,11 @@ class GameLogicTest { Arguments.of("set field [1][0] for player 2", 1, 0, 'o', new char[][] {{'x', '-', '-'}, {'o', '-', '-'}, - {'-', '-', '-'}}) + {'-', '-', '-'}}), + Arguments.of("try to set occupied field [1][0] for player 1", 1, 0, 'x', new char[][] + {{'x', '-', '-'}, + {'o', '-', '-'}, + {'-', '-', '-'}}) ); } From aad95ece07c2beaa50e3124fbbcdc631d02cc2a6 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 16:31:44 +0100 Subject: [PATCH 40/79] tictactoe: added test case for new parameterized constructor --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 9e08172..4c14782 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -42,6 +42,17 @@ class GameLogicTest { assertArrayEquals(expectedResult, realResult); } + @Test + void createGameLogicWithGivenBoardTest() { + char[][] expectedResult = new char[][]{{'x', '-', '-'}, + {'-', 'o', '-'}, + {'x', '-', '-'}}; + char[][] givenBoard = expectedResult; + char[][] realResult = new GameLogic(givenBoard).getBoard(); + + assertArrayEquals(expectedResult, realResult); + } + @ParameterizedTest(name = "[{index}] {0} -> {2} fields") @MethodSource("testCasesForCountPlayfields") void fieldCountTest(String testName, int size, int expectedResult) { From 25c39d107cad34ff395f98e2fcaf266268d48c80 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 16:38:28 +0100 Subject: [PATCH 41/79] tictactoe: added checkForWin method --- src/main/java/de/tims/tictactoe/GameLogic.java | 6 ++++-- .../java/de/tims/tictactoe/GameLogicTest.java | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 0790cb3..463bbc7 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -1,7 +1,5 @@ package de.tims.tictactoe; -import java.util.Arrays; - public class GameLogic { private char[][] board; @@ -42,5 +40,9 @@ public class GameLogic { } return true; } + + public boolean checkForWin() { + return true; + } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 4c14782..43b702a 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -80,6 +80,14 @@ class GameLogicTest { assertEquals(expectedResult, realResult); } + @ParameterizedTest(name = "[{index}] {0}") + @MethodSource("testCasesForCheckForWin") + void checkForWinTest(String testName, boolean expectedResult, char[][] boardToCheck) { + boolean realResult = new GameLogic(boardToCheck).checkForWin(); + + assertEquals(expectedResult, realResult); + } + private static Stream testCasesForCountPlayfields() { return Stream.of( Arguments.of("1x1 board with too few fields", 1, 9), @@ -123,5 +131,14 @@ class GameLogicTest { {'-', '-', '-'}}) ); } + + private static Stream testCasesForCheckForWin() { + return Stream.of( + Arguments.of("check win for player 1", true, new char[][] + {{'x', '-', '-'}, + {'x', '-', '-'}, + {'x', '-', '-'}}) + ); + } } From 1ad993e109ffd9122b521e3e957db83084c9bb75 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 16:39:59 +0100 Subject: [PATCH 42/79] tictactoe: added test case for checkForWin method --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 43b702a..11bffca 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -137,7 +137,11 @@ class GameLogicTest { Arguments.of("check win for player 1", true, new char[][] {{'x', '-', '-'}, {'x', '-', '-'}, - {'x', '-', '-'}}) + {'x', '-', '-'}}), + Arguments.of("check win for player 2", true, new char[][] + {{'o', '-', '-'}, + {'o', '-', '-'}, + {'o', '-', '-'}}) ); } From 26768bf8f38b10093262ed59b41de110e63d5ba0 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 17:15:16 +0100 Subject: [PATCH 43/79] tictactoe: added checkForWin for special player and checking all columns --- .../java/de/tims/tictactoe/GameLogic.java | 15 +++++++++-- .../java/de/tims/tictactoe/GameLogicTest.java | 26 +++++++++++-------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 463bbc7..49582bc 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -41,8 +41,19 @@ public class GameLogic { return true; } - public boolean checkForWin() { - return true; + public boolean checkForWin(char player) { + boolean finished = false; + int countFields = 0; + + // check columns + for (int i = 0; i < this.board.length; i++) { + for (int j = 0; j < this.board[0].length; j++) { + if(board[i][j] == player) countFields++; + } + } + if(countFields == this.board.length) finished = true; + + return finished; } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 11bffca..718caaf 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -80,10 +80,10 @@ class GameLogicTest { assertEquals(expectedResult, realResult); } - @ParameterizedTest(name = "[{index}] {0}") + @ParameterizedTest(name = "[{index}] {0}: should be {2}") @MethodSource("testCasesForCheckForWin") - void checkForWinTest(String testName, boolean expectedResult, char[][] boardToCheck) { - boolean realResult = new GameLogic(boardToCheck).checkForWin(); + void checkForWinTest(String testName, char player, boolean expectedResult, char[][] boardToCheck) { + boolean realResult = new GameLogic(boardToCheck).checkForWin(player); assertEquals(expectedResult, realResult); } @@ -134,14 +134,18 @@ class GameLogicTest { private static Stream testCasesForCheckForWin() { return Stream.of( - Arguments.of("check win for player 1", true, new char[][] - {{'x', '-', '-'}, - {'x', '-', '-'}, - {'x', '-', '-'}}), - Arguments.of("check win for player 2", true, new char[][] - {{'o', '-', '-'}, - {'o', '-', '-'}, - {'o', '-', '-'}}) + Arguments.of("check win for player 1", 'x', true, new char[][] + {{'x', '-', '-'}, + {'x', '-', '-'}, + {'x', '-', '-'}}), + Arguments.of("check win for player 2", 'o', true, new char[][] + {{'o', '-', '-'}, + {'o', '-', '-'}, + {'o', '-', '-'}}), + Arguments.of("check win for player 2", 'o', false, new char[][] + {{'o', '-', '-'}, + {'o', '-', '-'}, + {'-', '-', '-'}}) ); } From 54097b5c027eacb38786209335d584310d783c13 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 17:17:25 +0100 Subject: [PATCH 44/79] tictactoe: refactored test cases for checkForWin method --- .../java/de/tims/tictactoe/GameLogicTest.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 718caaf..83891b1 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -134,18 +134,18 @@ class GameLogicTest { private static Stream testCasesForCheckForWin() { return Stream.of( - Arguments.of("check win for player 1", 'x', true, new char[][] - {{'x', '-', '-'}, - {'x', '-', '-'}, - {'x', '-', '-'}}), - Arguments.of("check win for player 2", 'o', true, new char[][] - {{'o', '-', '-'}, - {'o', '-', '-'}, - {'o', '-', '-'}}), - Arguments.of("check win for player 2", 'o', false, new char[][] - {{'o', '-', '-'}, - {'o', '-', '-'}, - {'-', '-', '-'}}) + Arguments.of("check win in column 0 for player 1", 'x', true, new char[][] + {{'x', '-', '-'}, + {'x', '-', '-'}, + {'x', '-', '-'}}), + Arguments.of("check win in column 0 for player 2", 'o', true, new char[][] + {{'o', '-', '-'}, + {'o', '-', '-'}, + {'o', '-', '-'}}), + Arguments.of("check win in column 0 for player 2", 'o', false, new char[][] + {{'o', '-', '-'}, + {'o', '-', '-'}, + {'-', '-', '-'}}) ); } From 0d687f38e6b4ae278e0dfc28ba8cd0e4a0676c9a Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 17:22:00 +0100 Subject: [PATCH 45/79] tictactoe: added test case for check win in row 0 --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 83891b1..266d2bc 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -145,7 +145,11 @@ class GameLogicTest { Arguments.of("check win in column 0 for player 2", 'o', false, new char[][] {{'o', '-', '-'}, {'o', '-', '-'}, - {'-', '-', '-'}}) + {'-', '-', '-'}}), + Arguments.of("check win in row 0 for player 1", 'x', true, new char[][] + {{'x', 'x', 'x'}, + {'o', '-', '-'}, + {'-', '-', 'o'}}) ); } From 5c7908c23fd0d3a7e70f264a5181553ead7ab226 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 17:27:48 +0100 Subject: [PATCH 46/79] tictactoe: added test case to check if player 2 has won in row 0 --- src/main/java/de/tims/tictactoe/GameLogic.java | 9 +++++++++ src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 49582bc..6fc6f9f 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -53,6 +53,15 @@ public class GameLogic { } if(countFields == this.board.length) finished = true; + // check rows + for (int i = 0; i < this.board[0].length; i++) { + for (int j = 0; j < this.board.length; j++) { + if(board[i][j] == player) countFields++; + break; + } + } + if(countFields == this.board.length) finished = true; + return finished; } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 266d2bc..223fd9c 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -149,7 +149,11 @@ class GameLogicTest { Arguments.of("check win in row 0 for player 1", 'x', true, new char[][] {{'x', 'x', 'x'}, {'o', '-', '-'}, - {'-', '-', 'o'}}) + {'-', '-', 'o'}}), + Arguments.of("check win in row 0 for player 2", 'x', true, new char[][] + {{'o', 'o', 'o'}, + {'x', 'o', '-'}, + {'-', '-', 'x'}}) ); } From f81871b1807c07e6c79c5f71458bb4b26eb21fa7 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 17:55:52 +0100 Subject: [PATCH 47/79] tictactoe: fixed previous checkForWin test cases --- src/main/java/de/tims/tictactoe/GameLogic.java | 7 +++---- src/test/java/de/tims/tictactoe/GameLogicTest.java | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 6fc6f9f..d9a59ab 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -54,10 +54,9 @@ public class GameLogic { if(countFields == this.board.length) finished = true; // check rows - for (int i = 0; i < this.board[0].length; i++) { - for (int j = 0; j < this.board.length; j++) { - if(board[i][j] == player) countFields++; - break; + for (int i = 0; i < this.board.length; i++) { + for (int j = 0; j < this.board[0].length; j++) { + if(board[j][i] == player) countFields++; } } if(countFields == this.board.length) finished = true; diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 223fd9c..1dcc42b 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -148,12 +148,12 @@ class GameLogicTest { {'-', '-', '-'}}), Arguments.of("check win in row 0 for player 1", 'x', true, new char[][] {{'x', 'x', 'x'}, - {'o', '-', '-'}, - {'-', '-', 'o'}}), - Arguments.of("check win in row 0 for player 2", 'x', true, new char[][] + {'-', '-', '-'}, + {'-', '-', '-'}}), + Arguments.of("check win in row 0 for player 2", 'o', true, new char[][] {{'o', 'o', 'o'}, - {'x', 'o', '-'}, - {'-', '-', 'x'}}) + {'-', '-', '-'}, + {'-', '-', '-'}}) ); } From 00d129f9b89e8098a671e786c31400c36f82267c Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 17:57:11 +0100 Subject: [PATCH 48/79] tictactoe: added test case to check if player 2 has won in row 1 --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 1dcc42b..f045b5f 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -153,6 +153,10 @@ class GameLogicTest { Arguments.of("check win in row 0 for player 2", 'o', true, new char[][] {{'o', 'o', 'o'}, {'-', '-', '-'}, + {'-', '-', '-'}}), + Arguments.of("check win in row 1 for player 2", 'o', true, new char[][] + {{'-', '-', '-'}, + {'o', 'o', 'o'}, {'-', '-', '-'}}) ); } From 7bf8982378dd0fd96711edc91a570d732dc18847 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Wed, 9 Feb 2022 17:57:56 +0100 Subject: [PATCH 49/79] tictactoe: added test case to check if player 2 has won in row 2 --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index f045b5f..e22d0de 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -157,7 +157,11 @@ class GameLogicTest { Arguments.of("check win in row 1 for player 2", 'o', true, new char[][] {{'-', '-', '-'}, {'o', 'o', 'o'}, - {'-', '-', '-'}}) + {'-', '-', '-'}}), + Arguments.of("check win in row 2 for player 2", 'o', true, new char[][] + {{'-', '-', '-'}, + {'-', '-', '-'}, + {'o', 'o', 'o'}}) ); } From 3e99d48ff0ba82c1cfd0cb557e7f1dac82e49508 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 20:03:33 +0100 Subject: [PATCH 50/79] tictactoe: added test case to check if player 1 has won in column 1 --- src/main/java/de/tims/tictactoe/GameLogic.java | 6 +++--- src/test/java/de/tims/tictactoe/GameLogicTest.java | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index d9a59ab..2a71983 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -48,14 +48,14 @@ public class GameLogic { // check columns for (int i = 0; i < this.board.length; i++) { for (int j = 0; j < this.board[0].length; j++) { - if(board[i][j] == player) countFields++; + if(board[i][j] == player) countFields++; } } if(countFields == this.board.length) finished = true; // check rows - for (int i = 0; i < this.board.length; i++) { - for (int j = 0; j < this.board[0].length; j++) { + for (int i = 0; i < this.board[0].length; i++) { + for (int j = 0; j < this.board.length; j++) { if(board[j][i] == player) countFields++; } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index e22d0de..e2ec822 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -138,6 +138,10 @@ class GameLogicTest { {{'x', '-', '-'}, {'x', '-', '-'}, {'x', '-', '-'}}), + Arguments.of("check win in column 1 for player 1", 'x', true, new char[][] + {{'-', 'x', '-'}, + {'-', 'x', '-'}, + {'-', 'x', '-'}}), Arguments.of("check win in column 0 for player 2", 'o', true, new char[][] {{'o', '-', '-'}, {'o', '-', '-'}, From 84dcefef7ceea638d2f0b08f7f5203834494fa04 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 20:04:15 +0100 Subject: [PATCH 51/79] tictactoe: added test case to check if player 1 has won in column 2 --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index e2ec822..a9a184c 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -142,6 +142,10 @@ class GameLogicTest { {{'-', 'x', '-'}, {'-', 'x', '-'}, {'-', 'x', '-'}}), + Arguments.of("check win in column 2 for player 1", 'x', true, new char[][] + {{'-', '-', 'x'}, + {'-', '-', 'x'}, + {'-', '-', 'x'}}), Arguments.of("check win in column 0 for player 2", 'o', true, new char[][] {{'o', '-', '-'}, {'o', '-', '-'}, From 8e9f6221722527fce1742fdafde20698dcbe3415 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 20:14:32 +0100 Subject: [PATCH 52/79] tictactoe: added test case to check if player 1 has won in column 0 with full board --- src/main/java/de/tims/tictactoe/GameLogic.java | 9 ++++++--- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 2a71983..b60bf3d 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -47,16 +47,19 @@ public class GameLogic { // check columns for (int i = 0; i < this.board.length; i++) { + if(countFields == this.board.length) return finished = true; + countFields = 0; for (int j = 0; j < this.board[0].length; j++) { - if(board[i][j] == player) countFields++; + if(board[j][i] == player) countFields++; } + } - if(countFields == this.board.length) finished = true; + countFields = 0; // check rows for (int i = 0; i < this.board[0].length; i++) { for (int j = 0; j < this.board.length; j++) { - if(board[j][i] == player) countFields++; + if(board[i][j] == player) countFields++; } } if(countFields == this.board.length) finished = true; diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index a9a184c..075945d 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -169,7 +169,11 @@ class GameLogicTest { Arguments.of("check win in row 2 for player 2", 'o', true, new char[][] {{'-', '-', '-'}, {'-', '-', '-'}, - {'o', 'o', 'o'}}) + {'o', 'o', 'o'}}), + Arguments.of("check win in column 0 for player 1 with full board", 'x', true, new char[][] + {{'x', 'o', 'o'}, + {'x', 'o', 'x'}, + {'x', 'x', 'o'}}) ); } From 3ac4c2f22aafbbbd516eca1144d1150fa1054169 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 20:15:13 +0100 Subject: [PATCH 53/79] tictactoe: added test case to check if player 2 has won in column 1 with full board --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 075945d..1210ed1 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -173,7 +173,11 @@ class GameLogicTest { Arguments.of("check win in column 0 for player 1 with full board", 'x', true, new char[][] {{'x', 'o', 'o'}, {'x', 'o', 'x'}, - {'x', 'x', 'o'}}) + {'x', 'x', 'o'}}), + Arguments.of("check win in column 1 for player 2 with full board", 'o', true, new char[][] + {{'x', 'o', 'o'}, + {'x', 'o', 'x'}, + {'o', 'o', 'x'}}) ); } From cdb23b1d6affa950988e721079a9b36c34ddee37 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 23:10:00 +0100 Subject: [PATCH 54/79] tictactoe: added test case to check if player 2 has won in column 2 with full board --- src/main/java/de/tims/tictactoe/GameLogic.java | 8 ++++---- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index b60bf3d..7891235 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -47,12 +47,12 @@ public class GameLogic { // check columns for (int i = 0; i < this.board.length; i++) { - if(countFields == this.board.length) return finished = true; - countFields = 0; for (int j = 0; j < this.board[0].length; j++) { - if(board[j][i] == player) countFields++; + System.out.println(j + ", " + i); + if(board[j][i] == player) countFields++; } - + if(countFields == this.board.length) return finished = true; + countFields = 0; } countFields = 0; diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 1210ed1..00914d4 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -177,7 +177,11 @@ class GameLogicTest { Arguments.of("check win in column 1 for player 2 with full board", 'o', true, new char[][] {{'x', 'o', 'o'}, {'x', 'o', 'x'}, - {'o', 'o', 'x'}}) + {'o', 'o', 'x'}}), + Arguments.of("check win in column 2 for player 2 with full board", 'o', true, new char[][] + {{'x', 'o', 'o'}, + {'x', 'x', 'o'}, + {'o', 'o', 'o'}}) ); } From eec2f540a5e72c2907e4c3f68e713ccfb5256b90 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 23:14:32 +0100 Subject: [PATCH 55/79] tictactoe: added test case to check if player 1 has won in row 0 with full board --- src/main/java/de/tims/tictactoe/GameLogic.java | 4 ++-- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 7891235..6fed5b6 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -48,7 +48,6 @@ public class GameLogic { // check columns for (int i = 0; i < this.board.length; i++) { for (int j = 0; j < this.board[0].length; j++) { - System.out.println(j + ", " + i); if(board[j][i] == player) countFields++; } if(countFields == this.board.length) return finished = true; @@ -61,8 +60,9 @@ public class GameLogic { for (int j = 0; j < this.board.length; j++) { if(board[i][j] == player) countFields++; } + if(countFields == this.board.length) return finished = true; + countFields = 0; } - if(countFields == this.board.length) finished = true; return finished; } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 00914d4..70123df 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -181,7 +181,11 @@ class GameLogicTest { Arguments.of("check win in column 2 for player 2 with full board", 'o', true, new char[][] {{'x', 'o', 'o'}, {'x', 'x', 'o'}, - {'o', 'o', 'o'}}) + {'o', 'o', 'o'}}), + Arguments.of("check win in row 0 for player 1 with full board", 'x', true, new char[][] + {{'x', 'x', 'x'}, + {'x', 'o', 'o'}, + {'o', 'o', 'x'}}) ); } From 69d7d9c924aa507acdda6cb2d02af1fd400c011c Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 23:15:20 +0100 Subject: [PATCH 56/79] tictactoe: added test case to check if player 1 has won in row 1 with full board --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 70123df..1638a41 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -185,6 +185,10 @@ class GameLogicTest { Arguments.of("check win in row 0 for player 1 with full board", 'x', true, new char[][] {{'x', 'x', 'x'}, {'x', 'o', 'o'}, + {'o', 'o', 'x'}}), + Arguments.of("check win in row 1 for player 1 with full board", 'x', true, new char[][] + {{'x', 'x', 'o'}, + {'x', 'x', 'x'}, {'o', 'o', 'x'}}) ); } From 28796e3c160d88625ea09bbd4d4d0edd7388189f Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 23:16:06 +0100 Subject: [PATCH 57/79] tictactoe: added test case to check if player 2 has won in row 2 with full board --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 1638a41..a66e9d4 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -189,7 +189,11 @@ class GameLogicTest { Arguments.of("check win in row 1 for player 1 with full board", 'x', true, new char[][] {{'x', 'x', 'o'}, {'x', 'x', 'x'}, - {'o', 'o', 'x'}}) + {'o', 'o', 'x'}}), + Arguments.of("check win in row 2 for player 2 with full board", 'o', true, new char[][] + {{'x', 'x', 'o'}, + {'o', 'x', 'x'}, + {'o', 'o', 'o'}}) ); } From 64b3f88e935cf1ba1bf3506787b57e48f2b6e832 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 23:20:19 +0100 Subject: [PATCH 58/79] tictactoe: refactored test case and added cases to check draw --- .../java/de/tims/tictactoe/GameLogicTest.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index a66e9d4..30ab928 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -150,10 +150,6 @@ class GameLogicTest { {{'o', '-', '-'}, {'o', '-', '-'}, {'o', '-', '-'}}), - Arguments.of("check win in column 0 for player 2", 'o', false, new char[][] - {{'o', '-', '-'}, - {'o', '-', '-'}, - {'-', '-', '-'}}), Arguments.of("check win in row 0 for player 1", 'x', true, new char[][] {{'x', 'x', 'x'}, {'-', '-', '-'}, @@ -193,7 +189,19 @@ class GameLogicTest { Arguments.of("check win in row 2 for player 2 with full board", 'o', true, new char[][] {{'x', 'x', 'o'}, {'o', 'x', 'x'}, - {'o', 'o', 'o'}}) + {'o', 'o', 'o'}}), + Arguments.of("check win in column 0 for player 2", 'o', false, new char[][] + {{'o', '-', '-'}, + {'o', '-', '-'}, + {'-', '-', '-'}}), + Arguments.of("check a draw for player 2", 'o', false, new char[][] + {{'o', 'o', 'x'}, + {'o', 'o', 'x'}, + {'x', 'x', 'o'}}), + Arguments.of("check a draw for player 1", 'x', false, new char[][] + {{'o', 'o', 'x'}, + {'o', 'o', 'x'}, + {'x', 'x', 'o'}}) ); } From 85f79d14bc2c5c486b80e698c4182e580852c012 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 23:26:10 +0100 Subject: [PATCH 59/79] tictactoe: added test case to check diagonal left win for player 1 --- src/main/java/de/tims/tictactoe/GameLogic.java | 7 +++++++ src/test/java/de/tims/tictactoe/GameLogicTest.java | 10 +++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 6fed5b6..ffaa984 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -64,6 +64,13 @@ public class GameLogic { countFields = 0; } + // check diagonal left + for (int i = this.board.length - 1, j = this.board.length - 1; i >= 0 ; i--, j--) { + if (board[i][j] == player) countFields++; + } + if(countFields == this.board.length) return finished = true; + + return finished; } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 30ab928..216e02c 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -196,13 +196,17 @@ class GameLogicTest { {'-', '-', '-'}}), Arguments.of("check a draw for player 2", 'o', false, new char[][] {{'o', 'o', 'x'}, - {'o', 'o', 'x'}, + {'o', 'x', 'x'}, {'x', 'x', 'o'}}), Arguments.of("check a draw for player 1", 'x', false, new char[][] {{'o', 'o', 'x'}, {'o', 'o', 'x'}, - {'x', 'x', 'o'}}) - ); + {'x', 'x', 'o'}}), + Arguments.of("check diagonal left win for player 1", 'x', true, new char[][] + {{'x', 'o', 'x'}, + {'x', 'x', 'o'}, + {'o', 'o', 'x'}}) + ); } } From 94a38ff70eedce3b795dd361a36a4f5dae1a74ca Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 23:39:09 +0100 Subject: [PATCH 60/79] tictactoe: added test case to check diagonal right win for player 2 --- src/main/java/de/tims/tictactoe/GameLogic.java | 8 +++++++- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index ffaa984..568de32 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -68,9 +68,15 @@ public class GameLogic { for (int i = this.board.length - 1, j = this.board.length - 1; i >= 0 ; i--, j--) { if (board[i][j] == player) countFields++; } + if(countFields == this.board.length) return finished = true; + countFields = 0; + + // check diagonal right + for (int i = this.board.length - 1, j = 0; i >= 0 ; i--, j++) { + if (board[i][j] == player) countFields++; + } if(countFields == this.board.length) return finished = true; - return finished; } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 216e02c..58abc9d 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -205,7 +205,11 @@ class GameLogicTest { Arguments.of("check diagonal left win for player 1", 'x', true, new char[][] {{'x', 'o', 'x'}, {'x', 'x', 'o'}, - {'o', 'o', 'x'}}) + {'o', 'o', 'x'}}), + Arguments.of("check diagonal right win for player 2", 'o', true, new char[][] + {{'x', 'x', 'o'}, + {'x', 'o', 'o'}, + {'o', 'x', 'x'}}) ); } From 864906fb98859fba7c6e5007061710e53aa11ed7 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Thu, 10 Feb 2022 23:41:18 +0100 Subject: [PATCH 61/79] tictactoe: refactoring: formatted code and removed unused lines --- .../java/de/tims/tictactoe/GameLogic.java | 56 +++++++++++-------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 568de32..36ccc8f 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -1,7 +1,7 @@ package de.tims.tictactoe; public class GameLogic { - + private char[][] board; private final char[] occupiedFields = { 'x', 'o' }; @@ -10,7 +10,7 @@ public class GameLogic { size = 3; } this.board = new char[size][size]; - + for (int i = 0; i < this.board.length; i++) { for (int j = 0; j < this.board[0].length; j++) { this.setField(i, j, '-'); @@ -31,16 +31,18 @@ public class GameLogic { } public void setField(int column, int row, char player) { - if(fieldIsEmpty(column, row)) this.board[column][row] = player; + if (fieldIsEmpty(column, row)) + this.board[column][row] = player; } public boolean fieldIsEmpty(int column, int row) { for (char field : this.occupiedFields) { - if (this.board[column][row] == field) return false; + if (this.board[column][row] == field) + return false; } return true; } - + public boolean checkForWin(char player) { boolean finished = false; int countFields = 0; @@ -48,34 +50,40 @@ public class GameLogic { // check columns for (int i = 0; i < this.board.length; i++) { for (int j = 0; j < this.board[0].length; j++) { - if(board[j][i] == player) countFields++; + if (this.board[j][i] == player) + countFields++; } - if(countFields == this.board.length) return finished = true; - countFields = 0; + if (countFields == this.board.length) + return finished = true; + countFields = 0; } - countFields = 0; - // check rows for (int i = 0; i < this.board[0].length; i++) { for (int j = 0; j < this.board.length; j++) { - if(board[i][j] == player) countFields++; + if (this.board[i][j] == player) + countFields++; } - if(countFields == this.board.length) return finished = true; + if (countFields == this.board.length) + return finished = true; countFields = 0; } - + // check diagonal left - for (int i = this.board.length - 1, j = this.board.length - 1; i >= 0 ; i--, j--) { - if (board[i][j] == player) countFields++; - } - if(countFields == this.board.length) return finished = true; - countFields = 0; - - // check diagonal right - for (int i = this.board.length - 1, j = 0; i >= 0 ; i--, j++) { - if (board[i][j] == player) countFields++; - } - if(countFields == this.board.length) return finished = true; + for (int i = this.board.length - 1, j = this.board.length - 1; i >= 0; i--, j--) { + if (this.board[i][j] == player) + countFields++; + } + if (countFields == this.board.length) + return finished = true; + countFields = 0; + + // check diagonal right + for (int i = this.board.length - 1, j = 0; i >= 0; i--, j++) { + if (this.board[i][j] == player) + countFields++; + } + if (countFields == this.board.length) + return finished = true; return finished; } From 2cb34b28d92174ddd3aa0d9c01362158f641f232 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 18:01:13 +0100 Subject: [PATCH 62/79] tictactoe: added test case to check end of game with empty board --- src/main/java/de/tims/tictactoe/GameLogic.java | 5 +++++ .../java/de/tims/tictactoe/GameLogicTest.java | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 36ccc8f..0b6f370 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -88,4 +88,9 @@ public class GameLogic { return finished; } + public boolean checkEndOfGame() { + // TODO Auto-generated method stub + return false; + } + } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 58abc9d..db9ab36 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -88,6 +88,14 @@ class GameLogicTest { assertEquals(expectedResult, realResult); } + @ParameterizedTest(name = "[{index}] {0}: should be {1}") + @MethodSource("testCasesForCheckEndOfGame") + void checkEndOfGameTest(String testName, boolean expectedResult, char[][] boardToCheck) { + boolean realResult = new GameLogic(boardToCheck).checkEndOfGame(); + + assertEquals(expectedResult, realResult); + } + private static Stream testCasesForCountPlayfields() { return Stream.of( Arguments.of("1x1 board with too few fields", 1, 9), @@ -212,5 +220,14 @@ class GameLogicTest { {'o', 'x', 'x'}}) ); } + + private static Stream testCasesForCheckEndOfGame() { + return Stream.of( + Arguments.of("check empty board", false, new char[][] + {{'-', '-', '-'}, + {'-', '-', '-'}, + {'-', '-', '-'}}) + ); + } } From ef0aac938329122fc1fb90908ce4887c96e20ff2 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 18:15:00 +0100 Subject: [PATCH 63/79] tictactoe: added test case to check end of game with win for player 1 --- src/main/java/de/tims/tictactoe/GameLogic.java | 2 +- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 0b6f370..0aaac2b 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -89,7 +89,7 @@ public class GameLogic { } public boolean checkEndOfGame() { - // TODO Auto-generated method stub + if (checkForWin('x')) return true; return false; } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index db9ab36..1aa2d5e 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -226,7 +226,11 @@ class GameLogicTest { Arguments.of("check empty board", false, new char[][] {{'-', '-', '-'}, {'-', '-', '-'}, - {'-', '-', '-'}}) + {'-', '-', '-'}}), + Arguments.of("end of game with win for player 1", true, new char[][] + {{'x', 'o', 'x'}, + {'x', 'x', 'o'}, + {'x', 'o', 'o'}}) ); } From 3936ada743c578190ffad74aea47752d02045788 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 18:20:24 +0100 Subject: [PATCH 64/79] tictactoe: added test case to check end of game with win for player 2 --- src/main/java/de/tims/tictactoe/GameLogic.java | 1 + src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 0aaac2b..95aa451 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -90,6 +90,7 @@ public class GameLogic { public boolean checkEndOfGame() { if (checkForWin('x')) return true; + if (checkForWin('o')) return true; return false; } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 1aa2d5e..4f0e38b 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -230,7 +230,11 @@ class GameLogicTest { Arguments.of("end of game with win for player 1", true, new char[][] {{'x', 'o', 'x'}, {'x', 'x', 'o'}, - {'x', 'o', 'o'}}) + {'x', 'o', 'o'}}), + Arguments.of("end of game with win for player 2", true, new char[][] + {{'x', 'x', 'o'}, + {'o', 'o', 'o'}, + {'x', 'o', 'x'}}) ); } From 52622fa9906ff320630a000bf74546975ebd8c87 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 18:23:59 +0100 Subject: [PATCH 65/79] tictactoe: added test case to check tied game --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 4f0e38b..d824e3d 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -234,7 +234,11 @@ class GameLogicTest { Arguments.of("end of game with win for player 2", true, new char[][] {{'x', 'x', 'o'}, {'o', 'o', 'o'}, - {'x', 'o', 'x'}}) + {'x', 'o', 'x'}}), + Arguments.of("check tied game", true, new char[][] + {{'x', 'x', 'o'}, + {'o', 'x', 'o'}, + {'x', 'o', 'x'}}) ); } From d1d0aa119d90e7c412beeb24332ae97c002dac81 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 18:26:19 +0100 Subject: [PATCH 66/79] tictactoe: added test case to check not yed finished game --- src/test/java/de/tims/tictactoe/GameLogicTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index d824e3d..fbceac8 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -238,7 +238,11 @@ class GameLogicTest { Arguments.of("check tied game", true, new char[][] {{'x', 'x', 'o'}, {'o', 'x', 'o'}, - {'x', 'o', 'x'}}) + {'x', 'o', 'x'}}), + Arguments.of("check not yet finished game", false, new char[][] + {{'x', 'x', '-'}, + {'o', 'o', '-'}, + {'x', 'o', 'x'}}) ); } From c85bc7918dabef1194d6262cef52e3ca13f7d580 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 18:29:05 +0100 Subject: [PATCH 67/79] tictactoe: refactored productive code --- .../java/de/tims/tictactoe/GameLogic.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 95aa451..4a7c6d8 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -2,8 +2,10 @@ package de.tims.tictactoe; public class GameLogic { + private static final char PLAYER_1 = 'x'; + private static final char PLAYER_2 = 'o'; private char[][] board; - private final char[] occupiedFields = { 'x', 'o' }; + private final char[] occupiedFields = { PLAYER_1, PLAYER_2 }; public GameLogic(int size) { if (size < 3) { @@ -44,7 +46,7 @@ public class GameLogic { } public boolean checkForWin(char player) { - boolean finished = false; + boolean won = false; int countFields = 0; // check columns @@ -54,7 +56,7 @@ public class GameLogic { countFields++; } if (countFields == this.board.length) - return finished = true; + return won = true; countFields = 0; } // check rows @@ -64,7 +66,7 @@ public class GameLogic { countFields++; } if (countFields == this.board.length) - return finished = true; + return won = true; countFields = 0; } @@ -74,7 +76,7 @@ public class GameLogic { countFields++; } if (countFields == this.board.length) - return finished = true; + return won = true; countFields = 0; // check diagonal right @@ -83,15 +85,13 @@ public class GameLogic { countFields++; } if (countFields == this.board.length) - return finished = true; + return won = true; - return finished; + return won; } public boolean checkEndOfGame() { - if (checkForWin('x')) return true; - if (checkForWin('o')) return true; - return false; + return checkForWin(PLAYER_1) || checkForWin(PLAYER_2); } } From 435c51f3d77607dcdf8ade4d66e140903bf24395 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 20:57:44 +0100 Subject: [PATCH 68/79] tictactoe: added generateGUI method --- src/main/java/de/tims/tictactoe/GameLogic.java | 7 +++++++ src/test/java/de/tims/tictactoe/GameLogicTest.java | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 4a7c6d8..14de497 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -1,5 +1,7 @@ package de.tims.tictactoe; +import javax.swing.JPanel; + public class GameLogic { private static final char PLAYER_1 = 'x'; @@ -94,4 +96,9 @@ public class GameLogic { return checkForWin(PLAYER_1) || checkForWin(PLAYER_2); } + public JPanel generateGUI() { + // TODO Auto-generated method stub + return new JPanel(); + } + } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index fbceac8..a9fb9bd 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -5,6 +5,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.stream.Stream; +import javax.swing.JPanel; + import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; @@ -53,6 +55,14 @@ class GameLogicTest { assertArrayEquals(expectedResult, realResult); } + @Test + void generateGUITest() { + JPanel expectedResult = new JPanel(); + JPanel realResult = game.generateGUI(); + + assertEquals(expectedResult.getClass(), realResult.getClass()); + } + @ParameterizedTest(name = "[{index}] {0} -> {2} fields") @MethodSource("testCasesForCountPlayfields") void fieldCountTest(String testName, int size, int expectedResult) { From d6ce3f3efa49b60840a4dfbc42544b2a7f5ec71b Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 21:27:58 +0100 Subject: [PATCH 69/79] tictactoe: number of fields added to the gui --- src/main/java/de/tims/tictactoe/GameLogic.java | 15 +++++++++++++-- .../java/de/tims/tictactoe/GameLogicTest.java | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 14de497..a1881d0 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -1,5 +1,9 @@ package de.tims.tictactoe; +import java.awt.GridLayout; + +import javax.swing.BoxLayout; +import javax.swing.JButton; import javax.swing.JPanel; public class GameLogic { @@ -97,8 +101,15 @@ public class GameLogic { } public JPanel generateGUI() { - // TODO Auto-generated method stub - return new JPanel(); + JButton[] fields = new JButton[(int) Math.pow(this.board.length, 2)]; + JPanel contentPanel = new JPanel(); + contentPanel.setLayout(new GridLayout(this.board.length, this.board.length)); + + for (int i = 0; i < fields.length; i++) { + fields[i] = new JButton(); + contentPanel.add(fields[i]); + } + return contentPanel; } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index a9fb9bd..19ab25a 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -3,8 +3,11 @@ package de.tims.tictactoe; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.awt.Component; import java.util.stream.Stream; +import javax.swing.JButton; +import javax.swing.JComponent; import javax.swing.JPanel; import org.junit.jupiter.api.BeforeAll; @@ -63,6 +66,21 @@ class GameLogicTest { assertEquals(expectedResult.getClass(), realResult.getClass()); } + @Test + void numberOfGUIFieldsTest() { + int realResult = 0; + int expectedResult = (int) Math.pow(SIZE, 2); + + JPanel gui = game.generateGUI(); + Component[] components = gui.getComponents(); + + for (Component component : components) { + if (component instanceof JButton) realResult++; + } + + assertEquals(expectedResult, realResult); + } + @ParameterizedTest(name = "[{index}] {0} -> {2} fields") @MethodSource("testCasesForCountPlayfields") void fieldCountTest(String testName, int size, int expectedResult) { From 0d60a2a9f40ee02bd3b1469d125306d2498b1086 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 21:28:40 +0100 Subject: [PATCH 70/79] tictactoe: added ShowGUI class for testing new gui --- src/main/java/de/tims/tictactoe/ShowGUI.java | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/de/tims/tictactoe/ShowGUI.java diff --git a/src/main/java/de/tims/tictactoe/ShowGUI.java b/src/main/java/de/tims/tictactoe/ShowGUI.java new file mode 100644 index 0000000..47a7f2c --- /dev/null +++ b/src/main/java/de/tims/tictactoe/ShowGUI.java @@ -0,0 +1,22 @@ +package de.tims.tictactoe; + +import javax.swing.JFrame; + +public class ShowGUI { + + private JFrame frame; + + public ShowGUI() { + this.frame = new JFrame("TicTacToe"); + this.frame.setSize(600, 600); + + GameLogic game = new GameLogic(3); + this.frame.add(game.generateGUI()); + this.frame.setVisible(true); + } + + public static void main(String[] args) { + new ShowGUI(); + } + +} From 82890b25aa3041b1a9bd909176b12d2a43a02801 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 21:31:10 +0100 Subject: [PATCH 71/79] tictactoe: refactored generateGUI method --- src/main/java/de/tims/tictactoe/GameLogic.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index a1881d0..1591cd1 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -12,6 +12,9 @@ public class GameLogic { private static final char PLAYER_2 = 'o'; private char[][] board; private final char[] occupiedFields = { PLAYER_1, PLAYER_2 }; + + private JButton[] fields; + private JPanel contentPanel; public GameLogic(int size) { if (size < 3) { @@ -101,15 +104,15 @@ public class GameLogic { } public JPanel generateGUI() { - JButton[] fields = new JButton[(int) Math.pow(this.board.length, 2)]; - JPanel contentPanel = new JPanel(); - contentPanel.setLayout(new GridLayout(this.board.length, this.board.length)); + this.fields = new JButton[(int) Math.pow(this.board.length, 2)]; + this.contentPanel = new JPanel(); + this.contentPanel.setLayout(new GridLayout(this.board.length, this.board.length)); - for (int i = 0; i < fields.length; i++) { - fields[i] = new JButton(); - contentPanel.add(fields[i]); + for (int i = 0; i < this.fields.length; i++) { + this.fields[i] = new JButton(); + this.contentPanel.add(this.fields[i]); } - return contentPanel; + return this.contentPanel; } } From 5aa5d1a1fdffa02660d3dc21739ed0b816feac60 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 21:53:34 +0100 Subject: [PATCH 72/79] tictactoe: added test case to check field clicked state in gui --- src/main/java/de/tims/tictactoe/GameLogic.java | 16 ++++++++++++++-- .../java/de/tims/tictactoe/GameLogicTest.java | 12 ++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 1591cd1..0becf7a 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -1,12 +1,13 @@ package de.tims.tictactoe; import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; -import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JPanel; -public class GameLogic { +public class GameLogic implements ActionListener { private static final char PLAYER_1 = 'x'; private static final char PLAYER_2 = 'o'; @@ -110,9 +111,20 @@ public class GameLogic { for (int i = 0; i < this.fields.length; i++) { this.fields[i] = new JButton(); + this.fields[i].addActionListener(this); this.contentPanel.add(this.fields[i]); } return this.contentPanel; } + public JButton getGUIField(int number) { + // TODO Auto-generated method stub + return this.fields[number]; + } + + @Override + public void actionPerformed(ActionEvent e) { + // TODO Auto-generated method stub + } + } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 19ab25a..fddac3c 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -81,6 +81,18 @@ class GameLogicTest { assertEquals(expectedResult, realResult); } + @Test + void buttonStateTest() { + boolean expectedResult = true; + game.generateGUI(); + + JButton currentField = game.getGUIField(0); + ((JButton) currentField).doClick(); + boolean realResult = currentField.isEnabled(); + + assertEquals(expectedResult, realResult); + } + @ParameterizedTest(name = "[{index}] {0} -> {2} fields") @MethodSource("testCasesForCountPlayfields") void fieldCountTest(String testName, int size, int expectedResult) { From 0b3e24bb55f6fa5a0a12b15a3ae05ade9cc15f67 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 23:11:19 +0100 Subject: [PATCH 73/79] tictactoe: refactored gui playfields and related test cases --- .../java/de/tims/tictactoe/GameLogic.java | 25 +++++++++------ .../java/de/tims/tictactoe/GameLogicTest.java | 31 ++++++++++++------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 0becf7a..e933b98 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -14,7 +14,7 @@ public class GameLogic implements ActionListener { private char[][] board; private final char[] occupiedFields = { PLAYER_1, PLAYER_2 }; - private JButton[] fields; + private JButton[][] fields; private JPanel contentPanel; public GameLogic(int size) { @@ -105,26 +105,33 @@ public class GameLogic implements ActionListener { } public JPanel generateGUI() { - this.fields = new JButton[(int) Math.pow(this.board.length, 2)]; + this.fields = new JButton[this.board.length][this.board.length]; this.contentPanel = new JPanel(); this.contentPanel.setLayout(new GridLayout(this.board.length, this.board.length)); for (int i = 0; i < this.fields.length; i++) { - this.fields[i] = new JButton(); - this.fields[i].addActionListener(this); - this.contentPanel.add(this.fields[i]); + for (int j = 0; j < this.fields.length; j++) { + this.fields[i][j] = new JButton(); + this.fields[i][j].addActionListener(this); + this.contentPanel.add(this.fields[i][j]); + } } return this.contentPanel; } - public JButton getGUIField(int number) { - // TODO Auto-generated method stub - return this.fields[number]; + public JButton getGUIField(int column, int row) { + return this.fields[column][row]; } @Override public void actionPerformed(ActionEvent e) { - // TODO Auto-generated method stub + for (int i = 0; i < this.fields.length; i++) { + for (int j = 0; j < this.fields[0].length; j++) { + if (e.getSource() == this.fields[i][j]) { + this.fields[i][j].setText("clicked"); + } + } + } } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index fddac3c..276deb9 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -81,18 +81,6 @@ class GameLogicTest { assertEquals(expectedResult, realResult); } - @Test - void buttonStateTest() { - boolean expectedResult = true; - game.generateGUI(); - - JButton currentField = game.getGUIField(0); - ((JButton) currentField).doClick(); - boolean realResult = currentField.isEnabled(); - - assertEquals(expectedResult, realResult); - } - @ParameterizedTest(name = "[{index}] {0} -> {2} fields") @MethodSource("testCasesForCountPlayfields") void fieldCountTest(String testName, int size, int expectedResult) { @@ -136,6 +124,18 @@ class GameLogicTest { assertEquals(expectedResult, realResult); } + @ParameterizedTest(name = "[{index}] {0}: should be {1}") + @MethodSource("testCasesForCheckButtonState") + void buttonStateTest(String testName, boolean expectedResult, boolean doClick, int column, int row) { + game.generateGUI(); + JButton currentField = game.getGUIField(column, row); + + if (doClick) currentField.doClick(); + boolean realResult = !currentField.getText().isEmpty(); + + assertEquals(expectedResult, realResult); + } + private static Stream testCasesForCountPlayfields() { return Stream.of( Arguments.of("1x1 board with too few fields", 1, 9), @@ -285,5 +285,12 @@ class GameLogicTest { {'x', 'o', 'x'}}) ); } + + private static Stream testCasesForCheckButtonState() { + return Stream.of( + Arguments.of("trigger gui field [0][0]", true, true, 0, 0), + Arguments.of("dont't trigger gui field [1][1]", false, false, 1, 1) + ); + } } From 1c687f496fb47483c7d71aeb38e56536a636c6a9 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 23:14:53 +0100 Subject: [PATCH 74/79] tictactoe: added method to get current player --- src/main/java/de/tims/tictactoe/GameLogic.java | 4 ++++ src/test/java/de/tims/tictactoe/GameLogicTest.java | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index e933b98..4c464fa 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -103,6 +103,10 @@ public class GameLogic implements ActionListener { public boolean checkEndOfGame() { return checkForWin(PLAYER_1) || checkForWin(PLAYER_2); } + + public char getCurrentPlayer() { + return 'x'; + } public JPanel generateGUI() { this.fields = new JButton[this.board.length][this.board.length]; diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 276deb9..f939cff 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -81,6 +81,14 @@ class GameLogicTest { assertEquals(expectedResult, realResult); } + @Test + void getCurrentPlayerTest() { + char expectedResult = game.getCurrentPlayer(); + char realResult = 'x'; + + assertEquals(expectedResult, realResult); + } + @ParameterizedTest(name = "[{index}] {0} -> {2} fields") @MethodSource("testCasesForCountPlayfields") void fieldCountTest(String testName, int size, int expectedResult) { From 6d235a9763d8b6212ef741403aad48d8d48c4e34 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 23:18:56 +0100 Subject: [PATCH 75/79] tictactoe: added method to switch player --- src/main/java/de/tims/tictactoe/GameLogic.java | 10 ++++++++-- src/test/java/de/tims/tictactoe/GameLogicTest.java | 10 ++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 4c464fa..1a74151 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -13,6 +13,7 @@ public class GameLogic implements ActionListener { private static final char PLAYER_2 = 'o'; private char[][] board; private final char[] occupiedFields = { PLAYER_1, PLAYER_2 }; + private char currentPlayer = PLAYER_1; private JButton[][] fields; private JPanel contentPanel; @@ -105,8 +106,13 @@ public class GameLogic implements ActionListener { } public char getCurrentPlayer() { - return 'x'; + return this.currentPlayer; } + + public void switchPlayer() { + this.currentPlayer = this.currentPlayer == PLAYER_1 ? PLAYER_2 : PLAYER_1; + } + public JPanel generateGUI() { this.fields = new JButton[this.board.length][this.board.length]; @@ -137,5 +143,5 @@ public class GameLogic implements ActionListener { } } } - + } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index f939cff..de436d0 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -89,6 +89,16 @@ class GameLogicTest { assertEquals(expectedResult, realResult); } + @Test + void switchPlayerTest() { + game.switchPlayer(); + + char expectedResult = game.getCurrentPlayer(); + char realResult = 'o'; + + assertEquals(expectedResult, realResult); + } + @ParameterizedTest(name = "[{index}] {0} -> {2} fields") @MethodSource("testCasesForCountPlayfields") void fieldCountTest(String testName, int size, int expectedResult) { From 9c2d219ccc1ba20c6fddc22c1c602d19d213951d Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 23:26:24 +0100 Subject: [PATCH 76/79] tictactoe: added gui logic --- src/main/java/de/tims/tictactoe/GameLogic.java | 16 +++++++++++++++- .../java/de/tims/tictactoe/GameLogicTest.java | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 1a74151..a206cd7 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -5,6 +5,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; +import javax.swing.JOptionPane; import javax.swing.JPanel; public class GameLogic implements ActionListener { @@ -138,7 +139,20 @@ public class GameLogic implements ActionListener { for (int i = 0; i < this.fields.length; i++) { for (int j = 0; j < this.fields[0].length; j++) { if (e.getSource() == this.fields[i][j]) { - this.fields[i][j].setText("clicked"); + this.setField(i, j, currentPlayer); + this.fields[i][j].setText("" + this.getCurrentPlayer()); + + if (this.checkEndOfGame()) { + JOptionPane.showMessageDialog(contentPanel, "Spieler " + this.currentPlayer + " hat gewonnen."); + for (int k = 0; k < this.fields.length; k++) { + for (int l = 0; l < this.fields.length; l++) { + this.fields[k][l].setEnabled(false); + } + } + System.exit(0); + } + this.switchPlayer(); + } } } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index de436d0..27575ce 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -83,6 +83,7 @@ class GameLogicTest { @Test void getCurrentPlayerTest() { + GameLogic game = new GameLogic(SIZE); char expectedResult = game.getCurrentPlayer(); char realResult = 'x'; @@ -91,6 +92,7 @@ class GameLogicTest { @Test void switchPlayerTest() { + GameLogic game = new GameLogic(SIZE); game.switchPlayer(); char expectedResult = game.getCurrentPlayer(); From eaeb7bc48f1bdef90d4615baa8b277d857121185 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 23:30:15 +0100 Subject: [PATCH 77/79] tictactoe: refactored code to update gui --- .../java/de/tims/tictactoe/GameLogic.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index a206cd7..66de3c2 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -133,29 +133,32 @@ public class GameLogic implements ActionListener { public JButton getGUIField(int column, int row) { return this.fields[column][row]; } + + private void updateGUI() { + if (this.checkEndOfGame()) { + for (int i = 0; i < this.fields.length; i++) { + for (int j = 0; j < this.fields.length; j++) { + this.fields[i][j].setEnabled(false); + } + } + JOptionPane.showMessageDialog(contentPanel, "Spieler " + this.currentPlayer + " hat gewonnen."); + System.exit(0); + } + this.switchPlayer(); + } @Override public void actionPerformed(ActionEvent e) { for (int i = 0; i < this.fields.length; i++) { for (int j = 0; j < this.fields[0].length; j++) { - if (e.getSource() == this.fields[i][j]) { + if (e.getSource() == this.fields[i][j]) { this.setField(i, j, currentPlayer); this.fields[i][j].setText("" + this.getCurrentPlayer()); - - if (this.checkEndOfGame()) { - JOptionPane.showMessageDialog(contentPanel, "Spieler " + this.currentPlayer + " hat gewonnen."); - for (int k = 0; k < this.fields.length; k++) { - for (int l = 0; l < this.fields.length; l++) { - this.fields[k][l].setEnabled(false); - } - } - System.exit(0); - } - this.switchPlayer(); - + updateGUI(); } } } } + } From c4dcd9e4f1bedb1ebbe1aeadae891e5245cb966c Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Mon, 14 Feb 2022 23:37:53 +0100 Subject: [PATCH 78/79] tictactoe: added methods to reset internal board and gui after game over --- .../java/de/tims/tictactoe/GameLogic.java | 20 ++++++++++++++++++- .../java/de/tims/tictactoe/GameLogicTest.java | 14 +++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 66de3c2..7f3099c 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -114,6 +114,13 @@ public class GameLogic implements ActionListener { this.currentPlayer = this.currentPlayer == PLAYER_1 ? PLAYER_2 : PLAYER_1; } + public void resetBoard() { + for (int i = 0; i < this.board.length; i++) { + for (int j = 0; j < this.board.length; j++) { + this.board[i][j] = '-'; + } + } + } public JPanel generateGUI() { this.fields = new JButton[this.board.length][this.board.length]; @@ -142,7 +149,18 @@ public class GameLogic implements ActionListener { } } JOptionPane.showMessageDialog(contentPanel, "Spieler " + this.currentPlayer + " hat gewonnen."); - System.exit(0); + this.resetGUI(); + } + this.switchPlayer(); + } + + private void resetGUI() { + for (int i = 0; i < this.fields.length; i++) { + for (int j = 0; j < this.fields.length; j++) { + this.resetBoard(); + this.fields[i][j].setText(""); + this.fields[i][j].setEnabled(true); + } } this.switchPlayer(); } diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 27575ce..46c8e3c 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -101,6 +101,20 @@ class GameLogicTest { assertEquals(expectedResult, realResult); } + @Test + void resetBoardTest() { + GameLogic game = new GameLogic(SIZE); + game.setField(1, 2, 'x'); + + char[][] expectedResult = new char[][]{{'-', '-', '-'}, + {'-', '-', '-'}, + {'-', '-', '-'}};; + game.resetBoard(); + char[][] realResult = game.getBoard(); + + assertArrayEquals(expectedResult, realResult); + } + @ParameterizedTest(name = "[{index}] {0} -> {2} fields") @MethodSource("testCasesForCountPlayfields") void fieldCountTest(String testName, int size, int expectedResult) { From c556fe867d31adc7c9cd0c21f395f06a29a83dc8 Mon Sep 17 00:00:00 2001 From: Malte Schellhardt Date: Tue, 15 Feb 2022 00:16:46 +0100 Subject: [PATCH 79/79] tictactoe: refactored and formatted whole code --- .../java/de/tims/tictactoe/GameLogic.java | 43 ++-- .../java/de/tims/tictactoe/GameLogicTest.java | 193 +++++++++--------- 2 files changed, 122 insertions(+), 114 deletions(-) diff --git a/src/main/java/de/tims/tictactoe/GameLogic.java b/src/main/java/de/tims/tictactoe/GameLogic.java index 7f3099c..befbb06 100644 --- a/src/main/java/de/tims/tictactoe/GameLogic.java +++ b/src/main/java/de/tims/tictactoe/GameLogic.java @@ -10,12 +10,14 @@ import javax.swing.JPanel; public class GameLogic implements ActionListener { + private static final char EMPTY_FIELD = '-'; private static final char PLAYER_1 = 'x'; private static final char PLAYER_2 = 'o'; private char[][] board; private final char[] occupiedFields = { PLAYER_1, PLAYER_2 }; private char currentPlayer = PLAYER_1; - + private boolean gui = false; + private JButton[][] fields; private JPanel contentPanel; @@ -24,12 +26,7 @@ public class GameLogic implements ActionListener { size = 3; } this.board = new char[size][size]; - - for (int i = 0; i < this.board.length; i++) { - for (int j = 0; j < this.board[0].length; j++) { - this.setField(i, j, '-'); - } - } + this.resetBoard(); } public GameLogic(char[][] board) { @@ -45,8 +42,13 @@ public class GameLogic implements ActionListener { } public void setField(int column, int row, char player) { - if (fieldIsEmpty(column, row)) + if (this.fieldIsEmpty(column, row)) { this.board[column][row] = player; + if (gui) { + this.fields[column][row].setText("" + this.getCurrentPlayer()); + this.updateGUI(); + } + } } public boolean fieldIsEmpty(int column, int row) { @@ -103,13 +105,13 @@ public class GameLogic implements ActionListener { } public boolean checkEndOfGame() { - return checkForWin(PLAYER_1) || checkForWin(PLAYER_2); + return this.checkForWin(PLAYER_1) || this.checkForWin(PLAYER_2); } - + public char getCurrentPlayer() { return this.currentPlayer; } - + public void switchPlayer() { this.currentPlayer = this.currentPlayer == PLAYER_1 ? PLAYER_2 : PLAYER_1; } @@ -117,7 +119,7 @@ public class GameLogic implements ActionListener { public void resetBoard() { for (int i = 0; i < this.board.length; i++) { for (int j = 0; j < this.board.length; j++) { - this.board[i][j] = '-'; + this.board[i][j] = EMPTY_FIELD; } } } @@ -126,7 +128,7 @@ public class GameLogic implements ActionListener { this.fields = new JButton[this.board.length][this.board.length]; this.contentPanel = new JPanel(); this.contentPanel.setLayout(new GridLayout(this.board.length, this.board.length)); - + for (int i = 0; i < this.fields.length; i++) { for (int j = 0; j < this.fields.length; j++) { this.fields[i][j] = new JButton(); @@ -134,21 +136,22 @@ public class GameLogic implements ActionListener { this.contentPanel.add(this.fields[i][j]); } } + this.gui = true; return this.contentPanel; } public JButton getGUIField(int column, int row) { return this.fields[column][row]; } - - private void updateGUI() { + + private void updateGUI() { if (this.checkEndOfGame()) { for (int i = 0; i < this.fields.length; i++) { for (int j = 0; j < this.fields.length; j++) { this.fields[i][j].setEnabled(false); } } - JOptionPane.showMessageDialog(contentPanel, "Spieler " + this.currentPlayer + " hat gewonnen."); + JOptionPane.showMessageDialog(contentPanel, "Spieler " + this.currentPlayer + " hat gewonnen."); this.resetGUI(); } this.switchPlayer(); @@ -169,14 +172,12 @@ public class GameLogic implements ActionListener { public void actionPerformed(ActionEvent e) { for (int i = 0; i < this.fields.length; i++) { for (int j = 0; j < this.fields[0].length; j++) { - if (e.getSource() == this.fields[i][j]) { + if (e.getSource() == this.fields[i][j]) { this.setField(i, j, currentPlayer); - this.fields[i][j].setText("" + this.getCurrentPlayer()); - updateGUI(); + this.fields[i][j].getText(); } } } } - -} +} \ No newline at end of file diff --git a/src/test/java/de/tims/tictactoe/GameLogicTest.java b/src/test/java/de/tims/tictactoe/GameLogicTest.java index 46c8e3c..857be01 100644 --- a/src/test/java/de/tims/tictactoe/GameLogicTest.java +++ b/src/test/java/de/tims/tictactoe/GameLogicTest.java @@ -7,7 +7,6 @@ import java.awt.Component; import java.util.stream.Stream; import javax.swing.JButton; -import javax.swing.JComponent; import javax.swing.JPanel; import org.junit.jupiter.api.BeforeAll; @@ -23,7 +22,7 @@ class GameLogicTest { private final int SIZE = 3; private GameLogic game; - + @BeforeAll void setUpBeforeClass() throws Exception { this.game = new GameLogic(SIZE); @@ -33,153 +32,160 @@ class GameLogicTest { void createGameLogicTest() { GameLogic expectedResult = this.game; GameLogic realResult = new GameLogic(SIZE); - + assertEquals(expectedResult.getClass(), realResult.getClass()); } - + @Test void getBoardTest() { + // @formatter:off char[][] expectedResult = new char[][]{{'-', '-', '-'}, {'-', '-', '-'}, {'-', '-', '-'}}; + // @formatter:on char[][] realResult = this.game.getBoard(); assertArrayEquals(expectedResult, realResult); } - + @Test void createGameLogicWithGivenBoardTest() { + // @formatter:off char[][] expectedResult = new char[][]{{'x', '-', '-'}, {'-', 'o', '-'}, {'x', '-', '-'}}; + // @formatter:on char[][] givenBoard = expectedResult; char[][] realResult = new GameLogic(givenBoard).getBoard(); - + assertArrayEquals(expectedResult, realResult); } - + @Test void generateGUITest() { JPanel expectedResult = new JPanel(); - JPanel realResult = game.generateGUI(); - + JPanel realResult = this.game.generateGUI(); + assertEquals(expectedResult.getClass(), realResult.getClass()); } - + @Test void numberOfGUIFieldsTest() { - int realResult = 0; int expectedResult = (int) Math.pow(SIZE, 2); - - JPanel gui = game.generateGUI(); + int realResult = 0; + + JPanel gui = this.game.generateGUI(); Component[] components = gui.getComponents(); - + for (Component component : components) { - if (component instanceof JButton) realResult++; + if (component instanceof JButton) + realResult++; } - + assertEquals(expectedResult, realResult); } - + @Test void getCurrentPlayerTest() { GameLogic game = new GameLogic(SIZE); - char expectedResult = game.getCurrentPlayer(); - char realResult = 'x'; + char expectedResult = 'x'; + char realResult = game.getCurrentPlayer(); assertEquals(expectedResult, realResult); } - + @Test void switchPlayerTest() { GameLogic game = new GameLogic(SIZE); game.switchPlayer(); - - char expectedResult = game.getCurrentPlayer(); - char realResult = 'o'; + + char expectedResult = 'o'; + char realResult = game.getCurrentPlayer(); assertEquals(expectedResult, realResult); } - + @Test void resetBoardTest() { GameLogic game = new GameLogic(SIZE); game.setField(1, 2, 'x'); - + // @formatter:off char[][] expectedResult = new char[][]{{'-', '-', '-'}, {'-', '-', '-'}, - {'-', '-', '-'}};; + {'-', '-', '-'}}; + // @formatter:on game.resetBoard(); char[][] realResult = game.getBoard(); assertArrayEquals(expectedResult, realResult); } - - @ParameterizedTest(name = "[{index}] {0} -> {2} fields") - @MethodSource("testCasesForCountPlayfields") - void fieldCountTest(String testName, int size, int expectedResult) { - GameLogic game = new GameLogic(size); - int realResult = game.countFields(); - - assertEquals(expectedResult, realResult); - } - - @ParameterizedTest(name = "[{index}] {0}") - @MethodSource("testCasesForSetField") - void setFieldTest(String testName, int column, int row, char player, char[][] expectedResult) { - this.game.setField(column, row, player); - char[][] realResult = this.game.getBoard(); - - assertArrayEquals(expectedResult, realResult); - } - - @ParameterizedTest(name = "[{index}] {0}") - @MethodSource("testCasesForCheckEmptyField") - void fieldIsEmptyTest(String testName, int columnToCheck, int rowToCheck, boolean expectedResult, char[][] board) { - GameLogic game = new GameLogic(board); - boolean realResult = game.fieldIsEmpty(columnToCheck, rowToCheck); - - assertEquals(expectedResult, realResult); - } - - @ParameterizedTest(name = "[{index}] {0}: should be {2}") - @MethodSource("testCasesForCheckForWin") - void checkForWinTest(String testName, char player, boolean expectedResult, char[][] boardToCheck) { - boolean realResult = new GameLogic(boardToCheck).checkForWin(player); - - assertEquals(expectedResult, realResult); - } - - @ParameterizedTest(name = "[{index}] {0}: should be {1}") - @MethodSource("testCasesForCheckEndOfGame") - void checkEndOfGameTest(String testName, boolean expectedResult, char[][] boardToCheck) { - boolean realResult = new GameLogic(boardToCheck).checkEndOfGame(); - - assertEquals(expectedResult, realResult); - } - - @ParameterizedTest(name = "[{index}] {0}: should be {1}") - @MethodSource("testCasesForCheckButtonState") - void buttonStateTest(String testName, boolean expectedResult, boolean doClick, int column, int row) { - game.generateGUI(); - JButton currentField = game.getGUIField(column, row); - - if (doClick) currentField.doClick(); - boolean realResult = !currentField.getText().isEmpty(); - - assertEquals(expectedResult, realResult); - } - - private static Stream testCasesForCountPlayfields() { - return Stream.of( - Arguments.of("1x1 board with too few fields", 1, 9), - Arguments.of("2x2 board with too few fields", 2, 9), - Arguments.of("3x3 board with 9 playfields", 3, 9), - Arguments.of("4x4 board with 16 playfields", 4, 16), - Arguments.of("5x5 board with 25 playfields", 5,25) - ); - } - + + @ParameterizedTest(name = "[{index}] {0} -> {2} fields") + @MethodSource("testCasesForCountPlayfields") + void fieldCountTest(String testName, int size, int expectedResult) { + GameLogic game = new GameLogic(size); + int realResult = game.countFields(); + + assertEquals(expectedResult, realResult); + } + + @ParameterizedTest(name = "[{index}] {0}") + @MethodSource("testCasesForSetField") + void setFieldTest(String testName, int column, int row, char player, char[][] expectedResult) { + this.game.setField(column, row, player); + char[][] realResult = this.game.getBoard(); + + assertArrayEquals(expectedResult, realResult); + } + + @ParameterizedTest(name = "[{index}] {0}") + @MethodSource("testCasesForCheckEmptyField") + void fieldIsEmptyTest(String testName, int columnToCheck, int rowToCheck, boolean expectedResult, char[][] board) { + GameLogic game = new GameLogic(board); + boolean realResult = game.fieldIsEmpty(columnToCheck, rowToCheck); + + assertEquals(expectedResult, realResult); + } + + @ParameterizedTest(name = "[{index}] {0}: should be {2}") + @MethodSource("testCasesForCheckForWin") + void checkForWinTest(String testName, char player, boolean expectedResult, char[][] boardToCheck) { + boolean realResult = new GameLogic(boardToCheck).checkForWin(player); + + assertEquals(expectedResult, realResult); + } + + @ParameterizedTest(name = "[{index}] {0}: should be {1}") + @MethodSource("testCasesForCheckEndOfGame") + void checkEndOfGameTest(String testName, boolean expectedResult, char[][] boardToCheck) { + boolean realResult = new GameLogic(boardToCheck).checkEndOfGame(); + + assertEquals(expectedResult, realResult); + } + + @ParameterizedTest(name = "[{index}] {0}: should be {1}") + @MethodSource("testCasesForCheckButtonState") + void buttonStateTest(String testName, boolean expectedResult, boolean doClick, int column, int row) throws InterruptedException { + GameLogic game = new GameLogic(SIZE); + game.generateGUI(); + JButton currentField = game.getGUIField(0, 0); + + if (doClick) + currentField.doClick(); + boolean realResult = !currentField.getText().isEmpty(); + + assertEquals(expectedResult, realResult); + } + + // @formatter:off + private static Stream testCasesForCountPlayfields() { + return Stream.of(Arguments.of("1x1 board with too few fields", 1, 9), + Arguments.of("2x2 board with too few fields", 2, 9), + Arguments.of("3x3 board with 9 playfields", 3, 9), + Arguments.of("4x4 board with 16 playfields", 4, 16), + Arguments.of("5x5 board with 25 playfields", 5, 25)); + } + private static Stream testCasesForSetField() { return Stream.of( Arguments.of("set field [0][0] for player 1", 0, 0, 'x', new char[][] @@ -326,5 +332,6 @@ class GameLogicTest { Arguments.of("dont't trigger gui field [1][1]", false, false, 1, 1) ); } - + // @formatter:on + }