9 public int m_direction; // 0:still, 1:up, 2:down, 3:left, 4:right
14 public Ghost(int x, int y, Map map) {
17 this.m_dx = this.m_dy = 0;
24 // 0:still, 1:up, 2:down, 3:left, 4:right
25 public void tryMove() {
26 //System.printString("step 1\n");
29 // check the nearest pacman and set it as current target
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];
47 // System.printString("target: " + this.m_target + "\n");
49 if(this.m_target == -1) {
50 // no more pacmen to chase, stay still
53 this.m_direction = this.m_map.m_ghostdirections[this.m_index] = 0;
57 // find the shortest way to the chosen target
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];
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];
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();
79 // breadth-first traverse the graph view of the maze
80 // check the shortest path for the start node to the end node
82 Vector cuts = new Vector();
88 int parents[] = new int[this.m_map.m_nrofblocks * this.m_map.m_nrofblocks];
89 for(int i = 0; i < parents.length; i++) {
92 if(!BFS(start, end, parents, cuts)) {
95 this.m_map.m_ghostdirections[this.m_index] = this.m_direction = tmpdirection;
97 //System.printString("Use first choice: (" + this.m_dx + ", " + this.m_dy + ")\n");
99 // Reversely go over the parents array to find the next node to reach
100 boolean found = false;
101 int index = end.getIndex();
103 int parent = parents[index];
104 if(parent == start.getIndex()) {
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;
118 this.m_direction = 4;
119 } else if(this.m_dx < 0) {
121 this.m_direction = 3;
122 } else if(this.m_dy > 0) {
124 this.m_direction = 2;
125 } else if(this.m_dy < 0) {
127 this.m_direction = 1;
130 this.m_direction = 0;
135 tmpdirection = this.m_direction;
137 //System.printString("First choice: (" + tmpdx + ", " + tmpdy + ")\n");
140 // check if this choice follows some other ghosts' path
142 this.m_map.m_ghostdirections[this.m_index] = this.m_direction;
145 cuts.addElement(new Integer(index));
146 /*for( int h = 0; h < cuts.size(); h++) {
147 System.printString(cuts.elementAt(h) + ", ");
149 System.printString("\n");*/
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()) {
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) {
175 boolean ignore = false;
176 if(access.getIndex() == start.getIndex()) {
177 // start node, check if the neighbour node is in cuts
179 while((!ignore) && (j < cuts.size())) {
180 int tmp = ((Integer)cuts.elementAt(j)).intValue();
181 if(tmp == neighbour.getIndex()) {
188 parents[neighbour.getIndex()] = access.getIndex();
189 toaccess.addElement(neighbour);
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;
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++) {
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) {
217 // This will allow ghosts to often
218 // clump together for easier eating
219 dRandom = this.m_map.m_r.nextDouble();
221 //if (m_bInsaneAI && dRandom < .25)
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++) {
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) {
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
256 // Start off by advancing one in direction for specified location
257 if (direction == 1) {
260 } else if (direction == 2) {
263 } else if (direction == 3) {
266 } else if (direction == 4) {
271 // If we violate the grid boundary,
272 // then return false.
275 locY == this.m_map.m_nrofblocks ||
276 locX == this.m_map.m_nrofblocks) {
281 // Determine next turning location.
283 if (direction == 1 || direction == 2) {
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
293 if (direction == 1) {
294 // Check for Top Warp
297 point[1] = this.m_map.m_nrofblocks - 1;
303 // Check for Bottom Warp
304 if (locY == this.m_map.m_nrofblocks - 1) {
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
323 if (direction == 3) {
324 // Check for Left Warp
326 point[0] = this.m_map.m_nrofblocks - 1;
333 // Check for Right Warp
334 if (locX == this.m_map.m_nrofblocks - 1) {
348 public void doMove() {
349 this.m_locX += this.m_dx;
350 this.m_locY += this.m_dy;
353 //System.printString("Ghost " + this.m_index + ": (" + this.m_locX + ", " + this.m_locY + ")\n");