1 // Copyright (C) 2004 John Farrell
2 // Copyright (C) 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2006 Andrea Paternesi
4 // Copyright (C) 2009 Ben Asselstine
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU Library General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 #include "AI_Analysis.h"
24 #include "Threatlist.h"
26 #include "playerlist.h"
27 #include "stackreflist.h"
28 #include "stacklist.h"
31 #include "AICityInfo.h"
32 #include "armysetlist.h"
36 #define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<flush<<endl;}
39 //this instance is just needed in case one of the observed stacks dies during
40 //the analysis (and the following actions).
41 AI_Analysis* AI_Analysis::instance = 0;
43 AI_Analysis::AI_Analysis(Player *owner)
47 d_threats = new Threatlist();
48 d_stacks = new StackReflist(owner->getStacklist());
58 AI_Analysis::~AI_Analysis()
66 while (!d_cityInfo.empty())
68 delete (*d_cityInfo.begin()).second;
69 d_cityInfo.erase(d_cityInfo.begin());
73 void AI_Analysis::deleteStack(guint32 id)
77 instance->d_threats->deleteStack(id);
78 instance->d_stacks->removeStack(id);
82 void AI_Analysis::deleteStack(Stack* s)
86 debug("delete stack from ai_analysis")
87 instance->d_threats->deleteStack(s->getId());
88 instance->d_stacks->removeStack(s->getId());
89 debug("stack " << s << " died")
93 float AI_Analysis::assessArmyStrength(const Army *army)
95 return (float)army->getStat(Army::STRENGTH);
98 float AI_Analysis::assessStackStrength(const Stack *stack)
101 return stack->size() * 5.0;
103 if (stack->getOwner() == instance->d_owner)
105 // our stack, so we can look inside it
107 for (Stack::const_iterator it = stack->begin(); it != stack->end(); it++)
108 total += assessArmyStrength(*it);
115 // enemy stack, no cheating!
116 // if we were smarter, we would remember all stacks we had seen before and return a better number here.
117 // We don't assume a too high average strength
118 guint32 as = stack->getOwner()->getArmyset();
119 guint32 type_id = stack->getStrongestArmy()->getTypeId();
120 ArmyProto *strongest = Armysetlist::getInstance()->getArmy(as, type_id);
121 //if the strongest army has a strength of 4 or less,
122 //we assume that all army units in the stack have the same strength.
123 if (strongest->getStrength() < 5)
124 return stack->size() * strongest->getStrength();
125 //otherwise we round everything down to an average of 5 strength.
126 return stack->size() * 5.0;
130 const Threatlist* AI_Analysis::getThreatsInOrder()
132 d_threats->sortByValue();
136 const Threatlist* AI_Analysis::getThreatsInOrder(Vector<int> pos)
138 d_threats->sortByDistance(pos);
143 void AI_Analysis::getCityWorstDangers(float dangers[3])
145 std::map<guint32, AICityInfo *>::iterator it;
148 // i wanto to have a result array with the first worst dangers
149 for (int i=0;i<3;i++)
153 for (it=d_cityInfo.begin();it!=d_cityInfo.end();it++)
155 tmp=(*it->second).getDanger();
157 if (dangers[i] < tmp)
159 if (i>0) // If The iteration is not the first we do want to avoid to store
160 // already stored worst dangers
162 if(tmp < dangers[i-1])
167 dangers[i]=tmp; // The first iteration we get the real worst Danger
176 int AI_Analysis::getNumberOfDefendersInCity(City *city)
178 AICityMap::iterator it = d_cityInfo.find(city->getId());
179 if (it == d_cityInfo.end())
182 return (*it).second->getDefenderCount();
185 float AI_Analysis::getCityDanger(City *city)
187 AICityMap::iterator it = d_cityInfo.find(city->getId());
188 // city does not exist in the map
189 if (it == d_cityInfo.end())
192 debug("Threats to " << city->getName() << " are " << d_cityInfo[city->getId()]->getThreats()->toString())
193 return (*it).second->getDanger();
196 void AI_Analysis::reinforce(City *city, Stack *stack, int movesToArrive)
198 AICityMap::iterator it = d_cityInfo.find(city->getId()) ;
199 if (it == d_cityInfo.end())
202 (*it).second->addReinforcements(assessStackStrength(stack) / (float) movesToArrive);
205 float AI_Analysis::reinforcementsNeeded(City *city)
207 AICityMap::iterator it = d_cityInfo.find(city->getId());
208 if (it == d_cityInfo.end())
211 return (*it).second->getDanger() - (*it).second->getReinforcements();
214 void AI_Analysis::examineCities()
216 Citylist* cl = Citylist::getInstance();
217 for (Citylist::iterator it = cl->begin(); it != cl->end(); ++it)
220 if (!city->isFriend(d_owner) && !city->isBurnt())
222 d_threats->push_back(new Threat(city));
227 void AI_Analysis::examineStacks()
229 // add all enemy stacks to the list of threats
230 Playerlist *players = Playerlist::getInstance();
231 for (Playerlist::iterator it = players->begin(); it != players->end(); it++)
233 Player *player = (*it);
234 if (player == d_owner)
237 Stacklist *sl = player->getStacklist();
238 for (Stacklist::iterator sit = sl->begin(); sit != sl->end(); ++sit)
239 d_threats->addStack(*sit);
243 void AI_Analysis::examineRuins()
245 // enable the searching of ruins before you start to regard them as threats
246 /* Ruinlist *ruins = Ruinlist::getInstance();
247 for (Ruinlist::iterator it = ruins->begin(); it != ruins->end(); ++it)
250 if (!ruin->isSearched())
252 d_threats->push_back(new Threat(ruin));
258 void AI_Analysis::calculateDanger()
260 Citylist* cl = Citylist::getInstance();
261 for (Citylist::iterator it = cl->begin(); it != cl->end(); ++it)
264 if (city->isFriend(d_owner))
266 AICityInfo *info = new AICityInfo(city);
267 d_threats->findThreats(info);
268 d_cityInfo[city->getId()] = info;
273 void AI_Analysis::changeOwnership (Player * old_player, Player * new_player)
276 instance->d_threats->changeOwnership(old_player, new_player);