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