[BTS] Voting AI Discussion

jdog5000

Revolutionary
Joined
Nov 25, 2003
Messages
2,601
Location
California
So, trying to get to the bottom of some strange AI voting behavior I perused CvPlayerAI::AI_diploVote today. Here pieces that I'm thinking about updating:

---------------------------------------------

1. Always vote for proposals by Friendly Secretary General

Up at the top of section of voting for proposals (as opposed to electing a leader) is the following:

Code:
	if (eSecretaryGeneral == getTeam() ||([B]GET_TEAM(getTeam()).AI_getAttitude(eSecretaryGeneral) == ATTITUDE_FRIENDLY[/B]))
	{
		return PLAYER_VOTE_YES;
	}

The bold bit means that if the AI is Friendly towards the secretary general they vote for their proposals no matter what. The rest of the logic of picking how to vote isn't even considered.

It does make sense that a player's relationship with whoever is proposing the legislation would have an effect ... but that blanket condition is ridiculous. The AI would vote to put an embargo on itself if it was proposed by a conniving human they were friends with. They would vote for war against themselves or to give away their own city to. Not sure what is actually possible given constraints on what can be proposed by friends, but you get the idea.

Here's what I'm thinking instead:
- Never defy legislation from friends
- Auto approve trade routes, free trade, open borders, defensive pact, embargo (if not self)
- Up thresholds for voting against civics

That leaves stop war, start war, assigning cities, and nukes. It's possible to easily influence some of these a little bit towards yes, but these seem like more strategic decisions where it may be less appropriate to consider the relationship to the secretary.

---------------------------------------------

2. Stop war "logic"


So far I haven't been able to figure out the reasoning behind the logic the AI uses to vote on stopping wars. Here's the initial bit:

Code:
	int iWarsWinning = 0;
	int iWarsLosing = 0;
	int iChosenWar = 0;
	//Are we winning wars?
	for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
	{
		if (GET_TEAM((TeamTypes)iI).isAlive())
		{
			[B]if (iI != ePeaceTeam)[/B]
			{
				if (GET_TEAM((TeamTypes)iI).isAtWar(ePeaceTeam))
				{
					if (GET_TEAM((TeamTypes)iI).AI_getWarSuccess(ePeaceTeam) < GET_TEAM(ePeaceTeam).AI_getWarSuccess((TeamTypes)iI))
					{
						++iWarsWinning;
					}
					else
					{
						++iWarsLosing;
					}

					if (GET_TEAM(ePeaceTeam).AI_isChosenWar((TeamTypes)iI))
					{
						++iChosenWar;									
					}
				}
			}
		}
	}

Now the comment says "are we winning wars?" but it isn't really for this player ... iWarsWinning, iWarsLosing, and iChosenWars count how things are going for ePeaceTeam and will be the same for every player in the game.

Let's imagine there's a vote to end the war against the Aztecs. The code counts the wining/losing/chosen feelings of the Aztecs. So, we've got a count of the number of teams who the Aztecs think they're beating, the number the Aztecs are losing to/tied with, and the number of teams the Aztecs chose to go to war with.

One problem I see with this part is the handling of ties, particularly if there's an inactive war where no fighting has occurred and both sides war success is 0. For example, say the Aztecs decided to attack France and that France has two tiny vassal colonies. The Aztecs could be beating France handily but would have two "losses" if their troops have never seen France's weak vassals on the battle field. So, I'm thinking there should be some thresholds so that winning/losing only counts if there's been some real fighting (the thresholds could be dependent on whether Aggressive AI is on).

Now the flow continues on to the actual decision making, I've broken it into pieces so it's easier to work through. If bValid is true the AI will vote to end the war, if false it will vote against and may choose to defy it.

Code:
        if (ePeaceTeam == getTeam())
	{
		if (iWarsLosing < iChosenWar)
		{
			bValid = false;
		}
		else
		{
			bValid = (iWarsWinning < iWarsLosing);
		}
	}

The above block handles the case where the Aztecs are voting to end the war against themselves. The Aztecs will vote to continue the war against themselves if they have chosen to get into more wars than they are losing. Alternatively, the Aztecs will also choose to keep the wars going if they aren't losing more wars than they're winning.

These clauses reads okay at first, however, I think the case of ties where there hasn't been any actual fighting mentioned above would cause this to tilt towards a vote for peace.

Code:
	else if (eSecretaryGeneral == getTeam() && !bPropose)
	{
		bValid = true;
	}

This clause means the AI always votes for it's own legislation ... never actually fires as it's preempted by the code from issue 1.

Code:
	else if (GET_TEAM(ePeaceTeam).isAtWar(getTeam()))
	{
		bValid = (bPropose || NO_DENIAL == GET_TEAM(getTeam()).AI_makePeaceTrade(ePeaceTeam, eSecretaryGeneral));

		if (bValid)
		{
			bValid = (iWarsWinning > iWarsLosing);
		}
	}

