1 // Copyright (C) 2004 John Farrell
2 // Copyright (C) 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2006 Andrea Paternesi
4 // Copyright (C) 2009, 2014 Ben Asselstine
5 //
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.
10 //
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.
15 //
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
19 //  02110-1301, USA.
20 
21 #include <iostream>
22 #include "AI_Analysis.h"
23 #include "citylist.h"
24 #include "Threatlist.h"
25 #include "Threat.h"
26 #include "playerlist.h"
27 #include "stackreflist.h"
28 #include "stacklist.h"
29 #include "ruinlist.h"
30 #include "army.h"
31 #include "city.h"
32 #include "AICityInfo.h"
33 #include "armysetlist.h"
34 
35 //#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::flush<<std::endl;}
36 #define debug(x)
37 
38 //this instance is just needed in case one of the observed stacks dies during
39 //the analysis (and the following actions).
40 AI_Analysis* AI_Analysis::instance = 0;
41 
AI_Analysis(Player * owner)42 AI_Analysis::AI_Analysis(Player *owner)
43     :d_owner(owner)
44 {
45     d_stacks = 0;
46     d_threats = new Threatlist();
47     d_stacks = new StackReflist(owner->getStacklist());
48 
49     examineCities();
50     examineRuins();
51     examineStacks();
52     calculateDanger();
53 
54     instance = this;
55 }
56 
~AI_Analysis()57 AI_Analysis::~AI_Analysis()
58 {
59     instance = 0;
60 
61     delete d_threats;
62     delete d_stacks;
63 
64     while (!d_cityInfo.empty())
65     {
66         delete (*d_cityInfo.begin()).second;
67         d_cityInfo.erase(d_cityInfo.begin());
68     }
69 }
70 
deleteStack(guint32 id)71 void AI_Analysis::deleteStack(guint32 id)
72 {
73   if (instance)
74     {
75         instance->d_threats->deleteStack(id);
76         instance->d_stacks->removeStack(id);
77     }
78 }
79 
deleteStack(Stack * s)80 void AI_Analysis::deleteStack(Stack* s)
81 {
82     if (instance)
83     {
84         debug("delete stack from ai_analysis")
85         instance->d_threats->deleteStack(s->getId());
86         instance->d_stacks->removeStack(s->getId());
87         debug("stack " << s << " died")
88     }
89 }
90 
assessArmyStrength(const Army * army)91 float AI_Analysis::assessArmyStrength(const Army *army)
92 {
93   return (float)army->getStat(Army::STRENGTH);
94 }
95 
assessStackStrength(const Stack * stack)96 float AI_Analysis::assessStackStrength(const Stack *stack)
97 {
98     if (!instance)
99         return stack->size() * 5.0;
100 
101     if (stack->getOwner() == instance->d_owner)
102     {
103         // our stack, so we can look inside it
104         float total = 0.0;
105         for (Stack::const_iterator it = stack->begin(); it != stack->end(); it++)
106           total += assessArmyStrength(*it);
107 
108 
109         return total;
110     }
111     else
112       {
113         // enemy stack, no cheating!
114         // if we were smarter, we would remember all stacks we had seen before and return a better number here.
115         // We don't assume a too high average strength
116         guint32 as = stack->getOwner()->getArmyset();
117         guint32 type_id = stack->getStrongestArmy()->getTypeId();
118         ArmyProto *strongest = Armysetlist::getInstance()->getArmy(as, type_id);
119         //if the strongest army has a strength of 4 or less,
120         //we assume that all army units in the stack have the same strength.
121         if (strongest->getStrength() < 5)
122           return stack->size() * strongest->getStrength();
123         //otherwise we round everything down to an average of 5 strength.
124         return stack->size() * 5.0;
125       }
126 }
127 
getThreatsInOrder()128 const Threatlist* AI_Analysis::getThreatsInOrder()
129 {
130     d_threats->sortByValue();
131     return d_threats;
132 }
133 
getThreatsInOrder(Vector<int> pos)134 const Threatlist* AI_Analysis::getThreatsInOrder(Vector<int> pos)
135 {
136     d_threats->sortByDistance(pos);
137     return d_threats;
138 }
139 
140 
getCityWorstDangers(float dangers[3])141 void AI_Analysis::getCityWorstDangers(float dangers[3])
142 {
143     std::map<guint32, AICityInfo *>::iterator it;
144 
145 
146     // i wanto to have a result array with the first worst dangers
147     for (int i=0;i<3;i++)
148     {
149         float tmp=0.0;
150 
151         for (it=d_cityInfo.begin();it!=d_cityInfo.end();it++)
152 	{
153             tmp=(*it->second).getDanger();
154 
155             if (dangers[i] < tmp)
156 	    {
157 	         if (i>0) // If The iteration is not the first we do want to avoid to store
158                           // already stored worst dangers
159 		 {
160                      if(tmp < dangers[i-1])
161                          dangers[i]=tmp;
162 		 }
163                  else
164                  {
165 		     dangers[i]=tmp; // The first iteration we get the real worst Danger
166 		 }
167 	    }
168 	}
169     }
170 
171     return;
172 }
173 
getNumberOfDefendersInCity(City * city)174 int AI_Analysis::getNumberOfDefendersInCity(City *city)
175 {
176   AICityMap::iterator it = d_cityInfo.find(city->getId());
177   if (it == d_cityInfo.end())
178     return 0;
179 
180   return (*it).second->getDefenderCount();
181 }
182 
getCityDanger(City * city)183 float AI_Analysis::getCityDanger(City *city)
184 {
185   AICityMap::iterator it = d_cityInfo.find(city->getId());
186   // city does not exist in the map
187   if (it == d_cityInfo.end())
188     return 0.0;
189 
190   debug("Threats to " << city->getName() << " are " << d_cityInfo[city->getId()]->getThreats()->toString())
191     return (*it).second->getDanger();
192 }
193 
reinforce(City * city,Stack * stack,int movesToArrive)194 void AI_Analysis::reinforce(City *city, Stack *stack, int movesToArrive)
195 {
196   AICityMap::iterator it = d_cityInfo.find(city->getId()) ;
197   if (it == d_cityInfo.end())
198     return;
199 
200   (*it).second->addReinforcements(assessStackStrength(stack) / (float) movesToArrive);
201 }
202 
reinforcementsNeeded(City * city)203 float AI_Analysis::reinforcementsNeeded(City *city)
204 {
205   AICityMap::iterator it = d_cityInfo.find(city->getId());
206   if (it == d_cityInfo.end())
207     return -1000.0;
208 
209   return (*it).second->getDanger() - (*it).second->getReinforcements();
210 }
211 
examineCities()212 void AI_Analysis::examineCities()
213 {
214   for (auto city: *Citylist::getInstance())
215     if (!city->isFriend(d_owner) && !city->isBurnt())
216       d_threats->push_back(new Threat(city));
217 }
218 
examineStacks()219 void AI_Analysis::examineStacks()
220 {
221   // add all enemy stacks to the list of threats
222   for (auto player: *Playerlist::getInstance())
223     {
224       if (player == d_owner)
225         continue;
226 
227       Stacklist *sl = player->getStacklist();
228       for (Stacklist::iterator sit = sl->begin(); sit != sl->end(); ++sit)
229         d_threats->addStack(*sit);
230     }
231 }
232 
examineRuins()233 void AI_Analysis::examineRuins()
234 {
235     // enable the searching of ruins before you start to regard them as threats
236 /*    Ruinlist *ruins = Ruinlist::getInstance();
237     for (Ruinlist::iterator it = ruins->begin(); it != ruins->end(); ++it)
238     {
239         Ruin ruin = *it;
240         if (!ruin->isSearched())
241         {
242             d_threats->push_back(new Threat(ruin));
243         }
244     }
245 */
246 }
247 
calculateDanger()248 void AI_Analysis::calculateDanger()
249 {
250   for (auto city: *Citylist::getInstance())
251     {
252       if (city->isFriend(d_owner))
253         {
254           AICityInfo *info = new AICityInfo(city);
255           d_threats->findThreats(info);
256           d_cityInfo[city->getId()] = info;
257         }
258     }
259 }
260 
changeOwnership(Player * old_player,Player * new_player)261 void AI_Analysis::changeOwnership (Player * old_player, Player * new_player)
262 {
263   if (instance)
264     instance->d_threats->changeOwnership(old_player, new_player);
265 }
266 
267 // End of file
268