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