Skip to content

Method: getBoard()

1: package de.fhdw.gaming.ipspiel21.viergewinnt.core.domain.impl;
2:
3: import java.util.ArrayList;
4: import java.util.Collections;
5: import java.util.LinkedHashMap;
6: import java.util.List;
7: import java.util.Map;
8: import java.util.Objects;
9: import java.util.Set;
10:
11: import de.fhdw.gaming.core.domain.GameException;
12: import de.fhdw.gaming.core.domain.PlayerState;
13: import de.fhdw.gaming.ipspiel21.viergewinnt.core.domain.VierGewinntBoard;
14: import de.fhdw.gaming.ipspiel21.viergewinnt.core.domain.VierGewinntDirection;
15: import de.fhdw.gaming.ipspiel21.viergewinnt.core.domain.VierGewinntField;
16: import de.fhdw.gaming.ipspiel21.viergewinnt.core.domain.VierGewinntFieldState;
17: import de.fhdw.gaming.ipspiel21.viergewinnt.core.domain.VierGewinntPlayer;
18: import de.fhdw.gaming.ipspiel21.viergewinnt.core.domain.VierGewinntPlayerBuilder;
19: import de.fhdw.gaming.ipspiel21.viergewinnt.core.domain.VierGewinntState;
20: import de.fhdw.gaming.ipspiel21.viergewinnt.core.domain.moves.VierGewinntMove;
21:
22: /**
23: * The Implementation of a VierGewinntState.
24: *
25: * @author Robby Rabbitman
26: *
27: */
28: public class VierGewinntStateImpl implements VierGewinntState {
29: /**
30: * 4 in row.
31: *
32: */
33: private static final Integer WIN_CONDITION = 4;
34:
35: /**
36: * The board.
37: */
38: private final VierGewinntBoard board;
39: /**
40: * The player using yellow.
41: */
42: private final VierGewinntPlayer yellowPlayer;
43: /**
44: * The player using red.
45: */
46: private final VierGewinntPlayer redPlayer;
47: /**
48: * The current player.
49: */
50: private VierGewinntPlayer currentPlayer;
51: /**
52: * The states of the players.
53: */
54: private final Map<String, PlayerState> playerStates;
55: /**
56: * The outcomes of the players.
57: */
58: private final Map<String, Double> playerOutcomes;
59:
60: /**
61: * .
62: *
63: */
64: private Boolean gameOver;
65:
66: /**
67: * The Constructor.
68: *
69: * @param board
70: * @param yellowPlayer
71: * @param redPlayer
72: * @param currentPlayer
73: * @param playerStates
74: * @param playerOutcomes
75: */
76: public VierGewinntStateImpl(final VierGewinntBoard board, final VierGewinntPlayer yellowPlayer,
77: final VierGewinntPlayer redPlayer, final VierGewinntPlayer currentPlayer,
78: final Map<String, PlayerState> playerStates, final Map<String, Double> playerOutcomes) {
79: super();
80: this.board = board;
81: this.gameOver = false;
82: this.yellowPlayer = yellowPlayer;
83: this.redPlayer = redPlayer;
84: this.currentPlayer = currentPlayer;
85: this.playerStates = playerStates;
86: this.playerOutcomes = playerOutcomes;
87: }
88:
89: /**
90: * Creates an VierGewinnt state by copying an existing one.
91: *
92: * @param source The state to copy.
93: */
94: VierGewinntStateImpl(final VierGewinntStateImpl source) {
95: this.board = source.getBoard().deepCopy();
96: this.yellowPlayer = source.yellowPlayer.deepCopy(this);
97: this.redPlayer = source.redPlayer.deepCopy(this);
98: this.currentPlayer = source.isYellowPlayerCurrent() ? this.yellowPlayer : this.redPlayer;
99: this.playerOutcomes = new LinkedHashMap<>(source.playerOutcomes);
100: this.playerStates = new LinkedHashMap<>();
101: this.playerStates.put(this.redPlayer.getName(), source.playerStates.get(this.redPlayer.getName()));
102: this.playerStates.put(this.yellowPlayer.getName(), source.playerStates.get(this.yellowPlayer.getName()));
103: this.gameOver = source.gameOver;
104: }
105:
106: /**
107: * .
108: *
109: * @param board
110: * @param player1builder
111: * @param player2builder
112: * @throws GameException
113: */
114: public VierGewinntStateImpl(final VierGewinntBoardImpl board, final VierGewinntPlayerBuilder player1builder,
115: final VierGewinntPlayerBuilder player2builder) throws GameException {
116: this.board = Objects.requireNonNull(board, "board");
117: this.yellowPlayer = Objects.requireNonNull(player1builder, "crossesPlayerBuilder").build(this);
118: this.redPlayer = Objects.requireNonNull(player2builder, "noughtsPlayerBuilder").build(this);
119: this.currentPlayer = this.yellowPlayer;
120: this.playerOutcomes = new LinkedHashMap<>();
121:
122: this.gameOver = false;
123: this.playerStates = new LinkedHashMap<>();
124: this.playerStates.put(this.yellowPlayer.getName(), PlayerState.PLAYING);
125: this.playerStates.put(this.redPlayer.getName(), PlayerState.PLAYING);
126:
127: if (!this.yellowPlayer.isUsingYellow()) {
128: throw new IllegalArgumentException(String.format("Player %s does not use yellow.", this.yellowPlayer));
129: }
130: if (this.redPlayer.isUsingYellow()) {
131: throw new IllegalArgumentException(String.format("Player %s does not use red.", this.redPlayer));
132: }
133: if (this.yellowPlayer.getName().equals(this.redPlayer.getName())) {
134: throw new IllegalArgumentException(
135: String.format("Both players have the same name '%s'.", this.yellowPlayer.getName()));
136: }
137: }
138:
139: @Override
140: public Map<String, VierGewinntPlayer> getPlayers() {
141: return Map.ofEntries(Map.entry(this.getYellowPlayer().getName(), this.getYellowPlayer()),
142: Map.entry(this.getRedPlayer().getName(), this.getRedPlayer()));
143: }
144:
145: @Override
146: public PlayerState getPlayerState(final String playerName) throws IllegalArgumentException {
147: final PlayerState playerState = this.playerStates.get(playerName);
148: if (playerState != null) {
149: return playerState;
150: } else {
151: throw new IllegalArgumentException(String.format("Unknown player %s.", playerName));
152: }
153: }
154:
155: @Override
156: public void setPlayerState(final String playerName, final PlayerState newState)
157: throws IllegalArgumentException {
158: if (this.playerStates.containsKey(playerName)) {
159: this.playerStates.put(playerName, newState);
160: if (newState.equals(PlayerState.PLAYING)) {
161: this.playerOutcomes.remove(playerName);
162: }
163: } else {
164: throw new IllegalArgumentException(String.format("Unknown player %s.", playerName));
165: }
166: }
167:
168: @Override
169: public void setPlayerOutcome(final String playerName, final double newOutcome)
170: throws IllegalArgumentException {
171: if (this.getPlayerState(playerName).equals(PlayerState.PLAYING)) {
172: throw new IllegalArgumentException(String.format("Cannot set outcome for player %s.", playerName));
173: } else {
174: this.playerOutcomes.put(playerName, newOutcome);
175: }
176: }
177:
178: @Override
179: public Set<VierGewinntPlayer> computeNextPlayers() {
180: if (this.gameOver) {
181: return Set.of();
182: } else {
183: return Set.of(this.currentPlayer);
184: }
185: }
186:
187: @Override
188: public void nextTurn() {
189: this.currentPlayer = this.getOtherPlayer();
190: }
191:
192: @Override
193: public VierGewinntState deepCopy() {
194: return new VierGewinntStateImpl(this);
195: }
196:
197: @Override
198: public VierGewinntBoard getBoard() {
199: return this.board;
200: }
201:
202: @Override
203: public VierGewinntPlayer getYellowPlayer() {
204: return this.yellowPlayer;
205: }
206:
207: @Override
208: public VierGewinntPlayer getRedPlayer() {
209: return this.redPlayer;
210: }
211:
212: @Override
213: public VierGewinntPlayer getCurrentPlayer() {
214: return this.currentPlayer;
215: }
216:
217: @Override
218: public void moveCompleted(final VierGewinntMove move) {
219: // check if draw
220: final boolean draw = this.board.getFieldsBeing(VierGewinntFieldState.EMPTY).size() == 0;
221: if (draw) {
222: this.gameOver = true;
223: this.setPlayerState(this.currentPlayer.getName(), PlayerState.DRAW);
224: this.setPlayerState(this.getOtherPlayer().getName(), PlayerState.DRAW);
225: } else {
226: // check if current player won
227: final boolean currentPlayerWon = this
228: .getRows(this.getBoard().getFieldAt(move.getPosition()), VierGewinntStateImpl.WIN_CONDITION)
229: .stream().map(row -> this.checkGameOver(row, this.currentPlayer.getPlayerMark(),
230: VierGewinntStateImpl.WIN_CONDITION))
231: .anyMatch(gameover -> gameover.equals(true));
232: if (currentPlayerWon) {
233: this.gameOver = true;
234: this.setPlayerState(this.currentPlayer.getName(), PlayerState.WON);
235: this.setPlayerState(this.getOtherPlayer().getName(), PlayerState.LOST);
236: }
237: }
238: }
239:
240: /**
241: * Checks if a game is over or not.
242: *
243: * @param row
244: * @param state
245: * @param length
246: * @return
247: */
248: private Boolean checkGameOver(final List<VierGewinntField> row, final VierGewinntFieldState state,
249: final Integer length) {
250: boolean won = false;
251: for (int i = 0; i <= row.size() - length; i++) {
252: won = true;
253: for (int j = 0; j < length; j++) {
254: won = won && row.get(j + i).getState().name().equals(state.name());
255: }
256: if (won) {
257: return won;
258: }
259: }
260: return won;
261: }
262:
263: /**
264: * Return a nested list of the rows of a VierGewinntGame.
265: *
266: * @param field
267: * @param radius
268: * @return
269: */
270: private List<List<VierGewinntField>> getRows(final VierGewinntField field, final Integer radius) {
271: final List<List<VierGewinntField>> rows = new ArrayList<>();
272: rows.add(this.getRowsHelperConcat(this.getRowsHelper(field, radius, VierGewinntDirection.NORTHWEST), field,
273: this.getRowsHelper(field, radius, VierGewinntDirection.SOUTHEAST)));
274: rows.add(this.getRowsHelperConcat(this.getRowsHelper(field, radius, VierGewinntDirection.NORTHEAST), field,
275: this.getRowsHelper(field, radius, VierGewinntDirection.SOUTHWEST)));
276: rows.add(this.getRowsHelperConcat(this.getRowsHelper(field, radius, VierGewinntDirection.NORTH), field,
277: this.getRowsHelper(field, radius, VierGewinntDirection.SOUTH)));
278: rows.add(this.getRowsHelperConcat(this.getRowsHelper(field, radius, VierGewinntDirection.WEST), field,
279: this.getRowsHelper(field, radius, VierGewinntDirection.EAST)));
280:
281: return rows;
282: }
283:
284: /**
285: * Concat the return of the getRowsHelperfunction to a nested List.
286: *
287: * @param list1
288: * @param field
289: * @param list2
290: * @return
291: */
292: private List<VierGewinntField> getRowsHelperConcat(final List<VierGewinntField> list1,
293: final VierGewinntField field, final List<VierGewinntField> list2) {
294: final List<VierGewinntField> concat = new ArrayList<>();
295: concat.addAll(list1);
296: Collections.reverse(concat);
297: concat.add(field);
298: concat.addAll(list2);
299: return concat;
300:
301: }
302:
303: /**
304: * Helper to build the nested rows for a VierGewinntGame.
305: *
306: * @param field
307: * @param radius
308: * @param direction
309: * @return
310: */
311: private List<VierGewinntField> getRowsHelper(final VierGewinntField field, final Integer radius,
312: final VierGewinntDirection direction) {
313: final List<VierGewinntField> out = new ArrayList<>();
314: VierGewinntField currentField = field;
315: for (int i = 0; i < radius - 1; i++) {
316: if (currentField.hasNeighbour(direction)) {
317: currentField = currentField.getNeighbour(direction);
318: out.add(currentField);
319: } else {
320: return out;
321: }
322: }
323: return out;
324: }
325:
326: /**
327: * Returns the currently inactive player.
328: */
329: private VierGewinntPlayer getOtherPlayer() {
330: if (this.isYellowPlayerCurrent()) {
331: return this.redPlayer;
332: } else {
333: return this.yellowPlayer;
334: }
335: }
336:
337: /**
338: * Return if the Yellow Player is current.
339: *
340: * @return
341: */
342: private boolean isYellowPlayerCurrent() {
343: return this.currentPlayer.equals(this.yellowPlayer);
344: }
345:
346: }