170
Uint32 Path::calculate (Stack* s, Vector<int> dest, bool zigzag)
185
Uint32 Path::calculateToCity (Stack *s, Location *c, bool zigzag)
173
Vector<int> start = s->getPos();
174
debug("path from "<<start.x<<","<<start.y<<" to "<<dest.x<<","<<dest.y)
177
int width = GameMap::getWidth();
178
int height = GameMap::getHeight();
179
d_bonus = s->calculateMoveBonus();
180
//if (isBlocked(s, dest.x, dest.y, dest.x, dest.y))
182
//s->setMovesExhaustedAtPoint(0);
186
// Some notes concerning the path finding algorithm. The algorithm
187
// uses two different lists. There is a distance array, which contains how
188
// many MP one needs to get to the location (x,y), and a process queue that
189
// tells you at what point the number of movement points is calculated next.
191
// What we basically do is to start at the stack's position and calculate
192
// the distance (i.e. MP needed to get there) in circles around the starting
193
// position with the circles becoming increasingly larger. In detail, we
194
// start by appending the starting position in the queue of positions to be
195
// processed. Then, recursively, we take the first point in the queue and
196
// recalculate the distance for all bordering tiles, assuming that we go
197
// over this point and overwriting their current value if it is larger
198
// than what we find now. Then, we append each modified tile to the queue of
199
// tiles to be processed and continue. We stop when there are no more tiles
202
// Finally, all that is left is finding the minimum distance way from start
203
// point to destination.
205
// the conversion between x/y coordinates and index is (size is map size)
206
// index = y*width + x <=> x = index % width; y = index / width
207
int length = width*height;
208
int distance[length];
209
std::queue<Vector<int> > process;
210
bool flying = s->isFlying();
212
// initial filling of the distance vector
213
for (int i = 0; i < width*height; i++)
215
// -1 means don't know yet
216
// -2 means can't go there at all
217
// 0 or more is number of movement points needed to get there
219
if (isBlocked(s, i % width, i/width, dest.x, dest.y))
222
distance[start.y*width+start.x] = 0;
225
process.push(Vector<int>(start.x, start.y));
226
while (!process.empty())
228
Vector<int> pos = process.front();
229
process.pop(); // remove the first item
231
int dxy = distance[pos.y*width+pos.x]; // always >= 0
233
for (int sx = pos.x-1; sx <= pos.x+1; sx++)
235
if (sx < 0 || sx >= width)
238
for (int sy = pos.y-1; sy <= pos.y+1; sy++)
240
if (sy < 0 || sy >= height)
243
if (sx == pos.x && sy == pos.y)
246
//am i blocked from entering sx,sy from pos?
247
if (!flying && isBlockedDir(pos.x, pos.y, sx, sy))
250
int dsxy = distance[sy*width+sx];
252
continue; // can't move there anyway
188
Vector<int> shortest = c->getPos();
190
for (unsigned int i = 0; i < c->getSize(); i++)
191
for (unsigned int j = 0; j < c->getSize(); j++)
193
int distance = dist (s->getPos(), c->getPos() + Vector<int>(i, j));
196
if (distance < min_dist || min_dist == -1)
199
shortest = c->getPos() + Vector<int>(i, j);
203
int mp = calculate(s, shortest, zigzag);
206
//okay.. try really hard
208
for (unsigned int i = 0; i < c->getSize(); i++)
209
for (unsigned int j = 0; j < c->getSize(); j++)
211
int dist = calculate(s, c->getPos() + Vector<int>(i, j), zigzag);
214
if (dist < min_dist || min_dist == -1)
256
Vector<int> diff = pos - Vector<int>(sx, sy);
257
if (diff.x && diff.y)
217
shortest = c->getPos() + Vector<int>(i, j);
261
mp = pointsToMoveTo(s, pos.x, pos.y, sx, sy);
265
if (dsxy == -1 || dsxy > newDsxy)
267
distance[sy*width+sx] = newDsxy;
269
// append the item to the queue
270
process.push(Vector<int>(sx, sy));
276
// The distance array is now completely populated.
277
// What we have to do now is find the shortest path to the destination.
278
// We do that by starting at the destination and moving at each step to
279
// the neighbour closest to the start.
281
int dist = distance[dest.y * width + dest.x];
284
s->setMovesExhaustedAtPoint(0);
288
// choose the order in which we process directions so as to favour
289
// diagonals over straight lines
290
std::list<Vector<int> > diffs;
293
diffs.push_back(Vector<int>(-1, -1));
294
diffs.push_back(Vector<int>(-1, 1));
295
diffs.push_back(Vector<int>(1, -1));
296
diffs.push_back(Vector<int>(1, 1));
297
diffs.push_back(Vector<int>(1, 0));
298
diffs.push_back(Vector<int>(-1, 0));
299
diffs.push_back(Vector<int>(0, -1));
300
diffs.push_back(Vector<int>(0, 1));
304
diffs.push_back(Vector<int>(1, 0));
305
diffs.push_back(Vector<int>(-1, 0));
306
diffs.push_back(Vector<int>(0, -1));
307
diffs.push_back(Vector<int>(0, 1));
315
Vector<int> *p = new Vector<int>(x,y);
321
for (std::list<Vector<int> >::iterator it = diffs.begin();
322
it != diffs.end(); it++)
324
int newx = x + (*it).x;//diffs[i][0];
325
int newy = y + (*it).y;//diffs[i][1];
326
if (newx < 0 || newx == width || newy < 0 || newy == height)
328
//isBlockedDir is needed to catch crossings from land to sea when not thru a port/city
329
if (!flying && isBlockedDir(x, y, newx, newy))
332
dist = distance[newy*width+newx];
333
if (dist >= 0 && dist < min)
340
// found the best spot to go to from
346
//calculate when the waypoints show no more movement possible
347
Uint32 pathcount = 0;
348
Uint32 moves_left = s->getGroupMoves();
349
for (iterator it = begin(); it != end(); it++)
351
Uint32 moves = s->calculateTileMovementCost(**it);
352
if (moves_left >= moves)
358
s->setMovesExhaustedAtPoint(pathcount);
361
return distance[dest.y * width + dest.x];
221
mp = calculate(s, shortest, zigzag);
226
Uint32 Path::calculate (Stack* s, Vector<int> dest, bool zigzag)
229
Vector<int> start = s->getPos();
230
debug("path from "<<start.x<<","<<start.y<<" to "<<dest.x<<","<<dest.y)
233
//can we get there with one move?
234
if (dist(s->getPos(), dest) == 1 && canMoveThere(s, dest) == true)
236
Vector<int> *p = new Vector<int>(dest);
238
setMovesExhaustedAtPoint(1);
241
int width = GameMap::getWidth();
242
int height = GameMap::getHeight();
243
d_bonus = s->calculateMoveBonus();
244
//if (isBlocked(s, dest.x, dest.y, dest.x, dest.y))
246
//s->setMovesExhaustedAtPoint(0);
250
// Some notes concerning the path finding algorithm. The algorithm
251
// uses two different lists. There is a distance array, which contains how
252
// many MP one needs to get to the location (x,y), and a process queue that
253
// tells you at what point the number of movement points is calculated next.
255
// What we basically do is to start at the stack's position and calculate
256
// the distance (i.e. MP needed to get there) in circles around the starting
257
// position with the circles becoming increasingly larger. In detail, we
258
// start by appending the starting position in the queue of positions to be
259
// processed. Then, recursively, we take the first point in the queue and
260
// recalculate the distance for all bordering tiles, assuming that we go
261
// over this point and overwriting their current value if it is larger
262
// than what we find now. Then, we append each modified tile to the queue of
263
// tiles to be processed and continue. We stop when there are no more tiles
266
// Finally, all that is left is finding the minimum distance way from start
267
// point to destination.
269
// the conversion between x/y coordinates and index is (size is map size)
270
// index = y*width + x <=> x = index % width; y = index / width
271
int length = width*height;
272
int distance[length];
273
std::queue<Vector<int> > process;
274
bool flying = s->isFlying();
276
// initial filling of the distance vector
277
for (int i = 0; i < width*height; i++)
279
// -1 means don't know yet
280
// -2 means can't go there at all
281
// 0 or more is number of movement points needed to get there
283
if (isBlocked(s, i % width, i/width, dest.x, dest.y))
286
distance[start.y*width+start.x] = 0;
289
process.push(Vector<int>(start.x, start.y));
290
while (!process.empty())
292
Vector<int> pos = process.front();
293
process.pop(); // remove the first item
295
int dxy = distance[pos.y*width+pos.x]; // always >= 0
297
for (int sx = pos.x-1; sx <= pos.x+1; sx++)
299
if (sx < 0 || sx >= width)
302
for (int sy = pos.y-1; sy <= pos.y+1; sy++)
304
if (sy < 0 || sy >= height)
307
if (sx == pos.x && sy == pos.y)
310
//am i blocked from entering sx,sy from pos?
311
if (!flying && isBlockedDir(pos.x, pos.y, sx, sy))
314
int dsxy = distance[sy*width+sx];
316
continue; // can't move there anyway
320
Vector<int> diff = pos - Vector<int>(sx, sy);
321
if (diff.x && diff.y)
325
mp = pointsToMoveTo(s, pos.x, pos.y, sx, sy);
329
if (dsxy == -1 || dsxy > newDsxy)
331
distance[sy*width+sx] = newDsxy;
333
// append the item to the queue
334
process.push(Vector<int>(sx, sy));
340
// The distance array is now completely populated.
341
// What we have to do now is find the shortest path to the destination.
342
// We do that by starting at the destination and moving at each step to
343
// the neighbour closest to the start.
345
int dist = distance[dest.y * width + dest.x];
348
setMovesExhaustedAtPoint(0);
352
// choose the order in which we process directions so as to favour
353
// diagonals over straight lines
354
std::list<Vector<int> > diffs;
357
diffs.push_back(Vector<int>(-1, -1));
358
diffs.push_back(Vector<int>(-1, 1));
359
diffs.push_back(Vector<int>(1, -1));
360
diffs.push_back(Vector<int>(1, 1));
361
diffs.push_back(Vector<int>(1, 0));
362
diffs.push_back(Vector<int>(-1, 0));
363
diffs.push_back(Vector<int>(0, -1));
364
diffs.push_back(Vector<int>(0, 1));
368
diffs.push_back(Vector<int>(1, 0));
369
diffs.push_back(Vector<int>(-1, 0));
370
diffs.push_back(Vector<int>(0, -1));
371
diffs.push_back(Vector<int>(0, 1));
379
Vector<int> *p = new Vector<int>(x,y);
385
for (std::list<Vector<int> >::iterator it = diffs.begin();
386
it != diffs.end(); it++)
388
int newx = x + (*it).x;//diffs[i][0];
389
int newy = y + (*it).y;//diffs[i][1];
390
if (newx < 0 || newx == width || newy < 0 || newy == height)
392
//isBlockedDir is needed to catch crossings from land to sea when not thru a port/city
393
if (!flying && isBlockedDir(x, y, newx, newy))
396
dist = distance[newy*width+newx];
397
if (dist >= 0 && dist < min)
404
// found the best spot to go to from
410
//calculate when the waypoints show no more movement possible
411
Uint32 pathcount = 0;
412
Uint32 moves_left = s->getGroupMoves();
413
for (iterator it = begin(); it != end(); it++)
415
Uint32 moves = s->calculateTileMovementCost(**it);
416
if (moves_left >= moves)
422
setMovesExhaustedAtPoint(pathcount);
425
return distance[dest.y * width + dest.x];
428
void Path::eraseFirstPoint()
432
if (getMovesExhaustedAtPoint() > 0)
433
setMovesExhaustedAtPoint(getMovesExhaustedAtPoint()-1);
364
438
//am i blocked from entering destx,desty from x,y when i'm not flying?
365
439
bool Path::isBlockedDir(int x, int y, int destx, int desty) const
396
470
bool Path::isBlocked(const Stack* s, int x, int y, int destx, int desty) const
398
const Maptile* tile = GameMap::getInstance()->getTile(x,y);
400
// Return true on every condition which may prevent the stack from
401
// entering the tile, which are...
403
// TODO: you can extract quite some amount of time here with a clever
404
// search algorithm for stacklist
405
Stack* target = Stacklist::getObjectAt(x,y);
408
// ...enemy stacks which stand in the way...
409
if ((s->getPlayer() != target->getPlayer())
410
&& ((x != destx) || (y != desty)))
413
// ...friendly stacks which are too big to merge with...
414
if ((s->getPlayer() == target->getPlayer())
415
&& (s->size() + target->size() > MAX_STACK_SIZE))
420
// saves some computation time here
421
if (tile->getBuilding() == Maptile::CITY)
423
City* c = Citylist::getInstance()->getObjectAt(x,y);
424
if (c && (c->getPlayer() != s->getPlayer())
425
&& ((x != destx) || (y != desty)))
429
//no obstacles??? well, then...
472
const Maptile* tile = GameMap::getInstance()->getTile(x,y);
474
// Return true on every condition which may prevent the stack from
475
// entering the tile, which are...
477
// TODO: you can extract quite some amount of time here with a clever
478
// search algorithm for stacklist
479
Stack* target = Stacklist::getObjectAt(x,y);
482
// ...enemy stacks which stand in the way...
483
if ((s->getOwner() != target->getOwner())
484
&& ((x != destx) || (y != desty)))
487
//the computer walks around any too-big stacks of it's own
488
//unless it's the final destination.
489
if (s->getOwner() == target->getOwner()
490
&& s->canJoin(target) == false &&
491
s->getOwner()->getType() != Player::HUMAN)
493
if (Vector<int>(destx, desty) != Vector<int>(x,y))
500
// saves some computation time here
501
if (tile->getBuilding() == Maptile::CITY)
503
City* c = Citylist::getInstance()->getObjectAt(x,y);
504
if (c && (c->getOwner() != s->getOwner())
505
&& ((x != destx) || (y != desty)))
509
//no obstacles??? well, then...
433
513
int Path::pointsToMoveTo(const Stack *s, int x, int y, int destx, int desty) const
436
const Maptile* tile = GameMap::getInstance()->getTile(destx,desty);
438
if (x == destx && y == desty) //probably shouldn't happen
441
moves = tile->getMoves();
443
// does everything in the stack have a bonus to move onto this square?
444
if (tile->getMaptileType() & d_bonus && moves != 1)
516
const Maptile* tile = GameMap::getInstance()->getTile(destx,desty);
518
if (x == destx && y == desty) //probably shouldn't happen
521
moves = tile->getMoves();
523
// does everything in the stack have a bonus to move onto this square?
524
if (tile->getMaptileType() & d_bonus && moves != 1)