199 Commits

Author SHA1 Message Date
Malte Schellhardt c556fe867d tictactoe: refactored and formatted whole code 2 years ago
Malte Schellhardt c4dcd9e4f1 tictactoe: added methods to reset internal board and gui after game over 2 years ago
Malte Schellhardt eaeb7bc48f tictactoe: refactored code to update gui 2 years ago
Malte Schellhardt 9c2d219ccc tictactoe: added gui logic 2 years ago
Malte Schellhardt 6d235a9763 tictactoe: added method to switch player 2 years ago
Malte Schellhardt 1c687f496f tictactoe: added method to get current player 2 years ago
Malte Schellhardt 0b3e24bb55 tictactoe: refactored gui playfields and related test cases 2 years ago
Malte Schellhardt 5aa5d1a1fd tictactoe: added test case to check field clicked state in gui 2 years ago
Malte Schellhardt 82890b25aa tictactoe: refactored generateGUI method 2 years ago
Malte Schellhardt 0d60a2a9f4 tictactoe: added ShowGUI class for testing new gui 2 years ago
Malte Schellhardt d6ce3f3efa tictactoe: number of fields added to the gui 2 years ago
Malte Schellhardt 435c51f3d7 tictactoe: added generateGUI method 2 years ago
Malte Schellhardt c85bc7918d tictactoe: refactored productive code 2 years ago
Malte Schellhardt d1d0aa119d tictactoe: added test case to check not yed finished game 2 years ago
Malte Schellhardt 52622fa990 tictactoe: added test case to check tied game 2 years ago
Malte Schellhardt 3936ada743 tictactoe: added test case to check end of game with win for player 2 2 years ago
Malte Schellhardt ef0aac9383 tictactoe: added test case to check end of game with win for player 1 2 years ago
Malte Schellhardt 2cb34b28d9 tictactoe: added test case to check end of game with empty board 2 years ago
Malte Schellhardt 864906fb98 tictactoe: refactoring: formatted code and removed unused lines 2 years ago
Malte Schellhardt 94a38ff70e tictactoe: added test case to check diagonal right win for player 2 2 years ago
Malte Schellhardt 85f79d14bc tictactoe: added test case to check diagonal left win for player 1 2 years ago
Malte Schellhardt 64b3f88e93 tictactoe: refactored test case and added cases to check draw 2 years ago
Malte Schellhardt 28796e3c16 tictactoe: added test case to check if player 2 has won in row 2 with full board 2 years ago
Malte Schellhardt 69d7d9c924 tictactoe: added test case to check if player 1 has won in row 1 with full board 2 years ago
Malte Schellhardt eec2f540a5 tictactoe: added test case to check if player 1 has won in row 0 with full board 2 years ago
Malte Schellhardt cdb23b1d6a tictactoe: added test case to check if player 2 has won in column 2 with full board 2 years ago
Malte Schellhardt 3ac4c2f22a tictactoe: added test case to check if player 2 has won in column 1 with full board 2 years ago
Malte Schellhardt 8e9f622172 tictactoe: added test case to check if player 1 has won in column 0 with full board 2 years ago
Malte Schellhardt 84dcefef7c tictactoe: added test case to check if player 1 has won in column 2 2 years ago
Malte Schellhardt 3e99d48ff0 tictactoe: added test case to check if player 1 has won in column 1 2 years ago
Malte Schellhardt 7bf8982378 tictactoe: added test case to check if player 2 has won in row 2 2 years ago
Malte Schellhardt 00d129f9b8 tictactoe: added test case to check if player 2 has won in row 1 2 years ago
Malte Schellhardt f81871b180 tictactoe: fixed previous checkForWin test cases 2 years ago
Malte Schellhardt 5c7908c23f tictactoe: added test case to check if player 2 has won in row 0 2 years ago
Malte Schellhardt 0d687f38e6 tictactoe: added test case for check win in row 0 2 years ago
Malte Schellhardt 54097b5c02 tictactoe: refactored test cases for checkForWin method 2 years ago
Malte Schellhardt 26768bf8f3 tictactoe: added checkForWin for special player and checking all columns 2 years ago
Malte Schellhardt 1ad993e109 tictactoe: added test case for checkForWin method 2 years ago
Malte Schellhardt 25c39d107c tictactoe: added checkForWin method 2 years ago
Malte Schellhardt aad95ece07 tictactoe: added test case for new parameterized constructor 2 years ago
Malte Schellhardt 56da63b0e6 tictactoe: added test case for trying to set a field again 2 years ago
Malte Schellhardt 85e8867e06 tictactoe: refactored fieldIsEmpty method 2 years ago
Malte Schellhardt 58f7647ce8 tictactoe: added test cases for fieldIsEmpty method and created constructor with gameboard as parameter 2 years ago
Malte Schellhardt cc16fd3389 tictactoe: added method to check if field is not set 2 years ago
Malte Schellhardt 46b1605e31 tictactoe: refactored test code to use one game instance object for all test cases 2 years ago
Malte Schellhardt 8b31b76e69 tictactoe: added test case for player 2 in playfield setter 2 years ago
Tobias Krause 332a74df86 tictactoe: bugfix: if row and col with same number each contain two chars of same player, col isnt ignored anymore 2 years ago
Tobias Krause e305236728 tictactoe: hard ai sets first empy field if theres no better option 2 years ago
Tobias Krause 412558578c tictactoe: hard ai sets always in the nearest edge to opponents field 2 years ago
Tobias Krause f44e9e6eb2 tictactoe: hard ai sets always in the nearest edge to opponents field 2 years ago
Tobias Krause 9111545ec3 tictactoe: hard ai checks for own opportunity to win first 2 years ago
Tobias Krause c0310d8ed6 tictactoe: hard ai uses chance to win in diagonal 2 years ago
Tobias Krause 7f1b801c93 tictactoe: hard ai uses chance to win in cols 2 years ago
Tobias Krause 360870072e tictactoe: hard ai uses chance to win in row 2 years ago
Tobias Krause b29b7ee9d7 tictactoe: hard AI prevents opponents win in diagonal 2 years ago
Tobias Krause 7115050d60 tictactoe: hard AI prevents opponents win in col 2 years ago
Tobias Krause c6e0d83d70 tictactoe: hard AI prevents opponents win in row 2 years ago
Tobias Krause 01f94e3198 tictactoe: countCharsInDiag throws IndexOutOfBoundsException for invalid index 2 years ago
Tobias Krause cce28aacd0 tictactoe: countCharsInDiag counts number of given char in specific diagonal 2 years ago
Tobias Krause 525754409a tictactoe: added method countCharsInDiag 2 years ago
Tobias Krause 36b8cdfcac tictactoe: countCharsInCol counts number of given char in specific col 2 years ago
Tobias Krause 8c89d0edd6 tictactoe: added method countCharsInCol 2 years ago
Tobias Krause 9029de6c12 tictactoe: countCharsInRow counts number of given char in specific row 2 years ago
Tobias Krause ddf9aebb8f tictactoe: added method countCharsInRow 2 years ago
Tobias Krause 4456251b07 tictactoe: hard AI sets edge in second move 2 years ago
Tobias Krause 7c7e134ad9 tictactoe: hard AI sets middle field if it hasnt been set yet 2 years ago
Tobias Krause 93591f47c0 tictactoe: hard AI chooses edge field if field in the middle was already set 2 years ago
Tobias Krause 88d559c6c9 tictactoe: added hard AI 2 years ago
Tobias Krause bd561b7024 tictactoe: AIEasy never sets a field which was already set 2 years ago
Tobias Krause a786eb7496 tictactoe: added easy AI 2 years ago
Malte Schellhardt 972fcd97a6 tictactoe: added setter for playfield and changed internal board datatype to char 2 years ago
Malte Schellhardt 27cadc4097 tictactoe: refactored test code 2 years ago
Malte Schellhardt 4e425ff54b tictactoe: added restriction for board sizes below three 2 years ago
Malte Schellhardt edbbefc7ff tictactoe: fixed fieldCountTest. Now works with different playfield sizes 2 years ago
Malte Schellhardt 60ec15241b tictactoe: refactored board management and added constructor to handle different playfield sizes 2 years ago
Malte Schellhardt 068bed8357 tictactoe: added method to count playing fields 2 years ago
Malte Schellhardt d6b0153491 tictactoe: added getter for game board 2 years ago
Malte Schellhardt 4e743e694e tictactoe: added class for gamelogic 2 years ago
Lorenz Hohmann 2c299f689a Added GameManager and check if GameState is correct after start function call 2 years ago
Jenkins 5fe12bc7ec Merge commit '0559513f69bcd908594e5ad75e6d58972ed527ec' into HEAD 2 years ago
Jenkins 61e1035bb1 Merge commit '353c68c35867e57d918907c9d8d86edbeb0890e1' into HEAD 2 years ago
Lorenz Hohmann 353c68c358 Fixed JUnit Imports (Maven didn't compile correctly) 2 years ago
Lorenz Hohmann d5d6af193e Beautified GUI Won Screen 2 years ago
Lorenz Hohmann bed8f71879 Implemented gameOver() function in GUI with test case 2 years ago
Lorenz Hohmann 8e92a1caee Added third test for areAllShipsHit() when a ship is not fully hit 2 years ago
Lorenz Hohmann aae87e50e1 Refactoring MatchfieldShipTest class: added description for tests and outsourced multiple tests into more functions 2 years ago
Lorenz Hohmann 27e7a96ba7 Added second test case for areAllShipsHit() - all ships hit test 2 years ago
Lorenz Hohmann abeaff8d7b Implemented areAllShipsHit() with first test case if no ship was hit 2 years ago
Lorenz Hohmann 805c233108 Fixed GameLogicTest with new test parameter in start() function 2 years ago
Lorenz Hohmann 5d039543b7 GUI Refactoring 2 years ago
Lorenz Hohmann 629063b5ff Fixed that AI has next move when ship was hit 2 years ago
Lorenz Hohmann dd2ddc5811 Fixed chooseField returns null 2 years ago
Max Wenzel 53bc0d9064 chooseField still works after returning null 2 years ago
Lorenz Hohmann b11262ba56 Changed whole GUI layout to two matchfields 2 years ago
Lorenz Hohmann d472759a1c Implemented logic after ai made move and player made move 2 years ago
Lorenz Hohmann 79f90946a5 Refactored LogicTest: No longer useful with general game loop 2 years ago
Lorenz Hohmann a42df0aac2 Added shoot() function to panel click for general game loop 2 years ago
Lorenz Hohmann cc34afa847 Added test case when field was already hitted 2 years ago
Lorenz Hohmann 4d69cc3e76 Added test case when field was already shot (expect false) 2 years ago
Lorenz Hohmann 8c49de9767 New test case for shoot(): Check if field was already shot 2 years ago
Lorenz Hohmann dd87d19b18 Added second test case to shoot(): Call on Coordinate without ship 2 years ago
Lorenz Hohmann fadf708556 Added shoot() function to Coordinate class with first test case 2 years ago
Lorenz Hohmann fff174937b Refactoring: getCoordinateFromLabel() 2 years ago
Lorenz Hohmann 94ff308379 Implemented first move 'animation' for GUI 2 years ago
Lorenz Hohmann 7038a4c607 Added default ship positioning to GUI 2 years ago
Lorenz Hohmann 86e79f0a49 Implemented test if ship is already on position in shipSet 2 years ago
Lorenz Hohmann 65ad351305 Added second test case for invalid coordinates on setShip (5x1, direction 1) 2 years ago
Lorenz Hohmann 246ecfa6bd Added test case for invalid coordinates on setShip (2x1, direction 0) 2 years ago
Lorenz Hohmann 4426627a5b Added third test case for setShip() (4x1, direction 1) 2 years ago
Lorenz Hohmann d47d765c92 Added second test case for setShip() (3x1, direction 0) 2 years ago
Lorenz Hohmann 6de05cb134 Implemented setShip() in Matchfield with first test case for 2x1 ship in direction 0 2 years ago
Lorenz Hohmann 871f5fb860 United AI with GameLogic 2 years ago
Lorenz Hohmann c1cbf6a077 United GameManager with GUI class (Refactoring) 2 years ago
Lorenz Hohmann f36500d195 Added mouse listener to register click on matchfield 2 years ago
Lorenz Hohmann 46d51b2b8b Refactored GUI and generated Getters 2 years ago
Lorenz Hohmann b937245b63 Added game info sidebar 2 years ago
Lorenz Hohmann 936a563422 Created gui with minimal elements 2 years ago
Lorenz Hohmann 3211601bd5 Added nextMove() function to check wheter the player or AI has move 2 years ago
Lorenz Hohmann 557984b581 Added GameManager and check if GameState is correct after start function call 2 years ago
Max Wenzel 79a7556286 if ShipIsOnYAxis, ai doesent check XAxis 2 years ago
Max Wenzel 3c1e3d19e5 Refactoring: chooseField doesent need Params now 2 years ago
Max Wenzel 2022df6682 restrucered logic-Class 2 years ago
Max Wenzel 4a02c0b7cc chooseField returns correekt Field case:Left has Ship 2 years ago
Max Wenzel d983b43642 chooseField returns correekt Field case:Right has Ship 2 years ago
Max Wenzel f7c0a6da9c small Refactoring: chooseFieldBelowAfterHit 2 years ago
Max Wenzel 1fd251655c Fix: chooseField makes way more sense now 2 years ago
Max Wenzel fbdade30e3 chooseField returns correekt Field case:Down has Ship 2 years ago
Max Wenzel d5bd72a53c Refactoring: testChooseFieldAboveAfterHit 2 years ago
Max Wenzel af264751e5 chooseField returns correekt Field cae:Up has Ship 2 years ago
Max Wenzel ac9183ea27 overload getState() in Matchfield 2 years ago
Max Wenzel 3364446cd6 add sinkShip 2 years ago
Max Wenzel 8a169d52de add Setter for ClearedLeft 2 years ago
Max Wenzel 908beb15c8 add Setter for ClearedRight 2 years ago
Max Wenzel 6aa384e173 add Setter for ClearedBelow 2 years ago
Max Wenzel 3ddb76e0ab add Setter for ClearedAbove 2 years ago
Max Wenzel ed7474228a Refactoring: add Constructor to set DefaultValues 2 years ago
Max Wenzel 7db470de84 Refactoring: Coordinate target is private now 2 years ago
Max Wenzel cdf4b5b14d Refactoring: cleared-booleans are private now (add getters for Test) 2 years ago
Max Wenzel 6b53586a1b add clearleft 2 years ago
Max Wenzel ba410306ac add clearRight 2 years ago
Max Wenzel 0387c76c97 add clearBelow 2 years ago
Max Wenzel 794f4bbb51 add clearAbove 2 years ago
Max Wenzel e064873635 Refactoring: boolean foundShip is private now 2 years ago
Max Wenzel 61cd9ad08a add findShip() 2 years ago
Max Wenzel bf1f6b2ac3 Refactoring: getEverySecondField() doesn't need param matchfield anymore 2 years ago
Max Wenzel 2ace6f42a9 Refactoring: chooseField() doesn't need param matchfield anymore 2 years ago
Max Wenzel ba00efe5e2 Refactoring: setLastShot() doesn't need param matchfield anymore 2 years ago
Max Wenzel bc2e79b7a3 add Matchfield variable with Getter/Setter in ai-logic 2 years ago
Max Wenzel 6a00b0bad3 add lastShot with Getter/Setter in ai-logic 2 years ago
Max Wenzel 25d399e1a6 Refactoring testEverySecondField (override Equals of Coordinate) 2 years ago
Max Wenzel f3beee8e45 add getEverySecondField in ai-logic 2 years ago
Max Wenzel d847e33ef5 Refact6oring: ai-logicTest restructured 2 years ago
Max Wenzel 66e3394f09 add getBelow() in Matchfield - case: nothingBelow 2 years ago
Max Wenzel 7a43204fdd add getBelow() in Matchfield - DefaultCase 2 years ago
Max Wenzel 7c67747398 add getAbove() in Matchfield - Case: nothingAbove 2 years ago
Max Wenzel 304b3c943e add getAbove() in Matchfield - DefaultCase 2 years ago
Max Wenzel 2603cb9f83 Fix: Above = Right and Below = Left 2 years ago
Max Wenzel bdb4c30cdb add getAbove() in Matchfield - Case: nothingBelow 2 years ago
Max Wenzel ac41493feb add getBelow() in Matchfield - DefaultCase 2 years ago
Max Wenzel d703a7b1c6 add getAbove() in Matchfield - Case: nothingAbove 2 years ago
Max Wenzel 958fcf7166 add getAbove() in Matchfield - DefaultCase 2 years ago
Max Wenzel 0106ea2577 Refactoring: Use ParameterizedTest in CoordinateTest 2 years ago
Max Wenzel 78e804dff9 Refactoring: Implements Coordinate into ai-logic 2 years ago
Max Wenzel f8a8179650 Refactoring: Implements Coordinate into Matchfield 2 years ago
Max Wenzel 10c4518ed0 add setState 2 years ago
Max Wenzel 295ecd2bb1 add DeafaultState(EMPTY) to Coordinate 2 years ago
Max Wenzel b696244000 Coodrdinates returns correct Values for X and Y 2 years ago
Max Wenzel 1a2bd51394 choosenField returns only Fields with state != shot 2 years ago
Lorenz Hohmann 04d9a5d774 Merge branch 'matchfield' into fleetstorm2 2 years ago
Tobias Krause 0559513f69 player_management: login loads existing player from file or creates new player 2 years ago
Tobias Krause 6e61c04240 player_management: added layout for LoginPanel 2 years ago
Tobias Krause 75ca5e7f47 player_management: added LoginPanel to gameexplorer 2 years ago
Tobias Krause a0039979c2 player_management: selectPlayer adds new players to player-list 2 years ago
Tobias Krause 631fb4c698 player_management: savePlayers writes player list to file 2 years ago
Tobias Krause df6f48946e player_management: added method savePlayers 2 years ago
Tobias Krause d0f5efc885 player_management: loadPlayers reads list of players from csv-file 2 years ago
Tobias Krause b4b4fcfe39 player_management: loadPlayers reads player from csv-file 2 years ago
Tobias Krause fc256787f8 player_management: added method loadPlayers 2 years ago
Tobias Krause 4251b7b592 player_management: returns player from list if existing 2 years ago
Tobias Krause 9fb4099540 player_management: added method selectPlayer, added method equals and 2 years ago
Jenkins 8b4389e2d6 Merge commit '85669e4412c5b2d0138a234a914a8640c223386e' into HEAD 2 years ago
Lorenz Hohmann f6d4e8a182 matchfield: refactored Matchfield class structure 2 years ago
Lorenz Hohmann 6e5e212c3e matchfield: added setState() function 2 years ago
Lorenz Hohmann b060f385aa matchfield: added getState() to get state from one field 2 years ago
Lorenz Hohmann 2d36b5d7b1 matchfield: added dynamic field size with constructor 2 years ago
Lorenz Hohmann 08ba5092ce matchfield: added field size 2 years ago
Lorenz Hohmann bdb135116c matchfield: first test - creation not empty 2 years ago
Tobias Krause 85669e4412 gameexplorer: each button opens a different (dummy) game panel 2 years ago
Tobias Krause d2fb0fa2b3 gameexplorer: added action listeners for navigation between game and menu 2 years ago
Tobias Krause 52b0f2d064 gameexplorer: added game panel 2 years ago
Tobias Krause 5903ad6375 gameexplorer: added layout for navigation panel 2 years ago
Tobias Krause cd0ddb7a48 gameexplorer: added navigation panel + refactoring 2 years ago
Tobias Krause 081dc19237 gameexplorer: added gui layout 2 years ago
Tobias Krause cafb60008f gameexplorer: added gui 2 years ago
Tobias Krause 8a5ba92d52 gameexplorer: points cant be less than zero 2 years ago
Tobias Krause 65ddcbbe1f gameexplorer: addPoints() increases / decreases points of player 2 years ago
Tobias Krause ba3a74edb3 gameexplorer: addPoints() overrides points of player 2 years ago
Tobias Krause 32447ac27a gameexplorer: added new class player 2 years ago
Lorenz Hohmann 5b72e67974 Fixed pom.xml: JUnit 4 & 5 Integration 2 years ago
  1. 22
      pom.xml
  2. 19
      src/main/java/de/tims/fleetstorm/GameManager.java
  3. 227
      src/main/java/de/tims/fleetstorm/ai/Logic.java
  4. 268
      src/main/java/de/tims/fleetstorm/gui/GameLogic.java
  5. 61
      src/main/java/de/tims/fleetstorm/matchfield/Coordinate.java
  6. 113
      src/main/java/de/tims/fleetstorm/matchfield/Matchfield.java
  7. 313
      src/main/java/de/tims/gameexplorer/GameExplorer.java
  8. 45
      src/main/java/de/tims/player_management/Player.java
  9. 95
      src/main/java/de/tims/player_management/PlayerManager.java
  10. 183
      src/main/java/de/tims/tictactoe/GameLogic.java
  11. 22
      src/main/java/de/tims/tictactoe/ShowGUI.java
  12. 34
      src/main/java/de/tims/tictactoe/ai/AIEasy.java
  13. 190
      src/main/java/de/tims/tictactoe/ai/AIHard.java
  14. 5
      src/main/java/de/tims/tictactoe/ai/TicTacToeAI.java
  15. 0
      src/main/java/resources/player_data.csv
  16. 21
      src/test/java/de/tims/fleetstorm/GameManagerTest.java
  17. 366
      src/test/java/de/tims/fleetstorm/ai/LogicTest.java
  18. 36
      src/test/java/de/tims/fleetstorm/gui/LogicTest.java
  19. 82
      src/test/java/de/tims/fleetstorm/matchfield/CoordinateTest.java
  20. 144
      src/test/java/de/tims/fleetstorm/matchfield/MatchfieldCreationTest.java
  21. 133
      src/test/java/de/tims/fleetstorm/matchfield/MatchfieldShipTest.java
  22. 110
      src/test/java/de/tims/player_management/PlayerManagerTest.java
  23. 32
      src/test/java/de/tims/player_management/PlayerTest.java
  24. 337
      src/test/java/de/tims/tictactoe/GameLogicTest.java
  25. 62
      src/test/java/de/tims/tictactoe/ai/AIEasyTest.java
  26. 262
      src/test/java/de/tims/tictactoe/ai/AIHardTest.java
  27. 3
      src/test/java/resources/player_testdata.csv
  28. 2
      src/test/java/resources/player_testdata2.csv

22
pom.xml

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.hs-fulda</groupId>
<artifactId>TIMS</artifactId>
@ -9,12 +10,13 @@
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
<junit.jupiter.version>5.8.1</junit.jupiter.version>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<junit.jupiter.version>5.8.0</junit.jupiter.version>
<junit.platform.version>1.8.1</junit.platform.version>
<assertj.version>3.21.0</assertj.version>
<junit.version>3.8.1</junit.version>
<junit.version>4.12</junit.version>
<junit-vintage-engine>4.12.1</junit-vintage-engine>
<mockito.core.version>4.1.0</mockito.core.version>
<mockito.junit.jupiter.version>4.1.0</mockito.junit.jupiter.version>
<junit.platform.surefire.provider.version>1.0.1</junit.platform.surefire.provider.version>
@ -33,6 +35,11 @@
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
@ -70,6 +77,11 @@
<artifactId>junit-platform-surefire-provider</artifactId>
<version>${junit.platform.surefire.provider.version}</version>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit-vintage-engine}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>

