ls612's C2C AI thread

Is there a way to make Automated workers collaborate more?

After a certain point, when my empire's large enough, micromanaging improvements becomes too cumbersome to my tastes. So I tend to build a large amount of workers, spread them around and automate them. The problem is that the majority of the workers tend to pile up in a city while just a few tend to the improvements in single unit stacks, so building improvements costs quite a bit more time and money, unless you relent and micromanage. This behavior is especially apparent when a city gains access to a new tile(s).

It's not a huge deal, but better worker AI would be something "nice to have" :)

Indeed. Currently workers look for something that needs doing individually. They will gang up and work a newly discovered resource but they don''t look around and see another worker who they can help.
 
@Koshling:

Looking through the CvUnitAI, I saw that in the function DefendPlot() that there was absolutely no mention of terrain damage, meaning that the AI might order that plot to be defended for an indefinite amount of time, taking terrain damage out the nose! I added the following routine to that function

PHP:
	bool	bHasTerrainDamage = (plot()->getTerrainTurnDamage(this) > 0 ||
									(plot()->getFeatureType() != NO_FEATURE && GC.getFeatureInfo(plot()->getFeatureType()).getTurnDamage() > 0));	

    pCity = pPlot->getPlotCity();

	if (bHasTerrainDamage && !pPlot->isRoute() && pCity == NULL) 
	{
		return false;
	}

Will that do more good than harm? I wanted to add a check to see if the unit could ignore terrain damage, but couldn't figure out how, if you could tell me I'll add that as well.
 
You'd also want your adjustment to make sure the Terrain Damage option is on before it takes effect.

You could probably find a good example of determining if the unit has immunity by looking into the portion of the coding where it assigns the actual damage.

I'm still setting myself up on the new computer here so I can't help much more than that at the moment.
 
I noticed in v25 that ai build a lot of wter units even when water area is very small and have no contact with open ocean. Ex in sea area 10x4 squares i saw above 20 water units that only stay in place cause it area have no contact with ocen. Can you teach ai to not built water units when the water area is small and closed?
 
@Koshling:

Looking through the CvUnitAI, I saw that in the function DefendPlot() that there was absolutely no mention of terrain damage, meaning that the AI might order that plot to be defended for an indefinite amount of time, taking terrain damage out the nose! I added the following routine to that function

PHP:
	bool	bHasTerrainDamage = (plot()->getTerrainTurnDamage(this) > 0 ||
									(plot()->getFeatureType() != NO_FEATURE && GC.getFeatureInfo(plot()->getFeatureType()).getTurnDamage() > 0));	

    pCity = pPlot->getPlotCity();

	if (bHasTerrainDamage && !pPlot->isRoute() && pCity == NULL) 
	{
		return false;
	}

Will that do more good than harm? I wanted to add a check to see if the unit could ignore terrain damage, but couldn't figure out how, if you could tell me I'll add that as well.

You are already checking that the unit is not immune to the terrain damage by the call to getTerrainTurnDamage() passing 'this'. HOWEVER, that probably isn't the appropriate check because it only checks the head unit of the stack is immune, so it could still lead a large stack (the rest of which was not immune) to its death. Use getTerrainTurnDamage(getGroup()) instead (see AI_safety() for an example).

Also note that the routine here is not very widely used (indeed hardly ever), so changing here will have a very marginal effect. Most moves are based on searches for target tiles in the AI routine concerned (see for example AI_explore()), and it's the value assignment of tiles in those loops that really need the terrain-damage checks (as well as this routine). I already added this to most of the explore and hunt routines a few weeks ago, but most other routines lack it. Theer are probably two dozen or so such tile search loops scattered thoughout the UnitAI code.
 
You are already checking that the unit is not immune to the terrain damage by the call to getTerrainTurnDamage() passing 'this'. HOWEVER, that probably isn't the appropriate check because it only checks the head unit of the stack is immune, so it could still lead a large stack (the rest of which was not immune) to its death. Use getTerrainTurnDamage(getGroup()) instead (see AI_safety() for an example).

Also note that the routine here is not very widely used (indeed hardly ever), so changing here will have a very marginal effect. Most moves are based on searches for target tiles in the AI routine concerned (see for example AI_explore()), and it's the value assignment of tiles in those loops that really need the terrain-damage checks (as well as this routine). I already added this to most of the explore and hunt routines a few weeks ago, but most other routines lack it. Theer are probably two dozen or so such tile search loops scattered thoughout the UnitAI code.

OK, Thanks. I added that code for defending plots to the SVN, and I also found another place where that code would be useful. There is a function, CvUnitAI::AI_choke(), which gets the best plot for a stack to go to in enemy territory to hunker down, and it has no mention of terrain damage. That function is called many times in various AI movement routines, so I added the following code to it.
PHP:
						bool	bHasTerrainDamage = (plot()->getTerrainTurnDamage(getGroup()) > 0 ||
									(plot()->getFeatureType() != NO_FEATURE && GC.getFeatureInfo(plot()->getFeatureType()).getTurnDamage() > 0));	

						if(bHasTerrainDamage)
						{
							iValue = 0
						}

