New Version - December 1st (12/1)

Status
Not open for further replies.
Nice ones. No idea for starters (duh I'm useless) but a request: once you decide on some values, can you externalize them into .sql so we players can toy with them? If it's already like that I missed it.

I can't overstate how much I feel like this is going to be one of the best changes yet once the numbers are figured out. An AI that keeps pace (or appears too) is unheard of in my experience. Loving this.

This too if possible.

> but it did require me to create more variables for the handicaps table

There will be four variables in the handicaps tables (that will be editable without DLL compilation):

Code:
DifficultyBonusBase
           
DifficultyBonusEarly
          
DifficultyBonusMid
           
DifficultyBonusLate

G
 
Awesome work, Gazebo!

Re: numbers for difficulties -> I'm having a bit of trouble orienting within the new framework, which exact numbers in the formula do you want us to suggest? :)
 
Awesome work, Gazebo!

Re: numbers for difficulties -> I'm having a bit of trouble orienting within the new framework, which exact numbers in the formula do you want us to suggest? :)

iYieldHandicap = iHandicapBase * ((iHandicapA * iEra) * (iEra + iHandicapB) * iHandicapC);
 
Great People generation and World Wonder spamming seem like two hallmarks of a Civ doing very well for itself. Having those trigger handicap yields would seem to be the basis for a "Making of a Runaway" Netflix series.

Is the purpose of the handicap triggers to make all the AIs more competitive? Or is it a mechanism to allow the top AIs to really push the player? I always assumed it was the former and the rest of my post is based on that goal. Curious if others assumed or prefer the latter design philosophy.

Handicaps on Era advancement is the trigger I like best since all AIs benefit. City Settling strikes me as neutral-ish; wide can be very strong but has downsides so handicaps maybe help smooth things out; make up for the occasional poor decision. All the rest of the triggers (winning wars, GA, GP generation, WW building) seem like win-more mechanics. Strong AIs get stronger while weak AIs fade away.

Is it possible and would it make sense to make the additional triggers more success-neutral? Some example might be triggering every X techs researched (globally if possible), every session of the World Congress, or every time a World Wonder is built (i.e. all AI benefit, not just the WW builder).

I like the idea of a neutral trigger, would a trigger every X turns be enough? Seems neutral overall, and X could be tuned to the average rate you'd expect from most AIs throughout a match.
 
Alright, so I've reworked the difficulty model a bit. I like the polynomial concept, but it did require me to create more variables for the handicaps table. Which is fine, but it rules out a hotfix.

Anyways, here's the new function:

Code:
int iEra = GetCurrentEra();
    if(iEra <= 0)
    {
        iEra = 1;
    }
    int iHandicapBase = 0;
    int iHandicapA = 0;
    int iHandicapB = 0;
    int iHandicapC = 0;
    int iYieldHandicap = 0;
    CvHandicapInfo* pHandicapInfo = GC.getHandicapInfo(GC.getGame().getHandicapType());
    if(pHandicapInfo)
    {
        iHandicapBase = pHandicapInfo->getAIDifficultyBonusBase();
        iHandicapA = pHandicapInfo->getAIDifficultyBonusEarly();
        iHandicapB = pHandicapInfo->getAIDifficultyBonusMid();
        iHandicapC = pHandicapInfo->getAIDifficultyBonusLate();
        iYieldHandicap = iHandicapBase * ((iHandicapA * iEra) * (iEra + iHandicapB) * iHandicapC);
    }
    if (iYieldHandicap > 0)
    {
        bool IncludeCities = true;
        if (eHistoricEvent == HISTORIC_EVENT_GP ||
            eHistoricEvent == HISTORIC_EVENT_WONDER ||
            eHistoricEvent == HISTORIC_EVENT_DIG ||
            eHistoricEvent == HISTORIC_EVENT_TRADE_CS ||
            eHistoricEvent == HISTORIC_EVENT_TRADE_LAND ||
            eHistoricEvent == HISTORIC_EVENT_TRADE_SEA)
        {
            IncludeCities = false;
        }

        if (IncludeCities)
        {
            int iLoop;
            CvCity* pLoopCity;
            for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
            {
                if (pLoopCity != NULL)
                {
                    pLoopCity->ChangeJONSCultureStored(iYieldHandicap);
                    pLoopCity->changeFood(iYieldHandicap);
                    pLoopCity->changeProduction(iYieldHandicap);
                }
            }
        }

        GetTreasury()->ChangeGold(iYieldHandicap);
        ChangeGoldenAgeProgressMeter(iYieldHandicap);
        changeJONSCulture(iYieldHandicap);
  
        TechTypes eCurrentTech = GetPlayerTechs()->GetCurrentResearch();
        if(eCurrentTech == NO_TECH)
        {
            changeOverflowResearch(iYieldHandicap);
        }
        else
        {
            GET_TEAM(getTeam()).GetTeamTechs()->ChangeResearchProgress(eCurrentTech, iYieldHandicap, GetID());
        }
    }

Biggest changes:

Polynomial model (I need numbers for the difficulties - any ideas for starters? Haven't started testing it yet).
Only 'national' historic events give cities bonuses - otherwise they don't get any bonuses.
The science boost is now flat like the others, so it won't benefit leading AIs more than losing AIs.

G
Numbers...
Well, previous versions were like
0 * iEra ^ 2 + 5 * iEra + 0, ranging from 5 to 35
12-1 version was
2 * iEra ^ 2 + 0 * iEra + 0, ranging from 2 to 98

I think a good starting point can be
2 * iEra ^ 2 - 5 * iEra + 9, ranging from 5 to 72

I don't get your notation. I think you've misplaced a sign or something
iYieldHandicap = iHandicapBase * ((iHandicapA * iEra) * (iEra + iHandicapB) * iHandicapC);
this is Ax * (x+B) * C = ACx^2 + ABCx, not a full polynomial.
You might want to write it as A * (x + B) * (x + C), but this notation is only useful when you are looking for axis points. Or maybe it is useful for computational time. I suggest keeping the explicit mode ax^2+bx+c, unless there's a computational reason. In the latter case, constants can be easily translated.

EDIT.
iYieldHandicap = iHandicapBase * ((iHandicapA * iEra) * (iEra + iHandicapB) * iHandicapC);
I believe the intended formula is
iYieldHandicap = iHandicapBase * ((iEra + iHandicapA) * (iEra + iHandicapB) * iHandicapC);

EDIT 2. Values
I must be rusted, cause I can't turn the explicit polynomial into your notation. Please, make it
iYieldHandicap = iHandicapBase * (iHandicapA * iEra * iEra + iHandicapB * iEra + iHandicapC)

EDIT 3. I've discovered google math can plot functions, pretty useful.
And I'm realising that beginning with 5 at iEra=1 is starting in disadvantage, while starting with 2 gives an AI weaker than humans (upon my recent maya game). Could try a starting handicap of 3, with this one:
2 iEra^2 - 4 iEra + 5, ranging from 3 to 75.
(try searching this in google: "plot 5x, 2x^2, 2x^2-4x+5")
 
Last edited:
If the intended formula is to be like a*x^2 + b*x + c then the code should be little different:
iYieldHandicap = iHandicapBase * (iHandicapA * iEra * iEra + iHandicapB * iEra + iHandicapC);

From current code you get: A * C * x^2 + A * C * B * x
 
Assumptions:
1. Old formula was: iYieldHandicap = (iHandicap * iEra * 5); iHandicap going from 0 to 7 (Deity=7)
2. New formula is: iHandicap * Era * Era * 2 (Deity=5)

I propose to use: iHandicap * (a * era * era + b * era + c) where
era = 1..8, iHandicap = 0..7 (Deity=7), a = 1, b = -0.5, c=5

After that feel free to tune the params.

Code:
Era New Old Prop
1  10  35  39
2  40  70  56
3  90 105  88
4 160 140 133
5 250 175 193
6 360 210 266
7 490 245 354
8 640 280 455


upload_2017-12-6_0-42-54.png
 
Assumptions:
1. Old formula was: iYieldHandicap = (iHandicap * iEra * 5); iHandicap going from 0 to 7 (Deity=7)
2. New formula is: iHandicap * Era * Era * 2 (Deity=5)

I propose to use: iHandicap * (a * era * era + b * era + c) where
era = 1..8, iHandicap = 0..7 (Deity=7), a = 1, b = -0.5, c=5

After that feel free to tune the params.

Code:
Era New Old Prop
1  10  35  39
2  40  70  56
3  90 105  88
4 160 140 133
5 250 175 193
6 360 210 266
7 490 245 354
8 640 280 455


View attachment 482277
Quick note. There's no 8th era. Ancient and Classical are both 1. That means this starts off too strong imo given that more events should trigger now. I think it's a great start though.
 
iYieldHandicap = iHandicapBase * ((iHandicapA * iEra) * (iEra + iHandicapB) * iHandicapC)
G, with all the respect, you kinda messed up with the formula... This above formula is equal to
iYieldHandicap = iHandicapBase * C * A * (iEra^2 + B * iEra) and clearly A, B and C here does not work as you stated. I think brackets is not something that you need to use here, they are misleading

Also BonusEarly = C, BonusMid = B, BonusLate = A because when iEra is small C has the biggest impact on the result
 
Last edited:
As stated, C and A have exactly the same impact result, so it doesn't matter which one you denote as early and as late. It is B that is more important early and gets less important later on (because the iEra^2 overcomes the linear one).
 
(x - a) * (x - b) * c, can only be used for curves that touch the x axis, so you are limiting the number of valid solutions. That's why I couldn't write my values into the parametric form.

Also, it's not a direct correlation between a, b, c and the era. C affects height, it moves up and down all the values. B affects the angle of the parabolic, negative values turns right, positive values turns left. C affects convexity, values greater than 1 makes a straight parabolic, between 0 and 1 makes a wide parabolic, and negative values turns the parabolic upside down.

C is going to affect more for the early game, B is more noticeable in mid game, and A rules late game. But for a proper adjustment, C needs to be changed when all three moments are either better or worse, B when two moments are imbalanced and A when it's only one.

At least we have now an idea of what values are good for classical.
 
I like the idea of a neutral trigger, would a trigger every X turns be enough? Seems neutral overall, and X could be tuned to the average rate you'd expect from most AIs throughout a match.
Neutral triggers are difficult to find. Even passing eras rewards those who are advanced. But maybe it can be added bad triggers. For example, there's a trigger for settling and conquering cities. What if there's also a trigger for losing cities? This way, the bonus is not only for the civs that are successful.

Other bad triggers could be losing a wc proposal, suffering a theft and getting rebels.

Edit. This is not rubber banding, since there are already triggers for being successful. This only makes the rewards even between success and failure.
 
Last edited:
Quick note. There's no 8th era. Ancient and Classical are both 1. That means this starts off too strong imo given that more events should trigger now. I think it's a great start though.
You can e.g. use c=3, giving easier start. Formula is easy to tweak.
 
With respect, I feel like the basis for awarding the handicaps is not quite right.

Here's why I think the system used to be as it was: the intent was to pick one AI that was doing well, and give it additional bonuses, to create a challenge for the player - even if the challenge was artificial. This explains why these handicaps never applied to things that poorly-performing AIs would manage to achieve.

Here's what I think we are trying to do: the intent is to try and get all the AIs to mimic the position that a human player of a particular skill level would be in, to create a challenge for the player - but the challenge is not supposed to feel artificial, it is supposed to give a 'flavour' of what it would be like for me to play @CrazyG.

We can't just make an AI that plays like an equivalently skilled player because it would require machine learning. As it is, the AI has @Gazebo's wonderful AI routines, which do a good job, but can't possibly make decisions with the same foresight as the player. Under the new system, the goal should be to give handicaps to the AI to make up for their poor decision-making.

In practical terms, what is AI poor decision-making? It's the lost opportunity costs. If they can pick A and B, and A gives 5 Faith, and B gives 4 Faith, and they pick B, relative to a human, they're 1 Faith down - excusing the very simplistic example. The handicap here would have to be 1 Faith on the choosing of B. Handicaps need to rewarded with respect to choices, not results.

Now, we can distinguish choices on two levels. There are micro choices, and macro choices. Micro choices are: what do I assign each Citizen to work this turn? Which building do I begin next?

Then there are macro choices. Macro choices are: what is my long-term goal? What sort of victory condition am I aiming for? How can I best plan against future wars? Diplomatically, where am I in relation to other civs? What Religious choices and Policies might interact best in the long-term?

The AI does not need much more help at micro choices on Deity. It gets significantly more Citizens than the player, so gets more opportunity to assign a Citizen to the 'correct' tile. It produces building and units faster. It gets bonus XP to help it with picking substandard promotion paths. It produces Wonders faster than the player.

The AI does need help with macro choices. It doesn't really do long-term planning. It has faux long-term planning at best, where particular personality traits weight towards particular decisions, but it's not a proper evaluation. Moreover, it's really hard to adequately reimburse the AI for macro-choices. What is the opportunity cost of a war with Montezuma? Goodness knows, it's almost indeterminate, you can have a vague idea at best.

So we can provide generalized handicaps for the AI on making macro choices. What are the macro-choices - these long-term planning decisions, or planning-decisions with interactive effects?

Here's my list:
  • The tech path the AI follows
  • Security matters - making the decision to go to war, but also making the decision to seek allies, or move troops to a potential defensive border, or to start good trade relations with a potential threat
  • The Religious choices the AI makes
  • The Policy choices the AI makes.
  • Committing to a Wonder - ordinarily, buildings are built so quickly, and are so self-contained (in that they add few effects to other buildings or tiles, barring a few exceptions), I don't think they constitute macro choices, but this is less true of Wonders which do require long-term planning and consideration of the interactive effects.
  • Settling a city - this obviously requires enormous forward-planning
I'm open to others being suggested. Note I have excluded Great People production - I think this is actually closer to a micro choice and I've never felt like the AI struggles to produce or use Great People well.

So here's when I think the AI needs bonus handicap yields:
  • Whenever the AI finishes a tech, to compensate it for the tech it should have picked but didn't
  • Whenever the AI declares war, is declared war upon, or loses a war, or wins a war; to compensate it firstly for diverting resources to a war that may not bring significant gains, and secondly for losing a war it didn't properly foresee where a player would have and therefore didn't prepare for.
  • Whenever the AI makes a Religious choice, or adopts a new Religion (including Religions being spread to it)
  • Whenever the AI chooses a Policy, to compensate it for the policy it should have picked but didn't
  • Whenever the AI completes a Wonder, to compensate it for what it should have produced by didn't
  • Whenever the AI settles a City, to compensate it for misplacing the City relatively to how a player would have
I don't think these handicaps should be equal. They should be greatest for placing Cities and losing a War, since these have the most consequences for the AI and are what players do so much better than an AI relative to other areas. They should be relatively slight for completing a Wonder.

In addition, I don't think these handicaps should pay out in lump amounts, because that doesn't mean the AI mimics a player either. It makes the AI frontloaded.

As a player, when I found a better City than an equivalently positioned AI would, it doesn't pay out immediately. In fact, in the short-run, the AI City is often better, precisely because they don't evaluate long-term and are much better at instant pay-outs. Rather, the difference is in the long-run due to the strategic evaluation of where the City is placed.

So the AI's handicaps need to pay out similarly - start small, and steadily pay off more. Rather than a lump sum on settling a City, the AI needs to be getting an additional amount 50 turns *after* settling the City, if you see what I mean - that's when they're falling behind the equivalent player.

How can we do this? Well, this is my idea: bonus yields are actually continuous. Each time the AI does one of the above, it gets a permanent additional yield income. For example, every time it founds a City, it gets +1 Production/Food/Gold/etc (exact numbers to be discussed) until the end of the game, to mimic the fact the player continuously benefits from their superior placement, instead of a single payment of 50 Production/Food/Gold in one turn.

Thoughts?
 
We also need to examine where the ai is underperforming and where it is overpwerforming via bonuses, I feel like currntly for example the **** ton offree promotions get makes up for the few really dumb moves they make while in war.
Worth noting that bonuses to war should be done very carrefully because not only I have seen wonder spammer ,runawys civs but I also seen conquer half the world runaway civs and for the ai to get bonuses after a conquest to brings massive growth to it really feels artificial wen the player on the smae position receives so many maluses.
 
They should be greatest for placing Cities and losing a War, since these have the most consequences for the AI and are what players do so much better than an AI relative to other areas. They should be relatively slight for completing a Wonder.
I think an issue with a large bonus for placing cities is that it caused big AIs to really outperform smaller ones (even during patches where tall was much stronger for human players). Your opportunity cost analysis is interesting, but I think it misses two big things.

First, we want to avoid causing AI to snowball, which means that bonuses for things that already very positive. An issue with a bonus for something such as completing a tech is that AI which begin ahead will get more bonuses, then move further ahead.

The second is that the bonuses should apply about equally to the various strategies. If you are gettting bonuses for winning wars and taking cities, the tradition civs lag behind. If the bonus is to histoirc events, the tradition civs snowball. If we need to time bonuses to certain events, we should pick some strategy neutral options. Just firing every X turns seems like a reasonable idea to me. Upon entering a new era is fine, losing a war is a fine idea, but rewards for wars, settling, or great people aren't ideal.
 
I think an issue with a large bonus for placing cities is that it caused big AIs to really outperform smaller ones (even during patches where tall was much stronger for human players). Your opportunity cost analysis is interesting, but I think it misses two big things.

First, we want to avoid causing AI to snowball, which means that bonuses for things that already very positive. An issue with a bonus for something such as completing a tech is that AI which begin ahead will get more bonuses, then move further ahead.

The second is that the bonuses should apply about equally to the various strategies. If you are gettting bonuses for winning wars and taking cities, the tradition civs lag behind. If the bonus is to histoirc events, the tradition civs snowball. If we need to time bonuses to certain events, we should pick some strategy neutral options. Just firing every X turns seems like a reasonable idea to me. Upon entering a new era is fine, losing a war is a fine idea, but rewards for wars, settling, or great people aren't ideal.
Every X turns is the most neutral thing I've heard so far. It only needs to be tuned for different game speeds.

Rewarding only civs who lose wars is a rubber-banding mechanic. Rewarding civs who wins and civs who lose wars at the same time is a buff to warmongering. Rewarding the above plus golden ages (if the number of golden ages is a sign of a peaceful playing), is more neutral, but still penalizes isolated civs (no warmongering) that fail at happiness.

So I'd support making the bonus for every X turns, if it can be adjusted for different paces.
 
Instead of a bonus of X every Y turns, which creates strange stop-start momentum, why not just a consistent payout of Z per turn, scaling with the number of turns?
 
Status
Not open for further replies.
Back
Top Bottom