#include "ExampleAIModule.h"

using namespace BWAPI;

struct vect2d {
  int x;
  int y;
};

struct twopointlink {
  vect2d point1;
  vect2d point2;
};


bool analyzed,bnarrow,bfluidfilldone,bhighreslinksfound,bjustfinished,bletsgoagain,bgotitagain,bchecked;
bool analysis_just_finished;
BWTA::Region* home;
BWTA::Region* enemy_base;
int	mapwidth,mapheight;
int checked[1024][1024],nonwalk2[1024][1024];
bool nodebool[1024][1024],fluidedgechecked[1050000];

vect2d fluidzonepoints[1050000],fluidzoneedge[1050000];

int fluidzoneedgeindexes[1050000],fluidzoneindexes[1050000],zonelinkindexindex[1050000],zonelinkindex[1050000],fluidzoneareas[1050000];
vect2d links[30000000],linksinner[30000000],lastpoint,lastdir,firstdir,firstpoint,currdir,innerdir;

int nnumb,zonen,lastn,lastn2,zliid,firstlink,zliiid,currlink,lastarea,lastedge,lastx,scanx,scany,npointcheck,lasty,zoneid,longestcheckedbegin,longestcheckedend,currcheckedbegin,currcheckedend;
bool walk[1024][1024];
bool build[256][256],banalizis_finished,blinkunification_finished,bfirstpointselected;


void ExampleAIModule::onStart()
{
  int c1,c2;
	mapwidth=Broodwar->mapWidth();
	mapheight=Broodwar->mapHeight();
  nnumb=-1;
  lastn=-1;
  zliid=0;
  zliiid=0;
  currlink=0;
  scanx=0;
  lastpoint.x=9000;
  lastpoint.y=9000;
  scany=0;
  npointcheck=0;
  lastarea=0;
	lastx=0;
	lasty=0;
  Broodwar->sendText("Hello world!");
  Broodwar->printf("The map is %s, a %d player map",Broodwar->mapName().c_str(),Broodwar->getStartLocations().size());
  // Enable some cheat flags
  Broodwar->enableFlag(Flag::UserInput);
  // Uncomment to enable complete map information
  //Broodwar->enableFlag(Flag::CompleteMapInformation);

  //read map information into BWTA so terrain analysis can be done in another thread
  BWTA::readMap();
  for (c1=0;c1<mapwidth;c1++) {
	  for (c2=0;c2<mapheight;c2++) {
		build[c1][c2]=Broodwar->isBuildable(c1,c2,false);
	  }
  }
  
 
  
  mapwidth*=4;
  mapheight*=4;

  for (c1=0;c1<mapwidth;c1++) {
	  for (c2=0;c2<mapheight;c2++) {
		walk[c1][c2]=Broodwar->isWalkable(c1,c2);
	  }
  }
  

  analyzed=false;
  analysis_just_finished=false;

  show_bullets=false;
  show_visibility_data=false;

  if (Broodwar->isReplay())
  {
    Broodwar->printf("The following players are in this replay:");
    for(std::set<Player*>::iterator p=Broodwar->getPlayers().begin();p!=Broodwar->getPlayers().end();p++)
    {
      if (!(*p)->getUnits().empty() && !(*p)->isNeutral())
      {
        //Broodwar->printf("%s, playing as a %s",(*p)->getName().c_str(),(*p)->getRace().getName().c_str());
      }
    }
  }
  else
  {
    //Broodwar->printf("The match up is %s v %s",
    //  Broodwar->self()->getRace().getName().c_str(),
     // Broodwar->enemy()->getRace().getName().c_str());

    //send each worker to the mineral field that is closest to it
    for(std::set<Unit*>::const_iterator i=Broodwar->self()->getUnits().begin();i!=Broodwar->self()->getUnits().end();i++)
    {
      if ((*i)->getType().isWorker())
      {
        Unit* closestMineral=NULL;
        for(std::set<Unit*>::iterator m=Broodwar->getMinerals().begin();m!=Broodwar->getMinerals().end();m++)
        {
          if (closestMineral==NULL || (*i)->getDistance(*m)<(*i)->getDistance(closestMineral))
            closestMineral=*m;
        }
        if (closestMineral!=NULL)
          (*i)->rightClick(closestMineral);
      }
      else if ((*i)->getType().isResourceDepot())
      {
        //if this is a center, tell it to build the appropiate type of worker
        if ((*i)->getType().getRace()!=Races::Zerg)
        {
          (*i)->train(Broodwar->self()->getRace().getWorker());
        }
        else //if we are Zerg, we need to select a larva and morph it into a drone
        {
          std::set<Unit*> myLarva=(*i)->getLarva();
          if (myLarva.size()>0)
          {
            Unit* larva=*myLarva.begin();
            larva->morph(UnitTypes::Zerg_Drone);
          }
        }
      }
    }
  }
}

void ExampleAIModule::onEnd(bool isWinner)
{
  if (isWinner)
  {
    //log win to file
  }
}

