AI expansion behavior

Aradiel

Warlord
Joined
May 27, 2006
Messages
105
I have been testing some game strategys on different maps, and i came across for what i would call a strange behavior of the AI. As seen on the screenshots the Bannor AI does not seem to have an understanding of proper expansion. Instead of claiming the rich and vast territorys ahead he builds very unproductive settlements in his backyard.



The screenshots where taken on a huge world, bold continent on Prince difficulty.

I know the AI has not been tweaked yet, however i wonder if there might be something completly wrong with it ?
 
Often, in cases like that, the reason for the seemingly inexplicable choice of city location is an unrevealed resource. Have you tried using WB to see what resources are eventually going to show in that area?
 
Yes indeed theres a fish, although this would double the value of the spot its still very low compared to the sorrounding lands. So the ai only looks for special resources and does not care for the overall desirability at all ?
 
As best I can tell, the AI prefers to build close to home. My guess is that it sends out a wandering Settler using the automated scouting algorithms and as soon as it finds an acceptable site, it settles.
 
Yes indeed theres a fish, although this would double the value of the spot its still very low compared to the sorrounding lands. So the ai only looks for special resources and does not care for the overall desirability at all ?
It does. It just over-rates a city by the ocean, particularly the first one. Needless to say, were it on small islands, that's actually good behavior.

My opinion is that in general the AI (even in the Smarter Orcs mod) overrates the value of water tiles.
 
ive seen wierd ai behavior on arcapelgeo maps where the ai takes hundreds of turns to expand off their island and when they do they build it halfay across the globe not even caring about matinence. and its perfectly content to send out a undefended caravel out of its city dispite my kraken being only 2 spaces away
 
ive seen wierd ai behavior on arcapelgeo maps where the ai takes hundreds of turns to expand off their island and when they do they build it halfay across the globe not even caring about matinence. and its perfectly content to send out a undefended caravel out of its city dispite my kraken being only 2 spaces away

The Vanilla AI does not handle boats/ships well. Personally, I only play vanilla FfH II on maps where crossing water isn't essential (such as Pangea maps), so as not to give me yet another large advantage over the AI.
 
The two things I don't understand about the settlement-placement AI are its inordinate fondness for ports and the habit of trying to "settle someone in" at higher difficulty levels. The latter often leads to weird, curling border-extensions around other civilizations, which are themselves trying to work their way around someone else (often me). Often I'll see a great spot equally far from an AI's capital ignored or claimed later by someone else in favor of one near me.
 
The Vanilla AI does not handle boats/ships well. Personally, I only play vanilla FfH II on maps where crossing water isn't essential (such as Pangea maps), so as not to give me yet another large advantage over the AI.

Same as me. And 'does not handle boats well' is very kind what's more. :D
 
The two things I don't understand about the settlement-placement AI are its inordinate fondness for ports and the habit of trying to "settle someone in" at higher difficulty levels. The latter often leads to weird, curling border-extensions around other civilizations, which are themselves trying to work their way around someone else (often me). Often I'll see a great spot equally far from an AI's capital ignored or claimed later by someone else in favor of one near me.

