Пример #1
0
        public void Match_shape_grants_one_copy_of_corresponding_tool(Vector2Int[] horizontalMatches, Vector2Int[] verticalMatches, Tool awardedTool)
        {
            Toolbox   toolbox = CreateToolbox();
            MatchStep step    = MatchStepFromMatches(1, horizontalMatches, verticalMatches);

            toolbox.RewardMatches(step);

            Assert.That(toolbox.GetAvailableUses(awardedTool), Is.EqualTo(1));
        }
        private async Task ShowMatchShapeTutorialAsync(MatchStep matchStep, List <Tool> newTools)
        {
            var matchedRects = matchStep.LeftEndsOfHorizontalMatches
                               .Select(pos => new GridRect(pos, pos + new Vector2Int(2, 0)))
                               .Concat(matchStep.BottomEndsOfVerticalMatches
                                       .Select(pos => new GridRect(pos, pos + new Vector2Int(0, 2))))
                               .ToList();

            await TutorialManager.Instance.ShowTutorialIfNewAsync(TutorialID.MatchShapes, matchedRects, newTools);
        }
Пример #3
0
        public void Increasing_chain_length_still_rewards_tools(Vector2Int[] horizontalMatches, Vector2Int[] verticalMatches, Tool awardedTool)
        {
            Toolbox   toolbox = CreateToolbox();
            MatchStep step    = MatchStepFromMatches(1, horizontalMatches, verticalMatches);

            toolbox.RewardMatches(step);

            step = MatchStepFromMatches(2, horizontalMatches, verticalMatches);
            toolbox.RewardMatches(step);

            Assert.That(toolbox.GetAvailableUses(awardedTool), Is.EqualTo(2));
        }
