/// <summary>
 /// True, if the item has the same current position and the other equality conditions
 /// </summary>
 /// <param name="item">Item to compare</param>
 public bool Equals(PatternItem item)
 {
     var sameOrientation = (item.CurrentOrientation == Orientation.None || this.CurrentOrientation == Orientation.None) || item.CurrentOrientation == this.CurrentOrientation;
     var sameTargetPos = (item.TargetPosition == CubeFlag.None || this.TargetPosition == CubeFlag.None) || item.TargetPosition == this.TargetPosition;
     var result = item.CurrentPosition.Flags == this.CurrentPosition.Flags && sameOrientation && sameTargetPos;
     return result;
 }
        private void CompleteF2L()
        {
            List<Tuple<Cube, Cube>> unsolvedPairs = GetPairs(this.Rubik).ToList();

              while (unsolvedPairs.Count > 0) // 4 pairs
              {
            Tuple<Cube, Cube> currentPair = unsolvedPairs.First();

            Cube edge = currentPair.Item1;
            Cube corner = currentPair.Item2;

            CubePosition target = new CubePosition(Rubik.GetTargetFlags(corner));

            if (!corner.Position.HasFlag(CubeFlag.TopLayer) && Rubik.GetTargetFlags(corner) != corner.Position.Flags)
            {
              CubeFlag rotationLayer = CubeFlagService.FirstNotInvalidFlag(corner.Position.Flags, CubeFlag.BottomLayer);
              bool direction = new TestScenario(Rubik, new LayerMove(rotationLayer)).TestCubePosition(corner, CubeFlag.TopLayer);
              SolverMove(rotationLayer, direction);
              SolverMove(CubeFlag.TopLayer, true);
              SolverMove(rotationLayer, !direction);
            }
            // move edge to top position if necessary
            if (!edge.Position.HasFlag(CubeFlag.TopLayer) && Rubik.GetTargetFlags(edge) != edge.Position.Flags)
            {
              CubeFlag rotationLayer = CubeFlagService.FirstNotInvalidFlag(edge.Position.Flags, CubeFlag.MiddleLayer);
              bool direction = new TestScenario(Rubik, new LayerMove(rotationLayer)).TestCubePosition(edge, CubeFlag.TopLayer);
              SolverMove(rotationLayer, direction);
              while ((corner.Position.HasFlag(rotationLayer) && !corner.Position.HasFlag(CubeFlag.BottomLayer)) || edge.Position.HasFlag(rotationLayer)) SolverMove(CubeFlag.TopLayer, true);
              SolverMove(rotationLayer, !direction);
            }

            // detect right and front slice
            CubeFlag rightSlice = CubeFlagService.ToInt(target.X) == CubeFlagService.ToInt(target.Z) ? target.Z : target.X;
            CubeFlag frontSlice = CubeFlagService.FirstNotInvalidFlag(target.Flags, CubeFlag.YFlags | rightSlice);

            while (!corner.Position.HasFlag(target.Flags & ~CubeFlag.BottomLayer)) SolverMove(CubeFlag.TopLayer, true);

            PatternFilter filter = new PatternFilter(new Func<Pattern, Pattern, bool>(delegate(Pattern p1, Pattern p2)
            {
              PatternItem item = new PatternItem(corner.Position, Solvability.GetOrientation(this.Rubik, corner),target.Flags);
              return p2.Items.Any(i => i.Equals(item));
            }), true);

            Algorithm algo = null;
            for (int i = 0; i < 4; i++)
            {
              F2LPattern pattern = new F2LPattern(Rubik.GetTargetFlags(edge), Rubik.GetTargetFlags(corner), rightSlice, frontSlice);
              algo = pattern.FindBestMatch(Pattern.FromRubik(Rubik), CubeFlag.None, filter);
              if (algo != null) { SolverAlgorithm(algo); break; }
              SolverMove(CubeFlag.TopLayer, true);
            }

            int count = unsolvedPairs.Count;
            unsolvedPairs = GetPairs(this.Rubik).ToList();
            if (unsolvedPairs.Count == count)
            {
              this.BroadcastOnSolutionError("Complete first two layers", "Wrong algorithm");
              return;
            }
              }
        }