Sec General AI

r_rolo1

King of myself
Joined
May 19, 2006
Messages
13,818
Location
Lisbon, Portugal
I and my teammates in the current SGOTM, for reasons I can't tell here, decided to give a look at the code that governs the AI choose of resolution when it is the Apostolic resident or the UN Sec general......

CvTeamAI::AI_chooseElection ( "vanilla" 3.17 BtS )
Code:
int CvTeamAI::AI_chooseElection(const VoteSelectionData& kVoteSelectionData) const
{
	VoteSourceTypes eVoteSource = kVoteSelectionData.eVoteSource;

	FAssert(!isHuman());
	FAssert(GC.getGameINLINE().getSecretaryGeneral(eVoteSource) == getID());

	int iBestVote = -1;
	int iBestValue = 0;

	for (int iI = 0; iI < (int)kVoteSelectionData.aVoteOptions.size(); ++iI)
	{
		VoteTypes eVote = kVoteSelectionData.aVoteOptions[iI].eVote;
		CvVoteInfo& kVoteInfo = GC.getVoteInfo(eVote);

		FAssert(kVoteInfo.isVoteSourceType(eVoteSource));

		FAssert(GC.getGameINLINE().isChooseElection(eVote));
		bool bValid = true;

		if (!GC.getGameINLINE().isTeamVote(eVote))
		{
			for (int iJ = 0; iJ < MAX_PLAYERS; iJ++)
			{
				if (GET_PLAYER((PlayerTypes)iJ).isAlive())
				{
					if (GET_PLAYER((PlayerTypes)iJ).getTeam() == getID())
					{
						PlayerVoteTypes eVote = GET_PLAYER((PlayerTypes)iJ).AI_diploVote(kVoteSelectionData.aVoteOptions[iI], eVoteSource, true);

						if (eVote != PLAYER_VOTE_YES || eVote == GC.getGameINLINE().getVoteOutcome((VoteTypes)iI))
						{
							bValid = false;
							break;
						}
					}
				}
			}
		}

		if (bValid)
		{
			int iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Choose Vote"));

			if (iValue > iBestValue)
			{
				iBestValue = iValue;
				iBestVote = iI;
			}
		}
	}

	return iBestVote;
}

Resuming ( for those less code able ):
-Ok , I'm a AI
-Oh, I'm Sec general and/or Apostolic Palace Resident
-Let's see what resolutions are possible in the moment.....
-Ok, I have some resolutions in hand.....
-Let's just toss a coin in the air and chose one

Well, this obviously has ample space for improvement. I don't have clear ideas of how to make it better, but surely a look to what the AI has would help ( force FR vote when having Sankore and Spiral minaret is not the birghtest idea of them all ..... ). Maybe decreasing the odds of voting for a already passed resolution would also help in some cases ( I have my fair share of games where the Sec general AI repeatedly asking to pass the already passed Emancipation or FR vote )

P.S How could I forget the myriad times where the AI dows and as AP resident or Sec general calls the end of the war in the next turn ? :p
 
If that is really random, then I agree, improve!
 
Laugh. At least it is well structured, so we can add in some biases if we think of some.

I can just see the AI programmer at Firaxis saying "ok, placeholder..."
 
Laugh. At least it is well structured, so we can add in some biases if we think of some.

I can just see the AI programmer at Firaxis saying "ok, placeholder..."
" "...I'll come back to this tomorrow morning" - thinked him while drinking his 10th cup of coffee of the day. But that particular tomorrow never came.... " ;)

I have to agree that atleast the code in here is not the mess that we see in other areas of the program ( can you say air combat? ;) ), so it is relatively easy to set some biases and prohibitions.

I can think in a hand full :
- civics making wonders worthless should have lower weight
- AI should never propose a civic switch that she isn't willing to make by itself or by bribing ( c'mon, Isabella proposing FR ? :crazyeye: )
-AI should not propose to stop a war that it thinks it is winning or one where a ally is winning
-AI should weight resolutions by the diplo with the target if apliable ( proposing to give a ally city to a enemy is not good, for a quick example )
-AI should considers the economical impact that the resolutions would make in them

I have one more, but that it would probably give a LOT of extra work:
- AI, if possible and advisable should try to make damage to the their enemies using the AP/UN: obsolete their wonders, making them go out of Rep/Caste, stop their wars, steal their cities, forcing them to pile unhappiness for defying resolutions... what humans do ;)
 
