more dune wars related ai questions

davidlallen

Deity
Joined
Apr 28, 2008
Messages
4,743
Location
California
1. I have created a new worker unitclass with a few special features. It is cheaper than a regular worker, has +50% work rate, can only build one particular important improvement, and requires a certain civic to build (implemented with python cannotTrain). Overall it seems like a good value to me. But, the AI never builds it. Does the city AI look for multiple worker unitclasses and make some decision? Or does it always go with the worker unitclass? If there is a weight decision, I can push the cost or rate up till it starts winning, but if not, I guess I need a pointer to how I can add this.

2. Does anybody really understand AI_foundValue? I have written a new weighting function which seems to give good results for initial city site selection in a mapscript. It is highly customized and hardcoded for the mod. See this post for details. (The thread may be interesting to others considering modifications to AI_foundValue.) I hope to completely replace the existing AI_foundValue with this function, but I have failed several times to understand the existing function. In particular, I am confused about how it handles two good sites which are right next to each other. It seems that there should be some way to make sure to pick the best local site, and then discard the nearby losers. But, I cannot quite locate / understand how this is handled in AI_foundValue today. Can anybody give me a pointer?
 
Bump. Question #2 appears to be the worst problem in DW today. The DW map is so different from vanilla, that AI city placement is totally lame. Can anybody help?
 
Another interesting question is "will they use it semi-correctly if they built it?" (you can test this by granting it to the civilisation) If that works, you could end-run around it by some kind of "these workers pop into existence when you switch to the civic, and disappear when you leave the civic" thing. :)

I started reading up on AI_foundValue, but didn't get deep enough. I did find some code that tries to prune adjacent squares that have less, but similar, found values. (I ended up lost in several levels of cache -- plots cache the found values for each civilisation, areas cache the best found value per civilisation, etc -- but didn't get to the spot where the found values where calculated in the time I was reading it over). Have you learned anything in your investigations?
 
Here is a new question, #3 in this thread. In Dune Wars, which has generally poor tile yield (it is a desert after all) we find that when any civic has "hurry population" (whip), then all the AI's switch to that civic and whip their population down to almost nothing. Using the handy AI logging functions in BBAI 0.82 (thanks, that is *extremely* helpful!) I have found the code responsible, but I do not understand why the AI is making this decision.

The logfile shows:

[101675.094] City New Vernii hurry pop at 1 for growth with bad tiles with pop 8

This occurs in CvCityAI::AI_doHurry. My line numbers are probably different, but you can search the message. The key test is:

if (AI_countGoodTiles((healthRate(0) == 0), false, 100) <= (getPopulation() - iHurryPopulation))

AI_countGoodTiles counts the number of tiles in the BFC for which AI_getPlotMagicValue returns greater than the threshold, 100 in this case. And that function has a handy comment which says:

//Above 100 means it's definitely decent - seriously question ever not working it.

That function will return above 100 if (simplifying slightly) food yield + 1/2 hammer yield + 1/2 commerce yield is greater than 3. So even a base grassland tile fails by this definition.

Translating the key test into pseudocode, the test is, "Hurry if the remaining population is still enough to work all the definitely decent tiles". In other words, if you have any population which would be working marginal tiles, then sacrifice them.

Even in vanilla, this seems a little severe. It happens very often in DW that you have 3-4 good food production tiles, each producing 3-4 food, and the rest of the tiles in the BFC produce zero food. The production of the good tiles gets better as you increase tech, so city sizes can still be reasonable in the late game. So, your 3-4 tiles produce enough food for 4-8 population, and the above logic appears to want to whip it down to 3-4 population.

Have I missed something in understanding this part of the AI? Any suggestions on how to adapt it for a small number of high yield tiles?
 
I started reading up on AI_foundValue, but didn't get deep enough ... Have you learned anything in your investigations?

I have tried a few more times but not much luck. The found values are stored in a cache on the plot, and they are reset at the start of every turn. If any found value is requested for a civ, then the map is recomputed for that civ. This all seems reasonably OK.

The part which is still defeating me is related to CvPlayer::AI_getCitySite(). This stores a list of potential city sites, and it is persistent from turn to turn. At the start of foundValue, these plots are treated similarly to existing city plots, meaning that terrain and resources in the BFC of these plots are devalued since they are already in use to the civ. Then presumably after computing the foundvalues, the list of city sites must be refreshed in case some new site is better than one of the previously chosen sites. But I have not yet succeeded in tracing out all this logic.

So, I am still stuck. The problem is in understanding how existing potential city sites get updated. Can anybody shed some light on this?
 
