/* Copyright (C) 2001-2004 Stephane Magnenat & Luc-Olivier de Charrière for any question or comment contact us at or This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Map.h" #include "Game.h" #include "Utilities.h" #include "GlobalContainer.h" #include "LogFileManager.h" #include "Unit.h" #include #include #include #if defined( LOG_GRADIENT_LINE_GRADIENT ) #include #endif // use deltaOne for first perpendicular direction static const int deltaOne[8][2]={ { 0, -1}, { 1, 0}, { 0, 1}, {-1, 0}, {-1, -1}, { 1, -1}, { 1, 1}, {-1, 1}}; // use tabClose for original circular direction static const int tabClose[8][2]={ {-1, -1}, { 0, -1}, { 1, -1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}}; // use tabMiniFar for all miniGrad far points static const int tabFar[16][2]={ {-2, -2}, {-1, -2}, { 0, -2}, { 1, -2}, { 2, -2}, { 2, -1}, { 2, 0}, { 2, 1}, { 2, 2}, { 1, 2}, { 0, 2}, {-1, 2}, {-2, 2}, {-2, 1}, {-2, 0}, {-2, -1}}; Map::Map() { game=NULL; arraysBuilt=false; mapDiscovered=NULL; fogOfWar=NULL; fogOfWarA=NULL; fogOfWarB=NULL; cases=NULL; for (int t=0; t<32; t++) for (int r=0; rlogFileManager->getFile("Map.log"); std::fill(incRessourceLog, incRessourceLog + 16, 0); areaNames.resize(9); } Map::~Map(void) { FILE *resLogFile = globalContainer->logFileManager->getFile("IncRessourceLog.log"); for (int i=0; i<=11; i++) fprintf(resLogFile, "incRessourceLog[%2d] =%8d\n", i, incRessourceLog[i]); fprintf(resLogFile, "\n"); fflush(resLogFile); clear(); } void Map::clear() { logAtClear(); if (arraysBuilt) { assert(mapDiscovered); delete[] mapDiscovered; mapDiscovered=NULL; fogOfWar=NULL; assert(fogOfWarA); delete[] fogOfWarA; fogOfWarA=NULL; assert(fogOfWarB); delete[] fogOfWarB; fogOfWarB=NULL; assert(cases); delete[] cases; cases=NULL; for (int t=0; t<32; t++) if (ressourcesGradient[t][0][0]) for (int r=0; r%5d]:%5d\n", vi * (size / 64), (vi + 1) * (size / 64) - 1, sum); } /*fprintf(logFile, "listCountSizeStats:\n"); for (size_t i = 0; i< size; i++) if (listCountSizeStats[i][i]) fprintf(logFile, "[%5d]:%5d\n", i, listCountSizeStats[i][i]);*/ } } #endif } void Map::setSize(int wDec, int hDec, TerrainType terrainType) { clear(); assert(wDec<16); assert(hDec<16); this->wDec=wDec; this->hDec=hDec; w=1<>4; hSector=h>>4; sizeSector=wSector*hSector; sectors=new Sector[sizeSector]; arraysBuilt=true; #ifdef check_disorderable_gradient_error_probability // stats to check the probability of an error: for (int i = 0; i < GT_SIZE; i++) { if (listCountSizeStats[i]) delete[] listCountSizeStats[i]; listCountSizeStats[i] = new int[size]; listCountSizeStatsOver[i] = 0; } #endif } void Map::setGame(Game *game) { assert(game); fprintf(logFile, "Map::setGame(%p)\n", game); this->game=game; assert(arraysBuilt); assert(sectors); for (int i=0; i=16); Sint32 versionMinor = header.getVersionMinor(); clear(); stream->readEnterSection("Map"); char signature[4]; stream->read(signature, 4, "signatureStart"); if (memcmp(signature, "MapB", 4)!=0) { fprintf(stderr, "Map:: Failed to find signature at the beginning of Map.\n"); return false; } // We load and compute size: wDec = stream->readSint32("wDec"); hDec = stream->readSint32("hDec"); w = 1<read(undermap, size, "undermap"); stream->readEnterSection("cases"); for (size_t i=0; ireadEnterSection(i); mapDiscovered[i] = stream->readUint32("mapDiscovered"); cases[i].terrain = stream->readUint16("terrain"); cases[i].building = stream->readUint16("building"); stream->read(&(cases[i].ressource), 4, "ressource"); cases[i].groundUnit = stream->readUint16("groundUnit"); cases[i].airUnit = stream->readUint16("airUnit"); cases[i].forbidden = stream->readUint32("forbidden"); cases[i].hiddenForbidden = stream->readUint32("hiddenForbidden"); cases[i].guardArea = stream->readUint32("guardArea"); cases[i].clearArea = stream->readUint32("clearArea"); cases[i].scriptAreas = stream->readUint16("scriptAreas"); cases[i].canRessourcesGrow = stream->readUint8("canRessourcesGrow"); stream->readLeaveSection(); } stream->readLeaveSection(); for(int n=0; n<9; ++n) { stream->readEnterSection(n); setAreaName(n, stream->readText("areaname")); stream->readLeaveSection(); } if (game) { /* Must set game field before following action as they may need it (in particular makeDiscoveredAreasExplored uses it). */ this->game=game; // This is a game, so we do compute gradients for (int t=0; treadSint32("wSector"); hSector = stream->readSint32("hSector"); sizeSector = wSector*hSector; assert(sectors == NULL); sectors = new Sector[sizeSector]; arraysBuilt = true; stream->readEnterSection("sectors"); for (int i=0; ireadEnterSection(i); if (!sectors[i].load(stream, this->game, versionMinor)) { stream->readLeaveSection(3); return false; } stream->readLeaveSection(); } stream->readLeaveSection(); stream->read(signature, 4, "signatureEnd"); stream->readLeaveSection(); if (memcmp(signature, "MapE", 4)!=0) { fprintf(stderr, "Map:: Failed to find signature at the end of Map.\n"); return false; } return true; } void Map::loadTransitional() { std::string fileName = glob2NameToFilename("maps", "output", ""); InputStream *stream = new BinaryInputStream(Toolkit::getFileManager()->openInputStreamBackend(fileName)); stream->read(undermap, size, "undermap"); for (size_t i=0; ireadUint16("terrain"); stream->read(&(cases[i].ressource), 4, "ressource"); cases[i].scriptAreas = stream->readUint16("scriptAreas"); cases[i].canRessourcesGrow = stream->readUint8("canRessourcesGrow"); } //Load area names for(int n=0; n<9; ++n) { stream->readEnterSection(n); setAreaName(n, stream->readText("areaname")); stream->readLeaveSection(); } delete stream; } void Map::save(GAGCore::OutputStream *stream) { stream->writeEnterSection("Map"); stream->write("MapB", 4, "signatureStart"); // We save size: stream->writeSint32(wDec, "wDec"); stream->writeSint32(hDec, "hDec"); // We write what's inside the map: stream->write(undermap, size, "undermap"); stream->writeEnterSection("cases"); for (size_t i=0; iwriteEnterSection(i); stream->writeUint32(mapDiscovered[i], "mapDiscovered"); stream->writeUint16(cases[i].terrain, "terrain"); stream->writeUint16(cases[i].building, "building"); stream->write(&(cases[i].ressource), 4, "ressource"); stream->writeUint16(cases[i].groundUnit, "groundUnit"); stream->writeUint16(cases[i].airUnit, "airUnit"); stream->writeUint32(cases[i].forbidden, "forbidden"); stream->writeUint32(cases[i].hiddenForbidden, "hiddenForbidden"); stream->writeUint32(cases[i].guardArea, "guardArea"); stream->writeUint32(cases[i].clearArea, "clearArea"); stream->writeUint16(cases[i].scriptAreas, "scriptAreas"); stream->writeUint8(cases[i].canRessourcesGrow, "canRessourcesGrow"); stream->writeLeaveSection(); } stream->writeLeaveSection(); //Save area names for(int n=0; n<9; ++n) { stream->writeEnterSection(n); stream->writeText(getAreaName(n), "areaname"); stream->writeLeaveSection(); } // We save sectors: stream->writeSint32(wSector, "wSector"); stream->writeSint32(hSector, "hSector"); stream->writeEnterSection("sectors"); for (int i=0; iwriteEnterSection(i); sectors[i].save(stream); stream->writeLeaveSection(); } stream->writeLeaveSection(); stream->write("MapE", 4, "signatureEnd"); stream->writeLeaveSection(); } void Map::addTeam(void) { int numberOfTeam=game->mapHeader.getNumberOfTeams(); int oldNumberOfTeam=numberOfTeam-1; assert(numberOfTeam>0); for (int t=0; tmapHeader.getNumberOfTeams(); // int oldNumberOfTeam=numberOfTeam+1; assert(numberOfTeam<32); // for (int t=0; tressourcesTypes.get(r.type)->expendable) { // we extand ressource: int dx, dy; Unit::dxdyfromDirection((syncRand()&7), &dx, &dy); int nx=x+dx; int ny=y+dy; if(canRessourcesGrow(nx, ny)) incRessource(nx, ny, r.type, r.variety); } } } } } } void Map::syncStep(Uint32 stepCounter) { growRessources(); for (int i=0; i> 1) & 31; if (team < game->mapHeader.getNumberOfTeams()) updateExploredArea(team); } // We only update one gradient per step: bool updated=false; while (!updated) { int numberOfTeam=game->mapHeader.getNumberOfTeams(); for (int t=0; tressourcesTypes.get(r.type); if (!fulltype->shrinkable) return; if (fulltype->eternal) { if (r.amount > 0) r.amount--; } else { if (!fulltype->granular || r.amount<=1) r.clear(); else r.amount--; } } void Map::decRessource(int x, int y, int ressourceType) { if (isRessourceTakeable(x, y, ressourceType)) decRessource(x, y); } bool Map::incRessource(int x, int y, int ressourceType, int variety) { Ressource &r = getCase(x, y).ressource; const RessourceType *fulltype; incRessourceLog[0]++; if (r.type == NO_RES_TYPE) { incRessourceLog[1]++; if (getBuilding(x, y) != NOGBID) return false; incRessourceLog[2]++; if (getGroundUnit(x, y) != NOGUID) return false; incRessourceLog[3]++; fulltype = globalContainer->ressourcesTypes.get(ressourceType); if (getTerrainType(x, y) == fulltype->terrain) { r.type = ressourceType; r.variety = variety; r.amount = 1; r.animation = 0; incRessourceLog[4]++; return true; } else { incRessourceLog[5]++; return false; } } else { fulltype = globalContainer->ressourcesTypes.get(r.type); incRessourceLog[6]++; } incRessourceLog[7]++; if (r.type != ressourceType) return false; incRessourceLog[8]++; if (!fulltype->shrinkable) return false; incRessourceLog[9]++; if (r.amount < fulltype->sizesCount) { incRessourceLog[10]++; r.amount++; return true; } else { incRessourceLog[11]++; r.amount--; } return false; } bool Map::isFreeForGroundUnit(int x, int y, bool canSwim, Uint32 teamMask) { if (isRessource(x, y)) return false; if (getBuilding(x, y)!=NOGBID) return false; if (getGroundUnit(x, y)!=NOGUID) return false; if (!canSwim && isWater(x, y)) return false; if (getForbidden(x, y)&teamMask) return false; return true; } bool Map::isFreeForGroundUnitNoForbidden(int x, int y, bool canSwim) { if (isRessource(x, y)) return false; if (getBuilding(x, y)!=NOGBID) return false; if (getGroundUnit(x, y)!=NOGUID) return false; if (!canSwim && isWater(x, y)) return false; return true; } bool Map::isFreeForBuilding(int x, int y) { if (isRessource(x, y)) return false; if (getBuilding(x, y)!=NOGBID) return false; if (getGroundUnit(x, y)!=NOGUID) return false; if (isGrass(x, y)) return true; else return false; } bool Map::isFreeForBuilding(int x, int y, int w, int h) { for (int yi=y; yiposX; int y=unit->posY; for (int tdx=-1; tdx<=1; tdx++) for (int tdy=-1; tdy<=1; tdy++) if (getBuilding(x+tdx, y+tdy)==gbid) { *dx=tdx; *dy=tdy; return true; } return false; } bool Map::doesPosTouchBuilding(int x, int y, Uint16 gbid) { for (int tdx=-1; tdx<=1; tdx++) for (int tdy=-1; tdy<=1; tdy++) if (getBuilding(x+tdx, y+tdy)==gbid) return true; return false; } bool Map::doesPosTouchBuilding(int x, int y, Uint16 gbid, int *dx, int *dy) { for (int tdx=-1; tdx<=1; tdx++) for (int tdy=-1; tdy<=1; tdy++) if (getBuilding(x+tdx, y+tdy)==gbid) { *dx=tdx; *dy=tdy; return true; } return false; } bool Map::doesUnitTouchRessource(Unit *unit, int *dx, int *dy) { int x=unit->posX; int y=unit->posY; Uint32 me=unit->owner->me; for (int tdx=-1; tdx<=1; tdx++) for (int tdy=-1; tdy<=1; tdy++) if (isRessource(x+tdx, y+tdy) && ((getForbidden(x+tdx, y+tdy)&me)==0)) { *dx=tdx; *dy=tdy; return true; } return false; } bool Map::doesUnitTouchRessource(Unit *unit, int ressourceType, int *dx, int *dy) { int x=unit->posX; int y=unit->posY; Uint32 me=unit->owner->me; for (int tdx=-1; tdx<=1; tdx++) for (int tdy=-1; tdy<=1; tdy++) if (isRessourceTakeable(x+tdx, y+tdy, ressourceType) && ((getForbidden(x+tdx, y+tdy)&me)==0)) { *dx=tdx; *dy=tdy; return true; } return false; } bool Map::doesPosTouchRessource(int x, int y, int ressourceType, int *dx, int *dy) { for (int tdx=-1; tdx<=1; tdx++) for (int tdy=-1; tdy<=1; tdy++) if (isRessourceTakeable(x+tdx, y+tdy,ressourceType)) { *dx=tdx; *dy=tdy; return true; } return false; } //! This method gives a good direction to hit for a warrior, and return false if nothing was found. //! Currently, it chooses to hit any turret if available, then units, then other buildings. bool Map::doesUnitTouchEnemy(Unit *unit, int *dx, int *dy) { int x=unit->posX; int y=unit->posY; int bestTime=256;//Shorter is better int bdx=0, bdy=0; Uint32 enemies=unit->owner->enemies; for (int tdx=-1; tdx<=1; tdx++) for (int tdy=-1; tdy<=1; tdy++) { Sint32 gbid=getBuilding(x+tdx, y+tdy); if (gbid!=NOGBID) { int otherTeam=Building::GIDtoTeam(gbid); Uint32 otherTeamMask=1<teams[otherTeam]); int otherID=Building::GIDtoID(gbid); Building *b=game->teams[otherTeam]->myBuildings[otherID]; if (!b->type->defaultUnitStayRange) { if (b->type->shootingRange) { bdx=tdx; bdy=tdy; bestTime=0; } else if (bestTime>255) { bdx=tdx; bdy=tdy; bestTime=255; } } } } Sint32 guid=getGroundUnit(x+tdx, y+tdy); if (guid!=NOGUID) { int otherTeam=Unit::GIDtoTeam(guid); Uint32 otherTeamMask=1<teams[otherTeam]); int otherID=Unit::GIDtoID(guid); Unit *otherUnit=game->teams[otherTeam]->myUnits[otherID]; if ((unit->owner->sharedVisionExchange & otherTeamMask)==0) { int time=(256-otherUnit->delta)/otherUnit->speed; if (time>1); dx>1)+1; dx++) for (int dy=y-(l>>1); dy>1)+1; dy++) { if (t==GRASS) { if (getUMTerrain(dx,dy-1)==WATER) { // setNoRessource(dx, dy-1, 1); setUMTerrain(dx,dy-1,SAND); } if (getUMTerrain(dx,dy+1)==WATER) { // setNoRessource(dx, dy+1, 1); setUMTerrain(dx,dy+1,SAND); } if (getUMTerrain(dx-1,dy)==WATER) { // setNoRessource(dx-1, dy, 1); setUMTerrain(dx-1,dy,SAND); } if (getUMTerrain(dx+1,dy)==WATER) { // setNoRessource(dx+1, dy, 1); setUMTerrain(dx+1,dy,SAND); } if (getUMTerrain(dx-1,dy-1)==WATER) { // setNoRessource(dx-1, dy-1, 1); setUMTerrain(dx-1,dy-1,SAND); } if (getUMTerrain(dx+1,dy-1)==WATER) { // setNoRessource(dx+1, dy-1, 1); setUMTerrain(dx+1,dy-1,SAND); } if (getUMTerrain(dx+1,dy+1)==WATER) { // setNoRessource(dx+1, dy+1, 1); setUMTerrain(dx+1,dy+1,SAND); } if (getUMTerrain(dx-1,dy+1)==WATER) { // setNoRessource(dx-1, dy+1, 1); setUMTerrain(dx-1,dy+1,SAND); } } else if (t==WATER) { if (getUMTerrain(dx,dy-1)==GRASS) { // setNoRessource(dx, dy-1, 1); setUMTerrain(dx,dy-1,SAND); } if (getUMTerrain(dx,dy+1)==GRASS) { // setNoRessource(dx, dy+1, 1); setUMTerrain(dx,dy+1,SAND); } if (getUMTerrain(dx-1,dy)==GRASS) { // setNoRessource(dx-1, dy, 1); setUMTerrain(dx-1,dy,SAND); } if (getUMTerrain(dx+1,dy)==GRASS) { // setNoRessource(dx+1, dy, 1); setUMTerrain(dx+1,dy,SAND); } if (getUMTerrain(dx-1,dy-1)==GRASS) { // setNoRessource(dx-1, dy-1, 1); setUMTerrain(dx-1,dy-1,SAND); } if (getUMTerrain(dx+1,dy-1)==GRASS) { // setNoRessource(dx+1, dy-1, 1); setUMTerrain(dx+1,dy-1,SAND); } if (getUMTerrain(dx+1,dy+1)==GRASS) { // setNoRessource(dx+1, dy+1, 1); setUMTerrain(dx+1,dy+1,SAND); } if (getUMTerrain(dx-1,dy+1)==GRASS) { // setNoRessource(dx-1, dy+1, 1); setUMTerrain(dx-1,dy+1,SAND); } } setUMTerrain(dx,dy,t); } if (t==SAND) regenerateMap(x-(l>>1)-1,y-(l>>1)-1,l+1,l+1); else regenerateMap(x-(l>>1)-2,y-(l>>1)-2,l+3,l+3); } void Map::setNoRessource(int x, int y, int l) { assert(l>=0); assert(l>1); dx>1)+1; dx++) for (int dy=y-(l>>1); dy>1)+1; dy++) (cases+w*(dy&hMask)+(dx&wMask))->ressource.clear(); } void Map::setRessource(int x, int y, int type, int l) { assert(l>=0); assert(l>1); dx>1)+1; dx++) for (int dy=y-(l>>1); dy>1)+1; dy++) if (isRessourceAllowed(dx, dy, type)) { Ressource *rp=&((cases+w*(dy&hMask)+(dx&wMask))->ressource); rp->type=type; RessourceType *rt=globalContainer->ressourcesTypes.get(type); rp->variety=syncRand()%rt->varietiesCount; assert(rt->sizesCount>1); rp->amount=1+syncRand()%(rt->sizesCount-1); rp->animation=0; } } bool Map::isRessourceAllowed(int x, int y, int type) { return (getTerrainType(x, y)==globalContainer->ressourcesTypes.get(type)->terrain); } bool Map::isPointSet(int n, int x, int y) { return getCase(x, y).scriptAreas & 1< (w - 16)) x-=w; if (y > (h - 16)) y-=h; *px=x<<5; *py=y<<5; } void Map::mapCaseToDisplayableVector(int mx, int my, int *px, int *py, int viewportX, int viewportY, int screenW, int screenH) { int x = (mx - viewportX) & wMask; int y = (my - viewportY) & hMask; if (x > (w/2 + screenW/2)) x-=w; if (y > (h/2 + screenH/2)) y-=h; *px=x<<5; *py=y<<5; } void Map::displayToMapCaseAligned(int mx, int my, int *px, int *py, int viewportX, int viewportY) { *px=((mx>>5)+viewportX)&getMaskW(); *py=((my>>5)+viewportY)&getMaskH(); } void Map::displayToMapCaseUnaligned(int mx, int my, int *px, int *py, int viewportX, int viewportY) { *px=(((mx+16)>>5)+viewportX)&getMaskW(); *py=(((my+16)>>5)+viewportY)&getMaskH(); } void Map::cursorToBuildingPos(int mx, int my, int buildingWidth, int buildingHeight, int *px, int *py, int viewportX, int viewportY) { int tempX, tempY; if (buildingWidth&0x1) tempX=((mx)>>5)+viewportX; else tempX=((mx+16)>>5)+viewportX; if (buildingHeight&0x1) tempY=((my)>>5)+viewportY; else tempY=((my+16)>>5)+viewportY; *px=tempX&getMaskW(); *py=tempY&getMaskH(); } void Map::buildingPosToCursor(int px, int py, int buildingWidth, int buildingHeight, int *mx, int *my, int viewportX, int viewportY) { mapCaseToDisplayable(px, py, mx, my, viewportX, viewportY); *mx+=buildingWidth*16; *my+=buildingHeight*16; } bool Map::ressourceAvailable(int teamNumber, int ressourceType, bool canSwim, int x, int y) { Uint8 g = getGradient(teamNumber, ressourceType, canSwim, x, y); return g>1; //Becasue 0==obstacle, 1==no obstacle, but you don't know if there is anything around. } bool Map::ressourceAvailable(int teamNumber, int ressourceType, bool canSwim, int x, int y, int *dist) { Uint8 g = getGradient(teamNumber, ressourceType, canSwim, x, y); if (g>1) { *dist = 255-g; return true; } else return false; } bool Map::ressourceAvailable(int teamNumber, int ressourceType, bool canSwim, int x, int y, Sint32 *targetX, Sint32 *targetY, int *dist) { // distance and availability bool result; if (dist) result = ressourceAvailable(teamNumber, ressourceType, canSwim, x, y, dist); else result = ressourceAvailable(teamNumber, ressourceType, canSwim, x, y); // target position Uint8 *gradient = ressourcesGradient[teamNumber][ressourceType][canSwim]; ressourceAvailableCount[teamNumber][ressourceType]++; if (getGlobalGradientDestination(gradient, x, y, targetX, targetY)) ressourceAvailableCountSuccess[teamNumber][ressourceType]++; else ressourceAvailableCountFailure[teamNumber][ressourceType]++; return result; } bool Map::getGlobalGradientDestination(Uint8 *gradient, int x, int y, Sint32 *targetX, Sint32 *targetY) { // we start from our current position int vx = x & wMask; int vy = y & hMask; // max is initiaslized to gradient value of current position Uint8 max = gradient[(vx&wMask)+((vy&hMask)<max) { max = g; vddx = ddx; vddy = ddy; found = true; } } // change position vx = (vx+vddx) & wMask; vy = (vy+vddy) & hMask; // if we have reached destionation break if (max == 255) { result = true; break; } // if we haven't found a suitable direction, we break, but we do not have exact destination else if (!found) break; } // return best destination and wether it is exact or not *targetX = vx; *targetY = vy; return result; } /* This was the old way. I was much more complex but reliable with partially broken gradients. Let's keep it for now in case of such type of gradient reappears bool Map::ressourceAvailable(int teamNumber, int ressourceType, bool canSwim, int x, int y, Sint32 *targetX, Sint32 *targetY, int *dist) { ressourceAvailableCount[teamNumber][ressourceType]++; Uint8 *gradient=ressourcesGradient[teamNumber][ressourceType][canSwim]; assert(gradient); x&=wMask; y&=hMask; Uint8 g=gradient[(y<=255) { ressourceAvailableCountFast[teamNumber][ressourceType]++; *targetX=x; *targetY=y; return true; } int vx=x&wMask; int vy=y&hMask; Uint8 max=gradient[(vx&wMask)+((vy&hMask)<max) { max=g; vddx=ddx; vddy=ddy; found=true; } } if (found) { vx=(vx+vddx)&wMask; vy=(vy+vddy)&hMask; } else { ressourceAvailableCountFar[teamNumber][ressourceType]++; Uint8 miniGrad[25]; for (int ry=0; ry<5; ry++) for (int rx=0; rx<5; rx++) { int xg=(vx+rx-2)&wMask; int yg=(vy+ry-2)&hMask; miniGrad[rx+ry*5]=gradient[xg+yg*w]; } if (directionFromMinigrad(miniGrad, &vddx, &vddy, false, false)) { vx=(vx+vddx)&wMask; vy=(vy+vddy)&hMask; Uint8 g=gradient[(vx&wMask)+((vy&hMask)<max) max=g; } } if (max==255 || (max>=255 && (getBuilding(vx, vy)==NOGBID))) { ressourceAvailableCountSuccess[teamNumber][ressourceType]++; *targetX=vx; *targetY=vy; return true; } if (!found) { { int vx=x&wMask; int vy=y&hMask; if (verbose) printf("init v=(%d, %d)\n", vx, vy); Uint8 max=gradient[(vx&wMask)+((vy&hMask)<max) { max=g; vddx=ddx; vddy=ddy; found=true; } } if (found) { vx=(vx+vddx)&wMask; vy=(vy+vddy)&hMask; if (verbose) printf("fast v=(%d, %d), max=%d\n", vx, vy, max); } else { Uint8 miniGrad[25]; for (int ry=0; ry<5; ry++) for (int rx=0; rx<5; rx++) { int xg=(vx+rx-2)&wMask; int yg=(vy+ry-2)&hMask; miniGrad[rx+ry*5]=gradient[xg+yg*w]; } if (directionFromMinigrad(miniGrad, &vddx, &vddy, false, false)) { vx=(vx+vddx)&wMask; vy=(vy+vddy)&hMask; Uint8 g=gradient[(vx&wMask)+((vy&hMask)<max) max=g; if (verbose) printf("mini v=(%d, %d), g=%d, max=%d\n", vx, vy, g, max); } } if (max==255 || (max>=255 && (getBuilding(vx, vy)==NOGBID))) { if (verbose) printf("return true v=(%d, %d), max=%d\n", vx, vy, max); break; } if (!found) { if (verbose) printf("return false\n"); break; } } } ressourceAvailableCountFailureBase[teamNumber][ressourceType]++; fprintf(logFile, "target *not* found! pos=(%d, %d), vpos=(%d, %d), max=%d, team=%d, res=%d, swim=%d\n", x, y, vx, vy, max, teamNumber, ressourceType, canSwim); if (verbose) printf("target *not* found! pos=(%d, %d), vpos=(%d, %d), max=%d, team=%d, res=%d, swim=%d\n", x, y, vx, vy, max, teamNumber, ressourceType, canSwim); *targetX=vx; *targetY=vy; return false; } } { int vx=x&wMask; int vy=y&hMask; if (verbose) printf("init v=(%d, %d)\n", vx, vy); Uint8 max=gradient[(vx&wMask)+((vy&hMask)<max) { max=g; vddx=ddx; vddy=ddy; found=true; } } if (found) { vx=(vx+vddx)&wMask; vy=(vy+vddy)&hMask; if (verbose) printf("fast v=(%d, %d), max=%d\n", vx, vy, max); } else { Uint8 miniGrad[25]; for (int ry=0; ry<5; ry++) for (int rx=0; rx<5; rx++) { int xg=(vx+rx-2)&wMask; int yg=(vy+ry-2)&hMask; miniGrad[rx+ry*5]=gradient[xg+yg*w]; } if (directionFromMinigrad(miniGrad, &vddx, &vddy, false, false)) { vx=(vx+vddx)&wMask; vy=(vy+vddy)&hMask; Uint8 g=gradient[(vx&wMask)+((vy&hMask)<max) max=g; if (verbose) printf("mini v=(%d, %d), g=%d, max=%d\n", vx, vy, g, max); } } if (max==255 || (max>=255 && (getBuilding(vx, vy)==NOGBID))) { if (verbose) printf("return true v=(%d, %d), max=%d\n", vx, vy, max); break; } if (!found) { if (verbose) printf("return false\n"); break; } } } ressourceAvailableCountFailureOvercount[teamNumber][ressourceType]++; fprintf(logFile, "target *not* found! (count>255) pos=(%d, %d), vpos=(%d, %d), team=%d, res=%d, swim=%d\n", x, y, vx, vy, teamNumber, ressourceType, canSwim); if (verbose) printf("target *not* found! (count>255) pos=(%d, %d), vpos=(%d, %d), team=%d, res=%d, swim=%d\n", x, y, vx, vy, teamNumber, ressourceType, canSwim); *targetX=vx; *targetY=vy; return false; } */ void Map::updateGlobalGradientSlow(Uint8 *gradient) { if (size <= 65536) updateGlobalGradientSlow(gradient); else updateGlobalGradientSlow(gradient); } template void Map::updateGlobalGradientSlow(Uint8 *gradient) { Tint *listedAddr = new Tint[size]; size_t listCountWrite = 0; // make the first list: for (size_t i = 0; i < size; i++) if (gradient[i] >= 3) listedAddr[listCountWrite++] = i; updateGlobalGradient(gradient, listedAddr, listCountWrite, GT_UNDEFINED, true); delete[] listedAddr; } /*! Note that you can't provide any listedAddr[], or the gradient may technically end up wrong. Given the results of the tests, this will never happen. The easiest way to provide a listedAddr[] which guarantee a correct result, is to put only references to gradient heights that are all the same. Currently this is the case of all gradient computation but the AI ones (GT_UNDEFINED). For further undestanding you have to dig into the code and try #define check_disorderable_gradient_error_probability */ template void Map::updateGlobalGradientVersionSimple( Uint8 *gradient, Tint *listedAddr, size_t listCountWrite, GradientType gradientType) { size_t listCountRead = 0; #ifdef check_disorderable_gradient_error_probability size_t listCountSizeMax = 0; #endif while (listCountRead < listCountWrite) { Tint deltaAddrG = listedAddr[(listCountRead++)&(size-1)]; size_t y = deltaAddrG >> wDec; // Calculate the coordinates of size_t x = deltaAddrG & wMask; // the current field and of the size_t yu = ((y - 1) & hMask); // fields next to it. size_t yd = ((y + 1) & hMask); // We live on a torus! If we are on size_t xl = ((x - 1) & wMask); // the "last line" of the map, the size_t xr = ((x + 1) & wMask); // next line is the line 0 again. Uint8 g = gradient[(y << wDec) | x] - 1; if (g <= 1) // All free non-source-fields start with gradient=1 continue; // There is no need to propagate gradient when g==1 size_t deltaAddrC[8]; Uint8 *addr; Uint8 side; deltaAddrC[0] = (yu << wDec) | xl; // Calculate the positions of the deltaAddrC[1] = (yu << wDec) | x ; // 8 fields next to us from their deltaAddrC[2] = (yu << wDec) | xr; // coordinates. deltaAddrC[3] = (y << wDec) | xr; deltaAddrC[4] = (yd << wDec) | xr; deltaAddrC[5] = (yd << wDec) | x ; deltaAddrC[6] = (yd << wDec) | xl; deltaAddrC[7] = (y << wDec) | xl; for (int ci=0; ci<8; ci++) // Check for each of this fields if we { // can improve its gradient value addr = &gradient[deltaAddrC[ci]]; side = *addr; if (side > 0 && side < g) // side==0 means: you cannot walk on { // this field. // If we can improve this field *addr = g; // we must add it as a new source #ifdef check_disorderable_gradient_error_probability size_t listCountSize = 1 + listCountWrite - listCountRead; if (listCountSizeMax < listCountSize) listCountSizeMax = listCountSize; #endif // Here we check if the queue is large enough to // contain this field as a new gradient source. if (listCountWrite + 1 + size!= listCountRead) listedAddr[(listCountWrite++)&(size-1)] = deltaAddrC[ci]; else fprintf(stderr, "Map::updateGlobalGradientVersionSimple(): listedAddr[] overflow error"); } } } #ifdef check_disorderable_gradient_error_probability if (listCountSizeMax < size) listCountSizeStats[gradientType][listCountSizeMax]++; else listCountSizeStatsOver[gradientType]++; #endif //assert(listCountWrite<=size); } template void Map::updateGlobalGradientVersionSimon(Uint8 *gradient, Tint *listedAddr, size_t listCountWrite) { /* This algorithm uses the fact that all fields which are adjacent to the field directly below the current one, are also adjacent to either the field to its left or right. Thus this field only needs to become a source if its left or right is not accessable. The same with the other 3 directions. | | | | ------+-------+------ |current| |field | ------+-------+------ L | below | R | | ------+-------+------ next |next to| next to L | both | to R */ #if defined(LOG_SIMON_GRADIENT) size_t spared=0; size_t listCountWriteStart=listCountWrite; #endif size_t listCountRead = 0; while (listCountRead < listCountWrite) { Tint deltaAddrG = listedAddr[(listCountRead++)&(size-1)]; size_t y = deltaAddrG >> wDec; size_t x = deltaAddrG & wMask; size_t yu = ((y - 1) & hMask); size_t yd = ((y + 1) & hMask); size_t xl = ((x - 1) & wMask); size_t xr = ((x + 1) & wMask); Uint8 g = gradient[(y << wDec) | x] - 1; if (g <= 1) continue; Uint32 flag = 0; Uint8 *addr; Uint8 side; { // In this scope we care only about the diagonal neighbours. /* We will use flags to mark if at least one of the 2 fields next to a adjacent nondiagonal field is not accessable. Binary representation: 9 = 1001 3 = 0011 6 = 0110 12 = 1100 1 is the upper right 1 is the lower right 1 is the lower left 1 is the upper left */ const Uint32 diagFlags[4] = {9, 3, 6, 12}; size_t deltaAddrC[4]; deltaAddrC[0] = (yu << wDec) | xl; // Calculate the position deltaAddrC[1] = (yu << wDec) | xr; // of the 4 diagonal fields deltaAddrC[2] = (yd << wDec) | xr; deltaAddrC[3] = (yd << wDec) | xl; // 0|_|1 // _|*|_ * represents the current field // 3| |2 for (size_t ci = 0; ci < 4; ci++) // Check them { addr = &gradient[deltaAddrC[ci]]; side = *addr; if (side > 0 && side < g) { *addr = g; listedAddr[(listCountWrite++)&(size-1)] = deltaAddrC[ci]; } else if (side == 0) // If field is inaccessable, flag |= diagFlags[ci]; // mark the corresponding bit } } { // Now we take a look at our nondiagonal neighbours size_t deltaAddrC[4]; deltaAddrC[0] = (yu << wDec) | x ; // _|0|_ deltaAddrC[1] = (y << wDec) | xr; // 3|*|1 deltaAddrC[2] = (yd << wDec) | x ; // |2| deltaAddrC[3] = (y << wDec) | xl; for (size_t ci = 0; ci < 4; ci++) { addr = &gradient[deltaAddrC[ci]]; side = *addr; if (side > 0 && side < g) { *addr = g; // Only mark this as a new source, // if its left or right was inaccessable. if (flag & 1) // Information is in the first bit listedAddr[(listCountWrite++)&(size-1)] = deltaAddrC[ci]; #if defined(LOG_SIMON_GRADIENT) else spared++; #endif } flag >>= 1; // Shift the next bit into position } } } #if defined(LOG_SIMON_GRADIENT) FILE *logSimon = globalContainer->logFileManager->getFile("Simon.log"); fprintf(logSimon,"listed: %4d inserted: %4d spared: %3d\n",listCountWrite, listCountWrite-listCountWriteStart,spared); #endif //assert(listCountWrite<=size); } template void Map::updateGlobalGradientVersionKai(Uint8 *gradient, Tint *listedAddr, size_t listCountWrite) { // This version tries to go through the memory in consecutive order // in the hope that the cache usage will be improved. // Instead of picking one individual field and test its neighbours, // we test if the field to its right is the next field we must process. // If it is, we test the field to right of this field and so on. // Otherwise we stop. We also stop if the gradient value of the field to // the right differs from that of the current field or if we have reached // the end of the line. (We don't have to, but we do.) // After that we have a horizontal line segment. // Now we check if we can improve the line segment above it, and below it. // And the fields on the left and right. size_t sizeMask = size-1; // Mask needed to use listedAddr as queue. size_t listCountRead = 0; // Index of first untreated field in listedAddr. #if defined(LOG_GRADIENT_LINE_GRADIENT) std::map dcount; #endif #if defined(LOG_SIMON_GRADIENT) size_t spared=0; size_t listCountWriteStart=listCountWrite; #endif while (listCountRead < listCountWrite) // While listedAddr not empty. { Tint deltaAddrG = listedAddr[listCountRead&sizeMask]; size_t y = deltaAddrG >> wDec; size_t x = deltaAddrG & wMask; size_t yu = ((y - 1) & hMask); size_t yd = ((y + 1) & hMask); Uint8 myg = gradient[deltaAddrG]; // Get the gradient of the current field Uint8 g = myg-1; // g will be the gradient of the children. if (g <= 1) // All free non-source-fields start with gradient=1 { listCountRead++; continue; // There is no need to propagate gradient when g==1 } Uint8 *addr; // Pointer to a field. Uint8 side; // Gradient value of a field. size_t pos; // pos stores the combined (x,y) coordinate. // Get the length of the segment. size_t d; // Length of the line segment. size_t ylineDec = y << wDec; // Line the field is in. // remember: && and || only compute second argument if they have to. for (d=1; (++listCountRead < listCountWrite); d++) // While not empty. { pos = listedAddr[listCountRead&sizeMask]; // Next untreated field. // We can tollerate gaps of length 1. // Break if this field has not the same g as I, or is not the one // to my right or the one behind this. if (gradient[pos] != myg) // Need same g for all fields in line. break; if (pos == (ylineDec | ( (d + x) & wMask ) ) ) continue; // If the next field is beside to the right. #define ALLOW_SMALL_GAPS #if defined( ALLOW_SMALL_GAPS ) if (pos == (ylineDec | ( (d + 1 + x) & wMask ) ) ) { // If it is behind it. We overleap one field. addr = &gradient[(ylineDec | ( (x+d++) & wMask ) )]; side = *addr; if ( side>0 && side0 && side0 && side0 && side0 && side0 && sidelogFileManager->getFile("Simon.log"); fprintf(logSimon,"listed: %4d inserted: %4d spared: %3d\n",listCountWrite, listCountWrite-listCountWriteStart,spared); #endif #if defined( LOG_GRADIENT_LINE_GRADIENT ) FILE *dlog = globalContainer->logFileManager->getFile("GradientLineLength.log"); for (std::map::iterator it=dcount.begin();it!=dcount.end();it++) fprintf(dlog,"line length: %3d count: %4d\n",it->first,it->second); #endif } template void Map::updateGlobalGradient( Uint8 *gradient, Tint *listedAddr, size_t listCountWrite, GradientType gradientType, bool canSwim) { #define USE_DYNAMICAL_GRADIENT_VERSION_SR #if defined(LOG_GRADIENT_LINE_GRADIENT) FILE *dlog = globalContainer->logFileManager->getFile("GradientLineLength.log"); fprintf(dlog, "gradientType: %d\n", gradientType); fprintf(dlog, "canSwim: %d\n", canSwim); #endif #if defined(LOG_SIMON_GRADIENT) FILE *logSimon = globalContainer->logFileManager->getFile("Simon.log"); fprintf(logSimon, "gradientType: %d\n", gradientType); fprintf(logSimon, "canSwim: %d\n", canSwim); #endif #if defined( USE_GRADIENT_VERSION_TEST_KAI) if (gradientType == GT_UNDEFINED) updateGlobalGradientVersionSimple(gradient, listedAddr, listCountWrite, gradientType); else { Tint *testListedAddr = new Tint[size]; Uint8 *testGradient = new Uint8[size]; memcpy (testListedAddr, listedAddr, size); memcpy (testGradient, gradient, size); updateGlobalGradientVersionKai(testGradient, testListedAddr, listCountWrite); updateGlobalGradientVersionSimple(gradient, listedAddr, listCountWrite, gradientType); assert (memcmp (testGradient, gradient, size) == 0); } #elif defined(USE_GRADIENT_VERSION_KAI) updateGlobalGradientVersionKai(gradient, listedAddr, listCountWrite); #elif defined(USE_GRADIENT_VERSION_SIMON) updateGlobalGradientVersionSimon(gradient, listedAddr, listCountWrite); #elif defined(USE_GRADIENT_VERSION_SIMPLE) updateGlobalGradientVersionSimple(gradient, listedAddr, listCountWrite, gradientType); #elif defined(USE_DYNAMICAL_GRADIENT_VERSION_SR) if (gradientType == GT_RESOURCE) updateGlobalGradientVersionSimon(gradient, listedAddr, listCountWrite); else updateGlobalGradientVersionSimple(gradient, listedAddr, listCountWrite, gradientType); #elif defined(USE_DYNAMICAL_GRADIENT_VERSION_KR) if (gradientType == GT_RESOURCE) updateGlobalGradientVersionKai(gradient, listedAddr, listCountWrite); else updateGlobalGradientVersionSimple(gradient, listedAddr, listCountWrite, gradientType); #elif defined(USE_DYNAMICAL_GRADIENT_VERSION) // use the fastest gradient computation for each GradientType: switch (gradientType) { case GT_UNDEFINED: updateGlobalGradientVersionSimon(gradient, listedAddr, listCountWrite); // speed 105.09% compare to simple on test break; case GT_RESOURCE: updateGlobalGradientVersionSimon(gradient, listedAddr, listCountWrite); //speed 104.76% compare to simple on test break; case GT_BUILDING: updateGlobalGradientVersionKai(gradient, listedAddr, listCountWrite); // speed 100.29% compare to simple on test break; case GT_FORBIDDEN: updateGlobalGradientVersionKai(gradient, listedAddr, listCountWrite); // speed 100.18% compare to simple on test break; case GT_GUARD_AREA: updateGlobalGradientVersionSimple(gradient, listedAddr, listCountWrite, gradientType); // fastest one here break; default: assert(false); abort(); break; } #else #error Please select a gradient version #endif } void Map::updateRessourcesGradient(int teamNumber, Uint8 ressourceType, bool canSwim) { if (size <= 65536) updateRessourcesGradient(teamNumber, ressourceType, canSwim); else updateRessourcesGradient(teamNumber, ressourceType, canSwim); } template void Map::updateRessourcesGradient(int teamNumber, Uint8 ressourceType, bool canSwim) { Uint8 *gradient=ressourcesGradient[teamNumber][ressourceType][canSwim]; assert(gradient); Tint *listedAddr = new Tint[size]; size_t listCountWrite = 0; Uint32 teamMask=Team::teamNumberToMask(teamNumber); assert(globalContainer); for (size_t i=0; i=256 && c.terrain<16+256)) //!canSwim && isWater gradient[i]=0; else gradient[i]=1; } else if (c.ressource.type==ressourceType) { if (globalContainer->ressourcesTypes.get(ressourceType)->visibleToBeCollected && !(fogOfWar[i]&teamMask)) gradient[i]=0; else { gradient[i]=255; listedAddr[listCountWrite++] = i; } } else gradient[i]=0; } updateGlobalGradient(gradient, (Tint *)listedAddr, listCountWrite, GT_RESOURCE, canSwim); delete[] listedAddr; } bool Map::directionFromMinigrad(Uint8 miniGrad[25], int *dx, int *dy, const bool strict, bool verbose) { Uint8 max; Uint8 mxd; // max in direction Uint32 maxs[8]; max=mxd=miniGrad[1+1*5]; if (max && max!=255) { max=1; Uint8 side[5]; side[0]=miniGrad[0+2*5]; side[1]=miniGrad[0+1*5]; side[2]=miniGrad[0+0*5]; side[3]=miniGrad[1+0*5]; side[4]=miniGrad[2+0*5]; for (int i=0; i<5; i++) if (side[i]>max) max=side[i]; } maxs[0]=(max<<8)|mxd; max=mxd=miniGrad[3+1*5]; if (max && max!=255) { max=1; Uint8 side[5]; side[0]=miniGrad[2+0*5]; side[1]=miniGrad[3+0*5]; side[2]=miniGrad[4+0*5]; side[3]=miniGrad[4+1*5]; side[4]=miniGrad[4+2*5]; for (int i=0; i<5; i++) if (side[i]>max) max=side[i]; } maxs[1]=(max<<8)|mxd; max=mxd=miniGrad[3+3*5]; if (max && max!=255) { max=1; Uint8 side[5]; side[0]=miniGrad[4+2*5]; side[1]=miniGrad[4+3*5]; side[2]=miniGrad[4+4*5]; side[3]=miniGrad[3+4*5]; side[4]=miniGrad[2+4*5]; for (int i=0; i<5; i++) if (side[i]>max) max=side[i]; } maxs[2]=(max<<8)|mxd; max=mxd=miniGrad[1+3*5]; if (max && max!=255) { max=1; Uint8 side[5]; side[0]=miniGrad[2+4*5]; side[1]=miniGrad[1+4*5]; side[2]=miniGrad[0+4*5]; side[3]=miniGrad[0+3*5]; side[4]=miniGrad[0+2*5]; for (int i=0; i<5; i++) if (side[i]>max) max=side[i]; } maxs[3]=(max<<8)|mxd; max=mxd=miniGrad[2+1*5]; if (max && max!=255) { max=1; Uint8 side[3]; side[0]=miniGrad[1+0*5]; side[1]=miniGrad[2+0*5]; side[2]=miniGrad[3+0*5]; for (int i=0; i<3; i++) if (side[i]>max) max=side[i]; } maxs[4]=(max<<8)|mxd; max=mxd=miniGrad[3+2*5]; if (max && max!=255) { max=1; Uint8 side[3]; side[0]=miniGrad[4+1*5]; side[1]=miniGrad[4+2*5]; side[2]=miniGrad[4+3*5]; for (int i=0; i<3; i++) if (side[i]>max) max=side[i]; } maxs[5]=(max<<8)|mxd; max=mxd=miniGrad[2+3*5]; if (max && max!=255) { max=1; Uint8 side[3]; side[0]=miniGrad[1+4*5]; side[1]=miniGrad[2+4*5]; side[2]=miniGrad[3+4*5]; for (int i=0; i<3; i++) if (side[i]>max) max=side[i]; } maxs[6]=(max<<8)|mxd; max=mxd=miniGrad[1+2*5]; if (max && max!=255) { max=1; Uint8 side[3]; side[0]=miniGrad[0+1*5]; side[1]=miniGrad[0+2*5]; side[2]=miniGrad[0+3*5]; for (int i=0; i<3; i++) if (side[i]>max) max=side[i]; } maxs[7]=(max<<8)|mxd; int centerg=miniGrad[2+2*5]; centerg=(centerg<<8)|centerg; int maxg=centerg; int maxd=8; bool good=false; if (strict) for (int d=0; d<8; d++) { int g=maxs[d]; if (g>centerg) good=true; if (maxg<=g) { maxg=g; maxd=d; } } else for (int d=0; d<8; d++) { int g=maxs[d]; if (g && g!=centerg) good=true; if (maxg<=g) { maxg=g; maxd=d; } } if (verbose) { if (verbose) printf("miniGrad (%d):\n", strict); for (int ry=0; ry<5; ry++) { for (int rx=0; rx<5; rx++) if (verbose) printf("%4d", miniGrad[rx+ry*5]); if (verbose) printf("\n"); } if (verbose) { printf("maxs:\n"); for (int d=0; d<8; d++) printf("%4d.%4d (%d)\n", maxs[d]>>8, maxs[d]&0xFF, maxs[d]); printf("max=%4d.%4d (%d), d=%d, good=%d\n", maxs[maxd]>>8, maxs[maxd]&0xFF, maxs[maxd], maxd, good); }; } if (!good) return false; int stdd; if (maxd<4) stdd=(maxd<<1); else if (maxd!=8) stdd=1+((maxd-4)<<1); else stdd=8; //printf("stdd=%4d\n", maxd); Unit::dxdyfromDirection(stdd, dx, dy); return true; } bool Map::directionByMinigrad(Uint32 teamMask, bool canSwim, int x, int y, int *dx, int *dy, Uint8 *gradient, bool strict, bool verbose) { Uint8 miniGrad[25]; miniGrad[2+2*5]=gradient[x+y*w]; for (int di=0; di<16; di++) { int rx=tabFar[di][0]; int ry=tabFar[di][1]; int xg=(x+rx)&wMask; int yg=(y+ry)&hMask; int g=gradient[xg+yg*w]; if (g==0 || g==255 || isFreeForGroundUnit(xg, yg, canSwim, teamMask)) miniGrad[rx+ry*5+12]=g; else miniGrad[rx+ry*5+12]=0; } for (int di=0; di<8; di++) { int rx=tabClose[di][0]; int ry=tabClose[di][1]; int xg=(x+rx)&wMask; int yg=(y+ry)&hMask; int g=gradient[xg+yg*w]; if (g==0 || isFreeForGroundUnit(xg, yg, canSwim, teamMask)) miniGrad[rx+ry*5+12]=g; else miniGrad[rx+ry*5+12]=0; } if (verbose) printf("directionByMinigrad global %d\n", canSwim); return directionFromMinigrad(miniGrad, dx, dy, strict, verbose); } bool Map::directionByMinigrad(Uint32 teamMask, bool canSwim, int x, int y, int bx, int by, int *dx, int *dy, Uint8 localGradient[1024], bool strict, bool verbose) { Uint8 miniGrad[25]; for (int ry=0; ry<5; ry++) for (int rx=0; rx<5; rx++) { int gx=(x+rx-2)&wMask; int gy=(y+ry-2)&hMask; int lx=(x-bx+15+rx-2)&wMask; int ly=(y-by+15+ry-2)&hMask; //printf("+r=(%d, %d), b=(%d, %d), g=(%d, %d), l=(%d, %d)\n", rx, ry, bx, by, gx, gy, lx, ly); if (lx==wMask) { gx=(gx+1)&wMask; lx=0; } else if (lx==32) { gx=(gx-1)&wMask; lx=31; } if (ly==hMask) { gy=(gy+1)&hMask; ly=0; } else if (ly==32) { gy=(gy-1)&hMask; ly=31; } assert(lx>=0); assert(ly>=0); assert(lx<32); assert(ly<32); int g=localGradient[lx+ly*32]; //printf("|r=(%d, %d), b=(%d, %d), g=(%d, %d), l=(%d, %d), g=%d\n", rx, ry, bx, by, gx, gy, lx, ly, g); if (g==0 || g==255 || (rx==2 && ry==2) || isFreeForGroundUnit(gx, gy, canSwim, teamMask)) miniGrad[rx+ry*5]=g; else miniGrad[rx+ry*5]=0; } for (int ry=1; ry<=3; ry++) for (int rx=1; rx<=3; rx++) if (miniGrad[rx+ry*5]==255) { int gx=(x+rx-2)&wMask; int gy=(y+ry-2)&hMask; if (!isFreeForGroundUnit(gx, gy, canSwim, teamMask)) miniGrad[rx+ry*5]=0; } if (verbose) printf("directionByMinigrad local %d\n", canSwim); return directionFromMinigrad(miniGrad, dx, dy, strict, verbose); } bool Map::pathfindRessource(int teamNumber, Uint8 ressourceType, bool canSwim, int x, int y, int *dx, int *dy, bool *stopWork, bool verbose) { pathToRessourceCountTot++; if (verbose) printf("pathfindingRessource...\n"); assert(ressourceTypeposX; int y=unit->posY; if ((cases[x+(y<owner->me) { if (verbose) printf(" forbidden\n"); if (pathfindForbidden(NULL, unit->owner->teamNumber, (unit->performance[SWIM]>0), x, y, &unit->dx, &unit->dy, verbose)) { if (verbose) printf(" success\n"); unit->directionFromDxDy(); } else { if (verbose) printf(" failed\n"); unit->dx=0; unit->dy=0; unit->direction=8; } } else { bool da[8]; int count=0; for (int di=0; di<8; di++) { int tx=(x+tabClose[di][0])&wMask; int ty=(y+tabClose[di][1])&hMask; if (isFreeForGroundUnit(tx, ty, (unit->performance[SWIM]>0), unit->owner->me)) { da[di]=true; count++; } else da[di]=false; } if (verbose) { printf("count=%d\n", count); for (int di=0; di<8; di++) printf("da[%d]=%d\n", di, da[di]); } if (count==0) { unit->dx=0; unit->dy=0; unit->direction=8; return; } int dir=syncRand()%count; if (verbose) printf(" dir=%d\n", dir); for (int di=0; di<8; di++) if (da[di] && dir--==0) { unit->dx=tabClose[di][0]; unit->dy=tabClose[di][1]; unit->direction=di; if (verbose) printf("d=(%d, %d), d=%d\n", unit->dx, unit->dy, unit->direction); return; } assert(false); } } void Map::updateLocalGradient(Building *building, bool canSwim) { localBuildingGradientUpdate++; //fprintf(logFile, "updatingLocalGradient (gbid=%d)...\n", building->gid); //printf("updatingLocalGradient (gbid=%d)...\n", building->gid); assert(building); assert(building->type); building->dirtyLocalGradient[canSwim]=false; int posX=building->posX; int posY=building->posY; int posW=building->type->width; int posH=building->type->height; Uint32 teamMask=building->owner->me; Uint16 bgid=building->gid; Uint8 *gradient=building->localGradient[canSwim]; memset(gradient, 1, 1024); if (building->type->isVirtual) { assert(!building->type->zonableForbidden); int r=building->unitStayRange; int r2=r*r; for (int yi=-r; yi<=r; yi++) { int yi2=yi*yi; for (int xi=-r; xi<=r; xi++) if (yi2+(xi*xi)31) xxi=31; if (yyi<0) yyi=0; else if (yyi>31) xxi=31; gradient[xxi+(yyi<<5)]=255; } } } else for (int dy=0; dy31) xxi=31; if (yyi<0) yyi=0; else if (yyi>31) xxi=31; gradient[xxi+(yyi<<5)]=255; } // Here g=Global(map axis), l=Local(map axis) for (int yl=0; yl<32; yl++) { int wyl=(yl<<5); int yg=(yl+posY-15)&hMask; int wyg=w*yg; for (int xl=0; xl<32; xl++) { int xg=(xl+posX-15)&wMask; Case c=cases[wyg+xg]; int addrl=wyl+xl; if (gradient[addrl]!=255) { if (c.ressource.type!=NO_RES_TYPE) gradient[addrl]=0; else if (c.building!=NOGBID && c.building!=bgid) gradient[addrl]=0; else if (c.forbidden&teamMask || c.hiddenForbidden&teamMask) gradient[addrl]=0; else if (!canSwim && isWater(xg, yg)) gradient[addrl]=0; } } } if (building->type->zonable[WORKER]) { int r=building->unitStayRange; int r2=r*r; for (int yi=-r; yi<=r; yi++) { int yi2=yi*yi; for (int xi=-r; xi<=r; xi++) { if (yi2+(xi*xi)<=r2) { int xxi=15+xi; int yyi=15+yi; if (xxi<0) xxi=0; else if (xxi>31) xxi=31; if (yyi<0) yyi=0; else if (yyi>31) xxi=31; gradient[xxi+(yyi<<5)]=255; } } } } if (!building->type->isVirtual) { building->locked[canSwim]=true; int x=14; int y=14; int d=posW+1; for (int ai=0; ai<4; ai++) //angle-iterator for (int mi=0; mi=0); assert(y>=0); assert(x<32); assert(y<32); Uint8 g=gradient[(y<<5)+x]; //printf("ai=%d, mi=%d, (%d, %d), g=%d\n", ai, mi, x, y, g); if (g) { building->locked[canSwim]=false; goto doubleBreak; } switch (ai) { case 0: x++; break; case 1: y++; break; case 2: x--; break; case 3: y--; break; } } assert(building->locked[canSwim]); localBuildingGradientUpdateLocked++; //fprintf(logFile, "...not updatedLocalGradient! building bgid=%d is locked!\n", building->gid); //printf("...not updatedLocalGradient! building bgid=%d is locked!\n", building->gid); return; doubleBreak:; } else building->locked[canSwim]=false; //In this algotithm, "l" stands for one case at Left, "r" for one case at Right, "u" for Up, and "d" for Down. for (int depth=0; depth<2; depth++) // With a higher depth, we can have more complex obstacles. { for (int down=0; down<2; down++) { int x, y, dis, die, ddi; if (down) { x=0; y=0; dis=31; die=1; ddi=-2; } else { x=15; y=15; dis=1; die=31; ddi=+2; } for (int di=dis; di!=die; di+=ddi) //distance-iterator { for (int bi=0; bi<2; bi++) //back-iterator { for (int ai=0; ai<4; ai++) //angle-iterator { for (int mi=0; mi=0); assert(y>=0); assert(x<32); assert(y<32); int wy=(y<<5); int wyu, wyd; if (y==0) wyu=0; else wyu=((y-1)<<5); if (y==31) wyd=32*31; else wyd=((y+1)<<5); Uint8 max=gradient[wy+x]; if (max && max!=255) { int xl, xr; if (x==0) xl=0; else xl=x-1; if (x==31) xr=31; else xr=x+1; Uint8 side[8]; side[0]=gradient[wyu+xl]; side[1]=gradient[wyu+x ]; side[2]=gradient[wyu+xr]; side[3]=gradient[wy +xr]; side[4]=gradient[wyd+xr]; side[5]=gradient[wyd+x ]; side[6]=gradient[wyd+xl]; side[7]=gradient[wy +xl]; for (int i=0; i<8; i++) if (side[i]>max) max=side[i]; assert(max); if (max==1) gradient[wy+x]=1; else gradient[wy+x]=max-1; } if (bi==0) { switch (ai) { case 0: x++; break; case 1: y++; break; case 2: x--; break; case 3: y--; break; } } else { switch (ai) { case 0: y++; break; case 1: x++; break; case 2: y--; break; case 3: x--; break; } } } } } if (down) { x++; y++; } else { x--; y--; } } } } //printf("...updatedLocalGradient\n"); //fprintf(logFile, "...updatedLocalGradient\n"); } void Map::updateGlobalGradient(Building *building, bool canSwim) { if (size <= 65536) updateGlobalGradient(building, canSwim); else updateGlobalGradient(building, canSwim); } template void Map::updateGlobalGradient(Building *building, bool canSwim) { globalBuildingGradientUpdate++; assert(building); assert(building->type); //printf("updatingGlobalGradient (gbid=%d)\n", building->gid); //fprintf(logFile, "updatingGlobalGradient (gbid=%d)...", building->gid); int posX=building->posX; int posY=building->posY; int posW=building->type->width; //int posH=building->type->height; Uint32 teamMask=building->owner->me; Uint16 bgid=building->gid; Uint8 *gradient=building->globalGradient[canSwim]; assert(gradient); Tint *listedAddr = new Tint[size]; size_t listCountWrite = 0; memset(gradient, 1, size); if (building->type->isVirtual && !building->type->zonable[WORKER]) { assert(!building->type->zonableForbidden); int r=building->unitStayRange; int r2=r*r; for (int yi=-r; yi<=r; yi++) { int yi2=(yi*yi); for (int xi=-r; xi<=r; xi++) if (yi2+(xi*xi)type->zonable[WORKER]) { assert(!building->type->zonableForbidden); int r=building->unitStayRange; int r2=r*r; for (int yi=-r; yi<=r; yi++) { int yi2=(yi*yi); for (int xi=-r; xi<=r; xi++) if (yi2+(xi*xi)<=r2) { // TODO: check if this is really the ressource we are meant to remove size_t addr = ((posX+w+xi)&wMask)+(w*((posY+h+yi)&hMask)); gradient[addr] = 255; listedAddr[listCountWrite++] = addr; } } } if (!building->type->isVirtual) { building->locked[canSwim]=true; int x=(posX-1)&wMask; int y=(posY-1)&hMask; int d=posW+1; for (int ai=0; ai<4; ai++) //angle-iterator for (int mi=0; mi=0); assert(y>=0); assert(xlocked[canSwim]=false; goto doubleBreak; } switch (ai) { case 0: x++; break; case 1: y++; break; case 2: x--; break; case 3: y--; break; } x=(x+w)&wMask; y=(y+h)&hMask; } assert(building->locked[canSwim]); globalBuildingGradientUpdateLocked++; //printf("...not updatedGlobalGradient! building bgid=%d is locked!\n", building->gid); //fprintf(logFile, "...not updatedGlobalGradient! building bgid=%d is locked!\n", building->gid); return; doubleBreak:; } else building->locked[canSwim]=false; updateGlobalGradient(gradient, listedAddr, listCountWrite, GT_BUILDING, canSwim); delete[] listedAddr; } bool Map::updateLocalRessources(Building *building, bool canSwim) { localRessourcesUpdateCount++; assert(building); assert(building->type); assert(building->type->isVirtual); fprintf(logFile, "updatingLocalRessources[%d] (gbid=%d)...\n", canSwim, building->gid); int posX=building->posX; int posY=building->posY; Uint32 teamMask=building->owner->me; Uint8 *gradient=building->localRessources[canSwim]; if (gradient==NULL) { gradient=new Uint8[1024]; building->localRessources[canSwim]=gradient; } assert(gradient); bool *clearingRessources=building->clearingRessources; bool anyRessourceToClear=false; memset(gradient, 1, 1024); int range=building->unitStayRange; assert(range<=15); if (range>15) range=15; int range2=range*range; for (int yl=0; yl<32; yl++) { int wyl=(yl<<5); int yg=(yl+posY-15)&hMask; int wyg=w*yg; int dyl2=(yl-15)*(yl-15); for (int xl=0; xl<32; xl++) { int xg=(xl+posX-15)&wMask; Case c=cases[wyg+xg]; int addrl=wyl+xl; int dist2=(xl-15)*(xl-15)+dyl2; if (dist2<=range2) { if (c.ressource.type!=NO_RES_TYPE) { Sint8 t=c.ressource.type; if (tlocalRessourcesCleanTime[canSwim]=0; if (anyRessourceToClear) building->anyRessourceToClear[canSwim]=1; else { building->anyRessourceToClear[canSwim]=2; return false; } expandLocalGradient(gradient); return true; } void Map::expandLocalGradient(Uint8 *gradient) { for (int depth=0; depth<2; depth++) // With a higher depth, we can have more complex obstacles. { for (int down=0; down<2; down++) { int x, y, dis, die, ddi; if (down) { x=0; y=0; dis=31; die=1; ddi=-2; } else { x=15; y=15; dis=1; die=31; ddi=+2; } for (int di=dis; di!=die; di+=ddi) //distance-iterator { for (int bi=0; bi<2; bi++) //back-iterator { for (int ai=0; ai<4; ai++) //angle-iterator { for (int mi=0; mi=0); assert(y>=0); assert(x<32); assert(y<32); int wy=(y<<5); int wyu, wyd; if (y==0) wyu=0; else wyu=((y-1)<<5); if (y==31) wyd=32*31; else wyd=((y+1)<<5); Uint8 max=gradient[wy+x]; if (max && max!=255) { int xl, xr; if (x==0) xl=0; else xl=x-1; if (x==31) xr=31; else xr=x+1; Uint8 side[8]; side[0]=gradient[wyu+xl]; side[1]=gradient[wyu+x ]; side[2]=gradient[wyu+xr]; side[3]=gradient[wy +xr]; side[4]=gradient[wyd+xr]; side[5]=gradient[wyd+x ]; side[6]=gradient[wyd+xl]; side[7]=gradient[wy +xl]; for (int i=0; i<8; i++) if (side[i]>max) max=side[i]; assert(max); if (max==1) gradient[wy+x]=1; else gradient[wy+x]=max-1; } if (bi==0) { switch (ai) { case 0: x++; break; case 1: y++; break; case 2: x--; break; case 3: y--; break; } } else { switch (ai) { case 0: y++; break; case 1: x++; break; case 2: y--; break; case 3: x--; break; } } } } } if (down) { x++; y++; } else { x--; y--; } } } } } bool Map::buildingAvailable(Building *building, bool canSwim, int x, int y, int *dist) { buildingAvailableCountTot++; assert(building); int bx=building->posX; int by=building->posY; x&=wMask; y&=hMask; assert(x>=0); assert(y>=0); Uint8 *gradient=building->localGradient[canSwim]; if (isInLocalGradient(x, y, bx, by)) { buildingAvailableCountClose++; int lx=(x-bx+15+32)&31; int ly=(y-by+15+32)&31; if (!building->dirtyLocalGradient[canSwim]) { Uint8 currentg=gradient[lx+(ly<<5)]; if (currentg>1) { buildingAvailableCountCloseSuccessFast++; *dist=255-currentg; return true; } else for (int d=0; d<8; d++) { int ddx, ddy; Unit::dxdyfromDirection(d, &ddx, &ddy); int lxddx=lx+ddx; if (lxddx<0) lxddx=0; else if(lxddx>31) lxddx=31; int lyddy=ly+ddy; if (lyddy<0) lyddy=0; else if(lyddy>31) lyddy=31; Uint8 g=gradient[lxddx+(lyddy<<5)]; if (g>1) { buildingAvailableCountCloseSuccessAround++; *dist=255-g; return true; } } } updateLocalGradient(building, canSwim); if (building->locked[canSwim]) { buildingAvailableCountCloseFailureLocked++; //printf("ba-a- local gradient to building bgid=%d@(%d, %d) failed, locked. p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); //fprintf(logFile, "ba-a- local gradient to building bgid=%d@(%d, %d) failed, locked. p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); return false; } Uint8 currentg=gradient[lx+ly*32]; if (currentg>1) { buildingAvailableCountCloseSuccessUpdate++; *dist=255-currentg; return true; } else for (int d=0; d<8; d++) { int ddx, ddy; Unit::dxdyfromDirection(d, &ddx, &ddy); int lxddx=lx+ddx; if (lxddx<0) lxddx=0; else if(lxddx>31) lxddx=31; int lyddy=ly+ddy; if (lyddy<0) lyddy=0; else if(lyddy>31) lyddy=31; Uint8 g=gradient[lxddx+(lyddy<<5)]; if (g>1) { buildingAvailableCountCloseSuccessUpdateAround++; *dist=255-g; return true; } } buildingAvailableCountCloseFailureEnd++; } else buildingAvailableCountIsFar++; buildingAvailableCountFar++; gradient=building->globalGradient[canSwim]; if (gradient==NULL) { buildingAvailableCountFarNew++; gradient=new Uint8[size]; fprintf(logFile, "ba- allocating globalGradient for gbid=%d (%p)\n", building->gid, gradient); building->globalGradient[canSwim]=gradient; } else { buildingAvailableCountFarOld++; if (building->locked[canSwim]) { buildingAvailableCountFarOldFailureLocked++; //printf("ba-b- global gradient to building bgid=%d@(%d, %d) failed, locked. p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); //fprintf(logFile, "ba-b- global gradient to building bgid=%d@(%d, %d) failed, locked. p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); return false; } Uint8 currentg=gradient[(x&wMask)+w*(y&hMask)]; if (currentg>1) { buildingAvailableCountFarOldSuccessFast++; *dist=255-currentg; return true; } else { for (int d=0; d<8; d++) { int ddx, ddy; Unit::dxdyfromDirection(d, &ddx, &ddy); int xddx=(x+ddx)&wMask; int yddy=(y+ddy)&hMask; Uint8 g=gradient[xddx+yddy*w]; if (g>1) { buildingAvailableCountFarOldSuccessAround++; *dist=255-g; return true; } } buildingAvailableCountFarOldFailureEnd++; //printf("ba-c- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); //fprintf(logFile, "ba-c- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); return false; } } updateGlobalGradient(building, canSwim); if (building->locked[canSwim]) { buildingAvailableCountFarNewFailureLocked++; //printf("ba-d- global gradient to building bgid=%d@(%d, %d) failed, locked.\n", building->gid, building->posX, building->posY); fprintf(logFile, "ba-d- global gradient to building bgid=%d@(%d, %d) failed, locked.\n", building->gid, building->posX, building->posY); return false; } Uint8 currentg=gradient[(x&wMask)+w*(y&hMask)]; if (currentg>1) { buildingAvailableCountFarNewSuccessFast++; *dist=255-currentg; return true; } else { for (int d=0; d<8; d++) { int ddx, ddy; Unit::dxdyfromDirection(d, &ddx, &ddy); int xddx=(x+ddx)&wMask; int yddy=(y+ddy)&hMask; Uint8 g=gradient[xddx+yddy*w]; if (g>1) { buildingAvailableCountFarNewSuccessClosely++; *dist=255-g; return true; } } if (building->type->isVirtual) { //printf("ba-e- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); //fprintf(logFile, "ba-e- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); buildingAvailableCountFarNewFailureVirtual++; } else { if (building->verbose) printf("ba-f- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); fprintf(logFile, "ba-f- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); buildingAvailableCountFarNewFailureEnd++; } return false; } } bool Map::pathfindBuilding(Building *building, bool canSwim, int x, int y, int *dx, int *dy, bool verbose) { pathToBuildingCountTot++; assert(building); if (verbose) printf("pathfindingBuilding (gbid=%d)...\n", building->gid); int bx=building->posX; int by=building->posY; assert(x>=0); assert(y>=0); Uint32 teamMask=building->owner->me; if (((cases[x+y*w].forbidden | cases[x+y*w].hiddenForbidden) & teamMask)!=0) { int teamNumber=building->owner->teamNumber; if (verbose) printf(" ...pathfindForbidden(%d, %d, %d, %d)\n", teamNumber, canSwim, x, y); return pathfindForbidden(building->globalGradient[canSwim], teamNumber, canSwim, x, y, dx, dy, verbose); } Uint8 *gradient=building->localGradient[canSwim]; if (isInLocalGradient(x, y, bx, by)) { pathToBuildingCountClose++; int lx=(x-bx+15+32)&31; int ly=(y-by+15+32)&31; int max=0; Uint8 currentg=gradient[lx+(ly<<5)]; bool found=false; bool gradientUsable=false; if (!building->dirtyLocalGradient[canSwim] && currentg==255) { *dx=0; *dy=0; pathToBuildingCountCloseSuccessStand++; if (verbose) printf("...pathfindedBuilding v1\n"); return true; } if (!building->dirtyLocalGradient[canSwim] && currentg>1) { if (directionByMinigrad(teamMask, canSwim, x, y, bx, by, dx, dy, gradient, true, verbose)) { pathToBuildingCountCloseSuccessBase++; if (verbose) printf("...pathfindedBuilding v2\n"); return true; } } updateLocalGradient(building, canSwim); if (building->locked[canSwim]) { pathToBuildingCountCloseFailureLocked++; if (verbose) printf("a- local gradient to building bgid=%d@(%d, %d) failed, locked. p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); fprintf(logFile, "a- local gradient to building bgid=%d@(%d, %d) failed, locked. p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); return false; } max=0; currentg=gradient[lx+ly*32]; found=false; gradientUsable=false; if (currentg>1) { if (directionByMinigrad(teamMask, canSwim, x, y, bx, by, dx, dy, gradient, true, verbose)) { pathToBuildingCountCloseSuccessUpdated++; if (verbose) printf("...pathfindedBuilding v4\n"); return true; } } pathToBuildingCountCloseFailureEnd++; } else pathToBuildingCountIsFar++; pathToBuildingCountFar++; //Here the "local-32*32-cases-gradient-pathfinding-system" has failed, then we look for a full size gradient. gradient=building->globalGradient[canSwim]; if (gradient==NULL) { pathToBuildingCountFarIsNew++; gradient=new Uint8[size]; if (verbose) printf("allocating globalGradient for gbid=%d (%p)\n", building->gid, gradient); fprintf(logFile, "allocating globalGradient for gbid=%d (%p)\n", building->gid, gradient); building->globalGradient[canSwim]=gradient; } else { bool found=false; Uint8 currentg=gradient[(x&wMask)+w*(y&hMask)]; if (building->locked[canSwim]) { pathToBuildingCountFarOldFailureLocked++; if (verbose) printf("b- global gradient to building bgid=%d@(%d, %d) failed, locked. p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); fprintf(logFile, "b- global gradient to building bgid=%d@(%d, %d) failed, locked. p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); return false; } else if (currentg==1) { pathToBuildingCountFarOldFailureBad++; if (verbose) printf("c- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); fprintf(logFile, "c- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); return false; } else found=directionByMinigrad(teamMask, canSwim, x, y, dx, dy, gradient, true, verbose); //printf("found=%d, d=(%d, %d)\n", found, *dx, *dy); if (found) { pathToBuildingCountFarOldSuccess++; if (verbose) printf("...pathfindedBuilding v6\n"); return true; } else if (building->lastGlobalGradientUpdateStepCounter[canSwim]+128>game->stepCounter) // not faster than 5.12s { pathToBuildingCountFarOldFailureRepeat++; if (verbose) printf("d- global gradient to building bgid=%d@(%d, %d) failed, repeat.\n", building->gid, building->posX, building->posY); return directionByMinigrad(teamMask, canSwim, x, y, dx, dy, gradient, false, verbose); } else { pathToBuildingCountFarOldFailureUnusable++; } } updateGlobalGradient(building, canSwim); building->lastGlobalGradientUpdateStepCounter[canSwim]=game->stepCounter; if (building->locked[canSwim]) { pathToBuildingCountFarUpdateFailureLocked++; if (verbose) printf("e- global gradient to building bgid=%d@(%d, %d) failed, locked.\n", building->gid, building->posX, building->posY); fprintf(logFile, "e- global gradient to building bgid=%d@(%d, %d) failed, locked.\n", building->gid, building->posX, building->posY); return false; } Uint8 currentg=gradient[(x&wMask)+w*(y&hMask)]; if (currentg>1) { if (directionByMinigrad(teamMask, canSwim, x, y, dx, dy, gradient, true, verbose)) { pathToBuildingCountFarUpdateSuccess++; if (verbose) printf("...pathfindedBuilding v7\n"); return true; } } if (building->type->isVirtual) { pathToBuildingCountFarUpdateFailureVirtual++; if (verbose) printf("f- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); //fprintf(logFile, "f- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); } else { pathToBuildingCountFarUpdateFailureBad++; // TODO: find why this happend so often if (verbose) printf("g- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d), canSwim=%d\n", building->gid, building->posX, building->posY, x, y, canSwim); fprintf(logFile, "g- global gradient to building bgid=%d@(%d, %d) failed! p=(%d, %d), canSwim=%d\n", building->gid, building->posX, building->posY, x, y, canSwim); } return false; } bool Map::pathfindLocalRessource(Building *building, bool canSwim, int x, int y, int *dx, int *dy) { pathfindLocalRessourceCount++; assert(building); assert(building->type); assert(building->type->isVirtual); //printf("pathfindingLocalRessource[%d] (gbid=%d)...\n", canSwim, building->gid); int bx=building->posX; int by=building->posY; Uint32 teamMask=building->owner->me; Uint8 *gradient=building->localRessources[canSwim]; if (gradient==NULL) { if (!updateLocalRessources(building, canSwim)) return false; gradient=building->localRessources[canSwim]; } assert(gradient); assert(isInLocalGradient(x, y, bx, by)); int lx=(x-bx+15+32)&31; int ly=(y-by+15+32)&31; int max=0; Uint8 currentg=gradient[lx+(ly<<5)]; bool found=false; bool gradientUsable=false; if (currentg==1 && (building->localRessourcesCleanTime[canSwim]+=16)<128) { // This mean there are still ressources, but they are unreachable. // We wait 5[s] before recomputing anything. if (verbose) printf("...pathfindedLocalRessource v0 failure waiting\n"); pathfindLocalRessourceCountWait++; return false; } if (currentg>1 && currentg!=255) { for (int sd=0; sd<=1; sd++) for (int d=sd; d<8; d+=2) { int ddx, ddy; Unit::dxdyfromDirection(d, &ddx, &ddy); int lxddx=lx+ddx; if (lxddx<0) lxddx=0; else if(lxddx>31) lxddx=31; int lyddy=ly+ddy; if (lyddy<0) lyddy=0; else if(lyddy>31) lyddy=31; Uint8 g=gradient[lxddx+(lyddy<<5)]; if (!gradientUsable && g>currentg && isHardSpaceForGroundUnit(x+ddx, y+ddy, canSwim, teamMask)) gradientUsable=true; if (g>=max && isFreeForGroundUnit(x+ddx, y+ddy, canSwim, teamMask)) { max=g; *dx=ddx; *dy=ddy; found=true; } } if (gradientUsable) { if (found) { pathfindLocalRessourceCountSuccessBase++; //printf("...pathfindedLocalRessource v1\n"); return true; } else { *dx=0; *dy=0; pathfindLocalRessourceCountSuccessLocked++; if (verbose) printf("...pathfindedLocalRessource v2 locked\n"); return true; } } } updateLocalRessources(building, canSwim); max=0; currentg=gradient[lx+(ly<<5)]; found=false; gradientUsable=false; if (currentg==1) { pathfindLocalRessourceCountFailureNone++; //printf("...pathfindedLocalRessource v3 No ressource\n"); return false; } else if ((currentg!=0) && (currentg!=255)) { for (int sd=0; sd<=1; sd++) for (int d=sd; d<8; d+=2) { int ddx, ddy; Unit::dxdyfromDirection(d, &ddx, &ddy); int lxddx=lx+ddx; if (lxddx<0) lxddx=0; else if(lxddx>31) lxddx=31; int lyddy=ly+ddy; if (lyddy<0) lyddy=0; else if(lyddy>31) lyddy=31; Uint8 g=gradient[lxddx+(lyddy<<5)]; if (!gradientUsable && g>currentg && isHardSpaceForGroundUnit(x+ddx, y+ddy, canSwim, teamMask)) gradientUsable=true; if (g>=max && isFreeForGroundUnit(x+ddx, y+ddy, canSwim, teamMask)) { max=g; *dx=ddx; *dy=ddy; found=true; } } if (gradientUsable) { if (found) { pathfindLocalRessourceCountSuccessUpdate++; //printf("...pathfindedLocalRessource v3\n"); return true; } else { *dx=0; *dy=0; pathfindLocalRessourceCountSuccessUpdateLocked++; if (verbose) printf("...pathfindedLocalRessource v4 locked\n"); return true; } } else { pathfindLocalRessourceCountFailureUnusable++; fprintf(logFile, "lr-a- failed to pathfind localRessource bgid=%d@(%d, %d) p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); if (verbose) printf("lr-a- failed to pathfind localRessource bgid=%d@(%d, %d) p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); return false; } } else { pathfindLocalRessourceCountFailureBad++; fprintf(logFile, "lr-b- failed to pathfind localRessource bgid=%d@(%d, %d) p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); if (verbose) printf("lr-b- failed to pathfind localRessource bgid=%d@(%d, %d) p=(%d, %d)\n", building->gid, building->posX, building->posY, x, y); return false; } } void Map::dirtyLocalGradient(int x, int y, int wl, int hl, int teamNumber) { y &= hMask; x &= wMask; fprintf(logFile, "Map::dirtyLocalGradient(%d, %d, %d, %d, %d)\n", x, y, wl, hl, teamNumber); for (int hi=0; hiteams[teamNumber]->myBuildings[Building::GIDtoID(bgid)]; for (int canSwim=0; canSwim<2; canSwim++) { b->dirtyLocalGradient[canSwim]=true; b->locked[canSwim]=false; if (b->localRessources[canSwim]) { delete b->localRessources[canSwim]; b->localRessources[canSwim]=NULL; } } } } } } bool Map::pathfindForbidden(Uint8 *optionGradient, int teamNumber, bool canSwim, int x, int y, int *dx, int *dy, bool verbose) { if (verbose) printf("pathfindForbidden(%d, %d, (%d, %d))\n", teamNumber, canSwim, x, y); pathfindForbiddenCount++; Uint8 *gradient=forbiddenGradient[teamNumber][canSwim]; if (verbose && !gradient) printf("error, Map::pathfindForbidden(), forbiddenGradient[teamNumber=%d][canSwim=%d] is NULL\n", teamNumber, canSwim); assert(gradient); Uint32 maxValue=0; int maxd=0; for (int di=0; di<8; di++) { int rx=tabClose[di][0]; int ry=tabClose[di][1]; int xg=(x+rx)&wMask; int yg=(y+ry)&hMask; if (verbose) printf("[di=%d], r=(%d, %d), g=(%d, %d)\n", di, rx, ry, xg, yg); if (!isFreeForGroundUnitNoForbidden(xg, yg, canSwim)) continue; size_t addr=xg+(yg<(addr), gradient[addr]); Uint8 option; if (optionGradient!=NULL) option=optionGradient[addr]; else option=0; if (verbose) printf("option=%d @ %p\n", option, optionGradient); Uint32 value=(base<<8)|option; if (verbose) printf("value=%d \n", value); if (maxValue=(2<<8)) { *dx=tabClose[maxd][0]; *dy=tabClose[maxd][1]; if (verbose) printf(" Success (%d:%d) (%d, %d)\n", (maxValue>>8), (maxValue&0xFF), *dx, *dy); pathfindForbiddenCountSuccess++; return true; } else { if (verbose) printf(" Failure (%d)\n", maxValue); pathfindForbiddenCountFailure++; return false; } } bool Map::pathfindGuardArea(int teamNumber, bool canSwim, int x, int y, int *dx, int *dy) { Uint8 *gradient = guardAreasGradient[teamNumber][canSwim]; Uint8 max = gradient[x + (y<max && isFreeForGroundUnitNoForbidden(xg, yg, canSwim)) { max = g; *dx = ddx; *dy = ddy; found = true; } } // we are in a blocked situation, so we have to regenerate the forbidden gradient if (!found) updateGuardAreasGradient(teamNumber, canSwim); return found; } void Map::updateForbiddenGradient(int teamNumber, bool canSwim) { if (size <= 65536) updateForbiddenGradient(teamNumber, canSwim); else updateForbiddenGradient(teamNumber, canSwim); } template void Map::updateForbiddenGradient(int teamNumber, bool canSwim) { #define SIMONS_FORBIDDEN_GRADIENT_INIT #if defined(TEST_FORBIDDEN_GRADIENT_INIT) #define SIMONS_FORBIDDEN_GRADIENT_INIT #define SIMPLE_FORBIDDEN_GRADIENT_INIT #endif Tint *listedAddr = new Tint[size]; size_t listCountWrite=0; Uint32 teamMask = Team::teamNumberToMask(teamNumber); #ifdef SIMON2_FORBIDDEN_GRADIENT_INIT Uint8 *gradient = forbiddenGradient[teamNumber][canSwim]; assert(gradient); for (size_t i = 0; i < size; i++) { Case c = cases[i]; if ((c.ressource.type != NO_RES_TYPE) || (c.building!=NOGBID) || (!canSwim && isWater(i))) { gradient[i] = 0; } else if ((c.forbidden | c.hiddenForbidden) & teamMask) { // we compute the 8 addresses around i: // (a stands for address, u for up, d for down, l for left, r for right, m for middle) size_t aul = (i - 1 - w) & (size - 1); size_t aum = (i - w) & (size - 1); size_t aur = (i + 1 - w) & (size - 1); size_t amr = (i + 1 ) & (size - 1); size_t adr = (i + 1 + w) & (size - 1); size_t adm = (i + w) & (size - 1); size_t adl = (i - 1 + w) & (size - 1); size_t aml = (i - 1 ) & (size - 1); if( ((cases[aul].ressource.type != NO_RES_TYPE) || ((cases[aul].forbidden | cases[aul].hiddenForbidden) &teamMask) || (cases[aul].building!=NOGBID) || (!canSwim && isWater(aul))) && ((cases[aul].ressource.type != NO_RES_TYPE) || ((cases[aum].forbidden | cases[aum].hiddenForbidden) &teamMask) || (cases[aum].building!=NOGBID) || (!canSwim && isWater(aum))) && ((cases[aul].ressource.type != NO_RES_TYPE) || ((cases[aur].forbidden | cases[aur].hiddenForbidden) &teamMask) || (cases[aur].building!=NOGBID) || (!canSwim && isWater(aur))) && ((cases[aul].ressource.type != NO_RES_TYPE) || ((cases[amr].forbidden | cases[amr].hiddenForbidden) &teamMask) || (cases[amr].building!=NOGBID) || (!canSwim && isWater(amr))) && ((cases[aul].ressource.type != NO_RES_TYPE) || ((cases[adr].forbidden | cases[adr].hiddenForbidden) &teamMask) || (cases[adr].building!=NOGBID) || (!canSwim && isWater(adr))) && ((cases[aul].ressource.type != NO_RES_TYPE) || ((cases[adm].forbidden | cases[adm].hiddenForbidden) &teamMask) || (cases[adm].building!=NOGBID) || (!canSwim && isWater(adm))) && ((cases[aul].ressource.type != NO_RES_TYPE) || ((cases[adl].forbidden | cases[adl].hiddenForbidden) &teamMask) || (cases[adl].building!=NOGBID) || (!canSwim && isWater(adl))) && ((cases[aul].ressource.type != NO_RES_TYPE) || ((cases[aml].forbidden | cases[aml].hiddenForbidden) &teamMask) || (cases[aml].building!=NOGBID) || (!canSwim && isWater(aml))) ) { gradient[i]= 1; } else { gradient[i]=254; listedAddr[listCountWrite++] = i; } } else { gradient[i] = 255; } } // Then we propagate the gradient updateGlobalGradient(gradient, listedAddr, listCountWrite, GT_FORBIDDEN, canSwim); #endif #if defined(SIMONS_FORBIDDEN_GRADIENT_INIT) Uint8 *testgradient = forbiddenGradient[teamNumber][canSwim]; assert(testgradient); size_t listCountWriteInit = 0; // We set the obstacle and free places for (size_t i=0; i> wDec; // Calculate the coordinates of size_t x = i & wMask; // the current field and of the size_t yu = ((y - 1) & hMask); // fields next to it. size_t yd = ((y + 1) & hMask); size_t xl = ((x - 1) & wMask); size_t xr = ((x + 1) & wMask); size_t deltaAddrC[8]; deltaAddrC[0] = (yu << wDec) | xl; deltaAddrC[1] = (yu << wDec) | x ; deltaAddrC[2] = (yu << wDec) | xr; deltaAddrC[3] = (y << wDec) | xr; deltaAddrC[4] = (yd << wDec) | xr; deltaAddrC[5] = (yd << wDec) | x ; deltaAddrC[6] = (yd << wDec) | xl; deltaAddrC[7] = (y << wDec) | xl; for( int ci=0; ci<8; ci++) { if( testgradient[ deltaAddrC[ci] ] == 255 ) { testgradient[i] = 254; listedAddr[listCountWrite++] = i; break; } } } // Then we propagate the gradient updateGlobalGradient(testgradient, listedAddr, listCountWrite, GT_FORBIDDEN, canSwim); #endif #if defined(SIMPLE_FORBIDDEN_GRADIENT_INIT) listCountWrite = 0; #if defined(TEST_FORBIDDEN_GRADIENT_INIT) Uint8 *gradient = new Uint8[size]; #else Uint8 *gradient = forbiddenGradient[teamNumber][canSwim]; assert(gradient); #endif for (size_t i=0; imapHeader.getNumberOfTeams(); i++) updateForbiddenGradient(i); } void Map::updateGuardAreasGradient(int teamNumber, bool canSwim) { if (size <= 65536) updateGuardAreasGradient(teamNumber, canSwim); else updateGuardAreasGradient(teamNumber, canSwim); } template void Map::updateGuardAreasGradient(int teamNumber, bool canSwim) { Uint8 *gradient = guardAreasGradient[teamNumber][canSwim]; assert(gradient); Tint *listedAddr = new Tint[size]; size_t listCountWrite = 0; // We set the obstacle and free places Uint32 teamMask = Team::teamNumberToMask(teamNumber); for (size_t i=0; imapHeader.getNumberOfTeams(); i++) updateGuardAreasGradient(i); } void Map::initExploredArea(int teamNumber) { std::fill(exploredArea[teamNumber], exploredArea[teamNumber] + size, 0); } void Map::makeDiscoveredAreasExplored (int teamNumber) { /* This function is a stupid hack to make up for the fact that exploredArea is not saved in saved games. It allows doing something less awful than simply making everything considered unexplored (which completely messes up explorer behavior and makes them explore the entire world all over again) when games are reloaded. */ assert(game->teams[teamNumber]); assert(game->teams[teamNumber]->me); assert(exploredArea[teamNumber]); for (int x = 0; x < getW(); x++) { for (int y = 0; y < getH(); y++) { if (isMapDiscovered (x, y, game->teams[teamNumber]->me)) { setMapExploredByUnit (x, y, 1, 1, teamNumber); }}} } void Map::updateExploredArea(int teamNumber) { for (size_t i = 0; i < size; i++) if (exploredArea[teamNumber][i] > 0) exploredArea[teamNumber][i]--; } void Map::regenerateMap(int x, int y, int w, int h) { for (int dx=x; dxterrain + c->building + c->ressource.getUint32() + c->groundUnit + c->airUnit + c->forbidden + c->hiddenForbidden + c->scriptAreas; cs=(cs<<1)|(cs>>31); } }; return cs; } Sint32 Map::warpDistSquare(int px, int py, int qx, int qy) { Sint32 dx=abs(px-qx); Sint32 dy=abs(py-qy); dx&=wMask; dy&=hMask; if (dx>(w>>1)) dx=w-dx; if (dy>(h>>1)) dy=h-dy; return ((dx*dx)+(dy*dy)); } Sint32 Map::warpDistMax(int px, int py, int qx, int qy) { Sint32 dx=abs(px-qx); Sint32 dy=abs(py-qy); dx&=wMask; dy&=hMask; if (dx>(w>>1)) dx=abs(w-dx); if (dy>(h>>1)) dy=abs(h-dy); if (dx>dy) return dx; else return dy; } bool Map::isInLocalGradient(int ux, int uy, int bx, int by) { Sint32 dx=abs(ux-bx); Sint32 dy=abs(uy-by); dx&=wMask; dy&=hMask; if (dx>(w>>1)) dx=abs(w-dx); if (dy>(h>>1)) dy=abs(h-dy); if (dx>dy) { if (dx<15) return true; if (dx>15) return false; return ((bx+15) & wMask)==(ux & wMask); } else if (dx15) return false; return ((by+15) & wMask)==(uy & wMask); } else { if (dx<15) return true; if (dx>15) return false; return (((bx+15) & wMask)==(ux & wMask)) && (((by+15) & wMask)==(uy & wMask)); } } void Map::dumpGradient(Uint8 *gradient, const char *filename) { FILE *fp = globalContainer->fileManager->openFP(filename, "wb"); if (fp) { fprintf(fp, "P5 %d %d 255\n", w, h); fwrite(gradient, w, h, fp); fclose(fp); } }