19
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;
}
}

227
src/main/java/de/tims/fleetstorm/ai/Logic.java

@ -1,9 +1,232 @@
package de.tims.fleetstorm.ai;
import java.util.ArrayList;
import java.util.Random;
import de.tims.fleetstorm.matchfield.Coordinate;
import de.tims.fleetstorm.matchfield.Matchfield;
public class Logic {
public int[] chooseField() {
return new int[] {};
private Matchfield matchfield;
private ArrayList<Coordinate> everySecondField;
private Coordinate lastShot;
private Coordinate target;
private boolean foundShip;
private boolean clearedAbove;
private boolean clearedBelow;
private boolean clearedRight;
private boolean clearedLeft;
public Logic() {
foundShip = false;
clearedAbove = false;
clearedBelow = false;
clearedRight = false;
clearedLeft = false;
}
public Coordinate chooseField() {
Coordinate out;
if (foundShip) {
// Clear Y-Axis
if (!clearedAbove) {
target = matchfield.getAbove(target);
out = target;
if (target == null || target.getState() == Coordinate.EMPTY) {
clearedAbove = true;
target = lastShot;
}
return out;
}
if (!clearedBelow) {
target = matchfield.getBelow(target);
out = target;
if (target == null || target.getState() == Coordinate.EMPTY) {
clearedBelow = true;
target = lastShot;
}
isShipOnYAxis();
return out;
}
// Clear x-Axis
if (!clearedRight) {
target = matchfield.getRight(target);
out = target;
if (target == null || target.getState() == Coordinate.EMPTY) {
clearedRight = true;
target = lastShot;
}
return out;
}
if (!clearedLeft) {
target = matchfield.getLeft(target);
out = target;
if (target == null || target.getState() == Coordinate.EMPTY) {
clearedLeft = true;
target = lastShot;
}
sinkShip();
return out;
}
}
ArrayList<Coordinate> possibleFields = new ArrayList<Coordinate>();
for (int i = 0; i < everySecondField.size(); i++) {
if (everySecondField.get(i).getState() != Coordinate.SHOT
&& everySecondField.get(i).getState() != Coordinate.HIT) {
possibleFields.add(everySecondField.get(i));
}
}
Random randy = new Random();
lastShot = possibleFields.get(randy.nextInt(possibleFields.size()));
target = possibleFields.get(randy.nextInt(possibleFields.size()));
if (lastShot.getState() == Coordinate.SHIP) {
foundShip = true;
}
return lastShot;
}
public void isShipOnYAxis() {
if ((clearedAbove && clearedBelow) && ((matchfield.getAbove(lastShot) == null
|| (matchfield.getAbove(lastShot).getState() == Coordinate.HIT))
|| (matchfield.getBelow(lastShot) == null
|| (matchfield.getBelow(lastShot).getState() == Coordinate.HIT)))) {
clearedLeft = true;
clearedRight = true;
sinkShip();
}
}
public ArrayList<Coordinate> getEverySecondField() {
ArrayList<Coordinate> out = new ArrayList<Coordinate>();
for (int x = 0; x < Math.sqrt(this.matchfield.getSize()); x++) {
for (int y = 0; y < Math.sqrt(this.matchfield.getSize()); y++) {
if ((x % 2 == 0 && y % 2 == 0) || (x % 2 == 1 && y % 2 == 1)) {
out.add(this.matchfield.getField(x, y));
}
}
}
return out;
}
public void findShip() {
if (lastShot.getState() == Coordinate.HIT) {
foundShip = true;
}
}
public void sinkShip() {
if (foundShip && clearedAbove && clearedBelow && clearedLeft && clearedRight) {
this.foundShip = false;
this.clearedAbove = false;
this.clearedBelow = false;
this.clearedLeft = false;
this.clearedRight = false;
}
}
public void clearAbove(Coordinate shot) {
target = matchfield.getAbove(shot);
if (target.getState() == Coordinate.EMPTY) {
clearedAbove = true;
}
}
public void clearBelow(Coordinate shot) {
target = matchfield.getBelow(shot);
if (target.getState() == Coordinate.EMPTY) {
clearedBelow = true;
}
}
public void clearRight(Coordinate shot) {
target = matchfield.getRight(shot);
if (target.getState() == Coordinate.EMPTY) {
clearedRight = true;
}
}
public void clearLeft(Coordinate shot) {
target = matchfield.getLeft(shot);
if (target.getState() == Coordinate.EMPTY) {
clearedLeft = true;
}
}
// Getter And Setter
public void setEverySecondField(ArrayList<Coordinate> everySecondField) {
this.everySecondField = everySecondField;
}
public void setLastShot(Coordinate coordinate) {
lastShot = this.matchfield.getField(coordinate);
}
public Coordinate getLastShot() {
return lastShot;
}
public void setFoundShip(boolean b) {
this.foundShip = b;
}
public boolean getFoundShip() {
return this.foundShip;
}
public void setClearedAbove(boolean b) {
this.clearedAbove = b;
}
public boolean getClearedAbove() {
return this.clearedAbove;
}
public void setClearedBelow(boolean b) {
this.clearedBelow = b;
}
public boolean getClearedBelow() {
return this.clearedBelow;
}
public void setClearedRight(boolean b) {
this.clearedRight = b;
}
public boolean getClearedRight() {
return this.clearedRight;
}
public void setClearedLeft(boolean b) {
this.clearedLeft = b;
}
public boolean getClearedLeft() {
return this.clearedLeft;
}
public void setTarget(Coordinate target) {
this.target = target;
}
public Coordinate getTarget() {
return target;
}
public void setMatchfield(Matchfield matchfield) {
this.matchfield = matchfield;
this.everySecondField = getEverySecondField();
}
public Matchfield getMatchfield() {
return matchfield;
}
}

268
src/main/java/de/tims/fleetstorm/gui/GameLogic.java

@ -0,0 +1,268 @@
package de.tims.fleetstorm.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.MatteBorder;
import de.tims.fleetstorm.ai.Logic;
import de.tims.fleetstorm.matchfield.Coordinate;
import de.tims.fleetstorm.matchfield.Matchfield;
public class GameLogic extends JPanel {
// GameManager stuff
private int gameState;
private Matchfield matchfield;
private Matchfield enemyMatchfield;
private int matchfieldSize = 10;
private boolean playerMove;
private Logic aiLogic;
public static final int PREPARATION = 1;
public static final int RUNNING = 2;
public static final int GAME_OVER = 3;
// GUI stuff
private ArrayList<JPanel> playerFields;
private ArrayList<JPanel> enemyFields;
public GameLogic(int gapToFrameBorderX, int gapToFrameBorderY, int fieldWidth, int spaceBetween) {
this.playerFields = new ArrayList<>();
this.enemyFields = new ArrayList<>();
setSize(640, 480);
fieldWrapper = new JPanel();
fieldWrapper.setBounds(10, 11, 305, 458);
fieldWrapper.setLayout(null);
setLayout(null);
add(fieldWrapper);
enemyFieldWrapper = new JPanel();
enemyFieldWrapper.setLayout(null);
enemyFieldWrapper.setBounds(326, 11, 305, 458);
add(enemyFieldWrapper);
this.generateFieldsForGUI(gapToFrameBorderX, gapToFrameBorderY, fieldWidth, spaceBetween, fieldWrapper,
this.playerFields, false);
JLabel ownFieldLabel = new JLabel("Eigenes Spielfeld");
ownFieldLabel.setBounds(10, 11, 114, 14);
fieldWrapper.add(ownFieldLabel);
this.generateFieldsForGUI(gapToFrameBorderX, gapToFrameBorderY, fieldWidth, spaceBetween, enemyFieldWrapper,
this.enemyFields, true);
JLabel enemyFieldLabel = new JLabel("Gegnerisches Spielfeld");
enemyFieldLabel.setBounds(10, 11, 168, 14);
enemyFieldWrapper.add(enemyFieldLabel);
}
private void generateFieldsForGUI(int gapToFrameBorderX, int gapToFrameBorderY, int fieldWidth, int spaceBetween,
JPanel panel, ArrayList<JPanel> fields, boolean registerMouseListener) {
for (int x = 0; x < this.matchfieldSize; x++) {
for (int y = 0; y < this.matchfieldSize; y++) {
JPanel field = new JPanel();
int xPos = gapToFrameBorderX + x * fieldWidth + (x * spaceBetween);
int yPos = gapToFrameBorderY + y * fieldWidth + (y * spaceBetween);
field.setBounds(xPos, yPos, fieldWidth, fieldWidth);
field.setBorder(new MatteBorder(1, 1, 1, 1, (Color) new Color(0, 0, 0)));
field.setName(x + ":" + y);
fields.add(field);
panel.add(field);
if (!registerMouseListener)
continue;
field.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int[] coords = getCoordinateFromLabel(field);
int coordX = coords[0];
int coordY = coords[1];
Coordinate chosenField = enemyMatchfield.getField(coordX, coordY);
boolean shotSuccess = chosenField.shoot();
boolean areAllShipsHit = enemyMatchfield.areAllShipsHit();
if (areAllShipsHit) {
gameOver(true);
return;
}
if (shotSuccess && chosenField.getState() != Coordinate.HIT) {
nextMove(false);
} else {
nextMove(true);
}
}
});
}
}
}
private JLabel getXLabel() {
JLabel x = new JLabel("x");
x.setForeground(Color.WHITE);
return x;
}
private int[] getCoordinateFromLabel(JPanel panel) {
String panelName = panel.getName();
String[] panelNameSplit = panelName.split(":");
int coordX = Integer.parseInt(panelNameSplit[0]);
int coordY = Integer.parseInt(panelNameSplit[1]);
return new int[] { coordX, coordY };
}
private void updateFields() {
this.updateField(enemyMatchfield, this.enemyFields);
this.updateField(matchfield, this.playerFields);
}
private void updateField(Matchfield matchfield, ArrayList<JPanel> fields) {
for (JPanel coordinatePanel : fields) {
int[] coords = getCoordinateFromLabel(coordinatePanel);
int coordX = coords[0];
int coordY = coords[1];
// reset field
coordinatePanel.setBackground(null);
coordinatePanel.removeAll();
int state = matchfield.getField(coordX, coordY).getState();
switch (state) {
case Coordinate.SHIP:
if (playerMove)
coordinatePanel.setBackground(new Color(91, 58, 41));
break;
case Coordinate.SHOT:
coordinatePanel.setBackground(new Color(0, 94, 184));
break;
case Coordinate.HIT:
coordinatePanel.setBackground(new Color(91, 58, 41));
coordinatePanel.add(getXLabel());
break;
}
coordinatePanel.revalidate();
coordinatePanel.repaint();
}
}
/**
* This function is only for testing
*/
private static GameLogic gui;
private JPanel fieldWrapper;
private JPanel enemyFieldWrapper;
public static void main(String[] args) {
JFrame frame = new JFrame("Test GUI");
gui = new GameLogic(12, 35, 25, 1);
frame.setContentPane(gui);
frame.setSize(640, 480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.setVisible(true);
gui.start(false);
}
public void start(boolean test) {
this.gameState = GameLogic.PREPARATION;
this.playerMove = true;
// create player matchfield and set ships
this.matchfield = new Matchfield(matchfieldSize);
this.matchfield.createMatchfield();
this.matchfield.setShip(new Coordinate(4, 6), 2, 0);
this.matchfield.setShip(new Coordinate(1, 3), 3, 0);
this.matchfield.setShip(new Coordinate(9, 1), 4, 1);
this.matchfield.setShip(new Coordinate(0, 0), 5, 0);
this.aiLogic = new Logic();
this.aiLogic.setMatchfield(this.matchfield);
// create enemy matchfield, set ships and initialize AI (with player's
// matchfield)
this.enemyMatchfield = new Matchfield(matchfieldSize);
this.enemyMatchfield.createMatchfield();
this.enemyMatchfield.setShip(new Coordinate(8, 9), 2, 0);
this.enemyMatchfield.setShip(new Coordinate(0, 2), 3, 1);
this.enemyMatchfield.setShip(new Coordinate(7, 0), 4, 1);
this.enemyMatchfield.setShip(new Coordinate(3, 6), 5, 0);
// enter game loop
this.gameState = GameLogic.RUNNING;
if (!test)
this.nextMove(true);
}
public void nextMove(boolean playerMove) {
this.playerMove = playerMove;
if (this.playerMove) {
gui.updateFields();
// waiting here for mouse click event....
} else {
Coordinate aiChosenField = null;
while (aiChosenField == null) {
aiChosenField = this.aiLogic.chooseField();
}
aiChosenField.shoot();
gui.updateFields();
boolean areAllShipsHit = this.matchfield.areAllShipsHit();
if (areAllShipsHit) {
this.gameOver(false);
return;
}
boolean aiHasNextMove = aiChosenField.getState() != Coordinate.HIT;
this.nextMove(aiHasNextMove);
}
}
protected void gameOver(boolean playerWinner) {
this.gameState = GameLogic.GAME_OVER;
this.removeAll();
this.setLayout(new BorderLayout());
JLabel wonLabel = new JLabel(playerWinner ? "Du hast gewonnen!" : "Du hast verloren!");
wonLabel.setHorizontalAlignment(SwingConstants.CENTER);
wonLabel.setVerticalAlignment(SwingConstants.CENTER);
wonLabel.setFont(new Font("Tahoma", Font.BOLD, 18));
this.add(wonLabel, SwingConstants.CENTER);
this.revalidate();
this.repaint();
}
public int getGameState() {
return gameState;
}
}