Here is question #4 on this thread. With jdog's help in the all terrain settlers thread, I have gotten settlers to travel from one island to another. This has helped the Fremen through their initial expansion. Next, I am trying to get all terrain combat units to attack foes on water. I have set up a vanilla testcase based on 0.82 but again I am unable to find the right places in the AI to change.

Please follow these steps to see my problem.

1. Build BBAI 0.82 with the CvGameCoreUtils.cpp in the attachment; it has the one line change from this post. The remaining all-terrain changes are already in 0.82.

2. Make a blank mod using the attached CIV4UnitInfos.xml, same as in the all-terrain settlers thread. All of the early units, including settlers, workers and combat units, have bCanMoveAllTerrain set. All naval units are modified to be land units with land unitai's, so there are no pure water units.

3. Load the attached save game, which is a tiny, high water level, archipelago map with autoplay for 155 turns. There is nothing magic about this game, you can make your own. Observe that the settlers have walked on water to start colonies on other islands.

4. Declare war on Willam.

5. Using WB, place two workers on the map adjacent to Willam's cities. Place one on land, and one on water.

6. Advance one turn.

Notice that Willam captures the worker on land, but ignores the worker on water. The units in the city are capable of walking on water to capture the worker. But somehow they fail to realize it. You can check this by using WB to place two of Willam's workers adjacent to your cities; you can capture the one on water fine.

Any help in figuring out where there are more incorrect calls to "area == getarea()" or similar will be appreciated.
 

Attachments

I've been pretty busy in RL and must have missed this thread ... I'll try to catch up on what I can answer.

1. The decision flow goes to CvCityAI::AI_bestUnitAI and then to CvPlayerAI::AI_unitValue. In this second function, workers are valued at 50 * (how many builds they can build) + a speed term, so a specialist worker unit would always be lower value and probably never considered.

If the AI uses the unit properly when you give it to them, then the solution would be to find another way to get these units built. If the AI doesn't use them well, then you might want to create a UNITAI_WORKER_SPICE or something.

