Ejemplo n.º 1
0
        private RequirementGroupViewModel FindBestMatch(RequirementGroupViewModel needle, IEnumerable <RequirementGroupViewModel> haystack)
        {
            RequirementGroupViewModel bestMatch = null;
            int bestMatchCount = 0;
            var requirementExs = RequirementEx.Combine(needle.Requirements.Select(r => r.Requirement));

            foreach (var potentialMatch in haystack)
            {
                // convert to requirement clauses and compare
                var compareRequirementExs = RequirementEx.Combine(potentialMatch.Requirements.Select(r => r.Requirement));
                int matchCount            = compareRequirementExs.Count;

                foreach (var requirementEx in requirementExs)
                {
                    for (int i = 0; i < compareRequirementExs.Count; i++)
                    {
                        if (compareRequirementExs[i] == requirementEx)
                        {
                            compareRequirementExs.RemoveAt(i);
                            break;
                        }
                    }
                }

                matchCount -= compareRequirementExs.Count;
                if (matchCount > bestMatchCount)
                {
                    bestMatchCount = matchCount;
                    bestMatch      = potentialMatch;
                }
            }

            return(bestMatch);
        }
Ejemplo n.º 2
0
        protected override ParseErrorExpression ModifyRequirements(AchievementBuilder builder)
        {
            var requirementsEx = RequirementEx.Combine(builder.CoreRequirements);

            foreach (var requirementEx in requirementsEx)
            {
                var lastCondition = requirementEx.Requirements.Last();
                if (lastCondition.Type != RequirementType.None)
                {
                    return(new ParseErrorExpression(string.Format("Cannot apply '{0}' to condition already flagged with {1}", Name.Name, lastCondition.Type)));
                }

                lastCondition.Type = RequirementType.SubHits;
            }

            return(null);
        }
Ejemplo n.º 3
0
        private static int CalculateScore(RequirementEx left, RequirementEx right)
        {
            var score = 0;
            var unmatchedRequirements = new List <Requirement>(left.Requirements);

            foreach (var requirement in right.Requirements)
            {
                int bestScore = 0;
                int bestIndex = -1;

                for (int i = 0; i < unmatchedRequirements.Count; i++)
                {
                    if (unmatchedRequirements[i] == requirement)
                    {
                        bestScore = 40;
                        bestIndex = i;
                        break;
                    }
                    else
                    {
                        var matchScore = CalculateScore(unmatchedRequirements[i], requirement);
                        if (matchScore > bestScore)
                        {
                            bestScore = matchScore;
                            bestIndex = i;
                        }
                    }
                }

                if (bestIndex == -1)
                {
                    score -= 10;
                }
                else
                {
                    score += bestScore;
                    unmatchedRequirements.RemoveAt(bestIndex);
                }
            }

            score -= unmatchedRequirements.Count * 10;

            return(score);
        }
