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