Skip to content

Package: TicTacToeStateImpl

TicTacToeStateImpl

nameinstructionbranchcomplexitylinemethod
TicTacToeStateImpl(TicTacToeBoard, TicTacToePlayer, TicTacToePlayer, boolean)
M: 40 C: 46
53%
M: 3 C: 5
63%
M: 3 C: 2
40%
M: 4 C: 9
69%
M: 0 C: 1
100%
TicTacToeStateImpl(TicTacToeStateImpl)
M: 0 C: 30
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
computeNextPlayers()
M: 2 C: 10
83%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 2
67%
M: 0 C: 1
100%
deepCopy()
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
equals(Object)
M: 2 C: 33
94%
M: 1 C: 9
90%
M: 1 C: 5
83%
M: 1 C: 5
83%
M: 0 C: 1
100%
gameOver(TicTacToeFieldState)
M: 12 C: 33
73%
M: 1 C: 3
75%
M: 1 C: 3
75%
M: 2 C: 11
85%
M: 0 C: 1
100%
getBoard()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getCrossesPlayer()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getCurrentPlayer()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getNoughtsPlayer()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getOtherPlayer()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getPlayers()
M: 0 C: 22
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
hashCode()
M: 25 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
isCrossesPlayerCurrent()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
moveCompleted()
M: 0 C: 31
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
nextTurn()
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
toString()
M: 30 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright © 2021 Fachhochschule für die Wirtschaft (FHDW) Hannover
3: *
4: * This file is part of ipspiel22-tictactoe-core.
5: *
6: * ipspiel22-tictactoe-core is free software: you can redistribute it and/or modify it under
7: * the terms of the GNU General Public License as published by the Free Software
8: * Foundation, either version 3 of the License, or (at your option) any later
9: * version.
10: *
11: * ipspiel22-tictactoe-core is distributed in the hope that it will be useful, but WITHOUT
12: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14: * details.
15: *
16: * You should have received a copy of the GNU General Public License along with
17: * ipspiel22-tictactoe-core. If not, see <http://www.gnu.org/licenses/>.
18: */
19: package de.fhdw.gaming.ipspiel22.tictactoe.core.domain.impl;
20:
21: import java.util.Collections;
22: import java.util.LinkedHashMap;
23: import java.util.Map;
24: import java.util.Objects;
25: import java.util.Set;
26:
27: import de.fhdw.gaming.core.domain.GameException;
28: import de.fhdw.gaming.core.domain.PlayerState;
29: import de.fhdw.gaming.ipspiel22.tictactoe.core.domain.TicTacToeBoard;
30: import de.fhdw.gaming.ipspiel22.tictactoe.core.domain.TicTacToeField;
31: import de.fhdw.gaming.ipspiel22.tictactoe.core.domain.TicTacToeFieldState;
32: import de.fhdw.gaming.ipspiel22.tictactoe.core.domain.TicTacToePlayer;
33: import de.fhdw.gaming.ipspiel22.tictactoe.core.domain.TicTacToePosition;
34: import de.fhdw.gaming.ipspiel22.tictactoe.core.domain.TicTacToeRow;
35: import de.fhdw.gaming.ipspiel22.tictactoe.core.domain.TicTacToeState;
36:
37: /**
38: * Implements {@link TicTacToeState}.
39: */
40: @SuppressWarnings("PMD.GodClass")
41: final class TicTacToeStateImpl implements TicTacToeState {
42:
43: /**
44: * The board.
45: */
46: private final TicTacToeBoard board;
47: /**
48: * The player using crosses.
49: */
50: private final TicTacToePlayer crossesPlayer;
51: /**
52: * The player using noughts.
53: */
54: private final TicTacToePlayer noughtsPlayer;
55: /**
56: * The current player.
57: */
58: private TicTacToePlayer currentPlayer;
59:
60: /**
61: * Creates an Tic Tac Toe state.
62: *
63: * @param board The board.
64: * @param crossesPlayer The player using crosses.
65: * @param noughtsPlayer The player using noughts.
66: * @param crossesIsNext {@code true} if the player using crosses is next, else the player using noughts is next.
67: * @throws GameException if the state cannot be created according to the rules of the game.
68: */
69: TicTacToeStateImpl(final TicTacToeBoard board, final TicTacToePlayer crossesPlayer,
70: final TicTacToePlayer noughtsPlayer, final boolean crossesIsNext) throws GameException {
71:
72: this.board = Objects.requireNonNull(board, "board");
73: this.crossesPlayer = Objects.requireNonNull(crossesPlayer, "crossesPlayer");
74: this.noughtsPlayer = Objects.requireNonNull(noughtsPlayer, "noughtsPlayer");
75:• this.currentPlayer = crossesIsNext ? this.crossesPlayer : this.noughtsPlayer;
76:
77:• if (!this.crossesPlayer.isUsingCrosses()) {
78: throw new IllegalArgumentException(String.format("Player %s does not use crosses.", this.crossesPlayer));
79: }
80:• if (this.noughtsPlayer.isUsingCrosses()) {
81: throw new IllegalArgumentException(String.format("Player %s does not use noughts.", this.noughtsPlayer));
82: }
83:• if (this.crossesPlayer.getName().equals(this.noughtsPlayer.getName())) {
84: throw new IllegalArgumentException(
85: String.format("Both players have the same name '%s'.", this.crossesPlayer.getName()));
86: }
87: }
88:
89: /**
90: * Creates an TicTacToe state by copying an existing one.
91: *
92: * @param source The state to copy.
93: */
94: TicTacToeStateImpl(final TicTacToeStateImpl source) {
95: this.board = source.board.deepCopy();
96: this.crossesPlayer = source.crossesPlayer.deepCopy();
97: this.noughtsPlayer = source.noughtsPlayer.deepCopy();
98:• this.currentPlayer = source.isCrossesPlayerCurrent() ? this.crossesPlayer : this.noughtsPlayer;
99: }
100:
101: @Override
102: public String toString() {
103: return String.format(
104: "TicTacToeState[board=\n%s, crossesPlayer=%s, noughtsPlayer=%s, currentPlayer=%s]",
105: this.board,
106: this.crossesPlayer,
107: this.noughtsPlayer,
108:• this.currentPlayer.isUsingCrosses() ? TicTacToeFieldState.CROSS : TicTacToeFieldState.NOUGHT);
109: }
110:
111: @Override
112: public boolean equals(final Object obj) {
113:• if (obj instanceof TicTacToeStateImpl) {
114: final TicTacToeStateImpl other = (TicTacToeStateImpl) obj;
115:• return this.board.equals(other.board) && this.crossesPlayer.equals(other.crossesPlayer)
116:• && this.noughtsPlayer.equals(other.noughtsPlayer)
117:• && this.isCrossesPlayerCurrent() == other.isCrossesPlayerCurrent();
118: }
119: return false;
120: }
121:
122: @Override
123: public int hashCode() {
124: return Objects.hash(this.board, this.crossesPlayer, this.noughtsPlayer, this.isCrossesPlayerCurrent());
125: }
126:
127: @Override
128: public TicTacToeStateImpl deepCopy() {
129: return new TicTacToeStateImpl(this);
130: }
131:
132: @Override
133: public Map<String, TicTacToePlayer> getPlayers() {
134: final Map<String, TicTacToePlayer> result = new LinkedHashMap<>();
135: result.put(this.crossesPlayer.getName(), this.crossesPlayer);
136: result.put(this.noughtsPlayer.getName(), this.noughtsPlayer);
137: return result;
138: }
139:
140: @Override
141: public TicTacToeBoard getBoard() {
142: return this.board;
143: }
144:
145: @Override
146: public TicTacToePlayer getCrossesPlayer() {
147: return this.crossesPlayer;
148: }
149:
150: @Override
151: public TicTacToePlayer getNoughtsPlayer() {
152: return this.noughtsPlayer;
153: }
154:
155: @Override
156: public TicTacToePlayer getCurrentPlayer() {
157: return this.currentPlayer;
158: }
159:
160: @Override
161: public void moveCompleted() {
162: final Set<TicTacToeRow> uniformRows = this.board.getRowsUniformlyMarked();
163:• if (!uniformRows.isEmpty()) {
164: final TicTacToeFieldState rowState = uniformRows.iterator().next().getState().orElseThrow();
165: this.gameOver(rowState);
166: } else {
167: final Map<TicTacToePosition,
168: ? extends TicTacToeField> emptyFields = this.board.getFieldsBeing(TicTacToeFieldState.EMPTY);
169:• if (emptyFields.isEmpty()) {
170: this.gameOver(TicTacToeFieldState.EMPTY);
171: }
172: }
173: }
174:
175: @Override
176: public Set<TicTacToePlayer> computeNextPlayers() {
177:• if (this.currentPlayer.getState().equals(PlayerState.PLAYING)) {
178: return Collections.singleton(this.currentPlayer);
179: }
180: return Collections.emptySet();
181: }
182:
183: @Override
184: public void nextTurn() {
185: this.currentPlayer = this.getOtherPlayer();
186: }
187:
188: /**
189: * Returns the currently inactive player.
190: */
191: private TicTacToePlayer getOtherPlayer() {
192:• if (this.isCrossesPlayerCurrent()) {
193: return this.noughtsPlayer;
194: }
195: return this.crossesPlayer;
196: }
197:
198: /**
199: * Returns {@code true} iff the current player uses crosses.
200: */
201: @SuppressWarnings("PMD.CompareObjectsWithEquals")
202: private boolean isCrossesPlayerCurrent() {
203:• return this.currentPlayer == this.crossesPlayer;
204: }
205:
206: /**
207: * Updates the player states after the game has finished.
208: *
209: * @param rowState The state of some uniformly marked row, or {@link TicTacToeFieldState#EMPTY} if no player has won
210: * the game yet and no empty fields have remained.
211: */
212: private void gameOver(final TicTacToeFieldState rowState) {
213:• switch (rowState) {
214: case CROSS:
215: this.crossesPlayer.setState(PlayerState.WON);
216: this.noughtsPlayer.setState(PlayerState.LOST);
217: break;
218: case NOUGHT:
219: this.crossesPlayer.setState(PlayerState.LOST);
220: this.noughtsPlayer.setState(PlayerState.WON);
221: break;
222: case EMPTY:
223: this.crossesPlayer.setState(PlayerState.DRAW);
224: this.noughtsPlayer.setState(PlayerState.DRAW);
225: break;
226: default:
227: throw new IllegalArgumentException(
228: String.format("TicTacToeState.gameOver() called with state %s.", rowState));
229: }
230: }
231: }