/** * Generate a random pyraminx position. * @param r random int generator */ public PyraminxSolverState RandomState(Random r) { var state = new PyraminxSolverState(); do { state.EdgePerm = r.Next(NEdgePerm); } while (PrunPerm[state.EdgePerm] == -1); // incorrect permutation (bad parity) state.EdgeOrient = r.Next(NEdgeOrient); state.CornerOrient = r.Next(NCornerOrient); state.Tips = r.Next(NTips); return(state); }
private static string Solve(PyraminxSolverState state, int desiredLength, bool exactLength, bool inverse, bool includingTips) { var r = new Random(); var solution = new int[MaxLength]; var foundSolution = false; // If we count the tips in the desired length, we have to subtract the number of unsolved tips from the length of the main puzzle search. if (includingTips) { desiredLength -= state.UnsolvedTips(); } var length = exactLength ? desiredLength : 0; while (length <= desiredLength) { if (Search(state.EdgePerm, state.EdgeOrient, state.CornerOrient, 0, length, 42, solution, r)) { foundSolution = true; break; } length++; } if (!foundSolution) { return(null); } var scramble = new StringBuilder((MaxLength + 4) * 3); if (inverse) { for (var i = length - 1; i >= 0; i--) { scramble.Append(" ").Append(InverseMoveToString[solution[i]]); } } else { for (var i = 0; i < length; i++) { scramble.Append(" ").Append(MoveToString[solution[i]]); } } // Scramble the tips var arrayTips = new int[4]; UnpackCornerOrient(state.Tips, arrayTips); for (var tip = 0; tip < 4; tip++) { var dir = arrayTips[tip]; if (dir > 0) { scramble.Append(" ") .Append(inverse ? TipToString[tip * 2 + dir - 1] : InverseTipToString[tip * 2 + dir - 1]); } } return(scramble.ToString().Trim()); }
/** * Return a generator of a given position in exactly length number of turns or not at all. * Returns either the solution or the generator (inverse solution) * @param state state * @param length length of the desired solution * @param includingTips do we want to include tips in the solution lenght ? * @return a string representing the solution or the scramble of a random position */ public string GenerateExactly(PyraminxSolverState state, int length, bool includingTips) { return(Solve(state, length, true, true, includingTips)); }
/** * Solve a given position in less than or equal to length number of turns. * Returns either the solution or the generator (inverse solution) * @param state state * @param length length of the desired solution * @param includingTips do we want to include tips in the solution lenght ? * @return a string representing the solution or the scramble of a random position */ public string SolveIn(PyraminxSolverState state, int length, bool includingTips) { return(Solve(state, length, false, false, includingTips)); }
public PyraminxSolverState ToPyraminxSolverState() { var state = new PyraminxSolverState(); /** Each face color is assigned a value so that the sum of the color (minus 1) of each edge gives a unique integer. * These edge values match the edge numbering in the PyraminxSolver class, making the following code simpler. * U * ____ ____ ____ ____ ____ ____ * \ /\ /\ / /\ \ /\ /\ / * \ / \5 / \ / / \ \ / \5 / \ / * \/____\/____\/ /____\ \/____\/____\/ * \ /\ / /\ /\ \ /\ / * face +2 \2 / \1 / /1 \ /3 \ \3 / \4 / face +4 * \/____\/ /____\/____\ \/____\/ * \ / /\ /\ /\ \ / * \ / / \ /0 \ / \ \ / * \/ /____\/____\/____\ \/ * face +0 * L ____ ____ ____ R * \ /\ /\ / * \ / \0 / \ / * \/____\/____\/ * \ /\ / * \2 / \4 / * face +1 \/____\/ * \ / * \ / * \/ * * B */ int[][] stickersToEdges = { new[] { _image[0][5], _image[1][2] }, new[] { _image[0][8], _image[2][5] }, new[] { _image[1][8], _image[2][8] }, new[] { _image[0][2], _image[3][8] }, new[] { _image[1][5], _image[3][5] }, new[] { _image[2][2], _image[3][2] } }; int[] colorToValue = { 0, 1, 2, 4 }; var edges = new int[6]; for (var i = 0; i < edges.Length; i++) { edges[i] = colorToValue[stickersToEdges[i][0]] + colorToValue[stickersToEdges[i][1]] - 1; // In the PyraminxSolver class, the primary facelet of each edge correspond to the lowest face number. if (stickersToEdges[i][0] > stickersToEdges[i][1]) { edges[i] += 8; } } state.EdgePerm = PyraminxSolver.PackEdgePerm(edges); state.EdgeOrient = PyraminxSolver.PackEdgeOrient(edges); int[][] stickersToCorners = { new[] { _image[0][1], _image[2][4], _image[3][1] }, new[] { _image[0][7], _image[1][1], _image[2][7] }, new[] { _image[0][4], _image[3][7], _image[1][4] }, new[] { _image[1][7], _image[3][4], _image[2][1] } }; /* The corners are supposed to be fixed, so we are also checking if they are in the right place. * We can use the sum trick, but here, no need for transition table :) */ var corners = new int[4]; for (var i = 0; i < corners.Length; i++) { //azzertEquals(stickersToCorners[i][0] + stickersToCorners[i][1] + stickersToCorners[i][2], correctSum[i]); // The following code is not pretty, sorry... if (stickersToCorners[i][0] < stickersToCorners[i][1] && stickersToCorners[i][0] < stickersToCorners[i][2]) { corners[i] = 0; } if (stickersToCorners[i][1] < stickersToCorners[i][0] && stickersToCorners[i][1] < stickersToCorners[i][2]) { corners[i] = 1; } if (stickersToCorners[i][2] < stickersToCorners[i][1] && stickersToCorners[i][2] < stickersToCorners[i][0]) { corners[i] = 2; } } state.CornerOrient = PyraminxSolver.PackCornerOrient(corners); /* For the tips, we use the same numbering */ int[][] stickersToTips = { new[] { _image[0][0], _image[2][3], _image[3][0] }, new[] { _image[0][6], _image[1][0], _image[2][6] }, new[] { _image[0][3], _image[3][6], _image[1][3] }, new[] { _image[1][6], _image[3][3], _image[2][0] } }; var tips = new int[4]; for (var i = 0; i < tips.Length; i++) { //int[] stickers = stickersToTips[i]; // We can use the same color check as for the corners. //azzertEquals(stickers[0] + stickers[1] + stickers[2], correctSum[i]); // For the tips, we don't have to check colors against face, but against the attached corner. var cornerPrimaryColor = stickersToCorners[i][0]; var clockwiseTurnsToMatchCorner = 0; while (stickersToTips[i][clockwiseTurnsToMatchCorner] != cornerPrimaryColor) { clockwiseTurnsToMatchCorner++; } tips[i] = clockwiseTurnsToMatchCorner; } state.Tips = PyraminxSolver.PackCornerOrient(tips); // Same function as for corners. return(state); }