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;
            }
              }
        }
        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;
                }
            }
        }