mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-09-21 20:06:40 +00:00
Reshuffling of AI management of territory maps
Reviewed By: Sandarac Differential Revision: https://code.wildfiregames.com/D96 This was SVN commit r19174.
This commit is contained in:
@@ -60,10 +60,9 @@ m.HQ.prototype.init = function(gameState, queues)
|
||||
this.territoryMap = m.createTerritoryMap(gameState);
|
||||
// initialize base map. Each pixel is a base ID, or 0 if not or not accessible
|
||||
this.basesMap = new API3.Map(gameState.sharedScript, "territory");
|
||||
// area of n cells on the border of the map : 0=inside map, 1=border map, 2=border+inaccessible
|
||||
// create borderMap: flag cells on the border of the map
|
||||
// then this map will be completed with our frontier in updateTerritories
|
||||
this.borderMap = m.createBorderMap(gameState);
|
||||
// initialize frontier map. Each cell is 2 if on the near frontier, 1 on the frontier and 0 otherwise
|
||||
this.frontierMap = m.createFrontierMap(gameState);
|
||||
// list of allowed regions
|
||||
this.landRegions = {};
|
||||
// try to determine if we have a water map
|
||||
@@ -836,7 +835,7 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, template, resource,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.borderMap.map[j] > 0) // disfavor the borders of the map
|
||||
if (this.borderMap.map[j] & m.fullBorder_Mask) // disfavor the borders of the map
|
||||
norm *= 0.5;
|
||||
|
||||
let val = 2*gameState.sharedScript.ccResourceMaps[resource].map[j];
|
||||
@@ -988,7 +987,7 @@ m.HQ.prototype.findStrategicCCLocation = function(gameState, template)
|
||||
currentVal += delta*delta;
|
||||
}
|
||||
// disfavor border of the map
|
||||
if (this.borderMap.map[j] > 0)
|
||||
if (this.borderMap.map[j] & m.fullBorder_Mask)
|
||||
currentVal += 10000;
|
||||
|
||||
if (bestVal !== undefined && currentVal > bestVal)
|
||||
@@ -1060,8 +1059,8 @@ m.HQ.prototype.findMarketLocation = function(gameState, template)
|
||||
|
||||
for (let j = 0; j < this.territoryMap.length; ++j)
|
||||
{
|
||||
// do not try on the border of our territory
|
||||
if (this.frontierMap.map[j] === 2)
|
||||
// do not try on the narrow border of our territory
|
||||
if (this.borderMap.map[j] & m.narrowFrontier_Mask)
|
||||
continue;
|
||||
if (this.basesMap.map[j] === 0) // only in our territory
|
||||
continue;
|
||||
@@ -1186,9 +1185,9 @@ m.HQ.prototype.findDefensiveLocation = function(gameState, template)
|
||||
if (!wonderMode)
|
||||
{
|
||||
// do not try if well inside or outside territory
|
||||
if (this.frontierMap.map[j] === 0)
|
||||
if (!(this.borderMap.map[j] & m.fullFrontier_Mask))
|
||||
continue;
|
||||
if (this.frontierMap.map[j] === 1 && isTower)
|
||||
if (this.borderMap.map[j] & m.largeFrontier_Mask && isTower)
|
||||
continue;
|
||||
}
|
||||
if (this.basesMap.map[j] === 0) // inaccessible cell
|
||||
@@ -1883,16 +1882,25 @@ m.HQ.prototype.restartBuild = function(gameState, structure)
|
||||
|
||||
m.HQ.prototype.updateTerritories = function(gameState)
|
||||
{
|
||||
const around = [ [-0.7,0.7], [0,1], [0.7,0.7], [1,0], [0.7,-0.7], [0,-1], [-0.7,-0.7], [-1,0] ];
|
||||
let alliedVictory = gameState.getAlliedVictory();
|
||||
let passabilityMap = gameState.getMap();
|
||||
let width = this.territoryMap.width;
|
||||
let cellSize = this.territoryMap.cellSize;
|
||||
let insideSmall = Math.round(45 / cellSize);
|
||||
let insideLarge = Math.round(80 / cellSize); // should be about the range of towers
|
||||
let expansion = 0;
|
||||
|
||||
for (let j = 0; j < this.territoryMap.length; ++j)
|
||||
{
|
||||
if (this.borderMap.map[j] > 1)
|
||||
if (this.borderMap.map[j] & m.outside_Mask)
|
||||
continue;
|
||||
if (this.borderMap.map[j] & m.fullFrontier_Mask)
|
||||
this.borderMap.map[j] &= ~m.fullFrontier_Mask; // reset the frontier
|
||||
|
||||
if (this.territoryMap.getOwnerIndex(j) != PlayerID)
|
||||
{
|
||||
// If this tile was already accounted, remove it
|
||||
if (this.basesMap.map[j] === 0)
|
||||
continue;
|
||||
let base = this.getBaseByID(this.basesMap.map[j]);
|
||||
@@ -1905,8 +1913,46 @@ m.HQ.prototype.updateTerritories = function(gameState)
|
||||
base.territoryIndices.splice(index, 1);
|
||||
this.basesMap.map[j] = 0;
|
||||
}
|
||||
else if (this.basesMap.map[j] === 0)
|
||||
else
|
||||
{
|
||||
// Update the frontier
|
||||
let ix = j%width;
|
||||
let iz = Math.floor(j/width);
|
||||
let onFrontier = false;
|
||||
for (let a of around)
|
||||
{
|
||||
let jx = ix + Math.round(insideSmall*a[0]);
|
||||
if (jx < 0 || jx >= width)
|
||||
continue;
|
||||
let jz = iz + Math.round(insideSmall*a[1]);
|
||||
if (jz < 0 || jz >= width)
|
||||
continue;
|
||||
if (this.borderMap.map[jx+width*jz] & m.outside_Mask)
|
||||
continue;
|
||||
let territoryOwner = this.territoryMap.getOwnerIndex(jx+width*jz);
|
||||
if (territoryOwner !== PlayerID && !(alliedVictory && gameState.isPlayerAlly(territoryOwner)))
|
||||
{
|
||||
this.borderMap.map[j] |= m.narrowFrontier_Mask;
|
||||
break;
|
||||
}
|
||||
jx = ix + Math.round(insideLarge*a[0]);
|
||||
if (jx < 0 || jx >= width)
|
||||
continue;
|
||||
jz = iz + Math.round(insideLarge*a[1]);
|
||||
if (jz < 0 || jz >= width)
|
||||
continue;
|
||||
if (this.borderMap.map[jx+width*jz] & m.outside_Mask)
|
||||
continue;
|
||||
territoryOwner = this.territoryMap.getOwnerIndex(jx+width*jz);
|
||||
if (territoryOwner !== PlayerID && !(alliedVictory && gameState.isPlayerAlly(territoryOwner)))
|
||||
onFrontier = true;
|
||||
}
|
||||
if (onFrontier && !(this.borderMap.map[j] & m.narrowFrontier_Mask))
|
||||
this.borderMap.map[j] |= m.largeFrontier_Mask;
|
||||
|
||||
// If this tile was not already accounted, add it
|
||||
if (this.basesMap.map[j] !== 0)
|
||||
continue;
|
||||
let landPassable = false;
|
||||
let ind = API3.getMapIndices(j, this.territoryMap, passabilityMap);
|
||||
let access;
|
||||
@@ -1943,8 +1989,6 @@ m.HQ.prototype.updateTerritories = function(gameState)
|
||||
}
|
||||
}
|
||||
|
||||
this.frontierMap = m.createFrontierMap(gameState);
|
||||
|
||||
if (!expansion)
|
||||
return;
|
||||
// We've increased our territory, so we may have some new room to build
|
||||
|
||||
@@ -120,7 +120,23 @@ m.createTerritoryMap = function(gameState)
|
||||
return ret;
|
||||
};
|
||||
|
||||
/** flag cells around the border of the map (2 if all points into that cell are inaccessible, 1 otherwise) */
|
||||
/**
|
||||
* The borderMap contains some border and frontier information:
|
||||
* - border of the map filled once:
|
||||
* - all mini-cells (1x1) from the big cell (8x8) inaccessibles => bit 0
|
||||
* - inside a given distance to the border => bit 1
|
||||
* - frontier of our territory (updated regularly in updateFrontierMap)
|
||||
* - narrow border (inside our territory) => bit 2
|
||||
* - large border (inside our territory, exclusive of narrow) => bit 3
|
||||
*/
|
||||
|
||||
m.outside_Mask = 1;
|
||||
m.border_Mask = 2;
|
||||
m.fullBorder_Mask = m.outside_Mask | m.border_Mask;
|
||||
m.narrowFrontier_Mask = 4;
|
||||
m.largeFrontier_Mask = 8;
|
||||
m.fullFrontier_Mask = m.narrowFrontier_Mask | m.largeFrontier_Mask;
|
||||
|
||||
m.createBorderMap = function(gameState)
|
||||
{
|
||||
let map = new API3.Map(gameState.sharedScript, "territory");
|
||||
@@ -139,13 +155,13 @@ m.createBorderMap = function(gameState)
|
||||
let radius = dx*dx + dy*dy;
|
||||
if (radius < radcut)
|
||||
continue;
|
||||
map.map[j] = 2;
|
||||
map.map[j] = m.outside_Mask;
|
||||
let ind = API3.getMapIndices(j, map, passabilityMap);
|
||||
for (let k of ind)
|
||||
{
|
||||
if (passabilityMap.data[k] & obstructionMask)
|
||||
continue;
|
||||
map.map[j] = 1;
|
||||
map.map[j] = m.border_Mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -159,13 +175,13 @@ m.createBorderMap = function(gameState)
|
||||
let iy = Math.floor(j/width);
|
||||
if (ix < border || ix >= borderCut || iy < border || iy >= borderCut)
|
||||
{
|
||||
map.map[j] = 2;
|
||||
map.map[j] = m.outside_Mask;
|
||||
let ind = API3.getMapIndices(j, map, passabilityMap);
|
||||
for (let k of ind)
|
||||
{
|
||||
if (passabilityMap.data[k] & obstructionMask)
|
||||
continue;
|
||||
map.map[j] = 1;
|
||||
map.map[j] = m.border_Mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -176,61 +192,6 @@ m.createBorderMap = function(gameState)
|
||||
return map;
|
||||
};
|
||||
|
||||
/** map of our frontier : 2 means narrow border, 1 means large border */
|
||||
m.createFrontierMap = function(gameState)
|
||||
{
|
||||
let alliedVictory = gameState.getAlliedVictory();
|
||||
let territoryMap = gameState.ai.HQ.territoryMap;
|
||||
let borderMap = gameState.ai.HQ.borderMap;
|
||||
const around = [ [-0.7,0.7], [0,1], [0.7,0.7], [1,0], [0.7,-0.7], [0,-1], [-0.7,-0.7], [-1,0] ];
|
||||
|
||||
let map = new API3.Map(gameState.sharedScript, "territory");
|
||||
let width = map.width;
|
||||
let insideSmall = Math.round(45 / map.cellSize);
|
||||
let insideLarge = Math.round(80 / map.cellSize); // should be about the range of towers
|
||||
|
||||
for (let j = 0; j < territoryMap.length; ++j)
|
||||
{
|
||||
if (territoryMap.getOwnerIndex(j) !== PlayerID || borderMap.map[j] > 1)
|
||||
continue;
|
||||
let ix = j%width;
|
||||
let iz = Math.floor(j/width);
|
||||
for (let a of around)
|
||||
{
|
||||
let jx = ix + Math.round(insideSmall*a[0]);
|
||||
if (jx < 0 || jx >= width)
|
||||
continue;
|
||||
let jz = iz + Math.round(insideSmall*a[1]);
|
||||
if (jz < 0 || jz >= width)
|
||||
continue;
|
||||
if (borderMap.map[jx+width*jz] > 1)
|
||||
continue;
|
||||
let territoryOwner = territoryMap.getOwnerIndex(jx+width*jz);
|
||||
let safe = (alliedVictory && gameState.isPlayerAlly(territoryOwner)) || territoryOwner === PlayerID;
|
||||
if (!safe)
|
||||
{
|
||||
map.map[j] = 2;
|
||||
break;
|
||||
}
|
||||
jx = ix + Math.round(insideLarge*a[0]);
|
||||
if (jx < 0 || jx >= width)
|
||||
continue;
|
||||
jz = iz + Math.round(insideLarge*a[1]);
|
||||
if (jz < 0 || jz >= width)
|
||||
continue;
|
||||
if (borderMap.map[jx+width*jz] > 1)
|
||||
continue;
|
||||
territoryOwner = territoryMap.getOwnerIndex(jx+width*jz);
|
||||
safe = (alliedVictory && gameState.isPlayerAlly(territoryOwner)) || territoryOwner === PlayerID;
|
||||
if (!safe)
|
||||
map.map[j] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// m.debugMap(gameState, map);
|
||||
return map;
|
||||
};
|
||||
|
||||
m.debugMap = function(gameState, map)
|
||||
{
|
||||
let width = map.width;
|
||||
|
||||
@@ -238,7 +238,7 @@ m.ConstructionPlan.prototype.findGoodPosition = function(gameState)
|
||||
{
|
||||
let value = placement.map[j] - gameState.sharedScript.resourceMaps.wood.map[j]/3;
|
||||
placement.map[j] = value >= 0 ? value : 0;
|
||||
if (gameState.ai.HQ.borderMap.map[j] > 0)
|
||||
if (gameState.ai.HQ.borderMap.map[j] & m.fullBorder_Mask)
|
||||
placement.map[j] /= 2; // we need space around farmstead, so disfavor map border
|
||||
}
|
||||
}
|
||||
@@ -256,9 +256,9 @@ m.ConstructionPlan.prototype.findGoodPosition = function(gameState)
|
||||
{
|
||||
if (gameState.ai.HQ.basesMap.map[j] != base)
|
||||
placement.map[j] = 0;
|
||||
else if (favorBorder && gameState.ai.HQ.borderMap.map[j] > 0)
|
||||
else if (favorBorder && gameState.ai.HQ.borderMap.map[j] & m.border_Mask)
|
||||
placement.map[j] += 50;
|
||||
else if (disfavorBorder && gameState.ai.HQ.borderMap.map[j] === 0 && placement.map[j] > 0)
|
||||
else if (disfavorBorder && !(gameState.ai.HQ.borderMap.map[j] & m.fullBorder_Mask) && placement.map[j] > 0)
|
||||
placement.map[j] += 10;
|
||||
|
||||
if (placement.map[j] > 0)
|
||||
@@ -276,9 +276,9 @@ m.ConstructionPlan.prototype.findGoodPosition = function(gameState)
|
||||
{
|
||||
if (gameState.ai.HQ.basesMap.map[j] === 0)
|
||||
placement.map[j] = 0;
|
||||
else if (favorBorder && gameState.ai.HQ.borderMap.map[j] > 0)
|
||||
else if (favorBorder && gameState.ai.HQ.borderMap.map[j] & m.border_Mask)
|
||||
placement.map[j] += 50;
|
||||
else if (disfavorBorder && gameState.ai.HQ.borderMap.map[j] === 0 && placement.map[j] > 0)
|
||||
else if (disfavorBorder && !(gameState.ai.HQ.borderMap.map[j] & m.fullBorder_Mask) && placement.map[j] > 0)
|
||||
placement.map[j] += 10;
|
||||
|
||||
if (preferredBase && gameState.ai.HQ.basesMap.map[j] == this.metadata.preferredBase)
|
||||
@@ -435,7 +435,7 @@ m.ConstructionPlan.prototype.findDockPosition = function(gameState)
|
||||
dist += 0.6 * (maxRes - res);
|
||||
|
||||
// Add a penalty if on the map border as ship movement will be difficult
|
||||
if (gameState.ai.HQ.borderMap.map[j] > 0)
|
||||
if (gameState.ai.HQ.borderMap.map[j] & m.fullBorder_Mask)
|
||||
dist += 2;
|
||||
// do a pre-selection, supposing we will have the best possible water
|
||||
if (bestIdx !== undefined && dist > bestVal + maxWater)
|
||||
@@ -669,8 +669,10 @@ m.ConstructionPlan.prototype.isDockLocation = function(gameState, j, dimension,
|
||||
*/
|
||||
m.ConstructionPlan.prototype.getFrontierProximity = function(gameState, j)
|
||||
{
|
||||
let alliedVictory = gameState.getAlliedVictory();
|
||||
let territoryMap = gameState.ai.HQ.territoryMap;
|
||||
if (gameState.isPlayerAlly(territoryMap.getOwnerIndex(j)))
|
||||
let territoryOwner = territoryMap.getOwnerIndex(j);
|
||||
if (territoryOwner === PlayerID || alliedVictory && gameState.isPlayerAlly(territoryOwner))
|
||||
return 0;
|
||||
|
||||
let borderMap = gameState.ai.HQ.borderMap;
|
||||
@@ -689,9 +691,10 @@ m.ConstructionPlan.prototype.getFrontierProximity = function(gameState, j)
|
||||
let jz = iz + Math.round(i*step*a[1]);
|
||||
if (jz < 0 || jz >= width)
|
||||
continue;
|
||||
if (borderMap.map[jx+width*jz] > 1)
|
||||
if (borderMap.map[jx+width*jz] & m.outside_Mask)
|
||||
continue;
|
||||
if (gameState.isPlayerAlly(territoryMap.getOwnerIndex(jx+width*jz)))
|
||||
territoryOwner = territoryMap.getOwnerIndex(jx+width*jz);
|
||||
if (alliedVictory && gameState.isPlayerAlly(territoryOwner) || territoryOwner === PlayerID)
|
||||
{
|
||||
best = Math.min(best, i);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user