StupidAI.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include "stdafx.h"
  2. #include "StupidAI.h"
  3. #include "../../lib/BattleState.h"
  4. #include "../../CCallback.h"
  5. #include <boost/foreach.hpp>
  6. #include <boost/bind.hpp>
  7. #include "../../lib/CCreatureHandler.h"
  8. #include <algorithm>
  9. #include <boost/thread.hpp>
  10. IBattleCallback * cbc;
  11. CStupidAI::CStupidAI(void)
  12. : side(-1), cb(NULL)
  13. {
  14. print("created");
  15. }
  16. CStupidAI::~CStupidAI(void)
  17. {
  18. print("destroyed");
  19. }
  20. void CStupidAI::init( IBattleCallback * CB )
  21. {
  22. print("init called, saving ptr to IBattleCallback");
  23. cbc = cb = CB;
  24. }
  25. void CStupidAI::actionFinished( const BattleAction *action )
  26. {
  27. print("actionFinished called");
  28. }
  29. void CStupidAI::actionStarted( const BattleAction *action )
  30. {
  31. print("actionStarted called");
  32. }
  33. struct EnemyInfo
  34. {
  35. const CStack * s;
  36. int adi, adr;
  37. std::vector<THex> attackFrom; //for melee fight
  38. EnemyInfo(const CStack * _s) : s(_s)
  39. {}
  40. void calcDmg(const CStack * ourStack)
  41. {
  42. TDmgRange retal, dmg = cbc->battleEstimateDamage(ourStack, s, &retal);
  43. adi = (dmg.first + dmg.second) / 2;
  44. adr = (retal.first + retal.second) / 2;
  45. }
  46. bool operator==(const EnemyInfo& ei) const
  47. {
  48. return s == ei.s;
  49. }
  50. };
  51. bool isMoreProfitable(const EnemyInfo &ei1, const EnemyInfo& ei2)
  52. {
  53. return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr);
  54. }
  55. int distToNearestNeighbour(THex hex, const std::vector<int> & dists, THex *chosenHex = NULL)
  56. {
  57. int ret = 1000000;
  58. BOOST_FOREACH(THex n, hex.neighbouringTiles())
  59. {
  60. if(dists[n] >= 0 && dists[n] < ret)
  61. {
  62. ret = dists[n];
  63. if(chosenHex)
  64. *chosenHex = n;
  65. }
  66. }
  67. return ret;
  68. }
  69. bool isCloser(const EnemyInfo & ei1, const EnemyInfo & ei2, const std::vector<int> & dists)
  70. {
  71. return distToNearestNeighbour(ei1.s->position, dists) < distToNearestNeighbour(ei2.s->position, dists);
  72. }
  73. static bool willSecondHexBlockMoreEnemyShooters(const THex &h1, const THex &h2)
  74. {
  75. int shooters[2] = {0}; //count of shooters on hexes
  76. for(int i = 0; i < 2; i++)
  77. BOOST_FOREACH(THex neighbour, (i ? h2 : h1).neighbouringTiles())
  78. if(const CStack *s = cbc->battleGetStackByPos(neighbour))
  79. if(s->getCreature()->isShooting())
  80. shooters[i]++;
  81. return shooters[0] < shooters[1];
  82. }
  83. BattleAction CStupidAI::activeStack( const CStack * stack )
  84. {
  85. //boost::this_thread::sleep(boost::posix_time::seconds(2));
  86. print("activeStack called");
  87. std::vector<THex> avHexes = cb->battleGetAvailableHexes(stack, false);
  88. std::vector<int> dists = cb->battleGetDistances(stack);
  89. std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
  90. BOOST_FOREACH(const CStack *s, cb->battleGetStacks())
  91. {
  92. if(s->owner != stack->owner)
  93. {
  94. if(cb->battleCanShoot(stack, s->position))
  95. {
  96. enemiesShootable.push_back(s);
  97. }
  98. else
  99. {
  100. BOOST_FOREACH(THex hex, avHexes)
  101. {
  102. if(CStack::isMeleeAttackPossible(stack, s, hex))
  103. {
  104. std::vector<EnemyInfo>::iterator i = std::find(enemiesReachable.begin(), enemiesReachable.end(), s);
  105. if(i == enemiesReachable.end())
  106. {
  107. enemiesReachable.push_back(s);
  108. i = enemiesReachable.begin() + (enemiesReachable.size() - 1);
  109. }
  110. i->attackFrom.push_back(hex);
  111. }
  112. }
  113. if(!vstd::contains(enemiesReachable, s))
  114. enemiesUnreachable.push_back(s);
  115. }
  116. }
  117. }
  118. if(enemiesShootable.size())
  119. {
  120. const EnemyInfo &ei= *std::max_element(enemiesShootable.begin(), enemiesShootable.end(), isMoreProfitable);
  121. return BattleAction::makeShotAttack(stack, ei.s);
  122. }
  123. else if(enemiesReachable.size())
  124. {
  125. const EnemyInfo &ei= *std::max_element(enemiesReachable.begin(), enemiesReachable.end(), &isMoreProfitable);
  126. return BattleAction::makeMeleeAttack(stack, ei.s, *std::max_element(ei.attackFrom.begin(), ei.attackFrom.end(), &willSecondHexBlockMoreEnemyShooters));
  127. }
  128. else
  129. {
  130. const EnemyInfo &ei= *std::min_element(enemiesUnreachable.begin(), enemiesUnreachable.end(), boost::bind(isCloser, _1, _2, boost::ref(dists)));
  131. if(distToNearestNeighbour(ei.s->position, dists) < BFIELD_SIZE)
  132. {
  133. return goTowards(stack, ei.s->position);
  134. }
  135. }
  136. return BattleAction::makeDefend(stack);
  137. }
  138. void CStupidAI::battleAttack(const BattleAttack *ba)
  139. {
  140. print("battleAttack called");
  141. }
  142. void CStupidAI::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa)
  143. {
  144. print("battleStacksAttacked called");
  145. }
  146. void CStupidAI::battleEnd(const BattleResult *br)
  147. {
  148. print("battleEnd called");
  149. }
  150. void CStupidAI::battleResultsApplied()
  151. {
  152. print("battleResultsApplied called");
  153. }
  154. void CStupidAI::battleNewRoundFirst(int round)
  155. {
  156. print("battleNewRoundFirst called");
  157. }
  158. void CStupidAI::battleNewRound(int round)
  159. {
  160. print("battleNewRound called");
  161. }
  162. void CStupidAI::battleStackMoved(const CStack * stack, THex dest, int distance, bool end)
  163. {
  164. print("battleStackMoved called");;
  165. }
  166. void CStupidAI::battleSpellCast(const BattleSpellCast *sc)
  167. {
  168. print("battleSpellCast called");
  169. }
  170. void CStupidAI::battleStacksEffectsSet(const SetStackEffect & sse)
  171. {
  172. print("battleStacksEffectsSet called");
  173. }
  174. void CStupidAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side)
  175. {
  176. print("battleStart called");
  177. side = Side;
  178. }
  179. void CStupidAI::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom)
  180. {
  181. print("battleStacksHealedRes called");
  182. }
  183. void CStupidAI::battleNewStackAppeared(const CStack * stack)
  184. {
  185. print("battleNewStackAppeared called");
  186. }
  187. void CStupidAI::battleObstaclesRemoved(const std::set<si32> & removedObstacles)
  188. {
  189. print("battleObstaclesRemoved called");
  190. }
  191. void CStupidAI::battleCatapultAttacked(const CatapultAttack & ca)
  192. {
  193. print("battleCatapultAttacked called");
  194. }
  195. void CStupidAI::battleStacksRemoved(const BattleStacksRemoved & bsr)
  196. {
  197. print("battleStacksRemoved called");
  198. }
  199. void CStupidAI::print(const std::string &text) const
  200. {
  201. tlog0 << "CStupidAI [" << this <<"]: " << text << std::endl;
  202. }
  203. BattleAction CStupidAI::goTowards(const CStack * stack, THex hex)
  204. {
  205. THex realDest = hex;
  206. THex predecessors[BFIELD_SIZE];
  207. std::vector<int> dists = cb->battleGetDistances(stack, hex);
  208. if(distToNearestNeighbour(hex, dists, &realDest) > BFIELD_SIZE)
  209. {
  210. print("goTowards: Cannot reach");
  211. return BattleAction::makeDefend(stack);
  212. }
  213. dists = cb->battleGetDistances(stack, realDest, predecessors);
  214. std::vector<THex> avHexes = cb->battleGetAvailableHexes(stack, false);
  215. while(1)
  216. {
  217. assert(realDest.isValid());
  218. if(vstd::contains(avHexes, hex))
  219. return BattleAction::makeMove(stack, hex);
  220. hex = predecessors[hex];
  221. }
  222. }