Skip to contentMethod: evaluateState(TicTacToeState)
      1: package de.fhdw.gaming.ipspiel23.tictactoe.core.evaluation;
2: 
3: import java.util.Optional;
4: 
5: import de.fhdw.gaming.ipspiel23.tictactoe.core.domain.TicTacToeField;
6: import de.fhdw.gaming.ipspiel23.tictactoe.core.domain.TicTacToeFieldState;
7: import de.fhdw.gaming.ipspiel23.tictactoe.core.domain.TicTacToePosition;
8: import de.fhdw.gaming.ipspiel23.tictactoe.core.domain.TicTacToeState;
9: 
10: /**
11:  * A simple evaluation strategy for evaluating the state of a Tic-Tac-Toe game.
12:  * This strategy assigns scores to different game states based on the arrangement of marks on the board.
13:  * 
14:  * The evaluation score is determined by counting the number of marks in each row, column, and diagonal.
15:  * A higher score indicates a more favorable state for the current player.
16:  * 
17:  * The evaluation scores are predefined and can be adjusted by modifying the scoreLine() method.
18:  * 
19:  * @see IEvaluationStrategy
20:  * @see TicTacToeState
21:  *
22:  */
23: public class SimpleEvaluationStrategy implements IEvaluationStrategy {
24: 
25:     /**
26:      * Evaluates the given Tic-Tac-Toe game state using the simple evaluation strategy.
27:      * The evaluation score is determined by counting the number of marks in each 
28:      * row, column, and diagonal,
29:      * and assigning predefined scores based on the counts.
30:      * Too complex, but not easily simplifyable. Warning suppressed.
31:      * 
32:      * @param state The Tic-Tac-Toe game state to be evaluated.
33:      * @return An optional containing the evaluation score as an integer value.
34:      */
35:     @Override
36:     @SuppressWarnings({ "checkstyle:CyclomaticComplexity", "PMD.CyclomaticComplexity",
37:         "PMD.CognitiveComplexity" })
38:     public Optional<Integer> evaluateState(final TicTacToeState state) {
39:           int rowSum;
40:           int colSum;
41:           int diagSum1;
42:           int diagSum2;
43:           int score = 0;
44: 
45:           final int boardSize = state.getBoard().getSize();
46:•          for (int i = 0; i < boardSize; i++) {
47:                rowSum = 0;
48:                colSum = 0;
49:•               for (int j = 0; j < boardSize; j++) {
50:                     final TicTacToeField rField = state.getBoard().getFieldAt(TicTacToePosition.of(i, j));
51:                     final TicTacToeField cField = state.getBoard().getFieldAt(TicTacToePosition.of(j, i));
52: 
53:•                    if (rField.getState().equals(TicTacToeFieldState.CROSS)) {
54:                          rowSum += 1;
55:•                    } else if (rField.getState().equals(TicTacToeFieldState.NOUGHT)) {
56:                          rowSum -= 1;
57:                     }
58: 
59:•                    if (cField.getState().equals(TicTacToeFieldState.CROSS)) {
60:                          colSum += 1;
61:•                    } else if (cField.getState().equals(TicTacToeFieldState.NOUGHT)) {
62:                          colSum -= 1;
63:                     }
64:                     score += scoreLine(rowSum, boardSize);
65:                     score += scoreLine(colSum, boardSize);
66: 
67:                }
68: 
69:           }
70: 
71:           diagSum1 = 0;
72:           diagSum2 = 0;
73: 
74:•          for (int i = 0; i < boardSize; i++) {
75: 
76:                final TicTacToeField dAscField = state.getBoard().getFieldAt(TicTacToePosition.of(i, i));
77:                final TicTacToeField dDescField = state.getBoard().
78:                          getFieldAt(TicTacToePosition.of(i, boardSize - i - 1));
79: 
80:•               if (dAscField.getState().equals(TicTacToeFieldState.CROSS)) {
81:                     diagSum1 += 1;
82:•               } else if (dAscField.getState().equals(TicTacToeFieldState.NOUGHT)) {
83:                     diagSum1 -= 1;
84:                }
85:•               if (dDescField.getState().equals(TicTacToeFieldState.CROSS)) {
86:                     diagSum2 += 1;
87:•               } else if (dDescField.getState().equals(TicTacToeFieldState.NOUGHT)) {
88:                     diagSum2 -= 1;
89:                }
90: 
91:           }
92:           score += scoreLine(diagSum1, boardSize);
93:           score += scoreLine(diagSum2, boardSize);
94: 
95:                return Optional.of(score);
96:           
97:      }
98: 
99:     /**
100:      * Determines the score for a line based on the number of marks and the board size.
101:      * The predefined scores are as follows:
102:      * - If the line has all marks of the current player: 100 (winning state)
103:      * - If the line has all marks of the opponent player: -100 (losing state)
104:      * - If the line has one mark less than the board size 
105:      * and all other marks are of the current player: 10 (advantage state)
106:      * - If the line has one mark less than the board size 
107:      * and all other marks are of the opponent player: -10 (disadvantage state)
108:      * - Otherwise: 0 (neutral state)
109:      * 
110:      * @param lineSum The sum of marks in the line.
111:      * @param boardSize The size of the game board.
112:      * @return The score for the line.
113:      */
114:      private int scoreLine(final int lineSum, final int boardSize) {
115:           if (lineSum == boardSize) {
116:                return 100;
117:           }
118:           if (lineSum == -boardSize) {
119:                return -100;
120:           }
121:           if (lineSum == boardSize - 1) {
122:                return 10;
123:           }
124:           if (lineSum == -boardSize + 1) {
125:                return -10;
126:           }
127:           return 0;
128:      }
129: }