Ejemplo n.º 1
0
        /*
         * Perform all calculations that occur during a sub armies invasion of a city.
         * Assault template records some calculated values used in the FDiv process to prevent redundant calculations
         * Any sub army in the invasion is assumed to be strong enough to capture the corresponding fort
         * Once the fort is captured, the army will have it's health reduced, and if any healers are left alive, will heal
         * Once each army has performed attack/healing, they will be merged into a new army.
         * Remaining forts are merged into a new nation
         * New army/nation objects are created to prevent deep/shallow copy issues
         */
        public SearchState Ftrans(SearchState initialState, InvasionWave transition)
        {
            List <ArmyBlueprint> armiesAfterAttack = new List <ArmyBlueprint>();
            List <Fortification> captured          = new List <Fortification>();

            for (int subArmyIdx = 0; subArmyIdx < transition.Wave.Count; ++subArmyIdx)
            {
                AssaultTemplate assaultTemplate = transition.Wave[subArmyIdx];
                // run assault simulation. Capture fort, deal damage to invaders, and heal up after if possible
                ArmyBlueprint afterAssault = assaultTemplate.AssaultFortification();
                armiesAfterAttack.Add(afterAssault);
                // was there an unneccessary step in keeping units in reserve. Was not able to heal and could have contributed to the taking of a fort
                if (assaultTemplate.ToAssault.IsPlaceHolderFort && assaultTemplate.Attackers.CalculateArmyValue() == afterAssault.CalculateArmyValue())
                {
                    // assert false;
                    return(null);
                }
                if (!assaultTemplate.ToAssault.IsPlaceHolderFort) // fort used to simulate units held in reserve
                {
                    captured.Add(assaultTemplate.ToAssault);
                }
            }

            return(new SearchState(ArmyBlueprint.MergeSubArmies(armiesAfterAttack), new NationBlueprint(initialState.Prob.NationBlueprint, captured), initialState.Depth + 1, initialState, transition));
        }
Ejemplo n.º 2
0
 public SearchState(ArmyBlueprint army, NationBlueprint defender, int depth, SearchState parent, InvasionWave fromParent)
 {
     if (depth == 0)
     {
         sStateNumber = 0;
     }
     mStateNumber         = sStateNumber++;
     Depth                = depth;
     Prob                 = new Prob(army, defender);
     ParentProblem        = parent;
     TransitionFromParent = fromParent != null ? new InvasionWave(fromParent.Wave) : null;
 }