void ExampleAIModule::onFrame()
{
  int nsteps,c1,c2,c3,nlinkfound,sumcoord;
  vect2d innercoords[4],prevdir,rootnodes[2],currdir,innerside,tempcoord[4],tempcoord2[4];
	bool currenttilewalkable,edgefound,linkfound,blinkfound;
  if (show_visibility_data)
    drawVisibilityData();

  if (show_bullets)
    drawBullets();

  if (Broodwar->isReplay())
    return;
	
  drawStats();
	//do some operations from terrain analyzation
  if (!analyzed)
  {
		//fluidfill to find the edges
	  for (nsteps=0; scany<mapheight && nsteps < 10000; nsteps++) {

	    
	    
	    edgefound=false;
	    //do we have things to continue?
	    if (nnumb == lastn) {
	      lastx=scanx;
	      lasty=scany;
	      if (scanx==mapwidth-1) {
	        scanx=0;
	        scany++;
	      }
	      else {
	        scanx++;
	      }
	      lastarea=0;
	      bfirstpointselected=true;

	      
	      
	    }
	    else {
	    //yes, so lets continuew it
	      lastn++;
	      lastx=fluidzonepoints[lastn].x;
	      lasty=fluidzonepoints[lastn].y;
	      
	    }
	    
	    //if we hadn't then we check if scanned tile is walkable, and not checked [otherwise irrelevant..]
	    if (walk[lastx][lasty] && !checked[lastx][lasty]) {
	      
	      if (bfirstpointselected) {
	      
	        if (((!walk[lastx+1][lasty] || lastx==mapwidth-1) && (!walk[lastx-1][lasty] || lastx==0)) ||
	          ((!walk[lastx][lasty+1] || lasty==mapheight-1) && (!walk[lastx][lasty-1] || lasty==0))){
	          nonwalk2[lastx][lasty]=true;
	          bnarrow=true;
	          
	        }
	        else {
	        
	          bnarrow=false;
	        }
	        bfirstpointselected=false;
	       
	      }
	      
	        
	      
	      
	        if (lastn==nnumb) {
	          nnumb++;
	          lastn++;
	          fluidzonepoints[lastn].x=lastx;
	          fluidzonepoints[lastn].y=lasty;
	          lastarea++;
	        }
	        
	        
	        
	        
	        
	        
	        //check it
	        //right
	        if (walk[lastx+1][lasty] && lastx!=mapwidth-1) {
	         
	          //add to list
	          if (!checked[lastx+1][lasty]) {
	            if (bnarrow) {
	              if (((!walk[lastx+2][lasty] || lastx+1==mapwidth-1) && (!walk[lastx][lasty] || lastx+1==0)) ||
	              ((!walk[lastx+1][lasty+1] || lasty==mapheight-1) && (!walk[lastx+1][lasty-1] || lasty==0))){
	                if (!nodebool[lastx+1][lasty]) {
	                  nodebool[lastx+1][lasty]=true;
	                  nonwalk2[lastx+1][lasty]=true;
	                  nnumb++;
	                  lastarea++;
	                  fluidzonepoints[nnumb].x=lastx+1;
	                  fluidzonepoints[nnumb].y=lasty;
	                }
	              }
	              else {
	                edgefound=true;
	              }
	            }
	            else {
	              if (!(((!walk[lastx+2][lasty] || lastx+1==mapwidth-1) && (!walk[lastx][lasty] || lastx+1==0)) ||
	              ((!walk[lastx+1][lasty+1] || lasty==mapheight-1) && (!walk[lastx+1][lasty-1] || lasty==0)))){
	                if (!nodebool[lastx+1][lasty]) {
	                  nodebool[lastx+1][lasty]=true;
	                  
	                  nnumb++;
	                  lastarea++;
	                  fluidzonepoints[nnumb].x=lastx+1;
	                  fluidzonepoints[nnumb].y=lasty;
	                }
	              }
	              else {
	                edgefound=true;
	              }
	            }
	            
	          }
	          
	        }
	        else {
	          //edgefound.. ->
	          edgefound=true;
	        }
	        //left
	        if (walk[lastx-1][lasty] && lastx!=0) {
	          if (!checked[lastx-1][lasty]) {
	            if (bnarrow) {
	              if (((!walk[lastx][lasty] || lastx-1==mapwidth-1) && (!walk[lastx-2][lasty] || lastx-1==0)) ||
	              ((!walk[lastx-1][lasty+1] || lasty==mapheight-1) && (!walk[lastx-1][lasty-1] || lasty==0))){
	                if (!nodebool[lastx-1][lasty]) {
	                  nodebool[lastx-1][lasty]=true;
	                  nonwalk2[lastx-1][lasty]=true;
	                  nnumb++;
	                  lastarea++;
	                  fluidzonepoints[nnumb].x=lastx-1;
	                  fluidzonepoints[nnumb].y=lasty;
	                }
	              }
	              else {
	                edgefound=true;
	              }
	            }
	            else {
	              if (!(((!walk[lastx][lasty] || lastx-1==mapwidth-1) && (!walk[lastx-2][lasty] || lastx-1==0)) ||
	              ((!walk[lastx-1][lasty+1] || lasty==mapheight-1) && (!walk[lastx-1][lasty-1] || lasty==0)))){
	                if (!nodebool[lastx-1][lasty]) {
	                  nodebool[lastx-1][lasty]=true;
	                  nnumb++;
	                  lastarea++;
	                  fluidzonepoints[nnumb].x=lastx-1;
	                  fluidzonepoints[nnumb].y=lasty;
	                }
	              }
	              else {
	                edgefound=true;
	              }
	            }
	            
	          }
	        }
	        else {
	          edgefound=true;
	        }
	        //down
	        if (walk[lastx][lasty+1] && lasty!=mapheight-1) {
	          if (!checked[lastx][lasty+1]) {
	            if (bnarrow) {
	              if (((!walk[lastx+1][lasty+1] || lastx==mapwidth-1) && (!walk[lastx-1][lasty+1] || lastx==0)) ||
	              ((!walk[lastx][lasty+2] || lasty+1==mapheight-1) && (!walk[lastx][lasty] || lasty+1==0))){
	                if (!nodebool[lastx][lasty+1]) {
	                  nodebool[lastx][lasty+1]=true;
	                  nonwalk2[lastx][lasty+1]=true;
	                  nnumb++;
	                  lastarea++;
	                  fluidzonepoints[nnumb].x=lastx;
	                  fluidzonepoints[nnumb].y=lasty+1;
	                }
	              }
	              else {
	                edgefound=true;
	              }
	            }
	            else {
	              if (!(((!walk[lastx+1][lasty+1] || lastx==mapwidth-1) && (!walk[lastx-1][lasty+1] || lastx==0)) ||
	              ((!walk[lastx][lasty+2] || lasty+1==mapheight-1) && (!walk[lastx][lasty] || lasty+1==0)))){
	                if (!nodebool[lastx][lasty+1]) {
	                  nodebool[lastx][lasty+1]=true;
	                  nnumb++;
	                  lastarea++;
	                  fluidzonepoints[nnumb].x=lastx;
	                  fluidzonepoints[nnumb].y=lasty+1;
	                }
	              }
	              else {
	                edgefound=true;
	              }
	            }
	            
	          }
	        }
	        else {
	          edgefound=true;
	        }
	        //up
	        if (walk[lastx][lasty-1] && lasty!=0) {
	          if (!checked[lastx][lasty-1]) {
	            if (bnarrow) {
	              if (((!walk[lastx+1][lasty-1] || lastx==mapwidth-1) && (!walk[lastx-1][lasty-1] || lastx==0)) ||
	              ((!walk[lastx][lasty] || lasty-1==mapheight-1) && (!walk[lastx][lasty-2] || lasty-1==0))){
	                if (!nodebool[lastx][lasty-1]) {
	                  nodebool[lastx][lasty-1]=true;
	                  nonwalk2[lastx][lasty-1]=true;
	                  nnumb++;
	                  lastarea++;
	                  fluidzonepoints[nnumb].x=lastx;
	                  fluidzonepoints[nnumb].y=lasty-1;
	                }
	              }
	              else {
	                edgefound=true;
	              }
	            }
	            else {
	              if (!(((!walk[lastx+1][lasty-1] || lastx==mapwidth-1) && (!walk[lastx-1][lasty-1] || lastx==0)) ||
	              ((!walk[lastx][lasty] || lasty-1==mapheight-1) && (!walk[lastx][lasty-2] || lasty-1==0)))){
	                if (!nodebool[lastx][lasty-1]) {
	                  nodebool[lastx][lasty-1]=true;
	                  nnumb++;
	                  lastarea++;
	                  fluidzonepoints[nnumb].x=lastx;
	                  fluidzonepoints[nnumb].y=lasty-1;
	                }
	              }
	              else {
	                edgefound=true;
	              }
	            }
	            
	          }
	        }
	        else {
	          edgefound=true;
	        }
	      
	      
	      //addedge;
	      if (edgefound) {
	        fluidzoneedge[lastedge].x=lastx;
	        fluidzoneedge[lastedge].y=lasty;
	        
	        lastedge++;
	      }
	      //area done?
	      if (lastn==nnumb) {
	        fluidzoneareas[zonen]=lastarea;
	        lastarea=0;
	        zonen++;
	        fluidzoneedgeindexes[zonen]=lastedge;
	        fluidzoneindexes[zonen]=nnumb+1;
	      }
	    
	    }
	    checked[lastx][lasty]=true;
	  }
    if (scany>=mapheight && !bfluidfilldone) {
      bfluidfilldone=true;
      bjustfinished=true;
      
    }
    
    if (bjustfinished) {
      bjustfinished=false;
      for (c1=0;c1<1024;c1++) {
        for (c2=0;c2<1024;c2++) {
          nodebool[c1][c2]=false;
        }
      }
      lastn=0;
    }
    
    
    
    //draw stuff
    
    if (bfluidfilldone) {
      //Broodwar->printf("numberofzones: %d" , zonen);
      
      for (c1=0;c1<mapwidth;c1++) {
        for (c2=0;c2<mapheight;c2++) {
          if (walk[c1][c2]) {
            Broodwar->drawBox(CoordinateType::Map,c1*8,c2*8,c1*8+8,c2*8+8,Colors::Purple,false);
          }
          else {
            Broodwar->drawBox(CoordinateType::Map,c1*8,c2*8,c1*8+8,c2*8+8,Colors::Blue,false);
          }
        }
      }
      
      for (c1=0;c1<fluidzoneedgeindexes[zonen];c1++) {
        
          Broodwar->drawBox(CoordinateType::Map,fluidzoneedge[c1].x*8,fluidzoneedge[c1].y*8,fluidzoneedge[c1].x*8+8,fluidzoneedge[c1].y*8+8,Colors::Red,false);
       
      }
    }
    
    //FIND HIGHRES POLIGONS
    nsteps=0;
    while ( bfluidfilldone && !bhighreslinksfound && nsteps < 3000 && zliid<zonen) {
      //check edge points
      //Broodwar->printf("zliid, zonen %d %d" , zliid, zonen);
      while (nsteps < 3000 && npointcheck<fluidzoneedgeindexes[zliid+1]-fluidzoneedgeindexes[zliid] ) { //ONLYINCREMENT NPOINTCHECK, IF THE THING IS NOT ALREADY CHECKED
        //if we have no initial point, pick one
        nsteps++;
        if (lastpoint.x==9000) {
          //see if we are a narrow, or a normal zone
          c1=fluidzoneedgeindexes[zliid];
          lastpoint.x=fluidzoneedge[c1].x;
          lastpoint.y=fluidzoneedge[c1].y;
          if (nonwalk2[lastpoint.x][lastpoint.y]){
	          bnarrow=true;
	        }
	        else {
	        
	          bnarrow=false;
	        }

          //pick first nonchecked
          for (c1++;c1<fluidzoneedgeindexes[zliid+1]-1;c1++) {
            //if narrow zone, we might have a non ciruclar zone, so it will only stop, when all the number
            //of edges are checked, so only stop picking if we run out of points or find one of the end points if linear zone
            if (bnarrow) {
              sumcoord=0;
              lastx=fluidzoneedge[c1].x;
              lasty=fluidzoneedge[c1].y;
              
              if (!walk[lastx+1][lasty] || lastx==mapwidth-1) {
                sumcoord++;
              }
              if (!walk[lastx-1][lasty] || lastx==0) {
                sumcoord++;
              }
              if (!walk[lastx][lasty-1] || lasty==0) {
                sumcoord++;
              }
              if (!walk[lastx][lasty+1] || lasty==mapheight-1) {
                sumcoord++;
              }
              //if we have more then three points then one is an endpoint
              if (sumcoord>=3 && !nodebool[lastx][lasty]) {
                lastpoint=fluidzoneedge[c1];
                break;
              }
              else if (!nodebool[lastx][lasty]) {
                lastpoint=fluidzoneedge[c1];
              }
              
            }
            else {
              if (!nodebool[fluidzoneedge[c1].x][fluidzoneedge[c1].y]) {
                lastpoint.x=fluidzoneedge[c1].x;
                lastpoint.y=fluidzoneedge[c1].y;
                break;
              }
            }
          }

          
          if ((!walk[lastpoint.x+1][lastpoint.y] || lastpoint.x==mapwidth-1) && (walk[lastpoint.x-1][lastpoint.y] && lastpoint.x!=0)) {
            linksinner[currlink].x=lastpoint.x-1;
            linksinner[currlink].y=lastpoint.y;
          }
          else if ((!walk[lastpoint.x-1][lastpoint.y] || lastpoint.x==0) && (walk[lastpoint.x+1][lastpoint.y] && lastpoint.x!=mapwidth-1)) {
            linksinner[currlink].x=lastpoint.x+1;
            linksinner[currlink].y=lastpoint.y;
          }
          else if ((!walk[lastpoint.x][lastpoint.y-1] || lastpoint.y==0) && (walk[lastpoint.x][lastpoint.y+1] && lastpoint.y!=mapheight-1)) {
            linksinner[currlink].x=lastpoint.x;
            linksinner[currlink].y=lastpoint.y+1;
          }
          else if ((!walk[lastpoint.x][lastpoint.y+1] || lastpoint.y==mapheight-1) && (walk[lastpoint.x][lastpoint.y-1] && lastpoint.y!=0)) {
            linksinner[currlink].x=lastpoint.x;
            linksinner[currlink].y=lastpoint.y-1;
          }
          firstpoint.x=lastpoint.x;
          firstpoint.y=lastpoint.y;
          firstlink=currlink;
          zonelinkindexindex[zliiid]=firstlink;
          lastdir.x=0;
          lastdir.y=0;
          zliiid++;
          
          
          
          links[currlink].x=lastpoint.x;
          links[currlink].y=lastpoint.y;
          
          
          currlink++;
          npointcheck++;
          
          nodebool[lastpoint.x][lastpoint.y]=true;
          
          //pick a nearby point for link: THEY ARE GOING TO PICK THE ONE CLOSEST BENDING TOWARDS INNER POINT
          
          //right
          
          
        }
        //start comparing stuff to inital/last point
        
        while (nsteps <3000 && npointcheck<fluidzoneedgeindexes[zliid+1]-fluidzoneedgeindexes[zliid]){
          blinkfound=false;
          //pick a suitable point for next link
          
          
          nsteps++;
          sumcoord=0;
          
          //FIXMEEEE : we need an array, it will hold candidates for adding as links, then if we have more then 1 candidate, we will check those
          //which are part of the zone and the closest will remain.
          
          if (bnarrow) {
          
          //left
          if (walk[lastpoint.x-1][lastpoint.y] && lastpoint.x!=0 && !nodebool[lastpoint.x-1][lastpoint.y]){

            nodebool[lastpoint.x-1][lastpoint.y]=true;
            blinkfound=true;
            currdir.x=-1;
            currdir.y=0;
            //which side was inner?
            
          }
          //right
          else if (walk[lastpoint.x+1][lastpoint.y] && lastpoint.x!=mapwidth-1 && !nodebool[lastpoint.x+1][lastpoint.y] ){

            nodebool[lastpoint.x+1][lastpoint.y]=true;
            blinkfound=true;
            currdir.x=+1;
            currdir.y=0;
            
          }
          //down
          else if (walk[lastpoint.x][lastpoint.y+1] && lastpoint.y!=mapheight-1 && !nodebool[lastpoint.x][lastpoint.y+1] ){

            nodebool[lastpoint.x][lastpoint.y+1]=true;
            blinkfound=true;
            currdir.x=0;
            currdir.y=+1;
            
          }
          //up
          else if (walk[lastpoint.x][lastpoint.y-1] && lastpoint.y!=0 && !nodebool[lastpoint.x][lastpoint.y-1]){

            nodebool[lastpoint.x][lastpoint.y-1]=true;
            blinkfound=true;
            currdir.x=0;
            currdir.y=-1;
            
          }
          
          
          //upleft
          else if (walk[lastpoint.x-1][lastpoint.y-1] && lastpoint.x!=0 && lastpoint.y!=0 && !nodebool[lastpoint.x-1][lastpoint.y-1] ){

            nodebool[lastpoint.x-1][lastpoint.y-1]=true;
            blinkfound=true;
            currdir.x=-1;
            currdir.y=-1;
            
          }
          //upright
          else if (walk[lastpoint.x+1][lastpoint.y-1] && lastpoint.x!=mapwidth-1 && lastpoint.y!=0 && !nodebool[lastpoint.x+1][lastpoint.y-1]){

            nodebool[lastpoint.x+1][lastpoint.y-1]=true;
            blinkfound=true;
            currdir.x=1;
            currdir.y=-1;
            
          }
          //downright
          else if (walk[lastpoint.x+1][lastpoint.y+1] && lastpoint.x!=mapwidth-1 && lastpoint.y!=mapheight-1 && !nodebool[lastpoint.x+1][lastpoint.y+1] ){

            nodebool[lastpoint.x+1][lastpoint.y+1]=true;
            blinkfound=true;
            currdir.x=1;
            currdir.y=1;
            
          }
          //downleft
          else if (walk[lastpoint.x-1][lastpoint.y+1] && lastpoint.x!=0 && lastpoint.y!=mapheight-1 && !nodebool[lastpoint.x-1][lastpoint.y+1] ){

            nodebool[lastpoint.x-1][lastpoint.y+1]=true;
            blinkfound=true;
            currdir.x=-1;
            currdir.y=1;
           
            
          }
          
          
          
          }
          else {
          //left
          if (walk[lastpoint.x-1][lastpoint.y] && !nonwalk2[lastpoint.x-1][lastpoint.y] && lastdir.x!=1 && lastpoint.x!=0 && !nodebool[lastpoint.x-1][lastpoint.y] && (lastpoint.x-1!= firstpoint.x || lastpoint.y!=firstpoint.y) && 
            (((!walk[lastpoint.x-1][lastpoint.y-1]|| nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.y==0) && (lastdir.y != 0 || !walk[lastpoint.x+1][lastpoint.y-1] || nonwalk2[lastpoint.x+1][lastpoint.y-1] || lastpoint.y==0)) ||
             ((!walk[lastpoint.x-1][lastpoint.y+1] || nonwalk2[lastpoint.x-1][lastpoint.y+1] || lastpoint.y==mapheight-1) && (lastdir.y != 0 || !walk[lastpoint.x+1][lastpoint.y+1] || nonwalk2[lastpoint.x+1][lastpoint.y+1] || lastpoint.y==mapheight-1)) )){

            
            blinkfound=true;
            tempcoord[sumcoord].x=lastpoint.x-1;
            tempcoord[sumcoord].y=lastpoint.y;
            
            //which side was inner?
            if ((!walk[lastpoint.x-1][lastpoint.y-1] || nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.y==0)) {
              tempcoord2[sumcoord].x=lastpoint.x-1;
              tempcoord2[sumcoord].y=lastpoint.y+1;
            }
            
            else {
              tempcoord2[sumcoord].x=lastpoint.x-1;
              tempcoord2[sumcoord].y=lastpoint.y-1;
            }
            sumcoord++;
          }
          //right
          if (walk[lastpoint.x+1][lastpoint.y] && !nonwalk2[lastpoint.x+1][lastpoint.y] && lastdir.x!=-1 && lastpoint.x!=mapwidth-1 && !nodebool[lastpoint.x+1][lastpoint.y] && (lastpoint.x+1!= firstpoint.x || lastpoint.y!=firstpoint.y) && 
            (((lastdir.y!=0 || !walk[lastpoint.x-1][lastpoint.y-1]|| nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.y==0) && (!walk[lastpoint.x+1][lastpoint.y-1] || nonwalk2[lastpoint.x+1][lastpoint.y-1] || lastpoint.y==0)) ||
             ((lastdir.y!=0 || !walk[lastpoint.x-1][lastpoint.y+1] || nonwalk2[lastpoint.x-1][lastpoint.y+1] || lastpoint.y==mapheight-1) && (!walk[lastpoint.x+1][lastpoint.y+1] || nonwalk2[lastpoint.x+1][lastpoint.y+1] || lastpoint.y==mapheight-1))) ){

            
            blinkfound=true;
            tempcoord[sumcoord].x=lastpoint.x+1;
            tempcoord[sumcoord].y=lastpoint.y;
            //which side was inner?
            if (!walk[lastpoint.x+1][lastpoint.y-1] || nonwalk2[lastpoint.x+1][lastpoint.y-1] || lastpoint.y==0) {
              tempcoord2[sumcoord].x=lastpoint.x+1;
              tempcoord2[sumcoord].y=lastpoint.y+1;
            }
            else {
              tempcoord2[sumcoord].x=lastpoint.x+1;
              tempcoord2[sumcoord].y=lastpoint.y-1;
            }
            sumcoord++;
          }
          //down
          if (walk[lastpoint.x][lastpoint.y+1] && !nonwalk2[lastpoint.x][lastpoint.y+1] && lastdir.y !=-1 && lastpoint.y!=mapheight-1 && !nodebool[lastpoint.x][lastpoint.y+1] && (lastpoint.x!= firstpoint.x || lastpoint.y+1!=firstpoint.y) && 
            (((!walk[lastpoint.x-1][lastpoint.y+1] || nonwalk2[lastpoint.x-1][lastpoint.y+1] || lastpoint.x==0) && (lastdir.x!=0 || !walk[lastpoint.x-1][lastpoint.y-1] || nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.x==0)) ||
             ((!walk[lastpoint.x+1][lastpoint.y+1] || nonwalk2[lastpoint.x+1][lastpoint.y+1] || lastpoint.x==mapwidth-1) && (lastdir.x!= 0 || !walk[lastpoint.x+1][lastpoint.y-1] || nonwalk2[lastpoint.x+1][lastpoint.y-1] || lastpoint.x==mapwidth-1)) )){

            
            blinkfound=true;
            tempcoord[sumcoord].x=lastpoint.x;
            tempcoord[sumcoord].y=lastpoint.y+1;
            //which side was inner?
            if ((!walk[lastpoint.x-1][lastpoint.y+1] || nonwalk2[lastpoint.x-1][lastpoint.y+1] || lastpoint.x==0)) {
              tempcoord2[sumcoord].x=lastpoint.x+1;
              tempcoord2[sumcoord].y=lastpoint.y+1;
            }
            else {
              tempcoord2[sumcoord].x=lastpoint.x-1;
              tempcoord2[sumcoord].y=lastpoint.y+1;
            }
            sumcoord++;
          }
          //up
          if (walk[lastpoint.x][lastpoint.y-1] && !nonwalk2[lastpoint.x][lastpoint.y-1] && lastdir.y != 1 && lastpoint.y!=0 && !nodebool[lastpoint.x][lastpoint.y-1] && (lastpoint.x!= firstpoint.x || lastpoint.y-1!=firstpoint.y) && 
            (((lastdir.x!=0 || !walk[lastpoint.x-1][lastpoint.y+1] || nonwalk2[lastpoint.x-1][lastpoint.y+1] || lastpoint.x==0) && (!walk[lastpoint.x-1][lastpoint.y-1] || nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.x==0)) ||
             ((lastdir.x!=0 || !walk[lastpoint.x+1][lastpoint.y+1] || nonwalk2[lastpoint.x+1][lastpoint.y+1] || lastpoint.x==mapwidth-1) && (!walk[lastpoint.x+1][lastpoint.y-1] || nonwalk2[lastpoint.x+1][lastpoint.y-1] || lastpoint.x==mapwidth-1)) )){

            
            blinkfound=true;
            tempcoord[sumcoord].x=lastpoint.x;
            tempcoord[sumcoord].y=lastpoint.y-1;
            currdir.y=-1;
            //which side was inner?
            if ((!walk[lastpoint.x-1][lastpoint.y-1] || nonwalk2[lastpoint.x-1][lastpoint.y-1] || lastpoint.x==0)) {
              tempcoord2[sumcoord].x=lastpoint.x+1;
              tempcoord2[sumcoord].y=lastpoint.y-1;
            }
            else {
              tempcoord2[sumcoord].x=lastpoint.x-1;
              tempcoord2[sumcoord].y=lastpoint.y-1;
            }
            sumcoord++;
          }
          
          
          //upleft
          if (walk[lastpoint.x-1][lastpoint.y-1] && !nonwalk2[lastpoint.x-1][lastpoint.y-1] && ((lastdir.x!=1 && lastdir.y!=1) || (lastdir.x!=0 && lastdir.y!=0)) && lastpoint.x!=0 && lastpoint.y!=0 && !nodebool[lastpoint.x-1][lastpoint.y-1] && (lastpoint.x-1!= firstpoint.x || lastpoint.y-1!=firstpoint.y) && 
            ((!walk[lastpoint.x][lastpoint.y-1] || nonwalk2[lastpoint.x][lastpoint.y-1]) || (!walk[lastpoint.x-1][lastpoint.y] || nonwalk2[lastpoint.x-1][lastpoint.y])) ){
            
            
            blinkfound=true;
            tempcoord[sumcoord].x=lastpoint.x-1;
            tempcoord[sumcoord].y=lastpoint.y-1;
            //which side was inner?
            if ((!walk[lastpoint.x][lastpoint.y-1] || nonwalk2[lastpoint.x][lastpoint.y-1])) {
              tempcoord2[sumcoord].x=lastpoint.x-1;
              tempcoord2[sumcoord].y=lastpoint.y;
            }
            else {
              tempcoord2[sumcoord].x=lastpoint.x;
              tempcoord2[sumcoord].y=lastpoint.y-1;
            }
            sumcoord++;
          }
          //upright
          if (walk[lastpoint.x+1][lastpoint.y-1] && !nonwalk2[lastpoint.x+1][lastpoint.y-1] && ((lastdir.x!=-1 && lastdir.y!=1) || (lastdir.x!=0 && lastdir.y!=0)) && lastpoint.x!=mapwidth-1 && lastpoint.y!=0 && !nodebool[lastpoint.x+1][lastpoint.y-1] && (lastpoint.x+1!= firstpoint.x || lastpoint.y-1!=firstpoint.y) && 
            ((!walk[lastpoint.x][lastpoint.y-1] || nonwalk2[lastpoint.x][lastpoint.y-1]) || (!walk[lastpoint.x+1][lastpoint.y] || nonwalk2[lastpoint.x+1][lastpoint.y])) ){
            
            
            blinkfound=true;
            tempcoord[sumcoord].x=lastpoint.x+1;
            tempcoord[sumcoord].y=lastpoint.y-1;
            //which side was inner?
            if ((!walk[lastpoint.x][lastpoint.y-1] || nonwalk2[lastpoint.x][lastpoint.y-1])) {
              tempcoord2[sumcoord].x=lastpoint.x+1;
              tempcoord2[sumcoord].y=lastpoint.y;
            }
            else {
              tempcoord2[sumcoord].x=lastpoint.x;
              tempcoord2[sumcoord].y=lastpoint.y-1;
            }
            sumcoord++;
          }
          //downright
          if (walk[lastpoint.x+1][lastpoint.y+1] && !nonwalk2[lastpoint.x+1][lastpoint.y+1] && ((lastdir.x!=-1 && lastdir.y!=-1) || (lastdir.x!=0 && lastdir.y!=0)) && lastpoint.x!=mapwidth-1 && lastpoint.y!=mapheight-1 && !nodebool[lastpoint.x+1][lastpoint.y+1] && (lastpoint.x+1!= firstpoint.x || lastpoint.y+1!=firstpoint.y) && 
            ((!walk[lastpoint.x][lastpoint.y+1] || nonwalk2[lastpoint.x][lastpoint.y+1]) || (!walk[lastpoint.x+1][lastpoint.y] || nonwalk2[lastpoint.x+1][lastpoint.y])) ){
            
            
            blinkfound=true;
            tempcoord[sumcoord].x=lastpoint.x+1;
            tempcoord[sumcoord].y=lastpoint.y+1;
            //which side was inner?
            if ((!walk[lastpoint.x][lastpoint.y+1] || nonwalk2[lastpoint.x][lastpoint.y+1])) {
              tempcoord2[sumcoord].x=lastpoint.x+1;
              tempcoord2[sumcoord].y=lastpoint.y;
            }
            else {
              tempcoord2[sumcoord].x=lastpoint.x;
              tempcoord2[sumcoord].y=lastpoint.y+1;
            }
            sumcoord++;
          }
          //downleft
          if (walk[lastpoint.x-1][lastpoint.y+1] && !nonwalk2[lastpoint.x-1][lastpoint.y+1] && ((lastdir.x!=1 && lastdir.y!=-1) || (lastdir.x!=0 && lastdir.y!=0)) && lastpoint.x!=0 && lastpoint.y!=mapheight-1 && !nodebool[lastpoint.x-1][lastpoint.y+1] && (lastpoint.x-1!= firstpoint.x || lastpoint.y+1!=firstpoint.y) && 
            ((!walk[lastpoint.x][lastpoint.y+1] || nonwalk2[lastpoint.x][lastpoint.y+1]) || (!walk[lastpoint.x-1][lastpoint.y] || nonwalk2[lastpoint.x-1][lastpoint.y])) ){
            
            
            blinkfound=true;
            tempcoord[sumcoord].x=lastpoint.x-1;
            tempcoord[sumcoord].y=lastpoint.y+1;
            //which side was inner?
            if ((!walk[lastpoint.x][lastpoint.y+1] || nonwalk2[lastpoint.x][lastpoint.y+1])) {
              tempcoord2[sumcoord].x=lastpoint.x-1;
              tempcoord2[sumcoord].y=lastpoint.y;
            }
            else {
              tempcoord2[sumcoord].x=lastpoint.x;
              tempcoord2[sumcoord].y=lastpoint.y+1;
            }
            sumcoord++;
          }
          
          
          //IF THERE ARE MORE CANDIDATES FIND THE ONE WICH IS PRESENT IN THE LIST OF THE CURRENT ZONE EDGES.
          if (sumcoord==1) {
            nodebool[tempcoord[0].x][tempcoord[0].y]=true;
            currdir.x=tempcoord[0].x-lastpoint.x;
            currdir.y=tempcoord[0].y-lastpoint.y;
            linksinner[currlink].x=tempcoord2[0].x;
            linksinner[currlink].y=tempcoord2[0].y;
          }
          
          else if (sumcoord>1) {
            
            for (c1=0;c1<sumcoord;c1++) {
              blinkfound=false;
              for (c2=fluidzoneedgeindexes[zliid];c2<fluidzoneedgeindexes[zliid+1];c2++) {
                if (fluidzoneedge[c2].x==tempcoord[c1].x && fluidzoneedge[c2].y==tempcoord[c1].y) {
                  blinkfound=true;
                  
                }
           
              }
              if (!blinkfound) {
                tempcoord[c1].x=9000;
              }
            }
            blinkfound=false;
            
            currdir.x=0;
            currdir.y=0;
            lastn=0;
            for (c1=0;c1<sumcoord;c1++) {
              if (tempcoord[c1].x!=9000) {
                blinkfound=true;
                if (abs(tempcoord[c1].x-lastpoint.x+lastdir.x)+abs(tempcoord[c1].y-lastpoint.y+lastdir.y)>abs(currdir.x)+abs(currdir.y)) {
                  lastn=c1;
                  currdir.x=tempcoord[c1].x-lastpoint.x+lastdir.x;
                  currdir.y=tempcoord[c1].y-lastpoint.y+lastdir.y;
                }
                
              }
            }
            if (blinkfound) {
              nodebool[tempcoord[lastn].x][tempcoord[lastn].y]=true;
              currdir.x=tempcoord[lastn].x-lastpoint.x;
              currdir.y=tempcoord[lastn].y-lastpoint.y;
              linksinner[currlink].x=tempcoord2[lastn].x;
              linksinner[currlink].y=tempcoord2[lastn].y;
              
            }
          }
          
          
          
          }
          
          
          
          
          //FIXMEEEE end
          
          
          
          //add point.
          if (blinkfound) {
            lastpoint.x+=currdir.x;
            lastpoint.y+=currdir.y;
            if (currdir.x==lastdir.x && currdir.y==lastdir.y) {
              links[currlink-1].x=lastpoint.x;
              links[currlink-1].y=lastpoint.y;
            }
            else {
              links[currlink].x=lastpoint.x;
              links[currlink].y=lastpoint.y;
              linksinner[currlink].x=innerside.x;
              linksinner[currlink].y=innerside.y;
              lastdir.x=currdir.x;
              lastdir.y=currdir.y;
              currlink++;
            }
            npointcheck++;
            
          }
          else {
            lastpoint.x=9000;
            lastpoint.y=9000;
            //Broodwar->printf("nothing f9und " );
            
            break;
            
          }
          
          
          
        }
       
        //register where we were last time, will continue from there
        
        
        
      }
      
      /////////
      //all points of fluidzone checked, no more links to find?
      if (npointcheck>=fluidzoneedgeindexes[zliid+1]-fluidzoneedgeindexes[zliid]) {
        
        lastpoint.x=9000;
        lastpoint.y=9000;
        zliid++;
        npointcheck=0;
        zonelinkindex[zliid]=zliiid;
        bchecked=false;
        
      }
      
      
    }

    if (!bhighreslinksfound && bfluidfilldone && zliid>=zonen) {
      bjustfinished=true;
      bhighreslinksfound=true;
    }


    if (bhighreslinksfound) {
      for (c1=0;c1<zonen;c1++) {
        for (c2=zonelinkindex[c1];c2<zonelinkindex[c1+1];c2++) {
          for (c3=zonelinkindexindex[c2];c3<zonelinkindexindex[c2+1];c3++) {
            if (c3==zonelinkindexindex[c2+1]-1) {
              if (abs(links[zonelinkindexindex[c2]].x-links[c3].x) < 2 && abs(links[zonelinkindexindex[c2]].y-links[c3].y) < 2) {
                Broodwar->drawLineMap(links[zonelinkindexindex[c2]].x*8,links[zonelinkindexindex[c2]].y*8,links[c3].x*8,links[c3].y*8,Colors::Green);
              }
            }
            else {
              Broodwar->drawLineMap(links[c3+1].x*8,links[c3+1].y*8,links[c3].x*8,links[c3].y*8,Colors::Green);
            }
          }
        }
        
      }
    }

		//have we checked all tiles? IF YES, START TO REDUCE NODE TABLES but for now, just stop
		if (banalizis_finished) {
			analyzed=true;
		}


  }
  
	if (analyzed) {
    //draw edges and stuff
	}



}

