Skip to content

Method: getBoard()

1: package de.fhdw.gaming.ipspiel23.c4.domain.impl;
2:
3: import java.util.Map;
4: import java.util.Optional;
5:
6: import de.fhdw.gaming.ipspiel23.c4.domain.C4Direction;
7: import de.fhdw.gaming.ipspiel23.c4.domain.IC4Board;
8: import de.fhdw.gaming.ipspiel23.c4.domain.IC4Position;
9: import de.fhdw.gaming.ipspiel23.c4.domain.IC4BoardSlim;
10: import de.fhdw.gaming.ipspiel23.c4.domain.IC4Field;
11: import de.fhdw.gaming.ipspiel23.c4.domain.IC4Player;
12:
13: /**
14: * The default implementation of {@link IC4Field}.
15: */
16: public class C4Field implements IC4Field {
17:
18: /**
19: * The parent board that contains this field.
20: */
21: private final C4Board board;
22:
23: /**
24: * The row of this field.
25: */
26: private final int row;
27:
28: /**
29: * The column of this field.
30: */
31: private final int column;
32:
33: /**
34: * The lazily initialized {@link IC4Position} instance that represents the position of this field.
35: */
36: private IC4Position position;
37:
38: /**
39: * Creates a new instance of {@link C4Field}.
40: *
41: * @param board The parent board that contains this field.
42: * @param row The row of this field.
43: * @param column The column of this field.
44: */
45: public C4Field(final C4Board board, final int row, final int column) {
46: this.board = board;
47: this.row = row;
48: this.column = column;
49: }
50:
51: /**
52: * Creates a new instance of {@link C4Field}.
53: *
54: * @param board The parent board that contains this field.
55: * @param position The position of this field.
56: */
57: public C4Field(final C4Board board, final IC4Position position) {
58: this(board, position.getRow(), position.getColumn());
59: this.position = position;
60: }
61:
62: @Override
63: public IC4Board getBoard() {
64: return this.board;
65: }
66:
67: @Override
68: public IC4Position getBoardPosition() {
69: if (this.position == null) {
70: this.position = new C4Position(row, column);
71: }
72: return this.position;
73: }
74:
75: @Override
76: public Optional<IC4Player> getOccupyingPlayer() {
77: final IC4BoardSlim slimBoard = this.board.getInternalBoard();
78: final int token = slimBoard.getTokenUnsafe(this.row, this.column);
79: if (token == slimBoard.emptyToken()) {
80: return Optional.empty();
81: }
82: return Optional.of(slimBoard.getPlayerByToken(token));
83: }
84:
85: @Override
86: public boolean trySetOccupyingPlayer(final IC4Player player, final boolean allowOverride) {
87: final IC4BoardSlim slimBoard = this.board.getInternalBoard();
88: final int token = slimBoard.getTokenUnsafe(this.row, this.column);
89: if (!allowOverride && token != slimBoard.emptyToken()) {
90: return false;
91: }
92: // row + 1 because row 0 is top row
93: final int rowBeneath = this.row + 1;
94: // ensure we don't violate the laws on physics
95: if (slimBoard.isSolidUnsafe(rowBeneath, this.column)) {
96: slimBoard.updateTokenUnsafe(this.row, this.column, player.getToken());
97: return true;
98: }
99: return false;
100: }
101:
102: @Override
103: public boolean hasNeighbor(final C4Direction direction) {
104: final IC4Position neighborPosition = direction.stepFrom(this.getBoardPosition(), 1);
105: return this.board.getInternalBoard().checkBounds(neighborPosition.getRow(), neighborPosition.getColumn());
106: }
107:
108: @Override
109: public IC4Field getNeighbor(final C4Direction direction) {
110: return getNeighborInternal(direction, true);
111: }
112:
113: @Override
114: public Optional<IC4Field> tryGetNeighbor(final C4Direction direction) {
115: final IC4Field neighbor = getNeighborInternal(direction, false);
116: return Optional.ofNullable(neighbor);
117: }
118:
119: /**
120: * Gets the neighbor of this field in the provided direction.
121: *
122: * @param direction The direction to get the neighbor in.
123: * @param throwOob Whether to throw an {@link IndexOutOfBoundsException} if the neighbor is
124: * out of bounds, or to return null.
125: * @return The neighbor of this field in the provided direction, or null if the neighbor is
126: * out of bounds and throwOob is false.
127: */
128: private IC4Field getNeighborInternal(final C4Direction direction, final boolean throwOob) {
129: final IC4Position neighborPosition = direction.stepFrom(this.getBoardPosition(), 1);
130: final Map<IC4Position, IC4Field> fieldCache = this.board.getFieldCache();
131: IC4Field neighbor = fieldCache.get(neighborPosition);
132: if (neighbor != null) {
133: return neighbor;
134: }
135:
136: if (!this.board.checkBounds(neighborPosition.getRow(), neighborPosition.getColumn())) {
137: if (throwOob) {
138: throw new IndexOutOfBoundsException("The provided direction violates the bounds of the game board.");
139: }
140: return null;
141: }
142: neighbor = new C4Field(board, neighborPosition);
143: fieldCache.put(neighborPosition, neighbor);
144: return neighbor;
145: }
146:
147: @Override
148: public boolean equals(final Object obj) {
149: if (obj == null) {
150: return false;
151: }
152: if (!(obj instanceof IC4Field)) {
153: return false;
154: }
155: final IC4Field other = (IC4Field) obj;
156: return this.getBoardPosition().equals(other.getBoardPosition())
157: && this.getBoard().equals(other.getBoard());
158: }
159:
160: @Override
161: public int hashCode() {
162: int hash = 7;
163: hash = hash * 31 + this.getBoardPosition().hashCode();
164: hash = hash * 31 + this.getBoard().hashCode();
165: return hash;
166: }
167:
168: @Override
169: public String toString() {
170: final StringBuilder sb = new StringBuilder(32);
171: sb.append("C4Field[player=").append(this.getOccupyingPlayer().map(IC4Player::getName).orElse("empty"))
172: .append(", position=").append(this.getBoardPosition())
173: .append(']');
174: return sb.toString();
175: }
176:
177: @Override
178: public IC4Field deepCopy() {
179: return new C4Field(this.board, this.row, this.column);
180: }
181: }