/// <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); }
public PickInfo(Polygon poly, TwistData twistData) { Poly = poly; TwistData = twistData; }
/// <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(); }