void ExampleAIModule::onSendText(std::string text)
{
  if (text=="/show bullets")
  {
    show_bullets = !show_bullets;
  } else if (text=="/show players")
  {
    showPlayers();
  } else if (text=="/show forces")
  {
    showForces();
  } else if (text=="/show visibility")
  {
    show_visibility_data=!show_visibility_data;
  } else if (text=="/analyze")
  {
    if (analyzed == false)
    {
      Broodwar->printf("Analyzing map... this may take a minute");
      CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AnalyzeThread, NULL, 0, NULL);
    }
  } else
  {
    Broodwar->printf("You typed '%s'!",text.c_str());
    Broodwar->sendText("%s",text.c_str());
  }
}

void ExampleAIModule::onReceiveText(BWAPI::Player* player, std::string text)
{
  Broodwar->printf("%s said '%s'", player->getName().c_str(), text.c_str());
}

void ExampleAIModule::onPlayerLeft(BWAPI::Player* player)
{
  Broodwar->sendText("%s left the game.",player->getName().c_str());
}

void ExampleAIModule::onNukeDetect(BWAPI::Position target)
{
  if (target!=Positions::Unknown)
    Broodwar->printf("Nuclear Launch Detected at (%d,%d)",target.x(),target.y());
  else
    Broodwar->printf("Nuclear Launch Detected");
}

