TorchCraftAI
A bot for machine learning research on StarCraft: Brood War
tactics.h
1 /*
2  * Copyright (c) 2017-present, Facebook, Inc.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #pragma once
9 
10 #include "module.h"
11 #include "state.h"
12 #include "task.h"
13 #include "tilesinfo.h"
14 
15 #include <random>
16 
17 DECLARE_uint64(tactics_fight_or_flee_interval);
18 
19 namespace cherrypi {
20 
21 struct Unit;
22 
23 class TacticsTask : public Task {
24  public:
25  TacticsTask(int upcId) : Task(upcId) {}
26 
27  virtual void update(State* state) override {
29  }
30 
31  virtual void cancel(State* state) override {
32  units().clear();
33  state->board()->updateTasksByUnit(this);
34 
35  Task::cancel(state);
36  }
37 
38  void setUnits(State* state, std::unordered_set<Unit*> units) {
39  this->units() = std::move(units);
40  state->board()->updateTasksByUnit(this);
41  }
42 
43  std::vector<Unit*> myUnits;
46  bool isFighting = false;
47 
48  virtual const char* getName() const override {
49  return "Tactics";
50  };
51 };
52 
53 struct TacticsGroup {
54  std::vector<Unit*> enemyUnits;
55  std::vector<Unit*> myUnits;
56  Unit* targetUnit = nullptr;
59  std::shared_ptr<TacticsTask> task;
60  bool hasEnoughUnits = false;
61  bool hasEnemyGroundUnits = false;
62  bool hasEnemyAirUnits = false;
63  bool hasEnemyBuildings = false;
64  bool hasEnemyCloakedUnits = false;
65  bool hasEnemyTanks = false;
66  bool hasEnemyReavers = false;
67  bool hasEnemyBunkers = false;
68  bool hasEnemyWorkers = false;
69  bool hasEnemyAntiGround = false;
70  bool hasEnemyAntiAir = false;
71  bool hasEnemyStaticDefence = false;
72  bool enemiesAreAttacking = false;
73  bool enemiesInOurBase = false;
74  bool isAggressiveGroup = true;
75  double score = 0.0;
76  bool searchAndDestroy = false;
77  bool isIdleGroup = false;
78  bool isScoutGroup = false;
79  bool enemyIsOnlyWorkers = true;
80 };
81 
83  Tile* tile = nullptr;
84  TacticsGroup* group = nullptr;
85  Unit* nearestEnemy = nullptr;
86 };
87 
89  double score = 0;
90  bool airFight = true;
91  bool groundFight = true;
92 };
93 
94 struct TacticsState {
95  public:
96  int srcUpcId_;
97  // The distance around each enemy unit that will be considered "inside" their
98  // group. Any of our units in this area will be assigned to the group, and
99  // this effectively ends up being the distance away from enemy units that
100  // our units flee.
101  float insideGroupDistance_ = 4 * 16;
102  uint8_t visitNumber_ = 0;
103  std::vector<uint8_t> tileVisitTracker_ =
104  std::vector<uint8_t>(TilesInfo::tilesWidth * TilesInfo::tilesHeight);
105  std::vector<uint8_t> tileSpotTakenTracker_ =
106  std::vector<uint8_t>(TilesInfo::tilesWidth * TilesInfo::tilesHeight);
107  std::vector<TacticsMapNode> nodeInsideGroupTracker_ =
108  std::vector<TacticsMapNode>(
110  std::vector<TacticsGroup*> nodeGroupEdgeTracker_ = std::vector<TacticsGroup*>(
112  std::unordered_map<Unit*, TacticsGroup*> hardAssignedUnits_;
113  std::unordered_map<Unit*, TacticsGroup*> softAssignedUnits_;
114  std::list<TacticsGroup> groups_;
115 
116  // Used for creating groups
117  void createTacticsGroups(State* state, std::vector<uint8_t>& inBaseArea);
118  void collectMapNodesCoveredByGroups(State* state);
119  void assignUnits(
120  State* state,
121  std::unordered_set<Unit*>& wasInAGroup,
122  std::vector<Unit*> leftoverWorkers,
123  std::vector<std::shared_ptr<Task>>& tasks);
124 
125  // Used for fight/flee prediction
126  TacticsFightScores combatSimFightPrediction(
127  State* state,
128  TacticsGroup& g,
129  std::unordered_map<Unit*, int>& nmyInStaticDefenceRange,
130  std::unordered_map<Unit*, int>& nmyAlmostInStaticDefenceRange);
131  Unit* getBestEnemyTarget(
132  State* state,
133  TacticsGroup& g,
134  Unit* u,
135  std::unordered_map<Unit*, int>& meleeTargetCount,
136  std::unordered_map<Unit*, int>& lastTargetInRange,
137  bool& anySpiderMinesNearby);
138  bool shouldRunFromHiddenTarget(TacticsGroup& g, Unit* u, Unit* target);
139 
140  // Used for processing orders
141  Position
142  idleGroupTargetPos(State* state, Unit* u, std::vector<uint8_t>& inBaseArea);
143  Position findRunPos(State* state, Unit* u, std::vector<uint16_t>& fleeScore);
144  Position scoutGroupTargetPos(
145  State* state,
146  TacticsGroup& g,
147  Unit* u,
148  std::unordered_map<Unit*, std::pair<int, Position>>& scoutTarget,
149  std::ranlux24& rngEngine);
150  Position searchAndDestroyGroupTargetPos(
151  State* state,
152  Unit* u,
153  std::unordered_map<Unit*, std::pair<int, Position>>&
154  searchAndDestroyTarget,
155  std::ranlux24& rngEngine);
156 
157  private:
158  // Used for creating groups
159  void addEnemyUnitToGroup(
160  State* state,
161  Unit* u,
162  TacticsGroup* group,
163  std::vector<uint8_t> const& inBaseArea);
164  void assignUnitsBasedOnPreviousAssignments(
165  State* state,
166  std::unordered_set<Unit*>& wasInAGroup,
167  std::vector<std::shared_ptr<Task>>& tasks);
168  void collectAvailableUnits(State* state, std::vector<Unit*>& availableUnits);
169  void assignScoutingUnits(State* state, std::vector<Unit*>& availableUnits);
170  bool aggressiveUnit(State* state, Unit* unit);
171  double scoreUnitForGroup(State* state, Unit* u, TacticsGroup& g);
172  void assignNecessaryUnits(State* state, std::vector<Unit*>& availableUnits);
173  void assignDetectors(std::vector<Unit*>& availableUnits);
174  void assignLeftovers(
175  State* state,
176  std::vector<Unit*>& availableUnits,
177  std::vector<Unit*>& leftoverWorkers);
178 
179  // Used for fight/flee prediction
180  bool isAllyInRangeOfEnemy(TacticsGroup& g);
181  void prepareCombatSimulationData(
182  State* state,
183  TacticsGroup& g,
184  std::vector<Unit*>& nearbyAllies,
185  std::unordered_set<Unit*>& nearbyEnemies,
186  std::unordered_map<Unit*, int>& nmyInStaticDefenseRange,
187  std::unordered_map<Unit*, int>& nmyAlmostInStaticDefenseRange);
188  std::pair<double, double> combatSimCalculateFightScoreMod(
189  State* state,
190  TacticsGroup& g,
191  std::vector<Unit*>& nearbyAllies,
192  std::unordered_set<Unit*>& nearbyEnemies,
193  std::unordered_map<Unit*, int>& nmyInStaticDefenseRange);
194 
195  // Used for order processing
196  int getRandomCoord(int range, std::ranlux24& rngEngine);
197  Position
198  findMoveAwayPos(State* state, Unit* u, Position source, float distance);
199 };
200 
201 /**
202  * The Tactics module decides where on the map to allocate combat units.
203  *
204  * * Identifies clusters of enemy units, and which allied units are currently
205  * engaged with them.
206  * * Allocates other allied units to various jobs like attacking, defending,
207  * and scouting.
208  * * Uses a combat simulator to identify which clusters of allies should fight
209  * and which should flee (and where they should go)
210  *
211  * Finally, outputs a UPC for each group of units indicating where they should
212  * go or what they should fight.
213  */
214 class TacticsModule : public Module {
215  public:
216  virtual void step(State* s) override;
217  virtual void onGameEnd(State* s) override;
218 
219  protected:
220  UpcId findSourceUpc(State* s);
221 
222  FrameNum lastProcess_ = 0;
223 
224  virtual void process(State* state, int srcUpcId);
225 
226  // Methods likely useful in all TacticsModule subclasses
227 
228  /// Create groups based on distance rules, useful for the
229  /// scouting/worker/search and destroy functionality.
230  void formGroups(
231  State* state,
232  TacticsState& tstate,
233  std::vector<Unit*>& leftoverWorkers,
234  std::unordered_set<Unit*>& wasInAGroup);
235 
236  /// Return unused workers, doesn't rely on group creation, just on existance
237  /// of
238  /// leftoverWorkers which specifies the workers and wasInAGroup which
239  /// specifies
240  /// which will automatically be reassigned based on attachement to a
241  /// previously
242  /// existing task
243  void distributeLeftoverWorkers(
244  std::unordered_set<Unit*>& unitSet,
245  std::vector<Unit*>& leftoverWorkers,
246  std::unordered_set<Unit*>& wasInAGroup);
247 
248  /// Takes the scouting & search and destroy groups created in formGroups and
249  /// issues the commands, also returns leftoverWorkers.
250  void processNonFightFleeGroup(
251  State* state,
252  TacticsState& tstate,
253  TacticsGroup& g,
254  std::vector<Unit*>& leftoverWorkers,
255  std::unordered_set<Unit*>& wasInAGroup);
256 
257  /// Creates a move upc for unit with given target
258  void moveUnit(State* state, UpcId srcUpcId, Unit* u, Position target);
259 
260  // Methods likely only usable in the subclasses very similar to the base
261  // module.
262 
263  /// Uses combat sim + rules to put each unit into a fight or flee vector
264  std::pair<double, double> distributeFightFlee(
265  State* state,
266  TacticsState& tstate,
267  TacticsGroup& g,
268  std::vector<Unit*>& fightUnits,
269  std::vector<Unit*>& fleeUnits);
270 
271  /// Takes a group and the fight/flee assignments and issues commands
272  void processOrders(
273  State* state,
274  TacticsGroup& g,
275  int srcUpcId,
276  double deleteScore,
277  double moveScore,
278  std::vector<Unit*>& fightUnits,
279  std::vector<Unit*>& fleeUnits,
280  std::vector<Unit*>& leftoverWorkers,
281  std::unordered_set<Unit*>& wasInAGroup);
282 
283  std::vector<uint8_t> inBaseArea_ =
284  std::vector<uint8_t>(TilesInfo::tilesWidth * TilesInfo::tilesHeight);
285  FrameNum lastUpdateInBaseArea_ = 0;
286 
287  std::vector<uint16_t> fleeScore_ =
288  std::vector<uint16_t>(TilesInfo::tilesWidth * TilesInfo::tilesHeight);
289  FrameNum lastUpdateFleeScore_ = 0;
290 
291  std::unordered_map<Unit*, std::pair<int, Position>> searchAndDestroyTarget_;
292  std::unordered_map<Unit*, std::pair<int, Position>> scoutTarget_;
293  std::ranlux24 rngEngine_{42};
294 
295  std::unordered_map<Unit*, int> lastTargetInRange_;
296  std::unordered_map<Unit*, int> lastMove_;
297 
298  virtual bool alwaysFight() {
299  return false;
300  }
301 };
302 
304  virtual bool alwaysFight() override {
305  return true;
306  }
307 };
308 
309 } // namespace cherrypi
Game state.
Definition: state.h:42
int FrameNum
Definition: basetypes.h:22
std::list< TacticsGroup > groups_
Definition: tactics.h:114
std::unordered_map< Unit *, std::pair< int, Position > > searchAndDestroyTarget_
Definition: tactics.h:291
TacticsTask(int upcId)
Definition: tactics.h:25
UpcId upcId() const
UPC id in Blackboard that caused this Task to be spawned.
Definition: task.h:90
std::unordered_set< Unit * > const & units() const
A set of units occupied performing this task.
Definition: task.h:94
std::vector< Unit * > myUnits
Definition: tactics.h:43
void updateTasksByUnit(Task *task)
Updates the taskByUnit mapping, should be called after setUnits on a task.
Definition: blackboard.cpp:328
virtual const char * getName() const override
A name for this task, for debugging purposes.
Definition: tactics.h:48
std::vector< Unit * > enemyUnits
Definition: tactics.h:54
virtual void cancel(State *state) override
Definition: tactics.h:31
Position averagePos
Definition: tactics.h:58
virtual void removeDeadOrReassignedUnits(State *state)
Remove units that have been assigned to another task and units that have died.
Definition: task.cpp:36
Definition: tactics.h:53
Definition: tactics.h:94
The primary way for modules to publish their activity.
Definition: task.h:50
virtual void cancel(State *)
Definition: task.cpp:18
std::unordered_map< Unit *, std::pair< int, Position > > scoutTarget_
Definition: tactics.h:292
Definition: tactics.h:82
replayer::Unit Unit
Definition: state.h:36
Definition: tactics.h:23
Position targetPos
Definition: tactics.h:57
Represents a unit in the game.
Definition: unitsinfo.h:35
static const unsigned tilesWidth
Definition: tilesinfo.h:98
std::unordered_map< Unit *, int > lastTargetInRange_
Definition: tactics.h:295
Position averagePos
Definition: tactics.h:45
static const unsigned tilesHeight
Definition: tilesinfo.h:99
int srcUpcId_
Definition: tactics.h:96
std::unordered_map< Unit *, TacticsGroup * > softAssignedUnits_
Definition: tactics.h:113
Blackboard * board() const
Definition: state.h:99
virtual void update(State *state) override
Definition: tactics.h:27
Represents a tile on the map.
Definition: tilesinfo.h:29
std::vector< Unit * > myUnits
Definition: tactics.h:55
Definition: tactics.h:303
std::shared_ptr< TacticsTask > task
Definition: tactics.h:59
The Tactics module decides where on the map to allocate combat units.
Definition: tactics.h:214
Main namespace for bot-related code.
Definition: areainfo.cpp:17
std::unordered_map< Unit *, TacticsGroup * > hardAssignedUnits_
Definition: tactics.h:112
Definition: tactics.h:88
int UpcId
Definition: basetypes.h:23
Position targetPos
Definition: tactics.h:44
Interface for bot modules.
Definition: module.h:30
virtual bool alwaysFight()
Definition: tactics.h:298
bool isFighting
Definition: tactics.h:46
std::unordered_map< Unit *, int > lastMove_
Definition: tactics.h:296
void setUnits(State *state, std::unordered_set< Unit * > units)
Definition: tactics.h:38