initial commit, lordsawar source, slightly modified
[lordsawar] / src / AI_Analysis.cpp
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
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 "AICityInfo.h"
32 #include "armysetlist.h"
33
34 using namespace std;
35
36 #define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<flush<<endl;}
37 //#define debug(x)
38
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;
42
43 AI_Analysis::AI_Analysis(Player *owner)
44     :d_owner(owner)
45 {
46     d_stacks = 0;
47     d_threats = new Threatlist();
48     d_stacks = new StackReflist(owner->getStacklist());
49
50     examineCities();
51     examineRuins();
52     examineStacks();
53     calculateDanger();
54
55     instance = this;
56 }
57
58 AI_Analysis::~AI_Analysis()
59 {
60     instance = 0;
61
62     d_threats->flClear();
63     delete d_threats;
64     delete d_stacks;
65
66     while (!d_cityInfo.empty())
67     {
68         delete (*d_cityInfo.begin()).second;
69         d_cityInfo.erase(d_cityInfo.begin());
70     }
71 }
72
73 void AI_Analysis::deleteStack(guint32 id)
74 {
75   if (instance)
76     {
77         instance->d_threats->deleteStack(id);
78         instance->d_stacks->removeStack(id);
79     }
80 }
81
82 void AI_Analysis::deleteStack(Stack* s)
83 {
84     if (instance)
85     {
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")
90     }
91 }
92
93 float AI_Analysis::assessArmyStrength(const Army *army)
94 {
95   return (float)army->getStat(Army::STRENGTH);
96 }
97
98 float AI_Analysis::assessStackStrength(const Stack *stack)
99 {
100     if (!instance)
101         return stack->size() * 5.0;
102
103     if (stack->getOwner() == instance->d_owner)
104     {
105         // our stack, so we can look inside it
106         float total = 0.0;
107         for (Stack::const_iterator it = stack->begin(); it != stack->end(); it++)
108           total += assessArmyStrength(*it);
109             
110
111         return total;
112     }
113     else
114       {
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;
127       }
128 }
129
130 const Threatlist* AI_Analysis::getThreatsInOrder()
131 {
132     d_threats->sortByValue();
133     return d_threats;
134 }
135
136 const Threatlist* AI_Analysis::getThreatsInOrder(Vector<int> pos)
137 {
138     d_threats->sortByDistance(pos);
139     return d_threats;
140 }
141     
142
143 void AI_Analysis::getCityWorstDangers(float dangers[3])
144 {
145     std::map<guint32, AICityInfo *>::iterator it;
146
147
148     // i wanto to have a result array with the first worst dangers
149     for (int i=0;i<3;i++)
150     {
151         float tmp=0.0;
152
153         for (it=d_cityInfo.begin();it!=d_cityInfo.end();it++)
154         {
155             tmp=(*it->second).getDanger();
156
157             if (dangers[i] < tmp) 
158             {
159                  if (i>0) // If The iteration is not the first we do want to avoid to store 
160                           // already stored worst dangers
161                  {
162                      if(tmp < dangers[i-1]) 
163                          dangers[i]=tmp;
164                  }
165                  else 
166                  {
167                      dangers[i]=tmp; // The first iteration we get the real worst Danger
168                  }
169             }
170         }
171     }
172
173     return;
174 }
175
176 int AI_Analysis::getNumberOfDefendersInCity(City *city)
177 {
178   AICityMap::iterator it = d_cityInfo.find(city->getId());
179   if (it == d_cityInfo.end())
180     return 0;
181
182   return (*it).second->getDefenderCount();
183 }
184
185 float AI_Analysis::getCityDanger(City *city)
186 {
187   AICityMap::iterator it = d_cityInfo.find(city->getId());
188   // city does not exist in the map
189   if (it == d_cityInfo.end())
190     return 0.0;
191
192   debug("Threats to " << city->getName() << " are " << d_cityInfo[city->getId()]->getThreats()->toString())
193     return (*it).second->getDanger();
194 }
195
196 void AI_Analysis::reinforce(City *city, Stack *stack, int movesToArrive)
197 {
198   AICityMap::iterator it = d_cityInfo.find(city->getId()) ;
199   if (it == d_cityInfo.end())
200     return;
201
202   (*it).second->addReinforcements(assessStackStrength(stack) / (float) movesToArrive);
203 }
204
205 float AI_Analysis::reinforcementsNeeded(City *city)
206 {
207   AICityMap::iterator it = d_cityInfo.find(city->getId());
208   if (it == d_cityInfo.end())
209     return -1000.0;
210
211   return (*it).second->getDanger() - (*it).second->getReinforcements();
212 }
213
214 void AI_Analysis::examineCities()
215 {
216     Citylist* cl = Citylist::getInstance();
217     for (Citylist::iterator it = cl->begin(); it != cl->end(); ++it)
218     {
219         City *city = (*it);
220         if (!city->isFriend(d_owner) && !city->isBurnt())
221         {
222             d_threats->push_back(new Threat(city));
223         }
224     }
225 }
226
227 void AI_Analysis::examineStacks()
228 {
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++)
232     {
233         Player *player = (*it);
234         if (player == d_owner)
235             continue;
236
237         Stacklist *sl = player->getStacklist();
238         for (Stacklist::iterator sit = sl->begin(); sit != sl->end(); ++sit)
239           d_threats->addStack(*sit);
240     }
241 }
242
243 void AI_Analysis::examineRuins()
244 {
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)
248     {
249         Ruin ruin = *it;
250         if (!ruin->isSearched())
251         {
252             d_threats->push_back(new Threat(ruin));
253         }
254     }
255 */
256 }
257
258 void AI_Analysis::calculateDanger()
259 {
260     Citylist* cl = Citylist::getInstance();
261     for (Citylist::iterator it = cl->begin(); it != cl->end(); ++it)
262     {
263         City *city = (*it);
264         if (city->isFriend(d_owner))
265         {
266             AICityInfo *info = new AICityInfo(city);
267             d_threats->findThreats(info);
268             d_cityInfo[city->getId()] = info;
269         }
270     }
271 }
272
273 void AI_Analysis::changeOwnership (Player * old_player, Player * new_player)
274 {
275   if (instance)
276     instance->d_threats->changeOwnership(old_player, new_player);
277 }
278
279 // End of file