void ExampleAIModule::onUnitDiscover(BWAPI::Unit* unit)
{
 // if (!Broodwar->isReplay() && Broodwar->getFrameCount()>1)
    //Broodwar->sendText("A %s [%x] has been discovered at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
}

void ExampleAIModule::onUnitEvade(BWAPI::Unit* unit)
{
  //if (!Broodwar->isReplay() && Broodwar->getFrameCount()>1)
    //Broodwar->sendText("A %s [%x] was last accessible at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
}

void ExampleAIModule::onUnitShow(BWAPI::Unit* unit)
{
  //if (!Broodwar->isReplay() && Broodwar->getFrameCount()>1)
    //Broodwar->sendText("A %s [%x] has been spotted at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
}

void ExampleAIModule::onUnitHide(BWAPI::Unit* unit)
{
  //if (!Broodwar->isReplay() && Broodwar->getFrameCount()>1)
   // Broodwar->sendText("A %s [%x] was last seen at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
}

void ExampleAIModule::onUnitCreate(BWAPI::Unit* unit)
{
  if (Broodwar->getFrameCount()>1)
  {
  
  }
}

void ExampleAIModule::onUnitDestroy(BWAPI::Unit* unit)
{
  
}

void ExampleAIModule::onUnitMorph(BWAPI::Unit* unit)
{
  
}