Пример #4
0
        public void Chain_length_1_rewards_tools_only_once(Vector2Int[] horizontalMatches, Vector2Int[] verticalMatches, Tool awardedTool)
        {
            Toolbox   toolbox = CreateToolbox();
            MatchStep step    = MatchStepFromMatches(1, horizontalMatches, verticalMatches);

            toolbox.RewardMatches(step);

            step = MatchStepFromMatches(1, horizontalMatches, verticalMatches);
            toolbox.RewardMatches(step);

            Assert.That(toolbox.GetAvailableUses(awardedTool), Is.EqualTo(1));
        }
        public async Task RewardMatches(MatchStep matchStep)
        {
            List <Tool> newTools = toolbox.RewardMatches(matchStep);

            if (newTools.Count > 0)
            {
                sessionMetrics.RegisterToolRewards(newTools);
                await ShowMatchShapeTutorialAsync(matchStep, newTools);
            }

            UpdateUI();
        }
        /// <summary>
        /// Build a plan for processing the LIKE functionality.
        /// </summary>
        protected internal virtual void BuildPlan()
        {
            string pattern = Pattern;

            if (pattern == null)
            {
                // the result of "v LIKE NULL" is false for all values of "v"
                m_plan = OptimizationPlan.AlwaysFalse;
                return;
            }

            char[]        patternChars       = pattern.ToCharArray();
            int           patternCharsLength = patternChars.Length;
            char          escapeChar         = EscapeChar;
            bool          isEscape           = false;
            bool          ignoreCase         = IgnoreCase;
            StringBuilder sb   = null;
            BitArray      bits = null;
            IList         list = new ArrayList();

            // parse the pattern into a list of steps
            for (int of = 0; of < patternCharsLength; ++of)
            {
                char ch = patternChars[of];
                if (isEscape)
                {
                    isEscape = false;
                }
                else if (ch == escapeChar)
                {
                    isEscape = true;
                    continue;
                }
                else if (ch == '%')
                {
                    if (sb != null)
                    {
                        list.Add(new MatchStep(this, sb, bits));
                        sb   = null;
                        bits = null;
                    }

                    if ((list.Count == 0) || list[list.Count - 1] != ANY)
                    {
                        list.Add(ANY);
                    }
                    continue;
                }
                else if (ch == '_')
                {
                    if (bits == null)
                    {
                        bits = new BitArray(64);
                    }
                    CollectionUtils.SetBit(bits, sb == null ? 0 : sb.Length, true);
                }

                if (sb == null)
                {
                    sb = new StringBuilder();
                }
                sb.Append(ch);
            }

            // check for unclosed escape
            if (isEscape)
            {
                throw new ArgumentException("pattern ends with an unclosed escape: \"" + pattern + "\"");
            }

            // store off the last match step (if there is one)
            if (sb != null)
            {
                list.Add(new MatchStep(this, sb, bits));
            }

            // check for simple optimizations
            switch (list.Count)
            {
            case 0:
                // case sensistive     case insensitive    pattern
                // ------------------  ------------------  -------
                // OptimizationPlan.ExactMatch         OptimizationPlan.ExactMatch         ""
                m_plan = OptimizationPlan.ExactMatch;
                m_part = "";
                return;

            case 1:
                // case sensistive     case insensitive    pattern
                // ------------------  ------------------  -------
                // OptimizationPlan.ExactMatch         OptimizationPlan.InsensMatch        "xyz"  (no wildcards)
                // OptimizationPlan.AlwaysTrue         OptimizationPlan.AlwaysTrue         "%"    (only '%' wildcards)
            {
                object o = list[0];
                if (o == ANY)
                {
                    m_plan = OptimizationPlan.AlwaysTrue;
                    return;
                }

                var matchstep = (MatchStep)o;
                if (matchstep.IsLiteral)
                {
                    m_plan = ignoreCase ? OptimizationPlan.InsensMatch : OptimizationPlan.ExactMatch;

                    // matchstep may contain escaped chars (such as '_')
                    m_part = matchstep.String;
                    return;
                }
            }
            break;

            case 2:
                // case sensistive     case insensitive    pattern
                // ------------------  ------------------  -------
                // OptimizationPlan.StartsWithChar    OptimizationPlan.StartsWithInsens  "x%"
                // OptimizationPlan.StartsWithString  OptimizationPlan.StartsWithInsens  "xyz%"
                // OptimizationPlan.EndsWithChar      OptimizationPlan.EndsWithInsens    "%x"
                // OptimizationPlan.EndsWithString    OptimizationPlan.EndsWithInsens    "%xyz"
            {
                MatchStep matchStep;
                bool      startsWith;
                object    o = list[0];
                if (o == ANY)
                {
                    startsWith = false;
                    matchStep  = (MatchStep)list[1];
                }
                else
                {
                    startsWith = true;
                    matchStep  = (MatchStep)o;
                }
                if (matchStep.IsLiteral)
                {
                    if (ignoreCase)
                    {
                        m_plan = startsWith ? OptimizationPlan.StartsWithInsens : OptimizationPlan.EndsWithInsens;
                        m_part = matchStep.String;
                    }
                    else if (matchStep.Length == 1)
                    {
                        m_plan     = startsWith ? OptimizationPlan.StartsWithChar : OptimizationPlan.EndsWithChar;
                        m_partChar = matchStep.String[0];
                    }
                    else
                    {
                        m_plan = startsWith ? OptimizationPlan.StartsWithString : OptimizationPlan.EndsWithString;
                        m_part = matchStep.String;
                    }
                    return;
                }
            }
            break;

            case 3:
                // case sensistive     case insensitive    pattern
                // ------------------  ------------------  -------
                // OptimizationPlan.ContainsChar       n/a                 "%x%"
                // OptimizationPlan.ContainsString     n/a                 "%xyz%"
            {
                if (!ignoreCase)
                {
                    object o = list[1];
                    if (o != ANY)
                    {
                        var matchstep = (MatchStep)o;
                        if (matchstep.IsLiteral)
                        {
                            if (matchstep.Length == 1)
                            {
                                m_plan     = OptimizationPlan.ContainsChar;
                                m_partChar = matchstep.String[0];
                            }
                            else
                            {
                                m_plan = OptimizationPlan.ContainsString;
                                m_part = matchstep.String;
                            }
                            return;
                        }
                    }
                }
            }
            break;
            }

            // build iterative plan
            // # steps  description
            // -------  --------------------------------------------------------
            //    1     match with '_'
            //    2     starts with or ends with match with '_'
            //    3     starts and ends with matches, or contains match with '_'
            //    4+    alternating % and matches, potentially starting with
            //          and/or ending with matches, each could have '_'
            m_plan = OptimizationPlan.IterativeEval;
            switch (list.Count)
            {
            case 0:
                throw new Exception("assertion failed");

            case 1:
                m_stepFront             = (MatchStep)list[0];
                m_isTrailingTextAllowed = false;
                break;

            case 2:
            {
                object step1 = list[0];
                object step2 = list[1];

                // should not have two "ANYs" in a row, but one must be ANY
                Debug.Assert(step1 == ANY ^ step2 == ANY);

                if (step1 == ANY)
                {
                    m_stepBack = (MatchStep)step2;
                    m_isTrailingTextAllowed = false;
                }
                else
                {
                    m_stepFront             = (MatchStep)step1;
                    m_isTrailingTextAllowed = true;
                }
            }
            break;

            default:
            {
                int matchStepsCount = list.Count;

                // figure out where the "middle" is; the "middle" is
                // defined as those steps that occur after one or more
                // '%' matches and before one or more '%' matches
                int ofStartMiddle = 1;                   // offset in list of first middle step
                int ofEndMiddle   = matchStepsCount - 2; // offset in list of last middle step

                object first = list[0];
                if (first != ANY)
                {
                    m_stepFront = (MatchStep)first;
                    ++ofStartMiddle;
                }

                object last          = list[matchStepsCount - 1];
                bool   isLastStepAny = (last == ANY);
                if (!isLastStepAny)
                {
                    m_stepBack = (MatchStep)last;
                    --ofEndMiddle;
                }
                m_isTrailingTextAllowed = isLastStepAny;

                int matches      = (ofEndMiddle - ofStartMiddle) / 2 + 1;
                var matchesArray = new MatchStep[matches];
                int match        = 0;
                for (int of = ofStartMiddle; of <= ofEndMiddle; of += 2)
                {
                    matchesArray[match++] = (MatchStep)list[of];
                }
                m_stepsMiddle = matchesArray;
            }
            break;
            }
        }
        /// <summary>
        /// Check the passed string value to see if it matches the pattern
        /// that this filter was constructed with.
        /// </summary>
        /// <param name="value">
        /// The <b>string</b> value to match against this filter's pattern.
        /// </param>
        /// <returns>
        /// <b>true</b> if the passed <b>string</b> value is LIKE this
        /// filter's pattern.
        /// </returns>
        protected internal virtual bool IsMatch(string value)
        {
            if (value == null)
            {
                // null is not like anything
                return(false);
            }

            int length = value.Length;

            switch (m_plan)
            {
            case OptimizationPlan.StartsWithChar:
                return(length >= 1 && value[0] == m_partChar);

            case OptimizationPlan.StartsWithString:
                return(value.StartsWith(m_part));

            case OptimizationPlan.StartsWithInsens:
            {
                string prefix       = m_part;
                int    prefixLength = prefix.Length;
                if (prefixLength > length)
                {
                    return(false);
                }
                return(String.Compare(value, 0, prefix, 0, prefixLength, true) == 0);
            }

            case OptimizationPlan.EndsWithChar:
                return(length >= 1 && value[length - 1] == m_partChar);

            case OptimizationPlan.EndsWithString:
                return(value.EndsWith(m_part));

            case OptimizationPlan.EndsWithInsens:
            {
                string suffix       = m_part;
                int    suffixLength = suffix.Length;
                if (suffixLength > length)
                {
                    return(false);
                }
                return(String.Compare(value, length - suffixLength, suffix, 0, suffixLength, true) == 0);
            }

            case OptimizationPlan.ContainsChar:
                return(value.IndexOf(m_partChar) >= 0);

            case OptimizationPlan.ContainsString:
                return(value.IndexOf(m_part) >= 0);

            case OptimizationPlan.AlwaysTrue:
                return(true);

            case OptimizationPlan.AlwaysFalse:
                return(false);

            case OptimizationPlan.ExactMatch:
                return(m_part.Equals(value));

            case OptimizationPlan.InsensMatch:
                return(m_part.ToUpper().Equals(value.ToUpper()));
            }

            // get the character data and iteratively process the LIKE
            char[] chars       = value.ToCharArray();
            int    charsLength = chars.Length;
            int    ofBegin     = 0;
            int    ofEnd       = charsLength;

            // start by checking the front
            MatchStep matchStep = m_stepFront;

            if (matchStep != null)
            {
                int stepLength = matchStep.Length;
                if (stepLength > charsLength || matchStep.IndexOf(chars, ofBegin, stepLength) < 0)
                {
                    return(false);
                }
                ofBegin = stepLength;
            }

            // next check the back
            matchStep = m_stepBack;
            if (matchStep != null)
            {
                int stepLength = matchStep.Length;
                int ofStep     = charsLength - stepLength;
                if (ofStep < ofBegin || matchStep.IndexOf(chars, ofStep, ofEnd) < 0)
                {
                    return(false);
                }
                ofEnd = ofStep;
            }

            // check the middle
            MatchStep[] matchStepMiddle = m_stepsMiddle;
            if (matchStepMiddle != null)
            {
                for (int i = 0, c = matchStepMiddle.Length; i < c; ++i)
                {
                    matchStep = matchStepMiddle[i];
                    int of = matchStep.IndexOf(chars, ofBegin, ofEnd);
                    if (of < 0)
                    {
                        return(false);
                    }
                    ofBegin = of + matchStep.Length;
                }
            }

            // this is the "is there anything left" check, which solves an
            // ambiguity in the "iterative step" design that did not correctly
            // differentiate between "%a_%" and "%a_", for example
            if (m_stepBack == null && !m_isTrailingTextAllowed)
            {
                if (ofBegin != charsLength)
                {
                    return(false);
                }
            }

            return(true);
        }
 private async Task AnimateMatchStepAsync(MatchStep step)
 {
     await AnimateMatchedTilesAsync(step.MatchedTiles);
     await AnimateFallingTilesAsync(step.MovedTiles);
 }
 private int ScoreMatchStep(MatchStep matchStep, int level)
 {
     return(matchStep.MatchedTiles.Count * baseScore * matchStep.ChainLength * (level + 1));
 }
        public List <Tool> RewardMatches(MatchStep step)
        {
            var previousToolUses = new Dictionary <Tool, int>(availableToolUses);

            foreach (Vector2Int match in step.LeftEndsOfHorizontalMatches)
            {
                RewardShape(step.ChainLength, MatchShape.Row3);

                if (step.LeftEndsOfHorizontalMatches.Contains(match + new Vector2Int(1, 0)))
                {
                    RewardShape(step.ChainLength, MatchShape.Row4);
                }

                if (step.LeftEndsOfHorizontalMatches.Contains(match + new Vector2Int(2, 0)))
                {
                    RewardShape(step.ChainLength, MatchShape.Row5);
                }

                if (step.BottomEndsOfVerticalMatches.Contains(match))
                {
                    RewardShape(step.ChainLength, MatchShape.L);

                    if (step.LeftEndsOfHorizontalMatches.Contains(match + new Vector2Int(0, 2)))
                    {
                        RewardShape(step.ChainLength, MatchShape.U);

                        if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(2, 0)))
                        {
                            RewardShape(step.ChainLength, MatchShape.O);
                        }
                    }

                    if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(2, 0)))
                    {
                        RewardShape(step.ChainLength, MatchShape.U);
                    }
                }

                if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(2, 0)))
                {
                    RewardShape(step.ChainLength, MatchShape.L);

                    if (step.LeftEndsOfHorizontalMatches.Contains(match + new Vector2Int(0, 2)))
                    {
                        RewardShape(step.ChainLength, MatchShape.U);
                    }
                }

                if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(0, -2)))
                {
                    RewardShape(step.ChainLength, MatchShape.L);

                    if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(2, -2)))
                    {
                        RewardShape(step.ChainLength, MatchShape.U);
                    }
                }

                if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(2, -2)))
                {
                    RewardShape(step.ChainLength, MatchShape.L);
                }

                if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(1, 0)))
                {
                    RewardShape(step.ChainLength, MatchShape.T);

                    if (step.LeftEndsOfHorizontalMatches.Contains(match + new Vector2Int(0, 2)))
                    {
                        RewardShape(step.ChainLength, MatchShape.H);
                    }
                }

                if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(1, -2)))
                {
                    RewardShape(step.ChainLength, MatchShape.T);
                }


                if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(0, -1)))
                {
                    RewardShape(step.ChainLength, MatchShape.T);

                    if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(2, -1)))
                    {
                        RewardShape(step.ChainLength, MatchShape.H);
                    }
                }

                if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(2, -1)))
                {
                    RewardShape(step.ChainLength, MatchShape.T);
                }

                if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(1, -1)))
                {
                    RewardShape(step.ChainLength, MatchShape.Plus);
                }
            }

            foreach (Vector2Int match in step.BottomEndsOfVerticalMatches)
            {
                RewardShape(step.ChainLength, MatchShape.Row3);

                if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(0, 1)))
                {
                    RewardShape(step.ChainLength, MatchShape.Row4);
                }

                if (step.BottomEndsOfVerticalMatches.Contains(match + new Vector2Int(0, 2)))
                {
                    RewardShape(step.ChainLength, MatchShape.Row5);
                }
            }

            var newTools = new List <Tool>();

            foreach ((Tool tool, int uses) in availableToolUses)
            {
                for (int i = previousToolUses[tool]; i < uses; ++i)
                {
                    newTools.Add(tool);
                }
            }

            return(newTools);
        }