Maybe a factor to help prevent presenting the same resolution repeatedly when it fails as well. That happens occasionally at the moment, but I can certainly see the AI repeat resolutions more if it actually starts thinking and is not just rolling a die. :lol:
 
The C++ coders here might be able to speed this up by writing the code and presenting it here. Jdog has like a dozen other things he's working on, so it might be nice to have some of us figure it out and write the code and present it for experimentation in the next SVN. I know, I know, practice what you preach, but unfortunately I have no basic knowledge of C++.
 
If a hated civ keeps defying a resolution that passes, I can see putting it up for yet another vote. Stack up those unhappiness penalties on your enemies!
 
In general, adding storage to the Civ AI that doesn't already exist is a headache. So if someone thinks up an algorithm to put forward better Sec General proposals, try to make it stateless (you can examine the current game state, but not the history).

(The Civ4 file format is a pile of steaming bytes, and doesn't take to extensions that well. If you add more stuff, you break save game compatibility.)
 
OK, so I've now succesfuly done my first SDK modding. So I'll look at seeing if I can mess with this. Probably wol't be able to though, the only programming I understand is from looking at posts here, and just general knowledge of math (taken alot of math actually). So I probably wol't be able to tackle this, but at least I'll try. Anyway, to start with here's how I think the logic should progress:

Code:
Check to see if I am AI, Oh I'm an AI
  OK, Oh, and I have votes available
    I guess I'm looking at AP votes
      Oh, I guess I can call a vote to win the game
        Let's check, can the attitudes of the other players and crudely calculate if I could get enough votes
        It's close (within 10%) so I'll call a vote and see if I can win right now.
      Oh I'm at war with someone I don't want to be at war with
        There is a vote available to stop the war against me
          Lets call a vote to stop the war against me
      OK I'm at war with someone I want to be at war with
        And there is a vote available to declare war on someone I'm at war with
          Too bad, the war isn't going Very Easily
            Lets check to see how many enemies there are votes available to declare war against
            Let's check the power ratio and determine the biggest threat to me
            Now lets run a check to see other AI attitudes and determine of other players will vote to declare war against that enemy
            Looks like they will declare war
              Lets call that vote
            Let's pick the next biggest threat.  And lets do what we just did until there are no longer any more declare war votes against players we are at war with.
      Wow, I guess there are votes that can give me a city & there are votes to declare war against a player that I'm not involved in
        Let's flip a coin to see which one interests us more
          I guess I'm more interested in the wars that can be waged
            Let's check our attitude with the the Civs to declare war with, and order them by the one I hate the most to the one I am most friendly toward
              We'll roll our handy dice we seem to always use to make decisions, we'll use our Declare War dice outcomes in our personality file.
                We rolled to declare the war, let's see what the attitudes of the rest of the AP voters are, and figure out if the vote looks like it could pass
                  Oh look it very well might pass, let's pick that vote
              Let's continue checking against all war votes the way we just did until we run out of declare war votes
        Well I guess I'm more interested in getting a city via vote or I just ran through my war vote check and didn't decide to vote to declare war against anyone.
          Let's check my attitude with the Civ that currently owns the city, and roll my trusty dice to see if I would be willing to declare war based on my attitude with them, let's multiply all my die rolls by 3 as well, since getting a city by vote is much easier then declaring war
            Looks like I rolled to go through with it.  I don't really care what other civs think, I'm calling this vote right here and now because this city is rightfully mine.
        Well I was more interested in voting to get a city, but it was a passing interest.  Let's look at the war votes, and follow the steps above for war votes as though I was more interested in that ( don't do if we already checked the war votes)
      So there is a vote to declare war against a rival: lets follow the steps above
      So there is a vote to get a city of ours via voting:  Let's follow the steps above
      Wow there is the option to End a War out there, and there is an option to reallocate a city
        Let's flip a coin to see which interests us more
        I guess Ending a War is more interesting
          Let's check our attitude with the Civs to end the war against, and order them from the one I like the most, to the one I hate the most
            Lets roll the dice to see if we should end the war, using our Declare war probility personality, and let's multiply our dice rolls by 2, If I roll not to declare war, let's vote to end the war against our friend.
          We should follow this way to decide on the stoping of war votes until we run out of options to stop the wars
        Well I guess I'm more interested in reallocating a city or I just finished checking on my options to stop a war, and decided not to.
          Let's check our attitude with the Civs that we could allocate the City to And order them by who we are most friendly with, to the civ we dislike the most.
            I guess they are our friend or we are pleased with them
              Let's check to see our attitude with the Civ the City will be allocated away from.
                Well are are annoyed/furious with them
                  Call vote to flip the city
                We are neutral, let's flip a coin
                  We flipped tails, sorry you loose, call the vote
            Let's run through our options until we get to a civ we are just nuetral toward, when that happens ignore the rest of the votes.
        OK we were more interested in re allocating a city, but decided not, so let's check the ending war options, the same way we would have above, if we had flipped heads instead of tails
      Well I guess there is an End War vote available, Let's check to see if we want to end a way the way we would have above if there had also been a realocate city option
      Well I guess there is an option to reallocate a city, let's see if we want to do that the same way we would have if there was also an option to end the war.
      Oh, guess there weren't any interesting options to vote on.  At least there is an option to Embargo a Civ and an Option to declare open borders with all members
         Let's flip a coin to see which vote interests us more
           OK, heads, Lets make a list of who we can embargo, And order them from who we hate most, to who we are most friendly toward.
             Well, we are furious with them
                Call the vote
             They annoy us
               Let's check the attituteds of the other Civs toward this player
                 Looks like the vote could pass, call the vote
             Hmm, we are nuetral toward them, let's flip a coin to see if we should embargo them
               I flipped tails, Let's check the average attituded of the other AP voters and see if this vote can pass
                 Looks like it might pass, call the vote
             Tails, Let's see what we think of the other members of the AP
               Our average attitude is in the nuetral range, on the positive side.  It makes sense to increase goodwill among us, call the vote to open borders
               Our average attitude is in the nuetral range, but on the negative side.
               Hmm, well we aren't furious with anyone, let's just call the vote
               Oh, that's cause we hate someone who is a member, roll our trusty dice to declare war based on our personality.
                 Well I guess we decided not to declare war, so in this instance that means we'll call a vote to have open borders
       OK, At least there is an option to embargo someone, lets run our check the same way as we would have above, if open borders had also been an option
       Ok, at least there is an option to open borders, lets run a check to see if we want to open borders among all members the same way as we would have if there had also been an option to embargo someone.
       Wow, we didn't decide to make any votes/there are no votes available, guess we skip the whole thing.
 