61
src/main/java/de/tims/fleetstorm/matchfield/Coordinate.java

@ -0,0 +1,61 @@
package de.tims.fleetstorm.matchfield;
public class Coordinate {
private int x;
private int y;
private int state;
public static final int EMPTY = 0;
public static final int SHIP = 1;
public static final int SHOT = 2;
public static final int HIT = 3;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
this.state = 0;
}
public Integer getX() {
return x;
}
public Integer getY() {
return y;
}
public int getState() {
return this.state;
}
public void setState(int state) {
this.state = state;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Coordinate)) {
return false;
}
return this.x == ((Coordinate) obj).getX() && this.y == ((Coordinate) obj).getY();
}
public void print() {
System.out.println("X = " + this.x + ", Y = " + this.y + ", State = " + this.state);
}
public boolean shoot() {
if (this.state == Coordinate.SHOT || this.state == Coordinate.HIT)
return false;
if (this.state == Coordinate.SHIP) {
this.state = Coordinate.HIT;
return true;
}
this.state = Coordinate.SHOT;
return true;
}
}

113
src/main/java/de/tims/fleetstorm/matchfield/Matchfield.java

@ -0,0 +1,113 @@
package de.tims.fleetstorm.matchfield;
public class Matchfield {
private Coordinate[][] matchfield;
private int size;
public Matchfield(int size) {
this.size = size;
this.matchfield = new Coordinate[this.size][this.size];
}
public Coordinate[][] createMatchfield() {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
this.matchfield[i][j] = new Coordinate(i, j);
}
}
return this.matchfield;
}
public int getSize() {
return this.matchfield.length * this.matchfield[0].length;
}
public int getState(int x, int y) {
return this.matchfield[x][y].getState();
}
public void setState(int x, int y, int state) {
this.matchfield[x][y].setState(state);
}
public void setState(Coordinate coordinate, int state) {
this.matchfield[coordinate.getX()][coordinate.getY()].setState(state);
}
public Coordinate getField(Coordinate coordinate) {
return matchfield[coordinate.getX()][coordinate.getY()];
}
public Coordinate getField(int x, int y) {
return this.matchfield[x][y];
}
public Coordinate getRight(Coordinate center) {
if (center.getX() == matchfield.length - 1) {
return null;
}
return this.matchfield[center.getX() + 1][center.getY()];
}
public Coordinate getLeft(Coordinate center) {
if (center.getX() == 0) {
return null;
}
return this.matchfield[center.getX() - 1][center.getY()];
}
public Coordinate getAbove(Coordinate center) {
if (center.getY() == matchfield.length - 1) {
return null;
}
return matchfield[center.getX()][center.getY() + 1];
}
public Coordinate getBelow(Coordinate center) {
if (center.getY() == 0) {
return null;
}
return matchfield[center.getX()][center.getY() - 1];
}
/**
* direction 0 => x axis (to the right) direction 1 => y axis (to the bottom)
*/
public boolean setShip(Coordinate coordinate, int length, int direction) {
for (int i = 0; i < length; i++) {
Coordinate field = this.getField(coordinate);
if (field.getState() == Coordinate.SHIP)
return false;
field.setState(Coordinate.SHIP);
if (direction == 0)
coordinate = this.getRight(coordinate);
if (direction == 1)
coordinate = this.getAbove(coordinate);
if (coordinate == null)
return false;
}
return true;
}
public boolean areAllShipsHit() {
int shipCounter = 0;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
int fieldState = this.matchfield[i][j].getState();
if (fieldState == Coordinate.SHIP)
shipCounter++;
}
}
return shipCounter == 0;
}
}

