1 // Copyright (C) 2000, 2001, 2002, 2003 Michael Bartl
2 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2004, 2005, 2006 Andrea Paternesi
4 // Copyright (C) 2004 John Farrell
5 // Copyright (C) 2006, 2007, 2008, 2009 Ben Asselstine
6 // Copyright (C) 2008 Ole Laursen
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 3 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Library General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 #include "PathCalculator.h"
33 #include "stacklist.h"
34 #include "xmlhelper.h"
37 std::string Path::d_tag = "path";
47 //#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
53 d_moves_exhausted_at_point = 0;
56 Path::Path(const Path& p)
57 : d_bonus(p.d_bonus), d_moves_exhausted_at_point(p.d_moves_exhausted_at_point)
59 for (const_iterator it = p.begin(); it != p.end(); it++)
60 push_back(Vector<int>((*it).x, (*it).y));
63 Path::Path(XML_Helper* helper)
66 std::istringstream sx, sy;
69 helper->getData(d_moves_exhausted_at_point, "moves_exhausted_at_point");
70 helper->getData(i, "size");
72 helper->getData(s, "x");
74 helper->getData(s, "y");
79 Vector<int> p = Vector<int>(-1,-1);
92 bool Path::save(XML_Helper* helper) const
96 std::stringstream sx, sy;
97 for (const_iterator it = begin(); it != end(); it++)
103 retval &= helper->openTag(Path::d_tag);
104 retval &= helper->saveData("size", size());
105 retval &= helper->saveData("moves_exhausted_at_point",
106 d_moves_exhausted_at_point);
107 retval &= helper->saveData("x", sx.str());
108 retval &= helper->saveData("y", sy.str());
109 retval &= helper->closeTag();
114 bool Path::checkPath(Stack* s, int enemy_city_avoidance, int enemy_stack_avoidance)
121 iterator secondlast = end();
123 for (iterator it = begin(); it != secondlast; it++)
125 if (PathCalculator::isBlocked(s, *it, enemy_city_avoidance,
126 enemy_stack_avoidance) == false)
137 //this is used to update the moves_exhausted_at_point variable
138 void Path::recalculate (Stack* s)
143 // be careful to not go into cities that are now owned by the enemy
144 reverse_iterator it = rbegin();
145 for (; it != rend(); it++)
147 Vector<int> dest = *it;
148 City *c = GameMap::getCity(dest);
149 if (c && c->getOwner() != s->getOwner())
156 //well, it looks like all of our points were in enemy cities
157 setMovesExhaustedAtPoint(0);
162 Vector<int> dest = *it;
168 guint32 Path::calculateToCity (Stack *s, City *c, bool zigzag)
171 Vector<int> shortest = c->getPos();
172 bool checkJoin = s->getOwner() == c->getOwner();
174 for (unsigned int i = 0; i < c->getSize(); i++)
175 for (unsigned int j = 0; j < c->getSize(); j++)
177 if (checkJoin == true)
179 Stack *other_stack = GameMap::getStack(c->getPos() + Vector<int>(i,j));
180 if (other_stack && GameMap::canJoin(s,other_stack) == false)
183 int distance = dist (s->getPos(), c->getPos() + Vector<int>(i, j));
186 if (distance < min_dist || min_dist == -1)
189 shortest = c->getPos() + Vector<int>(i, j);
193 int mp = calculate(s, shortest, zigzag);
196 //okay.. try really hard
198 for (unsigned int i = 0; i < c->getSize(); i++)
199 for (unsigned int j = 0; j < c->getSize(); j++)
201 if (checkJoin == true)
203 Stack *other_stack = GameMap::getStack(c->getPos() + Vector<int>(i,j));
204 if (other_stack && GameMap::canJoin(s,other_stack) == false)
207 int dist = calculate(s, c->getPos() + Vector<int>(i, j), zigzag);
210 if (dist < min_dist || min_dist == -1)
213 shortest = c->getPos() + Vector<int>(i, j);
217 mp = calculate(s, shortest, zigzag);
222 void Path::calculate (Stack* s, Vector<int> dest, guint32 &moves, guint32 &turns, bool zigzag)
225 //Vector<int> start = s->getPos();
226 debug("path from "<<start.x<<","<<start.y<<" to "<<dest.x<<","<<dest.y)
230 // Some notes concerning the path finding algorithm. The algorithm
231 // uses two different lists. There is a nodes array, which contains how
232 // many MP one needs to get to the location (x,y), and a process queue that
233 // tells you at what point the number of movement points is calculated next.
235 // What we basically do is to start at the stack's position and calculate
236 // the distance (i.e. MP needed to get there) in circles around the starting
237 // position with the circles becoming increasingly larger. In detail, we
238 // start by appending the starting position in the queue of positions to be
239 // processed. Then, recursively, we take the first point in the queue and
240 // recalculate the distance for all bordering tiles, assuming that we go
241 // over this point and overwriting their current value if it is larger
242 // than what we find now. Then, we append each modified tile to the queue of
243 // tiles to be processed and continue. We stop when there are no more tiles
246 // Finally, all that is left is finding the minimum distance way from start
247 // point to destination.
250 int enemy_city_avoidance = -1;
251 int enemy_stack_avoidance = -1;
252 if (s->getOwner() && s->getOwner()->isComputer())
254 //If we're a computer player we don't let enemy stacks and cities
255 //prevent us from reaching our destination. When we encounter them
256 //we'll fight, but we try not to encounter them.
257 enemy_city_avoidance = 10;
258 enemy_stack_avoidance = 10;
260 PathCalculator pc = PathCalculator(s, zigzag, enemy_city_avoidance,
261 enemy_stack_avoidance);
263 Path *calculated_path = pc.calculate(dest, moves, turns, zigzag);
264 if (calculated_path->size())
266 for(Path::iterator it = calculated_path->begin(); it!= calculated_path->end(); it++)
270 //calculate when the waypoints show no more movement possible
271 guint32 pathcount = 0;
272 guint32 moves_left = s->getMoves();
273 for (iterator it = begin(); it != end(); it++)
275 guint32 moves = s->calculateTileMovementCost(*it);
276 if (moves_left >= moves)
282 setMovesExhaustedAtPoint(pathcount);
283 delete calculated_path;
288 guint32 Path::calculate (Stack* s, Vector<int> dest, guint32 &turns, bool zigzag)
291 calculate(s, dest, mp, turns, zigzag);
295 guint32 Path::calculate (Stack* s, Vector<int> dest, bool zigzag)
299 calculate(s, dest, mp, turns, zigzag);
303 void Path::eraseFirstPoint()
307 if (getMovesExhaustedAtPoint() > 0)
308 setMovesExhaustedAtPoint(getMovesExhaustedAtPoint()-1);