public static ImmutableFaceletCube ToFaceletCube(this ICubieCube cubieCube) { var facelets = new FaceColor[Extensions.GetEnumValues <FaceletPosition>().Count()]; foreach (var i in Extensions.GetEnumValues <Corner>().Cast <int>()) { var corner = cubieCube.CornerPositions[i]; var orientation = cubieCube.CornerOrientations[i]; for (var k = 0; k < 3; k++) { facelets[(int)Definitions.CornerFacelet[i][(k + orientation) % 3]] = Definitions.CornerColor[(int)corner][k]; } } foreach (var i in Extensions.GetEnumValues <Edge>().Cast <int>()) { var edge = cubieCube.EdgePositions[i]; var orientation = cubieCube.EdgeOrientations[i]; for (var k = 0; k < 2; k++) { facelets[(int)Definitions.EdgeFacelet[i][(k + orientation) % 2]] = Definitions.EdgeColor[(int)edge][k]; } } //set centers foreach (var c in Extensions.GetEnumValues <FaceColor>()) { var centre = (int)c * 9 + 4; facelets[centre] = c; } var fc = new ImmutableFaceletCube(facelets); return(fc); }
/// <inheritdoc /> public NamedCubieCube(string name, ICubieCube cube) { Name = name; CornerOrientations = cube.CornerOrientations.ToImmutableArray(); CornerPositions = cube.CornerPositions.ToImmutableArray(); EdgeOrientations = cube.EdgeOrientations.ToImmutableArray(); EdgePositions = cube.EdgePositions.ToImmutableArray(); }
public static ImmutableCoordinateCube ToCoordinateCube(this ICubieCube cubieCube, DataSource dataSource) { return(new ImmutableCoordinateCube( cubieCube.get_flip(), cubieCube.get_twist(), cubieCube.get_slice_sorted(), cubieCube.GetCorners(), cubieCube.get_u_edges(), cubieCube.get_d_edges(), dataSource)); }
#pragma warning restore 659 #endregion // Multiply this MoveCubes cube with another MoveCubes cube b, restricted to the corners. Does not change b. public void CornerMultiply(ICubieCube b) { var cPerm = new Corner[8]; //TODO stackalloc var cOri = new int[8]; var ori = 0; foreach (var c in Extensions.GetEnumValues <Corner>().Cast <int>()) { cPerm[c] = _cornerPositions[(int)b.CornerPositions[c]]; var oriA = _cornerOrientations[(int)b.CornerPositions[c]]; var oriB = b.CornerOrientations[c]; if (oriA < 3 && oriB < 3) { // two regular cubes ori = oriA + oriB; if (ori >= 3) { ori -= 3; } } else if (oriA < 3 && 3 <= oriB) { // cube b is in a mirrored state ori = oriA + oriB; if (ori >= 6) { ori -= 3; } } else if (oriA >= 3 && 3 > oriB) { // cube a is in a mirrored state ori = oriA - oriB; if (ori < 3) { ori += 3; } } else if (oriA >= 3 && oriB >= 3) { // if both cubes are in mirrored states ori = oriA - oriB; if (ori < 0) { ori += 3; } } cOri[c] = ori; } cPerm.CopyTo(_cornerPositions, 0); cOri.CopyTo(_cornerOrientations, 0); }
/// <summary> /// Get the flip of the 12 Edge. /// The flip is between 0 and 2047 inclusive in phase 1. /// The flip is zero in phase 2. /// </summary> /// <param name="cubieCube"></param> /// <returns></returns> public static ushort get_flip(this ICubieCube cubieCube) { var ret = 0; for (var i = 0; i < 11; i++) { ret = 2 * ret + cubieCube.EdgeOrientations[i]; } Debug.Assert(ret <= 2047); return(Convert.ToUInt16(ret)); }
// Multiply this MoveCubes cube with another cubiecube b, restricted to the Edge. Does not change b. //TODO comments should be summary comments public void EdgeMultiply(ICubieCube b) { var ePerm = new Edge[12]; //TODO stackalloc var eOri = new int[12]; foreach (var e in Extensions.GetEnumValues <Edge>().Cast <int>()) { ePerm[e] = EdgePositions[(int)b.EdgePositions[e]]; eOri[e] = (b.EdgeOrientations[e] + EdgeOrientations[(int)b.EdgePositions[e]]) % 2; } ePerm.CopyTo(_edgePositions, 0); eOri.CopyTo(_edgeOrientations, 0); }
/// <summary> /// Get the twist of the 8 corners. /// In phase 1 the twist is between zero and 2186 inclusive. /// In phase 2, the twist is zero. /// </summary> public static ushort get_twist(this ICubieCube cubieCube) { var ret = 0; for (var i = 0; i < 7; i++) { ret = 3 * ret + cubieCube.CornerOrientations[i]; } var r = Convert.ToUInt16(ret); Debug.Assert(r <= 2186); return(r); }
private static void CheckCube(ICubieCube symCube) { var currentCube = symCube.Clone(); for (var i = 0; i <= 12; i++) { currentCube.Multiply(symCube); if (currentCube.Equals(SolvedCube.Instance)) { return; } } Assert.True(currentCube.Equals(SolvedCube.Instance), "Cube was not solved after 12 applications"); }
/// <summary> /// Gets the edge permutation parity. A solvable cube has the same corner and edge parity. /// </summary> /// <param name="cubieCube"></param> /// <returns></returns> public static int GetEdgeParity(this ICubieCube cubieCube) { var s = 0; for (var i = 11; i > 0; i--) { for (var j = i - 1; j >= 0; j--) { if (cubieCube.EdgePositions[j] > cubieCube.EdgePositions[i]) { s += 1; } } } return(s % 2); }
/// <summary> /// Get the permutation of the 8 corners. /// Between 0 and 40319 /// 0 for solved cube /// </summary> public static ushort GetCorners(this ICubieCube cubieCube) { var perm = cubieCube.CornerPositions.ToArray(); var b = 0; for (var j = 7; j > 0; j--) { var k = 0; while (perm[j] != (Corner)j) { perm.rotate_left(0, j); k += 1; } b = (j + 1) * b + k; } return(Convert.ToUInt16(b)); }
/// <summary> /// Get the permutation of the 8 U and D Edge. /// Undefined in phase 1. /// Between 0 and 40319 inclusive in phase 2. /// 0 in solved cube. /// </summary> /// <param name="cubieCube"></param> /// <returns></returns> public static ushort get_ud_edges(this ICubieCube cubieCube) { var perm = cubieCube.EdgePositions.Take(8).ToArray(); //use slice var b = 0; for (var j = 7; j > 0; j--) { var k = 0; while ((int)perm[j] != j) { perm.rotate_left(0, j); k += 1; } b = (j + 1) * b + k; } return(Convert.ToUInt16(b)); }
private static IEnumerable <SearchState> CreateSearches(ICubieCube baseCube, DataSource dataSource) { for (byte rot = 0; rot <= 2; rot++) { foreach (var inv in new[] { false, true }) { MutableCubieCube cb; if (rot == 0) { // no rotation cb = baseCube.Clone(); } else if (rot == 1) { // conjugation by 120° rotation cb = Symmetries.Basic.Cubes[32].Clone(); cb.Multiply(baseCube); cb.Multiply(Symmetries.Basic.Cubes[16]); } else if (rot == 2) { // conjugation by 240° rotation cb = Symmetries.Basic.Cubes[16].Clone(); cb.Multiply(baseCube); cb.Multiply(Symmetries.Basic.Cubes[32]); } else { throw new ArgumentException("Rotation should be 1,2, or 3"); } if (inv) { cb = cb.Invert(); // invert cube } var coCube = cb.ToCoordinateCube(dataSource); var search = new SearchState(inv, rot, coCube, ImmutableLinkedList <Move> .Empty, false); yield return(search); } } }
public static Solution?Solve(this ICubieCube cbCube, TimeSpan timeout, int?stoppingLength, DataSource dataSource) { using var solveCoordinator = new SerialSolveCoordinator(dataSource); using var cts = new CancellationTokenSource(timeout); var searches = CreateSearches(cbCube, dataSource); foreach (var searchState in searches) { solveCoordinator.MaybeAddSearch(searchState); } var solution = solveCoordinator.GetSolution(stoppingLength, cts.Token); cts.Cancel(); return(solution); }
/// <summary> /// Inverts this cube /// </summary> /// <returns></returns> public static MutableCubieCube Invert(this ICubieCube cubieCube) { var edgePositions = new Edge[12]; var edgeOrientations = new int[12]; var cornerPositions = new Corner[8]; var cornerOrientations = new int[8]; foreach (var e in Extensions.GetEnumValues <Edge>().Cast <int>()) { edgePositions[(int)cubieCube.EdgePositions[e]] = (Edge)e; } foreach (var e in Extensions.GetEnumValues <Edge>().Cast <int>()) { edgeOrientations[e] = cubieCube.EdgeOrientations[(int)edgePositions[e]]; } foreach (var c in Extensions.GetEnumValues <Corner>()) { cornerPositions[(int)cubieCube.CornerPositions[(int)c]] = c; } foreach (var c in Extensions.GetEnumValues <Corner>().Cast <int>()) { var ori = cubieCube.CornerOrientations[(int)cornerPositions[c]]; if (ori >= 3) { cornerOrientations[c] = ori; } else { cornerOrientations[c] = -ori; if (cornerOrientations[c] < 0) { cornerOrientations[c] += 3; //TODO look at this - can orientation be negative? } } } return(new MutableCubieCube(cornerPositions, cornerOrientations, edgePositions, edgeOrientations)); }
/// <summary> /// Get the symmetries and antisymmetries of the cube /// </summary> public static IEnumerable <int> Symmetries(this ICubieCube cubieCube) { for (var j = 0; j < Definitions.NSym; j++) { var c = Basic.Cubes[j].Clone(); c.Multiply(cubieCube); c.Multiply(Inverse.GetCube(j)); if (CubeComparer.Instance.Equals(cubieCube, c)) { yield return(j); } var d = c.Invert(); if (CubeComparer.Instance.Equals(cubieCube, d)) { yield return(j + Definitions.NSym); } } }
public static async Task <Solution?> SolveAsync(this ICubieCube cbCube, int numberOfThreads, TimeSpan timeout, int?stoppingLength, DataSource dataSource) { using var solveCoordinator = new ParallelSolveCoordinator(numberOfThreads, dataSource); using var cts = new CancellationTokenSource(timeout); var searches = CreateSearches(cbCube, dataSource); foreach (var searchState in searches) { solveCoordinator.MaybeAddSearch(searchState); } var solution = solveCoordinator.GetSolution(stoppingLength, cts.Token); cts.Cancel(); await Task.CompletedTask; return(solution); }
/// <summary> /// Get the location of the UD-slice edges FR,FL,BL and BR ignoring their permutation. /// Slice is between 0 and 494 inclusive in phase 1. /// Slice is zero in phase 2. /// </summary> public static ushort get_slice(this ICubieCube cubieCube) { var a = 0; var x = 0; // Compute the index a < (12 choose 4) for (var j = 11; j >= 0; j--) { if (Edge.Fr > cubieCube.EdgePositions[j] || cubieCube.EdgePositions[j] > Edge.Br) { continue; } a += Miscellaneous.BinomialChoose(11 - j, x + 1); x += 1; } Debug.Assert(a <= 495); return(Convert.ToUInt16(a)); }
private static ushort GetEdges(this ICubieCube cubieCube, int offset) { var a = 0; var x = 0; var edge4 = new int[4]; var epMod = cubieCube.EdgePositions.ToArray(); for (var k = 0; k < 4; k++) { epMod.rotate_right(0, 11); } // First compute the index a < (12 choose 4) and the permutation array perm. for (var j = 11; j >= 0; j--) { var epModJ = (int)epMod[j]; if (offset <= epModJ && epModJ <= 3 + offset) { a += Miscellaneous.BinomialChoose(11 - j, x + 1); edge4[3 - x] = epModJ; x += 1; } } // Then compute the index b < 4! for the permutation in edge4 var b = 0; for (var j = 3; j > 0; j--) { var k = 0; while (edge4[j] != j + offset) { edge4.rotate_left(0, j); k += 1; } b = (j + 1) * b + k; } return(Convert.ToUInt16(24 * a + b)); }
/// <summary> /// Get the permutation and location of the UD-slice edges FR,FL,BL and BR. /// Between 0 and 11879 inclusive in phase 1. /// Between 0 and 24 in phase 2. /// 0 for solved cube. /// </summary> /// <param name="cubieCube"></param> /// <returns></returns> public static ushort get_slice_sorted(this ICubieCube cubieCube) { var a = 0; var x = 0; var edge4 = new Edge[4]; // First compute the index a < (12 choose 4) and the permutation array perm. for (var j = 11; j >= 0; j--) { var edge = cubieCube.EdgePositions[j]; if (Edge.Fr <= edge && edge <= Edge.Br) { a += Miscellaneous.BinomialChoose(11 - j, x + 1); edge4[3 - x] = edge; x += 1; } } // Then compute the index b < 4! for the permutation in edge4 var b = 0; for (var j = 3; j > 0; j--) { var k = 0; while ((int)edge4[j] != j + 8) { edge4.rotate_left(0, j); k += 1; } b = (j + 1) * b + k; } var r = 24 * a + b; return(Convert.ToUInt16(r)); }
/// <inheritdoc /> public override ushort GetValue(ICubieCube cube) => cube.get_flip();
/// <inheritdoc /> public override ushort GetValue(ICubieCube cube) => cube.get_d_edges();
/// <inheritdoc /> public override ushort GetValue(ICubieCube cube) => cube.GetCorners();
/// <summary> /// Get the permutation and location of the edges DR, DF, DL and DB. /// Between 0 and 11879 inclusive in phase 1 /// Between 0 and 1679 inclusive in phase 2 /// 1656 for solved cube /// </summary> public static ushort get_d_edges(this ICubieCube cubieCube) => GetEdges(cubieCube, 4);
public abstract ushort GetValue(ICubieCube cube);
public SolverTestCase(ICubieCube cube) { Cube = cube; }
public bool Equals(ICubieCube other) { return(CubeComparer.Instance.Equals(this, other)); }
public TestCase(ICubieCube cube, IReadOnlyList <Move> expectedSteps) { Cube = cube; ExpectedSteps = expectedSteps; }
/// <inheritdoc /> public override ushort GetValue(ICubieCube cube) => cube.get_slice_sorted();
/// <summary> /// Multiply with another MoveCubes cube. /// </summary> public void Multiply(ICubieCube b) { CornerMultiply(b); EdgeMultiply(b); }
/// <inheritdoc /> public override ushort GetValue(ICubieCube cube) => cube.get_twist();