This handles decisions for players who are at war with the Aztecs. The bPropose flag is a special case where the AI is considering whether to put a particular piece of legislation up for a vote. Aside from that, the first clause says the AI will vote for peace if it would be willing consider peace if asked in the diplomacy window by the secretary general. It's decision to vote for peace with the Aztecs (bValid = true) can be overridden if the Aztecs losing more wars than they're winning.

There are problems with using AI_makePeaceTrade here though ... if ePeaceTeam is the human player, AI_makePeaceTrade always returns DENIAL_CONTACT_THEM and so the AI would never vote for peace if they were at war with the human player regardless of how the war is going. Similarly, if the AI is losing badly enough the function returns the same DENIAL_CONTACT_THEM and so the AI won't vote for peace if it's getting beat badly. If the AI is a vassal the function returns DENIAL_VASSAL since as a vassal it doesn't control peace decisions in diplomacy but that doesn't apply here.

I'm not sure quite what to propose here ... I think the AI_makePeaceTrade should only be considered if the AI is on pretty good terms with the secretary. Also, there clearly needs to be a further consideration so the AI won't vote to continue a war which it is losing by more than a little.

Code:
	else
	{
		if (GET_TEAM(getTeam()).AI_getAttitude(ePeaceTeam) >= ATTITUDE_CAUTIOUS)
		{
			bValid = (iWarsLosing > iWarsWinning);
		}
		else
		{
			bValid = (iWarsWinning > iWarsLosing);
		}
	}

This clause handles how third-parties vote. If the third-party has a least okay relations with the Aztecs and the Aztecs are losing, then they vote for peace. If they don't like the Aztecs and the Aztecs are winning, they vote for peace.

It's a little to altruistic, there are several self-interest reasons the AI might want to keep this war going. If they're planning to invade the Aztecs soon, then they probably want the war to continue regardless of who is on top. Similarly, if they are at war with someone who is also at war with the Aztecs then they would want to keep them busy.

Code:
	if (!bValid && iWarsWinning > 0)
	{
		if (GC.getGame().getSorenRandNum(2, "AI Erratic Defiance (Force Peace)") == 0)
		{
			bDefy = true;
		}
	}

This block decides if the AI chooses to defy the resolution. I think there's a pretty clear bug here as the logic only makes sense for the Aztecs and not anyone who's at war with them. It's also possible based on this that a player not at war with the Aztecs would choose to defy the resolution, though that is caught later with a check to CvPlayer::canDefy.

There need to be two cases here, one for the Aztecs and one for those at war with the Aztecs. I'm not sure quite what the logic should be as it is hard to quantify the benefit of maintaining war versus the cost of happiness and lost bonuses. Certainly the AI should only defy if it is really winning and has reason to believe it will keep winning (power comparison).

--------------------------------------------

Thoughts? Ideas? Proposals?
 
Factors:
1> Does the AI want the war to end, for it's own future plans?
1a> Are we getting our but whooped in this war?
1b> Is someone we dislike winning the war?
1c> Is someone we like losing the war?

2> Does the AI want the war to continue, for it's own future plans?
2a> Are we winning the war?
2b> Is someone we dislike losing the war?
2c> Is someone we like winning the war?
2d> Do we want the diplomatic boost for sharing a war?

3> Does the AI like the sec. general who proposed it?
3a> Enough to say "sure, we'll help you?"
3b> Enough to push a decision over the edge?

...

The above should be influence by how peaceful/warlike we are.

The following don't really apply if we are the target of the peace/war initiative:

4> Do we want to distract anyone involved in the war?
4a> Do we want to attack a party involved?
4b> Is anyone we dislike in the war also at war with someone we like?
4c> Are we engaged in a 3rd party war we really don't want?

5> Do we want to free up anyone involved in the war?
5a> Is one of our allies in a war distracted by the war?
 
I'm currently not seeing where in the code the player AI considers what the penalties are for not agreeing with the secretary with regards to stop/start war, nukes and assigning cities? That's obviously a major relevant issue.
Cheers.
 
glider:

What particular penalties are you thinking of? The penalties for defying legislation?

Yakk:

A good collection of questions, thanks. I'm definitely working on adding a bit more of the leaders personality to their voting decisions like you mentioned, Gandhi and Genghis shouldn't have the same 50% odds of defying a call for peace!
 
glider:
What particular penalties are you thinking of? The penalties for defying legislation?
I'm getting distracted in what is a very complex area of code, between personal motivation and the motivation of being in a "council of civs". This slab of code is complex because of the interaction at the level of players and teams in a political context (the politics of being in a council of civs).

The question is whether there is any context for political questions in this code in terms of a civ considering relations hits with the secretary or other members for being uncooperative. "If I vote against the resolution will I experience a relations hit with civs that are critical to my security or economy?". Relations hit's feed into the game more broadly in complicated ways.

How about this question to clarify what is possible politically in the UN? If I am not wrong, the political domain in the grey areas of the UN at the moment comes down to whether a civ get's a point approval or disapproval with only the secretary? Is there any direct approval changes that can happen amongst civs participating in the UN other than with the secretary? (as aside from indirect approval changes that result).

Cheers.
 
Back
Top Bottom