Advertisement
Guest User

ud1, code troopers 2013

a guest
Dec 14th, 2013
125
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 134.21 KB | None | 0 0
  1. #include "MyStrategy.h"
  2.  
  3. #define _USE_MATH_DEFINES
  4. #include <cmath>
  5. #include <cstdlib>
  6. #include <string>
  7. #include <set>
  8. #include <map>
  9. #include <algorithm>
  10. #include <cassert>
  11.  
  12. #define ENABLE_LOGGING 0
  13.  
  14. const char * trooperTypeNames [] = {"UNKNOWN_TROOPER", "COMMANDER", "FIELD_MEDIC", "SOLDIER", "SNIPER", "SCOUT"};
  15. int trooperMoveOrderIndex = 0;
  16.  
  17. #if ENABLE_LOGGING
  18. #include <iostream>
  19. #define LOG(x_) cout << g_world->getMoveIndex() << "-" << trooperMoveOrderIndex << "|" << g_self->getTeammateIndex() << "-" << trooperTypeNames[g_self->getType() + 1] << ":" << g_self->getHitpoints() << "|" << x_ << std::endl
  20. std::string pad(int l)
  21. {
  22.     std::string res;
  23.     for (int i = 0; i < l; ++i)
  24.         res += "----";
  25.     res += "]";
  26.        return res;
  27. }
  28.  
  29. //#define LOG_PAD(i, x) LOG(pad(i) << x)
  30. #define LOG_PAD(i, x)
  31.  
  32. #else
  33. #define LOG(x)
  34. #define LOG_PAD(i, x)
  35. #endif
  36.  
  37. #define INF_DIST 1000000
  38. #define W 30
  39. #define H 20
  40.  
  41. #define TOOPERS_COUNT 5
  42. #define COVER_KNEELING 20.0
  43. #define COVER_PRONE 50.0
  44.  
  45. int ENEMY_TROOPERSN;
  46.  
  47. using namespace model;
  48. using namespace std;
  49.  
  50. const World * g_world;
  51. const Trooper * g_self;
  52. const Game * g_game;
  53. Move * g_move;
  54. int moveIndex = -1;
  55. map<TrooperType, int> moveOrder;
  56. map<TrooperType, int> stuck;
  57.  
  58.  
  59. unsigned int sp_random(unsigned int range)
  60. {
  61.     static unsigned int seed = 1234567890;
  62.     seed = (seed * 58321) + 11113;
  63.     return (seed >> 16) % range;
  64. }
  65.  
  66. vector<const Trooper *> troopersMap;
  67.  
  68. struct Point
  69. {
  70.     int x, y;
  71.  
  72.     Point() {}
  73.     Point(int x, int y) : x(x), y(y) {}
  74.     Point(const Point &o) : x(o.x), y(o.y) {}
  75.     Point(const Unit &unit)
  76.     {
  77.         x = unit.getX();
  78.         y = unit.getY();
  79.     }
  80.  
  81.     bool isClose(const Point & o) const
  82.     {
  83.         int dx = abs(x - o.x);
  84.         int dy = abs(y - o.y);
  85.  
  86.         return dx == 0 && dy == 1 || dx == 1 && dy == 0;
  87.     }
  88.  
  89.     bool operator == (const Point & o) const
  90.     {
  91.         return x == o.x && y == o.y;
  92.     }
  93.  
  94.     Point & operator = (const Point & o)
  95.     {
  96.         x = o.x;
  97.         y = o.y;
  98.         return *this;
  99.     }
  100.  
  101.     bool operator < (const Point & o) const
  102.     {
  103.         return (y*W + x) < (o.y*W + o.x);
  104.     }
  105.  
  106.     int dist2(const Point &o) const
  107.     {
  108.         return (x - o.x)*(x - o.x) + (y - o.y)*(y - o.y);
  109.     }
  110.  
  111.     int sqDist(const Point &o) const
  112.     {
  113.         return abs(x - o.x) + abs(y - o.y);
  114.     }
  115. };
  116.  
  117. vector<Point> nearDistDeltas;
  118. vector<Point> aheadDistDeltas1;
  119. vector<Point> aheadDistDeltas2;
  120. vector<Point> sideDistDeltas1;
  121. vector<Point> sideDistDeltas2;
  122. vector<Point> backDistDeltas1;
  123. vector<Point> backDistDeltas2;
  124.  
  125. void initializeNearDistDeltas()
  126. {
  127.     nearDistDeltas.push_back(Point(0, 0));
  128.  
  129.     nearDistDeltas.push_back(Point(-1, 0));
  130.     nearDistDeltas.push_back(Point(1, 0));
  131.     nearDistDeltas.push_back(Point(0, -1));
  132.     nearDistDeltas.push_back(Point(0, 1));
  133.  
  134.     nearDistDeltas.push_back(Point(-1, -1));
  135.     nearDistDeltas.push_back(Point(-1, 1));
  136.     nearDistDeltas.push_back(Point(1, -1));
  137.     nearDistDeltas.push_back(Point(1, 1));
  138.  
  139.     nearDistDeltas.push_back(Point(-2, 0));
  140.     nearDistDeltas.push_back(Point(2, 0));
  141.     nearDistDeltas.push_back(Point(0, -2));
  142.     nearDistDeltas.push_back(Point(0, 2));
  143.  
  144.     nearDistDeltas.push_back(Point(-2, -1));
  145.     nearDistDeltas.push_back(Point(-2, 1));
  146.     nearDistDeltas.push_back(Point(2, -1));
  147.     nearDistDeltas.push_back(Point(2, 1));
  148.     nearDistDeltas.push_back(Point(-1, -2));
  149.     nearDistDeltas.push_back(Point(1, -2));
  150.     nearDistDeltas.push_back(Point(-1, 2));
  151.     nearDistDeltas.push_back(Point(1, 2));
  152.  
  153.     nearDistDeltas.push_back(Point(-2, -2));
  154.     nearDistDeltas.push_back(Point(-2, 2));
  155.     nearDistDeltas.push_back(Point(2, -2));
  156.     nearDistDeltas.push_back(Point(2, 2));
  157.  
  158.     nearDistDeltas.push_back(Point(-3, 0));
  159.     nearDistDeltas.push_back(Point(3, 0));
  160.     nearDistDeltas.push_back(Point(0, -3));
  161.     nearDistDeltas.push_back(Point(0, 3));
  162.  
  163.     nearDistDeltas.push_back(Point(-3, -1));
  164.     nearDistDeltas.push_back(Point(-3, 1));
  165.     nearDistDeltas.push_back(Point(3, -1));
  166.     nearDistDeltas.push_back(Point(3, 1));
  167.     nearDistDeltas.push_back(Point(-1, -3));
  168.     nearDistDeltas.push_back(Point(1, -3));
  169.     nearDistDeltas.push_back(Point(-1, 3));
  170.     nearDistDeltas.push_back(Point(1, 3));
  171.  
  172.     aheadDistDeltas1.push_back(Point(1, 0));
  173.     aheadDistDeltas1.push_back(Point(1, 1));
  174.     aheadDistDeltas1.push_back(Point(1, -1));
  175.  
  176.     aheadDistDeltas2.push_back(Point(2, 0));
  177.     aheadDistDeltas2.push_back(Point(2, 1));
  178.     aheadDistDeltas2.push_back(Point(2, -1));
  179.  
  180.     sideDistDeltas1.push_back(Point(0, -1));
  181.     sideDistDeltas1.push_back(Point(0, 1));
  182.  
  183.     sideDistDeltas2.push_back(Point(0, -2));
  184.     sideDistDeltas2.push_back(Point(0, 2));
  185.  
  186.     backDistDeltas1.push_back(Point(-1, 0));
  187.     backDistDeltas1.push_back(Point(-1, 1));
  188.     backDistDeltas1.push_back(Point(-1, -1));
  189.  
  190.     backDistDeltas2.push_back(Point(-2, 0));
  191.     backDistDeltas2.push_back(Point(-2, 1));
  192.     backDistDeltas2.push_back(Point(-2, -1));
  193. }
  194.  
  195. map<Point, int> bonusInUse;
  196.  
  197. bool checkBounds(const Point &p)
  198. {
  199.     if (p.x < 0 || p.x >= W || p.y < 0 || p.y >= H)
  200.         return false;
  201.     return true;
  202. }
  203.  
  204. bool checkPoint(const Point &p)
  205. {
  206.     return checkBounds(p) && g_world->getCells()[p.x][p.y] == FREE;
  207. }
  208.  
  209. struct Position : public Point
  210. {
  211.     int stance;
  212.  
  213.     Position() {}
  214.     Position(const Trooper &tr)
  215.     {
  216.         x = tr.getX();
  217.         y = tr.getY();
  218.         stance = (int) tr.getStance();
  219.     }
  220.     Position(int x, int y, int stance)
  221.     {
  222.         this->x = x;
  223.         this->y = y;
  224.         this->stance = stance;
  225.     }
  226.  
  227.     bool isClose(const Position & o) const
  228.     {
  229.         int dx = abs(x - o.x);
  230.         int dy = abs(y - o.y);
  231.         int ds = abs(stance - o.stance);
  232.  
  233.         return (dx == 0 && dy == 1 || dx == 1 && dy == 0) && ds == 0 || (dx == 0 && dy == 0 && ds == 1);
  234.     }
  235.  
  236.     bool isValid() const
  237.     {
  238.         return stance >= 0 && stance < _TROOPER_STANCE_COUNT_ && checkBounds(*this);
  239.     }
  240.  
  241.     bool operator == (const Position & o) const
  242.     {
  243.         return x == o.x && y == o.y && stance == o.stance;
  244.     }
  245.  
  246.     Position & operator = (const Position & o)
  247.     {
  248.         x = o.x;
  249.         y = o.y;
  250.         stance = o.stance;
  251.         return *this;
  252.     }
  253. };
  254.  
  255. struct TrooperId
  256. {
  257.     long long playerId;
  258.     int teammateIndex;
  259.  
  260.     TrooperId() {}
  261.  
  262.     TrooperId(const Trooper & t)
  263.     {
  264.         teammateIndex = t.getTeammateIndex();
  265.         playerId = t.getPlayerId();
  266.     }
  267.  
  268.     TrooperId(const TrooperId & o)
  269.     {
  270.         playerId = o.playerId;
  271.         teammateIndex = o.teammateIndex;
  272.     }
  273.  
  274.     TrooperId & operator = (const TrooperId & o)
  275.     {
  276.         playerId = o.playerId;
  277.         teammateIndex = o.teammateIndex;
  278.         return *this;
  279.     }
  280.  
  281.     bool operator == (const TrooperId & o) const
  282.     {
  283.         return teammateIndex == o.teammateIndex && playerId == o.playerId;
  284.     }
  285.  
  286.     bool operator < (const TrooperId &o) const
  287.     {
  288.         if (playerId < o.playerId)
  289.             return true;
  290.  
  291.         if (playerId > o.playerId)
  292.             return false;
  293.  
  294.         return teammateIndex < o.teammateIndex;
  295.     }
  296. };
  297.  
  298. struct Enemy
  299. {
  300.     Position pos;
  301.     int hitPoints;
  302.     TrooperId id;
  303.     TrooperType type;
  304.     int lastSeenMoveIndex;
  305.     int lastSeenMoveOrderIndex;
  306.     bool hasGrenade;
  307.     bool hasMedikit;
  308.     bool hasFieldRation;
  309.  
  310.     bool isConfirmed() const
  311.     {
  312.         if (lastSeenMoveIndex == moveIndex && lastSeenMoveOrderIndex == trooperMoveOrderIndex)
  313.             return true;
  314.  
  315.         int enemyMoveIndex = moveOrder.count(type) ? moveOrder[type] : 0;
  316.         if (lastSeenMoveIndex == moveIndex)
  317.         {
  318.             return enemyMoveIndex > trooperMoveOrderIndex;
  319.         }
  320.  
  321.         if (lastSeenMoveIndex == (moveIndex - 1))
  322.         {
  323.             return enemyMoveIndex < lastSeenMoveOrderIndex && enemyMoveIndex > trooperMoveOrderIndex;
  324.         }
  325.  
  326.         return false;
  327.     }
  328.  
  329.     bool isProbable() const
  330.     {
  331.         return (moveIndex - lastSeenMoveIndex) <= 2;
  332.     }
  333. };
  334.  
  335. #define NO_BONUS (-2)
  336.  
  337. class FieldMap
  338. {
  339. public:
  340.     vector<int> bonuses;
  341.  
  342.     typedef map<TrooperId, Enemy> Enemies;
  343.     Enemies enemies;
  344.  
  345.     bool hasEnemies() const
  346.     {
  347.         for (Enemies::const_iterator it = enemies.begin(); it != enemies.end(); ++it)
  348.         {
  349.             const Enemy &enemy = it->second;
  350.  
  351.             if (enemy.isConfirmed() || enemy.isProbable())
  352.                 return true;
  353.         }
  354.  
  355.         return false;
  356.     }
  357.  
  358.     void initialize()
  359.     {
  360.         bonuses.resize(W*H);
  361.         for (int i = 0; i < W*H; ++i)
  362.             bonuses[i] = (int) UNKNOWN_BONUS;
  363.  
  364.         lastPoints = -1;
  365.     }
  366.  
  367.     int &getBonus(int x, int y)
  368.     {
  369.         return bonuses[y * W + x];
  370.     }
  371.  
  372.     Enemy *get(const TrooperId &id)
  373.     {
  374.         Enemies::iterator it = enemies.find(id);
  375.         if (it == enemies.end())
  376.             return NULL;
  377.  
  378.         return  &it->second;
  379.     }
  380.  
  381.     void update()
  382.     {
  383.         const vector<Trooper> &troopers = g_world->getTroopers();
  384.         vector<const Trooper *> myTroopers;
  385.         set<TrooperId> confirmedTroopers;
  386.  
  387.         for (int i = 0; i < troopers.size(); ++i)
  388.         {
  389.             const Trooper &trooper = troopers[i];
  390.             if (!trooper.isTeammate())
  391.             {
  392.                 TrooperId id = TrooperId(trooper);
  393.                 Enemy &e = enemies[id];
  394.  
  395.                 e.pos = Position(trooper);
  396.                 e.hitPoints = trooper.getHitpoints();
  397.                 e.id = id;
  398.                 e.type = trooper.getType();
  399.                 e.lastSeenMoveIndex = moveIndex;
  400.                 e.lastSeenMoveOrderIndex = trooperMoveOrderIndex;
  401.                 e.hasGrenade = trooper.isHoldingGrenade();
  402.                 e.hasMedikit = trooper.isHoldingMedikit();
  403.                 e.hasFieldRation = trooper.isHoldingFieldRation();
  404.                 confirmedTroopers.insert(id);
  405.             }
  406.             else
  407.             {
  408.                 myTroopers.push_back(&trooper);
  409.             }
  410.         }
  411.  
  412.         for (int y = 0; y < H; ++y)
  413.         {
  414.             for (int x = 0; x < W; ++x)
  415.             {
  416.                 bool isVisible = false;
  417.                 for (int i = 0; i < myTroopers.size(); ++i)
  418.                 {
  419.                     const Trooper *trooper = myTroopers[i];
  420.  
  421.                     isVisible = g_world->isVisible(trooper->getVisionRange(), trooper->getX(), trooper->getY(), trooper->getStance(), x, y, PRONE);
  422.                     if (isVisible)
  423.                         break;
  424.                 }
  425.  
  426.                 if (isVisible)
  427.                 {
  428.                     getBonus(x, y) = NO_BONUS;
  429.  
  430.                     for (Enemies::iterator it = enemies.begin(); it != enemies.end(); ++it)
  431.                     {
  432.                         Enemy &enemy = it->second;
  433.                         if (!confirmedTroopers.count(enemy.id))
  434.                         {
  435.                             if ((Point &) enemy.pos == Point(x, y))
  436.                             {
  437.                                 enemies.erase(it);
  438.                                 break;
  439.                             }
  440.                         }
  441.                     }
  442.                 }
  443.             }
  444.         }
  445.  
  446.         const std::vector<Bonus> &bns = g_world->getBonuses();
  447.         for (int i = 0; i < bns.size(); ++i)
  448.         {
  449.             const Bonus &bonus = bns[i];
  450.             int x = bonus.getX();
  451.             int y = bonus.getY();
  452.             getBonus(bonus.getX(), bonus.getY()) = bonus.getType();
  453.  
  454.             int x1 = W - x - 1;
  455.             int y1 = H - y- 1;
  456.  
  457.             if (getBonus(x1, y) == (int) UNKNOWN_BONUS)
  458.                 getBonus(x1, y) = bonus.getType();
  459.  
  460.             if (getBonus(x, y1) == (int) UNKNOWN_BONUS)
  461.                 getBonus(x, y1) = bonus.getType();
  462.  
  463.             if (getBonus(x1, y1) == (int) UNKNOWN_BONUS)
  464.                 getBonus(x1, y1) = bonus.getType();
  465.         }
  466.  
  467.         if (lastPoints >= 0)
  468.         {
  469.             if (lastActionType == SHOOT)
  470.             {
  471.                 int points = g_world->getPlayers()[g_self->getPlayerId()].getScore();
  472.  
  473.                 Enemies::iterator it;
  474.                 for (it = enemies.begin(); it != enemies.end(); ++it)
  475.                 {
  476.                     Enemy &enemy = it->second;
  477.                     if (!confirmedTroopers.count(enemy.id))
  478.                     {
  479.                         if ((Point &) enemy.pos == lastActionPoint)
  480.                         {
  481.  
  482.                             break;
  483.                         }
  484.                     }
  485.                 }
  486.                 if (it != enemies.end())
  487.                 {
  488.                     if (points == lastPoints)
  489.                     {
  490.                         enemies.erase(it);
  491.                     }
  492.                     else
  493.                     {
  494.                         Enemy &enemy = it->second;
  495.                         enemy.lastSeenMoveIndex = moveIndex;
  496.                         enemy.lastSeenMoveOrderIndex = trooperMoveOrderIndex;
  497.                     }
  498.                 }
  499.             }
  500.         }
  501.     }
  502.  
  503.     void updateAfterMove()
  504.     {
  505.         lastActionType = g_move->getAction();
  506.         lastActionPoint = Point(g_move->getX(), g_move->getY());
  507.         lastPoints = g_world->getPlayers()[g_self->getPlayerId()].getScore();
  508.  
  509.         if (g_move->getAction() == SHOOT)
  510.         {
  511.             Point shootPos = Point(g_move->getX(), g_move->getY());
  512.  
  513.             for (Enemies::iterator it = enemies.begin(); it != enemies.end(); ++it)
  514.             {
  515.                 Enemy &e = it->second;
  516.                 if (Point(e.pos) == shootPos)
  517.                 {
  518.                     int damage = g_self->getDamage(g_self->getStance());
  519.                     makeDamage(e, it, damage);
  520.                     return;
  521.                 }
  522.             }
  523.         }
  524.         else if (g_move->getAction() == THROW_GRENADE)
  525.         {
  526.             Point throwPos = Point(g_move->getX(), g_move->getY());
  527.             for (Enemies::iterator it = enemies.begin(); it != enemies.end();)
  528.             {
  529.                 Enemy &e = it->second;
  530.                 if (Point(e.pos) == throwPos)
  531.                 {
  532.                     int damage = g_game->getGrenadeDirectDamage();
  533.                     makeDamage(e, it++, damage);
  534.                 }
  535.                 else if (Point(e.pos).isClose(throwPos))
  536.                 {
  537.                     int damage = g_game->getGrenadeCollateralDamage();
  538.                     makeDamage(e, it++, damage);
  539.                 }
  540.                 else
  541.                 {
  542.                     ++it;
  543.                 }
  544.             }
  545.         }
  546.     }
  547.  
  548.     void makeDamage(Enemy &e, const Enemies::iterator &it, int damage)
  549.     {
  550.         if (damage >= e.hitPoints)
  551.         {
  552.             enemies.erase(it);
  553.         }
  554.         else
  555.         {
  556.             e.hitPoints -= damage;
  557.         }
  558.     }
  559.  
  560.     Point lastActionPoint;
  561.     ActionType lastActionType;
  562.     int lastPoints;
  563.  
  564. } fieldMap;
  565.  
  566. struct TrooperDistributionMap
  567. {
  568.     vector<double> probabilities;
  569.     double sum;
  570.     int lastUpdateMoveIndex;
  571.     int lastUpdateTroopMoveIndex;
  572.  
  573.     void initialize()
  574.     {
  575.         probabilities.resize(W*H);
  576.  
  577.         const vector<Trooper> &troopers = g_world->getTroopers();
  578.  
  579.         for (int i = 0; i < W*H; ++i)
  580.             probabilities[i] = 0.0;
  581.  
  582.         sum = 0.0;
  583.         for (int i = 0; i < troopers.size(); ++i)
  584.         {
  585.             const Trooper &trooper = troopers[i];
  586.             if (trooper.isTeammate())
  587.             {
  588.                 int x = trooper.getX();
  589.                 int y = trooper.getY();
  590.  
  591.                 probabilities[(H - y - 1)*W + x] = 1.0;
  592.                 probabilities[(H - y - 1)*W + (W - x - 1)] = 1.0;
  593.                 probabilities[y*W + (W - x - 1)] = 1.0;
  594.                 sum += 3.0;
  595.             }
  596.         }
  597.  
  598.         lastUpdateMoveIndex = 0;
  599.         lastUpdateTroopMoveIndex = 0;
  600.     }
  601.  
  602.     void update()
  603.     {
  604.         int rounds = 1;
  605.         if (moveIndex == lastUpdateMoveIndex)
  606.         {
  607.             if (trooperMoveOrderIndex != lastUpdateTroopMoveIndex)
  608.                 rounds += (trooperMoveOrderIndex - lastUpdateTroopMoveIndex - 1) * 4;
  609.         }
  610.         else
  611.         {
  612.             rounds += (ENEMY_TROOPERSN / 3 - lastUpdateTroopMoveIndex - 1) * 4;
  613.         }
  614.  
  615.         LOG("rounds " << rounds);
  616.  
  617.         lastUpdateMoveIndex = moveIndex;
  618.         lastUpdateTroopMoveIndex = trooperMoveOrderIndex;
  619.  
  620.         vector<double> newProbabilities(W*H);
  621.         for (int i = 0; i < W*H; ++i)
  622.            newProbabilities[i] = 0.0;
  623.  
  624.         const vector<Trooper> &troopers = g_world->getTroopers();
  625.         vector<const Trooper *> myTroopers;
  626.  
  627.         for (int i = 0; i < troopers.size(); ++i)
  628.         {
  629.             const Trooper &trooper = troopers[i];
  630.             if (trooper.isTeammate())
  631.             {
  632.                 myTroopers.push_back(&trooper);
  633.             }
  634.         }
  635.  
  636.         vector<bool> visibilityMap(W*H);
  637.         for (int y = 0; y < H; ++y)
  638.         {
  639.             for (int x = 0; x < W; ++x)
  640.             {
  641.                 bool isVisible = false;
  642.                 for (int i = 0; i < myTroopers.size(); ++i)
  643.                 {
  644.                     const Trooper *trooper = myTroopers[i];
  645.  
  646.                     isVisible = g_world->isVisible(trooper->getVisionRange(), trooper->getX(), trooper->getY(), trooper->getStance(), x, y, PRONE);
  647.  
  648.                     if (isVisible)
  649.                         break;
  650.                 }
  651.                 visibilityMap[y*W + x] = isVisible;
  652.                 if (isVisible)
  653.                     probabilities[y*W + x] = 0.0;
  654.             }
  655.         }
  656.  
  657.         const vector<vector<CellType> >&cells = g_world->getCells();
  658.  
  659.         for (int r = 0; r < rounds; ++r)
  660.         {
  661.             for (int y = 0; y < H; ++y)
  662.             {
  663.                 for (int x = 0; x < W; ++x)
  664.                 {
  665.                     if (g_world->getCells()[x][y] != FREE)
  666.                     {
  667.                         newProbabilities[y*W + x] = 0.0;
  668.                     }
  669.                     else
  670.                     {
  671.                         double surN = 0;
  672.                         double val = probabilities[y*W + x];
  673.  
  674.                         if (x > 0 && cells[x - 1][y] == FREE)
  675.                             surN++;
  676.                         if (y > 0 && cells[x][y - 1] == FREE)
  677.                             surN++;
  678.                         if ((x + 1) < W && cells[x + 1][y] == FREE)
  679.                             surN++;
  680.                         if ((y + 1) < H && cells[x][y + 1] == FREE)
  681.                             surN++;
  682.  
  683.                         double alpha = 0.2;
  684.                         val = val/(alpha + (1.0 - alpha)*surN);
  685.                         double cv = val * alpha;
  686.                         double sv = (1.0 - alpha) * val;
  687.  
  688.                         newProbabilities[y*W + x] += cv;
  689.                         if (x > 0 && cells[x - 1][y] == FREE)
  690.                             newProbabilities[y*W + (x - 1)] += sv;
  691.  
  692.                         if (y > 0 && cells[x][y - 1] == FREE)
  693.                             newProbabilities[(y - 1)*W + x] += sv;
  694.  
  695.                         if ((x + 1) < W && cells[x + 1][y] == FREE)
  696.                             newProbabilities[y*W + (x + 1)] += sv;
  697.  
  698.                         if ((y + 1) < H && cells[x][y + 1] == FREE)
  699.                             newProbabilities[(y + 1)*W + x] += sv;
  700.                     }
  701.                 }
  702.             }
  703.  
  704.             probabilities.swap(newProbabilities);
  705.         }
  706.  
  707.         for (int i = 0; i < W*H; ++i)
  708.         {
  709.             if (visibilityMap[i])
  710.                 probabilities[i] = 0.0;
  711.         }
  712.  
  713.         sum = 0.0;
  714.         for (int i = 0; i < W*H; ++i)
  715.            sum += probabilities[i];
  716.  
  717.         double koef = (ENEMY_TROOPERSN - (troopers.size() - myTroopers.size())) / sum;
  718.         for (int i = 0; i < W*H; ++i)
  719.            probabilities[i] *= koef;
  720.  
  721.         for (int i = 0; i < troopers.size(); ++i)
  722.         {
  723.             const Trooper &trooper = troopers[i];
  724.             if (!trooper.isTeammate())
  725.             {
  726.                 int x = trooper.getX();
  727.                 int y = trooper.getY();
  728.                 probabilities[y*W + x] = 1.0;
  729.                 sum++;
  730.             }
  731.         }
  732.     }
  733.  
  734.     void log()
  735.     {
  736.         #if ENABLE_LOGGING
  737.  
  738.         for (int y = 0; y < H; ++y)
  739.         {
  740.             cout << "|";
  741.             for (int x = 0; x < W; ++x)
  742.             {
  743.                 double v = probabilities[y*W + x];
  744.  
  745.                 int i;
  746.                 for (i = 0; i < 10; ++i)
  747.                 {
  748.                     if (v >= 1.0)
  749.                     {
  750.                         cout << (9 - i);
  751.                         break;
  752.                     }
  753.                     else
  754.                     {
  755.                         v *= 2.0;
  756.                     }
  757.                 }
  758.  
  759.                 if (i == 10)
  760.                 {
  761.                     cout << 0;
  762.                 }
  763.             }
  764.             cout << "|" << std::endl;
  765.         }
  766.  
  767.         cout << std::endl;
  768.         cout << "SUM " << sum << std::endl;
  769.         #endif
  770.     }
  771.  
  772.     double get(const Point &p) const
  773.     {
  774.         return probabilities[p.y*W + p.x];
  775.     }
  776.  
  777. } trooperDistributionMap;
  778.  
  779. const Trooper *getTrooper(const Point &p)
  780. {
  781.     if (!checkBounds(p))
  782.         return NULL;
  783.     return troopersMap[p.y * W + p.x];
  784. }
  785.  
  786. #define CLOSE_POINTS_N 5
  787.  
  788. Point getClosePoints(const Point &p, int k)
  789. {
  790.     if (k == 0)
  791.         return p;
  792.  
  793.     if (k == 1)
  794.         return Point(p.x + 1, p.y);
  795.  
  796.     if (k == 2)
  797.         return Point(p.x - 1, p.y);
  798.  
  799.     if (k == 3)
  800.         return Point(p.x, p.y + 1);
  801.  
  802.     if (k == 4)
  803.         return Point(p.x, p.y - 1);
  804.  
  805.     assert(false);
  806. }
  807.  
  808. bool isPointFree(const Point &p, const TrooperId *id, bool ignoreTeammates = false)
  809. {
  810.     if (!checkBounds(p))
  811.         return false;
  812.  
  813.     if (g_world->getCells()[p.x][p.y] != FREE)
  814.         return false;
  815.  
  816.     const Trooper *trooper = getTrooper(p);
  817.     return !trooper || !id || (TrooperId(*trooper) == *id) || ignoreTeammates && trooper->isTeammate();
  818. }
  819.  
  820. bool isPointFree(const Point &p, const Trooper *self, bool ignoreTeammates = false)
  821. {
  822.     if (self)
  823.     {
  824.         TrooperId id = TrooperId(*self);
  825.         return isPointFree(p, &id, ignoreTeammates);
  826.     }
  827.  
  828.     return isPointFree(p, (const TrooperId *) NULL, ignoreTeammates);
  829. }
  830.  
  831. Point getRandomPoint(const Trooper *self)
  832. {
  833.     int rounds = 0;
  834.     while(1)
  835.     {
  836.         ++rounds;
  837.         int x = (int) sp_random((unsigned int) W);
  838.         int y = (int) sp_random((unsigned int) H);
  839.  
  840.         Point result = Point(x, y);
  841.         if (isPointFree(result, self))
  842.             return result;
  843.  
  844.         if (rounds > 1000)
  845.         {
  846.             LOG("getRandomPoint doesn't work");
  847.             return Point(W / 2, H / 2);
  848.         }
  849.     }
  850. }
  851.  
  852. void fit(Point &p)
  853. {
  854.     if (p.x < 0)
  855.         p.x = 0;
  856.     if (p.y < 0)
  857.         p.y = 0;
  858.     if (p.x >= W)
  859.         p.x = W - 1;
  860.     if (p.y >= H)
  861.         p.y = H - 1;
  862. }
  863.  
  864. double getPointCover(const Point &p, TrooperStance stance)
  865. {
  866.     int r = 9;
  867.     Point p1 = Point(p.x - r, p.y - r);
  868.     Point p2 = Point(p.x + r, p.y + r);
  869.     fit(p1);
  870.     fit(p2);
  871.  
  872.     double res = 0.0;
  873.     for (int x = p1.x; x <= p2.x; ++x)
  874.     {
  875.         for (int y = p1.y; y <= p2.y; ++y)
  876.         {
  877.             if (g_world->getCells()[x][y] == FREE)
  878.             {
  879.                 int c = 0;
  880.                 if (g_world->isVisible(10.0, x, y, STANDING, p.x, p.y, STANDING))
  881.                     c++;
  882.                 if (g_world->isVisible(10.0, x, y, STANDING, p.x, p.y, stance))
  883.                     c--;
  884.  
  885.                 if (c)
  886.                 {
  887.                     double prob = trooperDistributionMap.probabilities[y * W + x];
  888.                     int dist2 = Point(x, y).dist2(p);
  889.                     if (dist2 <= 25)
  890.                         res += 100.0*prob;
  891.                     else if (dist2 <= 36)
  892.                         res += 80.0*prob;
  893.                     else
  894.                         res += 50.0*prob;
  895.                 }
  896.             }
  897.         }
  898.     }
  899.  
  900.     return res;
  901. }
  902.  
  903. int getViewRadius(TrooperType t)
  904. {
  905.     if (t == COMMANDER)
  906.         return 8;
  907.  
  908.     if (t == SOLDIER)
  909.         return 7;
  910.  
  911.     if (t == FIELD_MEDIC)
  912.         return 7;
  913.  
  914.     if (t == SNIPER)
  915.         return 7;
  916.  
  917.     if (t == SCOUT)
  918.         return 9;
  919.  
  920.     return 8;
  921. }
  922.  
  923. double estimateDanger(const Point &p, TrooperType type)
  924. {
  925.     int r = 9;
  926.     Point p1 = Point(p.x - r, p.y - r);
  927.     Point p2 = Point(p.x + r, p.y + r);
  928.     fit(p1);
  929.     fit(p2);
  930.  
  931.     double res = 0.0;
  932.     double viewRad = getViewRadius(type);
  933.     for (int x = p1.x; x <= p2.x; ++x)
  934.     {
  935.         for (int y = p1.y; y <= p2.y; ++y)
  936.         {
  937.             if (g_world->getCells()[x][y] == FREE)
  938.             {
  939.                 Point d = Point(x, y);
  940.                 double prob = trooperDistributionMap.get(d);
  941.                 int dist2 = d.dist2(p);
  942.  
  943.                 int c = 0;
  944.                 if (g_world->isVisible(10.0, x, y, STANDING, p.x, p.y, STANDING))
  945.                     c++;
  946.                 if (g_world->isVisible(viewRad, x, y, STANDING, p.x, p.y, STANDING))
  947.                     c--;
  948.  
  949.                 if (c)
  950.                 {
  951.                     res += prob * 50.0;
  952.                 }
  953.                 if (dist2 <= 25)
  954.                     res += prob * 80.0;
  955.             }
  956.         }
  957.     }
  958.     return res;
  959. }
  960.  
  961. bool isHoldingBonus(const Trooper &trooper, BonusType bonusType)
  962. {
  963.     switch (bonusType)
  964.     {
  965.     case GRENADE:
  966.         return trooper.isHoldingGrenade();
  967.     case MEDIKIT:
  968.         return trooper.isHoldingMedikit();
  969.     case FIELD_RATION:
  970.         return trooper.isHoldingFieldRation();
  971.     }
  972.     return true;
  973. }
  974.  
  975. int getMoveCost(int stance)
  976. {
  977.     if ((TrooperStance) stance == PRONE)
  978.         return g_game->getProneMoveCost();
  979.  
  980.     if ((TrooperStance) stance == KNEELING)
  981.         return g_game->getKneelingMoveCost();
  982.  
  983.     if ((TrooperStance) stance == STANDING)
  984.         return g_game->getStandingMoveCost();
  985.  
  986.     assert(false);
  987.     return 0;
  988. }
  989.  
  990. int getBonusPoints(bool hasBonus, BonusType bonusType)
  991. {
  992.     switch (bonusType)
  993.     {
  994.     case GRENADE:
  995.         return hasBonus ? 0 : 5;
  996.     case MEDIKIT:
  997.         return hasBonus ? 0 : 10;
  998.     case FIELD_RATION:
  999.         return hasBonus ? 0 : 5;
  1000.     }
  1001.     return 0;
  1002. }
  1003.  
  1004. const Trooper *findTeamTrooper(int index)
  1005. {
  1006.     const vector<Trooper>& troopers = g_world->getTroopers();
  1007.     for (int i = 0; i < troopers.size(); ++i)
  1008.     {
  1009.         const Trooper &trooper = troopers[i];
  1010.         if (trooper.isTeammate())
  1011.         {
  1012.             if (trooper.getTeammateIndex() == index)
  1013.                 return &trooper;
  1014.         }
  1015.     }
  1016.  
  1017.     return NULL;
  1018. }
  1019.  
  1020. const Trooper *findTrooper(const TrooperId &id)
  1021. {
  1022.     const vector<Trooper>& troopers = g_world->getTroopers();
  1023.     for (int i = 0; i < troopers.size(); ++i)
  1024.     {
  1025.         const Trooper &trooper = troopers[i];
  1026.         if (TrooperId(trooper) == id)
  1027.         {
  1028.             return &trooper;
  1029.         }
  1030.     }
  1031.  
  1032.     return NULL;
  1033. }
  1034.  
  1035. int getDamage(TrooperType t, TrooperStance s)
  1036. {
  1037.     if (t == COMMANDER)
  1038.     {
  1039.         if (s == STANDING)
  1040.             return 15;
  1041.         if (s == KNEELING)
  1042.             return 20;
  1043.         if (s == PRONE)
  1044.             return 25;
  1045.     }
  1046.  
  1047.     if (t == SOLDIER)
  1048.     {
  1049.         if (s == STANDING)
  1050.             return 25;
  1051.         if (s == KNEELING)
  1052.             return 30;
  1053.         if (s == PRONE)
  1054.             return 35;
  1055.     }
  1056.  
  1057.     if (t == FIELD_MEDIC)
  1058.     {
  1059.         if (s == STANDING)
  1060.             return 9;
  1061.         if (s == KNEELING)
  1062.             return 12;
  1063.         if (s == PRONE)
  1064.             return 15;
  1065.     }
  1066.  
  1067.     if (t == SNIPER)
  1068.     {
  1069.         if (s == STANDING)
  1070.             return 65;
  1071.         if (s == KNEELING)
  1072.             return 80;
  1073.         if (s == PRONE)
  1074.             return 95;
  1075.     }
  1076.  
  1077.     if (t == SCOUT)
  1078.     {
  1079.         if (s == STANDING)
  1080.             return 20;
  1081.         if (s == KNEELING)
  1082.             return 25;
  1083.         if (s == PRONE)
  1084.             return 30;
  1085.     }
  1086.     return 20;
  1087. }
  1088.  
  1089. int getShootCost(TrooperType t)
  1090. {
  1091.     if (t == COMMANDER)
  1092.         return 3;
  1093.  
  1094.     if (t == SOLDIER)
  1095.         return 4;
  1096.  
  1097.     if (t == FIELD_MEDIC)
  1098.         return 2;
  1099.  
  1100.     if (t == SNIPER)
  1101.         return 9;
  1102.  
  1103.     if (t == SCOUT)
  1104.         return 4;
  1105.  
  1106.     return 3;
  1107. }
  1108.  
  1109. int getShootRange(TrooperType t)
  1110. {
  1111.     if (t == COMMANDER)
  1112.         return 7;
  1113.  
  1114.     if (t == SOLDIER)
  1115.         return 8;
  1116.  
  1117.     if (t == FIELD_MEDIC)
  1118.         return 5;
  1119.  
  1120.     if (t == SNIPER)
  1121.         return 10;
  1122.  
  1123.     if (t == SCOUT)
  1124.         return 6;
  1125.  
  1126.     return 8;
  1127. }
  1128.  
  1129. const int getDanger(const Trooper &self, const Point &p)
  1130. {
  1131.     int result = 0;
  1132.     int dist2 = 100*100;
  1133.     for (FieldMap::Enemies::iterator it = fieldMap.enemies.begin(); it != fieldMap.enemies.end(); ++it)
  1134.     {
  1135.         Enemy &e = it->second;
  1136.         Point trooperPoint = e.pos;
  1137.  
  1138.         int curDist2 = trooperPoint.dist2(p);
  1139.         if (dist2 > curDist2)
  1140.             dist2 = curDist2;
  1141.  
  1142.         bool canShoot = g_world->isVisible(8,
  1143.             trooperPoint.x, trooperPoint.y, STANDING,
  1144.             p.x, p.y, self.getStance());
  1145.  
  1146.         int trooperDanger = 0;
  1147.         if (canShoot)
  1148.         {
  1149.             trooperDanger = getDamage(e.type, (TrooperStance) e.pos.stance)*(10/getShootCost(e.type));
  1150.         }
  1151.  
  1152.         for (int k = CLOSE_POINTS_N; k --> 0;)
  1153.         {
  1154.             Point cp = getClosePoints(p, k);
  1155.             if (cp.dist2(trooperPoint) <= g_game->getGrenadeThrowRange()*g_game->getGrenadeThrowRange() && checkBounds(cp))
  1156.             {
  1157.                 int damage = (cp == p) ? g_game->getGrenadeDirectDamage() : g_game->getGrenadeCollateralDamage();
  1158.                 if (canShoot)
  1159.                     damage += getShootCost(e.type);
  1160.                 if (trooperDanger < damage)
  1161.                     trooperDanger = damage;
  1162.             }
  1163.         }
  1164.  
  1165.         result += trooperDanger;
  1166.     }
  1167.  
  1168.     if (dist2 >= 81)
  1169.         dist2 = 100*100;
  1170.  
  1171.     return result*1000 + 1000 - (int) sqrt((double) (dist2 * 100));
  1172. }
  1173.  
  1174. void logMap(const vector<Position> *path)
  1175. {
  1176.     if (!ENABLE_LOGGING)
  1177.         return;
  1178.  
  1179.     const vector<vector<CellType> >& cells = g_world->getCells();
  1180.     const vector<Bonus> & bonuses = g_world->getBonuses();
  1181.     LOG("--------------------------------");
  1182.     for (int y = 0; y < g_world->getHeight(); ++y)
  1183.     {
  1184.         string rowStr = "|";
  1185.         for (int x = 0; x < g_world->getWidth(); ++x)
  1186.         {
  1187.             CellType cellType = cells[x][y];
  1188.             char ch;
  1189.             switch (cellType) {
  1190. case UNKNOWN_CELL:
  1191.     ch = 'U';
  1192.     break;
  1193. case FREE:
  1194.     ch = ' ';
  1195.     break;
  1196. case LOW_COVER:
  1197.     ch = '1';
  1198.     break;
  1199. case MEDIUM_COVER:
  1200.     ch = '2';
  1201.     break;
  1202. case HIGH_COVER:
  1203.     ch = '3';
  1204.     break;
  1205. default:
  1206.     break;
  1207.             }
  1208.  
  1209.             if (fieldMap.getBonus(x, y) >= 0)
  1210.             {
  1211.                 BonusType type = (BonusType) fieldMap.getBonus(x, y);
  1212.                 switch (type) {
  1213.             case UNKNOWN_BONUS:
  1214.                 ch = 'u';
  1215.                 break;
  1216.             case GRENADE:
  1217.                 ch = 'G';
  1218.                 break;
  1219.             case MEDIKIT:
  1220.                 ch = 'A';
  1221.                 break;
  1222.             case FIELD_RATION:
  1223.                 ch = 'F';
  1224.                 break;
  1225.                 }
  1226.             }
  1227.  
  1228.             if (path)
  1229.             {
  1230.                 for (int i = 0; i < path->size(); ++i)
  1231.                 {
  1232.                     Position p = (*path)[i];
  1233.                     if (p.x == x && p.y == y)
  1234.                     {
  1235.                         ch = 'X';
  1236.                         break;
  1237.                     }
  1238.                 }
  1239.             }
  1240.  
  1241.             if (troopersMap[y * W + x])
  1242.             {
  1243.                 const Trooper *trooper = troopersMap[y * W + x];
  1244.                 TrooperType type = trooper->getType();
  1245.                 if (trooper->isTeammate())
  1246.                 {
  1247.                     if (type == COMMANDER)
  1248.                     {
  1249.                         ch = 'C';
  1250.                     }
  1251.                     else if (type == FIELD_MEDIC)
  1252.                     {
  1253.                         ch = 'M';
  1254.                     }
  1255.                     else if(type == SOLDIER)
  1256.                     {
  1257.                         ch = 'S';
  1258.                     }
  1259.                 }
  1260.                 else
  1261.                 {
  1262.                     if (type == COMMANDER)
  1263.                     {
  1264.                         ch = 'c';
  1265.                     }
  1266.                     else if (type == FIELD_MEDIC)
  1267.                     {
  1268.                         ch = 'm';
  1269.                     }
  1270.                     else if(type == SOLDIER)
  1271.                     {
  1272.                         ch = 's';
  1273.                     }
  1274.                 }
  1275.             }
  1276.  
  1277.             rowStr += ch;
  1278.         }
  1279.         rowStr += "|";
  1280.         LOG(rowStr);
  1281.     }
  1282.     LOG("--------------------------------");
  1283. }
  1284.  
  1285. const Trooper *findTeamTrooperByType(TrooperType type);
  1286.  
  1287. class MapView
  1288. {
  1289. public:
  1290.     virtual bool isPointFree(const Point &p, const TrooperId &id, bool ignoreTeammates = false) = 0;
  1291. };
  1292.  
  1293. class DefaultMapView : public MapView
  1294. {
  1295.     virtual bool isPointFree(const Point &p, const TrooperId &id, bool ignoreTeammates = false)
  1296.     {
  1297.         return ::isPointFree(p, &id, ignoreTeammates);
  1298.     }
  1299. } defaultMapView;
  1300.  
  1301. class WalkMap
  1302. {
  1303. public:
  1304.     struct PtVal
  1305.     {
  1306.         int dist;
  1307.         //int bonuses; // TODO
  1308.         //int cover; // TODO
  1309.         Position from;
  1310.  
  1311.         PtVal()
  1312.         {
  1313.             dist = INF_DIST;
  1314.             //bonuses = 0;
  1315.             //cover = 0;
  1316.         }
  1317.  
  1318.         void operator = (const PtVal & o)
  1319.         {
  1320.             dist = o.dist;
  1321.             //bonuses = o.bonuses;
  1322.             //cover = o.cover;
  1323.             from = o.from;
  1324.         }
  1325.  
  1326.         void log() const
  1327.         {
  1328.             LOG("Pt " << dist << " " << from.x << " " << from.y << " " << from.stance);
  1329.         }
  1330.     };
  1331.  
  1332.     vector<PtVal> vals;
  1333.     bool ignoreTeammates;
  1334.     Position from;
  1335.     WalkMap(bool ignoreTeammates = false)
  1336.     {
  1337.         vals.resize(W*H*_TROOPER_STANCE_COUNT_);
  1338.         this->ignoreTeammates = ignoreTeammates;
  1339.     }
  1340.  
  1341.     void log()
  1342.     {
  1343. #if ENABLE_LOGGING
  1344.  
  1345.         for (int y = 0; y < H; ++y)
  1346.         {
  1347.             for (int x = 0; x < W; ++x)
  1348.             {
  1349.                 int dist = get(Position(x, y, STANDING)).dist;
  1350.  
  1351.                 if (dist >= INF_DIST)
  1352.                     dist = -1;
  1353.  
  1354.                 cout.width(2);
  1355.                 cout << dist << " ";
  1356.             }
  1357.             cout << std::endl;
  1358.         }
  1359.         cout << std::endl;
  1360. #endif
  1361.     }
  1362.  
  1363.     PtVal &get(const Position &p)
  1364.     {
  1365.         int ind = (p.y * W + p.x) * _TROOPER_STANCE_COUNT_ + (int) p.stance;
  1366.         return vals[ind];
  1367.     }
  1368.  
  1369.     const PtVal &get(const Position &p) const
  1370.     {
  1371.         int ind = (p.y * W + p.x) * _TROOPER_STANCE_COUNT_ + (int) p.stance;
  1372.         return vals[ind];
  1373.     }
  1374.  
  1375.     void build(const Trooper *trooper, int maxCost = -1, MapView *mapView = &defaultMapView)
  1376.     {
  1377.         return build(Position(*trooper), TrooperId(*trooper), maxCost, mapView);
  1378.     }
  1379.  
  1380.     void build(const Position &from, const TrooperId &id, int maxCost = -1, MapView *mapView = &defaultMapView)
  1381.     {
  1382.         this->from = from;
  1383.         PtVal &f = get(from);
  1384.         f.dist = 0;
  1385.  
  1386.         vector<Position> positions;
  1387.         positions.reserve(W*H*3 + 1);
  1388.  
  1389.         positions.push_back(from);
  1390.  
  1391.         int i = 0;
  1392.         while (i < positions.size())
  1393.         {
  1394.             Position p = positions[i++];
  1395.             PtVal &oldPtVal = get(p);
  1396.  
  1397.             if (maxCost != -1 && oldPtVal.dist > maxCost)
  1398.                 return;
  1399.  
  1400.             for (int k = 0; k < 6; ++k)
  1401.             {
  1402.                 int points;
  1403.                 Position newp = p;
  1404.                 if (k == 0)
  1405.                 {
  1406.                     newp.x++;
  1407.                     points = getMoveCost(p.stance);
  1408.                 }
  1409.                 else if (k == 1)
  1410.                 {
  1411.                     newp.x--;
  1412.                     points = getMoveCost(p.stance);
  1413.                 }
  1414.                 else if (k == 2)
  1415.                 {
  1416.                     newp.y++;
  1417.                     points = getMoveCost(p.stance);
  1418.                 }
  1419.                 else if (k == 3)
  1420.                 {
  1421.                     newp.y--;
  1422.                     points = getMoveCost(p.stance);
  1423.                 }
  1424.                 else if (k == 4)
  1425.                 {
  1426.                     newp.stance++;
  1427.                     points = g_game->getStanceChangeCost();
  1428.                 }
  1429.                 else if (k == 5)
  1430.                 {
  1431.                     newp.stance--;
  1432.                     points = g_game->getStanceChangeCost();
  1433.                 }
  1434.  
  1435.                 if (!newp.isValid())
  1436.                     continue;
  1437.  
  1438.                 PtVal &newPtVal = get(newp);
  1439.                 if (newPtVal.dist >= INF_DIST)
  1440.                 {
  1441.                     if (mapView->isPointFree(newp, id, ignoreTeammates))
  1442.                     {
  1443.                         newPtVal.dist = oldPtVal.dist + points;
  1444.                         newPtVal.from = p;
  1445.                         positions.push_back(newp);
  1446.                     }
  1447.                 }
  1448.             }
  1449.         }
  1450.     }
  1451.  
  1452.     void getPath(const Position &destination, vector<Position> &path, bool standing = true)
  1453.     {
  1454.         LOG("findPath " << from.x << " " << from.y);
  1455.  
  1456.         PtVal t;
  1457.  
  1458.         if (standing)
  1459.             t = get(Position(destination.x, destination.y, STANDING));
  1460.         else
  1461.             t = get(destination);
  1462.  
  1463.         path.clear();
  1464.         if (t.dist < INF_DIST && t.dist > 0)
  1465.         {
  1466.             Position p = destination;
  1467.             path.push_back(p);
  1468.  
  1469.             while (!(p == from))
  1470.             {
  1471.                 WalkMap::PtVal &val = get(p);
  1472.  
  1473.                 p = val.from;
  1474.                 path.push_back(p);
  1475.             }
  1476.  
  1477.             reverse(path.begin(), path.end());
  1478.         }
  1479.     }
  1480. };
  1481.  
  1482. enum FightActionDetailsType
  1483. {
  1484.     AD_NONE,
  1485.     AD_FIRE,
  1486.     AD_THROW_GRENADE,
  1487.     AD_HEAL_YOURSELF,
  1488.     AD_HEAL_YOURSELF_BY_MEDIKIT,
  1489.     AD_HEAL
  1490. };
  1491.  
  1492. const char* fightActionDetailsTypeNames[] = {"AD_NONE", "AD_FIRE", "AD_THROW_GRENADE", "AD_HEAL_YOURSELF", "AD_HEAL_YOURSELF_BY_MEDIKIT", "AD_HEAL"};
  1493.  
  1494. struct FightActionDetails
  1495. {
  1496.     FightActionDetails()
  1497.     {
  1498.         shootsN = 0;
  1499.     }
  1500.  
  1501.     FightActionDetailsType type;
  1502.     bool eat;
  1503.     Position from;
  1504.     Point to;
  1505.     TrooperId enemyId;
  1506.     Position evacuationPos;
  1507.     int shootsN;
  1508.  
  1509.     void log()
  1510.     {
  1511.         LOG("FightActionDetails: " << fightActionDetailsTypeNames[type]);
  1512.         LOG("eat " << eat);
  1513.         LOG("from: " << from.x << " " << from.y << " " << from.stance);
  1514.         LOG("to: " << to.x << " " << to.y);
  1515.         LOG("shootsN: " << shootsN);
  1516.         LOG("evacuationPos: " << evacuationPos.x << " " << evacuationPos.y << " " << evacuationPos.stance);
  1517.     }
  1518. };
  1519.  
  1520. struct TrooperState
  1521. {
  1522.     int hitPoints;
  1523. };
  1524.  
  1525. enum CoordinatedActionType
  1526. {
  1527.     AT_NONE,
  1528.     AT_FIGHT,
  1529.     AT_REGROUP,
  1530.     AT_COLLECT_BONUSES,
  1531.     AT_GOTO_RANDOM_POINT,
  1532.     AT_STOP
  1533. };
  1534.  
  1535. const char *coordinatedActionTypeNames[] = {"AT_NONE", "AT_FIGHT", "AT_REGROUP", "AT_COLLECT_BONUSES", "AT_GOTO_RANDOM_POINT", "AT_STOP"};
  1536.  
  1537. int getChangeCost(const Position &from, const Position &to)
  1538. {
  1539.     if (from == to)
  1540.         return 0;
  1541.  
  1542.     if (from.x == to.x && from.y == to.y)
  1543.         return g_game->getStanceChangeCost();
  1544.  
  1545.     return getMoveCost(from.stance);
  1546. }
  1547.  
  1548. enum NearPosType
  1549. {
  1550.     NP_AHEAD,
  1551.     NP_SIDE,
  1552.     NP_BACK,
  1553.     NP_OTHER
  1554. };
  1555.  
  1556. const char *nearPosTypeName[] = {"NP_AHEAD", "NP_SIDE", "NP_BACK", "NP_OTHER"};
  1557.  
  1558. bool findNearPoint(const Point &src, const Point &aheadDir, Point &out, const vector<Point> &deltas, const set<Point> &reserved, const WalkMap &walkMap)
  1559. {
  1560.     bool result = false;
  1561.     int dist = INF_DIST;
  1562.  
  1563.     Point p;
  1564.     Point sideDir = Point(aheadDir.y, - aheadDir.x);
  1565.     for (size_t i = 0; i < deltas.size(); ++i)
  1566.     {
  1567.         p = src;
  1568.         const Point &delta = deltas[i];
  1569.         p.x += aheadDir.x * delta.x + sideDir.x * delta.y;
  1570.         p.y += aheadDir.y * delta.x + sideDir.y * delta.y;
  1571.  
  1572.         if (checkPoint(p) && isPointFree(p, (const TrooperId *) NULL) && !reserved.count(p))
  1573.         {
  1574.             int curDist = walkMap.get(Position(p.x, p.y, STANDING)).dist;
  1575.  
  1576.             LOG("findNearPoint " << p.x << " " << p.y << " " << curDist << " " << dist);
  1577.             if (dist >= INF_DIST || dist > curDist)
  1578.             {
  1579.                 dist = curDist;
  1580.                 out = p;
  1581.                 result = true;
  1582.             }
  1583.         }
  1584.     }
  1585.  
  1586.     return result;
  1587. }
  1588.  
  1589. bool getNearPosition(const vector<Position> &path, int index, const NearPosType type, Position &out, const set<Point> &reserved, const WalkMap &walkMap)
  1590. {
  1591.     Point dir;
  1592.     int dind = index;
  1593.  
  1594.     if ((dind + 1) < path.size())
  1595.         dind++;
  1596.  
  1597.     if (path.size() == 0)
  1598.     {
  1599.         LOG("ERROR getNearPosition index == 0");
  1600.         return false;
  1601.     }
  1602.  
  1603.     dir = Point(1, 0);
  1604.     if (path.size() == 1)
  1605.     {
  1606.         LOG("getNearPosition index == 1");
  1607.     }
  1608.     else
  1609.     {
  1610.         Point nextPoint = path[dind];
  1611.         for (int i = dind; i --> 0;)
  1612.         {
  1613.             Point curPoint = path[i];
  1614.             if (!(nextPoint == curPoint))
  1615.             {
  1616.                 dir = Point(nextPoint.x - curPoint.x, nextPoint.y - curPoint.y);
  1617.                 LOG("getNearPosition " << nearPosTypeName[type] << " " << nextPoint.x << " " << nextPoint.y << "<--" << curPoint.x << " " << curPoint.y);
  1618.                 break;
  1619.             }
  1620.         }
  1621.     }
  1622.  
  1623.     Point side = Point(dir.y, -dir.x);
  1624.  
  1625.     if (type == NP_AHEAD)
  1626.     {
  1627.         if (findNearPoint(path[index], dir, out, aheadDistDeltas1, reserved, walkMap))
  1628.             return true;
  1629.  
  1630.         if (findNearPoint(path[index], dir, out, aheadDistDeltas2, reserved, walkMap))
  1631.             return true;
  1632.  
  1633.         return false;
  1634.     }
  1635.     else if (type == NP_SIDE)
  1636.     {
  1637.         if (findNearPoint(path[index], dir, out, sideDistDeltas1, reserved, walkMap))
  1638.             return true;
  1639.  
  1640.         if (findNearPoint(path[index], dir, out, sideDistDeltas2, reserved, walkMap))
  1641.             return true;
  1642.  
  1643.         return false;
  1644.     }
  1645.     else if (type == NP_BACK)
  1646.     {
  1647.         if (findNearPoint(path[index], dir, out, backDistDeltas1, reserved, walkMap))
  1648.             return true;
  1649.  
  1650.         if (findNearPoint(path[index], dir, out, backDistDeltas2, reserved, walkMap))
  1651.             return true;
  1652.  
  1653.         return false;
  1654.     }
  1655.     else
  1656.     {
  1657.         for (int i = 0; i < nearDistDeltas.size(); ++i)
  1658.         {
  1659.             out = path[index];
  1660.             out.x += nearDistDeltas[i].x;
  1661.             out.y += nearDistDeltas[i].y;
  1662.             if (isPointFree(out, (const TrooperId *) NULL) && !reserved.count(out))
  1663.                 return true;
  1664.         }
  1665.     }
  1666.  
  1667.     return false;
  1668. }
  1669.  
  1670. bool hasBonus(BonusType bt, const Trooper *trooper)
  1671. {
  1672.     return bt == (int) MEDIKIT && trooper->isHoldingMedikit() ||
  1673.         bt == (int) FIELD_RATION && trooper->isHoldingFieldRation() ||
  1674.         bt == (int) GRENADE && trooper->isHoldingGrenade();
  1675. }
  1676.  
  1677. struct TrooperStatus : public Enemy
  1678. {
  1679.     bool isTeammate;
  1680.     int actionPoints;
  1681.  
  1682.     void log()
  1683.     {
  1684.         LOG("TrooperStatus: " << (isTeammate ? "my " : "ememy ") << id.playerId << " " << trooperTypeNames[type + 1]);
  1685.         LOG("hitPoints: " << hitPoints);
  1686.         LOG("pos: " << pos.x << " " << pos.y << " " << pos.stance);
  1687.         LOG("actionPoints: " << actionPoints);
  1688.     }
  1689. };
  1690.  
  1691. struct SimulationMapView : public MapView
  1692. {
  1693.     map<Point, TrooperId> usedPoints;
  1694.     SimulationMapView(const vector <TrooperStatus> &allTroopers)
  1695.     {
  1696.         for (int i = 0; i < allTroopers.size(); ++i)
  1697.         {
  1698.             const TrooperStatus &ts = allTroopers[i];
  1699.             if (ts.hitPoints > 0)
  1700.             {
  1701.                 usedPoints[ts.pos] = ts.id;
  1702.             }
  1703.         }
  1704.     }
  1705.  
  1706.     virtual bool isPointFree(const Point &p, const TrooperId &id, bool ignoreTeammates = false)
  1707.     {
  1708.         if (!checkBounds(p))
  1709.             return false;
  1710.  
  1711.         if (g_world->getCells()[p.x][p.y] != FREE)
  1712.             return false;
  1713.  
  1714.         if (!usedPoints.count(p))
  1715.             return true;
  1716.  
  1717.         TrooperId &tid = usedPoints[p];
  1718.  
  1719.         if (ignoreTeammates && tid.playerId == g_self->getPlayerId())
  1720.             return true;
  1721.  
  1722.         return tid == id;
  1723.     }
  1724. };
  1725.  
  1726. #define MAX_ACTIONS 10
  1727. struct FightCounters
  1728. {
  1729.     void clean()
  1730.     {
  1731.         for (int i = 0; i < MAX_ACTIONS; ++i)
  1732.         {
  1733.             computeFightTeammate[i] = 0;
  1734.             computeFightAfterMove[i] = 0;
  1735.             computeFightAfterShoot[i] = 0;
  1736.         }
  1737.     }
  1738.  
  1739.     void log()
  1740.     {
  1741.         LOG("STATS");
  1742.         for (int i = 0; i < count; ++i)
  1743.         {
  1744.             LOG(i << " computeFightTeammate " << computeFightTeammate[i]);
  1745.             LOG(i << " computeFightAfterMove " << computeFightAfterMove[i]);
  1746.             LOG(i << " computeFightAfterShoot " << computeFightAfterShoot[i]);
  1747.         }
  1748.         LOG("END STATS");
  1749.     }
  1750.  
  1751.     int count;
  1752.     int computeFightTeammate[MAX_ACTIONS];
  1753.     int computeFightAfterMove[MAX_ACTIONS];
  1754.     int computeFightAfterShoot[MAX_ACTIONS];
  1755. };
  1756.  
  1757. class CoordinationCenter
  1758. {
  1759. public:
  1760.     Point bonusPoints[TOOPERS_COUNT];
  1761.     Position goToPositions[TOOPERS_COUNT];
  1762.     map<TrooperType, FightActionDetails> detailsMap;
  1763.     const Trooper *troopersByMoveOrder[TOOPERS_COUNT];
  1764.     const Trooper *troopers[TOOPERS_COUNT];
  1765.     TrooperState oldStates[TOOPERS_COUNT];
  1766.     TrooperState newStates[TOOPERS_COUNT];
  1767.     map<TrooperType, int> typeIndexMap;
  1768.     CoordinatedActionType actionType;
  1769.     bool hasLastRandomPoint;
  1770.     Point lastRandomPoint;
  1771.     TrooperType stopTrooperType;
  1772.     bool enemyFound;
  1773.     FightCounters counters;
  1774.  
  1775.     CoordinationCenter()
  1776.     {
  1777.         hasLastRandomPoint = false;
  1778.     }
  1779.  
  1780.     void updateMissions()
  1781.     {
  1782.         updateTroopers();
  1783.         updateCurrentState();
  1784.         actionType = AT_NONE;
  1785.         enemyFound = false;
  1786.  
  1787.         if (hasEnemies())
  1788.         {
  1789.             LOG("he");
  1790.             enemyFound = true;
  1791.             computeFight();
  1792.         }
  1793.         else if (hadDamageFromInvisibleEnemy())
  1794.         {
  1795.             LOG("hd");
  1796.             computeRegroup();
  1797.         }
  1798.         else if (needBonuses())
  1799.         {
  1800.             LOG("nb");
  1801.             computeCollectBonuses();
  1802.         }
  1803.         else
  1804.         {
  1805.             LOG("gr");
  1806.             computeGoToRandomPoint();
  1807.         }
  1808.  
  1809.         log();
  1810.     }
  1811.  
  1812.     void log()
  1813.     {
  1814. #if ENABLE_LOGGING
  1815.         LOG("coordinatedActionType " << coordinatedActionTypeNames[actionType]);
  1816.  
  1817.         if (actionType == AT_GOTO_RANDOM_POINT || actionType == AT_COLLECT_BONUSES)
  1818.         {
  1819.             for (int i = 0; i < TOOPERS_COUNT; ++i)
  1820.             {
  1821.                 const Trooper *trooper = troopersByMoveOrder[i];
  1822.                 if (trooper)
  1823.                 {
  1824.                     Position pos = goToPositions[trooper->getTeammateIndex()];
  1825.                     LOG("GoTo Point " << trooperTypeNames[trooper->getType() + 1] << " " << pos.x << " " << pos.y << " " << pos.stance);
  1826.                 }
  1827.             }
  1828.         }
  1829. #endif
  1830.     }
  1831.  
  1832.     void updateTroopers()
  1833.     {
  1834.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  1835.         {
  1836.             troopers[i] = NULL;
  1837.             troopersByMoveOrder[i] = NULL;
  1838.         }
  1839.  
  1840.         typeIndexMap.clear();
  1841.         int j = trooperMoveOrderIndex;
  1842.         const vector<Trooper>& trs = g_world->getTroopers();
  1843.         for (int i = 0; i < trs.size(); ++i)
  1844.         {
  1845.             const Trooper &trooper = trs[i];
  1846.             if (trooper.isTeammate())
  1847.             {
  1848.                 TrooperType type = trooper.getType();
  1849.                 if (moveOrder.count(type))
  1850.                 {
  1851.                     troopersByMoveOrder[moveOrder[type]] = &trooper;
  1852.                 }
  1853.                 else
  1854.                 {
  1855.                     troopersByMoveOrder[++j] = &trooper;
  1856.                 }
  1857.                 troopers[trooper.getTeammateIndex()] = &trooper;
  1858.                 typeIndexMap[trooper.getType()] = trooper.getTeammateIndex();
  1859.             }
  1860.         }
  1861.     }
  1862.  
  1863.     void updateCurrentState()
  1864.     {
  1865.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  1866.         {
  1867.             const Trooper *trooper = troopersByMoveOrder[i];
  1868.             if (trooper)
  1869.             {
  1870.                 TrooperState &state = newStates[trooper->getTeammateIndex()];
  1871.                 state.hitPoints = trooper->getHitpoints();
  1872.             }
  1873.         }
  1874.     }
  1875.  
  1876.     void updateState()
  1877.     {
  1878.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  1879.         {
  1880.             oldStates[i] = newStates[i];
  1881.         }
  1882.     }
  1883.  
  1884.     bool hasEnemies()
  1885.     {
  1886.         for (FieldMap::Enemies::iterator it = fieldMap.enemies.begin(); it != fieldMap.enemies.end(); ++it)
  1887.         {
  1888.             Enemy &e = it->second;
  1889.             if (e.isConfirmed() || e.isProbable())
  1890.                 return true;
  1891.         }
  1892.  
  1893.         return false;
  1894.     }
  1895.  
  1896.     bool hadDamageFromInvisibleEnemy()
  1897.     {
  1898.         if (moveIndex == 0 && trooperMoveOrderIndex == 0)
  1899.             return false;
  1900.  
  1901.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  1902.         {
  1903.             const Trooper *trooper = troopersByMoveOrder[i];
  1904.             if (trooper)
  1905.             {
  1906.                 TrooperState &state = newStates[trooper->getTeammateIndex()];
  1907.                 TrooperState &oldState = oldStates[trooper->getTeammateIndex()];
  1908.                 if (state.hitPoints < oldState.hitPoints)
  1909.                     return true;
  1910.             }
  1911.         }
  1912.  
  1913.         return false;
  1914.     }
  1915.  
  1916.     bool needBonuses()
  1917.     {
  1918.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  1919.         {
  1920.             const Trooper *trooper = troopersByMoveOrder[i];
  1921.             if (trooper)
  1922.             {
  1923.                 if (!(trooper->isHoldingFieldRation() && trooper->isHoldingGrenade() && trooper->isHoldingMedikit()))
  1924.                     return true;
  1925.             }
  1926.         }
  1927.         return false;
  1928.     }
  1929.  
  1930.     void computeFight()
  1931.     {
  1932.         //return ;
  1933.         actionType = AT_FIGHT;
  1934.  
  1935.         vector <TrooperStatus> allTroopers;
  1936.         allTroopers.push_back(TrooperStatus());
  1937.         TrooperStatus &ts = allTroopers[0];
  1938.         ts.hitPoints = g_self->getHitpoints();
  1939.         ts.isTeammate = true;
  1940.         ts.pos = Position(*g_self);
  1941.         ts.type = g_self->getType();
  1942.         ts.actionPoints = g_self->getActionPoints();
  1943.         ts.id = TrooperId(*g_self);
  1944.         ts.hasGrenade = g_self->isHoldingGrenade();
  1945.         ts.hasMedikit = g_self->isHoldingMedikit();
  1946.         ts.hasFieldRation = g_self->isHoldingFieldRation();
  1947.         if (g_self->isHoldingFieldRation())
  1948.             ts.actionPoints += 3;
  1949.  
  1950.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  1951.         {
  1952.             int subMoveInd = (trooperMoveOrderIndex + i) % TOOPERS_COUNT;
  1953.             for (int type = 0; type < TOOPERS_COUNT; ++type)
  1954.             {
  1955.                 if (moveOrder[(TrooperType) type] == subMoveInd)
  1956.                 {
  1957.                     for (FieldMap::Enemies::iterator it = fieldMap.enemies.begin(); it != fieldMap.enemies.end(); ++it)
  1958.                     {
  1959.                         Enemy &enemy = it->second;
  1960.  
  1961.                         if ((enemy.isConfirmed() || enemy.isProbable()) && enemy.type == type)
  1962.                         {
  1963.                             allTroopers.push_back(TrooperStatus());
  1964.                             (Enemy &) allTroopers[allTroopers.size() - 1] = enemy;
  1965.                             allTroopers[allTroopers.size() - 1].isTeammate = false;
  1966.                             if (allTroopers[allTroopers.size() - 1].actionPoints < 10)
  1967.                                 allTroopers[allTroopers.size() - 1].actionPoints = 10;
  1968.                         }
  1969.                     }
  1970.  
  1971.                     if (i > 0)
  1972.                     {
  1973.                         const Trooper * teamTrooper = findTeamTrooperByType((TrooperType) type);
  1974.                         if (teamTrooper)
  1975.                         {
  1976.                             allTroopers.push_back(TrooperStatus());
  1977.                             TrooperStatus &ts = allTroopers[allTroopers.size() - 1];
  1978.                             ts.hitPoints = teamTrooper->getHitpoints();
  1979.                             ts.isTeammate = true;
  1980.                             ts.pos = Position(*teamTrooper);
  1981.                             ts.type = teamTrooper->getType();
  1982.                             ts.actionPoints = 10;
  1983.                             ts.id = TrooperId(*teamTrooper);
  1984.                             ts.hasGrenade = teamTrooper->isHoldingGrenade();
  1985.                             ts.hasMedikit = teamTrooper->isHoldingMedikit();
  1986.                             ts.hasFieldRation = teamTrooper->isHoldingFieldRation();
  1987.                             if (teamTrooper->isHoldingFieldRation())
  1988.                                 ts.actionPoints += 3;
  1989.                         }
  1990.                     }
  1991.                 }
  1992.             }
  1993.         }
  1994.  
  1995.         vector<FightActionDetails> details;
  1996.         details.resize(allTroopers.size());
  1997.         for (int i = 0; i < details.size(); ++i)
  1998.         {
  1999.             details[i].type = AD_NONE;
  2000.         }
  2001.  
  2002.         counters.clean();
  2003.         counters.count = allTroopers.size();
  2004.         LOG("=========== Compute fight ===========");
  2005.         logMap(NULL);
  2006.         for (int i = 0; i < allTroopers.size(); ++i)
  2007.             allTroopers[i].log();
  2008.  
  2009.         int maxResult = -1000000;
  2010.         computeFight(allTroopers, 0, details, 0, maxResult);
  2011.         LOG("=========== RESULTS Compute fight ===========");
  2012.         LOG("maxResult " << maxResult);
  2013.         for (int i = 0; i < details.size(); ++i)
  2014.         {
  2015.             details[i].log();
  2016.         }
  2017.         LOG("=========== END Compute fight ===========");
  2018.  
  2019.         for (int i = 0; i < details.size(); ++i)
  2020.         {
  2021.             if (allTroopers[i].isTeammate)
  2022.             {
  2023.                 detailsMap[allTroopers[i].type] = details[i];
  2024.             }
  2025.             details[i].log();
  2026.         }
  2027.         counters.log();
  2028.  
  2029.         return;
  2030.     }
  2031.  
  2032.     int computeFightNext(vector <TrooperStatus> &allTroopers, int ind, vector<FightActionDetails> &details, int result, int &maxResult)
  2033.     {
  2034.         ind++;
  2035.         if (ind == allTroopers.size())
  2036.         {
  2037.             if (result > maxResult)
  2038.                 maxResult = result;
  2039.  
  2040.             return result;
  2041.         }
  2042.  
  2043.         return computeFight(allTroopers, ind, details, result, maxResult);
  2044.     }
  2045.  
  2046.     int computeFight(vector <TrooperStatus> &allTroopers, int ind, vector<FightActionDetails> &details, int result, int &maxResult)
  2047.     {
  2048.         LOG_PAD(ind, "call computeFight " << ind << " result:" << result << " maxResult:" << maxResult);
  2049.         /*for (int i = 0; i < allTroopers.size(); ++i)
  2050.             allTroopers[i].log();*/
  2051.  
  2052.         TrooperStatus &ts = allTroopers[ind];
  2053.         if (ts.hitPoints > 0)
  2054.         {
  2055.             if (ts.isTeammate)
  2056.             {
  2057.                 return computeFightTeammate(allTroopers, ind, details, result, maxResult);
  2058.             }
  2059.             else
  2060.             {
  2061.                 return computeFightEnemy(allTroopers, ind, details, result, maxResult);
  2062.             }
  2063.         }
  2064.  
  2065.         return computeFightNext(allTroopers, ind, details, result, maxResult);
  2066.     }
  2067.  
  2068.     int computeFightTeammate(vector <TrooperStatus> &allTroopers, int ind, vector<FightActionDetails> &details, int result, int &maxResult)
  2069.     {
  2070.         LOG_PAD(ind, "computeFightTeammate " << ind);
  2071.         TrooperStatus &ts = allTroopers[ind];
  2072.         SimulationMapView mapView = SimulationMapView(allTroopers);
  2073.         WalkMap walkMap;
  2074.  
  2075.         int ap = ts.actionPoints;
  2076.         if ((ind == 1 || ind == 2) && ap > 2)
  2077.             ap = 2;
  2078.         else if (ind >= 3)
  2079.             ap = 0;
  2080.  
  2081.         walkMap.build(ts.pos, ts.id, ap, &mapView);
  2082.  
  2083.         int r = (ind == 0) ? 2 : 1;
  2084.         Point p1 = Point(ts.pos.x - r, ts.pos.y - r);
  2085.         Point p2 = Point(ts.pos.x + r, ts.pos.y + r);
  2086.         fit(p1);
  2087.         fit(p2);
  2088.  
  2089.         int maxCalculatedResult = -1000000;
  2090.         for (int x = p1.x; x <= p2.x; ++x)
  2091.         {
  2092.             for (int y = p1.y; y <= p2.y; ++y)
  2093.             {
  2094.                 for (int s = 0; s < 3; ++s)
  2095.                 {
  2096.                     if (abs(s - ts.pos.stance) > 1)
  2097.                         continue;
  2098.  
  2099.                     WalkMap::PtVal &ptVal = walkMap.get(Position(x, y, s));
  2100.                     LOG_PAD(ind, "PtVal " << x << " " << y << " " << s << " " << ptVal.dist);
  2101.                     if (ptVal.dist < INF_DIST)
  2102.                     {
  2103.                         if (ptVal.dist <= ap)
  2104.                         {
  2105.                             counters.computeFightTeammate[ind]++;
  2106.                             int oldActionPoints = ts.actionPoints ;
  2107.                             ts.actionPoints -= ptVal.dist;
  2108.  
  2109.                             Position oldPos = ts.pos;
  2110.                             ts.pos = Position(x, y, s);
  2111.  
  2112.                             LOG_PAD(ind, "move i" << ind << " x" << x << " y" << y << " s" << s << " ap" << ts.actionPoints);
  2113.                             int calculatedResult = computeFightAfterMove(allTroopers, ind, details, result, maxResult);
  2114.                             LOG_PAD(ind, "computeFightTeammate " << ind << " " << calculatedResult);
  2115.  
  2116.                             if (calculatedResult > maxCalculatedResult)
  2117.                             {
  2118.                                 maxCalculatedResult = calculatedResult;
  2119.                             }
  2120.  
  2121.                             if (calculatedResult >= maxResult)
  2122.                             {
  2123.                                 FightActionDetails &thisDetails = details[ind];
  2124.                                 thisDetails.from = Position(x, y, s);
  2125.  
  2126.                                 if (ind == 0)
  2127.                                 {
  2128.                                     LOG("+++1 " << calculatedResult);
  2129.                                     for (int i = 0; i < details.size(); ++i)
  2130.                                         details[i].log();
  2131.                                 }
  2132.                             }
  2133.  
  2134.                             ts.pos = oldPos;
  2135.                             ts.actionPoints = oldActionPoints;
  2136.                         }
  2137.                     }
  2138.                 }
  2139.             }
  2140.         }
  2141.  
  2142.         return maxCalculatedResult;
  2143.     }
  2144.  
  2145.     int computeFightEnemy(vector <TrooperStatus> &allTroopers, int ind, vector<FightActionDetails> &details, int result, int &maxResult)
  2146.     {
  2147.         LOG_PAD(ind, "computeFightEnemy " << ind);
  2148.         TrooperStatus &ts = allTroopers[ind];
  2149.         int shootRange = getShootRange(ts.type);
  2150.         int shootDamage = getDamage(ts.type, KNEELING);
  2151.         int indToShoot = -1;
  2152.         int health = 1000;
  2153.         int grenageRange = g_game->getGrenadeThrowRange();
  2154.         bool hasGrenade = ts.hasGrenade;
  2155.         int shootCost = getShootCost(ts.type);
  2156.         int viewRad = getViewRadius(ts.type);
  2157.         int maxShoots = ts.actionPoints / shootCost;
  2158.  
  2159.         int inGrenadeRangeN = 0;
  2160.         for (int i = 0; i < allTroopers.size(); ++i)
  2161.         {
  2162.             TrooperStatus &tr = allTroopers[i];
  2163.             if (tr.isTeammate && tr.hitPoints > 0)
  2164.             {
  2165.                 bool isVisible = g_world->isVisible(shootRange, ts.pos.x, ts.pos.y, STANDING, tr.pos.x, tr.pos.y, (TrooperStance) tr.pos.stance);
  2166.                 if (isVisible)
  2167.                 {
  2168.                     if (health > tr.hitPoints)
  2169.                     {
  2170.                         health = tr.hitPoints;
  2171.                         indToShoot = i;
  2172.                     }
  2173.                     tr.hitPoints -= 5;
  2174.                     result -= 5;
  2175.                 }
  2176.  
  2177.                 bool isViewable = g_world->isVisible(viewRad, ts.pos.x, ts.pos.y, STANDING, tr.pos.x, tr.pos.y, (TrooperStance) tr.pos.stance);
  2178.                 if (isViewable)
  2179.                 {
  2180.                     health = tr.hitPoints;
  2181.                     tr.hitPoints -= 2;
  2182.                     result -= 2;
  2183.                 }
  2184.  
  2185.                 if (hasGrenade)
  2186.                 {
  2187.                     int dist2 = ts.pos.dist2(tr.pos);
  2188.                     if (dist2 <= (grenageRange + 1) * (grenageRange + 1))
  2189.                     {
  2190.                         inGrenadeRangeN++;
  2191.                     }
  2192.                 }
  2193.             }
  2194.         }
  2195.  
  2196.         if (hasGrenade && inGrenadeRangeN)
  2197.         {
  2198.             int damage = 60/inGrenadeRangeN;
  2199.             for (int i = 0; i < allTroopers.size(); ++i)
  2200.             {
  2201.                 TrooperStatus &tr = allTroopers[i];
  2202.                 if (tr.isTeammate && tr.hitPoints > 0)
  2203.                 {
  2204.                     int dist2 = ts.pos.dist2(tr.pos);
  2205.                     if (dist2 <= (grenageRange) * (grenageRange))
  2206.                     {
  2207.                         int dmg = damage * 1.4;
  2208.                         tr.hitPoints -= dmg;
  2209.                         result -= dmg;
  2210.                     }
  2211.                     else if (dist2 <= (grenageRange + 1) * (grenageRange + 1))
  2212.                     {
  2213.                         int dmg = damage;
  2214.                         tr.hitPoints -= dmg;
  2215.                         result -= dmg;
  2216.                     }
  2217.                 }
  2218.             }
  2219.         }
  2220.  
  2221.         int oldHitpoints;
  2222.         if (indToShoot != -1)
  2223.         {
  2224.             LOG_PAD(ind, "Enemy shoot " << trooperTypeNames[allTroopers[indToShoot].type + 1]);
  2225.             oldHitpoints = allTroopers[indToShoot].hitPoints;
  2226.             allTroopers[indToShoot].hitPoints -= shootDamage*maxShoots;
  2227.             result -= shootDamage*maxShoots;
  2228.  
  2229.             if (allTroopers[indToShoot].hitPoints <= 0)
  2230.             {
  2231.                 result -= allTroopers[indToShoot].hitPoints;
  2232.                 result -= 50;
  2233.             }
  2234.         }
  2235.         else
  2236.         {
  2237.             LOG_PAD(ind, "Enemy can't shoot");
  2238.         }
  2239.  
  2240.         int calculatedResult = computeFightNext(allTroopers, ind, details, result, maxResult);
  2241.         LOG_PAD(ind, "calculatedResult computeFightEnemy " << ind << " = " << calculatedResult);
  2242.         if (calculatedResult >= maxResult)
  2243.         {
  2244.             FightActionDetails &thisDetails = details[ind];
  2245.             thisDetails.from = ts.pos;
  2246.             thisDetails.evacuationPos = ts.pos;
  2247.             if (indToShoot != -1)
  2248.             {
  2249.                 thisDetails.to = allTroopers[indToShoot].pos;
  2250.                 thisDetails.type = AD_FIRE;
  2251.                 thisDetails.shootsN = maxShoots;
  2252.             }
  2253.             else
  2254.             {
  2255.                 thisDetails.to = Point(-1, -1);
  2256.                 thisDetails.type = AD_NONE;
  2257.             }
  2258.         }
  2259.  
  2260.         if (indToShoot != -1)
  2261.         {
  2262.             allTroopers[indToShoot].hitPoints = oldHitpoints;
  2263.         }
  2264.  
  2265.         return calculatedResult;
  2266.     }
  2267.  
  2268.     int computeFightAfterMove(vector <TrooperStatus> &allTroopers, int ind, vector<FightActionDetails> &details, int result, int &maxResult)
  2269.     {
  2270.         LOG_PAD(ind, "computeFightAfterMove " << ind);
  2271.         TrooperStatus &ts = allTroopers[ind];
  2272.         int shootCost = getShootCost(ts.type);
  2273.  
  2274.         int maxShoots = ts.actionPoints / shootCost;
  2275.         int damage = getDamage(ts.type, (TrooperStance) ts.pos.stance);
  2276.  
  2277.         double shootRange = getShootRange(ts.type);
  2278.  
  2279.         vector<TrooperStatus *> visibleEnemies;
  2280.         for (int i = 0; i < allTroopers.size(); ++i)
  2281.         {
  2282.             TrooperStatus &target = allTroopers[i];
  2283.             if (!target.isTeammate && target.hitPoints > 0)
  2284.             {
  2285.                 bool isVisible = g_world->isVisible(shootRange, ts.pos.x, ts.pos.y, (TrooperStance) ts.pos.stance, target.pos.x, target.pos.y, (TrooperStance) target.pos.stance);
  2286.                 if (isVisible)
  2287.                     visibleEnemies.push_back(&target);
  2288.             }
  2289.         }
  2290.  
  2291.         int maxCalculatedResult = -1000000;
  2292.  
  2293.         LOG_PAD(ind, "enemies " << visibleEnemies.size());
  2294.         for (int i = 0; i < visibleEnemies.size(); ++i)
  2295.         {
  2296.             TrooperStatus &target = *visibleEnemies[i];
  2297.             int shootsToKill = (target.hitPoints + damage - 1) / damage;
  2298.  
  2299.             if (shootsToKill < maxShoots)
  2300.                 maxShoots = shootsToKill;
  2301.  
  2302.             int shoots = maxShoots - 1;
  2303.             if (shoots < 0)
  2304.                 shoots = 0;
  2305.             for (; shoots <= maxShoots; ++shoots)
  2306.             {
  2307.                 counters.computeFightAfterMove[ind]++;
  2308.                 LOG_PAD(ind, "shootsN " << shoots << "/" << maxShoots);
  2309.  
  2310.                 int oldActionPoints = ts.actionPoints;
  2311.  
  2312.                 ts.actionPoints -= shoots*shootCost;
  2313.  
  2314.                 int oldTargetHitPoints = target.hitPoints;
  2315.                 target.hitPoints -= shoots * damage;
  2316.  
  2317.                 int newResult = result + shoots * damage;
  2318.                 if (target.hitPoints < 0)
  2319.                 {
  2320.                     newResult += target.hitPoints;
  2321.                     newResult += 25;
  2322.                 }
  2323.  
  2324.                 int calculatedResult = computeFightAfterShoot(allTroopers, ind, details, newResult, maxResult);
  2325.                 LOG_PAD(ind, "computeFightAfterMove " << ind << " " << calculatedResult);
  2326.                 if (calculatedResult >= maxResult)
  2327.                 {
  2328.                     FightActionDetails &thisDetails = details[ind];
  2329.                     thisDetails.type = AD_FIRE;
  2330.                     thisDetails.to = target.pos;
  2331.                     thisDetails.enemyId = target.id;
  2332.                     thisDetails.shootsN = shoots;
  2333.  
  2334.                     if (ind == 0)
  2335.                     {
  2336.                         LOG("+++2 " << calculatedResult);
  2337.                         thisDetails.log();
  2338.                     }
  2339.                 }
  2340.                 if (maxCalculatedResult < calculatedResult)
  2341.                     maxCalculatedResult = calculatedResult;
  2342.  
  2343.                 target.hitPoints = oldTargetHitPoints;
  2344.                 ts.actionPoints = oldActionPoints;
  2345.             }
  2346.         }
  2347.  
  2348.         if (visibleEnemies.empty())
  2349.         {
  2350.             LOG_PAD(ind, "Can't shoot " << ind);
  2351.             int calculatedResult = computeFightAfterShoot(allTroopers, ind, details, result, maxResult);
  2352.             LOG_PAD(ind, "computeFightAfterMove " << ind << " " << calculatedResult);
  2353.  
  2354.             if (maxCalculatedResult < calculatedResult)
  2355.                 maxCalculatedResult = calculatedResult;
  2356.  
  2357.             if (calculatedResult >= maxResult)
  2358.             {
  2359.                 FightActionDetails &thisDetails = details[ind];
  2360.                 thisDetails.type = AD_NONE;
  2361.  
  2362.                 if (ind == 0)
  2363.                 {
  2364.                     LOG("+++3 " << calculatedResult);
  2365.                     thisDetails.log();
  2366.                 }
  2367.             }
  2368.  
  2369.             return maxCalculatedResult;
  2370.         }
  2371.         return maxCalculatedResult;
  2372.     }
  2373.  
  2374.     int computeFightAfterShoot(vector <TrooperStatus> &allTroopers, int ind, vector<FightActionDetails> &details, int result, int &maxResult)
  2375.     {
  2376.         LOG_PAD(ind, "computeFightAfterShoot " << ind);
  2377.         TrooperStatus &ts = allTroopers[ind];
  2378.         SimulationMapView mapView = SimulationMapView(allTroopers);
  2379.         WalkMap walkMap;
  2380.  
  2381.         int ap = ts.actionPoints;
  2382.         if ((ind == 1 || ind == 2) && ap > 2)
  2383.             ap = 2;
  2384.         else if (ind >= 3)
  2385.             ap = 0;
  2386.  
  2387.         walkMap.build(ts.pos, ts.id, ap, &mapView);
  2388.  
  2389.         int r = 1;
  2390.         Point p1 = Point(ts.pos.x - r, ts.pos.y - r);
  2391.         Point p2 = Point(ts.pos.x + r, ts.pos.y + r);
  2392.         fit(p1);
  2393.         fit(p2);
  2394.  
  2395.         Position oldPos = ts.pos;
  2396.         int maxCalculatedResult = -1000000;
  2397.         int oldActionPoints = ts.actionPoints;
  2398.         for (int x = p1.x; x <= p2.x; ++x)
  2399.         {
  2400.             for (int y = p1.y; y <= p2.y; ++y)
  2401.             {
  2402.                 for (int s = 0; s < 3; ++s)
  2403.                 {
  2404.                     if (abs(s - ts.pos.stance) > 1)
  2405.                         continue;
  2406.  
  2407.                     WalkMap::PtVal &ptVal = walkMap.get(Position(x, y, s));
  2408.                     if (ptVal.dist < INF_DIST && ptVal.dist <= ap)
  2409.                     {
  2410.                         counters.computeFightAfterShoot[ind]++;
  2411.                         LOG_PAD(ind, "Move after shoot " << x << " " << y << " " << s);
  2412.  
  2413.                         ts.actionPoints = oldActionPoints - ptVal.dist;
  2414.                         ts.pos = Position(x, y, s);
  2415.  
  2416.                         int calculatedResult = computeFightNext(allTroopers, ind, details, result, maxResult);
  2417.                         LOG_PAD(ind, "calculatedResult computeFightAfterShoot " << ind << " = " << calculatedResult);
  2418.  
  2419.                         if (maxCalculatedResult < calculatedResult)
  2420.                             maxCalculatedResult = calculatedResult;
  2421.  
  2422.                         if (calculatedResult >= maxResult)
  2423.                         {
  2424.                             LOG_PAD(ind, "New result " << ind << " " << calculatedResult);
  2425.                             FightActionDetails &thisDetails = details[ind];
  2426.                             thisDetails.evacuationPos = Position(x, y, s);
  2427.                         }
  2428.                     }
  2429.                 }
  2430.             }
  2431.         }
  2432.         ts.pos = oldPos;
  2433.         ts.actionPoints = oldActionPoints;
  2434.  
  2435.         return maxCalculatedResult;
  2436.     }
  2437.  
  2438.     void computeRegroup()
  2439.     {
  2440.         //actionType = AT_REGROUP;
  2441.         //computeGoToRandomPoint();
  2442.     }
  2443.  
  2444.     void computeCollectBonuses()
  2445.     {
  2446.         actionType = AT_COLLECT_BONUSES;
  2447.  
  2448.         int needMedikitCount = 0;
  2449.         int needFieldRationCount = 0;
  2450.         int needGrenageCount = 0;
  2451.  
  2452.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  2453.         {
  2454.             const Trooper *trooper = troopersByMoveOrder[i];
  2455.             if (trooper)
  2456.             {
  2457.                 if (!trooper->isHoldingMedikit())
  2458.                     needMedikitCount++;
  2459.  
  2460.                 if (!trooper->isHoldingFieldRation())
  2461.                     needFieldRationCount++;
  2462.  
  2463.                 if (!trooper->isHoldingGrenade())
  2464.                     needGrenageCount++;
  2465.             }
  2466.         }
  2467.  
  2468.         BonusType bonusTypeOrdered[] = {MEDIKIT, FIELD_RATION, GRENADE};
  2469.         int tempOrder[] = {needMedikitCount, needFieldRationCount, needGrenageCount};
  2470.  
  2471.         if (tempOrder[0] < tempOrder[1])
  2472.         {
  2473.             swap(tempOrder[0], tempOrder[1]);
  2474.             swap(bonusTypeOrdered[0], bonusTypeOrdered[1]);
  2475.         }
  2476.  
  2477.         if (tempOrder[1] < tempOrder[2])
  2478.         {
  2479.             swap(tempOrder[1], tempOrder[2]);
  2480.             swap(bonusTypeOrdered[1], bonusTypeOrdered[2]);
  2481.         }
  2482.  
  2483.         if (tempOrder[0] < tempOrder[1])
  2484.         {
  2485.             swap(tempOrder[0], tempOrder[1]);
  2486.             swap(bonusTypeOrdered[0], bonusTypeOrdered[1]);
  2487.         }
  2488.  
  2489.         TrooperType mainTrooperType = getMainTrooperType();
  2490.         const Trooper *mainTrooper = troopers[typeIndexMap[mainTrooperType]];
  2491.  
  2492.         WalkMap walkMap(true);
  2493.         walkMap.build(mainTrooper);
  2494.  
  2495.         Point closestBonuses[3];
  2496.         int bonusDist[3] = {INF_DIST, INF_DIST, INF_DIST};
  2497.  
  2498.         for (int y = 0; y < H; ++y)
  2499.         {
  2500.             for (int x = 0; x < W; ++x)
  2501.             {
  2502.                 int bonusType = fieldMap.getBonus(x, y);
  2503.                 if (bonusType >= 0)
  2504.                 {
  2505.                     int dist = walkMap.get(Position(x, y, STANDING)).dist;
  2506.                     if (bonusDist[bonusType] == INF_DIST || bonusDist[bonusType] > dist)
  2507.                     {
  2508.                         closestBonuses[bonusType] = Point(x, y);
  2509.                         bonusDist[bonusType] = dist;
  2510.                     }
  2511.                 }
  2512.             }
  2513.         }
  2514.  
  2515.         Point goToPoint;
  2516.         BonusType bt;
  2517.         LOG("bonusTypeOrdered " << bonusTypeOrdered[0] << " " << bonusTypeOrdered[1] << " " << bonusTypeOrdered[2]);
  2518.         LOG("bonusDist " << bonusDist[MEDIKIT] << " " << bonusDist[GRENADE] << " " << bonusDist[FIELD_RATION]);
  2519.         if (bonusDist[bonusTypeOrdered[0]] != INF_DIST && tempOrder[0] > 0)
  2520.         {
  2521.             goToPoint = closestBonuses[bonusTypeOrdered[0]];
  2522.             bt = bonusTypeOrdered[0];
  2523.         }
  2524.         else if (bonusDist[bonusTypeOrdered[1]] != INF_DIST && tempOrder[1] > 0)
  2525.         {
  2526.             goToPoint = closestBonuses[bonusTypeOrdered[1]];
  2527.             bt = bonusTypeOrdered[1];
  2528.         }
  2529.         else if (bonusDist[bonusTypeOrdered[2]] != INF_DIST && tempOrder[2] > 0)
  2530.         {
  2531.             goToPoint = closestBonuses[bonusTypeOrdered[2]];
  2532.             bt = bonusTypeOrdered[2];
  2533.         }
  2534.         else
  2535.         {
  2536.             computeGoToRandomPoint();
  2537.             return;
  2538.         }
  2539.  
  2540.         LOG("computeCollectBonuses point " << goToPoint.x << " " << goToPoint.y);
  2541.  
  2542.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  2543.         {
  2544.             const Trooper *trooper = troopersByMoveOrder[i];
  2545.             if (trooper)
  2546.             {
  2547.                 LOG("TR " << trooperTypeNames[trooper->getType() + 1] << " M" << trooper->isHoldingMedikit() << " F" << trooper->isHoldingFieldRation() << " G" << trooper->isHoldingGrenade());
  2548.             }
  2549.         }
  2550.  
  2551.         if (hasBonus(bt, mainTrooper) && goToPoint.sqDist(Point(*mainTrooper)) < 3 && !(goToPoint == Point(*mainTrooper)))
  2552.         {
  2553.             bool stop = true;
  2554.             Point mp = Point(*mainTrooper);
  2555.             for (int i = 0; i < TOOPERS_COUNT; ++i)
  2556.             {
  2557.                 const Trooper *trooper = troopersByMoveOrder[i];
  2558.                 if (trooper && trooper->getType() != mainTrooper->getType())
  2559.                 {
  2560.                     LOG("III " << i << mp.sqDist(Point(*trooper)) );
  2561.                     if (mp.sqDist(Point(*trooper)) > 2)
  2562.                     {
  2563.                         stop = false;
  2564.                         break;
  2565.                     }
  2566.                 }
  2567.             }
  2568.  
  2569.             if (stop)
  2570.             {
  2571.                 actionType = AT_STOP;
  2572.                 stopTrooperType = mainTrooper->getType();
  2573.                 return;
  2574.             }
  2575.         }
  2576.  
  2577.         computeGoToPoint(goToPoint, mainTrooper, 1);
  2578.  
  2579.         set<Point> reservedPoints;
  2580.         set<int> reservedBy;
  2581.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  2582.         {
  2583.             const Trooper *trooper = troopersByMoveOrder[i];
  2584.             if (trooper)
  2585.             {
  2586.                 Position &target = goToPositions[trooper->getTeammateIndex()];
  2587.  
  2588.                 LOG("TR " << trooperTypeNames[trooper->getType() + 1] << " M" << trooper->isHoldingMedikit() << " F" << trooper->isHoldingFieldRation() << " G" << trooper->isHoldingGrenade());
  2589.  
  2590.                 for (int i = 0; i < nearDistDeltas.size(); ++i)
  2591.                 {
  2592.                     Point p = target;
  2593.                     p.x += nearDistDeltas[i].x;
  2594.                     p.y += nearDistDeltas[i].y;
  2595.  
  2596.                     //LOG("check p " << p.x << " " << p.y);
  2597.                     if (checkPoint(p) && !reservedPoints.count(p))
  2598.                     {
  2599.                         //LOG("check p2 " << p.x << " " << p.y);
  2600.                         int bonusType = fieldMap.getBonus(p.x, p.y);
  2601.  
  2602.                         if (bonusType >= 0)
  2603.                         {
  2604.                             if (bonusInUse[p] != trooper->getTeammateIndex())
  2605.                                 continue;
  2606.  
  2607.                             if (bonusType == (int) MEDIKIT && !trooper->isHoldingMedikit() ||
  2608.                                 bonusType == (int) FIELD_RATION && !trooper->isHoldingFieldRation() ||
  2609.                                 bonusType == (int) GRENADE && !trooper->isHoldingGrenade())
  2610.                             {
  2611.                                 LOG("Bonus Target " << trooperTypeNames[trooper->getType() + 1] << " " << p.x << " " << p.y);
  2612.                                 target.x = p.x;
  2613.                                 target.y = p.y;
  2614.                                 reservedPoints.insert(p);
  2615.                                 reservedBy.insert(trooper->getTeammateIndex());
  2616.  
  2617.                                 bonusInUse[p] = trooper->getTeammateIndex();
  2618.                                 break;
  2619.                             }
  2620.                         }
  2621.                     }
  2622.                 }
  2623.             }
  2624.         }
  2625.  
  2626.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  2627.         {
  2628.             const Trooper *trooper = troopersByMoveOrder[i];
  2629.             if (trooper && !reservedBy.count(trooper->getTeammateIndex()))
  2630.             {
  2631.                 Position &target = goToPositions[trooper->getTeammateIndex()];
  2632.                 if (reservedPoints.count(target))
  2633.                 {
  2634.                     for (int i = 0; i < nearDistDeltas.size(); ++i)
  2635.                     {
  2636.                         Point p = target;
  2637.                         p.x += nearDistDeltas[i].x;
  2638.                         p.y += nearDistDeltas[i].x;
  2639.  
  2640.                         if (checkPoint(p) && !reservedPoints.count(p))
  2641.                         {
  2642.                             target.x = p.x;
  2643.                             target.y = p.y;
  2644.                             reservedPoints.insert(p);
  2645.                             reservedBy.insert(trooper->getTeammateIndex());
  2646.                             break;
  2647.                         }
  2648.                     }
  2649.                 }
  2650.                 else
  2651.                 {
  2652.                     reservedPoints.insert(target);
  2653.                 }
  2654.             }
  2655.         }
  2656.     }
  2657.  
  2658.     TrooperType getMainTrooperType()
  2659.     {
  2660.         TrooperType mainType;
  2661.         if (typeIndexMap.count(COMMANDER))
  2662.             mainType = COMMANDER;
  2663.         else if (typeIndexMap.count(SCOUT))
  2664.             mainType = SCOUT;
  2665.         else if (typeIndexMap.count(SOLDIER))
  2666.             mainType = SOLDIER;
  2667.         else if (typeIndexMap.count(SNIPER))
  2668.             mainType = SNIPER;
  2669.         else if (typeIndexMap.count(FIELD_MEDIC))
  2670.             mainType = FIELD_MEDIC;
  2671.  
  2672.         return mainType;
  2673.     }
  2674.  
  2675.     void computeGoToRandomPoint()
  2676.     {
  2677.         actionType = AT_GOTO_RANDOM_POINT;
  2678.  
  2679.         TrooperType mainType = getMainTrooperType();
  2680.  
  2681.         const Trooper *mainTrooper = troopers[typeIndexMap[mainType]];
  2682.         if (hasLastRandomPoint)
  2683.         {
  2684.             if (Point(*mainTrooper).dist2(lastRandomPoint) < 9)
  2685.                 hasLastRandomPoint = false;
  2686.         }
  2687.  
  2688.         if (!hasLastRandomPoint)
  2689.         {
  2690.             lastRandomPoint = getRandomPoint(mainTrooper);
  2691.             hasLastRandomPoint = true;
  2692.         }
  2693.  
  2694.         LOG("GOTO RANDOM POINT " << lastRandomPoint.x << " " << lastRandomPoint.y);
  2695.         computeGoToPoint(lastRandomPoint, mainTrooper, 1);
  2696.     }
  2697.  
  2698.  
  2699.     void computeGoToPoint(const Point &point, const Trooper *mainTrooper, int reservedMoves)
  2700.     {
  2701.         WalkMap walkMap(false);
  2702.         walkMap.build(mainTrooper);
  2703.  
  2704.         vector<Position> path;
  2705.         walkMap.getPath(Position(point.x, point.y, STANDING), path);
  2706.  
  2707.         {
  2708.             WalkMap walkMap2(true);
  2709.             walkMap2.build(mainTrooper);
  2710.  
  2711.             vector<Position> path2;
  2712.             walkMap2.getPath(Position(point.x, point.y, STANDING), path2);
  2713.  
  2714.  
  2715.             if (path.size() <= 1 || path.size() > (path2.size() + 4))
  2716.             {
  2717.                 path.swap(path2);
  2718.             }
  2719.         }
  2720.  
  2721.         if (path.size() <= 1)
  2722.         {
  2723.             LOG("computeGoToPoint ERROR " << mainTrooper->getX() << " " << mainTrooper->getY() << "->" << point.x << " " << point.y);
  2724.             actionType = AT_NONE;
  2725.             hasLastRandomPoint = false;
  2726.             return;
  2727.         }
  2728.  
  2729.         logMap(&path);
  2730.  
  2731.         int points = mainTrooper->getActionPoints() - reservedMoves*g_game->getStandingMoveCost();
  2732.         Position &lastPoint = path[0];
  2733.         int pi;
  2734.         for (pi = 1; pi < path.size(); ++pi)
  2735.         {
  2736.             int cost = getChangeCost(lastPoint, path[pi]);
  2737.             if (points >= cost)
  2738.             {
  2739.                 if (points >= g_game->getStanceChangeCost() && points < (g_game->getStanceChangeCost() + cost))
  2740.                 {
  2741.                     int cover = getPointCover(path[pi], KNEELING);
  2742.                     LOG("cover " << path[pi].x << " " << path[pi].y << "=" << cover);
  2743.                     if (cover > COVER_KNEELING)
  2744.                     {
  2745.                         LOG("KNEELING");
  2746.                         lastPoint = path[pi];
  2747.                         lastPoint.stance = KNEELING;
  2748.                         points -= g_game->getStanceChangeCost();
  2749.                         break;
  2750.                     }
  2751.                 }
  2752.  
  2753.                 lastPoint = path[pi];
  2754.                 points -= cost;
  2755.             }
  2756.             else
  2757.             {
  2758.                 break;
  2759.             }
  2760.         }
  2761.         pi--;
  2762.  
  2763.         goToPositions[mainTrooper->getTeammateIndex()] = lastPoint;
  2764.         set <Point> reservedPoints;
  2765.         reservedPoints.insert(lastPoint);
  2766.  
  2767.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  2768.         {
  2769.             const Trooper *trooper = troopersByMoveOrder[i];
  2770.             if (trooper && trooper->getType() != mainTrooper->getType())
  2771.             {
  2772.                 WalkMap trooperWalkMap(true);
  2773.                 trooperWalkMap.build(trooper, trooper->getActionPoints() + 5);
  2774.                 Position &p = goToPositions[trooper->getTeammateIndex()];
  2775.  
  2776.                 if (trooper->getType() == SCOUT)
  2777.                 {
  2778.                     if (getNearPosition(path, pi, NP_AHEAD, p, reservedPoints, trooperWalkMap))
  2779.                     {
  2780.                         reservedPoints.insert(p);
  2781.                         continue;
  2782.                     }
  2783.  
  2784.                     if (getNearPosition(path, pi, NP_SIDE, p, reservedPoints, trooperWalkMap))
  2785.                     {
  2786.                         reservedPoints.insert(p);
  2787.                         continue;
  2788.                     }
  2789.  
  2790.                     if (getNearPosition(path, pi, NP_OTHER, p, reservedPoints, trooperWalkMap))
  2791.                     {
  2792.                         reservedPoints.insert(p);
  2793.                         continue;
  2794.                     }
  2795.                     LOG("ERROR, cant find position for SCOUT");
  2796.                 }
  2797.                 else if (trooper->getType() == SOLDIER)
  2798.                 {
  2799.                     if (getNearPosition(path, pi, NP_SIDE, p, reservedPoints, trooperWalkMap))
  2800.                     {
  2801.                         reservedPoints.insert(p);
  2802.                         continue;
  2803.                     }
  2804.  
  2805.                     if (getNearPosition(path, pi, NP_AHEAD, p, reservedPoints, trooperWalkMap))
  2806.                     {
  2807.                         reservedPoints.insert(p);
  2808.                         continue;
  2809.                     }
  2810.  
  2811.                     if (getNearPosition(path, pi, NP_OTHER, p, reservedPoints, trooperWalkMap))
  2812.                     {
  2813.                         reservedPoints.insert(p);
  2814.                         continue;
  2815.                     }
  2816.                     LOG("ERROR, cant find position for SOLDIER");
  2817.                 }
  2818.                 else if (trooper->getType() == SNIPER)
  2819.                 {
  2820.                     if (getNearPosition(path, pi, NP_BACK, p, reservedPoints, trooperWalkMap))
  2821.                     {
  2822.                         reservedPoints.insert(p);
  2823.                         continue;
  2824.                     }
  2825.  
  2826.                     if (getNearPosition(path, pi, NP_OTHER, p, reservedPoints, trooperWalkMap))
  2827.                     {
  2828.                         reservedPoints.insert(p);
  2829.                         continue;
  2830.                     }
  2831.                     LOG("ERROR, cant find position for SNIPER");
  2832.                 }
  2833.                 else if (trooper->getType() == FIELD_MEDIC)
  2834.                 {
  2835.                     if (getNearPosition(path, pi, NP_BACK, p, reservedPoints, trooperWalkMap))
  2836.                     {
  2837.                         reservedPoints.insert(p);
  2838.                         continue;
  2839.                     }
  2840.  
  2841.                     if (getNearPosition(path, pi, NP_OTHER, p, reservedPoints, trooperWalkMap))
  2842.                     {
  2843.                         reservedPoints.insert(p);
  2844.                         continue;
  2845.                     }
  2846.                     LOG("ERROR, cant find position for FIELD_MEDIC");
  2847.                 }
  2848.             }
  2849.         }
  2850.     }
  2851. } coordinationCenter;
  2852.  
  2853. MyStrategy::MyStrategy() { }
  2854.  
  2855. class Mission
  2856. {
  2857. public:
  2858.     virtual bool perform() = 0;
  2859.     virtual bool isPossible()
  2860.     {
  2861.         return true;
  2862.     }
  2863.  
  2864.     virtual ~Mission() {}
  2865. };
  2866.  
  2867. bool eatFieldRation()
  2868. {
  2869.     if (g_self->getActionPoints() <= (g_self->getInitialActionPoints() - g_game->getFieldRationBonusActionPoints())
  2870.         && g_self->getActionPoints() >= g_game->getFieldRationEatCost()
  2871.         && g_self->isHoldingFieldRation())
  2872.     {
  2873.         g_move->setAction(EAT_FIELD_RATION);
  2874.         return true;
  2875.     }
  2876.     return false;
  2877. }
  2878.  
  2879. class GoToPointMission : public Mission
  2880. {
  2881. public:
  2882.     GoToPointMission(const Trooper & trooper, const Point & destination, TrooperStance stance = STANDING)
  2883.     {
  2884.         this->from = Position(trooper);
  2885.         this->destination = Position(destination.x, destination.y, stance);
  2886.         this->trooperIndex = trooper.getTeammateIndex();
  2887.         this->ignoreDanger = true;
  2888.         this->mayIgnoreTeammates = true;
  2889.         findPath(trooper, false);
  2890.     }
  2891.  
  2892.     virtual bool perform()
  2893.     {
  2894.         const Trooper *trooper = findTeamTrooper(trooperIndex);
  2895.         if (!trooper)
  2896.         {
  2897.             LOG("No Trooper " << trooperIndex);
  2898.             return false;
  2899.         }
  2900.  
  2901.         logMap(&path);
  2902.  
  2903.         Point d = Point(*trooper);
  2904.  
  2905.         if (path.size() > 1)
  2906.             d = path[1];
  2907.  
  2908.         if (!canWalk(trooper, d))
  2909.             return false;
  2910.  
  2911.         //optimizePath(trooper);
  2912.  
  2913.         if (!canWalk(trooper, d, 1) && trooper->getActionPoints() >= g_game->getStanceChangeCost() && trooper->getStance() == STANDING)
  2914.         {
  2915.             int cover = getPointCover(Point(*trooper), KNEELING);
  2916.             if (cover >= COVER_KNEELING)
  2917.             {
  2918.                 g_move->setAction(LOWER_STANCE);
  2919.                 return true;
  2920.             }
  2921.         }
  2922.  
  2923.         /*if (!canWalk(trooper, 2) && trooper->getActionPoints() >= g_game->getStanceChangeCost() && trooper->getStance() == STANDING
  2924.                 || !canWalk(trooper, 1) && trooper->getActionPoints() >= g_game->getStanceChangeCost() && trooper->getStance() == KNEELING)
  2925.         {
  2926.             int coverKneeling = getPointCover(Point(*trooper), KNEELING);
  2927.             int coverProne = getPointCover(Point(*trooper), PRONE);
  2928.             LOG("Cover " << coverProne << " " << coverKneeling);
  2929.             if ((coverProne - coverKneeling) >= COVER_PRONE)
  2930.             {
  2931.                 g_move->setAction(LOWER_STANCE);
  2932.                 return true;
  2933.             }
  2934.         }*/
  2935.  
  2936.         if (path.size() > 1)
  2937.         {
  2938.             Position p = path[1];
  2939.             Position curPoint = Position(*trooper);
  2940.             if (p.isClose(curPoint) && isPointFree(p, trooper))
  2941.             {
  2942.                 if (p.stance > curPoint.stance)
  2943.                 {
  2944.                     if (trooper->getActionPoints() < g_game->getStanceChangeCost())
  2945.                         return false;
  2946.                     g_move->setAction(RAISE_STANCE);
  2947.                 }
  2948.                 else if (p.stance < curPoint.stance)
  2949.                 {
  2950.                     if (trooper->getActionPoints() < g_game->getStanceChangeCost())
  2951.                         return false;
  2952.                     g_move->setAction(LOWER_STANCE);
  2953.                 }
  2954.                 else
  2955.                 {
  2956.                     if (trooper->getActionPoints() < getMoveCost(trooper->getStance()))
  2957.                         return false;
  2958.  
  2959.                     g_move->setAction(MOVE);
  2960.                     g_move->setX(p.x);
  2961.                     g_move->setY(p.y);
  2962.                 }
  2963.                 return true;
  2964.             }
  2965.             else
  2966.             {
  2967.                 LOG("No GoToPointMission move " << curPoint.x << " " << curPoint.y << " -> " << p.x << " " << p.y);
  2968.                 stuck[trooper->getType()] = moveIndex;
  2969.  
  2970.                 for (int i = 1; i < path.size(); ++i)
  2971.                 {
  2972.                     const Trooper * obstacleTrooper = getTrooper(path[i]);
  2973.                     if (obstacleTrooper && obstacleTrooper->isTeammate() && obstacleTrooper->getTeammateIndex() != trooperIndex)
  2974.                     {
  2975.                         LOG("notifyObstacle " << trooperTypeNames[obstacleTrooper->getType() + 1]);
  2976.                         notifyObstacle(obstacleTrooper);
  2977.                     }
  2978.                 }
  2979.             }
  2980.         }
  2981.  
  2982.         LOG("No GoToPointMission move " << path.size());
  2983.         return true;
  2984.     }
  2985.  
  2986.     void notifyObstacle(const Trooper * obstacleTrooper);
  2987.  
  2988.    /* void optimizePath(const Trooper *trooper)
  2989.     {
  2990.         WalkMap walkMap;
  2991.         walkMap.build(trooper, trooper->getActionPoints() - reservedMoves*2);
  2992.  
  2993.         Position lastPos = Position(*trooper);
  2994.         int i = 1;
  2995.         for (i = 1; i < path.size(); ++i)
  2996.         {
  2997.             Position &p = path[i];
  2998.             int coverKneeling = getPointCover(Point(*trooper), KNEELING);
  2999.             int coverProne = getPointCover(Point(*trooper), PRONE);
  3000.  
  3001.             TrooperStance stance = (TrooperStance) p.stance;
  3002.             if (coverKneeling >= COVER_KNEELING)
  3003.                 stance = KNEELING;
  3004.  
  3005.             if ((coverProne - coverKneeling) >= COVER_PRONE)
  3006.                 stance = PRONE;
  3007.  
  3008.             int dist = walkMap.get(Position(p.x, p.y, stance)).dist ;
  3009.             LOG("i " << i << " " << dist);
  3010.             if (dist >= INF_DIST)
  3011.                 break;
  3012.  
  3013.             lastPos = Position(p.x, p.y, stance);
  3014.             LOG(p.x << " " << p.y);
  3015.         }
  3016.  
  3017.         walkMap.getPath(lastPos, path);
  3018.     }*/
  3019.  
  3020.     virtual bool canWalk(const Trooper *trooper, const Point &to, int nm = 0)
  3021.     {
  3022.         int reservedMoves = 0;
  3023.         if (!this->ignoreDanger)
  3024.         {
  3025.             double danger = estimateDanger(to, trooper->getType());
  3026.             LOG("Estimated danger " << danger);
  3027.             if (danger > 20.0)
  3028.                 reservedMoves = 1;
  3029.         }
  3030.  
  3031.         LOG("ActionPoints " << trooper->getActionPoints());
  3032.         if (trooper->getActionPoints() < (1 + reservedMoves + nm) * g_game->getStandingMoveCost())
  3033.         {
  3034.             if (nm == 0)
  3035.                 LOG("GoToPointMission, no actionPoints " << trooperIndex << " reservedMoves: " << reservedMoves);
  3036.             return false;
  3037.         }
  3038.  
  3039.         return true;
  3040.     }
  3041.  
  3042.     const vector<Position> &getPath() const
  3043.     {
  3044.         return path;
  3045.     }
  3046.  
  3047.     int getLength() const
  3048.     {
  3049.         return path.size();
  3050.     }
  3051.  
  3052.     virtual bool isPossible()
  3053.     {
  3054.         if (path.empty())
  3055.             return false;
  3056.  
  3057.         const Trooper *trooper = findTeamTrooper(trooperIndex);
  3058.         if (!trooper)
  3059.         {
  3060.             LOG("No Trooper " << trooperIndex);
  3061.             return false;
  3062.         }
  3063.         if (path.size() > 1 && !isPointFree(path[1], trooper) && stuck.count(trooper->getType()) && (stuck[trooper->getType()] + 1) == moveIndex)
  3064.         {
  3065.             return false;
  3066.         }
  3067.  
  3068.         return true;
  3069.     }
  3070.  
  3071. private:
  3072.     void findPath(const Trooper &trooper, bool standing = true)
  3073.     {
  3074.         WalkMap walkMap;
  3075.         walkMap.build(&trooper);
  3076.  
  3077.         LOG("findPath " << from.x << " " << from.y);
  3078.         walkMap.getPath(destination, path, standing);
  3079.  
  3080.         if (mayIgnoreTeammates)
  3081.         {
  3082.             WalkMap walkMap2(true);
  3083.             walkMap2.build(&trooper);
  3084.  
  3085.             vector<Position> path2;
  3086.             walkMap2.getPath(destination, path2, standing);
  3087.  
  3088.  
  3089.             if (path.size() <= 1 || path.size() > (path2.size() + 4))
  3090.             {
  3091.                 if (path2.size() > 1 && !isPointFree(path2[1], &trooper) && stuck.count(trooper.getType()) && (stuck[trooper.getType()] + 1) == moveIndex)
  3092.                 {
  3093.                     LOG("Stuck!");
  3094.                     for (int i = 1; i < path2.size() && i < 5; ++i)
  3095.                     {
  3096.                         const Trooper * obstacleTrooper = getTrooper(path2[i]);
  3097.                         if (obstacleTrooper && obstacleTrooper->isTeammate() && obstacleTrooper->getTeammateIndex() != trooper.getTeammateIndex())
  3098.                         {
  3099.                             LOG("findPath notifyObstacle " << trooperTypeNames[obstacleTrooper->getType() + 1]);
  3100.                             notifyObstacle(obstacleTrooper);
  3101.                         }
  3102.                     }
  3103.                 }
  3104.  
  3105.                 LOG("Shoose path ignoring teammates");
  3106.                 path.swap(path2);
  3107.             }
  3108.         }
  3109.     }
  3110.  
  3111.     void logPath()
  3112.     {
  3113.         if (!ENABLE_LOGGING)
  3114.             return;
  3115.  
  3116.         LOG("PATH");
  3117.         for (int i = 0; i < path.size(); ++i)
  3118.         {
  3119.             LOG(i << " - (" << path[i].x << ", " << path[i].y << ")");
  3120.         }
  3121.     }
  3122.  
  3123. protected:
  3124.     vector<Position> path;
  3125.     Position from, destination;
  3126.     int trooperIndex;
  3127.     bool ignoreDanger;
  3128.     bool mayIgnoreTeammates;
  3129. };
  3130.  
  3131. class ClearWayMission : public GoToPointMission
  3132. {
  3133. public:
  3134.     ClearWayMission(const Trooper & trooper, const Point & destination) : GoToPointMission(trooper, destination)
  3135.     {
  3136.         this->ignoreDanger = false;
  3137.         this->mayIgnoreTeammates = false;
  3138.     }
  3139. };
  3140.  
  3141. class GoToBonusMission : public GoToPointMission
  3142. {
  3143. public:
  3144.     GoToBonusMission(const Trooper & trooper, const Point & destination) : GoToPointMission(trooper, destination)
  3145.     {
  3146.         this->ignoreDanger = false;
  3147.     }
  3148.  
  3149.     ~GoToBonusMission()
  3150.     {
  3151.         if (bonusInUse.count(destination))
  3152.             LOG("BONUS IN USE REMOVE" << destination.x << " " << destination.y << " - " << bonusInUse[destination]);
  3153.         bonusInUse.erase(destination);
  3154.     }
  3155. };
  3156.  
  3157. class GoToRandomPointMission : public GoToPointMission
  3158. {
  3159. public:
  3160.     GoToRandomPointMission(const Trooper & trooper, const Point & destination) : GoToPointMission(trooper, destination)
  3161.     {
  3162.         this->ignoreDanger = false;
  3163.     }
  3164. };
  3165.  
  3166. class Fight
  3167. {
  3168. public:
  3169.     Fight()
  3170.     {
  3171.         for (int i = 0; i < TOOPERS_COUNT; ++i)
  3172.         {
  3173.             distances[i] = INF_DIST;
  3174.             closestEnemyes[i] = NULL;
  3175.             minDistTrooper = -1;
  3176.         }
  3177.     }
  3178.  
  3179.     void calculateDistances();
  3180.     bool calculate()
  3181.     {
  3182.         if (minDistTrooper == -1)
  3183.             return false;
  3184.  
  3185.         const Trooper * trooper = findTeamTrooper(minDistTrooper);
  3186.         if (!trooper)
  3187.             return false;
  3188.  
  3189.         WalkMap walkMap;
  3190.         walkMap.build(trooper, trooper->getActionPoints());
  3191.  
  3192.         Enemy *enemies[3*5];
  3193.         int enemiesN = 0;
  3194.         for (FieldMap::Enemies::iterator it = fieldMap.enemies.begin(); it != fieldMap.enemies.end(); ++it)
  3195.         {
  3196.             enemies[enemiesN++] = &it->second;
  3197.         }
  3198.  
  3199.  
  3200.     }
  3201.  
  3202.     int distances[TOOPERS_COUNT];
  3203.     Enemy *closestEnemyes[TOOPERS_COUNT];
  3204.     int minDistTrooper;
  3205. };
  3206.  
  3207.  
  3208. class ShootEnemyMission : public Mission
  3209. {
  3210. public:
  3211.     ShootEnemyMission(const Trooper & self, const Enemy & enemy)
  3212.     {
  3213.         this->trooperIndex = self.getTeammateIndex();
  3214.         this->enemyId = enemy.id;
  3215.     }
  3216.  
  3217.     virtual bool perform()
  3218.     {
  3219.         if (eatFieldRation())
  3220.             return true;
  3221.  
  3222.         const Trooper *self = findTeamTrooper(trooperIndex);
  3223.  
  3224.         if (!fieldMap.enemies.count(this->enemyId))
  3225.             return false;
  3226.  
  3227.        const Enemy &enemy = fieldMap.enemies.find(this->enemyId)->second;
  3228.  
  3229.         if (self->getActionPoints() >= g_game->getGrenadeThrowCost() && self->isHoldingGrenade())
  3230.         {
  3231.             int dirInd = s_canThrowGrenage(*self, enemy);
  3232.             if (dirInd != -1)
  3233.             {
  3234.                 Point target = getClosePoints(enemy.pos, dirInd);
  3235.                 g_move->setAction(THROW_GRENADE);
  3236.                 g_move->setX(target.x);
  3237.                 g_move->setY(target.y);
  3238.                 return true;
  3239.             }
  3240.         }
  3241.  
  3242.         if (self->getActionPoints() < self->getShootCost())
  3243.         {
  3244.             LOG("ShootEnemyMission, no actionPoints " << trooperIndex);
  3245.             return false;
  3246.         }
  3247.  
  3248.         if (!s_canShoot(*self, enemy))
  3249.         {
  3250.             LOG("Can't shoot " << self->getX() << " " << self->getY() << "->" << enemy.pos.x << " " << enemy.pos.y);
  3251.             return false;
  3252.         }
  3253.  
  3254.         LOG("SHOOT " << sqrt((double) (enemy.pos.dist2(Point(*self)))));
  3255.         g_move->setAction(SHOOT);
  3256.         g_move->setX(enemy.pos.x);
  3257.         g_move->setY(enemy.pos.y);
  3258.         return true;
  3259.     }
  3260.  
  3261.     virtual bool isPossible()
  3262.     {
  3263.         const Trooper *self = findTeamTrooper(trooperIndex);
  3264.         if (!self)
  3265.             return false;
  3266.  
  3267.         const Enemy *enemy = fieldMap.get(enemyId);
  3268.         if (!enemy || !(enemy->isConfirmed() || enemy->isProbable()))
  3269.             return false;
  3270.  
  3271.         return s_canShoot(*self, *enemy);
  3272.     }
  3273.  
  3274.     static bool s_canShoot(const Trooper &self, const Enemy &enemy)
  3275.     {
  3276.         bool canShoot = g_world->isVisible(self.getShootingRange(),
  3277.             self.getX(), self.getY(), self.getStance(),
  3278.             enemy.pos.x, enemy.pos.y, (TrooperStance) enemy.pos.stance);
  3279.  
  3280.         return canShoot;
  3281.     }
  3282.  
  3283.     static int s_canThrowGrenage(const Trooper &self, const Enemy &enemy)
  3284.     {
  3285.         Point target = enemy.pos;
  3286.         Point selfPoint = Point(self);
  3287.         int maxDamage = 0;
  3288.         int result = -1;
  3289.  
  3290.         for (int k = CLOSE_POINTS_N; k --> 0;)
  3291.         {
  3292.             Point cp = getClosePoints(target, k);
  3293.             if (selfPoint.dist2(cp) <= g_game->getGrenadeThrowRange()*g_game->getGrenadeThrowRange() && checkBounds(cp) && !selfPoint.isClose(cp))
  3294.             {
  3295.                 int damage = (cp == target) ? g_game->getGrenadeDirectDamage() : g_game->getGrenadeCollateralDamage();
  3296.                 if (maxDamage < damage)
  3297.                 {
  3298.                     maxDamage = damage;
  3299.                     result = k;
  3300.                 }
  3301.             }
  3302.         }
  3303.  
  3304.         return result;
  3305.     }
  3306.  
  3307. private:
  3308.     int trooperIndex;
  3309.     TrooperId enemyId;
  3310. };
  3311.  
  3312. const Trooper *findTeamTrooperByType(TrooperType type)
  3313. {
  3314.     const vector<Trooper>& troopers = g_world->getTroopers();
  3315.     for (int i = 0; i < troopers.size(); ++i)
  3316.     {
  3317.         const Trooper &trooper = troopers[i];
  3318.         if (trooper.isTeammate())
  3319.         {
  3320.             if (trooper.getType() == type)
  3321.             {
  3322.                 return &trooper;
  3323.             }
  3324.         }
  3325.     }
  3326.     return NULL;
  3327. }
  3328.  
  3329. class MyTrooper
  3330. {
  3331. public:
  3332.     MyTrooper()
  3333.     {
  3334.         mission = NULL;
  3335.         hasLastRandomPoint = false;
  3336.         fireTime = -1000;
  3337.         getAwayFromWay = false;
  3338.         getAwayMoveIndex = -1;
  3339.         getAwayTrooperOrderIndex = -1;
  3340.     }
  3341.  
  3342.     virtual void recalculateMission() {}
  3343.     virtual ~MyTrooper()
  3344.     {
  3345.         delete mission;
  3346.     }
  3347.  
  3348.     void setMission(Mission *m)
  3349.     {
  3350.         delete mission;
  3351.         mission = m;
  3352.     }
  3353.  
  3354.     Mission * getMission()
  3355.     {
  3356.         return mission;
  3357.     }
  3358.  
  3359.     bool useMedikit()
  3360.     {
  3361.         const Trooper *self = findTeamTrooper(teammateIndex);
  3362.  
  3363.         if (self->getActionPoints() >= g_game->getMedikitUseCost() && self->isHoldingMedikit())
  3364.         {
  3365.             Point selfPoint = Point(*self);
  3366.             for (int k = CLOSE_POINTS_N; k --> 0;)
  3367.             {
  3368.                 Point p = getClosePoints(selfPoint, k);
  3369.                 const Trooper * trooper = getTrooper(p);
  3370.                 int points = (selfPoint == p) ? g_game->getMedikitHealSelfBonusHitpoints() : g_game->getMedikitBonusHitpoints();
  3371.                 if (trooper && trooper->isTeammate() && trooper->getHitpoints() <= (trooper->getMaximalHitpoints() - points))
  3372.                 {
  3373.                     LOG("USE MEDIKIT " << p.x << " " << p.y << " " << trooper->getHitpoints());
  3374.                     g_move->setAction(USE_MEDIKIT);
  3375.                     g_move->setX(p.x);
  3376.                     g_move->setY(p.y);
  3377.                     return true;
  3378.                 }
  3379.             }
  3380.         }
  3381.         return false;
  3382.     }
  3383.  
  3384.     virtual bool heal()
  3385.     {
  3386.         return false;
  3387.     }
  3388.  
  3389.     bool findEnemy()
  3390.     {
  3391.         const Trooper *self = findTeamTrooper(teammateIndex);
  3392.         const vector<Trooper>& troopers = g_world->getTroopers();
  3393.         int enemyHealth = 1000;
  3394.         const Enemy *foundEnemy = NULL;
  3395.         for (FieldMap::Enemies::iterator it = fieldMap.enemies.begin(); it != fieldMap.enemies.end(); ++it)
  3396.         {
  3397.             const Enemy &enemy = it->second;
  3398.             if (enemy.isConfirmed())
  3399.             {
  3400.                 bool canShoot = ShootEnemyMission::s_canShoot(*self, enemy);
  3401.                 int curEnemyHealth = enemy.hitPoints;
  3402.                 if (canShoot && (!foundEnemy || enemyHealth > curEnemyHealth))
  3403.                 {
  3404.                     enemyHealth = curEnemyHealth;
  3405.                     foundEnemy = &enemy;
  3406.                 }
  3407.             }
  3408.         }
  3409.  
  3410.         if (foundEnemy)
  3411.         {
  3412.             setMission(new ShootEnemyMission(*self, *foundEnemy));
  3413.  
  3414.             fireTime = g_world->getMoveIndex();
  3415.  
  3416.             return true;
  3417.         }
  3418.  
  3419.         for (FieldMap::Enemies::iterator it = fieldMap.enemies.begin(); it != fieldMap.enemies.end(); ++it)
  3420.         {
  3421.             const Enemy &enemy = it->second;
  3422.             if (enemy.isProbable())
  3423.             {
  3424.                 bool canShoot = ShootEnemyMission::s_canShoot(*self, enemy);
  3425.                 int curEnemyHealth = enemy.hitPoints;
  3426.                 if (canShoot && (!foundEnemy || enemyHealth > curEnemyHealth))
  3427.                 {
  3428.                     enemyHealth = curEnemyHealth;
  3429.                     foundEnemy = &enemy;
  3430.                 }
  3431.             }
  3432.         }
  3433.  
  3434.         if (foundEnemy)
  3435.         {
  3436.             setMission(new ShootEnemyMission(*self, *foundEnemy));
  3437.  
  3438.             fireTime = g_world->getMoveIndex();
  3439.  
  3440.             return true;
  3441.         }
  3442.  
  3443.         /*for (FieldMap::Enemies::iterator it = fieldMap.enemies.begin(); it != fieldMap.enemies.end(); ++it)
  3444.         {
  3445.             const Enemy &enemy = it->second;
  3446.             if (enemy.isConfirmed())
  3447.             {
  3448.                 int viewRad = getViewRadius(enemy.type);
  3449.                 int shootRad = getShootRange(enemy.type);
  3450.                 int rad = (viewRad > shootRad) ? viewRad : shootRad;
  3451.  
  3452.                 bool isVisible = g_world->isVisible(rad, enemy.pos.x, enemy.pos.y, STANDING, self->getX(), self->getY(), self->getStance());
  3453.                 int curEnemyHealth = enemy.hitPoints;
  3454.                 if (isVisible && (!foundEnemy || enemyHealth < curEnemyHealth))
  3455.                 {
  3456.                     enemyHealth = curEnemyHealth;
  3457.                     foundEnemy = &enemy;
  3458.                 }
  3459.             }
  3460.         }
  3461.  
  3462.         if (foundEnemy)
  3463.         {
  3464.             setMission(new ShootEnemyMission(*self, *foundEnemy));
  3465.  
  3466.             fireTime = g_world->getMoveIndex();
  3467.  
  3468.             return true;
  3469.         }*/
  3470.  
  3471.         return false;
  3472.     }
  3473.  
  3474.     bool findBonus()
  3475.     {
  3476.         const Trooper *self = findTeamTrooper(teammateIndex);
  3477.         const Trooper *commander = findTeamTrooperByType(COMMANDER);
  3478.  
  3479.         Point foundBonusPoint;
  3480.         int bonusCost = 10000;
  3481.         bool foundBonus = false;
  3482.         for (int y = 0; y < H; ++y)
  3483.         {
  3484.             for (int x = 0; x < W; ++x)
  3485.             {
  3486.                 int bonusType = fieldMap.getBonus(x, y);
  3487.                 if (bonusType >= 0)
  3488.                 {
  3489.                     Point bonusPoint = Point(x, y);
  3490.  
  3491.                     if (!isPointFree(bonusPoint, self))
  3492.                         continue;
  3493.  
  3494.                     if (bonusInUse.find(bonusPoint) != bonusInUse.end())
  3495.                     {
  3496.                         if (bonusInUse[bonusPoint] != self->getTeammateIndex())
  3497.                             continue;
  3498.                     }
  3499.  
  3500.                     bool hasBonus = isHoldingBonus(*self, (BonusType) bonusType);
  3501.                     int points = getBonusPoints(hasBonus, (BonusType) bonusType);
  3502.  
  3503.                     if (points > 0)
  3504.                     {
  3505.                         GoToPointMission m(*self, bonusPoint);
  3506.                         //if (m.isPossible())
  3507.                         {
  3508.                             int cost = m.getLength() * 2 - points;
  3509.  
  3510.                             if (bonusCost > cost)
  3511.                             {
  3512.                                 bonusCost = cost;
  3513.                                 foundBonusPoint = bonusPoint;
  3514.                                 foundBonus = true;
  3515.                             }
  3516.                         }
  3517.                     }
  3518.                 }
  3519.             }
  3520.         }
  3521.  
  3522.         if (foundBonus)
  3523.         {
  3524.  
  3525.             LOG("GoToPointMission " << foundBonusPoint.x << " " << foundBonusPoint.y);
  3526.             setMission(new GoToBonusMission(*self, foundBonusPoint));
  3527.             bonusInUse[foundBonusPoint] = self->getTeammateIndex();
  3528.             return true;
  3529.         }
  3530.  
  3531.         return false;
  3532.     }
  3533.  
  3534.     bool goToSafePlace()
  3535.     {
  3536.         LOG("goToSafePlace");
  3537.         const Trooper *self = findTeamTrooper(teammateIndex);
  3538.         if (self->getActionPoints() < g_game->getStandingMoveCost())
  3539.         {
  3540.             LOG("goToSafePlace, no actionPoints " << teammateIndex);
  3541.             return false;
  3542.         }
  3543.  
  3544.         Point selfPoint = Point(*self);
  3545.  
  3546.         int safePointInd = -1;
  3547.         int estimatedSafePointInd = -1;
  3548.         int danger = 1000000;
  3549.         double estimatedDanger = 1000000;
  3550.         int cdanger = danger;
  3551.         double cEstimatedDanger = estimatedDanger;
  3552.         for (int k = CLOSE_POINTS_N; k --> 0;)
  3553.         {
  3554.             Point p = getClosePoints(selfPoint, k);
  3555.             if (isPointFree(p, self))
  3556.             {
  3557.                 int curDanger = getDanger(*self, p);
  3558.                 double curEstimatedDanger = estimateDanger(p, self->getType());
  3559.                 if (p == selfPoint)
  3560.                 {
  3561.                     cdanger = curDanger;
  3562.                     cEstimatedDanger = curEstimatedDanger;
  3563.                 }
  3564.  
  3565.                 LOG("Danger " << p.x << " " << p.y << " = " << curDanger << "|" << curEstimatedDanger);
  3566.                 if (danger > curDanger)
  3567.                 {
  3568.                     danger = curDanger;
  3569.                     safePointInd = k;
  3570.                 }
  3571.                 if (estimatedDanger > curEstimatedDanger)
  3572.                 {
  3573.                     estimatedDanger = curEstimatedDanger;
  3574.                     estimatedSafePointInd = k;
  3575.                 }
  3576.             }
  3577.         }
  3578.  
  3579.         int moveToInd = -1;
  3580.         if (safePointInd != -1 && danger < cdanger)
  3581.         {
  3582.             moveToInd = safePointInd;
  3583.         }
  3584.         else if (estimatedSafePointInd != -1 && estimatedDanger < cEstimatedDanger && cEstimatedDanger > 20.0)
  3585.         {
  3586.             moveToInd = estimatedSafePointInd;
  3587.         }
  3588.  
  3589.         if (moveToInd != -1)
  3590.         {
  3591.             Point p = getClosePoints(selfPoint, moveToInd);
  3592.             if (!(p == selfPoint))
  3593.             {
  3594.                 if (self->getActionPoints() < getMoveCost(self->getStance()))
  3595.                     return false;
  3596.  
  3597.                 g_move->setAction(MOVE);
  3598.                 g_move->setX(p.x);
  3599.                 g_move->setY(p.y);
  3600.                 return true;
  3601.             }
  3602.         }
  3603.  
  3604.         return false;
  3605.     }
  3606.  
  3607.     bool findRandomPoint()
  3608.     {
  3609.         const Trooper *self = findTeamTrooper(teammateIndex);
  3610.  
  3611.         if (hasLastRandomPoint)
  3612.         {
  3613.             if (Point(*self).dist2(lastRandomPoint) < 9)
  3614.                 hasLastRandomPoint = false;
  3615.         }
  3616.  
  3617.         if (!hasLastRandomPoint)
  3618.         {
  3619.             lastRandomPoint = getRandomPoint(self);
  3620.             hasLastRandomPoint = true;
  3621.         }
  3622.  
  3623.         LOG("GOTO RANDOM POINT " << lastRandomPoint.x << " " << lastRandomPoint.y);
  3624.         setMission(new GoToRandomPointMission(*self, lastRandomPoint));
  3625.         return true;
  3626.     }
  3627.  
  3628.     bool goToTeamMember(TrooperType type)
  3629.     {
  3630.         const Trooper *self = findTeamTrooper(teammateIndex);
  3631.  
  3632.         const Trooper * trooper = findTeamTrooperByType(type);
  3633.         int danger = 1000000;
  3634.         if (trooper)
  3635.         {
  3636.             bool isMedic = (self->getType() == FIELD_MEDIC);
  3637.             Point trooperPoint = Point(*trooper);
  3638.             int dirInd = -1;
  3639.             int len = 1000000;
  3640.             for (int k = CLOSE_POINTS_N; k --> 0;)
  3641.             {
  3642.                 Point p = getClosePoints(trooperPoint, k);
  3643.                 if (isPointFree(p, self))
  3644.                 {
  3645.                     GoToPointMission m = GoToPointMission(*self, p);
  3646.                     if (m.isPossible())
  3647.                     {
  3648.                         int curDanger = getDanger(*self, p);
  3649.                         if (dirInd == -1)
  3650.                         {
  3651.                             dirInd = k;
  3652.                             len = m.getLength();
  3653.                             danger =  curDanger;
  3654.                         }
  3655.                         else
  3656.                         {
  3657.                             if (isMedic)
  3658.                             {
  3659.                                 if (len > m.getLength())
  3660.                                     len = m.getLength();
  3661.  
  3662.                                 if ((len + 2) > m.getLength() && curDanger < danger)
  3663.                                 {
  3664.                                     dirInd = k;
  3665.                                     danger =  curDanger;
  3666.                                 }
  3667.                             }
  3668.                             else
  3669.                             {
  3670.                                 if (len > m.getLength())
  3671.                                 {
  3672.                                     dirInd = k;
  3673.                                     len = m.getLength();
  3674.                                     danger =  curDanger;
  3675.                                 }
  3676.                             }
  3677.                         }
  3678.                     }
  3679.                 }
  3680.             }
  3681.  
  3682.             if (dirInd != -1)
  3683.             {
  3684.                 Point p = getClosePoints(trooperPoint, dirInd);
  3685.                 LOG("GOTO Teammember " << p.x << " " << p.y);
  3686.                 setMission(new GoToPointMission(*self, p));
  3687.                 return true;
  3688.             }
  3689.         }
  3690.  
  3691.         return false;
  3692.     }
  3693.  
  3694.     bool getAway()
  3695.     {
  3696.         LOG("Check getAway " << getAwayFromWay << " " << getAwayMoveIndex << " " << getAwayTrooperOrderIndex);
  3697.         const Trooper *self = findTeamTrooper(teammateIndex);
  3698.  
  3699.         if (getAwayFromWay)
  3700.         {
  3701.             LOG("Set GetAway");
  3702.             if (self->getType() == g_self->getType())
  3703.                 getAwayFromWay = false;
  3704.  
  3705.             getAwayMoveIndex = moveIndex;
  3706.             getAwayTrooperOrderIndex = trooperMoveOrderIndex;
  3707.         }
  3708.  
  3709.         if (getAwayMoveIndex == moveIndex && getAwayTrooperOrderIndex == trooperMoveOrderIndex)
  3710.         {
  3711.             LOG("GetAway");
  3712.             Point curPoint = Point(*self);
  3713.             if (!obstaclePoints.count(curPoint))
  3714.                 return true;
  3715.  
  3716.             WalkMap walkMap;
  3717.             walkMap.build(self, self->getActionPoints());
  3718.  
  3719.             int r = 5;
  3720.             Point p1 = Point(curPoint.x - r, curPoint.y - r);
  3721.             Point p2 = Point(curPoint.x + r, curPoint.y + r);
  3722.             fit(p1);
  3723.             fit(p2);
  3724.  
  3725.             int dist = INF_DIST;
  3726.             Point destination;
  3727.             for (int x = p1.x; x <= p2.x; ++x)
  3728.             {
  3729.                 for (int y = p1.y; y <= p2.y; ++y)
  3730.                 {
  3731.                     Point t = Point(x, y);
  3732.                     const WalkMap::PtVal &val = walkMap.get(Position(t.x, t.y, STANDING));
  3733.                     if (dist > val.dist && !obstaclePoints.count(t))
  3734.                     {
  3735.                         dist = val.dist;
  3736.                         destination = t;
  3737.                     }
  3738.                 }
  3739.             }
  3740.  
  3741.             if (dist == INF_DIST)
  3742.             {
  3743.                 LOG("getAway can't find free point");
  3744.                 return false;
  3745.             }
  3746.  
  3747.             setMission(new ClearWayMission(*self, destination));
  3748.  
  3749.             return true;
  3750.         }
  3751.         return false;
  3752.     }
  3753.  
  3754.     bool getCommandFromCoordinationCenter()
  3755.     {
  3756.         if ((coordinationCenter.actionType == AT_COLLECT_BONUSES ||
  3757.              coordinationCenter.actionType == AT_GOTO_RANDOM_POINT ||
  3758.              coordinationCenter.actionType == AT_STOP) && getAway())
  3759.             return true;
  3760.  
  3761.         const Trooper *self = findTeamTrooper(teammateIndex);
  3762.  
  3763.         if (coordinationCenter.actionType == AT_COLLECT_BONUSES)
  3764.         {
  3765.             Position &p = coordinationCenter.goToPositions[teammateIndex];
  3766.             LOG("AT_COLLECT_BONUSES " << p.x << " " << p.y);
  3767.             setMission(new GoToBonusMission(*self, p));
  3768.  
  3769.             if (getMission()->isPossible())
  3770.                 return true;
  3771.         }
  3772.  
  3773.         if (coordinationCenter.actionType == AT_GOTO_RANDOM_POINT)
  3774.         {
  3775.             Position &p = coordinationCenter.goToPositions[teammateIndex];
  3776.             LOG("AT_GOTO_RANDOM_POINT " << p.x << " " << p.y);
  3777.             setMission(new GoToRandomPointMission(*self, p));
  3778.             if (getMission()->isPossible())
  3779.                 return true;
  3780.         }
  3781.  
  3782.         if (coordinationCenter.actionType == AT_STOP && coordinationCenter.stopTrooperType == self->getType())
  3783.         {
  3784.             return true;
  3785.         }
  3786.  
  3787.         if (coordinationCenter.actionType == AT_FIGHT)
  3788.         {
  3789.             if (self->getType() == g_self->getType() && coordinationCenter.detailsMap.count(self->getType()))
  3790.             {
  3791.                 FightActionDetails &details = coordinationCenter.detailsMap[self->getType()];
  3792.                 if (details.type == AD_FIRE)
  3793.                 {
  3794.                     if (details.from == Position(*self))
  3795.                     {
  3796.                         if (fieldMap.enemies.count(details.enemyId))
  3797.                         {
  3798.                             LOG(trooperTypeNames[self->getType() + 1] << ": shoot enemy " << details.to.x << " " << details.to.y);
  3799.                             setMission(new ShootEnemyMission(*self, fieldMap.enemies[details.enemyId]));
  3800.                             return true;
  3801.                         }
  3802.                     }
  3803.                     else
  3804.                     {
  3805.                         LOG(trooperTypeNames[self->getType() + 1] << ": go to pos " << details.from.x << " " << details.from.y << " " << details.from.stance);
  3806.                         setMission(new GoToPointMission(*self, details.from, (TrooperStance) details.from.stance));
  3807.                         return true;
  3808.                     }
  3809.                 }
  3810.             }
  3811.         }
  3812.  
  3813.         return false;
  3814.     }
  3815.  
  3816.     bool goToCommander()
  3817.     {
  3818.         LOG("goToCommander");
  3819.         return goToTeamMember(COMMANDER);
  3820.     }
  3821.  
  3822.     bool goToMedic()
  3823.     {
  3824.         LOG("goToMedic");
  3825.         return goToTeamMember(FIELD_MEDIC);
  3826.     }
  3827.  
  3828.     bool goToSniper()
  3829.     {
  3830.         LOG("goToSniper");
  3831.         return goToTeamMember(SNIPER);
  3832.     }
  3833.  
  3834.     bool goToScout()
  3835.     {
  3836.         LOG("goToScout");
  3837.         return goToTeamMember(SCOUT);
  3838.     }
  3839.  
  3840.     bool goToSoldier()
  3841.     {
  3842.         LOG("goToSoldier");
  3843.         return goToTeamMember(SOLDIER);
  3844.     }
  3845.  
  3846.     bool needBackup() const
  3847.     {
  3848.         bool result = (fireTime > (g_world->getMoveIndex() - 1));
  3849.         if (result)
  3850.             LOG("Need Backup " << teammateIndex << " fireTime: " << fireTime);
  3851.         return result;
  3852.     }
  3853.  
  3854.     void notifyObstacle(const vector<Position> &path)
  3855.     {
  3856.         if (!getAwayFromWay)
  3857.             obstaclePoints.clear();
  3858.  
  3859.         getAwayFromWay = true;
  3860.  
  3861.         for (int i = 0; i < path.size(); ++i)
  3862.             obstaclePoints.insert(path[i]);
  3863.     }
  3864.  
  3865.     int teammateIndex;
  3866.  
  3867. private:
  3868.     int fireTime;
  3869.     Mission *mission;
  3870.     Point lastRandomPoint;
  3871.     bool hasLastRandomPoint;
  3872.     bool getAwayFromWay;
  3873.     int getAwayMoveIndex, getAwayTrooperOrderIndex;
  3874.     set<Point> obstaclePoints;
  3875. };
  3876.  
  3877. typedef MyTrooper * MyTrooperPtr;
  3878. MyTrooperPtr g_myTroopers[TOOPERS_COUNT];
  3879. MyTrooperPtr g_myTroopersOrdered[TOOPERS_COUNT];
  3880.  
  3881. void GoToPointMission::notifyObstacle(const Trooper *obstacleTrooper)
  3882. {
  3883.     MyTrooperPtr myTrooper = g_myTroopers[obstacleTrooper->getTeammateIndex()];
  3884.     if (myTrooper)
  3885.     {
  3886.         myTrooper->notifyObstacle(path);
  3887.     }
  3888. }
  3889.  
  3890. class MyCommander : public MyTrooper
  3891. {
  3892.     virtual void recalculateMission()
  3893.     {
  3894.         LOG("Commander recalculateMission");
  3895.         if (getCommandFromCoordinationCenter())
  3896.             return;
  3897.  
  3898.         if (findEnemy())
  3899.             return;
  3900.  
  3901.         if (getAway())
  3902.             return;
  3903.  
  3904.         const Trooper * soldier = findTeamTrooperByType(SOLDIER);
  3905.         if (soldier && g_myTroopers[soldier->getTeammateIndex()]->needBackup())
  3906.         {
  3907.             LOG("cgs");
  3908.             if (goToSoldier())
  3909.                 return;
  3910.         }
  3911.  
  3912.         const Trooper * medic = findTeamTrooperByType(FIELD_MEDIC);
  3913.         if (medic && g_myTroopers[medic->getTeammateIndex()]->needBackup())
  3914.         {
  3915.             LOG("cgm");
  3916.             if (goToMedic())
  3917.                 return;
  3918.         }
  3919.  
  3920.         LOG("cgb");
  3921.         if (findBonus())
  3922.             return;
  3923.  
  3924.         if (soldier && soldier->getHitpoints() < soldier->getMaximalHitpoints())
  3925.         {
  3926.             LOG("cgs2");
  3927.             if (goToSoldier())
  3928.                 return;
  3929.         }
  3930.  
  3931.         LOG("cgr");
  3932.         findRandomPoint();
  3933.     }
  3934. };
  3935.  
  3936. class MyMedic : public MyTrooper
  3937. {
  3938.     bool heal()
  3939.     {
  3940.         LOG("Medic heal");
  3941.         const Trooper *self = findTeamTrooper(teammateIndex);
  3942.         Point selfPoint = Point(*self);
  3943.  
  3944.         bool canHeal = false;
  3945.         Point healPoint;
  3946.         int healHitpoints = 0;
  3947.         if (self->getActionPoints() >= g_game->getFieldMedicHealCost())
  3948.         {
  3949.             for (int k = CLOSE_POINTS_N; k --> 0;)
  3950.             {
  3951.                 Point p = getClosePoints(selfPoint, k);
  3952.                 const Trooper * trooper = getTrooper(p);
  3953.                 int points = (selfPoint == p) ? g_game->getFieldMedicHealSelfBonusHitpoints() : g_game->getFieldMedicHealBonusHitpoints();
  3954.                 if (trooper && trooper->isTeammate() && trooper->getHitpoints() < trooper->getMaximalHitpoints())
  3955.                 {
  3956.                     if (!fieldMap.hasEnemies() || trooper->getHitpoints() <= (trooper->getMaximalHitpoints() - points))
  3957.                     {
  3958.                         canHeal = true;
  3959.  
  3960.                         int currentHealHitpoints = trooper->getMaximalHitpoints() - trooper->getHitpoints();
  3961.                         if (currentHealHitpoints > points)
  3962.                             currentHealHitpoints = points;
  3963.  
  3964.                         if (healHitpoints < currentHealHitpoints)
  3965.                         {
  3966.                             healHitpoints = currentHealHitpoints;
  3967.                             healPoint = p;
  3968.                         }
  3969.                     }
  3970.                 }
  3971.             }
  3972.         }
  3973.  
  3974.         // if not healing yorself and there is danger, go to safe point
  3975.         if (canHeal && (healPoint == selfPoint))
  3976.         {
  3977.             if (getDanger(*self, selfPoint) > 0 || estimateDanger(Point(*self), self->getType()) > 20.0)
  3978.             {
  3979.                 const Trooper * commander = findTeamTrooperByType(COMMANDER);
  3980.                 const Trooper * soldier = findTeamTrooperByType(SOLDIER);
  3981.  
  3982.                 int minDist = 1000;
  3983.                 if (commander)
  3984.                 {
  3985.                     int md = selfPoint.sqDist(Point(*commander));
  3986.                     if (md < minDist)
  3987.                         minDist = md;
  3988.                 }
  3989.                 if (soldier)
  3990.                 {
  3991.                     int md = selfPoint.sqDist(Point(*soldier));
  3992.                     if (md < minDist)
  3993.                         minDist = md;
  3994.                 }
  3995.  
  3996.                 if (minDist >= 2)
  3997.                 {
  3998.                     if (goToSafePlace())
  3999.                         return true;
  4000.                 }
  4001.             }
  4002.         }
  4003.  
  4004.         if (canHeal)
  4005.         {
  4006.             g_move->setAction(HEAL);
  4007.             g_move->setX(healPoint.x);
  4008.             g_move->setY(healPoint.y);
  4009.             return true;
  4010.         }
  4011.  
  4012.         return false;
  4013.     }
  4014.  
  4015.     virtual void recalculateMission()
  4016.     {
  4017.         LOG("Medic recalculateMission");
  4018.         if (getCommandFromCoordinationCenter())
  4019.             return;
  4020.  
  4021.         if (findEnemy())
  4022.             return;
  4023.  
  4024.         if (getAway())
  4025.             return;
  4026.  
  4027.         const Trooper * commander = findTeamTrooperByType(COMMANDER);
  4028.         if (commander && (commander->getHitpoints() < commander->getMaximalHitpoints() || g_myTroopers[commander->getTeammateIndex()]->needBackup()))
  4029.         {
  4030.             LOG("mgc");
  4031.             if (goToCommander())
  4032.                 return;
  4033.         }
  4034.  
  4035.         const Trooper * soldier = findTeamTrooperByType(SOLDIER);
  4036.         if (soldier && (soldier->getHitpoints() < soldier->getMaximalHitpoints() || g_myTroopers[soldier->getTeammateIndex()]->needBackup()))
  4037.         {
  4038.             LOG("mgs");
  4039.             if (goToSoldier())
  4040.                 return;
  4041.         }
  4042.  
  4043.         if (commander && coordinationCenter.enemyFound)
  4044.         {
  4045.             if (goToCommander())
  4046.                 return;
  4047.         }
  4048.  
  4049.         if (soldier && coordinationCenter.enemyFound)
  4050.         {
  4051.             if (goToSoldier())
  4052.                 return;
  4053.         }
  4054.  
  4055.         LOG("mgb");
  4056.         if (findBonus())
  4057.             return;
  4058.  
  4059.         LOG("mgc2");
  4060.         if (goToCommander())
  4061.             return;
  4062.  
  4063.         LOG("mgs2");
  4064.         if (goToSoldier())
  4065.             return;
  4066.  
  4067.         LOG("mgr");
  4068.         findRandomPoint();
  4069.     }
  4070. };
  4071.  
  4072. class MySoldier : public MyTrooper
  4073. {
  4074.     virtual void recalculateMission()
  4075.     {
  4076.         LOG("Soldier recalculateMission");
  4077.         if (getCommandFromCoordinationCenter())
  4078.             return;
  4079.  
  4080.         if (findEnemy())
  4081.             return;
  4082.  
  4083.         if (getAway())
  4084.             return;
  4085.  
  4086.         const Trooper * commander = findTeamTrooperByType(COMMANDER);
  4087.         if (commander && g_myTroopers[commander->getTeammateIndex()]->needBackup())
  4088.         {
  4089.             LOG("sgc");
  4090.             if (goToCommander())
  4091.                 return;
  4092.         }
  4093.  
  4094.         const Trooper * medic = findTeamTrooperByType(FIELD_MEDIC);
  4095.         if (medic && g_myTroopers[medic->getTeammateIndex()]->needBackup())
  4096.         {
  4097.             LOG("sgm");
  4098.             if (goToMedic())
  4099.                 return;
  4100.         }
  4101.  
  4102.         if (findBonus())
  4103.             return;
  4104.  
  4105.         const Trooper *self = findTeamTrooper(teammateIndex);
  4106.         if (self->getHitpoints() < self->getMaximalHitpoints())
  4107.         {
  4108.             LOG("sgm");
  4109.             if (goToMedic())
  4110.                 return;
  4111.         }
  4112.  
  4113.         LOG("sgc2");
  4114.         if (goToCommander())
  4115.             return;
  4116.  
  4117.         LOG("sgr");
  4118.         findRandomPoint();
  4119.     }
  4120. };
  4121.  
  4122. class MySniper : public MyTrooper
  4123. {
  4124.     virtual void recalculateMission()
  4125.     {
  4126.         LOG("Soldier recalculateMission");
  4127.         if (getCommandFromCoordinationCenter())
  4128.             return;
  4129.  
  4130.         if (findEnemy())
  4131.             return;
  4132.  
  4133.         if (getAway())
  4134.             return;
  4135.  
  4136.         const Trooper *self = findTeamTrooper(teammateIndex);
  4137.         Point selfPoint = Point(*self);
  4138.         if (getDanger(*self, selfPoint) > 0 || estimateDanger(Point(*self), self->getType()) > 20.0)
  4139.         {
  4140.             const Trooper * commander = findTeamTrooperByType(COMMANDER);
  4141.             const Trooper * soldier = findTeamTrooperByType(SOLDIER);
  4142.  
  4143.             int minDist = 1000;
  4144.             if (commander)
  4145.             {
  4146.                 int md = selfPoint.sqDist(Point(*commander));
  4147.                 if (md < minDist)
  4148.                     minDist = md;
  4149.             }
  4150.             if (soldier)
  4151.             {
  4152.                 int md = selfPoint.sqDist(Point(*soldier));
  4153.                 if (md < minDist)
  4154.                     minDist = md;
  4155.             }
  4156.  
  4157.             if (minDist >= 2)
  4158.             {
  4159.                 if (goToSafePlace())
  4160.                     return;
  4161.             }
  4162.         }
  4163.  
  4164.         const Trooper * commander = findTeamTrooperByType(COMMANDER);
  4165.         if (commander && g_myTroopers[commander->getTeammateIndex()]->needBackup())
  4166.         {
  4167.             LOG("sngc");
  4168.             if (goToCommander())
  4169.                 return;
  4170.         }
  4171.  
  4172.         const Trooper * soldier = findTeamTrooperByType(SOLDIER);
  4173.         if (soldier && g_myTroopers[soldier->getTeammateIndex()]->needBackup())
  4174.         {
  4175.             LOG("sngs");
  4176.             if (goToSoldier())
  4177.                 return;
  4178.         }
  4179.  
  4180.         const Trooper * scout = findTeamTrooperByType(SCOUT);
  4181.         if (scout && g_myTroopers[scout->getTeammateIndex()]->needBackup())
  4182.         {
  4183.             LOG("sngsc");
  4184.             if (goToScout())
  4185.                 return;
  4186.         }
  4187.  
  4188.         const Trooper * medic = findTeamTrooperByType(FIELD_MEDIC);
  4189.         if (medic && g_myTroopers[medic->getTeammateIndex()]->needBackup())
  4190.         {
  4191.             LOG("sngm");
  4192.             if (goToMedic())
  4193.                 return;
  4194.         }
  4195.  
  4196.         if (findBonus())
  4197.             return;
  4198.  
  4199.         if (self->getHitpoints() < self->getMaximalHitpoints())
  4200.         {
  4201.             LOG("sngm");
  4202.             if (goToMedic())
  4203.                 return;
  4204.         }
  4205.  
  4206.         LOG("sngc2");
  4207.         if (goToCommander())
  4208.             return;
  4209.  
  4210.         LOG("sngr");
  4211.         findRandomPoint();
  4212.     }
  4213. };
  4214.  
  4215. class MyScout : public MyTrooper
  4216. {
  4217.     virtual void recalculateMission()
  4218.     {
  4219.         LOG("Soldier recalculateMission");
  4220.         if (getCommandFromCoordinationCenter())
  4221.             return;
  4222.  
  4223.         if (findEnemy())
  4224.             return;
  4225.  
  4226.         if (getAway())
  4227.             return;
  4228.  
  4229.         const Trooper *self = findTeamTrooper(teammateIndex);
  4230.         Point selfPoint = Point(*self);
  4231.         if (getDanger(*self, selfPoint) > 0 || estimateDanger(Point(*self), self->getType()) > 20.0)
  4232.         {
  4233.             const Trooper * commander = findTeamTrooperByType(COMMANDER);
  4234.             const Trooper * soldier = findTeamTrooperByType(SOLDIER);
  4235.  
  4236.             int minDist = 1000;
  4237.             if (commander)
  4238.             {
  4239.                 int md = selfPoint.sqDist(Point(*commander));
  4240.                 if (md < minDist)
  4241.                     minDist = md;
  4242.             }
  4243.             if (soldier)
  4244.             {
  4245.                 int md = selfPoint.sqDist(Point(*soldier));
  4246.                 if (md < minDist)
  4247.                     minDist = md;
  4248.             }
  4249.  
  4250.             if (minDist >= 2)
  4251.             {
  4252.                 if (goToSafePlace())
  4253.                     return;
  4254.             }
  4255.         }
  4256.  
  4257.         const Trooper * commander = findTeamTrooperByType(COMMANDER);
  4258.         if (commander && g_myTroopers[commander->getTeammateIndex()]->needBackup())
  4259.         {
  4260.             LOG("sngc");
  4261.             if (goToCommander())
  4262.                 return;
  4263.         }
  4264.  
  4265.         const Trooper * soldier = findTeamTrooperByType(SOLDIER);
  4266.         if (soldier && g_myTroopers[soldier->getTeammateIndex()]->needBackup())
  4267.         {
  4268.             LOG("scgs");
  4269.             if (goToSoldier())
  4270.                 return;
  4271.         }
  4272.  
  4273.         const Trooper * sniper = findTeamTrooperByType(SNIPER);
  4274.         if (sniper && g_myTroopers[sniper->getTeammateIndex()]->needBackup())
  4275.         {
  4276.             LOG("scgsn");
  4277.             if (goToSniper())
  4278.                 return;
  4279.         }
  4280.  
  4281.         const Trooper * medic = findTeamTrooperByType(FIELD_MEDIC);
  4282.         if (medic && g_myTroopers[medic->getTeammateIndex()]->needBackup())
  4283.         {
  4284.             LOG("scgm");
  4285.             if (goToMedic())
  4286.                 return;
  4287.         }
  4288.  
  4289.         if (findBonus())
  4290.             return;
  4291.  
  4292.         if (self->getHitpoints() < self->getMaximalHitpoints())
  4293.         {
  4294.             LOG("scgm");
  4295.             if (goToMedic())
  4296.                 return;
  4297.         }
  4298.  
  4299.         LOG("scgc2");
  4300.         if (goToCommander())
  4301.             return;
  4302.  
  4303.         LOG("scgr");
  4304.         findRandomPoint();
  4305.     }
  4306. };
  4307.  
  4308.  
  4309.  
  4310. void initialize()
  4311. {
  4312.     LOG("Initialize");
  4313.     initializeNearDistDeltas();
  4314.     fieldMap.initialize();
  4315.     trooperDistributionMap.initialize();;
  4316.  
  4317. #if ENABLE_LOGGING
  4318.     //g_world->saveMap();
  4319. #endif
  4320.  
  4321.     for (int i = 0; i < TOOPERS_COUNT; ++i)
  4322.     {
  4323.         g_myTroopers[i] = NULL;
  4324.     }
  4325.  
  4326.     ENEMY_TROOPERSN = 0;
  4327.     const vector<Trooper>& troopers = g_world->getTroopers();
  4328.     for (int i = 0; i < troopers.size(); ++i)
  4329.     {
  4330.         const Trooper &trooper = troopers[i];
  4331.         if (trooper.isTeammate())
  4332.         {
  4333.             ENEMY_TROOPERSN++;
  4334.             TrooperType type = trooper.getType();
  4335.             MyTrooperPtr myTooper = NULL;
  4336.             if (type == COMMANDER)
  4337.             {
  4338.                 myTooper = new MyCommander;
  4339.             }
  4340.             else if (type == FIELD_MEDIC)
  4341.             {
  4342.                 myTooper = new MyMedic;
  4343.             }
  4344.             else if(type == SOLDIER)
  4345.             {
  4346.                 myTooper = new MySoldier;
  4347.             }
  4348.             else if(type == SNIPER)
  4349.             {
  4350.                 myTooper = new MySniper;
  4351.             }
  4352.             else if(type == SCOUT)
  4353.             {
  4354.                 myTooper = new MyScout;
  4355.             }
  4356.  
  4357.             if (myTooper)
  4358.             {
  4359.                 myTooper->teammateIndex = trooper.getTeammateIndex();
  4360.                 g_myTroopers[trooper.getTeammateIndex()] = myTooper;
  4361.             }
  4362.         }
  4363.     }
  4364.     ENEMY_TROOPERSN *= 3;
  4365. }
  4366.  
  4367. void newMove()
  4368. {
  4369.     for (int i = 0; i < TOOPERS_COUNT; ++i)
  4370.     {
  4371.         g_myTroopersOrdered[i] = NULL;
  4372.     }
  4373.  
  4374.     for (int i = 0 ; i < TOOPERS_COUNT; ++i)
  4375.     {
  4376.         MyTrooperPtr myTrooper = g_myTroopers[i];
  4377.         if (myTrooper)
  4378.         {
  4379.             const Trooper *trooper = findTeamTrooper(myTrooper->teammateIndex);
  4380.             if (trooper != NULL)
  4381.             {
  4382.                 TrooperType type = trooper->getType();
  4383.                 if (moveOrder.count(type))
  4384.                 {
  4385.                     g_myTroopersOrdered[moveOrder[type]] = myTrooper;
  4386.                 }
  4387.             }
  4388.             else
  4389.             {
  4390.                 delete g_myTroopers[i];
  4391.                 g_myTroopers[i] = NULL;
  4392.             }
  4393.         }
  4394.     }
  4395.  
  4396.     for (int i = 0; i < TOOPERS_COUNT; ++i)
  4397.     {
  4398.         if (g_myTroopersOrdered[i])
  4399.         {
  4400.             g_myTroopersOrdered[i]->recalculateMission();
  4401.         }
  4402.     }
  4403. }
  4404.  
  4405. bool g_newMove;
  4406. void updateMoveIndex()
  4407. {
  4408.     g_newMove = false;
  4409.     static TrooperType oldType = UNKNOWN_TROOPER;
  4410.     static int oldMoveIndex = -1;
  4411.  
  4412.     if (moveIndex == -1)
  4413.     {
  4414.         initialize();
  4415.     }
  4416.  
  4417.     moveIndex = g_world->getMoveIndex();
  4418.     if (oldMoveIndex != moveIndex)
  4419.     {
  4420.         oldMoveIndex = moveIndex;
  4421.         g_newMove = true;
  4422.     }
  4423.  
  4424.     if (moveIndex == 0)
  4425.     {
  4426.         if (oldType == UNKNOWN_TROOPER)
  4427.         {
  4428.             trooperMoveOrderIndex = 0;
  4429.         }
  4430.         else if (g_self->getType() != oldType)
  4431.         {
  4432.             trooperMoveOrderIndex++;
  4433.         }
  4434.         oldType = g_self->getType();
  4435.         moveOrder[oldType] = trooperMoveOrderIndex;
  4436.     }
  4437.     else
  4438.     {
  4439.         trooperMoveOrderIndex = moveOrder[g_self->getType()];
  4440.     }
  4441. }
  4442.  
  4443. void updateTroopersMap()
  4444. {
  4445.     for (int i = 0; i < W * H; ++i)
  4446.         troopersMap[i] = NULL;
  4447.  
  4448.     const vector<Trooper>& troopers = g_world->getTroopers();
  4449.     for (int i = 0; i < troopers.size(); ++i)
  4450.     {
  4451.         const Trooper &trooper = troopers[i];
  4452.         troopersMap[trooper.getY() * W + trooper.getX()] = &trooper;
  4453.     }
  4454. }
  4455.  
  4456. void logMove()
  4457. {
  4458.     if (!ENABLE_LOGGING)
  4459.         return;
  4460.  
  4461.     ActionType actionType = g_move->getAction();
  4462.     string actionName;
  4463.     if (actionType == END_TURN)
  4464.         actionName = "END_TURN";
  4465.     else if (actionType == MOVE)
  4466.         actionName = "MOVE";
  4467.     else if (actionType == SHOOT)
  4468.         actionName = "SHOOT";
  4469.     else if (actionType == RAISE_STANCE)
  4470.         actionName = "RAISE_STANCE";
  4471.     else if (actionType == LOWER_STANCE)
  4472.         actionName = "LOWER_STANCE";
  4473.     else if (actionType == THROW_GRENADE)
  4474.         actionName = "THROW_GRENADE";
  4475.     else if (actionType == USE_MEDIKIT)
  4476.         actionName = "USE_MEDIKIT";
  4477.     else if (actionType == EAT_FIELD_RATION)
  4478.         actionName = "EAT_FIELD_RATION";
  4479.     else if (actionType == HEAL)
  4480.         actionName = "HEAL";
  4481.     else if (actionType == REQUEST_ENEMY_DISPOSITION)
  4482.         actionName = "REQUEST_ENEMY_DISPOSITION";
  4483.  
  4484.     LOG("Action " << actionName << " " << g_move->getX() << " " << g_move->getY());
  4485. }
  4486.  
  4487. void makeMove()
  4488. {
  4489.     LOG("actionPoints " << g_self->getActionPoints());
  4490.  
  4491.     MyTrooperPtr myTrooper = g_myTroopers[g_self->getTeammateIndex()];
  4492.     if (myTrooper)
  4493.     {
  4494.         if (myTrooper->useMedikit())
  4495.             return;
  4496.  
  4497.         if (myTrooper->heal())
  4498.             return;
  4499.  
  4500.         myTrooper->recalculateMission();
  4501.         if (myTrooper->getMission())
  4502.         {
  4503.             if (!myTrooper->getMission()->perform())
  4504.                 myTrooper->goToSafePlace();
  4505.         }
  4506.     }
  4507. }
  4508.  
  4509. #if ENABLE_LOGGING
  4510. struct Env
  4511. {
  4512.     Env()
  4513.     {
  4514.  
  4515.     }
  4516.  
  4517.     int moveIndex;
  4518.     std::vector<Player> players;
  4519.     std::vector<Trooper> troopers;
  4520.     std::vector<Bonus> bonuses;
  4521.     std::vector<std::vector<CellType> > cells;
  4522.     std::vector<bool> cellVisibilities;
  4523. } env;
  4524.  
  4525. void makeEnv()
  4526. {
  4527.     Trooper commander = Trooper(1, 5, 15, 1, 0, true, COMMANDER, STANDING,
  4528.     100, 100, 10, 10, 9.0, 8.0, 3, 25, 30, 35, 30, false, false, false);
  4529.     env.troopers.push_back(commander);
  4530.  
  4531.     Trooper soldier = Trooper(1, 5, 16, 1, 1, true, SOLDIER, STANDING,
  4532.         100, 100, 10, 10, 9.0, 8.0, 3, 25, 30, 35, 30, false, false, false);
  4533.     env.troopers.push_back(soldier);
  4534.  
  4535.     env.cells.resize(30);
  4536.     for (int x = 0; x < 30; ++x)
  4537.     {
  4538.         env.cells[x].resize(20);
  4539.         for (int y = 0; y < 20; ++y)
  4540.         {
  4541.             env.cells[x][y] = FREE;
  4542.  
  4543.             if (x > 10 && x < 15 && y > 7 && y < 12)
  4544.                 env.cells[x][y] = HIGH_COVER;
  4545.         }
  4546.     }
  4547.  
  4548.     env.cellVisibilities.resize(30 * 20 * 30 * 20 * 3);
  4549.     for (int i = 0; i < env.cellVisibilities.size(); ++i)
  4550.     {
  4551.         env.cellVisibilities[i] = true;
  4552.     }
  4553.  
  4554.  
  4555.     Bonus b = Bonus(1, 25, 15, MEDIKIT);
  4556.     env.bonuses.push_back(b);
  4557.  
  4558.  
  4559.     g_world = new World(1, 30, 20, env.players, env.troopers, env.bonuses, env.cells, env.cellVisibilities);
  4560.  
  4561.     g_game = new Game(50,
  4562.         100, 100,
  4563.         100, 100,
  4564.         2, 2, 4, 6,
  4565.         2, 5.0,
  4566.         9, 5,
  4567.         2, 50, 50,
  4568.         0, 1, 2,
  4569.         12, 10,
  4570.         2.0, 1.0,
  4571.         5, 5, 80, 60,
  4572.         2, 50, 30,
  4573.         2, 5);
  4574.  
  4575.     g_self = &g_world->getTroopers()[0];
  4576.  
  4577. }
  4578.  
  4579. void test()
  4580. {
  4581.     makeEnv();
  4582.  
  4583.     troopersMap.resize(W * H);
  4584.     updateTroopersMap();
  4585.     updateMoveIndex();
  4586.     fieldMap.update();
  4587.  
  4588.  
  4589.  
  4590.     coordinationCenter.updateMissions();
  4591.  
  4592.     logMap(NULL);
  4593. }
  4594.  
  4595. #endif
  4596.  
  4597. void MyStrategy::move(const Trooper& self, const World& world, const Game& game, Move& move) {
  4598.     g_self = &self;
  4599.     g_world = &world;
  4600.     g_game = &game;
  4601.     g_move = &move;
  4602.  
  4603.     LOG("BNS M" << self.isHoldingMedikit() << " G" << self.isHoldingGrenade() << " F" << self.isHoldingFieldRation());
  4604.  
  4605.     troopersMap.resize(W * H);
  4606.     updateTroopersMap();
  4607.     updateMoveIndex();
  4608.     fieldMap.update();
  4609.  
  4610.     trooperDistributionMap.update();
  4611.     coordinationCenter.updateMissions();
  4612.  
  4613.     if (g_newMove)
  4614.     {
  4615.         g_newMove = false;
  4616.         newMove();
  4617.     }
  4618.  
  4619.     makeMove();
  4620.  
  4621.     logMap(NULL);
  4622.  
  4623.     logMove();
  4624.     fieldMap.updateAfterMove();
  4625.     coordinationCenter.updateState();
  4626.  
  4627.     trooperDistributionMap.log();
  4628. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement