public SearchResults(long numLeafsCreated, long numSolutionsFound, InvasionSolution defaultSolution, InvasionSolution optimizedSolution) { SearchTimeSeconds = -1; NumLeafsCreated = numLeafsCreated; NumSolutionsFound = numSolutionsFound; DefaultSolution = defaultSolution; OptimizedSolution = optimizedSolution; }
/* * Driver for search logic. * i) Check if the chosen state is solved, and if so update solution records accordiningly * ii) If not solved, check for preliminary qualities that would disqualify this sub problem from being searched * iii) If not disqualified, run a recursive division on the invading army into all possible invasion groupings * Each combination found will be added as a new leaf on the tree */ public void Search(SearchState chosenState, bool keepArmyTogether) { if (chosenState.IsSolved) { mNumLeafsCreated++; #region SolutionFound // Check if the solution is relevant depending on which optimizations are being used and solution quality bool updateSolution = false; bool recordSolution = false; int numStepsInInvasion = chosenState.Depth; if (mBestSolution == null) // havent found a solution yet { recordSolution = updateSolution = true; if (mIsOptimized) { // only accept solutions that occur in as many turns as the new solution mMaxDepthOfTree = numStepsInInvasion; } } else if (numStepsInInvasion < mBestSolutionDepth) // found a quicker invasion strategy { recordSolution = updateSolution = true; mBestSolution = null; // reset solution tracking if (mIsOptimized) { mNumSolutionsFound = 0; mMaxDepthOfTree = numStepsInInvasion; } } else if (mBestSolutionDepth == numStepsInInvasion) // occurs in the same number of turns as previous solutions { recordSolution = true; if (chosenState.Prob.InvadingArmy.CalculateArmyValue() > mBestSolutionArmyValue) { updateSolution = true; } } else // worse quality of solution { recordSolution = !mIsOptimized; } if (recordSolution) { mNumSolutionsFound++; } // Create and store new solution if (updateSolution) { mBestSolution = ToSolution(chosenState, mInitialArmy, mInitialNation); mBestSolutionDepth = numStepsInInvasion; mBestSolutionArmyValue = chosenState.Prob.InvadingArmy.CalculateArmyValue(); } #endregion } else // sub problem is not solved. Check if sub problem can be divided { if (mBestSolution == null) // record partial solutions until an actual solution is found { if (mBestPartialSolution == null) { mBestPartialSolution = chosenState; mBestPartialSolutionValue = chosenState.Prob.ProblemValue; } else { // only update partial solution if it was able to take more cities than the previous, regardless of better army value if (chosenState.Prob.NationBlueprint.NumCitiesRemaining < mBestPartialSolution.Prob.NationBlueprint.NumCitiesRemaining) { float probValue = chosenState.Prob.ProblemValue; if (probValue < mBestPartialSolutionValue) { mBestPartialSolution = chosenState; mBestPartialSolutionValue = probValue; } } } } // check for disqualifying features of invasion state bool validState = true; if (chosenState.ParentProblem != null) { if (chosenState.ParentProblem.StateValue == chosenState.StateValue) // army did not heal nor was a city taken { // do nothing, this state didn't progress the invasion validState = false; } } // took more turns to complete than our max turn limit if (mMaxDepthOfTree != -1 && mIsOptimized && chosenState.Depth >= mMaxDepthOfTree) { validState = false; } // valid subproblem. Add all new leafs possible from this state if (validState) { List <SearchState> subProblems = Fdiv(chosenState, keepArmyTogether); mNumLeafsCreated += subProblems.Count; foreach (SearchState subProblem in subProblems) { mOpenLeafs.AddLast(subProblem); } } else { mNumLeafsCreated++; } } }
public SearchResults SearchForSolutions(ArmyBlueprint attackers, NationBlueprint defenders, bool optimize) { mInitialArmy = attackers; mInitialNation = defenders; mIsOptimized = true; /* = optimize; Replace after data collection*/ // Initialize start variables and start invasion search SearchState initialState = new SearchState(attackers, defenders, 0, null, null); mOpenLeafs.Clear(); // orrient the nations layout relative to the army. TODO: allow for dynamic invasion direction initialState.Prob.NationBlueprint.BeginInvasion(Vector2.right); // Do the default search keeping the units together mOpenLeafs.AddLast(initialState); mPruneSolutions = true; // only care about the best solution with army grouped up. Only record mMaxDepthOfTree = mBestSolutionDepth = -1; // max depth = -1 until a solution is found creating a limit to depth // Search for solutions with linear invasion strategy while (mOpenLeafs.Count > 0) { SearchState pop = mOpenLeafs.Last.Value; mOpenLeafs.RemoveLast(); Search(pop, true); } // record default invasion stats InvasionSolution linearSolution = null; if (mBestSolution == null) // no solution was found { // record the best result possible linearSolution = ToSolution(mBestPartialSolution, mInitialArmy, mInitialNation); } else { linearSolution = mBestSolution; } int bestLinearDepth = linearSolution != null ? mBestSolutionDepth : -1; // update the max depth of the optimized search to be the depth of the default time mMaxDepthOfTree = bestLinearDepth; //Debug.Log("Best Case Group Scenario took " + mMaxDepthOfTree + " turns to complete, needing " + (mMaxDepthOfTree - initialState.Prob.NationBlueprint.NumCitiesRemaining) + " turns to heal"); // reset search variables for the optimized search mPruneSolutions = optimize; mOpenLeafs.Clear(); mBestSolution = null; mBestPartialSolution = null; mOpenLeafs.AddLast(initialState); // search for parallel attack strategy solutions while (mOpenLeafs.Count > 0) { SearchState pop = mOpenLeafs.Last.Value; mOpenLeafs.RemoveLast(); Search(pop, false); } // Record optimized Solution InvasionSolution parallelSolution = null; if (mBestSolution == null) { parallelSolution = ToSolution(mBestPartialSolution, mInitialArmy, mInitialNation); } else { parallelSolution = mBestSolution; } int bestOptimizedDepth = parallelSolution != null ? mBestSolutionDepth : -1; return(new SearchResults(mNumLeafsCreated, mNumSolutionsFound, linearSolution, parallelSolution)); }