public override void Resolve(RubikCube from, RubikCube to) // From: Generalmente mastercube To: Obtener un cubo que contemple el modelo recibido
        {
            this.init(to);

            if (!to.Equals(from))
            {
                ProcessParms parms = null;

                // Load all axis
                parms = new ProcessParms(from, 0, 9, new ArrayList());
                fillCubeAux(parms);
            }
            else
            {
                this.cubeMatch = from.Clone();
            }
        }
        private void processAxis(Object o)
        {
            ProcessParms parms = (ProcessParms)o;

            // Se procesan todas las conbinaciones de movimientos para un nivel
            for (int level1 = 0; level1 <= 3; level1++)
            {
                if (this.Rotate(parms, parms.CurrentAxis, 1))
                {
                    return;
                }

                for (int level2 = 0; level2 <= 3; level2++)
                {
                    if (this.Rotate(parms, parms.CurrentAxis, 2))
                    {
                        return;
                    }

                    for (int level3 = 0; level3 <= 3; level3++)
                    {
                        if (this.Rotate(parms, parms.CurrentAxis, 3))
                        {
                            return;
                        }

                        // Don't you fillcubeaux on the original cube
                        if (!(level1 == 3 && level2 == 3 && level3 == 3))
                        {
                            fillCubeAux(parms);
                        }

                        if (this.cubeMatch != null || this.IsCanceled)
                        {
                            return;
                        }
                    } // Level3
                }     // Level2
            }         // Level1
        }
        private void fillCubeAux(ProcessParms parms)
        {
            // Axis deep
            parms.Deep += 1;

            if (parms.Deep <= maxDeep)
            {
                // Axis changes
                for (int axis = 0; axis < 3; axis++)
                {
                    if (axis != parms.CurrentAxis || parms.CurrentAxis > 2) // The last is for axis = 9
                    {
                        ProcessParms p2 = new ProcessParms(parms.WorkingCube, parms.Deep, axis, parms.Moves);

                        if (parms.Thread == -1)
                        {
                            p2.Thread = this.getFreeThread();
                            this.startProcess(p2.Thread, () => processAxis(p2));
                        }
                        else
                        {
                            p2.Thread = parms.Thread;
                            processAxis(p2);
                        }

                        if (this.cubeMatch != null)
                        {
                            if (this.Template.Equals(this.cubeMatch) || this.IsCanceled)
                            {
                                return;
                            }
                        }
                    } // Axis
                }
            }

            parms.Deep -= 1;
        }
        /// <summary>
        /// Do a cube rotation and return true if the process was cancelled or exists a match winner
        /// </summary>
        /// <param name="param1">Some Parameter.</param>
        /// <returns>What this method returns.</returns>
        protected bool Rotate(ProcessParms parms, int axis, int level)
        {
            if (this.cubeMatch != null || this.IsCanceled)
            {
                return(true);
            }

            // -----------------------------------------
            // Add movement to list
            // -----------------------------------------
            bool rotate = true;

            Move m   = null;
            bool add = false;

            if (parms.Moves.Count == 0)
            {
                add = true;
            }
            else
            {
                m = (Move)parms.Moves[parms.Moves.Count - 1];
                if (m.Axis == axis && m.Level == level)
                {
                    // If last movment is the 3rd, we remove it because one more is useless
                    if (m.Turns >= 3)
                    {
                        parms.Moves.RemoveAt(parms.Moves.Count - 1);
                        rotate = false;
                    }
                    else
                    {
                        m.Turns++; // Same movement
                    }
                }
                else
                {
                    add = true;
                }
            }

            if (add)
            {
                m = new Move(axis, level, 1);
                parms.Moves.Add(m);
            }
            // ---------------------------------

            // Chequeo si se eliminó el movimiento. En ese caso no es necesario chequear
            // Se rota pero no se compara, esto es para que regrese a la posición anterior
            //if (parms.Thread == 2)
            //   Console.WriteLine("Axis: {0} Level: {1} Deep: {2}", axis, level, parms.Deep);

            parms.WorkingCube.rotateFace(axis, level);
            if (rotate)
            {
                lock (this.winnerMoves)
                {
                    // Siempre se chequea desde el template para optimizar el cache de viewPoints
                    if (this.Template.Equals(parms.WorkingCube))
                    {
                        this.cubeMatch    = parms.WorkingCube.Clone();
                        this.winnerThread = parms.Thread;
                        this.winnerMoves  = parms.Moves;
                    }

                    lock (this.operationsByThread)
                    {
                        this.operationsByThread[parms.Thread]++;
                    }
                    if (this.Operations % 5000 == 0)
                    {
                        this.raiseUpdateForm(parms.WorkingCube);
                    }
                }
            }
            if (this.cubeMatch != null)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }