Example #1
0
        /// <summary>
        /// Grabs a set of undo twists we want to apply all at once.
        /// </summary>
        private void ApplyUndoBlockInstantaneously(SingleTwist start)
        {
            m_currentTwist = start;
            FinishRotate(updateStatus: false);

            if (!start.MacroStart)
            {
                SingleTwist undo;
                while (m_twistHistory.GetUndoTwist(out undo))
                {
                    m_currentTwist = undo;
                    FinishRotate(updateStatus: false);
                    if (undo.MacroStart)
                    {
                        break;
                    }
                }
            }

            // ZZZ - could be smarter and invalidate less.
            InvalidateAllAndUpdateStatus();

            // Bump the solve to continue.
            if (this.Solving)
            {
                Solve();
            }
        }
Example #2
0
        private void FinishRotate(bool updateStatus = true)
        {
            //Trace.WriteLine( "FinishRotate " );
            m_timer.Enabled = false;
            m_rotation      = 0;

            // Update the state.
            m_puzzle.UpdateState(m_currentTwist);
            BeepIfSolved();

            // Track the history.
            // NOTE: This needs to happen after the 'Undoing' check in BeepIfSolved method above.
            m_twistHistory.Update(m_currentTwist);
            m_setupMoves.Update(m_currentTwist);
            m_workingMacro.Update(m_currentTwist);

            m_currentTwist.IdentifiedTwistData.EndTwist(m_currentTwist.SliceMask, m_puzzle.IsSpherical);
            if (m_currentTwist.IdentifiedTwistDataEarthquake != null)
            {
                m_currentTwist.IdentifiedTwistDataEarthquake.EndTwist(m_currentTwist.SliceMask, m_puzzle.IsSpherical);
            }
            m_currentTwist = null;

            if (updateStatus)
            {
                m_status();
            }
        }
Example #3
0
        /// <summary>
        /// NOTE: This is not meant to be called when undoing/redoing.
        /// </summary>
        private void ApplyMacroTwistsInstantaneously(SingleTwist[] twists)
        {
            for (int i = 0; i < twists.Length; i++)
            {
                m_currentTwist = twists[i];

                // Don't mark as macro if there is only one twist in the macro.
                if (twists.Length > 1)
                {
                    if (i == 0)
                    {
                        m_currentTwist.MacroStart = true;
                    }
                    if (i == twists.Length - 1)
                    {
                        m_currentTwist.MacroEnd = true;
                    }
                }

                FinishRotate(updateStatus: false);
            }

            // ZZZ - could be smarter and invalidate less.
            InvalidateAllAndUpdateStatus();
        }
Example #4
0
 /// <summary>
 /// Compare two twists.
 /// NOTE: This ignores the MacroStart/MacroEnd properties.
 /// </summary>
 public bool Compare(SingleTwist other)
 {
     return
         (this.IdentifiedTwistData == other.IdentifiedTwistData &&
          this.LeftClick == other.LeftClick &&
          this.SliceMask == other.SliceMask);
 }
Example #5
0
        /// <summary>
        /// Adds a twist to our history.
        /// </summary>
        public void Update(SingleTwist twist)
        {
            if (m_undoMode)
            {
                // Remove from twist list.
                m_twists.RemoveAt(m_twists.Count - 1);

                // Save in our redo list.
                SingleTwist temp = twist.Clone();
                temp.ReverseTwist();
                m_redoTwists.Add(temp);
                m_undoMode = false;
                return;
            }

            if (m_redoMode)
            {
                m_redoTwists.RemoveAt(m_redoTwists.Count - 1);
                m_redoMode = false;
            }
            else
            {
                m_redoTwists.Clear();
            }

            // This block should apply to normal twists and redo twists.
            m_twists.Add(twist);
        }
Example #6
0
 public void PuzzleUpdated(Puzzle puzzle)
 {
     m_puzzle       = puzzle;
     m_twistHistory = m_puzzle.TwistHistory;
     m_setupMoves.Reset();
     m_workingMacro.Reset();
     m_currentTwist = null;
 }
Example #7
0
        public void Update(SingleTwist twist)
        {
            if (m_recordingSetup)
            {
                m_setupMoves.Update(twist);
            }

            if (m_recordingCommutator)
            {
                m_commutatorMoves.Update(twist);
            }
        }
Example #8
0
        /// <summary>
        /// Checks if we are an undo of another twist.
        /// </summary>
        public bool IsUndo(SingleTwist other)
        {
            if (other == null)
            {
                return(false);
            }

            SingleTwist clone = this.Clone();

            clone.ReverseTwist();
            return(clone.Compare(other));
        }
