From c47326b7ade1a64a9af1aa4abf2e802926b2a49a Mon Sep 17 00:00:00 2001
From: Martin Goik <goik@hdm-stuttgart.de>
Date: Fri, 18 Sep 2015 11:59:58 +0200
Subject: [PATCH] Human vs. computer

---
 P/Sd1/TicTacToe/V4/.gitignore                 |   5 +
 P/Sd1/TicTacToe/V4/pom.xml                    |  66 +++++
 .../hdm_stuttgart/mi/sd1/tictactoe/Board.java | 271 ++++++++++++++++++
 .../mi/sd1/tictactoe/Helper.java              |  15 +
 .../mi/sd1/tictactoe/Player.java              |  31 ++
 .../mi/sd1/tictactoe/TicTacToe.java           |  64 +++++
 .../V4/src/main/resources/log4j2.xml          |  21 ++
 .../mi/sd1/connectfour/HelperTest.java        |  66 +++++
 .../mi/sd1/connectfour/PerfectMoveTest.java   |  59 ++++
 .../mi/sd1/connectfour/ScoreTest.java         | 130 +++++++++
 10 files changed, 728 insertions(+)
 create mode 100644 P/Sd1/TicTacToe/V4/.gitignore
 create mode 100644 P/Sd1/TicTacToe/V4/pom.xml
 create mode 100644 P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Board.java
 create mode 100644 P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Helper.java
 create mode 100644 P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Player.java
 create mode 100644 P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/TicTacToe.java
 create mode 100644 P/Sd1/TicTacToe/V4/src/main/resources/log4j2.xml
 create mode 100644 P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/HelperTest.java
 create mode 100644 P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/PerfectMoveTest.java
 create mode 100644 P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/ScoreTest.java

