home | features | getting started | FAQ | Stone | Iron | Control the Iron! | download | help | about

Getting started



How to install the library

The library should be structured as follows: First note: the BWEM library includes the EasyBMP library (BSD-revised), whose source files are all contained in the EasyBMP_1.06 folder. If you don't use the BWEM::utils::printMap() utility though, you don't need this third party library either and you can freely remove the whole folder. In this case, just make sure you also remove src/mapPrinter.h and src/mapPrinter.cpp plus any reference to these files. Before you do that though, note this simple and flexible utility may prove to be very useful while debugging for example. Alternatively, you can just set BWEM_USE_MAP_PRINTER to 0 in src/defs.s: this will disable the compilation of the related files.
Note that the EasyBMP library includes some Windows headers, so if you are on Linux, you have to set BWEM_USE_MAP_PRINTER to 0.

Second note: if you are in Linux, you also have to set BWEM_USE_WINUTILS to 0 in src/defs.s. This will disable the compilation of the optional utils provided in winutils.h.

The BWEM library consists in C++ source files only. You could create a library project to get a library file (.lib or .dll) from them. In the following though, only the direct approach will be discussed, i.e. adding these files into your C++ project.

First, you should have a starting or an existing project that makes use of the BWAPI library. In the following, I will assume you are using the ExampleAIModule that comes with the BWAPI release. Also, make sure to use the latest version (at least 4.1.2).

Copy the BWEM folder into your project (wherever appropriate). For example, in ExampleAIModule\Source.
Now you have to add the files into your C++ project, just as you would for any other C++ source file.
If you are using Visual Studio, this can be achieved using the solution explorer.
Right-click on your project, then add a new filter "BWEM".
Right-click on that filter, then add an existing item : actually you will browse and select all the files in ExampleAIModule\Source\BWEM\src.
Right-click on the filter once again, then browse and add the files EasyBMP.h and EasyBMP.cpp located in ExampleAIModule\Source\BWEM\src\EasyBMP_1.06.
That's all!


How to use the library

Again, I will assume you are working on the ExampleAIModule. To use the library, we will only modify ExampleAIModule.cpp.

First, modify the first lines so that it shows as:

#include "ExampleAIModule.h"
#include "BWEM/src/bwem.h"      // update the path if necessary
#include <iostream>

using namespace BWAPI;
using namespace Filter;
//using namespace BWEM;
//using namespace BWEM::BWAPI_ext;
//using namespace BWEM::utils;

namespace { auto & theMap = BWEM::Map::Instance(); }
The class BWEM::Map is the entry point for almost every thing in BWEM.
The unique instance can be accessed using BWEM::Map::Instance(). For convenience, we define an alias for it : theMap, local to this file. We could as well use a reference or a pointer member of the class ExampleAIModule but, because the instance of Map is a global variable, this matters little.

You may want to uncomment some or all of the 3 using directives. The namespace BWEM introduces very few names so bringing them all is probably not a big deal.
The two other namespaces are not direcly related to BWEM functionnality, but you might still want to use some of their stuff.
BWEM::BWAPI_ext contains several helper functions, built on top of the BWAPI library, that prove to be useful while implementing the BWEM library.
BWEM::utils also contains helper functions, but they are more general and do not depend on the BWAPI library.

Before we can use theMap, we need to initialize it. The right place to do this is in ExampleAIModule::onStart(). But first, let's inclose the whole code inside a standard and basic: try-catch handler:

void ExampleAIModule::onStart()
{
  try
  {
    // Hello World!

    // ...
  }
  catch (const std::exception & e)
  {
    Broodwar << "EXCEPTION: " << e.what() << std::endl;
  }
}
This will catch any standard exception, as well as any exception from BWEM. We will do that in the other methods too.

Now, we add the initialization code:

    // ...
      
    else // if this is not a replay
    {
      // Retrieve you and your enemy's races. enemy() will just return the first enemy.
      // If you wish to deal with multiple enemies then you must use enemies().
      if ( Broodwar->enemy() ) // First make sure there is an enemy
        Broodwar << "The matchup is " << Broodwar->self()->getRace() << " vs " << Broodwar->enemy()->getRace() << std::endl;
      
      Broodwar << "Map initialization..." << std::endl;

      theMap.Initialize();
      theMap.EnableAutomaticPathAnalysis();
      bool startingLocationsOK = theMap.FindBasesForStartingLocations();
      assert(startingLocationsOK);

      BWEM::utils::MapPrinter::Initialize(&theMap);
      BWEM::utils::printMap(theMap);      // will print the map into the file <StarCraftFolder>bwapi-data/map.bmp
      BWEM::utils::pathExample(theMap);   // add to the printed map a path between two starting locations
       
      Broodwar << "gg" << std::endl;
    }
  }
  catch (const std::exception & e)
We have correctly initialized BWEM, and we have started using it (see the code in printMap and pathExample, which are good examples).
But to get the best out of it we need to inform it of two events, so we add the following:
void ExampleAIModule::onUnitDestroy(BWAPI::Unit unit)
{
  try
  {
    if      (unit->getType().isMineralField())    theMap.OnMineralDestroyed(unit);
    else if (unit->getType().isSpecialBuilding()) theMap.OnStaticBuildingDestroyed(unit);
  }
  catch (const std::exception & e)
  {
    Broodwar << "EXCEPTION: " << e.what() << std::endl;
  }
}
As an example, let's use BWEM::utils::drawMap, which provides similar functionality to BWEM::utils::printMap.
Instead of printing the map into a file, it draws it directly on the game screen, using BWAPI primitives.
Don't forget to look at the code of drawMap. To use it, we just insert the following in ExampleAIModule::onFrame():
void ExampleAIModule::onFrame()
{
  // Called once every game frame
  try
  {
    BWEM::utils::gridMapExample(theMap);
    BWEM::utils::drawMap(theMap);

    // Display the game frame rate as text in the upper left area of the screen
    Broodwar->drawTextScreen(200, 0,  "FPS: %d", Broodwar->getFPS() );
    Broodwar->drawTextScreen(200, 20, "Average FPS: %f", Broodwar->getAverageFPS() );

    // ...
  }
  catch (const std::exception & e)
  {
    Broodwar << "EXCEPTION: " << e.what() << std::endl;
  }
}
(We also called BWEM::utils::gridMapExample, which demonstrates the use of the new class utils::GridMap.)
Finally, the class BWEM::utils::MapDrawer comes in handy for controling the information displayed on the screen. To see that, let's modify ExampleAIModule::onSendText:
void ExampleAIModule::onSendText(std::string text)
{
  BWEM::utils::MapDrawer::ProcessCommand(text);

  // Send the text to the game if it is not being processed.
  Broodwar->sendText("%s", text.c_str());

  // Make sure to use %s and pass the text as a parameter,
  // otherwise you may run into problems when you use the %(percent) character!
}
Run your bot. You should now be able select which information you want to show.
Press <enter>, then type: minerals
Do it again.
In MapDrawer::ProcessCommand you will find all the available items you can control.

home | features | getting started | FAQ | Stone | Iron | Control the Iron! | download | help | about