Example #9
0
        public SingleTwist Clone()
        {
            SingleTwist newTwist = new SingleTwist();

            newTwist.IdentifiedTwistData           = this.IdentifiedTwistData;
            newTwist.IdentifiedTwistDataEarthquake = this.IdentifiedTwistDataEarthquake;
            newTwist.LeftClick           = this.LeftClick;
            newTwist.SliceMask           = this.SliceMask;
            newTwist.SliceMaskEarthquake = this.SliceMaskEarthquake;
            newTwist.MacroStart          = this.MacroStart;
            newTwist.MacroEnd            = this.MacroEnd;
            return(newTwist);
        }
Example #10
0
        /// <summary>
        /// Get redo rotation parameters.
        /// Calling this will set us in the "redo" state for the next rotation.
        /// Returns false if there are no more twists to redo.
        /// </summary>
        public bool GetRedoTwist(out SingleTwist twist)
        {
            twist = null;

            if (0 == m_redoTwists.Count)
            {
                return(false);
            }

            twist = m_redoTwists[m_redoTwists.Count - 1];

            m_redoMode = true;
            return(true);
        }
Example #11
0
        /// <summary>
        /// Transforms us into a new macro based on a different click location.
        /// </summary>
        public Macro Transform(Cell clickedCell, Vector3D clickedPoint, Puzzle puzzle, bool mouseMotionReflected)
        {
            Macro m = this.CloneAllButTwists();

            m.SetupMobius(clickedCell, clickedPoint, puzzle, mouseMotionReflected);

            // Did we have an odd number of view reflections?
            bool viewReflected = this.ViewReflected ^ m.ViewReflected;

            Isometry iso1 = new Isometry(m.Mobius, null);
            Isometry iso2 = new Isometry(this.Mobius, null);

            if (viewReflected)
            {
                iso1 = Isometry.ReflectX() * iso1;
            }
            Isometry combined = iso1.Inverse() * iso2;

            foreach (SingleTwist t in this.m_twists)
            {
                // Find the transformed twist data.
                // NOTE: We choose the one which will be closest to the origin after transformation,
                //		 which hopefully won't lead to performance problems.
                //		 I initially just used the first TwistDataForStateCalcs list item,
                //		 but that led to issues because sometimes it would get transformed
                //		 to very near the disk boundary. We'd have run out of cells to
                //		 find the correct closest, and the transformed macros got all messed up.
                TwistData tdOriginal = t.IdentifiedTwistData.TwistDataForStateCalcs
                                       .OrderBy(td => combined.Apply(td.Center).MagSquared())
                                       .First();
                Vector3D  newCenter = combined.Apply(tdOriginal.Center);
                TwistData tdNew     = puzzle.ClosestTwistingCircles(newCenter);

                SingleTwist tClone = t.Clone();
                tClone.IdentifiedTwistData = tdNew.IdentifiedTwistData;

                // If the reverse state of our transformed twist
                // has changed, we may need to reverse the new twist.
                bool reverse = tdOriginal.Reverse ^ tdNew.Reverse;
                if (reverse ^ viewReflected)                    // NOTE: Very similar to code in Renderer.
                {
                    tClone.ReverseTwist();
                }

                m.m_twists.Add(tClone);
            }

            return(m);
        }
Example #12
0
        /// <summary>
        /// Get undo rotation parameters.
        /// Calling this will set us in the "undo" state for the next rotation.
        /// Returns false if there are no more twists to undo.
        /// </summary>
        public bool GetUndoTwist(out SingleTwist twist)
        {
            twist = null;

            if (0 == m_twists.Count)
            {
                return(false);
            }

            twist = m_twists[m_twists.Count - 1].Clone();
            twist.ReverseTwist();

            m_undoMode = true;
            return(true);
        }
Example #13
0
        public void StartRotate(SingleTwist twist)
        {
            if (this.Twisting)
            {
                return;
            }

            m_rotation     = 0;
            m_currentTwist = twist;
            m_currentTwist.IdentifiedTwistData.StartTwist(m_currentTwist.SliceMask, m_puzzle.IsSpherical);
            if (m_currentTwist.IdentifiedTwistDataEarthquake != null)
            {
                m_currentTwist.IdentifiedTwistDataEarthquake.StartTwist(m_currentTwist.SliceMask, m_puzzle.IsSpherical);
            }
            m_timer.Enabled = true;
        }
