Announcement

Collapse
No announcement yet.

Possible inefficient code in AI_assaultSeaMove?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Possible inefficient code in AI_assaultSeaMove?

    I have been reviewing the code in CvUnitAI.cpp, function AI_assaultSeaMove, for Beyond the Sword 3.17, and I am finding a curious section of code, which is the following:

    if (bEmpty)
    {
    if (AI_anyAttack(1, 65))
    {
    return;
    }
    if (AI_anyAttack(1, 40))
    {
    return;
    }
    }

    The thing that I am finding curious is the fact that AI_anyAttack gets checked twice: first with a second argument of 65, second with a second argument of 40. From reviewing the code for AI_anyAttack, it seems to me that the above code is identical to the following:

    if (bEmpty)
    {
    if (AI_anyAttack(1, 40))
    {
    return;
    }
    }

    If I understand AI_anyAttack at its most basic level, it is testing to see if you have at least a [second argument] odds of winning a battle against any enemy unit within a range of [first argument]. Let us consider a very basic scenario with the code that AI_assaultSeaMove is using: There is only one enemy unit within the range of a transport unit that is empty, and there is a 50% chance that the transport unit will win the battle. So AI_anyAttack(1, 65) gets called, and ignoring any extreme calculations that it may do, it returns false because 50 is less than 65. So then AI_anyAttack(1, 40) gets called, but (again ignoring any extreme calculations) it returns true because 50 is greater than 40.

    So why is AI_anyAttack(1, 65) being utilized in the code even though AI_anyAttack(1, 40) is called right after it? Isn't AI_anyAttack(1, 65) useless code for situations where the odds are between 40 and 64? I could understand this code being utilized if there was another section of code between the two if statements or if AI_anyAttack was not returning the weakest unit to attack, but this appears to not be the case. Also, I don't see any random calculations that are being done in AI_anyAttack that would result in a situation where AI_anyAttack(1, 65) would return true but AI_anyAttack(1, 40) would return false for a given unit. Am I missing something, or is calling AI_anyAttack(1, 65) inefficient code? Can somebody explain a situation where we would actually need AI_anyAttack(1, 65)?

  • #2
    Perhaps one refers to the transport, and the second refers to the units on the transport?
    No matter where you go, there you are. - Buckaroo Banzai
    "I played it [Civilization] for three months and then realised I hadn't done any work. In the end, I had to delete all the saved files and smash the CD." Iain Banks, author

    Comment


    • #3
      Could it be for stack attacks, that it will go for the higher worse odds for the first attack if it can get better odds on the second attack
      It's almost as if all his overconfident, absolutist assertions were spoonfed to him by a trusted website or subreddit. Sheeple
      RIP Tony Bogey & Baron O

      Comment


      • #4
        Rah, "higher worse odds" is not a combination of terms you see every day. I take it you mean it will take decreased initial odds, if attack two will get better odds. Yes?
        No matter where you go, there you are. - Buckaroo Banzai
        "I played it [Civilization] for three months and then realised I hadn't done any work. In the end, I had to delete all the saved files and smash the CD." Iain Banks, author

        Comment


        • #5
          Picky picky picky. (YES, THAT"S WHAT I MEANT) but I do believe it relates to multiple attacks.
          Look how often a large stack will attack when the odds of the AI winning the first combat is quickly approaching Zero. (and the second and the third no less)
          It's almost as if all his overconfident, absolutist assertions were spoonfed to him by a trusted website or subreddit. Sheeple
          RIP Tony Bogey & Baron O

          Comment


          • #6
            Thanks Blaupanzer and rah for your ideas, but I am not quite in agreement. The heart of the code in AI_anyAttack is the following:

            iValue = getGroup()->AI_attackOdds(pLoopPlot, true);
            if (iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
            {
            if (iValue > iBestValue)
            {
            iBestValue = iValue;
            pBestPlot = ((bFollow) ? pLoopPlot : getPathEndTurnPlot());
            FAssert(!atPlot(pBestPlot));
            }
            }

            This is within two for loops that are looping on plots within the unit's movement area. I believe the point of these two if statements that are within the two for loops is to try to get the "best" enemy unit to attack, with "best" meaning the enemy unit that is the weakest. Yes, a transport unit within a stack will attack an enemy unit that it has low odds against, but this is only because of the following code in AI_finalOddsThreshold:

            if ((getDomainType() == DOMAIN_SEA) && !getGroup()->hasCargo())
            {
            iFinalOddsThreshold *= 3;
            iFinalOddsThreshold /= 2 + getGroup()->getNumUnits();
            }

            But even if we consider a more complicated situation where a unit is within a large group, I don't see the point of having AI_anyAttack(1, 65) if we are calling AI_anyAttack(1, 40). Consider a transport unit that is part of a group of four units. If we throw in the AI_finalOddsThreshold calculation noted above, then the odds would be about 65 / (2 + 4) = 10.8 for AI_anyAttack(1, 65) (I am ignoring other small calculations that AI_finalOddsThreshold may do, but these should be minor anyways). For AI_anyAttack(1, 40), it would be 40 / (2 + 4) = 6.67. If (iValue > iBestValue) would have been true for AI_anyAttack(1, 65), then AI_anyAttack(1, 40) certainly also would have been true, because if iValue was 20, then 20 is greater than 10.8, and 20 is certainly greater than 6.67.

            I guess the main problem I am having is I am not seeing a situation where AI_anyAttack(1, 65) would have returned true, but AI_anyAttack(1, 40) would have returned false and therefore we need AI_anyAttack(1, 65) in order to make the AI act smarter. Let's consider another situation: AI_anyAttack(1, 65) finds five potential enemy units to attack with successful odds of 80, 70, 60, 50, and 35. 60, 50, and 35 are thrown out because it is not greater than 65 (in a very basic situation). So we are left with 70 and 80. However, 80 is chosen because of the heart of the code in AI_anyAttack that I outlined above. Wouldn't AI_anyAttack(1, 40) have kept 80, 70, 60, 50, but not 35, but yet 80 still would have been chosen due to the heart of the code? So why call AI_anyAttack(1, 65) when AI_anyAttack(1, 40) would have found the best enemy unit to attack anyways?

            Comment


            • #7
              AI_anyAttack(1, 65) indeed seems irrelevant.

              By the way, I doubt rah or Blaupanzer know anything about C++, so it's kinda pointless asking this question here. I'd suggest to check out the Better BTS AI project by jdog5000, which modifies AI sea assaults and many other things!
              Contraria sunt Complementa. -- Niels Bohr
              Mods: SMAniaC (SMAC) & Planetfall (Civ4)

              Comment

              Working...
              X