One simple solution would be to add something to the AI weight for the unit in XML equal to something like (3/4)*50*(# of build types - 1), as the AI will probabilistically build units that have at least 2/3 of the best valuation. Alternatively, you could add something to the UNITAI_WORKER value section of CvPlayerAI::AI_unitValue to up the value of these units to balance things out. The best way I think for such a specialized worker would be to create a new UNITAI type and add some custom code in CvCityAI::AI_chooseProduction for when to build it.


2. I've been meaning to expose more useful information when mousing around in debug mode ... the correlation between plot value and city sites is definitely a bit confusing because of the difficulty of seeing the underlying info.

I'll plan to check out the city site selection code after 0.83 is out, let me know if you figure anything out!


3. Yeah, the AI is definitely a little whip happy even in plain BTS. I think the 100 value is a little bit too high, but my approach has been to try to get more workers going so plot magic values (what an awesome name ...) are higher. It's worth noting that this whipping is intended to help with the "growth" of the city long term, although what is defined as growth is pretty liberal.

If 4 tiles around a city are really good and a city is at pop say 7, are those extra 3 citizens providing something of value at the moment?


4. I think this should be handled in CvUnitAI::AI_anyAttack, but I can't see what would be going wrong ... there are no area checks in that function. Hmmm ...
 
1. The decision flow goes to CvCityAI::AI_bestUnitAI and then to CvPlayerAI::AI_unitValue. In this second function, workers are valued at 50 * (how many builds they can build) + a speed term, so a specialist worker unit would always be lower value and probably never considered.

Thanks for the pointer. I will look into that function and tweak the unit so it gets considered.

2. ... I'll plan to check out the city site selection code after 0.83 is out, let me know if you figure anything out!

I will just have to dive in at some point and just do it, probably just before Christmas.

3. ... If 4 tiles around a city are really good and a city is at pop say 7, are those extra 3 citizens providing something of value at the moment?

Well, specialists, for one thing. Or working cottages, which will develop into more over time. I'll try commenting out this whole test from the function and see how much whipping remains. As long as the AI stops over-using it, then at least it is available for the human player.

4. I think this should be handled in CvUnitAI::AI_anyAttack, but I can't see what would be going wrong ... there are no area checks in that function. Hmmm ...

Any further leads on this would be really helpful.
 
Question #4 is still open regarding all-terrain units failing to attack units on ocean.

Here is question 5. In Dune Wars, we have noticed a problem with UNITAI_ASSAULT_SEA. On an assault, all-terrain transports (which have a low combat strength) take their full load of units onto land adjacent to the enemy city and then end their turn, with their troops still loaded. These transports are sitting ducks for the city defender, so they usually get destroyed, losing all the loaded troops. A human player bringing the transports up will unload the transport at the end of the turn so that the loaded troops can defend themselves; they obviously have a higher strength than the transports. The AI is therefore playing poorly compared to a human. This is the second biggest problem for the Dune Wars AI. (The first biggest being poor city placement, question #2 in this thread.)

I have looked into CvUnitAI::AI_assaultSeaMove(), and I see that cephalo has locally modified this function for DW. But, I am not really able to understand it well enough to modify it. See this thread for discussion of the changes cephalo made. I have attached the locally modified CvUnitAI.cpp file for reference.

Can anybody suggest how to modify this function so that transports will unload sooner?
 

Attachments

The most logical way to do this would be to make a rule change, where when a transport is over land, units inside it may defend. This makes sense, as requiring the player to manually unload really only adds to micromanagement and tedium; there is no reason not to unload, so it might as well be done automatically, at least functionally.
 
Apart from what the AI does, getting the right rules for all-terrain transport is a little tricky. I have changed a number of the CvUnit::canXXX checks to prevent many actions for a unit which is cargo; for example, a spy in an all-terrain transport on land used to be able to perform a spy action from inside the transport. In particular, I have disallowed loading and unloading on the same turn. Otherwise, you can sit off a distance in a transport, zoom up, unload, have the troops pillage, reload, and zoom out of range again. Also it seems that you should be able to surprise a transport on land and kill the troops; they should be as vulnerable as a transport on water.

So, I don't think unloading and loading every turn is the right solution. Unloading when you reach the destination seems better. If anybody can suggest the needed AI change, or help me understand the function better, that would be great.
 
Question #4 is still open regarding all-terrain units failing to attack units on ocean.

Here is question 5. In Dune Wars, we have noticed a problem with UNITAI_ASSAULT_SEA. On an assault, all-terrain transports (which have a low combat strength) take their full load of units onto land adjacent to the enemy city and then end their turn, with their troops still loaded. These transports are sitting ducks for the city defender, so they usually get destroyed, losing all the loaded troops. A human player bringing the transports up will unload the transport at the end of the turn so that the loaded troops can defend themselves; they obviously have a higher strength than the transports. The AI is therefore playing poorly compared to a human. This is the second biggest problem for the Dune Wars AI. (The first biggest being poor city placement, question #2 in this thread.)

I have looked into CvUnitAI::AI_assaultSeaMove(), and I see that cephalo has locally modified this function for DW. But, I am not really able to understand it well enough to modify it. See this thread for discussion of the changes cephalo made. I have attached the locally modified CvUnitAI.cpp file for reference.

Can anybody suggest how to modify this function so that transports will unload sooner?

I figured this might be a problem someday. I suggest that the transports should keep the target city and head in that direction. But, as soon as they are on land, on the same continent as their target, in enemy territory, they should unload.
 
As for question number 4, I'm a bit rusty, but I think I remember we changed ocean to be AREAAI_OFFENSIVE so that fremen will attack across the ocean. Since in the normal game ships can be on land(in ports) and sea, it may use the AREAAI_NEUTRAL to determine if it should make a naval attack. ( I hope I spelled that right... we don't want to see any navel attacks in DW right? nyuk nyuk)
 
I figured this might be a problem someday. I suggest that the transports should keep the target city and head in that direction. But, as soon as they are on land, on the same continent as their target, in enemy territory, they should unload.

That is a helpful suggestion. One problem may be, sometimes the AI chooses to attack a city which is deep inland. (Not that you can get "too" deep on DW archipelago style maps, but anyway several moves away from coast.) If there is no threat, it will be faster to continue using the transports.

Do you know if the ground units are unloaded some distance away from the city, will they forget their objective? You had mentioned that when units change domain, they may forget.

If you have a chance, can you look into AI_assaultSeaMove and suggest a change which may make this happen? In case the city is on the "coast", it would be embarrassing for the transport to auto-unload the ground troops into the "ocean" where they drown.
 
That is a helpful suggestion. One problem may be, sometimes the AI chooses to attack a city which is deep inland. (Not that you can get "too" deep on DW archipelago style maps, but anyway several moves away from coast.) If there is no threat, it will be faster to continue using the transports.

Do you know if the ground units are unloaded some distance away from the city, will they forget their objective? You had mentioned that when units change domain, they may forget.

If you have a chance, can you look into AI_assaultSeaMove and suggest a change which may make this happen? In case the city is on the "coast", it would be embarrassing for the transport to auto-unload the ground troops into the "ocean" where they drown.

I think there's a inDanger function available to the AI if you want to throw that into the criteria. Umm, It's been a while, but I believe the AI actually just chooses the closest enemy city. This might be different for land attacks, but any time you are using transports your using the sea assault AI. Then again this may be a false memory.

Regarding the forgetting, no they won't forget. They actually relearn what they are supposed to do every move. The area thing was because the area designation prevented the relearning. If they are on the same continent, they will know what to do.
 
I know players have reported a weaker inland city being attacked by all-terrain transports. It was good, but a nasty surprise, and the moral of the story is you have to defend all your cities, not just the "coastal" ones.

Is it as simple as sticking a clause like, "if (inDanger()) and (domain == land)) then unload all" into the function? But I would like the transport to complete its move first, so that the movement points they have available are not wasted.
 
Some good stuff here.

I would note that at least usually, the AI atatcks the closest city. I don't think I have observed a non-coastal inland city be attacked by a stack of transports (maybe by thopters/suspensors?) when there was another city on the coast that was closer to the AI.
But cities more than 2 tiles from the coast are rare.

I agree with the proposal for unloading asap in general.
Possible exception though:
often the mapscrips generate little 1-2 tile islands. We do not want a situation where transports are approaching their target city, but then move over a little 2 tile junk island, and then unload all their troops.
So there would need to be some kind of check for being on the same continent as the target, when unloading.

Also:
The most logical way to do this would be to make a rule change, where when a transport is over land, units inside it may defend. This makes sense, as requiring the player to manually unload really only adds to micromanagement and tedium; there is no reason not to unload, so it might as well be done automatically, at least functionally.
The biggest problem with this is that units in transports are not actualyl displayed in a mouseover. It would be incredibly frustrating to attack what seems to be a bunch of weak transports, and lose your units because the invisible units loaded in the transports are actually able to defend.
 
We do not want a situation where transports are approaching their target city, but then move over a little 2 tile junk island, and then unload all their troops.

Interesting point. The first clause of the proposed check is "if in danger". So, suppose a transport is driving to another continent and happens to be passing over a junk island, when an enemy appears in range. Whether or not to temporarily unload is an interesting tactical decision. If they unload and forget where they are going, that is bad. Ideally they should decide if they can outrun the enemy and do so if they can, otherwise unload and hope the enemy passes by or is dealt with by the escorts, and then reload and continue on.

I have not located the "in danger" function yet. Workers are in danger simply if any enemy capable of attack is visible in one turn of its movement range. Heavy transports with sufficient escorts are only in danger from an enemy SOD. If we have only a worker danger function, I don't want an escorted heavy transport to nervously unload because a lone enemy warrior showed up.
 
Whether or not to temporarily unload is an interesting tactical decision. If they unload and forget where they are going, that is bad. Ideally they should decide if they can outrun the enemy and do so if they can, otherwise unload and hope the enemy passes by or is dealt with by the escorts, and then reload and continue on.

I think forcing them not to unload would be ok.
Any transport stack will haev escorts to protect from thopters and suspensors, which are of lower strength than normal land units.

The problem comes when transport stacks can be attacked by normal high-strength land units before they unload.

But by definition, if an AI transport stack is hovering over a junk island, there won't be any land units on that junk island that can attack them. So they're no more vulnerable than if they were hovering over empty desert, where they couldn't unload anyway.

So it would seem far simpler to have them treat the junk island as if it were just desert and not unload, but to unload as soon as they hit the continent - or as soon as they hit the continent and are "in danger".
And as long as they're on the continent, the cost of prematurely unloading is relatively low (takes an extra turn or two to get next to their target city), whereas the cost of unloading too late (ie after a bunch of city defender units kill the escorts and then start destroying fully loaded transports) is much higher.
So the "in danger" check isn't even all that important.

Also note; failing to unload costs an extra turn anyway, because troops can't bombard or attack on the turn they are unloaded.
 
I would not unload them onto a junk island, I'm not sure the AI knows how to pick up stranded units. To check for same continent you compare the areaID of your plot vs. the areaID of the target plot.

Also david, I don't remember the exact function name for danger, it's like getDangerCount or something. It's used when a land attack unit meets a hostile on the way to his target. It decides if you should walk to your destination or attack this unit if your odds are good.
 
Back
Top Bottom