1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

Version 0.84 discussion thread

Discussion in 'Civ4 - Better AI' started by jdog5000, Feb 12, 2010.

  1. Janov

    Janov Chieftain

    Joined:
    Nov 7, 2009
    Messages:
    20
    As it turns out, it seems that I was wrong on the combat-odds thing. When my pikeman attacked a currasier, the strenght was 6.60 vs 6.66 - yielding 37.something odds. I didn´t notice the disparity in strength, sorry! :blush:

    Move along, nothing to see here :mischief:

    Jan
     
  2. Still_Asleep

    Still_Asleep Warlord

    Joined:
    Apr 5, 2006
    Messages:
    152
    Location:
    Vienna, Austria
    this definitalely happened prior 0.84 as well, sadly I saw this happen quite often. Dont know when it started, but certainly a while ago.
     
  3. Janov

    Janov Chieftain

    Joined:
    Nov 7, 2009
    Messages:
    20
    I agree, this has happened before with single fast stacks. It looks like they don´t check their targets defence value when launchings themselves across the border at some city - but for me the new thing was that the fast units from within a big stack working on dwindling down the defence value would attack right away. I could see the sense in that with some high-withdrawal-chance units to weaken defending siege units. But in my case they were chariots, part of the attacking stack, seemingly attacking prematurely...

    Jan
     
  4. jdog5000

    jdog5000 Revolutionary

    Joined:
    Nov 25, 2003
    Messages:
    2,601
    Location:
    California
    Janov, techno:

    Hmmm ... that is puzzling. What it sounds like is that the fast units are not joining the same attack stack group as the other units, they're forming their own separate stack for some reason.

    I tried recreating this, but for me attack stacks are working properly. I'll keep my eyes open, but what I really need is a save from when the AI decides to send the fast unit stack separately. If anyone sees this and can upload a save from a few turns before it happens, that would be very beneficial.

    As for the incorrect combat odds display, that's not happening for me at all. Would need some more info to track that down.

    Yakk:

    I'll keep my eyes open, that really shouldn't be happening. Is this something you've seen frequently, or a rare occurrence?

    The only way this could happen is if the city's computation of what the best build for a plot is changes while the first set of workers are working. Or, I suppose, if which city is working the plot changes. Should be possible to check when setting city best builds for a plot whether something else is being built and cancel it.
     
  5. Janov

    Janov Chieftain

    Joined:
    Nov 7, 2009
    Messages:
    20
    I could provide a save like the one you required, but I have merged BUG4.2 and BBAI 0.84 - would that still be helpful?

    As for the combat odds, it appears that this was a mistake on my side. They seems to be working properly.

    Thanks, Jan
     
  6. jdog5000

    jdog5000 Revolutionary

    Joined:
    Nov 25, 2003
    Messages:
    2,601
    Location:
    California
    Janov:

    Yes, the save should still be helpful. If for some reason I can't load it, then a Worldbuilder save would probably work. Thanks.
     
  7. Janov

    Janov Chieftain

    Joined:
    Nov 7, 2009
    Messages:
    20
    Hi Jdog,

    I have a save that is right on the turn before they attack. Look at the city on the very left. To the left of it is the attacking stack, it was dropped of by a bunch of galleons. If you hit the "turn" button, the chariots in the stack will attack. I don´t know if they are considered "seperate stacks" as far as game mechanics are concerned, but they were all dropped of the same turn, as far as I can tell.

    Hope this helps, Jan

    View attachment AutoSave_AD-1770.CivBeyondSwordSave
     
  8. jdog5000

    jdog5000 Revolutionary

    Joined:
    Nov 25, 2003
    Messages:
    2,601
    Location:
    California
  9. jdog5000

    jdog5000 Revolutionary

    Joined:
    Nov 25, 2003
    Messages:
    2,601
    Location:
    California
    Thank you for posting and following up Janov! I figured out the bug causing the suicide chariots. The logic for having the AI group its units into attack stacks is written for when the AI is forming stacks in its own territory ...

    The strongest land unit the Chinese (and the Arabs) can build are knights, so the AI is using the strategy FAST_MOVERS where it builds more fast units and tries to have stacks of fast units. The UNITAI_COUNTER chariots the Chinese brought along were happy to join a stack of slower units on their main continent where they're running AREAAI_ASSAULT (invasion logic), but once they land in the new area where they're running AREAAI_OFFENSIVE, then they refuse to join the slower units.

    This poor behavior has been around forever it seems, thanks for spotting it! It's a kind of rare confluence of factors that cause the chariots to suicide attack but not the rest of the stack in this case, making an otherwise very difficult bug to spot very apparent!

    Will be fixed in the next version.

    My suspicion was that the strategy FAST_MOVERS was involved, and it's almost certainly the cause of the other report (knights moving in ahead of slow stack). I can understand why it's a cool idea to have the AI press its advantage with fast units, but it doesn't seem to play well ... plus, a stack of just Knights or just Cavalry are too easy to counter and have little hope of capturing a fortified city. Might be best to drop this strategy entirely until the modern era where there are multiple types of fast units available.

    (BTW, very interesting situation you've got yourself in ... I hope you can handle the invasions!)
     
  10. Janov

    Janov Chieftain

    Joined:
    Nov 7, 2009
    Messages:
    20
    I do have a tendency to get myself into situations like this :D It usually doensn´t go well for long...

    I am happy that I was able to contribute with BBAI!

    Jan
     
  11. PieceOfMind

    PieceOfMind Drill IV Defender Retired Moderator

    Joined:
    Jan 15, 2006
    Messages:
    9,319
    Location:
    Australia
    Ok, I'm wanting to raise the issue with forest preserves again.

    Just a reminder that in PIG mod FPs are available with Monarchy and Lumbermills are available relatively early as well, at Guilds.

    I've made sure not to make the mistake of leaving the option checked "workers leave forests" in all my recent tests using AI autoplay and I'm still seeing very poor decision making with respect to these two improvements. It's not uncommon to see the classic "oscillation" problem, that used to happen with cottages/workshops/ now happening with lumbermills (LMs) and forest preserves (FPs). I will watch a worker stand on a forest and not move off it, continuously building FP after LM after FP.

    Obviously this is going to have a negative impact on the AI's performance.

    I've tried looking at the code but am having difficulty making much sense of it. However, I was able to narrow my attention to this piece of code in CvCityAI.cpp:

    Code:
    					int iHappiness = GC.getImprovementInfo(eFinalImprovement).getHappiness();
    					if ((iHappiness != 0) && !(GET_PLAYER(getOwnerINLINE()).getAdvancedStartPoints() >= 0))
    					{
    						int iHappyLevel = iHappyAdjust + (happyLevel() - unhappyLevel(0));
    						if (eImprovement == pPlot->getImprovementType())
    						{
    							iHappyLevel -= iHappiness;
    						}
    						int iHealthLevel = (goodHealth() - badHealth(false, 0));
    						
    						int iHappyValue = 0;
    						if (iHappyLevel <= 0)
    						{
    							iHappyValue += 400;
    						}
    						bool bCanGrow = true;// (getYieldRate(YIELD_FOOD) > foodConsumption());
    						
    						if (iHappyLevel <= iHealthLevel)
    						{
    							iHappyValue += 200 * std::max(0, (bCanGrow ? std::min(6, 2 + iHealthLevel - iHappyLevel) : 0) - iHappyLevel);
    						}
    						else
    						{
    							iHappyValue += 200 * std::max(0, (bCanGrow ? 1 : 0) - iHappyLevel);
    						}
    						if (!pPlot->isBeingWorked())
    						{
    							iHappyValue *= 4;
    							iHappyValue /= 3;
    						}
    						iHappyValue += std::max(0, (pPlot->getCityRadiusCount() - 1)) * ((iHappyValue > 0) ? iHappyLevel / 2 : [B]200[/B]);
    						iValue += iHappyValue * iHappiness;
    					}
    
    My guess is that on that line:
    Code:
    iHappyValue += std::max(0, (pPlot->getCityRadiusCount() - 1)) * ((iHappyValue > 0) ? iHappyLevel / 2 : [B]200[/B]);
    (pPlot->getCityRadiusCount() - 1)) is often 1, and the expression it is being multiplied by often equates to 200.

    My fairly direct question I guess, is "Why is that last part of the multiplication returning 200 when the boolean test is negative?"
    If 200 is arbitrary then it's almost certainly too high.

    I see the number 200 a lot for the AI's valuation of FPs.

    I would happily look into changing some of the logic here myself if someone can give me a brief desccription of the meaning of some of the functions/variables here. e.g.
    iHappyAdjust, happyLevel(), unhappylevel(0)

    I'm also suspicious of the logic on this:
    Code:
    bool bCanGrow = true;// (getYieldRate(YIELD_FOOD) > foodConsumption());
    As in, why is the logic commented out?
     
  12. jdog5000

    jdog5000 Revolutionary

    Joined:
    Nov 25, 2003
    Messages:
    2,601
    Location:
    California
    That is a mess ... yikes. Thanks for keeping the focus on FPs!

    The line you highlighted makes no sense ... first of all, I'm quite certain that iHappyValue is always > 0. The true : false options there are also just too different ... iHappyLevel will be between -10 to +10 maybe, it's just non-sensical. What that piece is supposed to do is be the boost for having a tile which lies in the BFC of multiple cities, I believe the happiness benefit is applied to all the cities.

    Anyway, if you can make sense of this code that would be a great service. To help you get started:

    iHappyAdjust = happiness boost/penalty of buildings and improvements currently being constructed in and around city

    happyLevel() = number of happy faces in the city, the smiley part of the tool tip in the city screen for happiness

    unhappyLevel(0) = number of unhappy faces in the city, where the 0 means "with 0 extra population" (so unhappyLevel(1) would tell you how many unhappy faces the city would have after growing one pop point)

    The health functions work the same way.

    bCanGrow - At first glance I kind of agree with the programmers decision to have this always be on ... the two things it controls seem like they work better with bCanGrow always true. Tieing improvement value too much to current food production could cause improvement cycling issues, and iHappyLevel is good measure of whether a city can/should grow for these purposes.
     
  13. LunarMongoose

    LunarMongoose King

    Joined:
    Jan 29, 2006
    Messages:
    731
    Gender:
    Male
    Location:
    Boston, MA, USA
    I just want to say... I am really glad you guys are on top of this particular situation, because it means I don't have to be. lol.

    p.s. - I just discovered this show on Science Channel called Mantracker, which is actually pretty neat... Okay, shutting up now.
     
  14. Fuyu

    Fuyu Emperor

    Joined:
    Nov 5, 2009
    Messages:
    1,225
    Location:
    Austria
    To me it looks like the FP get their value properly, whether they are already built or not, and LM gets nothing. Which is a bit different from the yieldchange valuation, where the difference to the old improvement is what gives the value. Still, on a linear scale that shouldn't matter.
    And as jdog said, unless the AI is oscillating FP & LM only on tiles that are in the city radius of at least 2 cities, you are on the wrong track there.

    edit: @PoM: if you want to try something, here is my attempt to make the difference to the previous improvement count, instead of simply always adding the FP bonus. Should also work as expected if that difference is negative and/or bigger than 1 absolute (like when building a shaft mine over a forest preserve where diff would be -2)
    Spoiler :
    Code:
    					[COLOR="Green"]//int iNewHappiness = GC.getImprovementInfo(eFinalImprovement).getHappiness();
    					//int iCurHappiness = GC.getImprovementInfo(eCurFinalImprovement).getHappiness();
    					//int iHappinessDiff = iNewHappiness - iCurHappiness;[/COLOR]
    
    					int iHappinessDiff = GC.getImprovementInfo(eFinalImprovement).getHappiness() - ((eCurFinalImprovement != NO_IMPROVEMENT)? GC.getImprovementInfo(eCurFinalImprovement).getHappiness() : 0);
    					if ((iHappinessDiff != 0) && !(GET_PLAYER(getOwnerINLINE()).getAdvancedStartPoints() >= 0))
    					{
    						bool bIsNegative = false;
    						if (iHappinessDiff < 0)
    						{
    							bIsNegative = true;
    							iHappinessDiff = -iHappinessDiff;
    						}
    
    						int iHappyLevel = iHappyAdjust + (happyLevel() - unhappyLevel(0)) + getEspionageHappinessCounter();
    						int iHealthLevel = std::max(0, iHealthAdjust) + (goodHealth() - badHealth(false, 0)) + getEspionageHealthCounter();
    					
    						for (iJ = 0; iJ < iHappinessDiff; iJ++)
    						{
    							int iHappyValue = 0;
    
    							if (bIsNegative)
    							{
    								iHappyLevel--;
    							}
    
    							if (iHappyLevel <= 0)
    							{
    								iHappyValue += 400;
    							}
    							bool bCanGrow = true;[COLOR="Green"]// (getYieldRate(YIELD_FOOD) > foodConsumption());[/COLOR]
    						
    							if (iHappyLevel <= iHealthLevel)
    							{
    								iHappyValue += 200 * std::max(0, (bCanGrow ? std::min(6, 2 + iHealthLevel - iHappyLevel) : 0) - iHappyLevel);
    							}
    							else
    							{
    								iHappyValue += 200 * std::max(0, (bCanGrow ? 1 : 0) - iHappyLevel);
    							}
    							if (!pPlot->isBeingWorked())
    							{
    								iHappyValue *= 4;
    								iHappyValue /= 3;
    							}
    
    							[COLOR="Green"]//iHappyValue += std::max(0, (pPlot->getCityRadiusCount() - 1)) * ((iHappyValue > 0) ? iHappyLevel / 2 : 200);[/COLOR]
    							iHappyValue += (pPlot->getPlayerCityRadiusCount(getOwnerINLINE()) - 1) * ((iHappyValue > 0) ? 200 : 50);
    
    
    							if (!bIsNegative)
    							{
    								iHappyLevel++;
    								iValue += iHappyValue;
    							}
    							else
    							{
    								iValue -= iHappyValue;
    							}
    						}
    					}
     
  15. PieceOfMind

    PieceOfMind Drill IV Defender Retired Moderator

    Joined:
    Jan 15, 2006
    Messages:
    9,319
    Location:
    Australia
    Oi, you're not off the hook yet - get to work mister! :lol:

    Problems do seem to be greater when the forest is in the BFC of more than one city, though this is a loose observation. I cannot definitely say whether or not I've seen the oscillation problems in forests in single BFCs.

    Also, the observation made by Fuyu that it seems to be right for FPs but not LMs sounds to me like it's on the right track. When I checked the improvement valuations before and after the changed improvement, the FP valuation didn't change my much I don't think. I think the problem may indeed be with the LM side of things.

    I'll try your code Fuyu, thanks. My time for working on this stuff is pretty limited at the moment, so I could be pretty slow in getting anything done about this. If Fuyu or LunarMongoose (or jdog) find a suitable fix in the meantime, I'd probably go with that. :) Besides, I think you all have more C++ experience than I do (that's the cop out answer :lol:).

    Finally, I'd like to point out that I'm pretty sure the problems are evident in UG versions of the game. After Scientific Method, any remaining forests will probably reveal the worker behaviour I'm complaining about. I guess I'm pointing out the obvious, but it's not a problem unique to the early game, and hence not unique to PIG Mod.
     
  16. Fuyu

    Fuyu Emperor

    Joined:
    Nov 5, 2009
    Messages:
    1,225
    Location:
    Austria
    I never said it doesn't work for LMs, I said it's handling happy differently from yield. My changes should make differences in happiness count, instead of just the happy bonus itself, that change however should not change what the bestbuild for a tile is - which should in the end still slow down oscillation, it should NOT fix it though.
    As for the line
    iHappyValue += std::max(0, (pPlot->getCityRadiusCount() - 1)) * ((iHappyValue > 0) ? iHappyLevel / 2 : 200);
    I still have no clue what iHappyLevel / 2 means there, so I replaced that line with something that makes sense to me. No clue if that fixes anything though.

    Improvement oscillation is not unique to your mod, I know. And that has nothing to do with happy value either, the issue lies deeper: it's just the way bestbuild works in general, with its emphasizing one yield type one turn, and a different yield type the next - toning down emphasis as a whole might limit the problem, but there's still the issue that this function doesn't look into the future (it should know what will happen when the improvement on the current tile improvement completes; and much more complicated: if other workers are improving the same city, what they build would need to be taken into account too).
    Fixing those issues does not look all that simple.

    Also PoM, you said you checked improvement values? Screw that, really. The AI_getImprovementValue() numbers you see on screen and the values from AI_bestPlotBuild() are different, simply because those functions have little to do with each other - apart from trying to valuate improvements. I dare you to put each funcion into a different file and compare them (diff).
    Watching worker behaviour is all you can do unless you want do some work on getImprovementValue() to make it return actually useful numbers.
    Also, if you try my code, be sure to apply the changes to AI_bestPlotBuild() - applying it only to the other function will change your onscreen numbers but the AI will behave the same way as before.
     
  17. Ninja2

    Ninja2 Great Engineer

    Joined:
    Nov 17, 2005
    Messages:
    1,142
    Location:
    Denmarkia
    If you mean that the fast movers should try and make succesful flanking attacks, then recall that you cannot do flank attacks to siege units in cities or forts.
     
  18. Janov

    Janov Chieftain

    Joined:
    Nov 7, 2009
    Messages:
    20
    Wow, I have been playing Civ4 for years and didn´t even know that! :eek:

    Thanks, Jan
     
  19. PieceOfMind

    PieceOfMind Drill IV Defender Retired Moderator

    Joined:
    Jan 15, 2006
    Messages:
    9,319
    Location:
    Australia
    Yes, a siege-loaded fort is a dangerous place for a stack to pass by.

    IMO, it would be cool if AIs learnt/knew this (I'm not sure if they do or not, but I doubt it). Build a fort in one of their non-BFC tiles or non-valuable BCF tiles near the lines of an enemy or soon-to-be enemy, load it up with some siege units and a couple CG defenders.
    Could take quite a bit of effort though and it is very tactical, so may not be of much real benefit at all. It would be cool though. :)
     
  20. Andy06r

    Andy06r Chieftain

    Joined:
    Jun 10, 2007
    Messages:
    89
    Check this picture - why is the city AI recommending that tile, of all things? The one I'm moving too is far better - there is a 2nd fish within the BFC that is out of the picture.

    I've noticed in a few games that the AI is building some questionable cities and is building wonders extremely early in the game - I've seen stonehenge finished around the turn 30-40 mark.
     

Share This Page