示例#1
0
 /// <summary>
 /// Copy constructor
 /// </summary>
 /// <param name="toClone">The original plan to be copied</param>
 public ProvinceAttackPlan(ProvinceAttackPlan toClone)
 {
     _province      = toClone._province;
     _provinceValue = toClone._provinceValue;
     _orders        = new List <ArmyMovementOrder>();
     for (int i = 0; i < toClone._orders.Count; i++)
     {
         _orders.Add(toClone._orders[i]);
     }
     _combatSimulations     = new List <Combat>();
     _state                 = State.INCOMPLETE;
     _areHeroesInvolved     = toClone._areHeroesInvolved;
     _defendersTrainingCost = toClone._defendersTrainingCost;
 }
示例#2
0
    /// <summary>
    /// Prepare a list of army movement orders for the current turn
    /// </summary>
    /// <returns>List of army movement orders</returns>
    public List <ArmyMovementOrder> SelectMovements()
    {
        // this is our guy to be returned
        List <ArmyMovementOrder> result = new List <ArmyMovementOrder>();

        // this is how many combat simulations we have run for this turn
        int simulationsRan = 0;
        // shouldn't exceed this number
        int maxCombatSimulations = 200;

        // movement orders will depend on the accepted attack plans
        List <ProvinceAttackPlan> plans = new List <ProvinceAttackPlan>();

        // we need to consider all garrisons across our vast empire
        List <Province> provinces = new List <Province>(_faction.GetProvinces().Values);

        // we want to consider the most powerful armies first
        provinces.Sort((x, y) => y.GetUnits().Count.CompareTo(x.GetUnits().Count));
        // no need to pay attention to provinces without garrisons
        provinces.RemoveAll(province => province.GetUnits().Count == 0);

        for (int i = 0; i < provinces.Count; i++)
        {
            if (provinces[i].IsInnerProvince())
            {
                // no enemy neighbors => the move is going to be non-combat
                List <ArmyMovementOrder> orders = SelectNonCombatMoves(provinces[i]);
                if (orders.Count > 0)
                {
                    result.AddRange(orders);
                }
            }
            else
            {
                // plans involving garrison of this particular province
                List <ProvinceAttackPlan> currentPlans = new List <ProvinceAttackPlan>();
                List <Unit> attackers = provinces[i].GetUnits();

                List <Province> targets = provinces[i].GetTargetableNeighbors();
                // consider adding these attackers to an existing invasion plan
                if (_faction.GetAILevel() > 0)
                {
                    for (int j = 0; j < plans.Count; j++)
                    {
                        if (!plans[j].IsIncomplete() && plans[j].GetLoss() > 0)
                        {
                            Province province = plans[j].GetTargetProvince();
                            if (targets.Contains(province))
                            {
                                ProvinceAttackPlan plan = new ProvinceAttackPlan(plans[j]);
                                plan.AddMovementOrder(new ArmyMovementOrder(provinces[i], province, attackers));
                                currentPlans.Add(plan);
                            }
                        }
                    }
                }

                // create new incomplete attack plans
                for (int j = 0; j < targets.Count; j++)
                {
                    ProvinceAttackPlan plan = new ProvinceAttackPlan(targets[j],
                                                                     GameUtils.CalculateProvinceValue(targets[j], _faction));
                    plan.AddMovementOrder(new ArmyMovementOrder(provinces[i], targets[j], attackers));
                    currentPlans.Add(plan);
                }
                currentPlans.Sort((x, y) => y.GetProvinceValue().CompareTo(x.GetProvinceValue()));

                // evaluate plans that seem promising
                double maxScore = -1;
                for (int j = 0; j < currentPlans.Count; j++)
                {
                    ProvinceAttackPlan currentPlan = currentPlans[j];
                    if (simulationsRan < maxCombatSimulations && currentPlan.GetProvinceValue() + currentPlan.GetDefendersTrainingCost() > maxScore)
                    {
                        int numberOfRuns = currentPlan.AreHeroesInvolved() ? 2 * COMBATS_TO_RUN : COMBATS_TO_RUN;
                        int realRuns     = currentPlan.RunCombatSimulations(numberOfRuns, _faction.GetAILevel());
                        simulationsRan += realRuns;
                        maxScore        = Math.Max(maxScore, currentPlan.GetScore());
                    }
                }
                plans.AddRange(currentPlans);
            }
        }
        plans.RemoveAll(plan => plan.IsIncomplete());

        FileLogger.Trace("AI", "Reviewing attack plans");
        List <ProvinceAttackPlan> savedPlans = new List <ProvinceAttackPlan>();
        bool havePlansToReview = true;
        int  plansReviewed     = 0;
        int  maxPlansToReview  = _faction.GetAILevel() == 0 ? 1 : 10;

        while (havePlansToReview && plansReviewed < maxPlansToReview)
        {
            // select the best plan to implement
            double maxScore      = -1;
            int    maxScoreIndex = -1;
            for (int i = 0; i < plans.Count; i++)
            {
                double planScore = plans[i].GetScore();
                if (planScore > maxScore)
                {
                    maxScore      = planScore;
                    maxScoreIndex = i;
                }
            }

            if (maxScoreIndex >= 0)
            {
                ProvinceAttackPlan       currentPlan = plans[maxScoreIndex];
                List <ArmyMovementOrder> movements   = currentPlan.GetMovementOrders();
                result.AddRange(movements);
                string attackOriginDescription = movements[0].GetOrigin().GetName();
                for (int j = 1; j < movements.Count; j++)
                {
                    attackOriginDescription += ", " + movements[j].GetOrigin().GetName();
                }
                FileLogger.Trace("AI", _faction.GetName() + ": will attack province " + movements[0].GetDestination().GetName() + " from [" + attackOriginDescription + "]");
                currentPlan.MarkAccepted();
                savedPlans.Add(currentPlan);
                plans.RemoveAt(maxScoreIndex);
                // iterating plans starting with the highest index
                for (int i = plans.Count - 1; i > -1; i--)
                {
                    if (!plans[i].IsCompatibleWith(movements))
                    {
                        plans[i].MarkRejected();
                        savedPlans.Add(plans[i]);
                        plans.RemoveAt(i);
                    }
                }
            }
            else
            {
                if (result.Count == 0)
                {
                    FileLogger.Trace("AI", _faction.GetName() + ": not attacking anyone");
                }
                havePlansToReview = false;
            }
            plansReviewed++;
            FileLogger.Trace("AI", "Selecting attack plans: pass " + plansReviewed.ToString() + " is done");
        }

        // training units may depend on the attack plans
        SelectTraining(savedPlans);

        return(result);
    }