void ExampleAIModule::onUnitRenegade(BWAPI::Unit* unit)
{
  //if (!Broodwar->isReplay())
    //Broodwar->sendText("A %s [%x] is now owned by %s",unit->getType().getName().c_str(),unit,unit->getPlayer()->getName().c_str());
}

void ExampleAIModule::onSaveGame(std::string gameName)
{
  Broodwar->printf("The game was saved to \"%s\".", gameName.c_str());
}

DWORD WINAPI AnalyzeThread()
{
  BWTA::analyze();

  //self start location only available if the map has base locations
  if (BWTA::getStartLocation(BWAPI::Broodwar->self())!=NULL)
  {
    home       = BWTA::getStartLocation(BWAPI::Broodwar->self())->getRegion();
  }
  //enemy start location only available if Complete Map Information is enabled.
  if (BWTA::getStartLocation(BWAPI::Broodwar->enemy())!=NULL)
  {
    enemy_base = BWTA::getStartLocation(BWAPI::Broodwar->enemy())->getRegion();
  }
  analyzed   = true;
  analysis_just_finished = true;
  return 0;
}

void ExampleAIModule::drawStats()
{
  std::set<Unit*> myUnits = Broodwar->self()->getUnits();
  Broodwar->drawTextScreen(5,0,"I have %d units:",myUnits.size());
  std::map<UnitType, int> unitTypeCounts;
  for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
  {
    if (unitTypeCounts.find((*i)->getType())==unitTypeCounts.end())
    {
      unitTypeCounts.insert(std::make_pair((*i)->getType(),0));
    }
    unitTypeCounts.find((*i)->getType())->second++;
  }
  int line=1;
  for(std::map<UnitType,int>::iterator i=unitTypeCounts.begin();i!=unitTypeCounts.end();i++)
  {
    Broodwar->drawTextScreen(5,16*line,"- %d %ss",(*i).second, (*i).first.getName().c_str());
    line++;
  }
}

