helpful progress reporting
[IRC.git] / Robust / src / Benchmarks / MMG / Java / Ghost.java
1 public class Ghost {
2     
3     public int m_locX;
4     public int m_locY;
5     public int m_index;
6     public int m_target;
7     public int m_direction;  // 0:still, 1:up, 2:down, 3:left, 4:right
8     int m_dx;
9     int m_dy;
10     Map m_map;
11     
12     public Ghost(int x, int y, Map map) {
13         this.m_locX = x;
14         this.m_locY = y;
15         this.m_dx = this.m_dy = 0;
16         this.m_index = -1;
17         this.m_target = -1;
18         this.m_direction = 0;
19         this.m_map = map;
20     }
21     
22     // 0:still, 1:up, 2:down, 3:left, 4:right
23     public void tryMove() {
24         //System.printString("step 1\n");
25         // reset the target
26         this.m_target = -1;
27         // find the shortest possible way to the chosen target
28         setNextDirection();
29     }
30     
31     private void setNextDirection() {
32         // current position of the ghost
33         int start = this.m_locY * this.m_map.m_nrofblocks + this.m_locX;
34         boolean set = false;
35         Vector cuts = new Vector();
36         int tmptarget = 0;
37         int tmpdx = 0;
38         int tmpdy = 0;
39         int tmpdirection = 0;
40         boolean first = true;
41         while(!set) {
42             int parents[] = new int[this.m_map.m_nrofblocks * this.m_map.m_nrofblocks + 1];
43             for(int i = 0; i < parents.length; i++) {
44                 parents[i] = -1;
45             }
46             if(!BFS(start, parents, cuts)) {
47                 this.m_target = tmptarget;
48                 this.m_dx = tmpdx;
49                 this.m_dy = tmpdy;
50                 this.m_map.m_ghostdirections[this.m_index] = this.m_direction = tmpdirection;
51                 set = true;
52                 //System.printString("Use first choice: (" + this.m_dx + ", " + this.m_dy + ")\n");
53             } else {
54                 // Reversely go over the parents array to find the next node to reach
55                 int index = this.m_map.m_pacMenY[this.m_target] * this.m_map.m_nrofblocks + this.m_map.m_pacMenX[this.m_target];
56                 int steps = parents[parents.length - 1];
57                 if(steps == 0) {
58                     // already caught one pacman, stay still
59                     this.m_dx = this.m_dy = 0;
60                     this.m_map.m_ghostdirections[this.m_index] = this.m_direction = 0;
61                     //System.printString("Stay still\n");
62                     set = true;
63                 } else {
64                     boolean found = false;
65                     while(!found) {
66                         int parent = parents[index];
67                         if(parent == start) {
68                             found = true;
69                         } else {
70                             index = parent;
71                         }
72                         // System.printString("parent: " + parent + "\n");
73                     }
74                     //System.printString("Index: " + index + "\n");
75
76                     // set the chase direction
77                     int nx = index % this.m_map.m_nrofblocks;
78                     int ny = index / this.m_map.m_nrofblocks;
79                     this.m_dx = nx - this.m_locX;
80                     this.m_dy = ny - this.m_locY;
81                     if(this.m_dx > 0) {
82                         // right
83                         this.m_direction = 4;
84                     } else if(this.m_dx < 0) {
85                         // left
86                         this.m_direction = 3;
87                     } else if(this.m_dy > 0) {
88                         // down
89                         this.m_direction = 2;
90                     } else if(this.m_dy < 0) {
91                         // up
92                         this.m_direction = 1;
93                     } else {
94                         // still
95                         this.m_direction = 0;
96                     }
97                     if(first) {
98                         tmptarget = this.m_target;
99                         tmpdx = this.m_dx;
100                         tmpdy = this.m_dy;
101                         tmpdirection = this.m_direction;
102                         first = false;
103                         //System.printString("First choice: (" + tmpdx + ", " + tmpdy + ")\n");
104                     }
105                 }
106
107                 // check if this choice follows some other ghosts' path
108                 if(!isFollowing()) {
109                     this.m_map.m_ghostdirections[this.m_index] = this.m_direction;
110                     set = true;
111                 } else {
112                     cuts.addElement(new Integer(index));
113                     /*for( int h = 0; h < cuts.size(); h++) {
114                         System.printString(cuts.elementAt(h) + ", ");
115                     }
116                     System.printString("\n");*/
117                 }
118             }
119         }
120     }
121     
122     // This methos do BFS from start node to end node
123     // If there is a path from start to end, return true; otherwise, return false
124     // Array parents records parent for a node in the BFS search,
125     // the last item of parents records the least steps to reach end node from start node
126     // Vector cuts specifies which nodes can not be the first one to access in this BFS
127     private boolean BFS(int start, int[] parents, Vector cuts) {
128         int steps = 0;
129         Vector toaccess = new Vector();
130         toaccess.addElement(new Integer(start));
131         while(toaccess.size() > 0) {
132             //System.printString("bbb\n");
133             // pull out the first one to access
134             int access = ((Integer)toaccess.elementAt(0)).intValue();
135             toaccess.removeElementAt(0);
136             for(int i = 0; i < this.m_map.m_pacMenX.length; i++) {
137                 if(((access%this.m_map.m_nrofblocks) == this.m_map.m_pacMenX[i]) && ((access/this.m_map.m_nrofblocks) == this.m_map.m_pacMenY[i])) {
138                     // hit one pacman
139                     this.m_target = i;
140                     parents[parents.length - 1] = steps;
141                     return true;
142                 }
143             }
144             steps++;
145             Vector neighbours = this.m_map.getNeighbours(access);
146             for(int i = 0; i < neighbours.size(); i++) {
147                 int neighbour = ((Integer)neighbours.elementAt(i)).intValue();
148                 if(parents[neighbour] == -1) {
149                     // not accessed
150                     boolean ignore = false;
151                     if(access == start) {
152                         // start node, check if the neighbour node is in cuts
153                         int j = 0;
154                         while((!ignore) && (j < cuts.size())) {
155                             int tmp = ((Integer)cuts.elementAt(j)).intValue();
156                             if(tmp == neighbour) {
157                                 ignore = true;
158                             }
159                             j++;
160                         }
161                     }
162                     if(!ignore) {
163                         parents[neighbour] = access;
164                         toaccess.addElement(new Integer(neighbour));
165                     }
166                 }
167             }
168         }
169         parents[parents.length - 1] = -1;
170         return false;
171     }
172     
173     // This method returns true if this ghost is traveling to the same
174     // destination with the same direction as another ghost.
175     private boolean isFollowing () {
176         boolean bFollowing = false;
177         double  dRandom;
178
179         // If the ghost is in the same location as another ghost
180         // and moving in the same direction, then they are on
181         // top of each other and should not follow.
182         for (int i = 0; i < this.m_map.m_ghostsX.length; i++) {
183             // Ignore myself
184             if (this.m_index != i) {
185                 if (this.m_map.m_ghostsX[i] == this.m_locX &&
186                         this.m_map.m_ghostsY[i] == this.m_locY &&
187                         this.m_map.m_ghostdirections[i] == this.m_direction) {
188                     return true;
189                 }
190             }
191         }
192
193         // This will allow ghosts to often
194         // clump together for easier eating
195         dRandom = this.m_map.m_r.nextDouble();
196         if (dRandom < .90) {  
197             //if (m_bInsaneAI && dRandom < .25)
198             //   return false;
199             //else
200             return false;
201         }
202
203         // If ghost is moving to the same location and using the
204         // same direction, then it is following another ghost.      
205         for (int i = 0; i < this.m_map.m_ghostsX.length; i++) {        
206             // Ignore myself        
207             if (this.m_index != i) {
208                 if (this.m_map.m_targets[i] == this.m_target &&
209                         this.m_map.m_ghostdirections[i] == this.m_direction) {
210                     return true;
211                 }
212             }
213         }
214
215         return bFollowing;
216     }
217     
218     // This method will take the specified location and direction and determine
219     // for the given location if the thing moved in that direction, what the
220     // next possible turning location would be.
221     private boolean getDestination (int direction, int locX, int locY, int[] point) {
222        // If the request direction is blocked by a wall, then just return the current location
223        if (((direction == 1) && ((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 2) != 0)) || // up
224            ((direction == 3) && ((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 1) != 0)) ||  // left
225            ((direction == 2) && ((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 8) != 0)) || // down
226            ((direction == 4) && ((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 4) != 0))) { // right 
227           point[0] = locX;
228           point[1] = locY;
229           return false;
230        }
231           
232        // Start off by advancing one in direction for specified location
233        if (direction == 1) {
234            // up
235            locY--;
236        } else if (direction == 2) {
237            // down
238            locY++;
239        } else if (direction == 3) {
240            // left
241            locX--;
242        } else if (direction == 4) {
243            // right
244            locX++;
245        }
246        
247        // If we violate the grid boundary,
248        // then return false.
249        if (locY < 0 ||
250            locX < 0 ||
251            locY == this.m_map.m_nrofblocks ||
252            locX == this.m_map.m_nrofblocks) {
253            return false;
254        }
255        
256        boolean set = false;
257        // Determine next turning location.
258        while (!set) {
259           if (direction == 1 || direction == 2) { 
260               // up or down
261               if (((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 4) == 0) || // right
262                       ((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 1) == 0) || // left
263                       ((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 2) != 0) || // up
264                       ((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 8) != 0))  { // down
265                   point[0] = locX;
266                   point[1] = locY;
267                   set = true;
268                } else {
269                    if (direction == 1) {
270                        // Check for Top Warp
271                        if (locY == 0) {
272                            point[0] = locX;
273                            point[1] = this.m_map.m_nrofblocks - 1;
274                            set = true;
275                        } else {
276                            locY--;
277                        }
278                    } else {
279                        // Check for Bottom Warp
280                        if (locY == this.m_map.m_nrofblocks - 1) {
281                            point[0] = locX;
282                            point[1] = 0;
283                            set = true;
284                        } else {
285                            locY++;
286                        }
287                    }
288                }
289           } else {
290               // left or right
291               if (((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 2) == 0) || // up
292                       ((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 8) == 0) || // down
293                       ((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 4) != 0) || // right
294                       ((int)(this.m_map.m_map[locX + locY * this.m_map.m_nrofblocks] & 1) != 0)) { // left  
295                   point[0] = locX;
296                   point[1] = locY;
297                   set = true;
298               } else {
299                   if (direction == 3) {
300                       // Check for Left Warp
301                       if (locX == 0) {
302                           point[0] = this.m_map.m_nrofblocks - 1;
303                           point[1] = locY;
304                           set = true;
305                       } else {
306                           locX--;
307                       }
308                   } else {
309                       // Check for Right Warp
310                       if (locX == this.m_map.m_nrofblocks - 1) {
311                           point[0] = 0;
312                           point[1] = locY;
313                           set = true;
314                       } else {
315                           locX++;
316                       }
317                   }
318               }
319           }
320        }
321        return true;
322     }
323     
324     public void doMove() {
325         if((this.m_dx == -1) && (this.m_locX == 0)) {
326             // go left and currently this.m_locX is 0
327             this.m_locX = this.m_map.m_nrofblocks - 1;
328         } else if((this.m_dx == 1) && (this.m_locX == this.m_map.m_nrofblocks - 1)) {
329             this.m_locX = 0;
330         } else {
331             this.m_locX += this.m_dx;
332         }
333
334         if((this.m_dy == -1) && (this.m_locY == 0)) {
335             // go up and currently this.m_locY is 0
336             this.m_locY = this.m_map.m_nrofblocks - 1;
337         } else if((this.m_dy == 1) && (this.m_locY == this.m_map.m_nrofblocks - 1)) {
338             this.m_locY = 0;
339         } else {
340             this.m_locY += this.m_dy;
341         }
342         this.m_dx = 0;
343         this.m_dy = 0;
344         //System.printString("Ghost " + this.m_index + ": (" + this.m_locX + ", " + this.m_locY + ")\n");
345     }
346 }