text: #pragma once
  
  #include "UnitData.h"
  
  //#define FAP_DEBUG 1
  
  namespace UAlbertaBot {
  
      struct FastAPproximation {
          struct FAPUnit {
              FAPUnit(BWAPI::Unit u);
              FAPUnit(UnitInfo ui);
              const FAPUnit &operator=(const FAPUnit &other) const;
  
              int id = 0;
  
              mutable int x = 0, y = 0;
  
              mutable int health = 0;
              mutable int maxHealth = 0;
              mutable int armor = 0;
  
              mutable int shields = 0;
              mutable int shieldArmor = 0;
              mutable int maxShields = 0;
  
              mutable double speed = 0;
              mutable bool flying = 0;
              mutable int elevation = -1;
  
              mutable bool undetected = false;
  
              mutable BWAPI::UnitSizeType unitSize;
  
              mutable int groundDamage = 0;
              mutable int groundCooldown = 0;
              mutable int groundMaxRange = 0;
              mutable int groundMinRange = 0;
              mutable BWAPI::DamageType groundDamageType;
  
              mutable int airDamage = 0;
              mutable int airCooldown = 0;
              mutable int airMaxRange = 0;
              mutable int airMinRange = 0;
              mutable BWAPI::DamageType airDamageType;
  
              mutable BWAPI::UnitType unitType;
              mutable BWAPI::Player player = nullptr;
              mutable bool isOrganic = false;
              mutable bool didHealThisFrame = false;
              mutable int score = 0;
  
              mutable int attackCooldownRemaining = 0;
  
              bool operator<(const FAPUnit &other) const;
          };
  
          FastAPproximation();
  
          void addUnitPlayer1(FAPUnit fu);
          void addIfCombatUnitPlayer1(FAPUnit fu);
          void addUnitPlayer2(FAPUnit fu);
          void addIfCombatUnitPlayer2(FAPUnit fu);
  
          void simulate(int nFrames = 96); // = 24*4, 4 seconds on fastest
  
          std::pair<int, int> playerScores() const;
          std::pair<int, int> playerScoresUnits() const;
          std::pair<int, int> playerScoresBuildings() const;
          std::pair<std::vector<FAPUnit> *, std::vector<FAPUnit> *> getState();
          void clearState();
  
      private:
  #ifdef FAP_DEBUG
          std::ofstream debug;
  #endif
  
          std::vector<FAPUnit> player1, player2;
  
          // Current approach to collisions: allow two units to share the same grid cell, using half-tile resolution
          // This seems to strike a reasonable balance between improving how large melee armies are simmed and avoiding
          // expensive collision-based pathing calculations
          unsigned short collision[512][512] = {};
  
          int frame;
          bool didSomething;
          void dealDamage(const FastAPproximation::FAPUnit &fu, int damage,
              BWAPI::DamageType damageType) const;
          int distance(const FastAPproximation::FAPUnit &u1,
              const FastAPproximation::FAPUnit &u2) const;
          void updatePosition(const FAPUnit &fu, int x, int y);
          bool isSuicideUnit(BWAPI::UnitType ut);
          void unitsim(const FAPUnit &fu, std::vector<FAPUnit> &enemyUnits);
          void medicsim(const FAPUnit &fu, std::vector<FAPUnit> &friendlyUnits);
          bool suicideSim(const FAPUnit &fu, std::vector<FAPUnit> &enemyUnits);
          void isimulate();
          void unitDeath(const FAPUnit &fu, std::vector<FAPUnit> &itsFriendlies);
          void convertToUnitType(const FAPUnit &fu, BWAPI::UnitType ut);
          };
  
  }
  
  extern UAlbertaBot::FastAPproximation fap;