313
src/main/java/de/tims/gameexplorer/GameExplorer.java

@ -0,0 +1,313 @@
package de.tims.gameexplorer;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import de.tims.player_management.Player;
import de.tims.player_management.PlayerManager;
public class GameExplorer {
private JFrame frame;
private JPanel explorerPanel;
private JPanel loginPanel;
private JPanel gamePanel;
private JPanel navigationPanel;
private JPanel fleetstormPanel;
private JPanel fourwinsPanel;
private JPanel tictactoePanel;
private JPanel leaderboardPanel;
private JPanel border1;
private JPanel border2;
private JPanel border3;
private JPanel border4;
private JPanel border5;
private JPanel border6;
private JButton loginBtn;
private JButton fleetstormBtn;
private JButton fourwinsBtn;
private JButton tictactoeBtn;
private JButton leaderboardBtn;
private JButton backBtn;
private JLabel username;
private JLabel loginWarning;
private JLabel chosenGame;
private JTextField usernameInput;
private Dimension minSize;
private Dimension loginBtnSize;
private Dimension btnSize;
private GridBagConstraints gbc;
private static final String playerFile = "src/main/java/resources/player_data.csv";
private enum Game { FLEETSTORM, FOURWINS, TICTACTOE, LEADERBOARD };
private Game actualGame;
private PlayerManager manager;
private Player actualPlayer;
public GameExplorer() {
manager = new PlayerManager();
frame = new JFrame("1000 infomagische Spiele");
minSize = new Dimension(400, 300);
loginBtnSize = new Dimension(91, 20);
btnSize = new Dimension(160, 40);
gbc = new GridBagConstraints();
buildExplorerPanel();
buildLoginPanel();
buildNavigationPanel();
buildGamePanels();
frame.add(loginPanel);
frame.setMinimumSize(minSize);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(640, 480);
frame.setResizable(true);
frame.setVisible(true);
}
private void buildExplorerPanel() {
explorerPanel = new JPanel();
explorerPanel.setLayout(new GridBagLayout());
fleetstormBtn = new JButton("Schiffe versenken");
fleetstormBtn.setPreferredSize(btnSize);
fleetstormBtn.addActionListener(new GameAction());
fourwinsBtn = new JButton("Vier gewinnt");
fourwinsBtn.setPreferredSize(btnSize);
fourwinsBtn.addActionListener(new GameAction());
tictactoeBtn = new JButton("TicTacToe");
tictactoeBtn.setPreferredSize(btnSize);
tictactoeBtn.addActionListener(new GameAction());
leaderboardBtn = new JButton("Leaderboard");
leaderboardBtn.setPreferredSize(btnSize);
leaderboardBtn.addActionListener(new GameAction());
border1 = new JPanel();
border1.setOpaque(false);
border2 = new JPanel();
border2.setOpaque(false);
border3 = new JPanel();
border3.setOpaque(false);
border4 = new JPanel();
border4.setOpaque(false);
border5 = new JPanel();
border5.setOpaque(false);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weighty = 0.2;
explorerPanel.add(border1, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.weighty = 0.0;
explorerPanel.add(fleetstormBtn, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
gbc.weighty = 0.2;
explorerPanel.add(border2, gbc);
gbc.gridx = 0;
gbc.gridy = 3;
gbc.weighty = 0.0;
explorerPanel.add(fourwinsBtn, gbc);
gbc.gridx = 0;
gbc.gridy = 4;
gbc.weighty = 0.2;
explorerPanel.add(border3, gbc);
gbc.gridx = 0;
gbc.gridy = 5;
gbc.weighty = 0.0;
explorerPanel.add(tictactoeBtn, gbc);
gbc.gridx = 0;
gbc.gridy = 6;
gbc.weighty = 0.2;
explorerPanel.add(border4, gbc);
gbc.gridx = 0;
gbc.gridy = 7;
gbc.weighty = 0.0;
explorerPanel.add(leaderboardBtn, gbc);
gbc.gridx = 0;
gbc.gridy = 8;
gbc.weighty = 0.2;
explorerPanel.add(border5, gbc);
}
private void buildLoginPanel() {
loginPanel = new JPanel();
loginPanel.setLayout(new GridBagLayout());
loginBtn = new JButton("Login");
loginBtn.setPreferredSize(loginBtnSize);
loginBtn.addActionListener(new LoginAction());
username = new JLabel("Name eingeben:");
loginWarning = new JLabel();
usernameInput = new JTextField(8);
gbc.weighty = 0;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(0, 0, 5, 0);
loginPanel.add(username, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.insets = new Insets(5, 0, 5, 0);
loginPanel.add(usernameInput, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
gbc.insets = new Insets(5, 0, 5, 0);
loginPanel.add(loginBtn, gbc);
gbc.gridx = 0;
gbc.gridy = 3;
gbc.insets = new Insets(5, 0, 0, 0);
loginPanel.add(loginWarning, gbc);
}
private void buildNavigationPanel() {
navigationPanel = new JPanel();
navigationPanel.setLayout(new GridBagLayout());
backBtn = new JButton("< Zurück");
backBtn.addActionListener(new BackAction());
chosenGame = new JLabel();
border6 = new JPanel();
border6.setOpaque(false);
gbc.weighty = 0.0;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 0.0;
gbc.insets = new Insets(5, 20, 5, 0);
navigationPanel.add(backBtn, gbc);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.weightx = 1.0;
gbc.insets = new Insets(0, 0, 0, 0);
navigationPanel.add(border6, gbc);
gbc.gridx = 2;
gbc.gridy = 0;
gbc.weightx = 0.0;
gbc.insets = new Insets(5, 0, 5, 20);
navigationPanel.add(chosenGame, gbc);
}
private void buildGamePanels() {
gamePanel = new JPanel();
gamePanel.setLayout(new BorderLayout());
gamePanel.add(navigationPanel, BorderLayout.PAGE_START);
//use of dummy panels because real panels have not been implemented yet
fleetstormPanel = new JPanel();
fleetstormPanel.setBackground(Color.BLUE);
fourwinsPanel = new JPanel();
fourwinsPanel.setBackground(Color.GREEN);
tictactoePanel = new JPanel();
tictactoePanel.setBackground(Color.YELLOW);
leaderboardPanel = new JPanel();
leaderboardPanel.setBackground(Color.RED);
}
private class LoginAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String userInput = usernameInput.getText();
if (!userInput.equals("")) {
loginWarning.setText("");
manager.loadPlayers(playerFile);
actualPlayer = manager.selectPlayer(userInput);
frame.remove(loginPanel);
frame.add(explorerPanel);
frame.revalidate();
frame.repaint();
System.out.println("Actual Player: " + actualPlayer.getName() + ", Points: " + actualPlayer.getPoints());
} else {
loginWarning.setText("Kein Name eingegeben!");
}
}
}
private class GameAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//each button adds a different dummy panel to the gamePanel
if (e.getSource() == fleetstormBtn) {
actualGame = Game.FLEETSTORM;
chosenGame.setText("Schiffe versenken");
gamePanel.add(fleetstormPanel, BorderLayout.CENTER);
} else if (e.getSource() == fourwinsBtn) {
actualGame = Game.FOURWINS;
chosenGame.setText("Vier gewinnt");
gamePanel.add(fourwinsPanel, BorderLayout.CENTER);
} else if (e.getSource() == tictactoeBtn) {
actualGame = Game.TICTACTOE;
chosenGame.setText("TicTacToe");
gamePanel.add(tictactoePanel, BorderLayout.CENTER);
} else if (e.getSource() == leaderboardBtn) {
actualGame = Game.LEADERBOARD;
chosenGame.setText("Leaderboard");
gamePanel.add(leaderboardPanel, BorderLayout.CENTER);
}
frame.remove(explorerPanel);
frame.add(gamePanel);
frame.revalidate();
frame.repaint();
}
}
private class BackAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
switch (actualGame) {
case FLEETSTORM:
gamePanel.remove(fleetstormPanel);
break;
case FOURWINS:
gamePanel.remove(fourwinsPanel);
break;
case TICTACTOE:
gamePanel.remove(tictactoePanel);
break;
case LEADERBOARD:
gamePanel.remove(leaderboardPanel);
}
frame.remove(gamePanel);
frame.add(explorerPanel);
frame.revalidate();
frame.repaint();
}
}
public static void main(String[] args) {
new GameExplorer();
}
}