void ExampleAIModule::drawBullets()
{
  std::set<Bullet*> bullets = Broodwar->getBullets();
  for(std::set<Bullet*>::iterator i=bullets.begin();i!=bullets.end();i++)
  {
    Position p=(*i)->getPosition();
    double velocityX = (*i)->getVelocityX();
    double velocityY = (*i)->getVelocityY();
    if ((*i)->getPlayer()==Broodwar->self())
    {
      Broodwar->drawLineMap(p.x(),p.y(),p.x()+(int)velocityX,p.y()+(int)velocityY,Colors::Green);
      Broodwar->drawTextMap(p.x(),p.y(),"\x07%s",(*i)->getType().getName().c_str());
    }
    else
    {
      Broodwar->drawLineMap(p.x(),p.y(),p.x()+(int)velocityX,p.y()+(int)velocityY,Colors::Red);
      Broodwar->drawTextMap(p.x(),p.y(),"\x06%s",(*i)->getType().getName().c_str());
    }
  }
}

void ExampleAIModule::drawVisibilityData()
{
  for(int x=0;x<Broodwar->mapWidth();x++)
  {
    for(int y=0;y<Broodwar->mapHeight();y++)
    {
      if (Broodwar->isExplored(x,y))
      {
        if (Broodwar->isVisible(x,y))
          Broodwar->drawDotMap(x*32+16,y*32+16,Colors::Green);
        else
          Broodwar->drawDotMap(x*32+16,y*32+16,Colors::Blue);
      }
      else
        Broodwar->drawDotMap(x*32+16,y*32+16,Colors::Red);
    }
  }
}