Ejemplo n.º 4
0
        public bool RequirementsAreEqual(RequirementGroupViewModel that)
        {
            // quick check to make sure the same number of requirements exist
            if (Requirements.Count() != that.Requirements.Count())
            {
                return(false);
            }

            // convert to requirement clauses and compare
            var requirementExs        = RequirementEx.Combine(Requirements.Select(r => r.Requirement));
            var compareRequirementExs = RequirementEx.Combine(that.Requirements.Select(r => r.Requirement));

            if (requirementExs.Count != compareRequirementExs.Count)
            {
                return(false);
            }

            foreach (var requirementEx in requirementExs)
            {
                bool matched = false;
                for (int i = 0; i < compareRequirementExs.Count; i++)
                {
                    if (compareRequirementExs[i] == requirementEx)
                    {
                        compareRequirementExs.RemoveAt(i);
                        matched = true;
                        break;
                    }
                }

                if (!matched)
                {
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 5
0
        public void TestCombine(string input, string expected)
        {
            var achievement = new AchievementBuilder();

            achievement.ParseRequirements(Tokenizer.CreateTokenizer(input));
            var groups = RequirementEx.Combine(achievement.CoreRequirements);

            var builder = new StringBuilder();

            foreach (var group in groups)
            {
                if (builder.Length > 0)
                {
                    builder.Append('|');
                }

                group.AppendString(builder, NumberFormat.Decimal);
            }

            Assert.That(builder.ToString(), Is.EqualTo(expected));

            // make sure we didn't modify the source requirements
            Assert.That(achievement.SerializeRequirements(), Is.EqualTo(input));
        }
Ejemplo n.º 6
0
        private static bool CanUseAddHits(List <ICollection <Requirement> > requirements)
        {
            // make sure each clause ends with a value comparison
            foreach (var requirement in requirements)
            {
                if (requirement.Last().Right.Type != FieldType.Value)
                {
                    return(false);
                }

                // cannot change OrNext to AddHits if AddHits already exists
                if (requirement.Any(r => r.Type == RequirementType.AddHits))
                {
                    return(false);
                }
            }

            // find the first condition that doesn't evaluate to always_false
            List <RequirementEx> first;
            var firstIndex = 0;

            do
            {
                first = RequirementEx.Combine(requirements[firstIndex]);
                if (first.Count >= 1)
                {
                    break;
                }

                // condition is always_false, try next
                ++firstIndex;
            } while (firstIndex < requirements.Count);

            if (first.Count != 1)
            {
                return(false);
            }

            var firstOperator = first[0].Requirements.Last().Operator;

            for (int i = firstIndex + 1; i < requirements.Count; ++i)
            {
                var requirementEx = RequirementEx.Combine(requirements[i]);
                if (requirementEx.Count == 0)
                {
                    continue;
                }
                if (requirementEx.Count > 1)
                {
                    return(false);
                }

                var right = requirementEx[0];
                if (right.Evaluate() == false)
                {
                    continue;
                }

                if (right.Requirements.Last().Operator != firstOperator ||
                    right.Requirements.Last().Right.Type != FieldType.Value ||
                    !right.LeftEquals(first[0]))
                {
                    // if both sides are not making the same comparison to different values, they
                    // could occur in the same frame. don't change the OrNext to an AddHits
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 7
0
        public RequirementGroupViewModel(string label, IEnumerable <Requirement> requirements, IEnumerable <Requirement> compareRequirements, NumberFormat numberFormat, IDictionary <int, string> notes)
        {
            Label = label;

            var requirementExs        = RequirementEx.Combine(requirements);
            var compareRequirementExs = RequirementEx.Combine(compareRequirements);

            var unmatchedCompareRequirementExs = new List <RequirementEx>(compareRequirementExs);
            var matches = new Dictionary <RequirementEx, RequirementEx>();
            var unmatchedRequirementExs = new List <RequirementEx>();

            // first pass: find exact matches
            foreach (var requirementEx in requirementExs)
            {
                bool matched = false;
                for (int i = 0; i < unmatchedCompareRequirementExs.Count; i++)
                {
                    if (unmatchedCompareRequirementExs[i] == requirementEx)
                    {
                        matches[requirementEx] = unmatchedCompareRequirementExs[i];
                        unmatchedCompareRequirementExs.RemoveAt(i);
                        matched = true;
                        break;
                    }
                }

                if (!matched)
                {
                    unmatchedRequirementExs.Add(requirementEx);
                }
            }

            // second pass: find close matches
            while (unmatchedRequirementExs.Count > 0)
            {
                var bestScore    = MinimumMatchingScore - 1;
                var matchIndex   = -1;
                var compareIndex = -1;

                for (var i = 0; i < unmatchedRequirementExs.Count; i++)
                {
                    var requirementEx = unmatchedRequirementExs[i];
                    var evaluation    = requirementEx.Evaluate();
                    if (evaluation != null)
                    {
                        for (var j = 0; j < unmatchedCompareRequirementExs.Count; j++)
                        {
                            if (unmatchedCompareRequirementExs[j].Evaluate() == evaluation)
                            {
                                bestScore    = 1000;
                                matchIndex   = i;
                                compareIndex = j;
                                break;
                            }
                        }
                    }

                    for (var j = 0; j < unmatchedCompareRequirementExs.Count; j++)
                    {
                        var score = CalculateScore(requirementEx, unmatchedCompareRequirementExs[j]);
                        if (score > bestScore)
                        {
                            bestScore    = score;
                            matchIndex   = i;
                            compareIndex = j;
                        }
                    }
                }

                if (matchIndex == -1)
                {
                    break;
                }

                matches[unmatchedRequirementExs[matchIndex]] = unmatchedCompareRequirementExs[compareIndex];
                unmatchedRequirementExs.RemoveAt(matchIndex);
                unmatchedCompareRequirementExs.RemoveAt(compareIndex);
            }

            // construct the output list from the requirements
            var pairs = new List <Tuple <RequirementEx, RequirementEx> >(matches.Count + unmatchedCompareRequirementExs.Count);

            foreach (var requirementEx in requirementExs)
            {
                RequirementEx match;
                matches.TryGetValue(requirementEx, out match);
                pairs.Add(new Tuple <RequirementEx, RequirementEx>(requirementEx, match));
            }

            // allow an always_true() group to match an empty group
            if (pairs.Count == 0 &&
                unmatchedCompareRequirementExs.Count == 1 &&
                unmatchedCompareRequirementExs[0].Evaluate() == true)
            {
                pairs.Add(new Tuple <RequirementEx, RequirementEx>(unmatchedCompareRequirementExs[0], unmatchedCompareRequirementExs[0]));
                unmatchedCompareRequirementExs.Clear();
            }

            // third pass: insert any unmatched comparison requirements
            if (unmatchedCompareRequirementExs.Count > 0)
            {
                var indices = new int[compareRequirementExs.Count + 2];
                for (int i = 1; i < indices.Length - 1; ++i)
                {
                    indices[i] = -2;
                }
                indices[0] = -1;
                indices[compareRequirementExs.Count + 1] = compareRequirementExs.Count + 1;
                for (int i = 0; i < requirementExs.Count; i++)
                {
                    RequirementEx match;
                    if (matches.TryGetValue(requirementExs[i], out match))
                    {
                        indices[compareRequirementExs.IndexOf(match) + 1] = i;
                    }
                }

                foreach (var requirementEx in unmatchedCompareRequirementExs)
                {
                    var insertIndex = pairs.Count;

                    var requirementIndex = compareRequirementExs.IndexOf(requirementEx);
                    if (requirementIndex < compareRequirementExs.Count - 1)
                    {
                        for (int i = 1; i < indices.Length - 1; i++)
                        {
                            if (indices[i - 1] == requirementIndex - 1 || indices[i + 1] == requirementIndex + 1)
                            {
                                insertIndex = i - 1;
                                break;
                            }
                        }
                    }

                    if (insertIndex < pairs.Count)
                    {
                        for (int i = 0; i < indices.Length; i++)
                        {
                            if (indices[i] >= insertIndex)
                            {
                                indices[i]++;
                            }
                        }
                    }

                    if (insertIndex < indices.Length - 1)
                    {
                        indices[insertIndex + 1] = requirementIndex;
                    }
                    pairs.Insert(insertIndex, new Tuple <RequirementEx, RequirementEx>(null, requirementEx));
                }
            }

            // convert RequirementEx pairs to RequirementComparisonViewModels
            var list = new List <RequirementViewModel>();

            foreach (var pair in pairs)
            {
                AppendRequirements(list, pair.Item1, pair.Item2, numberFormat, notes);
            }

            // attempt to merge requirements that may have been separated into separate RequirementExs
            int leftIndex, rightIndex;

            while (GetBestMerge(list, out leftIndex, out rightIndex))
            {
                list[leftIndex] = new RequirementComparisonViewModel(list[leftIndex].Requirement,
                                                                     ((RequirementComparisonViewModel)list[rightIndex]).CompareRequirement, numberFormat, notes);
                list.RemoveAt(rightIndex);
            }

            Requirements = list;
        }
Ejemplo n.º 8
0
        private void AppendRequirements(List <RequirementViewModel> list, RequirementEx left, RequirementEx right, NumberFormat numberFormat, IDictionary <int, string> notes)
        {
            if (right == null)
            {
                foreach (var requirement in left.Requirements)
                {
                    list.Add(new RequirementComparisonViewModel(requirement, null, numberFormat, notes));
                }
            }
            else if (left == null)
            {
                foreach (var requirement in right.Requirements)
                {
                    list.Add(new RequirementComparisonViewModel(null, requirement, numberFormat, notes));
                }
            }
            else if (left.Requirements.Count == right.Requirements.Count)
            {
                for (int i = 0; i < left.Requirements.Count; ++i)
                {
                    list.Add(new RequirementComparisonViewModel(left.Requirements[i], right.Requirements[i], numberFormat, notes));
                }
            }
            else
            {
                var unmatchedCompareRequirements = new List <Requirement>(right.Requirements);
                var matches = new Dictionary <Requirement, Requirement>();
                var unmatchedRequirements = new List <Requirement>();

                foreach (var requirement in left.Requirements)
                {
                    bool matched = false;
                    for (var i = 0; i < unmatchedCompareRequirements.Count; i++)
                    {
                        if (unmatchedCompareRequirements[i] == requirement)
                        {
                            matches[requirement] = unmatchedCompareRequirements[i];
                            unmatchedCompareRequirements.RemoveAt(i);
                            matched = true;
                            break;
                        }
                    }

                    if (!matched)
                    {
                        unmatchedRequirements.Add(requirement);
                    }
                }

                while (unmatchedRequirements.Count > 0)
                {
                    var bestScore    = MinimumMatchingScore - 1;
                    var matchIndex   = -1;
                    var compareIndex = -1;

                    for (var i = 0; i < unmatchedRequirements.Count; i++)
                    {
                        var requirement = unmatchedRequirements[i];

                        for (var j = 0; j < unmatchedCompareRequirements.Count; j++)
                        {
                            var score = CalculateScore(requirement, unmatchedCompareRequirements[j]);
                            if (score > bestScore)
                            {
                                bestScore    = score;
                                matchIndex   = i;
                                compareIndex = j;
                            }
                        }
                    }

                    if (matchIndex == -1)
                    {
                        break;
                    }

                    matches[unmatchedRequirements[matchIndex]] = unmatchedCompareRequirements[compareIndex];
                    unmatchedRequirements.RemoveAt(matchIndex);
                    unmatchedCompareRequirements.RemoveAt(compareIndex);
                }

                var rightIndex = 0;

                foreach (var requirement in left.Requirements)
                {
                    Requirement match;
                    if (matches.TryGetValue(requirement, out match))
                    {
                        var matchIndex = right.Requirements.IndexOf(match);
                        while (rightIndex < matchIndex)
                        {
                            var rightRequirement = right.Requirements[rightIndex++];
                            if (unmatchedCompareRequirements.Remove(rightRequirement))
                            {
                                list.Add(new RequirementComparisonViewModel(null, rightRequirement, numberFormat, notes));
                            }
                        }

                        rightIndex++;
                    }

                    list.Add(new RequirementComparisonViewModel(requirement, match, numberFormat, notes));
                }

                foreach (var requirement in unmatchedCompareRequirements)
                {
                    list.Add(new RequirementComparisonViewModel(null, requirement, numberFormat, notes));
                }
            }
        }