////////////////////////////////////////////////////////////////////////// // // This file is part of the BWEM Library. // BWEM is free software, licensed under the MIT/X11 License. // A copy of the license is provided with the library in the LICENSE file. // Copyright (c) 2015, 2017, Igor Dimitrijevic // ////////////////////////////////////////////////////////////////////////// #ifndef BWEM_AREA_H #define BWEM_AREA_H #include #include "bwapiExt.h" #include "utils.h" #include "defs.h" namespace BWEM { class Mineral; class Geyser; class Tile; class Base; class ChokePoint; class Map; namespace detail { class Graph; } ////////////////////////////////////////////////////////////////////////////////////////////// // // // class Area // // ////////////////////////////////////////////////////////////////////////////////////////////// // // Areas are regions that BWEM automatically computes from Brood War's maps // Areas aim at capturing relevant regions that can be walked, though they may contain small inner non walkable regions called lakes. // More formally: // - An area consists in a set of 4-connected MiniTiles, which are either Terrain-MiniTiles or Lake-MiniTiles. // - An Area is delimited by the side of the Map, by Water-MiniTiles, or by other Areas. In the latter case // the adjoining Areas are called neighbouring Areas, and each pair of such Areas defines at least one ChokePoint. // Like ChokePoints and Bases, the number and the addresses of Area instances remain unchanged. // To access Areas one can use their ids or their addresses with equivalent efficiency. // // Areas inherit utils::Markable, which provides marking ability // Areas inherit utils::UserData, which provides free-to-use data. class Area : public utils::Markable, public utils::UserData { public: typedef int16_t id; typedef int16_t groupId; // Unique id > 0 of this Area. Range = 1 .. Map::Areas().size() // this == Map::GetArea(Id()) // Id() == Map::GetMiniTile(w).AreaId() for each walkable MiniTile w in this Area. // Area::ids are guaranteed to remain unchanged. id Id() const { return m_id; } // Unique id > 0 of the group of Areas which are accessible from this Area. // For each pair (a, b) of Areas: a->GroupId() == b->GroupId() <==> a->AccessibleFrom(b) // A groupId uniquely identifies a maximum set of mutually accessible Areas, that is, in the absence of blocking ChokePoints, a continent. groupId GroupId() const { return m_groupId; } // Bounding box of this Area. const BWAPI::TilePosition & TopLeft() const { return m_topLeft ; } const BWAPI::TilePosition & BottomRight() const { return m_bottomRight ; } BWAPI::TilePosition BoundingBoxSize() const; // Position of the MiniTile with the highest Altitude() value. const BWAPI::WalkPosition & Top() const { return m_top; } // Returns Map::GetMiniTile(Top()).Altitude(). altitude_t MaxAltitude() const { return m_maxAltitude; } // Returns the number of MiniTiles in this Area. // This most accurately defines the size of this Area. int MiniTiles() const { return m_miniTiles; } // Returns the percentage of low ground Tiles in this Area. int LowGroundPercentage() const { return (m_tiles - m_highGroundTiles - m_veryHighGroundTiles) * 100 / m_tiles; } // Returns the percentage of high ground Tiles in this Area. int HighGroundPercentage() const { return m_highGroundTiles * 100 / m_tiles; } // Returns the percentage of very high ground Tiles in this Area. int VeryHighGroundPercentage() const { return m_veryHighGroundTiles * 100 / m_tiles; } // Returns the ChokePoints between this Area and the neighbouring ones. // Note: if there are no neighbouring Areas, then an empty set is returned. // Note there may be more ChokePoints returned than the number of neighbouring Areas, as there may be several ChokePoints between two Areas (Cf. ChokePoints(const Area * pArea)). const std::vector & ChokePoints() const { return m_ChokePoints; } // Returns the ChokePoints between this Area and pArea. // Assumes pArea is a neighbour of this Area, i.e. ChokePointsByArea().find(pArea) != ChokePointsByArea().end() // Note: there is always at least one ChokePoint between two neighbouring Areas. const std::vector & ChokePoints(const Area * pArea) const; // Returns the ChokePoints of this Area grouped by neighbouring Areas // Note: if there are no neighbouring Areas, than an empty set is returned. const std::map *> & ChokePointsByArea() const { return m_ChokePointsByArea; } // Returns the accessible neighbouring Areas. // The accessible neighbouring Areas are a subset of the neighbouring Areas (the neighbouring Areas can be iterated using ChokePointsByArea()). // Two neighbouring Areas are accessible from each over if at least one the ChokePoints they share is not Blocked (Cf. ChokePoint::Blocked). const std::vector&AccessibleNeighbours() const { return m_AccessibleNeighbours; } // Returns whether this Area is accessible from pArea, that is, if they share the same GroupId(). // Note: accessibility is always symmetrical. // Note: even if a and b are neighbouring Areas, // we can have: a->AccessibleFrom(b) // and not: contains(a->AccessibleNeighbours(), b) // See also GroupId() bool AccessibleFrom(const Area * pArea) const { return GroupId() == pArea->GroupId(); } // Returns the Minerals contained in this Area. // Note: only a call to Map::OnMineralDestroyed(BWAPI::Unit u) may change the result (by removing eventually one element). const std::vector & Minerals() const { return m_Minerals; } // Returns the Geysers contained in this Area. // Note: the result will remain unchanged. const std::vector & Geysers() const { return m_Geysers; } // Returns the Bases contained in this Area. // Note: the result will remain unchanged. const std::vector & Bases() const { return m_Bases; } Map * GetMap() const; Area & operator=(const Area &) = delete; //////////////////////////////////////////////////////////////////////////// // Details: The functions below are used by the BWEM's internals Area(detail::Graph * pGraph, id areaId, BWAPI::WalkPosition top, int miniTiles); Area(const Area & Other); void AddChokePoints(Area * pArea, std::vector * pChokePoints); void AddMineral(Mineral * pMineral); void AddGeyser(Geyser * pGeyser); void AddTileInformation(const BWAPI::TilePosition t, const Tile & tile); void OnMineralDestroyed(const Mineral * pMineral); void PostCollectInformation(); std::vector ComputeDistances(const ChokePoint * pStartCP, const std::vector & TargetCPs) const; void UpdateAccessibleNeighbours(); void SetGroupId(groupId gid) { bwem_assert(gid >= 1); m_groupId = gid; } void CreateBases(); std::vector & Bases() { return m_Bases; } private: const detail::Graph * GetGraph() const { return m_pGraph; } detail::Graph * GetGraph() { return m_pGraph; } int ComputeBaseLocationScore(BWAPI::TilePosition location) const; bool ValidateBaseLocation(BWAPI::TilePosition location, std::vector & BlockingMinerals) const; std::vector ComputeDistances(BWAPI::TilePosition start, const std::vector & Targets) const; detail::Graph * const m_pGraph; id m_id; groupId m_groupId = 0; BWAPI::WalkPosition m_top; BWAPI::TilePosition m_topLeft = {std::numeric_limits::max(), std::numeric_limits::max()}; BWAPI::TilePosition m_bottomRight = {std::numeric_limits::min(), std::numeric_limits::min()}; altitude_t m_maxAltitude; int m_miniTiles; int m_tiles = 0; int m_buildableTiles = 0; int m_highGroundTiles = 0; int m_veryHighGroundTiles = 0; std::map *> m_ChokePointsByArea; std::vector m_AccessibleNeighbours; std::vector m_ChokePoints; std::vector m_Minerals; std::vector m_Geysers; std::vector m_Bases; }; } // namespace BWEM #endif