Example #14
0
        public void Update(SingleTwist twist)
        {
            if (!Recording)
            {
                return;
            }

            // Check for undos.
            if (m_twists.Count > 0)
            {
                SingleTwist last = m_twists.Last();
                if (twist.IsUndo(last))
                {
                    m_twists.RemoveAt(m_twists.Count - 1);
                    return;
                }
            }

            m_twists.Add(twist);
        }
Example #15
0
        /// <summary>
        /// Grabs a set of redo twists we want to apply all at once.
        /// </summary>
        private void ApplyRedoBlockInstantaneously(SingleTwist start)
        {
            m_currentTwist = start;
            FinishRotate(updateStatus: false);

            if (!start.MacroEnd)
            {
                SingleTwist redo;
                while (m_twistHistory.GetRedoTwist(out redo))
                {
                    m_currentTwist = redo;
                    FinishRotate(updateStatus: false);
                    if (redo.MacroEnd)
                    {
                        break;
                    }
                }
            }

            // ZZZ - could be smarter and invalidate less.
            InvalidateAllAndUpdateStatus();
        }
Example #16
0
        public Mobius MobiusForTwist(Geometry g, SingleTwist twist, double rotation, bool earthquake, bool earthquakeData = false)
        {
            Mobius mobius = new Mobius();

            if (earthquake)
            {
                int seg = earthquakeData ?
                          (twist.SliceMaskEarthquake * 2 + 3) % 6 :
                          (twist.SliceMask * 2 + 3) % 6;
                Vector3D p1 = this.Pants.Hexagon.Segments[seg].P2;
                Vector3D p2 = Pants.Hexagon.Segments[seg].P1;
                if (Pants.Isometry.Reflected)
                {
                    R3.Core.Utils.SwapPoints(ref p1, ref p2);
                }
                System.Diagnostics.Debug.Assert(!Reverse);
                mobius.Geodesic(Geometry.Hyperbolic, p1, p2, rotation);
            }
            else
            {
                mobius.Elliptic(g, Center, Reverse ? rotation * -1 : rotation);
            }
            return(mobius);
        }
Example #17
0
        /// <summary>
        /// Scramble.
        /// </summary>
        /// <param name="numTwists"></param>
        public void Scramble(int numTwists)
        {
            System.Random rand = new System.Random();
            List <IdentifiedTwistData> allTwistData = m_puzzle.AllTwistData;

            if (allTwistData.Count == 0)
            {
                return;
            }

            bool earthquake = m_puzzle.Config.Earthquake;

            for (int i = 0; i < numTwists; i++)
            {
                m_currentTwist = new SingleTwist();
                m_currentTwist.IdentifiedTwistData = allTwistData[rand.Next(allTwistData.Count)];
                m_currentTwist.LeftClick           = rand.Next(2) == 1;

                // Try to avoid repeats of last (suggested by Melinda).
                IdentifiedTwistData last = m_twistHistory.AllTwists.Count == 0 ? null : m_twistHistory.AllTwists.Last().IdentifiedTwistData;
                if (last != null && allTwistData.Count > 2)
                {
                    while (last == m_currentTwist.IdentifiedTwistData)
                    {
                        m_currentTwist.IdentifiedTwistData = allTwistData[rand.Next(allTwistData.Count)];
                    }
                }
                else
                {
                    m_currentTwist.IdentifiedTwistData = allTwistData[rand.Next(allTwistData.Count)];
                }

                TwistData td          = m_currentTwist.IdentifiedTwistData.TwistDataForStateCalcs.First();
                int       numSlices   = td.NumSlices;
                int       randomSlice = rand.Next(numSlices);
                if (!earthquake)
                {
                    randomSlice += 1;
                }
                m_currentTwist.SliceMask = SliceMask.SliceToMask(randomSlice);

                if (earthquake)
                {
                    int       choppedSeg   = m_currentTwist.SliceMask * 2;
                    Vector3D  lookup       = td.Pants.TinyOffset(choppedSeg);
                    Vector3D  reflected    = td.Pants.Hexagon.Segments[choppedSeg].ReflectPoint(lookup);
                    TwistData tdEarthQuake = m_puzzle.ClosestTwistingCircles(reflected);

                    m_currentTwist.IdentifiedTwistDataEarthquake = tdEarthQuake.IdentifiedTwistData;

                    // Fix scrambing here.
                    m_currentTwist.SliceMaskEarthquake = tdEarthQuake.Pants.Closest(reflected) / 2;
                }

                // Apply the twist.
                FinishRotate(updateStatus: false);
            }

            m_twistHistory.Scrambles += numTwists;

            InvalidateAllAndUpdateStatus();
        }