1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package aigames.soccer.field;
21
22 import aigames.soccer.InvalidMoveException;
23 import aigames.soccer.Move;
24
25 import aigames.soccer.field.constructor.Constructor;
26
27 import org.apache.log4j.Logger;
28
29 import java.awt.Point;
30
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.Iterator;
36 import java.util.Map;
37
38
39 /***
40 * @version $Id: BasicGameField.java,v 1.10 2004/05/08 21:55:25 mwerla Exp $
41 */
42 public class BasicGameField implements GameField {
43 private static Logger logger = Logger.getLogger(BasicGameField.class);
44 private Point currentPosition;
45 private FieldPoint[][] field;
46 private Map summaryMoveLengthMap = Collections.synchronizedMap(new HashMap());
47 private Map noOfMovesMap = Collections.synchronizedMap(new HashMap());
48 private Constructor fieldConstructor;
49
50 /***
51 * Class contructor which uses given field constructor to create new field.
52 * @param fieldConstructor Field constructor used to create new field.
53 */
54 public BasicGameField(Constructor fieldConstructor) {
55 this.fieldConstructor = fieldConstructor;
56 }
57
58 /***
59 * @see aigames.soccer.field.GameField#makeMove(Move, int)
60 */
61 public void makeMove(Move move, int color) throws InvalidMoveException {
62 Point currentPoint = getCurrentPosition();
63
64 Collection steps = move.getSteps();
65 boolean isMovePossible = true;
66
67 for (Iterator iter = steps.iterator(); iter.hasNext();) {
68 if (isGameOver()) {
69 throw new InvalidMoveException("Game is over!");
70 }
71
72 int edge = ((Integer) iter.next()).intValue();
73 logger.debug("Trying to make move " + edge);
74
75 if (!isMovePossible) {
76 throw new InvalidMoveException("Move too long!");
77 }
78
79 Point nextPoint = getSecondPoint(currentPoint, edge);
80 FieldPoint pointToCheck = field[currentPoint.x][currentPoint.y];
81 int edgeToCheck = edge;
82
83 if (edge > 4) {
84 try {
85 pointToCheck = field[nextPoint.x][nextPoint.y];
86 } catch (ArrayIndexOutOfBoundsException e) {
87 throw new InvalidMoveException("There is no edge!");
88 }
89
90 edgeToCheck = edge - 4;
91 }
92
93 if (pointToCheck.getEdgeColor(edgeToCheck) != FieldPoint.BLANK_EDGE) {
94 throw new InvalidMoveException(
95 "There is no edge or edge was visited");
96 }
97
98 pointToCheck.setEdgeColor(edgeToCheck, color);
99
100 isMovePossible = wasNeighbourPointVisited(nextPoint);
101
102 currentPoint = nextPoint;
103 }
104
105 currentPosition = currentPoint;
106
107 if (isMovePossible && !isGameOver()) {
108 throw new InvalidMoveException("Move too short!");
109 }
110
111 increaseIntegerMap(noOfMovesMap, color, 1);
112 increaseIntegerMap(summaryMoveLengthMap, color, move.getSteps().size());
113 }
114
115 private void increaseIntegerMap(Map integerMap, int color, int i) {
116 Integer valueInt = (Integer) integerMap.get(new Integer(color));
117 int value = 0;
118
119 if (valueInt != null) {
120 value = valueInt.intValue();
121 }
122
123 value += i;
124 integerMap.put(new Integer(color), new Integer(value));
125 }
126
127 /***
128 * @see aigames.soccer.field.GameField#isDeadLock()
129 */
130 public boolean isDeadLock() {
131 return isDeadLock(currentPosition, new ArrayList());
132 }
133
134 private boolean isDeadLock(Point point, Collection visitedPoints) {
135 if (visitedPoints.contains(point)) {
136 return true;
137 }
138
139 visitedPoints.add(point);
140
141 logger.debug("Checking deadlock in point (" + point.x + "," + point.y +
142 ")");
143
144 boolean isDeadLock = wasPointVisited(point);
145
146 if (isDeadLock) {
147 FieldPoint pointToCheck = field[point.x][point.y];
148
149 for (int i = 1; i <= 4; i++) {
150 if (pointToCheck.getEdgeColor(i) == FieldPoint.BLANK_EDGE) {
151 isDeadLock = isDeadLock(getSecondPoint(point, i),
152 visitedPoints);
153
154 if (!isDeadLock) {
155 break;
156 }
157 }
158 }
159
160 if (isDeadLock) {
161 for (int i = 5; i <= 8; i++) {
162 Point secondPoint = getSecondPoint(point, i);
163
164 if ((secondPoint.x >= 0) && (secondPoint.y >= 0)) {
165 pointToCheck = field[secondPoint.x][secondPoint.y];
166
167 if (pointToCheck.getEdgeColor(i - 4) == FieldPoint.BLANK_EDGE) {
168 isDeadLock = isDeadLock(secondPoint, visitedPoints);
169
170 if (!isDeadLock) {
171 break;
172 }
173 }
174 }
175 }
176 }
177 }
178
179 return isDeadLock;
180 }
181
182 private boolean wasNeighbourPointVisited(Point point) {
183 int visCount = 0;
184
185 FieldPoint pointToCheck = field[point.x][point.y];
186
187 for (int i = 1; i <= 4; i++) {
188 if (pointToCheck.getEdgeColor(i) != FieldPoint.BLANK_EDGE) {
189 visCount++;
190 }
191 }
192
193 for (int i = 5; i <= 8; i++) {
194 if (checkPoint(point, i)) {
195 visCount++;
196 }
197 }
198
199 return visCount > 1;
200 }
201
202 private boolean checkPoint(Point point, int direction) {
203 boolean result = false;
204 Point secondPoint = getSecondPoint(point, direction);
205
206 if ((secondPoint.x >= 0) && (secondPoint.y >= 0)) {
207 FieldPoint pointToCheck = field[secondPoint.x][secondPoint.y];
208
209 if (pointToCheck.getEdgeColor(direction - 4) != FieldPoint.BLANK_EDGE) {
210 result = true;
211 }
212 } else {
213 result = true;
214 }
215
216 return result;
217 }
218
219 private boolean wasPointVisited(Point point) {
220 boolean visited = false;
221
222 FieldPoint pointToCheck = field[point.x][point.y];
223
224 for (int i = 1; i <= 4; i++) {
225 if (pointToCheck.getEdgeColor(i) != FieldPoint.BLANK_EDGE) {
226 visited = true;
227
228 break;
229 }
230 }
231
232 if (!visited) {
233 for (int i = 5; i <= 8; i++) {
234 visited = checkPoint(point, i);
235
236 if (visited) {
237 break;
238 }
239 }
240 }
241
242 return visited;
243 }
244
245 private Point getSecondPoint(Point currentPoint, int step) {
246 int[] translation = Move.getTranslation(new Integer(step));
247 Point newPoint = ((Point) currentPoint.clone());
248 newPoint.translate(translation[0], translation[1]);
249
250 return newPoint;
251 }
252
253 /***
254 * @see aigames.soccer.field.GameField#getCurrentPosition()
255 */
256 public Point getCurrentPosition() {
257 return currentPosition;
258 }
259
260 /***
261 * @see aigames.soccer.field.GameField#startGame()
262 */
263 public void startGame() {
264 field = fieldConstructor.getNewField();
265 currentPosition = fieldConstructor.getStartingPosition();
266 }
267
268 /***
269 * @see aigames.soccer.field.GameField#isGoal()
270 */
271 public int isGoal() {
272 return fieldConstructor.isGoalPosition(currentPosition);
273 }
274
275 /***
276 * @see aigames.soccer.field.GameField#isGameOver()
277 */
278 public boolean isGameOver() {
279 return fieldConstructor.isGameOverPosition(currentPosition) ||
280 isDeadLock();
281 }
282
283 /***
284 * @see aigames.soccer.field.GameField#getNumberOfMoves(int)
285 */
286 public int getNumberOfMoves(int color) {
287 Integer number = (Integer) noOfMovesMap.get(new Integer(color));
288
289 return (number == null) ? 0 : number.intValue();
290 }
291
292 /***
293 * @see aigames.soccer.field.GameField#getAvgMoveLength(int)
294 */
295 public float getAvgMoveLength(int color) {
296 int numberOfMoves = getNumberOfMoves(color);
297
298 if (numberOfMoves == 0) {
299 numberOfMoves = 1;
300 }
301
302 Integer lengthInt = (Integer) summaryMoveLengthMap.get(new Integer(
303 color));
304 int length = 0;
305
306 if (lengthInt != null) {
307 length = lengthInt.intValue();
308 }
309
310 return length / numberOfMoves;
311 }
312
313 /***
314 * @see aigames.soccer.field.GameField#getFieldPoint(int, int)
315 */
316 public FieldPoint getFieldPoint(int x, int y) {
317 return field[x][y];
318 }
319
320 /***
321 * @see aigames.soccer.field.GameField#getMaximumXIndex()
322 */
323 public int getMaximumXIndex() {
324 return field.length - 1;
325 }
326
327 /***
328 * @see aigames.soccer.field.GameField#getMaximumYIndex()
329 */
330 public int getMaximumYIndex() {
331 if (field.length > 0) {
332 return field[0].length - 1;
333 } else {
334 return 0;
335 }
336 }
337 }