For pseudo-code it is not actually bad. As I'm a noob regarding C ( I suposedely know how to program in C , but only had a semester of C in the previous millenium, so don't ask me to code :p ), I'll limit to that too ;)

My main correction to do will be remembering that this routine is also used for the UN, so it is needed some more options in the pseudo code. Other correction ( I'm skimming it at work, so I can't detail much more now ) is to consider that in terms of finishing a war, preventing war vs me or vs them is the same thing ( technically it isn't, because preventing any war vs you for 10 turns is not the same as preventing war vs them for 10 turns ( they can have far diferent values in some situations ), but as first aproach they are roughly equal ).

I'll make my suggestions ( based on yours ) later, when I have more time to think about it .
 
It should also be (at it's core) non-deterministic.

Ie, you should always generate a collection of options, barring extreme cases(I am certain I can win the game because me + vassals + team mates is a win), then select somewhat randomly between them.

This is because of a few points:
1> We have no state, and we want to avoid repeating the same fruitless thing.
2> Our model of the world is not perfect -- even if we predict what all other AIs will do, there is a human player out there. And RP wise, we shouldn't treat the human player differently.

Even if we simply eliminated all of the counter-productive/pointless options, we'd have a significant boost to the AI's ability to be Sec General.
 
I agree with Yakk, not only because of the reasons he stated, but because there is no way to tell that a certain vote is better suited than other when both are possible in all situations . I would propose something like:

-Check what are the possible resolutions
-Weight them according with perceived usefulness
-Toss a coin

On other issue: AI does not need to have extra memory to have some idea that a civ defied other vote , atleast with the AP. The AI can certainly be made aware that a theoretical status in terms of membership not coincident with the one that the civ really have is a sign of recent defy. And regarding the repeated resolutions: I assume that the AI has access to the (PASSED) that appears both in the pop-up and the Diplo votes tab in F8 ). Both options are not perfect, but avoid adding memory slots to the saves

I would like to add more constructive comments , but my SGOTM team had a huge technical problem and I passed last hours trying to solve it
 
Top Bottom