diff --git a/P/Sd1/TicTacToe/V4/.gitignore b/P/Sd1/TicTacToe/V4/.gitignore
new file mode 100644
index 000000000..4ef0c0524
--- /dev/null
+++ b/P/Sd1/TicTacToe/V4/.gitignore
@@ -0,0 +1,5 @@
+/target/
+/.settings/
+A1.log
+.classpath
+.project
diff --git a/P/Sd1/TicTacToe/V4/pom.xml b/P/Sd1/TicTacToe/V4/pom.xml
new file mode 100644
index 000000000..6e9ef6fc9
--- /dev/null
+++ b/P/Sd1/TicTacToe/V4/pom.xml
@@ -0,0 +1,66 @@
+<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>
+  
+  <parent>
+    <groupId>de.hdm-stuttgart.mi</groupId>
+    <artifactId>lecturenotes-pom</artifactId>
+    <version>1.0</version>
+    <relativePath>../../../pom.xml</relativePath>
+  </parent>
+
+
+  <groupId>de.hdm-stuttgart.mi.sd1</groupId>
+  <artifactId>tictactoe</artifactId>
+  <version>4.0</version>
+  <packaging>jar</packaging>
+  
+  <name>TicTacToe</name>
+
+  <url>http://www.mi.hdm-stuttgart.de/freedocs</url>
+  
+  <build>
+    <plugins>
+
+        <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.1</version>
+        <configuration>
+          <source>1.8</source>
+          <target>1.8</target>
+        </configuration>
+      </plugin>
+
+    <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>2.10.1</version>
+        <configuration/>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>2.3</version>
+        <configuration>
+          <transformers>
+            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+              <manifestEntries>
+                <Main-Class>de.hdm_stuttgart.mi.sd1.connectfour.App</Main-Class>
+              </manifestEntries>
+            </transformer>
+          </transformers>
+        </configuration>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      
+    </plugins>
+  </build>
+</project>
diff --git a/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Board.java b/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Board.java
new file mode 100644
index 000000000..7d1982065
--- /dev/null
+++ b/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Board.java
@@ -0,0 +1,271 @@
+package de.hdm_stuttgart.mi.sd1.tictactoe;
+
+public class Board {
+
+  static private int clearTerminalLineCount = 20;                        // Scroll down this many lines simulating terminal clear.
+  static private int fieldSize = 3;
+  static private int numberOfFields = fieldSize * fieldSize;             // Each Tic-Tac-Toe board has got 3 x 3 = 9 fields
+  private short numberOfMoves = 0;                                       // Game will be over after a maximum of 9 moves
+
+  private Player currentActivePlayer;                                    // Player about to start next move
+
+  final Player[] board = new Player[numberOfFields];                     // Allocating a one- dimensional array, yet empty.
+
+  public Board(final Player startingPlayer) {
+    currentActivePlayer = startingPlayer; 
+    for (int i = 0; i < numberOfFields; i++) {                          // Initialize board with null values.
+      board[i] = null;
+    }
+  }
+
+  public Board(final Player activePlayer, Player[] initial) {           // For unit testing purpose.
+    currentActivePlayer = activePlayer;
+    for (int i = 0; i < numberOfFields; i++) {                          // Initialize board with null values.
+      board[i] = initial[i];
+      if (null != board[i]) {
+        numberOfMoves++;
+      }
+    }
+  }
+
+  public void nextPerfectMove() {
+    final int[] freeFields = getFreeFields();
+    
+    if (0 == freeFields.length) {
+      return;
+    }
+    
+    int drawOrLooseIndex = freeFields[0];                            // Choose a candidate. If not confirmed, we're bound to loose anyway
+    
+    for (int i = 0; i < freeFields.length; i++) {
+      
+      final int freeFieldIndex = freeFields[i];
+      
+      board[freeFieldIndex] = currentActivePlayer;                    // Set empty field to player.
+      final int score = getScore(
+          board, currentActivePlayer.getOtherPlayer(),
+          Helper.excludeIndex(freeFields, i));
+      
+      if (currentActivePlayer.score == score) {
+        currentActivePlayer = currentActivePlayer.getOtherPlayer();
+        numberOfMoves++;
+        return;                                                       // Leave current field occupied by active player.
+      } else {
+        if (0 == score) {
+          drawOrLooseIndex = freeFieldIndex;                          // Better off than loosing.        
+        }
+      }
+      board[freeFieldIndex] = null;                                   // Reset field to empty state, continue searching.
+    }
+    board[drawOrLooseIndex] = currentActivePlayer;
+    numberOfMoves++;
+    currentActivePlayer = currentActivePlayer.getOtherPlayer();
+  }
+  
+  
+  public int[] getFreeFields() {
+    final int[] freeFields = new int[numberOfFields - numberOfMoves];
+
+    int index = 0;
+    for (int i = 0; i < numberOfFields; i++) {
+      if (null == board[i]) {
+        freeFields[index++] = i;
+      }
+    }
+    return freeFields;
+  }
+
+  public int getScore() {                                               // For unit testing purpose.
+    final int[] freeFields = getFreeFields();
+    return getScore(board, currentActivePlayer, freeFields);
+  }
+
+  private int getScore(final Player[] evalBoard, final Player activePlayer, final int[] freeFields) {
+
+    {
+      final Player winner = getWinner(evalBoard);
+
+      if (null != winner) { 
+        return winner.score;                          // "Winning" end state.
+      } else if (0 == freeFields.length) {
+        return 0;                                     // "Draw" end state: Board completely populated.
+      }
+    }
+
+    boolean drawChildExists = false;
+    for(int i = 0; i < freeFields.length; i++) {
+      final int freeFieldIndex = freeFields[i];
+
+      evalBoard[freeFieldIndex] = activePlayer;       // Set empty field to player.
+      final int score = getScore(
+          evalBoard, activePlayer.getOtherPlayer(),
+          Helper.excludeIndex(freeFields, i));
+      evalBoard[freeFieldIndex] = null;               // Reset field to empty state.
+
+      if (activePlayer.score == score) {              // Maximum or minimum (with respect to active player) has been reached.
+        return activePlayer.score;
+      } else if (0 == score) {
+        drawChildExists = true;                       // Continue searching for better (maximal or minimal) score.
+      }
+    }
+
+    if (drawChildExists) {
+      return 0;                                       // There is at least one "draw" child to choose from.
+    } else {
+      return activePlayer.getOtherPlayer().score;     // All board children score to the active player's enemy
+    }
+  }
+
+  public  Player evaluateWinner(){
+    return getWinner(board);
+  }
+
+  /**
+   * Test whether one of our two players has won the game.
+   * 
+   * @return The winner instance if a winner exists, null otherwise
+   */
+  static public Player getWinner(Player[] evalBoard) {
+
+    if (null != evalBoard[4] && (                                            // Check both diagonals
+        (evalBoard[4] == evalBoard[0] && evalBoard[4] == evalBoard[8]) ||                //
+        (evalBoard[4] == evalBoard[6] && evalBoard[4] == evalBoard[2]))) {               //   x x
+      return evalBoard[4];                                                   //    x
+    }                                                                    //   x x
+
+    for (int i = 0; i < fieldSize; i++) {                                // Check all three columns
+      if (null != evalBoard[i] &&                                            //  +-=                                      
+          evalBoard[i] == evalBoard[i + fieldSize] &&
+          evalBoard[i] == evalBoard[i + 2* fieldSize]) {                         //  +-=
+        return evalBoard[i];                                                 //  +-=
+      }
+    }
+
+    for (int i = 0; i < 2 * fieldSize + 1; i += fieldSize) {             // Check all three rows
+      if (null != evalBoard[i] &&                                            // +++
+          evalBoard[i] == evalBoard[i + 1] && evalBoard[i] == evalBoard[i + 2]) {        // ---
+        return evalBoard[i];                                                 // ===
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Occupy the next field by player {@link #getCurrentActivePlayer()}.
+   * 
+   * Fields are being numbered by:
+   * 
+   *  1|2|3
+   *  -+-+-
+   *  4|5|6
+   *  -+-+-
+   *  7|8|9
+   * 
+   * @param field The field in question
+   *  
+   * @return An error message indication either an occupied field or an index violation.
+   *          null if everything is o.K.
+   */
+  public String nextMove(final int field) {                          
+
+    if (field < 1 || numberOfFields < field) {
+      return "Field index out of range [0 ..." + 
+          numberOfFields + "]";
+    } else {
+      final int fieldIndex = field - 1;                               // User to (computer) nerd point of view
+      final Player current = board[fieldIndex];
+      if (current == null) {
+        board[fieldIndex] = currentActivePlayer;
+        currentActivePlayer = currentActivePlayer.getOtherPlayer();
+        numberOfMoves++;
+        return null;
+      } else {
+        return "Field already occupied by " + current.nickname;
+      }
+    }
+  }
+
+  static public void printNumberingHint() {
+    System.out.println("Numbering scheme:\n");
+    for (int y = 0; y < 3; y++) {
+      for (int x = 0; x < 3; x++) {
+        System.out.print((char)('1' + x + y * fieldSize));
+        if (x < fieldSize - 1) {
+          System.out.print('|');
+        }
+      }
+      if (y < fieldSize - 1) {
+        System.out.println("\n-+-+-");
+      }
+    }
+  }
+
+  /**
+   * Get the player instance which will do the next move. See {@link #nextMove(short)}
+   * 
+   * @return the currently active player.
+   */
+  public Player getCurrentActivePlayer() {
+    return currentActivePlayer;
+  }
+
+  /**
+   * After nine moves all fields will have been occupied.
+   * @return true if all possible moves have been completed, false otherwise.
+   */
+  public boolean allMovesFinished() {
+    return numberOfFields <= numberOfMoves;
+  }
+
+  public void print(boolean simulateClear, boolean printNumberingHints) {
+    print(board, simulateClear, printNumberingHints);
+  }
+
+  /**
+   * Publish the current state to standard output using
+   * ASCII graphics.
+   */
+  static private void print(final Player[] boardState, boolean simulateClear, boolean printNumberingHints) {
+    for (int clear = 0; simulateClear && clear < clearTerminalLineCount; clear++) {
+      System.out.println("\n");
+    }
+
+    System.out.println("\n\nPlayer " + Player.YOU.nickname + "("
+        + Player.YOU.representation + ")" + "\nvs. " + Player.COM.nickname
+        + "(" + Player.COM.representation + ")"  + "          Free fields\n");
+
+    final String tableSeparator = "                  ";
+    for (int x = 0; x < fieldSize; x++) {
+      
+      // Print current values
+      for (int y = 0; y < fieldSize; y++) {
+        final int fieldIndex = y + fieldSize * x;
+        System.out.print(null == boardState[fieldIndex] ? " " : boardState[fieldIndex].representation);
+        if (y < fieldSize - 1) {
+          System.out.print('|'  );
+        } 
+      }
+      if (printNumberingHints) {
+      System.out.print(tableSeparator);
+      
+      // print free field numbering hints.
+      for (int y = 0; y < fieldSize; y++) {
+        final int fieldIndex = y + fieldSize * x;
+        System.out.print(null == boardState[fieldIndex] ? fieldIndex + 1 : // Nerd to user perspective.
+            " ");
+        if (y < fieldSize - 1) {
+          System.out.print('|');
+        }
+      }
+      }
+
+      if (x < fieldSize - 1) {
+        System.out.print("\n-+-+-" + (printNumberingHints ? tableSeparator + "-+-+-" : "") );
+        System.out.println();
+      }
+    }
+  }
+  public Player[] getBoard() {
+    return board.clone();
+  }  
+}
diff --git a/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Helper.java b/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Helper.java
new file mode 100644
index 000000000..025744917
--- /dev/null
+++ b/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Helper.java
@@ -0,0 +1,15 @@
+package de.hdm_stuttgart.mi.sd1.tictactoe;
+
+public class Helper {
+  
+  static public int[] excludeIndex(final int[] values, int excludeIndex) {
+    final int[] ret = new int[values.length - 1];
+    for (int i = 0; i < excludeIndex; i++) {
+      ret[i] = values[i];
+    }
+    for (int i = excludeIndex; i < values.length - 1; i++) {
+      ret[i] = values[i + 1];
+    }
+    return ret;
+  }
+}
diff --git a/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Player.java b/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Player.java
new file mode 100644
index 000000000..bd323a2fb
--- /dev/null
+++ b/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/Player.java
@@ -0,0 +1,31 @@
+package de.hdm_stuttgart.mi.sd1.tictactoe;
+
+public enum Player {
+
+  YOU("You", 'O', 1), COM("Me (computer)", 'X', -1);
+
+  public final String nickname;
+  public final char representation;
+  public int score;
+  private Player other;
+  
+  static {                // For further explanation see
+    YOU.other = COM;      // http://stackoverflow.com/questions/5678309/illegal-forward-reference-and-enums#5678375 
+    COM.other = YOU;
+  }
+  
+  public Player getOtherPlayer() {
+    return other;
+  }
+  
+  Player(final String nickname, final char representation, final int score) {
+    this.nickname = nickname;
+    this.representation = representation;
+    this.score = score;
+  }
+
+  @Override
+  public String toString() {
+    return nickname + ", " + score + ", "+ representation;
+  }
+}
diff --git a/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/TicTacToe.java b/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/TicTacToe.java
new file mode 100644
index 000000000..413b64d06
--- /dev/null
+++ b/P/Sd1/TicTacToe/V4/src/main/java/de/hdm_stuttgart/mi/sd1/tictactoe/TicTacToe.java
@@ -0,0 +1,64 @@
+package de.hdm_stuttgart.mi.sd1.tictactoe;
+
+import java.util.Scanner;
+
+/**
+ * Playing Tic-tac-toe with two players.
+ * 
+ */
+public class TicTacToe {
+
+   /**
+    * @param args
+    *           Unused
+    */
+   public static void main(String[] args) {
+
+      final Scanner scan = new Scanner(System.in);
+
+      Board.printNumberingHint();
+      System.out.println("\n\n");
+      
+      System.out.println("Who is going to start? " + 
+        Player.YOU.ordinal() + " = " + Player.YOU.nickname +
+          ", other = " + Player.COM.nickname);
+      
+      final int firstPlayer = scan.nextShort();
+      
+      final Board board;
+      if (Player.YOU.ordinal() == firstPlayer) {
+        board = new Board(Player.YOU);
+      } else {
+        board = new Board(Player.COM);
+        board.nextPerfectMove();
+      }
+      board.print(true, true);
+      
+      Player winner;
+      do {
+         do {
+            System.out.print("\n\nPlease enter next field's number:");
+            final short nextField = scan.nextShort();
+            final String errorMessage = board.nextMove(nextField);
+            if (null == errorMessage) {
+               break;                            // o.K., quit loop for next move.
+            } else {
+               System.err.println(errorMessage); // Field already occupied?
+            }
+         } while (true);
+         board.nextPerfectMove();
+         board.print(true, !board.allMovesFinished());
+      } while (null == (winner = board.evaluateWinner()) && !board.allMovesFinished());
+
+      if (null == winner) {
+         System.out.println("\n\nGame over: draw");
+      } else {
+        switch(winner) {
+        case YOU: System.out.println("\n\nCongratulations, you won!");break;
+        case COM: System.out.println("\n\nSorry, you lost!");break;
+        }
+      }
+
+      scan.close();
+   }
+}
diff --git a/P/Sd1/TicTacToe/V4/src/main/resources/log4j2.xml b/P/Sd1/TicTacToe/V4/src/main/resources/log4j2.xml
new file mode 100644
index 000000000..52f0a47cb
--- /dev/null
+++ b/P/Sd1/TicTacToe/V4/src/main/resources/log4j2.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration>
+    <Appenders>
+        <File name="A1" fileName="A1.log" append="false">
+            <PatternLayout pattern="%t %-5p %c{2} - %m%n"/>
+        </File>
+        <Console name="STDOUT" target="SYSTEM_OUT">
+            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
+        </Console>
+    </Appenders>
+    <Loggers>
+
+        <!-- You my want to define class or package level per-logger rules -->
+        <Logger name="de.hdm_stuttgart.mi.sd1.connectfour.App" level="debug">
+            <AppenderRef ref="A1"/>
+        </Logger>
+        <Root level="info">
+            <AppenderRef ref="STDOUT"/>
+        </Root>
+    </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/HelperTest.java b/P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/HelperTest.java
new file mode 100644
index 000000000..3b8ef79f6
--- /dev/null
+++ b/P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/HelperTest.java
@@ -0,0 +1,66 @@
+package de.hdm_stuttgart.mi.sd1.connectfour;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import de.hdm_stuttgart.mi.sd1.tictactoe.Helper;
+
+/**
+ * Testing Tic-tac-toe.
+ */
+public class HelperTest {
+  
+  @Test
+  public void testOneField() {
+    final int[] input = {9},
+          result = Helper.excludeIndex(input, 0),
+          expectedResult = {};
+    
+    Assert.assertArrayEquals(expectedResult, result);
+  }
+
+  @Test
+  public void testTwoFields0() {
+    final int[] input = {0, 8},
+          result = Helper.excludeIndex(input, 0),
+          expectedResult = {8};
+    
+    Assert.assertArrayEquals(expectedResult, result);
+  }
+
+  @Test
+  public void testTwoFields1() {
+    final int[] input = {0, 8},
+          result = Helper.excludeIndex(input, 1),
+          expectedResult = {0};
+    
+    Assert.assertArrayEquals(expectedResult, result);
+  }
+
+  @Test
+  public void testArrayFields0() {
+    final int[] input = {1,2,3},
+          result = Helper.excludeIndex(input, 0),
+          expectedResult = {2,3};
+    
+    Assert.assertArrayEquals(expectedResult, result);
+  }
+
+  @Test
+  public void testArrayFields2() {
+    final int[] input = {1,2,3},
+          result = Helper.excludeIndex(input, 1),
+          expectedResult = {1,3};
+    
+    Assert.assertArrayEquals(expectedResult, result);
+  }
+
+  @Test
+  public void testThreeFields3() {
+    final int[] input = {1,2,3},
+          result = Helper.excludeIndex(input, 2),
+          expectedResult = {1,2};
+    
+    Assert.assertArrayEquals(expectedResult, result);
+  }
+}
\ No newline at end of file
diff --git a/P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/PerfectMoveTest.java b/P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/PerfectMoveTest.java
new file mode 100644
index 000000000..05d8167b1
--- /dev/null
+++ b/P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/PerfectMoveTest.java
@@ -0,0 +1,59 @@
+package de.hdm_stuttgart.mi.sd1.connectfour;
+
+import static de.hdm_stuttgart.mi.sd1.tictactoe.Player.YOU;
+import static de.hdm_stuttgart.mi.sd1.tictactoe.Player.COM;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import de.hdm_stuttgart.mi.sd1.tictactoe.Board;
+import de.hdm_stuttgart.mi.sd1.tictactoe.Player;
+/**
+ * Testing Tic-tac-toe.
+ */
+public class PerfectMoveTest {
+
+  @Test
+  public void testWinningMove() {
+
+    final Board board = new Board(
+        COM,                      // active player.
+
+        new Player[] {
+            null,  COM,   YOU,    //  |X|O
+            //                       -+-+-
+            null,  COM,   YOU,    //  |X|O
+            //                       -+-+-
+            null,  null,  null}); //  | |
+
+    board.nextPerfectMove();
+    
+    final Player[] expected = new Player[] {
+        null,  COM,   YOU,    //  |X|O
+        //                       -+-+-
+        null,  COM,   YOU,    //  |X|O
+        //                       -+-+-
+        null,  COM,  null};   //  |X| 
+    
+    Assert.assertArrayEquals(expected, board.getBoard());
+  }
+
+  @Test
+  public void testStartPlayer() {
+
+    final Board board = new Board(YOU);
+
+    board.nextMove(1);
+    board.nextPerfectMove();
+    board.print(false, true);
+    
+    board.nextMove(2);
+    board.print(false, true);
+    
+    board.nextPerfectMove();
+    board.print(false, true);
+  }
+  
+  
+
+}
diff --git a/P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/ScoreTest.java b/P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/ScoreTest.java
new file mode 100644
index 000000000..4cf14dfe9
--- /dev/null
+++ b/P/Sd1/TicTacToe/V4/src/test/java/de/hdm_stuttgart/mi/sd1/connectfour/ScoreTest.java
@@ -0,0 +1,130 @@
+package de.hdm_stuttgart.mi.sd1.connectfour;
+
+import static de.hdm_stuttgart.mi.sd1.tictactoe.Player.YOU;
+import static de.hdm_stuttgart.mi.sd1.tictactoe.Player.COM;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import de.hdm_stuttgart.mi.sd1.tictactoe.Board;
+import de.hdm_stuttgart.mi.sd1.tictactoe.Player;
+/**
+ * Testing Tic-tac-toe.
+ */
+public class ScoreTest {
+
+  @Test
+  public void testEmptyBoard() {
+
+    final Board board = new Board(
+        COM,                      // active player.
+
+        new Player[] {
+            null,  null,  null,   //  | |
+            //                       -+-+-
+            null,  null,  null,   //  | |
+            //                       -+-+-
+            null,  null,  null}); //  | |
+
+    Assert.assertEquals(0, board.getScore());
+  }
+
+  @Test
+  public void testDrawTwoEnd() {
+
+    final Board board = new Board(
+        YOU,                      // active player.
+
+        new Player[] { 
+            YOU,  COM,  COM,      // O|X|X
+            //                       -+-+-
+            COM,  YOU,   YOU,     // X|O|O 
+            //                       -+-+-
+            null, null, COM});    //  | |X
+
+    Assert.assertEquals(0, board.getScore());
+  }
+  
+  @Test
+  public void testDraw1() {
+
+    final Board board = new Board(
+        COM,                      // active player.
+
+        new Player[] {
+            null, null, null,     //  | | 
+            //                       -+-+-
+            null, YOU, null,      //  |O|  
+            //                       -+-+-
+            YOU, null, COM});     // O| |X
+
+    Assert.assertEquals(YOU.score, board.getScore());
+  }
+
+
+  @Test
+  public void testDrawEnd() {
+
+    final Board board = new Board(
+        COM,                      // active player.
+
+        new Player[] { 
+            YOU,  COM,  COM,      // O|X|X
+            //                       -+-+-
+            COM,  YOU,   YOU,     // X|O|O 
+            //                       -+-+-
+            YOU,  null, COM});    // O| |X
+
+    Assert.assertEquals(0, board.getScore());
+  }
+  
+  @Test
+  public void testWinOne1() {
+
+    final Board board = new Board(
+        YOU,                      // active player.
+
+        new Player[] {
+            null, null, null,     //  | | 
+            //                       -+-+-
+            null, YOU, null,      //  |O|  
+            //                       -+-+-
+            YOU,  COM, COM});     // O|X|X
+
+    Assert.assertEquals(YOU.score, board.getScore());
+  }
+  
+
+  
+  @Test
+  public void testWinTwoMoves() {
+
+    final Board board = new Board(
+        COM,                      // active player.
+
+        new Player[] {
+            null, YOU, COM,       //  |O|X
+            //                       -+-+-
+            COM,  YOU, YOU,       // X|O|O 
+            //                       -+-+-
+            null, COM, null});    //  |X|
+
+    Assert.assertEquals(COM.score, board.getScore());
+  }
+  
+  @Test
+  public void testLooseNextMove() {
+
+    final Board board = new Board(
+        COM,                      // active player.
+
+        new Player[] {
+            null,  YOU, YOU,       //  |O|O
+            //                        -+-+-
+            null,  COM, YOU,       //  |X|O 
+            //                        -+-+-
+            COM,  null, null});    // X| |
+
+    Assert.assertEquals(YOU.score, board.getScore());
+  }
+}
-- 
GitLab