To stop the AI from making a damaging terrain plot as it's defensive position.

Also, what function determines the path that an AI SoD uses to get from it's staging area to it's target city?
 
OK, Thanks. I added that code for defending plots to the SVN, and I also found another place where that code would be useful. There is a function, CvUnitAI::AI_choke(), which gets the best plot for a stack to go to in enemy territory to hunker down, and it has no mention of terrain damage. That function is called many times in various AI movement routines, so I added the following code to it.
PHP:
						bool	bHasTerrainDamage = (plot()->getTerrainTurnDamage(getGroup()) > 0 ||
									(plot()->getFeatureType() != NO_FEATURE && GC.getFeatureInfo(plot()->getFeatureType()).getTurnDamage() > 0));	

						if(bHasTerrainDamage)
						{
							iValue = 0
						}

To stop the AI from making a damaging terrain plot as it's defensive position.

Also, what function determines the path that an AI SoD uses to get from it's staging area to it's target city?

Depending on exactly what aspect of it you're interested in, one of:
  • AI_attackCityMove - overall control routine for that AI type
  • AI_pickTargetCity - pick the city it wants to attack
  • AI_moveToStagingCity - move to gathering point
  • AI_goToTargetCity - final move to attack
 
@Koshling:

Regarding the issue Cyrusfan posted about a Tracker suiciding itself on a neander, I was looking through the code and found that this line in CvUnitAI::AI_Explore
PHP:
					if (!pLoopPlot->isVisible(getTeam(),false) || !(pLoopPlot->isVisibleEnemyUnit(this))

is the gateway to the whole routine that assigns which plot has the bestvalue for the exploration. Should it not be an AND condition instead of an OR condition? Otherwise of the first condition is fulfilled (ie, the plot is visible), the AI will totally ignore the presense or not of enemy units, if I understand this correctly.
 
if (!pLoopPlot->isVisible(getTeam(),false) || !(pLoopPlot->isVisibleEnemyUnit(this))

states: if the plot is not visible or the plot does not have a visible enemy unit.

Just pointing out that ! before any boolean statement, no matter how tied to other functions that statement may be, will always be a not indicator. So if the first condition is fulfilled, it means the plot is unseen entirely and thus wouldn't be evaluatable by any kind of security concern anyhow. The second seems to want to make sure they aren't attacking... ever. So now that you've pointed this out... its strange that such a unit is attacking at all. Now are we talking about Hunting or Scouting here?
 
if (!pLoopPlot->isVisible(getTeam(),false) || !(pLoopPlot->isVisibleEnemyUnit(this))

states: if the plot is not visible or the plot does not have a visible enemy unit.

Just pointing out that ! before any boolean statement, no matter how tied to other functions that statement may be, will always be a not indicator. So if the first condition is fulfilled, it means the plot is unseen entirely and thus wouldn't be evaluatable by any kind of security concern anyhow. The second seems to want to make sure they aren't attacking... ever. So now that you've pointed this out... its strange that such a unit is attacking at all. Now are we talking about Hunting or Scouting here?

Oh, I totally misread that. Yes we are talking about hunters, and specifically why they are suiciding against Neanderthals on Goody Huts.
 
I have absolutely no idea what was causing the abnormal behavior of the AI hunters in Cyrusfan's game, but I have added a change to the SVN that will prevent the AI from even considering a plot with enemy defenders on it in it's valuations. This should hopefully fix that issue.
 
I was going to say though... there is an option in the bug menus that allows the player to set the minimum combat odds acceptable if the unit is considering an attack when automated to hunt. If you've made it so that hunters won't ever evaluate an attack, you've disabled automated hunting entirely.

Most likely, he had his set to the default value there, which is something ridiculously low, like 40% or something like that. His tracker may have just barely qualified to consider it a winnable fight, most likely due to its high level and promotions.
 
I was going to say though... there is an option in the bug menus that allows the player to set the minimum combat odds acceptable if the unit is considering an attack when automated to hunt. If you've made it so that hunters won't ever evaluate an attack, you've disabled automated hunting entirely.

Most likely, he had his set to the default value there, which is something ridiculously low, like 40% or something like that. His tracker may have just barely qualified to consider it a winnable fight, most likely due to its high level and promotions.

I shouldn't have, this was in the AI_Explore function. I think (Koshling can correct me if I'm wrong) that CvUnitAI::AI_HuntingTarget (can't remember the exact name) controls hunting. If I did break hunting I can revert it tomorrow.
 
Ok... sounds like you should be fine then. Actually not a bad idea to have explorers AVOID battle... that seems to be their function is to see as much as possible without dying first.

Then again... that original line you posted above seems to be accomplishing that... though... hmm... if the unit is somehow moving into an unseen territory and incidentally finds an enemy unit there... if a human player does this it will stop the move and give you the choice to attack or otherwise - but I'm not sure if automated moves or ai moves would have the same luxury without reviewing the code. Usually, however, whatever the player experiences, the ai's experience as well (in a manner of speaking) by default of the same coding.
 
Ok... sounds like you should be fine then. Actually not a bad idea to have explorers AVOID battle... that seems to be their function is to see as much as possible without dying first.

Then again... that original line you posted above seems to be accomplishing that... though... hmm... if the unit is somehow moving into an unseen territory and incidentally finds an enemy unit there... if a human player does this it will stop the move and give you the choice to attack or otherwise - but I'm not sure if automated moves or ai moves would have the same luxury without reviewing the code. Usually, however, whatever the player experiences, the ai's experience as well (in a manner of speaking) by default of the same coding.

The original was correct. It is cheating for the AI to evaluate presence (or otherwise) of a unit on a tile that is not visible to it! The visibility tests are thereof to stop the AI being omniscient.

As to why the Neanderthal got attacked on the hut, I'll look into it when I get time (work is insanely busy right now). I don't suppose Cyrus posted an autosave so we could reproduce it? That would make diagnosis totally trivial.
 
The original was correct. It is cheating for the AI to evaluate presence (or otherwise) of a unit on a tile that is not visible to it! The visibility tests are thereof to stop the AI being omniscient.

As to why the Neanderthal got attacked on the hut, I'll look into it when I get time (work is insanely busy right now). I don't suppose Cyrus posted an autosave so we could reproduce it? That would make diagnosis totally trivial.

That wasn't the line I ended up changing. I added a check for isVisibleEnemyDefender earlier in the routine (you can check the SVN logs to see exactly where), so it shouldn't be a cheat.
 
The original was correct. It is cheating for the AI to evaluate presence (or otherwise) of a unit on a tile that is not visible to it! The visibility tests are thereof to stop the AI being omniscient.

As to why the Neanderthal got attacked on the hut, I'll look into it when I get time (work is insanely busy right now). I don't suppose Cyrus posted an autosave so we could reproduce it? That would make diagnosis totally trivial.

Comment 353 of the v25 bug thread. Just to confirm, I had the automate hunt minimum set to 95% generally and tried at 100% before posting the save. I've noticed a pretty high mortality rate for the hidden nationality/camo units under the automate hunt command, as well, but don't have a save for them at the moment. I do kinda want hunters to explore goody huts, since I use them rather than scouts to uncover the map.

Edit: Current SVN seems to have fixed the issue in the save. I don't have an easy way to check, but I'm guessing the part of the automation that looks for targets to attack will in effect grab those goody huts once the neanderthals are beatable per the minimum combats odds restriction?
 
That wasn't the line I ended up changing. I added a check for isVisibleEnemyDefender earlier in the routine (you can check the SVN logs to see exactly where), so it shouldn't be a cheat.

As far as I can tell your change should ghave no effect, since that routine already had this line in the same loop that would also pevent the plot in question being considered:

Code:
if (!pLoopPlot->isVisible(getTeam(),false) || !(pLoopPlot->isVisibleEnemyUnit(this)))

Did you step through the code in the debugger to verify what was happening in the save game?

Edit: Current SVN seems to have fixed the issue in the save. I don't have an easy way to check, but I'm guessing the part of the automation that looks for targets to attack will in effect grab those goody huts once the neanderthals are beatable per the minimum combats odds restriction?

Interesting that it appears to change the behaviour - if I acn find time I'll step through and try to figure out why.

Regarding the odds you set in the option - it isn't very religiously used by the code, and in particular much of the explore code currently uses a fixed 60%. However, since it no longer uses pure odds to make the decision anyway it's slightly moot - the 60% (even though that number no longer represents pure odds since its weighted by expected gain on win) should probably be overridden by the option setting.
 
As far as I can tell your change should ghave no effect, since that routine already had this line in the same loop that would also pevent the plot in question being considered:

Code:
if (!pLoopPlot->isVisible(getTeam(),false) || !(pLoopPlot->isVisibleEnemyUnit(this)))

Did you step through the code in the debugger to verify what was happening in the save game?



Interesting that it appears to change the behaviour - if I acn find time I'll step through and try to figure out why.

Regarding the odds you set in the option - it isn't very religiously used by the code, and in particular much of the explore code currently uses a fixed 60%. However, since it no longer uses pure odds to make the decision anyway it's slightly moot - the 60% (even though that number no longer represents pure odds since its weighted by expected gain on win) should probably be overridden by the option setting.

No, I made the debugging equivalent of an educated guess, but it seems to have fixed things for Cyrus, so I'll call it a success, even if I can't explain why.
 
No, I made the debugging equivalent of an educated guess, but it seems to have fixed things for Cyrus, so I'll call it a success, even if I can't explain why.

Fortunately I have just stepped through in his save and it wasn't even that routine that was attacking! It was AI_goodie(), and the reason was a bug in the oddds calculation that caused it to think it had 99% success chances!

I'll push the fix later along with other changes for maintenance etc.

I strongly recommedn ALWAYS stepping through fixes in the debugger when you have a repeatable test case (like the save here) to vaildate that what is going on is what you thought, otherwise thinsg like different random number generation can lead to observed effects that are not for the reason you think they are.
 
Back
Top Bottom