Here's a summary of the algorithm, at least how it's typically used (I'm mostly ignoring a lot of the starting location code):

For the following purposes, all cities owned by a sprawling player are treated as sprawling:

If more than 1/3 of the tiles are owned by another team, ignore this plot.

Bad Tiles:
Each impassible plot (or non-plot, due to being off the edge of the map) is worth 1 bad tile.
each plot naturally granting 0 food or 1 or less items total (with and without any feature) is worth 1 bad tile.
water that's not coastal land with less than 2 food (with or without a feature) is worth 1/2 a bad tile.

If over a third of the potential city's tiles are "bad tiles", and there are not unowned bonuses that are either presently not tradeable, nor where the value of the bonus is greater than 10, ignore this plot.

Taken tiles:
Any tiles that don't exist, or are within a city radius are "taken". if over 1/3 of the city's tiles are taken, or over 1 are taken by a teammate, ignore this plot.

Health:
Health = the sum of health percent from all features. 1/10 of that is added to the value.

Value:
base 1000
For each tile in the potential city radius:
For each tile that grants at least 2 food,
add 20* the number of food + 80* the number of production + 40 * the number of commerce
For each tile that grants at least 1 food,
add 10* the number of food + 40* the number of production + 20 * the number of commerce
For each tile that grants 0 food,
add 10* the number of food + 20* the number of production + 10 * the number of commerce
each tile that has a river adds 10
The center tile's value is doubled; the tiles within 1 of the center are multiplied by 1.5
If this has a bonus, and there are no tradeable bonuses of that type, add 20 * the bonuses' value; otherwise, add 80 * its value (yes, this logic seems backwards)
If this is a bonus, add 10.
If this is a bonus in the water, add 300 (! this is probably the issue noted initially)
Coastal:
If the center plot is coastal, add 600. If this is not the starting location add another 200. If there are no cities in this area and this is not the starting location, add another 400.​

Hills:
If this center plot is a Hill, add 200​

River:
If this center plot is a river, add 60​

Fresh Water:
If this center plot has access to fresh water, add 40 + 20* the fresh water health change (2)​

Own City nearness:
If this player is the barbarians:
subtract the maximum of 0 or 8- the distance to the nearest city * 200
If this player if not the barbarians, and is sprawling,
subtract the distance -8 *500
If this player if not the barbarians, and is not sprawling,
subtract the distance -5 *500 (yep- this is the other issue mentioned above- the further away from an existing city, the more the plot is worth)​

Number of cities in an area:
If 0, double the value.
If all cities in this area are owned by this team,
multiply the value by 3/2
else If all cities in this area are owned by this team or the barbarian player,
multiply the value by 4/3
else If there's at least 1 city in this area owned by this team,
multiply the value by 5/4​

Bad Plots (again)
divide the value by the maximum of 0 or the number of bad tiles - 1/4 of the city tiles + 3 (warning! were there a city radius of 4, this could cause a divide by 0 error!)​

If there is no bonus in the central plot, subtract 300
return the value.

Source:
Spoiler :
Code:
int CvPlayerAI::AI_foundValue(int iX, int iY, int iMinRivalRange, bool bStartingLoc)
{
	PROFILE("CvPlayerAI::AI_foundValue()");

	CvCity* pNearestCity;
	CvArea* pArea;
	CvPlot* pPlot;
	CvPlot* pLoopPlot;
	FeatureTypes eFeature;
	BonusTypes eBonus;
	bool bHasGoodBonus;
	int iOwnedTiles;
	int iBadTile;
	int iTakenTiles;
	int iTeammateTakenTiles;
	int iDifferentAreaTile;
	int iTeamAreaCities;
	int iHealth;
	int iValue;
	int iTempValue;
	int iRange;
	int iDX, iDY;
	int iI;

/*FfH: Added by Chalid Sprawling 06/11/2006*/
    int iNumCityPlots = 21;
    int iSprawling = 0;
//FfH: End Add

	if (!canFound(iX, iY))
	{
		return 0;
	}

/*FfH: Added by Chalid Sprawling 06/11/2006*/
    if (this->isSprawling())
    {
            iNumCityPlots = 37;
            iSprawling = 1;
    }
//FfH: End Add

	pPlot = GC.getMapINLINE().plotINLINE(iX, iY);
	pArea = pPlot->area();

	if (iMinRivalRange != -1)
	{
		for (iDX = -(iMinRivalRange); iDX <= iMinRivalRange; iDX++)
		{
			for (iDY = -(iMinRivalRange); iDY <= iMinRivalRange; iDY++)
			{
				pLoopPlot	= plotXY(iX, iY, iDX, iDY);

				if (pLoopPlot != NULL)
				{
					if (pLoopPlot->plotCheck(PUF_isOtherTeam, getID()) != NULL)
					{
						return 0;
					}
				}
			}
		}
	}

	if (bStartingLoc)
	{
		if (pPlot->isGoody())
		{
			return 0;
		}
/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//		for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
//		{
//			pLoopPlot = plotCity(iX, iY, iI);
		for (iI = 0; iI < iNumCityPlots; iI++)
		{
			pLoopPlot = plotCity(iX, iY, iI, iSprawling);
//FfH: End Modify
			if (pLoopPlot == NULL)
			{
				return 0;
			}
		}
	}

	iOwnedTiles = 0;

/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//	for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
//	{
//		pLoopPlot = plotCity(iX, iY, iI);
    for (iI = 0; iI < iNumCityPlots; iI++)
    {
        pLoopPlot = plotCity(iX, iY, iI, iSprawling);
//FfH: End Modify
		if (pLoopPlot == NULL)
		{
			iOwnedTiles++;
		}
		else
		{
			if (pLoopPlot->isOwned())
			{
				if (pLoopPlot->getTeam() != getTeam())
				{
					iOwnedTiles++;
				}
			}
		}
	}

/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//	if (iOwnedTiles > (NUM_CITY_PLOTS / 3))
	if (iOwnedTiles > (iNumCityPlots / 3))
//FfH: End Modify
	{
		return 0;
	}

	iBadTile = 0;

/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//	for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
//	{
//		PROFILE("CvPlayerAI::AI_foundValue() 1");
//      pLoopPlot = plotCity(iX, iY, iI);
    for (iI = 0; iI < iNumCityPlots; iI++)
    {
        PROFILE("CvPlayerAI::AI_foundValue() 1");

        pLoopPlot = plotCity(iX, iY, iI, iSprawling);
//FfH: End Modify

		if ((pLoopPlot == NULL) || pLoopPlot->isImpassable())
		{
			iBadTile += 2;
		}
		else if (!(pLoopPlot->isFreshWater()) && !(pLoopPlot->isHills()))
		{
			if ((pLoopPlot->calculateBestNatureYield(YIELD_FOOD, getTeam()) == 0) || (pLoopPlot->calculateTotalBestNatureYield(getTeam()) <= 1))
			{
				iBadTile += 2;
			}

//FfH: Modified by Blake 09/28/2006
//			else if (pLoopPlot->isWater() && (pLoopPlot->calculateBestNatureYield(YIELD_FOOD, getTeam()) <= 1))
			else if (pLoopPlot->isWater() && !(pPlot->isCoastalLand()) && (pLoopPlot->calculateBestNatureYield(YIELD_FOOD, getTeam()) <= 1) )
//FfH: End Modify

			{
				iBadTile++;
			}
		}
	}

	iBadTile /= 2;

	if (!bStartingLoc)
	{
/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//		if (iBadTile > (NUM_CITY_PLOTS / 3))
		if (iBadTile > (iNumCityPlots / 3))
//FfH: End Modify
		{
			bHasGoodBonus = false;

/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//			for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
			for (iI = 0; iI < iNumCityPlots; iI++)
			{
//				pLoopPlot = plotCity(iX, iY, iI);
				pLoopPlot = plotCity(iX, iY, iI, iSprawling);
//FfH: End Modify

				if (pLoopPlot != NULL)
				{
					if (!(pLoopPlot->isOwned()))
					{
						if (pLoopPlot->isWater() || (pLoopPlot->area() == pArea))
						{
							eBonus = pLoopPlot->getBonusType(getTeam());

							if (eBonus != NO_BONUS)
							{
								if ((getNumTradeableBonuses(eBonus) == 0) || (AI_bonusVal(eBonus) > 10))
								{
									bHasGoodBonus = true;
									break;
								}
							}
						}
					}
				}
			}

			if (!bHasGoodBonus)
			{
				return 0;
			}
		}
	}

	iTakenTiles = 0;
	iTeammateTakenTiles = 0;
	iHealth = 0;
	iValue = 1000;

/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//	for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
//	{
//		PROFILE("CvPlayerAI::AI_foundValue() 2");
//      pLoopPlot = plotCity(iX, iY, iI);
    //For Settlements only consider the inner circle.
    //This is true independed of the fact if we actually use reduced city circles
    //As we want to settle really close to Boni.
    int iTempCityPlots = iNumCityPlots;
//Modified du to flexible Sprawling.
//    if (this->isSprawling() && this->getNumCities()>GC.getDefineINT("SPRAWLING_NUMBER_OF_CITIES"))
//    {
//        iTempCityPlots = 9;
//    }
    if (this->isSprawling())
    {
        int iSprCities=GC.getDefineINT("SPRAWLING_NUMBER_OF_CITIES");
        switch (GC.getMapINLINE().getWorldSize())
        {
            case WORLDSIZE_DUEL:
                iSprCities--;
                break;
            case WORLDSIZE_LARGE:
                iSprCities++;
                break;
            case WORLDSIZE_HUGE:
                iSprCities +=2;
                break;
            default:
                break;
        }
        if (this->getNumCities()>iSprCities)
        {
            iTempCityPlots = 9;
        }
    }

//End Modify flexible Sprawling

    for (iI = 0; iI < iTempCityPlots; iI++)
    {
        PROFILE("CvPlayerAI::AI_foundValue() 2");

        pLoopPlot = plotCity(iX, iY, iI, iSprawling);
//FfH: End Modify

		if (pLoopPlot == NULL)
		{
			iTakenTiles++;
		}
		else if (pLoopPlot->isCityRadius())
		{
			iTakenTiles++;

			if (pLoopPlot->isWithinTeamCityRadius(getTeam(), getID()))
			{
				iTeammateTakenTiles++;
			}
		}
		else
		{
			PROFILE("CvPlayerAI::AI_foundValue() 3");

			iTempValue = 0;

			if (pLoopPlot->getYield(YIELD_FOOD) >= GC.getFOOD_CONSUMPTION_PER_POPULATION())
			{
				iTempValue += (pLoopPlot->getYield(YIELD_FOOD) * 20);
				iTempValue += (pLoopPlot->getYield(YIELD_PRODUCTION) * 80);
				iTempValue += (pLoopPlot->getYield(YIELD_COMMERCE) * 40);

				if (bStartingLoc)
				{
					iTempValue *= 2;
				}
			}
			else if (pLoopPlot->getYield(YIELD_FOOD) == (GC.getFOOD_CONSUMPTION_PER_POPULATION() - 1))
			{
				iTempValue += (pLoopPlot->getYield(YIELD_FOOD) * 10);
				iTempValue += (pLoopPlot->getYield(YIELD_PRODUCTION) * 40);
				iTempValue += (pLoopPlot->getYield(YIELD_COMMERCE) * 20);
			}
			else
			{
				iTempValue += (pLoopPlot->getYield(YIELD_FOOD) * 10);
				iTempValue += (pLoopPlot->getYield(YIELD_PRODUCTION) * 20);
				iTempValue += (pLoopPlot->getYield(YIELD_COMMERCE) * 10);
			}

			if (pLoopPlot->isRiver())
			{
				iTempValue += 10;
			}

			if (iI == CITY_HOME_PLOT)
			{
				iTempValue *= 2;
			}
			else if (stepDistance(iX, iY, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) == 1)
			{
				iTempValue *= 3;
				iTempValue /= 2;
			}

			iValue += iTempValue;

			eFeature = pLoopPlot->getFeatureType();

			if (eFeature != NO_FEATURE)
			{
				iHealth += GC.getFeatureInfo(eFeature).getHealthPercent();
			}

			eBonus = pLoopPlot->getBonusType((bStartingLoc) ? NO_TEAM : getTeam());

			if (eBonus != NO_BONUS)
			{
				PROFILE("CvPlayerAI::AI_foundValue() 4");

				iValue += (AI_bonusVal(eBonus) * (((getNumTradeableBonuses(eBonus) == 0) && !bStartingLoc) ? 80 : 20));
				iValue += 10;

//FfH: Added by Blake 09/28/2006
				if (pLoopPlot->isWater())
				{
                	iValue += 300;
				}
//FfH: End Add

			}
		}
	}

/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//	if (iTakenTiles > (NUM_CITY_PLOTS / 3))
	if (iTakenTiles > (iNumCityPlots / 3))
//FfH: End Modify
	{
		return 0;
	}

	if (iTeammateTakenTiles > 1)
	{
		return 0;
	}

	iValue += (iHealth / 10);

	if (pPlot->isCoastalLand())
	{
		iValue += 600;

		if (!bStartingLoc)
		{
			if (pArea->getCitiesPerPlayer(getID()) == 0)
			{
				iValue += 400;
			}

			iValue += 200;
		}
	}

	if (pPlot->isHills())
	{
		iValue += 200;
	}

	if (pPlot->isRiver())
	{
		iValue += 60;
	}

	if (pPlot->isFreshWater())
	{
		iValue += 40;
		iValue += (GC.getDefineINT("FRESH_WATER_HEALTH_CHANGE") * 20);
	}

	if (bStartingLoc)
	{
		PROFILE("CvPlayerAI::AI_foundValue() 5");

		iRange = GREATER_FOUND_RANGE;

		for (iDX = -(iRange); iDX <= iRange; iDX++)
		{
			for (iDY = -(iRange); iDY <= iRange; iDY++)
			{
				pLoopPlot = plotXY(iX, iY, iDX, iDY);

				if (pLoopPlot != NULL)
				{
					if (pLoopPlot->isWater() || (pLoopPlot->area() == pArea))
					{
						if (plotDistance(iX, iY, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) <= iRange)
						{
							iValue += (pLoopPlot->getYield(YIELD_FOOD) * 10);
							iValue += (pLoopPlot->getYield(YIELD_PRODUCTION) * 10);
							iValue += (pLoopPlot->getYield(YIELD_COMMERCE) * 5);
						}
					}
				}
			}
		}
	}

	if (bStartingLoc)
	{
		if (pPlot->getMinOriginalStartDist() == -1)
		{
			iValue += (GC.getMapINLINE().maxStepDistance() * 100);
		}
		else
		{
			iValue += (pPlot->getMinOriginalStartDist() * 100);
		}
	}

	pNearestCity = GC.getMapINLINE().findCity(iX, iY, ((isBarbarian()) ? NO_PLAYER : getID()));

	if (pNearestCity != NULL)
	{
		if (isBarbarian())
		{
			iValue -= (max(0, (8 - plotDistance(iX, iY, pNearestCity->getX_INLINE(), pNearestCity->getY_INLINE()))) * 200);
		}
		else
		{
/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//			iValue -= (abs(plotDistance(iX, iY, pNearestCity->getX_INLINE(), pNearestCity->getY_INLINE()) - 5) * 500);
			if (this->isSprawling())
            {
                iValue -= (abs(plotDistance(iX, iY, pNearestCity->getX_INLINE(), pNearestCity->getY_INLINE()) - 8) * 500);
			}
			else
			{
			    iValue -= (abs(plotDistance(iX, iY, pNearestCity->getX_INLINE(), pNearestCity->getY_INLINE()) - 5) * 500);
			}
//FfH: End Modify
		}
	}

	if (pArea->getNumCities() == 0)
	{
		iValue *= 2;
	}
	else
	{
		iTeamAreaCities = GET_TEAM(getTeam()).countNumCitiesByArea(pArea);

		if (pArea->getNumCities() == iTeamAreaCities)
		{
			iValue *= 3;
			iValue /= 2;
		}
		else if (pArea->getNumCities() == (iTeamAreaCities + GET_TEAM(BARBARIAN_TEAM).countNumCitiesByArea(pArea)))
		{
			iValue *= 4;
			iValue /= 3;
		}
		else if (iTeamAreaCities > 0)
		{
			iValue *= 5;
			iValue /= 4;
		}
	}

/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//	iValue /= (max(0, (iBadTile - (NUM_CITY_PLOTS / 4))) + 3);
	iValue /= (max(0, (iBadTile - (iNumCityPlots / 4))) + 3);
//FfH: End Modify

	if (pPlot->getBonusType() != NO_BONUS)
	{

//FfH: Modified by Blake 09/28/2006
//		iValue /= 4;

		iValue -= 300;
//FfH: End Modify

	}

	if (bStartingLoc)
	{
		iDifferentAreaTile = 0;

/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//		for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
		for (iI = 0; iI < iNumCityPlots; iI++)
//FfH: End Modify
		{

//FfH: Modified by Kael 03/07/2007
//			pLoopPlot = plotCity(iX, iY, iI);
			pLoopPlot = plotCity(iX, iY, iI, 0);
//FfH: End Modify

			if ((pLoopPlot == NULL) || (pLoopPlot->area() != pArea))
			{
				iDifferentAreaTile++;
			}
		}

/*FfH: Modified by Chalid Sprawling 06/11/2006*/
//		iValue /= (max(0, (iDifferentAreaTile - ((NUM_CITY_PLOTS * 2) / 3))) + 2);
		iValue /= (max(0, (iDifferentAreaTile - ((iNumCityPlots * 2) / 3))) + 2);
//FfH: End Modify
	}

	return max(1, iValue);
}
 
Here's a summary of the algorithm, at least how it's typically used (I'm mostly ignoring a lot of the starting location code):

That certainly does a lot to clarify things. By this, it looks like a river-bordered hill with access to the coast and lots of floodplains is the AI's ideal city location.

I'm pretty sure this:

Coastal:

If the center plot is coastal, add 600. If this is not the starting location add another 200. If there are no cities in this area and this is not the starting location, add another 400.

Has as much to do with the "it must be a port!" issue as the line you pointed out.

What's interesting is that if this is the code used to determine what improvements are built, it also goes a long way towards explaining the windmill phenomenon (AKA the "The AI hates mines" phenomenon), since the addition of food production to any plot is always rated as more-desirable for a tile since it vaults it into a higher multiplier bracket. A windmill added to a grassland hill takes it from 1f, 1p (value 50) to 2f, 2p (value 200!) which beats the heck out of 1f, 3p (value 130) from a mine - and this leaves out the improvement-enhancement technologies' impact. Only Arete + Blasting Powder mines would be considered better than windmills for grassland hills.

I don't know about anyone else, but that seems a little skewed to me - again, if that same value calculus is used for building improvements.

The Own City Nearness calculations don't make a great deal of sense to me the way you wrote them out. Are those "subtract 8 from the distance" for sprawling civs and "subtract 5 from the distance" for everyone else?

I'm guessing (since some AI's in both Vanilla and FFH do not merely work their asses off to improve food production) that the AI behavior weighting affects what improvements a particular AI builds. Heck, I'm certain that other people have already caught onto this and done something about it. It's just interesting to me to see the numbers.
 
Here's a summary of the algorithm, at least how it's typically used (I'm mostly ignoring a lot of the starting location code):

Excellent post, it really explains why it always wants to build on the shore :lol: Now i wonder what would happen if the value of a good tile is raised like woods and plains. Also a having a river close by should be essential as the ai certainly has no idea how to spread water via farms.
 
If I were trying to make the AI play more like me (and assuming - which isn't safe - that this is the system it uses to pick improvements too), the solution would be to lower the value for settling on the coast substantially, increase the value of production on tiles with 0 or 1 food, and rate commerce a lot higher on 2+ food tiles. Certainly lowering the value of a coastal city might produce better results in terms of settlement choice.

It occurs to me, though, that if this were the only way the computer assigned tile values and picked improvements, you'd expect to see an awful lot more watermills, since the production and commerce bonuses are rated higher than food once you hit 2. There's probably more to it than just that.
 
It occurs to me, though, that if this were the only way the computer assigned tile values and picked improvements, you'd expect to see an awful lot more watermills, since the production and commerce bonuses are rated higher than food once you hit 2. There's probably more to it than just that.

The logic I refer to above is a central function for determining where to settle (not where or how to work tiles). The later is through two functions, CvCityAI::AI_bestPlotBuild (which determines what to build) and CvCityAI::AI_updateBestBuild (which determines the priorities and where to build them).
 
It may look strange but it really seems that Bannor has problems with expansion in certain games, not due to city placement though, and only Bannor.
 
It may look strange but it really seems that Bannor has problems with expansion in certain games, not due to city placement though, and only Bannor.

Yes Bannor always suck at expansion, i have been watching this in 3 different games, 2 on prince and 1 on monarch. Everytime they fall behind with expansion, and get sorrounded. Neverthenless any ai makes constant failures in settlement, as they overrate seaacess and bonusgoods.
 
Back
Top Bottom