45
src/main/java/de/tims/player_management/Player.java

@ -0,0 +1,45 @@
package de.tims.player_management;
public class Player {
private String name;
private int points;
public Player(String name, int points) {
this.name = name;
this.points = points;
}
public String getName() {
return name;
}
public int getPoints() {
return this.points;
}
public void addPoints(int pointsToAdd) {
this.points = (this.points + pointsToAdd > 0) ? this.points + pointsToAdd : 0;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if ((o == null) || this.getClass() != o.getClass()) {
return false;
}
Player player2 = (Player) o;
return this.points == player2.points && this.name.equals(player2.getName());
}
@Override
public int hashCode() {
return points + name.hashCode();
}
}

95
src/main/java/de/tims/player_management/PlayerManager.java

@ -0,0 +1,95 @@
package de.tims.player_management;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
public class PlayerManager {
private List<Player> players;
private static final int PLAYER_ATTRIBUTES = 2;
public List<Player> getPlayers() {
return players;
}
public void setPlayers(List<Player> players) {
this.players = players;
}
public Player selectPlayer(String playerName) {
for (Player p : this.players) {
if (playerName.equals(p.getName())) {
return p;
}
}
Player newPlayer = new Player(playerName, 0);
players.add(newPlayer);
return newPlayer;
}
public void loadPlayers(String fileName) {
players = new LinkedList<Player>();
File playerData = new File(fileName);
try {
FileReader fr = new FileReader(playerData);
int c = -1;
String playerName;
int playerPoints;
StringBuilder nameBuilder = new StringBuilder();
StringBuilder pointBuilder = new StringBuilder();
StringBuilder[] sb = {nameBuilder, pointBuilder};
do {
for (int i = 0; i < PLAYER_ATTRIBUTES; i++) {
do {
c = fr.read();
if (c != ';' && c != '\n' && c != -1) {
sb[i].append((char) c);
}
} while (c != ';' && c != '\n' && c != -1);
}
if (!nameBuilder.toString().equals("") && !pointBuilder.toString().equals("")) {
playerName = nameBuilder.toString();
playerPoints = Integer.parseInt(pointBuilder.toString());
players.add(new Player(playerName, playerPoints));
nameBuilder.delete(0, nameBuilder.length());
pointBuilder.delete(0, pointBuilder.length());
}
} while (c != -1);
fr.close();
} catch (IOException e) {
return;
}
}
public void savePlayers(String fileName) {
File playerData = new File(fileName);
try {
FileWriter fw = new FileWriter(playerData, false);
for (Player elem : players) {
fw.write(elem.getName() + ";" + elem.getPoints() + "\n");
}
fw.close();
} catch (IOException e) {
return;
}
}
}

183
src/main/java/de/tims/tictactoe/GameLogic.java

@ -0,0 +1,183 @@
package de.tims.tictactoe;
import java.awt.GridLayout;
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 {
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;
public GameLogic(int size) {
if (size < 3) {
size = 3;
}
this.board = new char[size][size];
this.resetBoard();
}
public GameLogic(char[][] board) {
this.board = board;
}
public char[][] getBoard() {
return this.board;
}
public int countFields() {
return this.board[0].length * this.board.length;
}
public void setField(int column, int row, char player) {
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) {
for (char field : this.occupiedFields) {
if (this.board[column][row] == field)
return false;
}
return true;
}
public boolean checkForWin(char player) {
boolean won = 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 (this.board[j][i] == player)
countFields++;
}
if (countFields == this.board.length)
return won = 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 (this.board[i][j] == player)
countFields++;
}
if (countFields == this.board.length)
return won = true;
countFields = 0;
}
// check diagonal left
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 won = 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 won = true;
return won;
}
public boolean checkEndOfGame() {
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;
}
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] = EMPTY_FIELD;
}
}
}
public JPanel generateGUI() {
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();
this.fields[i][j].addActionListener(this);
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() {
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.");
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();
}
@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]) {
this.setField(i, j, currentPlayer);
this.fields[i][j].getText();
}
}
}
}
}

22
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();
}
}

34
src/main/java/de/tims/tictactoe/ai/AIEasy.java

@ -0,0 +1,34 @@
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 static final char EMPTY_CHAR = '-';
private Random rand;
private GameLogic gl;
private int boardSize;
public AIEasy(GameLogic gl) {
this.gl = gl;
boardSize = gl.getBoard().length;
rand = new Random();
}
@Override
public void calculateNextMove() {
char[][] board = gl.getBoard();
int row;
int col;
do {
row = rand.nextInt(boardSize);
col = rand.nextInt(boardSize);
} while (board[row][col] != EMPTY_CHAR);
gl.setField(row, col, AI_CHAR);
}
}

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

@ -0,0 +1,190 @@
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 static final char PLAYER_CHAR = 'x';
private static final int BOARD_SIZE = 3;
private GameLogic gl;
public AIHard(GameLogic gl) throws IllegalArgumentException {
if (gl.getBoard().length != BOARD_SIZE) {
throw new IllegalArgumentException("Hard AI only supports 3x3 boards!");
}
this.gl = gl;
}
@Override
public void calculateNextMove() {
char[][] board = gl.getBoard();
int row;
int col;
int charsInRow = 0;
int charsInCol = 0;
int charsInDiag = 0;
char actualChar;
for (int i = 0; i < 2; i++) {
actualChar = (i == 0) ? AI_CHAR : PLAYER_CHAR;
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++) {
row = k;
col = (j == 0) ? k : BOARD_SIZE - 1 - k;
if (board[row][col] == EMPTY_CHAR) {
gl.setField(row, col, AI_CHAR);
return;
}
}
}
}
if (charsInRow == BOARD_SIZE - 1 || charsInCol == BOARD_SIZE - 1) {
for (int k = 0; k < BOARD_SIZE; k++) {
if (charsInRow == BOARD_SIZE - 1) {
row = j;
col = k;
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;
}
}
}
}
}
}
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++) {
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;
row = -1;
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) {
if (board[i][j] == EMPTY_CHAR) {
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;
}
}
}
if (emptyEdgeFound) {
break;
}
}
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;
}
}
}
}
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) {
int count = 0;
char[][] board = gl.getBoard();
for (int i = 0; i < BOARD_SIZE; i++) {
count += (board[i][index] == charToCount) ? 1 : 0;
}
return count;
}
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();
for (int i = 0; i < BOARD_SIZE; i++) {
count += (board[i][(index == 0) ? i : BOARD_SIZE - 1 - i] == charToCount) ? 1 : 0;
}
return count;
}
}

5
src/main/java/de/tims/tictactoe/ai/TicTacToeAI.java

@ -0,0 +1,5 @@
package de.tims.tictactoe.ai;
public interface TicTacToeAI {
void calculateNextMove();
}

0
src/main/java/resources/player_data.csv

21
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);
}
}

366
src/test/java/de/tims/fleetstorm/ai/LogicTest.java