void ExampleAIModule::drawTerrainData()
{
  //we will iterate through all the base locations, and draw their outlines.
  for(std::set<BWTA::BaseLocation*>::const_iterator i=BWTA::getBaseLocations().begin();i!=BWTA::getBaseLocations().end();i++)
  {
    TilePosition p=(*i)->getTilePosition();
    Position c=(*i)->getPosition();

    //draw outline of center location
    Broodwar->drawBox(CoordinateType::Map,p.x()*32,p.y()*32,p.x()*32+4*32,p.y()*32+3*32,Colors::Blue,false);

    //draw a circle at each mineral patch
    for(std::set<BWAPI::Unit*>::const_iterator j=(*i)->getStaticMinerals().begin();j!=(*i)->getStaticMinerals().end();j++)
    {
      Position q=(*j)->getInitialPosition();
      Broodwar->drawCircle(CoordinateType::Map,q.x(),q.y(),30,Colors::Cyan,false);
    }

    //draw the outlines of vespene geysers
    for(std::set<BWAPI::Unit*>::const_iterator j=(*i)->getGeysers().begin();j!=(*i)->getGeysers().end();j++)
    {
      TilePosition q=(*j)->getInitialTilePosition();
      Broodwar->drawBox(CoordinateType::Map,q.x()*32,q.y()*32,q.x()*32+4*32,q.y()*32+2*32,Colors::Orange,false);
    }

    //if this is an island expansion, draw a yellow circle around the base location
    if ((*i)->isIsland())
      Broodwar->drawCircle(CoordinateType::Map,c.x(),c.y(),80,Colors::Yellow,false);
  }

  //we will iterate through all the regions and draw the polygon outline of it in green.
  for(std::set<BWTA::Region*>::const_iterator r=BWTA::getRegions().begin();r!=BWTA::getRegions().end();r++)
  {
    BWTA::Polygon p=(*r)->getPolygon();
    for(int j=0;j<(int)p.size();j++)
    {
      Position point1=p[j];
      Position point2=p[(j+1) % p.size()];
      Broodwar->drawLine(CoordinateType::Map,point1.x(),point1.y(),point2.x(),point2.y(),Colors::Green);
    }
  }

  //we will visualize the chokepoints with red lines
  for(std::set<BWTA::Region*>::const_iterator r=BWTA::getRegions().begin();r!=BWTA::getRegions().end();r++)
  {
    for(std::set<BWTA::Chokepoint*>::const_iterator c=(*r)->getChokepoints().begin();c!=(*r)->getChokepoints().end();c++)
    {
      Position point1=(*c)->getSides().first;
      Position point2=(*c)->getSides().second;
      Broodwar->drawLine(CoordinateType::Map,point1.x(),point1.y(),point2.x(),point2.y(),Colors::Red);
    }
  }
}

void ExampleAIModule::showPlayers()
{
  std::set<Player*> players=Broodwar->getPlayers();
  for(std::set<Player*>::iterator i=players.begin();i!=players.end();i++)
  {
    Broodwar->printf("Player [%d]: %s is in force: %s",(*i)->getID(),(*i)->getName().c_str(), (*i)->getForce()->getName().c_str());
  }
}

void ExampleAIModule::showForces()
{
  std::set<Force*> forces=Broodwar->getForces();
  for(std::set<Force*>::iterator i=forces.begin();i!=forces.end();i++)
  {
    std::set<Player*> players=(*i)->getPlayers();
    Broodwar->printf("Force %s has the following players:",(*i)->getName().c_str());
    for(std::set<Player*>::iterator j=players.begin();j!=players.end();j++)
    {
      Broodwar->printf("  - Player [%d]: %s",(*j)->getID(),(*j)->getName().c_str());
    }
  }
}
