private void StartSearch() { #region rotate cube CubieCube rotatedCube = CubieCube.CreateSolved(); for (int i = 0; i < _rotation; i++) { rotatedCube.Rotate(Rotation.y3); rotatedCube.Rotate(Rotation.x3); } rotatedCube.Multiply(_notRotatedCube); for (int i = 0; i < _rotation; i++) { rotatedCube.Rotate(Rotation.x1); rotatedCube.Rotate(Rotation.y1); } if (_inversed) { rotatedCube.Inverse(); } #endregion rotate cube //calculate coordinates int co = Coordinates.GetCornerOrientation(rotatedCube); int cp = Coordinates.GetCornerPermutation(rotatedCube); int eo = Coordinates.GetEdgeOrientation(rotatedCube); int equator = Coordinates.GetEquatorPermutation(rotatedCube); int uEdges = Coordinates.GetUEdgePermutation(rotatedCube); int dEdges = Coordinates.GetDEdgePermutation(rotatedCube); //store coordinates used in phase 2 _cp = cp; _uEdges = uEdges; _dEdges = dEdges; int pruningIndex = PruningTables.GetPhase1PruningIndex(co, eo, equator / Coordinates.NumEquatorOrders); int minPhase1Length = TableController.Phase1PruningTable[pruningIndex]; int maxPhase1Length = (_requiredLength > 0 && _requiredLength < GodsNumber) ? _requiredLength : GodsNumber; _currentPhase1Solution = new int[maxPhase1Length]; _currentPhase2Solution = new int[MaxPhase2Length]; for (int phase1Length = minPhase1Length; phase1Length < maxPhase1Length; phase1Length++) { SearchPhase1(eo, co, equator, depth: 0, remainingMoves: phase1Length, minPhase1Length); } }
//TODO handle exceptions /// <summary> /// Initialize the corner permutation and equator permutation pruning /// table for phase 2. /// </summary> public static void InitializePhase2CornerUdPruningTable() { if (Phase2CornerUdPruningTable is null) { string file = Directory + @"\phase2CornerUd.pruningtable"; if (File.Exists(file)) { Console.WriteLine("Loading phase 2 corner permutation and U- and D-edge permutation pruning table"); Phase2CornerUdPruningTable = File.ReadAllBytes(file); } else { Console.WriteLine("Initializing phase 2 corner permutation and U- and D-edge permutation pruning table"); Phase2CornerUdPruningTable = PruningTables.CreatePhase2CornerUdTable(); File.WriteAllBytes(file, Phase2CornerUdPruningTable); } } }
//TODO add exception handling /// <summary> /// Initialize the pruning table for phase 1. /// </summary> public static void InitializePhase1PruningTable() { if (Phase1PruningTable is null) { string file = Directory + @"\phase1.pruningtable"; if (File.Exists(file)) { Console.WriteLine("Loading phase 1 pruning table"); Phase1PruningTable = File.ReadAllBytes(file); } else { Console.WriteLine("Initializing phase 1 pruning table"); Phase1PruningTable = PruningTables.CreatePhase1Table(); File.WriteAllBytes(file, Phase1PruningTable); } } }
private void SearchPhase2(int cp, int equatorPermutation, int udEdgeOrder, int depth, int remainingMoves, int phase1Length) { if (IsTerminated.Value) { return; } if (remainingMoves == 0 && equatorPermutation == 0) //check if solved { Alg solution = Alg.FromEnumerable(_currentPhase1Solution.Take(phase1Length).Concat(_currentPhase2Solution.Take(depth)).Cast <Move>()); for (int i = 0; i < _rotation; i++) { solution = solution.Rotate(Rotation.y3).Rotate(Rotation.x3); } if (_inversed) { solution = solution.Inverse(); } lock (_lockObject) { if (solution.Length < _shortestSolutionLength.Value) { _shortestSolutionIndex.Value = _solutions.Count; _shortestSolutionLength.Value = solution.Length; } _solutions.Add(solution); } if (solution.Length <= _returnLength) { IsTerminated.Value = true; } return; } //increase depth foreach (int move in TwoPhaseConstants.Phase2Moves) { //prevent two consecutive moves on the same face or two //consecutive moves on the same axis in the wrong order if (depth == 0) { if (phase1Length > 0) { int relation = move / 3 - _currentPhase1Solution[phase1Length - 1] / 3; if (relation == SameFace || relation == SameAxisInWrongOrder) { continue; } } } else { int relation = move / 3 - _currentPhase2Solution[depth - 1] / 3; if (relation == SameFace || relation == SameAxisInWrongOrder) { continue; } } int newCp = TableController.CornerPermutationMoveTable[cp, move]; int newEquatorPermutation = TableController.EquatorPermutationMoveTable[equatorPermutation, move]; int newUdEdgePermutation = TableController.UdEdgeOrderMoveTable[udEdgeOrder, MoveTables.Phase1IndexToPhase2Index[move]]; //prune int cornerUdPruningIndex = PruningTables.GetPhase2CornerUdPruningIndex(newUdEdgePermutation, newCp); int cornerUdPruningValue = TableController.Phase2CornerUdPruningTable[cornerUdPruningIndex]; int cornerEquatorPruningIndex = Coordinates.NumEquatorOrders * newCp + newEquatorPermutation; int cornerEquatorPruningValue = TableController.Phase2CornerEquatorPruningTable[cornerEquatorPruningIndex]; if (Math.Max(cornerUdPruningValue, cornerEquatorPruningValue) > remainingMoves - 1) { continue; } _currentPhase2Solution[depth] = move; SearchPhase2(newCp, newEquatorPermutation, newUdEdgePermutation, depth + 1, remainingMoves - 1, phase1Length); } }
private void SearchPhase1(int eo, int co, int equator, int depth, int remainingMoves, int previousPruningValue) { if (IsTerminated.Value) { return; } if (remainingMoves == 0) //check if solved { lock (_lockObject) //manage timeout if (_timePassed.Elapsed > _timeout && (_requiredLength < 0 || (_solutions.Count > 0 && _shortestSolutionLength.Value <= _requiredLength))) { IsTerminated.Value = true; } int cp = _cp; int uEdges = _uEdges; int dEdges = _dEdges; int equatorPermutation = equator; //TEST improvement for (int moveIndex = 0; moveIndex < depth; moveIndex++) { int move = _currentPhase1Solution[moveIndex]; cp = TableController.CornerPermutationMoveTable[cp, move]; } int cornerEquatorPruningIndex = Coordinates.NumEquatorOrders * cp + equator; int cornerEquatorPruningValue = TableController.Phase2CornerEquatorPruningTable[cornerEquatorPruningIndex]; if (cornerEquatorPruningValue > MaxPhase2Length) { return; } for (int moveIndex = 0; moveIndex < depth; moveIndex++) { int move = _currentPhase1Solution[moveIndex]; uEdges = TableController.UEdgePermutationMoveTable[uEdges, move]; dEdges = TableController.DEdgePermutationMoveTable[dEdges, move]; } int udEdgeOrder = Coordinates.CombineUEdgePermutationAndDEdgeOrder(uEdges, dEdges % Coordinates.NumDEdgeOrders); //prune int cornerUdPruningIndex = PruningTables.GetPhase2CornerUdPruningIndex(udEdgeOrder, cp); int minMoves = TableController.Phase2CornerUdPruningTable[cornerUdPruningIndex]; int maxMoves = Math.Min(_shortestSolutionLength.Value - depth - 1, MaxPhase2Length); for (int length = minMoves; length <= maxMoves; length++) { SearchPhase2(cp, equatorPermutation, udEdgeOrder, depth: 0, remainingMoves: length, phase1Length: depth); } return; } //increase depth for (int move = 0; move < NumMoves; move++) { //If the cube is already in the subgroup H and there are less //than 5 moves left it is only possible to stay in the subgroup //if exclusivly phase 2 moves are used, which means that this //solution can also be generated in phase 2. if (previousPruningValue == 0 && remainingMoves < 5 && !TwoPhaseConstants.Phase2Moves.Contains((Move)move)) { continue; } //prevent two consecutive moves on the same face or two //consecutive moves on the same axis in the wrong order if (depth > 0) { int relation = move / 3 - _currentPhase1Solution[depth - 1] / 3; if (relation == SameFace || relation == SameAxisInWrongOrder) { continue; } } int newEo = TableController.EdgeOrientationMoveTable[eo, move]; int newCo = TableController.CornerOrientationMoveTable[co, move]; int newEquator = TableController.EquatorPermutationMoveTable[equator, move]; //prune int pruningCoord = PruningTables.GetPhase1PruningIndex(newCo, newEo, newEquator / Coordinates.NumEquatorOrders); int pruningValue = TableController.Phase1PruningTable[pruningCoord]; if (pruningValue > remainingMoves - 1) { continue; } _currentPhase1Solution[depth] = move; SearchPhase1(newEo, newCo, newEquator, depth + 1, remainingMoves - 1, pruningValue); } }
private void StartSearch() { #region rotate cube CubieCube rotatedCube = CubieCube.CreateSolved(); for (int i = 0; i < _rotation; i++) { rotatedCube.Rotate(Rotation.y3); rotatedCube.Rotate(Rotation.x3); } rotatedCube.Multiply(_notRotatedCube); for (int i = 0; i < _rotation; i++) { rotatedCube.Rotate(Rotation.x1); rotatedCube.Rotate(Rotation.y1); } if (_inversed) { rotatedCube.Inverse(); } #endregion rotate cube #region rotate weights _rotatedWeights = new float[NumMoves]; for (int oldIndex = 0; oldIndex < NumMoves; oldIndex++) { int newIndex = oldIndex; for (int i = 0; i < _rotation; i++) { newIndex = (int)((Move)newIndex).Rotate(Rotation.x1).Rotate(Rotation.y1); } _rotatedWeights[newIndex] = _nonRotatedWeights[oldIndex]; } if (_inversed) { for (int face = 0; face < NumFaces; face++) { //face * 3 = 90° cw, face * 3 + 2 = 90° ccw float temp = _rotatedWeights[face * 3]; _rotatedWeights[face * 3] = _rotatedWeights[face * 3 + 2]; _rotatedWeights[face * 3 + 2] = temp; } } #endregion rotate weights _phase1MoveOrder = MoveWeightsUtils.OrderedMoves((Move[])Enum.GetValues(typeof(Move)), _rotatedWeights); _phase2MoveOrder = MoveWeightsUtils.OrderedMoves(TwoPhaseConstants.Phase2Moves, _rotatedWeights); //calculate coordinates int co = Coordinates.GetCornerOrientation(rotatedCube); int cp = Coordinates.GetCornerPermutation(rotatedCube); int eo = Coordinates.GetEdgeOrientation(rotatedCube); int equator = Coordinates.GetEquatorPermutation(rotatedCube); int uEdges = Coordinates.GetUEdgePermutation(rotatedCube); int dEdges = Coordinates.GetDEdgePermutation(rotatedCube); //store coordinates used in phase 2 _cp = cp; _uEdges = uEdges; _dEdges = dEdges; int pruningIndex = PruningTables.GetPhase1PruningIndex(co, eo, equator / Coordinates.NumEquatorOrders); int minPhase1Length = TableController.Phase1PruningTable[pruningIndex]; _currentPhase1Solution = new int[MaxPhase1Length]; _currentPhase2Solution = new int[MaxPhase2Length]; for (int phase1Length = minPhase1Length; phase1Length < MaxPhase1Length; phase1Length++) { SearchPhase1(eo, co, equator, depth: 0, remainingMoves: phase1Length, minPhase1Length); } }