Skip to content

Method: getPlayers()

1: /*
2: * Copyright © 2021-2023 Fachhochschule für die Wirtschaft (FHDW) Hannover
3: *
4: * This file is part of ipspiel24-VierConnects-core.
5: *
6: * ipspiel24-VierConnects-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: * ipspiel24-VierConnects-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: * ipspiel24-VierConnects-core. If not, see <http://www.gnu.org/licenses/>.
18: */
19: package de.fhdw.gaming.ipspiel24.VierConnects.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.ipspiel24.VierConnects.core.domain.VierConnectsBoard;
30: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsField;
31: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsFieldState;
32: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsPlayer;
33: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsPosition;
34: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsRow;
35: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsState;
36:
37: /**
38: * Implements {@link VierConnectsState}.
39: */
40: @SuppressWarnings("PMD.GodClass")
41: final class VierConnectsStateImpl implements VierConnectsState {
42:
43: /**
44: * The board.
45: */
46: private final VierConnectsBoard board;
47:
48: /**
49: * The player using crosses.
50: */
51: private final VierConnectsPlayer crossesPlayer;
52:
53: /**
54: * The player using noughts.
55: */
56: private final VierConnectsPlayer noughtsPlayer;
57:
58: /**
59: * The current player.
60: */
61: private VierConnectsPlayer currentPlayer;
62:
63: /**
64: * Creates an Vier Connects state.
65: *
66: * @param board The board.
67: * @param crossesPlayer The player using crosses.
68: * @param noughtsPlayer The player using noughts.
69: * @param crossesIsNext {@code true} if the player using crosses is next, else the player using noughts is next.
70: * @throws GameException if the state cannot be created according to the rules of the game.
71: */
72: VierConnectsStateImpl(final VierConnectsBoard board, final VierConnectsPlayer crossesPlayer,
73: final VierConnectsPlayer noughtsPlayer, final boolean crossesIsNext) throws GameException {
74:
75: this.board = Objects.requireNonNull(board, "board");
76: this.crossesPlayer = Objects.requireNonNull(crossesPlayer, "crossesPlayer");
77: this.noughtsPlayer = Objects.requireNonNull(noughtsPlayer, "noughtsPlayer");
78: this.currentPlayer = crossesIsNext ? this.crossesPlayer : this.noughtsPlayer;
79:
80: if (!this.crossesPlayer.isUsingCrosses()) {
81: throw new IllegalArgumentException(String.format("Player %s does not use crosses.", this.crossesPlayer));
82: }
83: if (this.noughtsPlayer.isUsingCrosses()) {
84: throw new IllegalArgumentException(String.format("Player %s does not use noughts.", this.noughtsPlayer));
85: }
86: if (this.crossesPlayer.getName().equals(this.noughtsPlayer.getName())) {
87: throw new IllegalArgumentException(
88: String.format("Both players have the same name '%s'.", this.crossesPlayer.getName()));
89: }
90: }
91:
92: /**
93: * Creates an VierConnects state by copying an existing one.
94: *
95: * @param source The state to copy.
96: */
97: VierConnectsStateImpl(final VierConnectsStateImpl source) {
98: this.board = source.board.deepCopy();
99: this.crossesPlayer = source.crossesPlayer.deepCopy();
100: this.noughtsPlayer = source.noughtsPlayer.deepCopy();
101: this.currentPlayer = source.isCrossesPlayerCurrent() ? this.crossesPlayer : this.noughtsPlayer;
102: }
103:
104: @Override
105: public String toString() {
106: return String.format(
107: "VierConnectsState[board=\n%s, crossesPlayer=%s, noughtsPlayer=%s, currentPlayer=%s]",
108: this.board,
109: this.crossesPlayer,
110: this.noughtsPlayer,
111: this.currentPlayer.isUsingCrosses() ? VierConnectsFieldState.CROSS : VierConnectsFieldState.NOUGHT);
112: }
113:
114: @Override
115: public boolean equals(final Object obj) {
116: if (obj instanceof VierConnectsStateImpl) {
117: final VierConnectsStateImpl other = (VierConnectsStateImpl) obj;
118: return this.board.equals(other.board) && this.crossesPlayer.equals(other.crossesPlayer)
119: && this.noughtsPlayer.equals(other.noughtsPlayer)
120: && this.isCrossesPlayerCurrent() == other.isCrossesPlayerCurrent();
121: }
122: return false;
123: }
124:
125: @Override
126: public int hashCode() {
127: return Objects.hash(this.board, this.crossesPlayer, this.noughtsPlayer, this.isCrossesPlayerCurrent());
128: }
129:
130: @Override
131: public VierConnectsStateImpl deepCopy() {
132: return new VierConnectsStateImpl(this);
133: }
134:
135: @Override
136: public Map<String, VierConnectsPlayer> getPlayers() {
137: final Map<String, VierConnectsPlayer> result = new LinkedHashMap<>();
138: result.put(this.crossesPlayer.getName(), this.crossesPlayer);
139: result.put(this.noughtsPlayer.getName(), this.noughtsPlayer);
140: return result;
141: }
142:
143: @Override
144: public VierConnectsBoard getBoard() {
145: return this.board;
146: }
147:
148: @Override
149: public VierConnectsPlayer getCrossesPlayer() {
150: return this.crossesPlayer;
151: }
152:
153: @Override
154: public VierConnectsPlayer getNoughtsPlayer() {
155: return this.noughtsPlayer;
156: }
157:
158: @Override
159: public VierConnectsPlayer getCurrentPlayer() {
160: return this.currentPlayer;
161: }
162:
163:
164: @Override
165: public void moveCompleted() {
166: final Set<VierConnectsRow> winningRows = this.board.getRowsWithFourMarked();
167: if (!winningRows.isEmpty()) {
168: final VierConnectsFieldState rowState = winningRows.iterator().next().getState().orElseThrow();
169: this.gameOver(rowState);
170: } else {
171: final Map<VierConnectsPosition,
172: ? extends VierConnectsField> emptyFields = this.board.getFieldsBeing(VierConnectsFieldState.EMPTY);
173: if (emptyFields.isEmpty()) {
174: this.gameOver(VierConnectsFieldState.EMPTY);
175: }
176: }
177: }
178:
179: @Override
180: public Set<VierConnectsPlayer> computeNextPlayers() {
181: if (this.currentPlayer.getState().equals(PlayerState.PLAYING)) {
182: return Collections.singleton(this.currentPlayer);
183: }
184: return Collections.emptySet();
185: }
186:
187: @Override
188: public void nextTurn() {
189: this.currentPlayer = this.getOtherPlayer();
190: }
191:
192: /**
193: * Returns the currently inactive player.
194: */
195: private VierConnectsPlayer getOtherPlayer() {
196: if (this.isCrossesPlayerCurrent()) {
197: return this.noughtsPlayer;
198: }
199: return this.crossesPlayer;
200: }
201:
202: /**
203: * Returns {@code true} iff the current player uses crosses.
204: */
205: @SuppressWarnings("PMD.CompareObjectsWithEquals")
206: private boolean isCrossesPlayerCurrent() {
207: return this.currentPlayer == this.crossesPlayer;
208: }
209:
210: /**
211: * Updates the player states after the game has finished.
212: *
213: * @param rowState The state of some uniformly marked row, or {@link VierConnectsFieldState#EMPTY} if no player has
214: * won
215: * the game yet and no empty fields have remained.
216: */
217: private void gameOver(final VierConnectsFieldState rowState) {
218: switch (rowState) {
219: case CROSS:
220: this.crossesPlayer.setState(PlayerState.WON);
221: this.noughtsPlayer.setState(PlayerState.LOST);
222: break;
223: case NOUGHT:
224: this.crossesPlayer.setState(PlayerState.LOST);
225: this.noughtsPlayer.setState(PlayerState.WON);
226: break;
227: case EMPTY:
228: this.crossesPlayer.setState(PlayerState.DRAW);
229: this.noughtsPlayer.setState(PlayerState.DRAW);
230: break;
231: default:
232: throw new IllegalArgumentException(
233: String.format("VierConnectsState.gameOver() called with state %s.", rowState));
234: }
235: }
236: }