View Javadoc

1   /*
2    * AI Soccer Project - network gaming environment for AI warriors.
3    * Copyright (C) 2001-2004  Marcin Werla, Pawel Widera
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, you can find it here:
17   * http://www.gnu.org/licenses/gpl.html
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 }