Ejemplo n.º 3
0
        /*
         * Recurses through all possible army combinations into sub armies to attack each border city provided.
         * Checks if the sub army will be able to capture the assigned fort, and if not discards the combination
         * Sub Army combinations are cached to prevent situations such as 3 soldiers with the same health being split into armies of size 1 and being treated as distinct
         * Caching system uses a similarity value defined in Common Constants.
         * TODO: the similarity factor is too simplistic and should be scaled based on percent health, and how close to death the unit is, rather than a fixed value
         */
        private static void RecurseFdiv(ArmyBlueprint armyToSubdivide, int currentGroup, List <Fortification> toCapture, InvasionWave currentWave, List <InvasionWave> possibleInvasionWaves, bool keepArmyTogether)
        {
            if (currentGroup == toCapture.Count - 1) // last fort to capture
            {
                if (!armyToSubdivide.IsEmpty)        // units left over to subdivide
                {
                    // put all units in last invasion group
                    // ASSUMPTION: Last fort is always a place holder fort
                    currentWave.Wave.Add(AssaultTemplate.GetAssualtTemplate(toCapture[currentGroup], armyToSubdivide));
                }
                // add invasion wave to possible solutions
                possibleInvasionWaves.Add(currentWave);
            }
            else if (armyToSubdivide.IsEmpty) // No units left to allocate to the remaining sub armies
            {
                // add invasion wave up to this point to return list
                possibleInvasionWaves.Add(currentWave);
            }
            else
            {
                int           armySize = armyToSubdivide.Size; // num remaining units to subdivide
                long          numDifferentCombinations = (long)Mathf.Pow(2, armySize);
                IteratorCache invasionCache            = new IteratorCache();

                // iterate through all possible bitwise combinations of the subarmy
                // Combinations begin with all units being added as it orrients the leaf list to have a higher chance of
                // a successful solution and arriving at optimization values quicker.
                // Doing in reverse order (ie combinationNumber = 0, combinationNumber < NumDifferentCombinations) will
                // bias all units to be in reserve and take longer to arrive at a solution
                for (long combinationNumber = numDifferentCombinations - 1; combinationNumber >= 0; combinationNumber--)
                {
                    ArmyBlueprint subArmy       = new ArmyBlueprint();
                    ArmyBlueprint remainingArmy = new ArmyBlueprint();

                    #region Create SubArmy from combination number
                    BitArray combinationArray = new BitArray(System.BitConverter.GetBytes(combinationNumber));
                    for (int j = 0; j < armySize; ++j)
                    {
                        if (j < armyToSubdivide.Soldiers.Count) // bit represents a soldier
                        {
                            if (combinationArray[j])            // put soldier in sub army
                            {
                                subArmy.Soldiers.Add(armyToSubdivide.Soldiers[j]);
                            }
                            else // keep soldier in reserve
                            {
                                remainingArmy.Soldiers.Add(armyToSubdivide.Soldiers[j]);
                            }
                        }
                        else if (j < armyToSubdivide.Soldiers.Count + armyToSubdivide.Healers.Count) // bit is a healer
                        {
                            if (combinationArray[j])                                                 // put healer in sub army
                            {
                                subArmy.Healers.Add(armyToSubdivide.Healers[j - armyToSubdivide.Soldiers.Count]);
                            }
                            else // keep healer in reserve
                            {
                                remainingArmy.Healers.Add(armyToSubdivide.Healers[j - armyToSubdivide.Soldiers.Count]);
                            }
                        }
                        else // bit represents an archer
                        {
                            if (combinationArray[j]) // put archer in sub army
                            {
                                subArmy.Archers.Add(armyToSubdivide.Archers[j - armyToSubdivide.Soldiers.Count - armyToSubdivide.Healers.Count]);
                            }
                            else // keep archer in reserve
                            {
                                remainingArmy.Archers.Add(armyToSubdivide.Archers[j - armyToSubdivide.Soldiers.Count - armyToSubdivide.Healers.Count]);
                            }
                        }
                    }
                    #endregion

                    // Only consider iteration if it can capture the city it was tasked to take
                    if (combinationNumber == 0) // Empty sub army.
                    {
                        InvasionWave recursiveTransitionCopy = new InvasionWave(currentWave.Wave);
                        RecurseFdiv(remainingArmy, currentGroup + 1, toCapture, recursiveTransitionCopy, possibleInvasionWaves, keepArmyTogether);
                    }
                    else if (!mIsOptimized || !invasionCache.IsCached(subArmy))
                    {
                        // check is assualt will be successful and record values in assault template
                        AssaultTemplate assaultTemplate = AssaultTemplate.GetAssualtTemplate(toCapture[currentGroup], subArmy);
                        if (assaultTemplate != null /* is valid assault */)
                        {
                            invasionCache.Cache(subArmy);
                            InvasionWave recursiveTransitionCopy = new InvasionWave(currentWave.Wave);
                            recursiveTransitionCopy.Wave.Add(assaultTemplate);
                            // recurse with remaining units not included in this sub army
                            RecurseFdiv(remainingArmy, currentGroup + 1, toCapture, recursiveTransitionCopy, possibleInvasionWaves, keepArmyTogether);
                        }
                        // else discard combination
                    }

                    // Used for linear invasion strategies to prevent unneccessary combination checks.
                    // jump to putting the army in reserve if it wasn't assigned to a fort
                    if (keepArmyTogether && combinationNumber == numDifferentCombinations - 1) // first sub army created
                    {
                        combinationNumber = 1;                                                 // will become 0 next loop iteration and second army option will be empty
                    }
                }
            }
        }