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