Currently, the AI mostly runs itself on a per-unit or per-stack basis.
I'm thinking that we might want to generate a "start of turn" process where the AI identifies threats, targets, and locations that need reserves.
A threat is something like an enemy stack that is in your territory or near your territory. Possibly unexplored enemy terrain near your borders would also have low-grade threat attached.
A target is something like a city you want to take.
Cities, by their very existence, will have a presumed level of threat, plus extra threat based off being near borders (or near water), based off of the total power of neutral and enemy powers (and enemy units). They also like having reserves located in them.
Ideally, we want to do this without adding extra save game data (or cheat, and store it in a way that is compatible old save games). If we can do without actually saving anything, that would be ideal.
Once the AI identifies threats, it can then iterate over it's units, and propose a plan to deal with threats, and resources that can be directed towards targets. It would be acceptable to decide that a given threat should be ignored, but the AI should make that decision.
Explicit threats, like enemy stacks, can be dealt with by two methods.
First, you can beef up defenses of nearby cities (that leaves the pillage threat of the enemy stack intact).
Second, you can attempt to eliminate the enemy stack. In that case, an attempt to keep most baseline defenses intact, and protect the attacker against threat after the fight, should be taken into account.
Targets would be delt with similarly, except you'd look at where units are planning to go, and bias your target selection towards their plans. (Ie, if you have a large number of units gathering in a given city, the AI would think about plans for naval invasions being launched from that city, and about land-wars being launched from that city, each turn. This might even take into account the current number of nearby cities producing boats (ie, potential transport capacity) for the naval invasion case.)
This all would happen in:
void CvPlayer::doTurnUnits();
or, more accurately, in the function:
void CvPlayer::AI_doTurnUnitsPre();
that doTurnUnits() calls.
or maybe in the CvPlayer::doTurn() code.
Currently, unit movement decisions are done in:
CvPlayer::AI_unitUpdate()
which iterates over each selection group, and makes plans for it.
This is called from:
CvGame::updateMoves()
which is called from
CvGame::update()
which seems to be called from the DLL.
CvPlayer::setTurnActive() calls CvPlayer::doTurnUnits()
which is called from CvGame::doTurn()
which is called from CvGame::update() before it calls updateMoves().
So... that looks like the vaguely the right place to do this.
A pass to identify:
Low-level threats (all cities are threatened)
Unknown-level threats (cities that are near boarders have extra, unknown threat)
Immediate threats (enemy stacks)
Ideal reserves (clumps of units over the empire, stationed at cities -- but if you have to dip into these, that's what they are there for)
Targets or Goals (a massing naval invasion, a massing land invasion, a marching army at an enemy city, etc)
Then a pass to identify resources that can reach each of the threats, reserve locations, immediate threats and targets & goals, a "is it already on it's way there" detector, an idea of how soon it it can engage.
This would include an idea about the future already-queued production of resources on what time-lines, and the possible "omg, let's make units quick" options.
Then a check to see if we can deal with all immediate threats in a single turn while maintaining sufficient defenses to deal with low-level and unknown threats... (including to the units that are used to attack the threats in question) Then see if you can make a plan for multiple turns, etc.
Do this check for each of, say, 1, 2, 3 or 4 turns into the future. Once you know you can deal with it in N turns, you can fine-tune the plan (mass the units at a particular location, instead of charging in, etc, or determine if you can reinforce threatened cities along the enemy advance route). -- ie, what is the cost of the delay?
Now, determine what happens if you start dipping into the "unknown threat" reserves. This is dangerous, but if that is the only way to deal with an incoming army that is about to take out a major city, it might be worth it...
Ie: you see a monster stack approaching. Can you kill it or damage it enough that it isn't a danger any more? If not, should you start whipping?
Or, you see an enemy naval force off of your coasts. Can you take it out? Do you have naval forces to spare to take it out?
The idea is to try to get the AI to think less on a per-unit basis, and more on a "here are the resources I have, and here are the problems I have" basis.
This might be way way way way way to ambitious.
I'm thinking that we might want to generate a "start of turn" process where the AI identifies threats, targets, and locations that need reserves.
A threat is something like an enemy stack that is in your territory or near your territory. Possibly unexplored enemy terrain near your borders would also have low-grade threat attached.
A target is something like a city you want to take.
Cities, by their very existence, will have a presumed level of threat, plus extra threat based off being near borders (or near water), based off of the total power of neutral and enemy powers (and enemy units). They also like having reserves located in them.
Ideally, we want to do this without adding extra save game data (or cheat, and store it in a way that is compatible old save games). If we can do without actually saving anything, that would be ideal.
Once the AI identifies threats, it can then iterate over it's units, and propose a plan to deal with threats, and resources that can be directed towards targets. It would be acceptable to decide that a given threat should be ignored, but the AI should make that decision.
Explicit threats, like enemy stacks, can be dealt with by two methods.
First, you can beef up defenses of nearby cities (that leaves the pillage threat of the enemy stack intact).
Second, you can attempt to eliminate the enemy stack. In that case, an attempt to keep most baseline defenses intact, and protect the attacker against threat after the fight, should be taken into account.
Targets would be delt with similarly, except you'd look at where units are planning to go, and bias your target selection towards their plans. (Ie, if you have a large number of units gathering in a given city, the AI would think about plans for naval invasions being launched from that city, and about land-wars being launched from that city, each turn. This might even take into account the current number of nearby cities producing boats (ie, potential transport capacity) for the naval invasion case.)
This all would happen in:
void CvPlayer::doTurnUnits();
or, more accurately, in the function:
void CvPlayer::AI_doTurnUnitsPre();
that doTurnUnits() calls.
or maybe in the CvPlayer::doTurn() code.
Currently, unit movement decisions are done in:
CvPlayer::AI_unitUpdate()
which iterates over each selection group, and makes plans for it.
This is called from:
CvGame::updateMoves()
which is called from
CvGame::update()
which seems to be called from the DLL.
CvPlayer::setTurnActive() calls CvPlayer::doTurnUnits()
which is called from CvGame::doTurn()
which is called from CvGame::update() before it calls updateMoves().
So... that looks like the vaguely the right place to do this.
A pass to identify:
Low-level threats (all cities are threatened)
Unknown-level threats (cities that are near boarders have extra, unknown threat)
Immediate threats (enemy stacks)
Ideal reserves (clumps of units over the empire, stationed at cities -- but if you have to dip into these, that's what they are there for)
Targets or Goals (a massing naval invasion, a massing land invasion, a marching army at an enemy city, etc)
Then a pass to identify resources that can reach each of the threats, reserve locations, immediate threats and targets & goals, a "is it already on it's way there" detector, an idea of how soon it it can engage.
This would include an idea about the future already-queued production of resources on what time-lines, and the possible "omg, let's make units quick" options.
Then a check to see if we can deal with all immediate threats in a single turn while maintaining sufficient defenses to deal with low-level and unknown threats... (including to the units that are used to attack the threats in question) Then see if you can make a plan for multiple turns, etc.
Do this check for each of, say, 1, 2, 3 or 4 turns into the future. Once you know you can deal with it in N turns, you can fine-tune the plan (mass the units at a particular location, instead of charging in, etc, or determine if you can reinforce threatened cities along the enemy advance route). -- ie, what is the cost of the delay?
Now, determine what happens if you start dipping into the "unknown threat" reserves. This is dangerous, but if that is the only way to deal with an incoming army that is about to take out a major city, it might be worth it...
Ie: you see a monster stack approaching. Can you kill it or damage it enough that it isn't a danger any more? If not, should you start whipping?
Or, you see an enemy naval force off of your coasts. Can you take it out? Do you have naval forces to spare to take it out?
The idea is to try to get the AI to think less on a per-unit basis, and more on a "here are the resources I have, and here are the problems I have" basis.
This might be way way way way way to ambitious.