@ -1,16 +1,376 @@
package de.tims.fleetstorm.ai;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.util.ArrayList;
import org.junit.jupiter.api.Test;
import de.tims.fleetstorm.matchfield.Coordinate;
import de.tims.fleetstorm.matchfield.Matchfield;
class LogicTest {
Logic logic = new Logic();
@Test
void testFielIsNotNull() {
int[] calcResult = logic.chooseField();
void testFieldIsNotNull() {
Logic logic = new Logic();
Matchfield matchfield;
int size = 5;
matchfield = new Matchfield(size);
matchfield.createMatchfield();
logic.setMatchfield(matchfield);
// ArrayList<Coordinate> everySecondField = logic.getEverySecondField();
Coordinate calcResult = logic.chooseField();
assertNotNull(calcResult);
}
@Test
void testChoosenFieldHasNotStateShot() {
Logic logic = new Logic();
Matchfield matchfield;
int size = 5;
matchfield = new Matchfield(size);
matchfield.createMatchfield();
logic.setMatchfield(matchfield);
ArrayList<Coordinate> everySecondField = logic.getEverySecondField();
for (int i = 0; i < everySecondField.size(); i++) {
everySecondField.get(i).setState(Coordinate.SHOT);
}
matchfield.setState(2, 2, Coordinate.EMPTY);
logic.setEverySecondField(everySecondField);
int calcState = logic.chooseField().getState();
assertNotEquals(calcState, Coordinate.SHOT);
}
@Test
void testGetEverySecondField() {
Logic logic = new Logic();
Matchfield matchfield;
int size = 4;
matchfield = new Matchfield(size);
matchfield.createMatchfield();
logic.setMatchfield(matchfield);
ArrayList<Coordinate> everySecondField = logic.getEverySecondField();
ArrayList<Coordinate> expectedResult = new ArrayList<Coordinate>();
expectedResult.add(new Coordinate(0, 0));
expectedResult.add(new Coordinate(0, 2));
expectedResult.add(new Coordinate(1, 1));
expectedResult.add(new Coordinate(1, 3));
expectedResult.add(new Coordinate(2, 0));
expectedResult.add(new Coordinate(2, 2));
expectedResult.add(new Coordinate(3, 1));
expectedResult.add(new Coordinate(3, 3));
assertEquals(everySecondField, expectedResult);
}
@Test
void testGetAndSetLastShot() {
Logic logic = new Logic();
Matchfield matchfield;
int size = 4;
matchfield = new Matchfield(size);
matchfield.createMatchfield();
logic.setMatchfield(matchfield);
Coordinate expectedResult = new Coordinate(2, 2);
logic.setLastShot(expectedResult);
Coordinate result = logic.getLastShot();
assertEquals(result, expectedResult);
}
@Test
void testSetMatchfield() {
Logic logic = new Logic();
Matchfield matchfield;
int size = 4;
matchfield = new Matchfield(size);
matchfield.createMatchfield();
Matchfield result = logic.getMatchfield();
assertEquals(result, null);
logic.setMatchfield(matchfield);
result = logic.getMatchfield();
assertNotNull(result);
}
@Test
void testFindShip() {
Logic logic = new Logic();
Matchfield matchfield;
int size = 4;
matchfield = new Matchfield(size);
matchfield.createMatchfield();
logic.setMatchfield(matchfield);
logic.setLastShot(new Coordinate(2, 2));
logic.getLastShot().setState(Coordinate.HIT);
logic.findShip();
assertEquals(logic.getFoundShip(), true);
}
@Test
void testGetAndsetFoundShip() {
Logic logic = new Logic();
logic.setFoundShip(true);
assertEquals(logic.getFoundShip(), true);
}
@Test
void testClearAbove() {
Logic logic = new Logic();
Matchfield matchfield;
Coordinate shot = new Coordinate(2, 2);
int size = 4;
matchfield = new Matchfield(size);
matchfield.createMatchfield();
logic.setMatchfield(matchfield);
logic.setLastShot(shot);
matchfield.getField(shot).setState(Coordinate.EMPTY);
logic.clearAbove(shot);
assertEquals(logic.getClearedAbove(), true);
}
@Test
void testClearBelow() {
Logic logic = new Logic();
Matchfield matchfield;
Coordinate shot = new Coordinate(2, 2);
int size = 4;
matchfield = new Matchfield(size);
matchfield.createMatchfield();
logic.setMatchfield(matchfield);
logic.setLastShot(shot);
matchfield.getField(shot).setState(Coordinate.EMPTY);
logic.clearBelow(shot);
assertEquals(logic.getClearedBelow(), true);
}
@Test
void testClearRight() {
Logic logic = new Logic();
Matchfield matchfield;
Coordinate shot = new Coordinate(2, 2);
int size = 4;
matchfield = new Matchfield(size);
matchfield.createMatchfield();
logic.setMatchfield(matchfield);
logic.setLastShot(shot);
matchfield.getField(shot).setState(Coordinate.EMPTY);
logic.clearRight(shot);
assertEquals(logic.getClearedRight(), true);
}
@Test
void testClearLeft() {
Logic logic = new Logic();
Matchfield matchfield;
Coordinate shot = new Coordinate(2, 2);
int size = 4;
matchfield = new Matchfield(size);
matchfield.createMatchfield();
logic.setMatchfield(matchfield);
logic.setLastShot(shot);
matchfield.getField(shot).setState(Coordinate.EMPTY);
logic.clearLeft(shot);
assertEquals(logic.getClearedLeft(), true);
}
@Test
void testConstructor() {
Logic logic = new Logic();
assertEquals(logic.getFoundShip(), false);
assertEquals(logic.getClearedAbove(), false);
assertEquals(logic.getClearedBelow(), false);
assertEquals(logic.getClearedLeft(), false);
assertEquals(logic.getClearedRight(), false);
}
@Test
void testSetterClearedAbove() {
Logic logic = new Logic();
logic.setClearedAbove(true);
assertEquals(logic.getClearedAbove(), true);
}
@Test
void testSetterClearedBelow() {
Logic logic = new Logic();
logic.setClearedBelow(true);
assertEquals(logic.getClearedBelow(), true);
}
@Test
void testSetterClearedRight() {
Logic logic = new Logic();
logic.setClearedRight(true);
assertEquals(logic.getClearedRight(), true);
}
@Test
void testSetterClearedLeft() {
Logic logic = new Logic();
logic.setClearedLeft(true);
assertEquals(logic.getClearedLeft(), true);
}
@Test
void testSinkShip() {
Logic logic = new Logic();
logic.setFoundShip(true);
logic.setClearedAbove(true);
logic.setClearedBelow(true);
logic.setClearedRight(true);
logic.setClearedLeft(true);
logic.sinkShip();
assertEquals(logic.getFoundShip(), false);
assertEquals(logic.getClearedAbove(), false);
assertEquals(logic.getClearedBelow(), false);
assertEquals(logic.getClearedLeft(), false);
assertEquals(logic.getClearedRight(), false);
}
@Test
void testChooseFieldAboveAfterHit() {
Logic logic = new Logic();
int size = 4;
Coordinate center = new Coordinate(2, 2);
Coordinate expectedResult = new Coordinate(2, 3);
Matchfield matchfield = new Matchfield(size);
matchfield.createMatchfield();
matchfield.setState(center, Coordinate.HIT);
matchfield.setState(expectedResult, Coordinate.HIT);
logic.setMatchfield(matchfield);
logic.setLastShot(center);
logic.setTarget(center);
logic.setFoundShip(true);
Coordinate result = logic.chooseField();
assertEquals(result, expectedResult);
}
@Test
void testChooseFieldBelowAfterHit() {
Logic logic = new Logic();
int size = 4;
Coordinate center = new Coordinate(2, 2);
Coordinate expectedResult = new Coordinate(2, 1);
Matchfield matchfield = new Matchfield(size);
matchfield.createMatchfield();
matchfield.setState(center, Coordinate.HIT);
matchfield.setState(expectedResult, Coordinate.HIT);
logic.setMatchfield(matchfield);
logic.setLastShot(center);
logic.setTarget(center);
logic.setFoundShip(true);
logic.chooseField();// first Shot
Coordinate result = logic.chooseField(); // second Shot
assertEquals(result, expectedResult);
}
@Test
void testChooseFieldRightAfterHit() {
Logic logic = new Logic();
int size = 4;
Coordinate center = new Coordinate(2, 2);
Coordinate expectedResult = new Coordinate(3, 2);
Matchfield matchfield = new Matchfield(size);
matchfield.createMatchfield();
matchfield.setState(center, Coordinate.HIT);
matchfield.setState(expectedResult, Coordinate.HIT);
logic.setMatchfield(matchfield);
logic.setLastShot(center);
logic.setTarget(center);
logic.setFoundShip(true);
logic.chooseField(); // first Shot
logic.chooseField(); // second Shot
Coordinate result = logic.chooseField();
assertEquals(result, expectedResult);
}
@Test
void testChooseFieldLeftAfterHit() {
Logic logic = new Logic();
int size = 4;
Coordinate center = new Coordinate(2, 2);
Coordinate expectedResult = new Coordinate(1, 2);
Matchfield matchfield = new Matchfield(size);
matchfield.createMatchfield();
matchfield.setState(center, Coordinate.HIT);
matchfield.setState(expectedResult, Coordinate.HIT);
logic.setMatchfield(matchfield);
logic.setLastShot(center);
logic.setTarget(center);
logic.setFoundShip(true);
logic.chooseField(); // first Shot
logic.chooseField(); // second Shot
logic.chooseField(); // third Shot Coordinate
Coordinate result = logic.chooseField();
assertEquals(result, expectedResult);
}
@Test
void testShipIsOnYAxis() {
int size = 10;
Logic logic = new Logic();
Matchfield matchfield = new Matchfield(size);
Coordinate s1 = new Coordinate(5, 4);
Coordinate s2 = new Coordinate(5, 5);
Coordinate s3 = new Coordinate(5, 6);
matchfield.createMatchfield();
matchfield.setState(s1, Coordinate.SHIP);
matchfield.setState(s2, Coordinate.HIT);
matchfield.setState(s3, Coordinate.SHIP);
logic.setMatchfield(matchfield);
logic.setLastShot(s2);
logic.setTarget(s2);
logic.setFoundShip(true);
logic.chooseField(); // First shot (s3)
logic.getMatchfield().setState(s3, Coordinate.HIT); //
logic.chooseField(); // Second Shot
logic.getMatchfield().setState(new Coordinate(5, 7), Coordinate.SHOT);
logic.chooseField(); // Third Shot (s1)
logic.getMatchfield().setState(s1, Coordinate.HIT); //
logic.chooseField(); // fourth Shot
assertEquals(logic.getFoundShip(), false);
assertEquals(logic.getClearedAbove(), false);
assertEquals(logic.getClearedBelow(), false);
assertEquals(logic.getClearedLeft(), false);
assertEquals(logic.getClearedRight(), false);
}
}

36
src/test/java/de/tims/fleetstorm/gui/LogicTest.java

@ -0,0 +1,36 @@
package de.tims.fleetstorm.gui;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class LogicTest {
GameLogic guiLogic = new GameLogic(0, 0, 0, 0);
@BeforeEach
void setup() {
guiLogic.start(true);
}
@Test
void testIfGameStateIsRunningAfterStart() {
int expectedState = GameLogic.RUNNING;
int calculatedState = guiLogic.getGameState();
assertEquals(expectedState, calculatedState);
}
@Test
void testIfGameStateIsGameOverAfterGameOverFunction() {
int expectedState = GameLogic.GAME_OVER;
guiLogic.gameOver(true);
int calculatedState = guiLogic.getGameState();
assertEquals(expectedState, calculatedState);
}
}

82
src/test/java/de/tims/fleetstorm/matchfield/CoordinateTest.java

@ -0,0 +1,82 @@
package de.tims.fleetstorm.matchfield;
import static org.junit.jupiter.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.stream.Stream;
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 CoordinateTest {
int x = 1;
int y = 3;
Coordinate coordinate = new Coordinate(x, y);
@Test
void testGetCorrectValuesForXY() {
assertEquals(coordinate.getX(), x);
assertEquals(coordinate.getY(), y);
}
@Test
void testCoordinatehasDefaultStates() {
assertEquals(coordinate.getState(), Coordinate.EMPTY);
assertEquals(coordinate.getState(), 0);
}
@ParameterizedTest(name = "All Getters/Setters are working")
@MethodSource("AllGettersAreWorking")
void testGetAndSetForAllStates(String testName, int state, int stateCode, int expectedResult) {
coordinate.setState(state);
int result = coordinate.getState();
assertThat(result).describedAs(testName).isEqualTo(expectedResult);
}
static Stream<Arguments> AllGettersAreWorking() {
return Stream.of(Arguments.of("State = SHIP", 1, Coordinate.SHIP, Coordinate.SHIP),
Arguments.of("State = SHOT", 2, Coordinate.SHOT, Coordinate.SHOT),
Arguments.of("State = HIT", 3, Coordinate.HIT, Coordinate.HIT),
Arguments.of("State = EMPTY", 0, Coordinate.EMPTY, Coordinate.EMPTY));
}
@ParameterizedTest(name = "test if shoot function sets correct field states")
@MethodSource("ShootFunctionFieldStates")
void testShootFunctionSetsCorrectFieldStates(String testName, Coordinate coordinateToTest, int expectedState) {
Matchfield matchfield = new Matchfield(10);
matchfield.createMatchfield();
// set dummy ship
matchfield.setShip(new Coordinate(0, 0), 5, 0);
Coordinate realCoordinate = matchfield.getField(coordinateToTest);
realCoordinate.shoot();
int calculatedResult = realCoordinate.getState();
assertThat(calculatedResult).describedAs(testName).isEqualTo(expectedState);
}
static Stream<Arguments> ShootFunctionFieldStates() {
return Stream.of(Arguments.of("Field State is HIT", new Coordinate(0, 0), Coordinate.HIT),
Arguments.of("Field State is SHOT", new Coordinate(0, 1), Coordinate.SHOT));
}
@Test
void testIfShootCheckWhenFieldIsAlreadyShot() {
Matchfield matchfield = new Matchfield(10);
matchfield.createMatchfield();
// set dummy ship
matchfield.setShip(new Coordinate(3, 3), 4, 1);
assertTrue(matchfield.getField(0, 0).shoot());
assertFalse(matchfield.getField(0, 0).shoot());
matchfield.getField(3, 4).shoot();
assertFalse(matchfield.getField(3, 4).shoot());
}
}

144
src/test/java/de/tims/fleetstorm/matchfield/MatchfieldCreationTest.java

@ -0,0 +1,144 @@
package de.tims.fleetstorm.matchfield;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.util.stream.Stream;
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 MatchfieldCreationTest {
@Test
void testMatchfieldCreateNotEmpty() {
Matchfield matchfield = new Matchfield(0);
Coordinate[][] calcResult = matchfield.createMatchfield();
assertNotNull(calcResult);
}
@ParameterizedTest(name = "matchfield creation has correct size")
@MethodSource("testMatchfieldSize")
void testMatchfieldCreationHasCorrectSize(String testName, int size, int expectedResult) {
Matchfield matchfield = new Matchfield(size);
matchfield.createMatchfield();
int calcResult = matchfield.getSize();
assertThat(calcResult).describedAs(testName).isEqualTo(expectedResult);
}
static Stream<Arguments> testMatchfieldSize() {
return Stream.of(Arguments.of("field size 10x10", 10, 100), Arguments.of("field size 15x15", 15, 225));
}
@ParameterizedTest(name = "matchfield get field is correct")
@MethodSource("testMatchfieldGetFieldState")
void testMatchfieldGetCorrectState(String testName, int x, int y, int expectedResult) {
Matchfield matchfield = new Matchfield(10);
matchfield.createMatchfield();
int calcResult = matchfield.getState(x, y);
assertThat(calcResult).describedAs(testName).isEqualTo(expectedResult);
}
static Stream<Arguments> testMatchfieldGetFieldState() {
return Stream.of(Arguments.of("field x:0 y:0 has empty state", 0, 0, Coordinate.EMPTY));
}
@ParameterizedTest(name = "matchfield change field is correct")
@MethodSource("testMatchfieldSetStateIsCorrect")
void testMatchfieldGetCorrectState(String testName, int x, int y, int state, int expectedResult) {
Matchfield matchfield = new Matchfield(10);
matchfield.createMatchfield();
matchfield.setState(x, y, state);
int calcResult = matchfield.getState(x, y);
assertThat(calcResult).describedAs(testName).isEqualTo(expectedResult);
}
static Stream<Arguments> testMatchfieldSetStateIsCorrect() {
return Stream.of(
Arguments.of("field x:0 y:0 has state SHIP after setState()", 0, 0, Coordinate.SHIP, Coordinate.SHIP));
}
@ParameterizedTest(name = "Get the Coordinate right")
@MethodSource("getCoordinateRight")
void testGetRight(String testName, Matchfield matchfield, Coordinate center, Coordinate expectedResult) {
Coordinate result = matchfield.getRight(center);
assertThat(result).describedAs(testName).isEqualTo(expectedResult);
}
static Stream<Arguments> getCoordinateRight() {
Matchfield matchfield = new Matchfield(10);
return Stream.of(
Arguments.of("right from (5/5) - should be (6,5)", matchfield, new Coordinate(5, 5),
matchfield.getField(6, 5)),
Arguments.of("right from (9/5) - should be null", matchfield, new Coordinate(9, 5), null));
}
@ParameterizedTest(name = "Get the Coordinate left")
@MethodSource("getCoordinateLeft")
void testGetLeft(String testName, Matchfield matchfield, Coordinate center, Coordinate expectedResult) {
Coordinate result = matchfield.getLeft(center);
assertThat(result).describedAs(testName).isEqualTo(expectedResult);
}
static Stream<Arguments> getCoordinateLeft() {
Matchfield matchfield = new Matchfield(10);
return Stream.of(
Arguments.of("left from (5/5) - should be (4,5)", matchfield, new Coordinate(5, 5),
matchfield.getField(4, 5)),
Arguments.of("left from (0/5) - should be null", matchfield, new Coordinate(0, 5), null));
}
@ParameterizedTest(name = "Get the Coordinate above")
@MethodSource("getCoordinateAbove")
void testGetAbove(String testName, Matchfield matchfield, Coordinate center, Coordinate expectedResult) {
Coordinate result = matchfield.getAbove(center);
assertThat(result).describedAs(testName).isEqualTo(expectedResult);
}
static Stream<Arguments> getCoordinateAbove() {
Matchfield matchfield = new Matchfield(10);
return Stream.of(
Arguments.of("above from (5/5) - should be (5,6)", matchfield, new Coordinate(5, 5),
matchfield.getField(5, 6)),
Arguments.of("above from (5/9) - should be null", matchfield, new Coordinate(5, 5), null));
}
@ParameterizedTest(name = "Get the Coordinate below")
@MethodSource("getCoordinateBelow")
void testGetBelow(String testName, Matchfield matchfield, Coordinate center, Coordinate expectedResult) {
Coordinate result = matchfield.getBelow(center);
assertThat(result).describedAs(testName).isEqualTo(expectedResult);
}
static Stream<Arguments> getCoordinateBelow() {
Matchfield matchfield = new Matchfield(10);
return Stream.of(
Arguments.of("below from (5/5) - should be (5,4)", matchfield, new Coordinate(5, 5),
matchfield.getField(5, 4)),
Arguments.of("below from (5/0) - should be null", matchfield, new Coordinate(5, 0), null));
}
@Test
void testsetStateOverloaded() {
Matchfield matchfield = new Matchfield(10);
matchfield.createMatchfield();
int x = 3;
int y = 3;
matchfield.setState(new Coordinate(x, y), Coordinate.SHIP);
int result = matchfield.getState(x, y);
assertEquals(result, Coordinate.SHIP);
}
}

133
src/test/java/de/tims/fleetstorm/matchfield/MatchfieldShipTest.java

@ -0,0 +1,133 @@
package de.tims.fleetstorm.matchfield;
import static org.junit.jupiter.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.stream.Stream;
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 MatchfieldShipTest {
@ParameterizedTest(name = "ship was set on the correct positions")
@MethodSource("testShipPositioning")
void testMatchfieldShipSetHasCorrectPositions(String testName, int matchfieldSize, Coordinate coordinate,
int direction, int length, Coordinate[] coordinatesWithShip) {
Matchfield matchfield = new Matchfield(matchfieldSize);
matchfield.createMatchfield();
matchfield.setShip(coordinate, length, direction);
int shipSetCounter = 0;
for (Coordinate toCheckCoordinate : coordinatesWithShip) {
if (matchfield.getField(toCheckCoordinate).getState() == Coordinate.SHIP)
shipSetCounter++;
}
assertThat(shipSetCounter).describedAs(testName).isEqualTo(length);
}
static Stream<Arguments> testShipPositioning() {
Coordinate[] coordinatesWithShip00_2_0 = new Coordinate[] { new Coordinate(0, 0), new Coordinate(1, 0) };
Coordinate[] coordinatesWithShip01_3_0 = new Coordinate[] { new Coordinate(0, 1), new Coordinate(1, 1),
new Coordinate(2, 1) };
Coordinate[] coordinatesWithShip02_4_1 = new Coordinate[] { new Coordinate(0, 2), new Coordinate(0, 3),
new Coordinate(0, 4), new Coordinate(0, 5) };
return Stream.of(
Arguments.of("set ship from 0:0, length 2, direction 0", 10, new Coordinate(0, 0), 0, 2,
coordinatesWithShip00_2_0),
Arguments.of("set ship from 0:1, length 3, direction 0", 10, new Coordinate(0, 1), 0, 3,
coordinatesWithShip01_3_0),
Arguments.of("set ship from 0:2, length 4, direction 1", 10, new Coordinate(0, 2), 1, 4,
coordinatesWithShip02_4_1));
}
@ParameterizedTest(name = "ship positioning on invalid or valid coordinates")
@MethodSource("testShipPositioningFailed")
void testMatchfieldShipSetWithInvalidOrValidCoordinates(String testName, int matchfieldSize, Coordinate coordinate,
int direction, int length, boolean expectedResult) {
Matchfield matchfield = new Matchfield(matchfieldSize);
matchfield.createMatchfield();
boolean calculatedResult = matchfield.setShip(coordinate, length, direction);
if (expectedResult)
assertThat(calculatedResult).describedAs(testName).isEqualTo(true);
if (!expectedResult)
assertThat(calculatedResult).describedAs(testName).isEqualTo(false);
}
static Stream<Arguments> testShipPositioningFailed() {
return Stream.of(
Arguments.of("invalid ship position from 9:0, length 2, direction 0", 10, new Coordinate(9, 0), 0, 2,
false),
Arguments.of("valid ship position from 8:0, length 5, direction 1", 10, new Coordinate(9, 0), 1, 5,
true));
}
@Test
void testShipPositionAlreadySetWithShip() {
Matchfield matchfield = new Matchfield(10);
matchfield.createMatchfield();
matchfield.setShip(new Coordinate(0, 0), 5, 1);
assertThat(matchfield.setShip(new Coordinate(0, 1), 5, 1)).describedAs("set ship on coordinate with ship")
.isEqualTo(false);
assertThat(matchfield.setShip(new Coordinate(1, 1), 4, 0)).describedAs("set ship on coordinate without ship")
.isEqualTo(true);
assertThat(matchfield.setShip(new Coordinate(4, 1), 2, 1))
.describedAs("set second ship on coordinate without ship").isEqualTo(false);
}
@Test
void testIfAllShipsHitReturnsFalseWhenNoShipIsHit() {
Matchfield matchfield = new Matchfield(10);
matchfield.createMatchfield();
matchfield.setShip(new Coordinate(0, 0), 5, 1);
boolean calulatedResult = matchfield.areAllShipsHit();
assertFalse(calulatedResult);
}
@Test
void testIfAllShipsHitReturnsTrueWhenAllShipsAreHit() {
Matchfield matchfield = new Matchfield(10);
matchfield.createMatchfield();
matchfield.setShip(new Coordinate(0, 0), 5, 1);
matchfield.getField(0, 0).setState(Coordinate.HIT);
matchfield.getField(0, 1).setState(Coordinate.HIT);
matchfield.getField(0, 2).setState(Coordinate.HIT);
matchfield.getField(0, 3).setState(Coordinate.HIT);
matchfield.getField(0, 4).setState(Coordinate.HIT);
boolean calulatedResult = matchfield.areAllShipsHit();
assertTrue(calulatedResult);
}
@Test
void testIfAllShipsHitReturnsFalseWhenTwoShipsAreNotFullyHit() {
Matchfield matchfield = new Matchfield(10);
matchfield.createMatchfield();
matchfield.setShip(new Coordinate(0, 0), 5, 1);
matchfield.getField(0, 0).setState(Coordinate.HIT);
matchfield.getField(0, 1).setState(Coordinate.HIT);
matchfield.getField(0, 2).setState(Coordinate.HIT);
matchfield.getField(0, 3).setState(Coordinate.HIT);
matchfield.getField(0, 4).setState(Coordinate.HIT);
matchfield.setShip(new Coordinate(3, 4), 2, 0);
matchfield.getField(4, 4).setState(Coordinate.HIT);
boolean calulatedResult = matchfield.areAllShipsHit();
assertFalse(calulatedResult);
}
}

110
src/test/java/de/tims/player_management/PlayerManagerTest.java

@ -0,0 +1,110 @@
package de.tims.player_management;
import static org.assertj.core.api.Assertions.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Stream;
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 PlayerManagerTest {
PlayerManager manager = new PlayerManager();
@ParameterizedTest
@MethodSource("testCasesForSelectPlayer")
void selectPlayerTest(String testName, List<Player> players, String playerName, Player expectedResult) {
manager.setPlayers(players);
Player calculatedResult = manager.selectPlayer(playerName);
assertThat(calculatedResult).describedAs(testName).isEqualTo(expectedResult);
}
private static Stream<Arguments> testCasesForSelectPlayer() {
return Stream.of(Arguments.of("NoPlayersYetReturnNewPlayer", new LinkedList<Player>(List.of()),
"Tobias", new Player("Tobias", 0)),
Arguments.of("NoPlayerWithNameInListReturnNewPlayer", new LinkedList<Player>(List.of(new Player("Steffen", 40), new Player("Lorenz", 60))),
"Tobias", new Player("Tobias", 0)),
Arguments.of("PlayerWithNameInListReturnPlayerInList", new LinkedList<Player>(List.of(new Player("Steffen", 40), new Player("Tobias", 50))),
"Tobias", new Player("Tobias", 50)));
}
@ParameterizedTest
@MethodSource("testCasesForLoadPlayers")
void loadPlayersTest(String testName, String fileContent, String fileName, List<Player> expectedResult) {
File playerData = new File(fileName);
try {
FileWriter fw = new FileWriter(playerData, false);
fw.write(fileContent);
fw.close();
} catch (IOException e) {
fail("Cannot open file");
}
manager.loadPlayers(fileName);
List<Player> calculatedResult = manager.getPlayers();
assertThat(calculatedResult).describedAs(testName).isEqualTo(expectedResult);
}
private static Stream<Arguments> testCasesForLoadPlayers() {
return Stream.of(Arguments.of("EmptyFileReturnsEmtpyList", "", "src/test/java/resources/player_testdata.csv", List.of()),
Arguments.of("OnePlayerInFileReturnsListWithOneElement", "Tobias;50", "src/test/java/resources/player_testdata.csv",
List.of(new Player("Tobias", 50))),
Arguments.of("MorePlayersInFileReturnLongerList", "Tobias;50\nLorenz;40\nSteffen;60", "src/test/java/resources/player_testdata.csv",
List.of(new Player("Tobias", 50), new Player("Lorenz", 40), new Player("Steffen", 60))));
}
@ParameterizedTest
@MethodSource("testCasesForSavePlayers")
void savePlayersTest(String testName, String fileName, List<Player> expectedResult) {
manager.setPlayers(expectedResult);
manager.savePlayers(fileName);
manager.loadPlayers(fileName);
List<Player> calculatedResult = manager.getPlayers();
assertThat(calculatedResult).describedAs(testName).isEqualTo(expectedResult);
}
private static Stream<Arguments> testCasesForSavePlayers() {
return Stream.of(Arguments.of("EmptyListIsWrittenAsEmptyFile", "src/test/java/resources/player_testdata2.csv", List.of()),
Arguments.of("WriteElementsOfListToFile", "src/test/java/resources/player_testdata2.csv",
List.of(new Player("Tobias", 50), new Player("Steffen", 60))));
}
@Test
void selectPlayerAddsNewPlayersToList() {
LinkedList<Player> players = new LinkedList<Player>();
players.add(new Player("Steffen", 40));
players.add(new Player("Max", 60));
manager.setPlayers(players);
manager.selectPlayer("Tobias");
List<Player> expectedResult = List.of(new Player("Steffen", 40), new Player("Max", 60), new Player("Tobias", 0));
List<Player> calculatedResult = manager.getPlayers();
assertThat(calculatedResult).describedAs("SelectNewPlayerAddsNewPlayerToPlayersList").isEqualTo(expectedResult);
}
@Test
void selectExistingPlayerDoesntChangeTheList() {
LinkedList<Player> players = new LinkedList<Player>();
players.add(new Player("Steffen", 40));
players.add(new Player("Max", 60));
manager.setPlayers(players);
manager.selectPlayer("Max");
List<Player> expectedResult = List.of(new Player("Steffen", 40), new Player("Max", 60));
List<Player> calculatedResult = manager.getPlayers();
assertThat(calculatedResult).describedAs("SelectNewPlayerAddsNewPlayerToPlayersList").isEqualTo(expectedResult);
}
}

32
src/test/java/de/tims/player_management/PlayerTest.java

@ -0,0 +1,32 @@
package de.tims.player_management;
import static org.assertj.core.api.Assertions.*;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class PlayerTest {
Player player;
@ParameterizedTest
@MethodSource("testCasesForAddPoints")
void addPointsTest(String testName, int pointsBefore, int pointsToAdd, int expectedResult) {
player = new Player("TestPlayer", pointsBefore);
player.addPoints(pointsToAdd);
int calculatedResult = player.getPoints();
assertThat(calculatedResult).describedAs(testName).isEqualTo(expectedResult);
}
private static Stream<Arguments> testCasesForAddPoints() {
return Stream.of(Arguments.of("NoPointsBeforeGet0Points", 0, 0, 0),
Arguments.of("NoPointsBeforeGet10Points", 0, 10, 10),
Arguments.of("10PointsBeforeAdd10Points", 10, 10, 20),
Arguments.of("10PointsBeforeLose10Points", 10, -10, 0),
Arguments.of("LoseMorePointsThanYouHave", 10, -20, 0));
}
}

337
src/test/java/de/tims/tictactoe/GameLogicTest.java

@ -0,0 +1,337 @@
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.JPanel;
import org.junit.jupiter.api.BeforeAll;
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 final int SIZE = 3;
private GameLogic game;
@BeforeAll
void setUpBeforeClass() throws Exception {
this.game = new GameLogic(SIZE);
}
@Test
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 = this.game.generateGUI();
assertEquals(expectedResult.getClass(), realResult.getClass());
}
@Test
void numberOfGUIFieldsTest() {
int expectedResult = (int) Math.pow(SIZE, 2);
int realResult = 0;
JPanel gui = this.game.generateGUI();
Component[] components = gui.getComponents();
for (Component component : components) {
if (component instanceof JButton)
realResult++;
}
assertEquals(expectedResult, realResult);
}
@Test
void getCurrentPlayerTest() {
GameLogic game = new GameLogic(SIZE);
char expectedResult = 'x';
char realResult = game.getCurrentPlayer();
assertEquals(expectedResult, realResult);
}
@Test
void switchPlayerTest() {
GameLogic game = new GameLogic(SIZE);
game.switchPlayer();
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) 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<Arguments> 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<Arguments> testCasesForSetField() {
return Stream.of(
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[][]
{{'x', '-', '-'},
{'o', '-', '-'},
{'-', '-', '-'}}),
Arguments.of("try to set occupied field [1][0] for player 1", 1, 0, 'x', new char[][]
{{'x', '-', '-'},
{'o', '-', '-'},
{'-', '-', '-'}})
);
}
private static Stream<Arguments> 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', '-', '-'},
{'-', '-', '-'},
{'-', '-', '-'}})
);
}
private static Stream<Arguments> testCasesForCheckForWin() {
return Stream.of(
Arguments.of("check win in column 0 for player 1", 'x', true, new char[][]
{{'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 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', '-', '-'},
{'o', '-', '-'}}),
Arguments.of("check win in row 0 for player 1", 'x', true, new char[][]
{{'x', 'x', 'x'},
{'-', '-', '-'},
{'-', '-', '-'}}),
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'},
{'-', '-', '-'}}),
Arguments.of("check win in row 2 for player 2", 'o', true, new char[][]
{{'-', '-', '-'},
{'-', '-', '-'},
{'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'}}),
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'}}),
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'}}),
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'}}),
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'}}),
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', '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'}}),
Arguments.of("check diagonal left win for player 1", 'x', true, new char[][]
{{'x', 'o', 'x'},
{'x', 'x', 'o'},
{'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'}})
);
}
private static Stream<Arguments> testCasesForCheckEndOfGame() {
return Stream.of(
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'}}),
Arguments.of("end of game with win for player 2", true, new char[][]
{{'x', 'x', 'o'},
{'o', 'o', 'o'},
{'x', 'o', 'x'}}),
Arguments.of("check tied game", true, new char[][]
{{'x', 'x', 'o'},
{'o', 'x', 'o'},
{'x', 'o', 'x'}}),
Arguments.of("check not yet finished game", false, new char[][]
{{'x', 'x', '-'},
{'o', 'o', '-'},
{'x', 'o', 'x'}})
);
}
private static Stream<Arguments> 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)
);
}
// @formatter:on
}

62
src/test/java/de/tims/tictactoe/ai/AIEasyTest.java

@ -0,0 +1,62 @@
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));
}
@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<Integer> {
@Override
public boolean matches(Integer argument) {
return argument.intValue() >= 0 && argument.intValue() < size;
}
}
}

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

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

3
src/test/java/resources/player_testdata.csv

@ -0,0 +1,3 @@
Tobias;50
Lorenz;40
Steffen;60

2
src/test/java/resources/player_testdata2.csv

@ -0,0 +1,2 @@
Tobias;50
Steffen;60
Loading…
Cancel
Save