diff --git a/catch-all/09_rubiks-cube-solver/README.md b/catch-all/09_rubiks-cube-solver/README.md new file mode 100644 index 0000000..773f1d5 --- /dev/null +++ b/catch-all/09_rubiks-cube-solver/README.md @@ -0,0 +1,33 @@ +# Solucionador de Cubo de Rubik + +Solucionador de Cubo de Rubik codificado en Python. + +> Repositorio original: https://github.com/CubeLuke/Rubiks-Cube-Solver +> Codificado por Lucas y Tom Brannan + +Para ejecutar el solucionador, ejecuta el archivo cube.py. La interfaz gráfica se iniciará automáticamente. Si obtienes errores, es posible que no tengas tkinter instalado. Es necesario tenerlo para ejecutar la interfaz gráfica. + +### Características +Solo lee las instrucciones para ver algunas de las características incluidas en el solucionador. +Entre las características incluidas se encuentran: +* Scrambles generados por el usuario o por el programa +* La capacidad de hacer movimientos personalizados +* La capacidad de presionar el botón de resolución o cada paso de la resolución para ver el cubo resolverse paso a paso +* La capacidad de ejecutar simulaciones con una cantidad definida por el usuario de resoluciones (ten cuidado, demasiadas podrían hacer que el programa se congele) +* Capacidad de copiar scrambles o soluciones al portapapeles, así como verlas externamente +* Hacer clic en el cubo 2D te permitirá ver los otros mosaicos inferiores que normalmente no son visibles + +
+ +
+ +### Comandos Varios +Si no deseas usar la interfaz gráfica, también puedes escribir comandos de función en el intérprete. Aquí tienes algunos de los útiles: +* print_cube() Imprime el cubo en formato de texto +* scramble() Puedes proporcionar un número, un scramble en formato de cadena o nada para un scramble por defecto de 25 movimientos +* get_scramble() Imprime el scramble previo +* solve() Resolverá el cubo +* get_moves() Imprime la solución que se generó al usar solve() +* simulation(num) El número proporcionado es la cantidad de resoluciones que deseas simular. Te devolverá la mejor resolución con su scramble, así como la peor resolución y su scramble. + +El solucionador en sí está basado en el método CFOP (Fridrich) para resolver el cubo. Resuelve el Cross, realiza el paso F2L, hace un OLL de 2 pasos y un PLL de 2 pasos. En cuanto a la notación, se utiliza la notación básica del mundo del cubing; sin embargo, un movimiento en sentido contrario a las agujas del reloj puede denotarse con un apóstrofe (forma estándar) o usando la letra i (denotando i para inverso). diff --git a/catch-all/09_rubiks-cube-solver/cube.py b/catch-all/09_rubiks-cube-solver/cube.py new file mode 100644 index 0000000..aa2294b --- /dev/null +++ b/catch-all/09_rubiks-cube-solver/cube.py @@ -0,0 +1,2011 @@ +""" +Este es el Solucionador de Cubos +Esta versión contiene una interfaz gráfica +Última edición el: 05/12/2014 +Escrito originalmente por: +- Lucas Liberacki (https://github.com/CubeLuke) +- & Tom Brannan (https://github.com/TomBrannan) +Modificado por manuelver +""" + +from random import randint +from tkinter import * + +import copy +import webbrowser +import os +import tkinter as tk + + +# Variables globales +moves_list = [] +last_scramble = [] +f2l_list = [] +step_moves_list = [] +solution_length = 0 + + +# creates a 3d list representing a solved cube +def make_cube(): + global step_moves_list, f2l_list, moves_list + step_moves_list = [0, 0, 0, 0] + f2l_list = [] + moves_list = [] + return [[ + ['W', 'W', 'W'], + ['W', 'W', 'W'], + ['W', 'W', 'W']], # Arriba/blanco + + [['G', 'G', 'G'], + ['G', 'G', 'G'], + ['G', 'G', 'G']], # Frontal/verde + + [['R', 'R', 'R'], + ['R', 'R', 'R'], + ['R', 'R', 'R']], # Derecha/rojo + + [['O', 'O', 'O'], + ['O', 'O', 'O'], + ['O', 'O', 'O']], # Izquierda/naranja + + [['Y', 'Y', 'Y'], + ['Y', 'Y', 'Y'], + ['Y', 'Y', 'Y']], # Abajo/amarillo + + [['B', 'B', 'B'], + ['B', 'B', 'B'], + ['B', 'B', 'B'] # Trasero/azul + ]] + + +a = make_cube() + + +# Imprime una representación en cadena del cubo en el intérprete +def print_cube(): + print('\t\t'+str(a[5][0])+'\n\t\t'+str(a[5][1])+'\n\t\t'+str(a[5][2])) + print(str(a[3][0])+' '+str(a[0][0])+' '+str(a[2][0])) + print(str(a[3][1])+' '+str(a[0][1])+' '+str(a[2][1])) + print(str(a[3][2])+' '+str(a[0][2])+' '+str(a[2][2])) + print('\t\t'+str(a[1][0])+'\n\t\t'+str(a[1][1])+'\n\t\t'+str(a[1][2])) + print('\t\t'+str(a[4][0])+'\n\t\t'+str(a[4][1])+'\n\t\t'+str(a[4][2])) + + +# Simplifica la lista de movimientos y devuelve una representación en cadena de +# los movimientos +def get_moves(): + simplify_moves() + s = "" + for i in moves_list: + s += str(i) + " " + s = str.replace(s, "i", "'")[:-1] + return s + + +# Devuelve una representación en cadena del último scramble +def get_scramble(): + s = "" + for i in last_scramble: + s += str(i) + " " + s = str.replace(s, "i", "'")[:-1] + return s + + +# Función auxiliar: +# devuelve True si todos los elementos en un conjunto son iguales +def all_same(items): + return all(x == items[0] for x in items) + + +# Transforma un movimiento dado en el movimiento correspondiente después de una +# rotación Y +def yTransform(move): + if move[0] in ["U", "D"]: + return move + if move[0] == "F": + return "R" + move[1:] + if move[0] == "R": + return "B" + move[1:] + if move[0] == "B": + return "L" + move[1:] + if move[0] == "L": + return "F" + move[1:] + raise Exception("Invalid move to yTransform: " + move) + + +# Modifica la lista global de movimientos eliminando redundancias +def simplify_moves(): + global moves_list, solution_length + new_list = [] + prev_move = "" + yCount = 0 + for move in moves_list: + if move == "Y": + yCount += 1 + yCount %= 4 + continue + if move == "Yi": + yCount += 3 + yCount %= 4 + continue + if move == "Y2": + yCount += 2 + yCount %= 4 + continue + if yCount > 0: + for i in range(yCount): + move = yTransform(move) + if prev_move == "" or prev_move == '': + prev_move = move + new_list.append(move) + continue + if move[0] == prev_move[0]: + if len(move) == 1: + if len(prev_move) <= 1: + del new_list[-1] + mv = move[0] + "2" + new_list.append(mv) + prev_move = mv + continue + if prev_move[1] == "i": + del new_list[-1] + prev_move = new_list[-1] if len(new_list) > 0 else "" + continue + if prev_move[1] == "2": + del new_list[-1] + mv = move[0] + "i" + new_list.append(mv) + prev_move = mv + continue + if move[1] == "i": + if len(prev_move) == 1: + del new_list[-1] + prev_move = new_list[-1] if len(new_list) > 0 else "" + continue + if prev_move[1] == "i": + del new_list[-1] + mv = move[0] + "2" + new_list.append(mv) + prev_move = mv + continue + if prev_move[1] == "2": + del new_list[-1] + mv = move[0] + new_list.append(mv) + prev_move = mv + continue + if move[1] == "2": + if len(prev_move) == 1: + del new_list[-1] + mv = move[0] + "i" + new_list.append(mv) + prev_move = mv + continue + if prev_move[1] == "i": + del new_list[-1] + mv = move[0] + new_list.append(mv) + prev_move = mv + continue + if prev_move[1] == "2": + del new_list[-1] + prev_move = new_list[-1] if len(new_list) > 0 else "" + continue + new_list.append(move) + prev_move = move + solution_length = len(new_list) + moves_list = new_list + + +# Configura el cubo para realizar un movimiento rotando esa cara hacia arriba +def setup(face): + face = str.lower(face) + if face == "f": + move("X") + elif face == "r": + move("Zi") + elif face == "l": + move("Z") + elif face == "d": + move("X2") + elif face == "b": + move("Xi") + else: + raise Exception("Invalid setup; face: " + face) + + +# Realiza la inversa de setup para restaurar la orientación previa del cubo +def undo(face): + face = str.lower(face) + if face == "f": + move("Xi") + elif face == "r": + move("Z") + elif face == "l": + move("Zi") + elif face == "d": + move("X2") + elif face == "b": + move("X") + else: + raise Exception("Invalid undo; face: " + face) + + +# Tokeniza una cadena de movimientos +def m(s): + s = str.replace(s, "'", "i") + k = s.split(' ') + global moves_list, solution_length + solution_length += len(k) + for word in k: + moves_list.append(word) + move(word) + + +# Realiza un movimiento configurando, ejecutando movimientos U y deshaciendo la +# configuración +def move(mv): + mv = str.lower(mv) + if mv == "u": + U() + elif mv == "u2": + move("U") + move("U") + elif mv == "ui": + move("U") + move("U") + move("U") + elif mv == "f": + setup("F") + U() + undo("F") + elif mv == "f2": + move("F") + move("F") + elif mv == "fi": + move("F") + move("F") + move("F") + elif mv == "r": + setup("R") + U() + undo("R") + elif mv == "r2": + move("R") + move("R") + elif mv == "ri": + move("R") + move("R") + move("R") + elif mv == "l": + setup("L") + U() + undo("L") + elif mv == "l2": + move("L") + move("L") + elif mv == "li": + move("L") + move("L") + move("L") + elif mv == "b": + setup("B") + U() + undo("B") + elif mv == "b2": + move("B") + move("B") + elif mv == "bi": + move("B") + move("B") + move("B") + elif mv == "d": + setup("D") + U() + undo("D") + elif mv == "d2": + move("D") + move("D") + elif mv == "di": + move("D") + move("D") + move("D") + elif mv == "x": + rotate("X") + elif mv == "x2": + move("X") + move("X") + elif mv == "xi": + move("X") + move("X") + move("X") + elif mv == "y": + rotate("Y") + elif mv == "y2": + move("Y") + move("Y") + elif mv == "yi": + move("Y") + move("Y") + move("Y") + elif mv == "z": + rotate("Z") + elif mv == "z2": + move("Z") + move("Z") + elif mv == "zi": + move("Z") + move("Z") + move("Z") + elif mv == "uw": + move("D") + move("Y") + elif mv == "uw2": + move("UW") + move("UW") + elif mv == "uwi": + move("UW") + move("UW") + move("UW") + elif mv == "m": + move("Li") + move("R") + move("Xi") + elif mv == "mi": + move("M") + move("M") + move("M") + elif mv == "m2": + move("M") + move("M") + elif mv == "rw": + move("L") + move("X") + elif mv == "rwi": + move("RW") + move("RW") + move("RW") + elif mv == "rw2": + move("RW") + move("RW") + elif mv == "fw": + move("Bi") + move("Z") + elif mv == "fwi": + move("FW") + move("FW") + move("FW") + elif mv == "fw2": + move("FW") + move("FW") + elif mv == "lw": + move("R") + move("Xi") + elif mv == "lwi": + move("LW") + move("LW") + move("LW") + elif mv == "lw2": + move("LW") + move("LW") + elif mv == "bw": + move("F") + move("Zi") + elif mv == "bwi": + move("BW") + move("BW") + move("BW") + elif mv == "bw2": + move("BW") + move("BW") + elif mv == "dw": + move("U") + move("Yi") + elif mv == "dwi": + move("DW") + move("DW") + move("DW") + elif mv == "dw2": + move("DW") + move("DW") + else: + raise Exception("Invalid Move: " + str(mv)) + + + +# rota todo el cubo a lo largo de un eje particular +def rotate(axis): + axis = str.lower(axis) + if axis == 'x': # R + temp = a[0] + a[0] = a[1] + a[1] = a[4] + a[4] = a[5] + a[5] = temp + rotate_face_counterclockwise("L") + rotate_face_clockwise("R") + elif axis == 'y': # U + temp = a[1] + a[1] = a[2] + a[2] = a[5] + a[5] = a[3] + a[3] = temp + # después de los intercambios, + rotate_face_clockwise("L") + rotate_face_clockwise("F") + rotate_face_clockwise("R") + rotate_face_clockwise("B") + rotate_face_clockwise("U") + rotate_face_counterclockwise("D") + elif axis == 'z': # F + temp = a[0] + a[0] = a[3] + a[3] = a[4] + a[4] = a[2] + a[2] = temp + rotate_face_clockwise("L") + rotate_face_clockwise("L") + rotate_face_clockwise("D") + rotate_face_clockwise("D") + rotate_face_clockwise("F") + rotate_face_counterclockwise("B") + else: + raise Exception("Rotation inválida: " + axis) + + +# realiza un movimiento U +def U(): + # rota la cara U + temp = a[0][0][0] + a[0][0][0] = a[0][2][0] + a[0][2][0] = a[0][2][2] + a[0][2][2] = a[0][0][2] + a[0][0][2] = temp + temp = a[0][0][1] + a[0][0][1] = a[0][1][0] + a[0][1][0] = a[0][2][1] + a[0][2][1] = a[0][1][2] + a[0][1][2] = temp + + # rota otros + temp = a[5][2][0] + a[5][2][0] = a[3][2][2] + a[3][2][2] = a[1][0][2] + a[1][0][2] = a[2][0][0] + a[2][0][0] = temp + temp = a[5][2][1] + a[5][2][1] = a[3][1][2] + a[3][1][2] = a[1][0][1] + a[1][0][1] = a[2][1][0] + a[2][1][0] = temp + temp = a[5][2][2] + a[5][2][2] = a[3][0][2] + a[3][0][2] = a[1][0][0] + a[1][0][0] = a[2][2][0] + a[2][2][0] = temp + + +# Rota una cara particular en sentido antihorario +def rotate_face_counterclockwise(face): + rotate_face_clockwise(face) + rotate_face_clockwise(face) + rotate_face_clockwise(face) + + +# Rota una cara particular en sentido horario +def rotate_face_clockwise(face): + f_id = -1 + face = str.lower(face) + if face == "u": + f_id = 0 + elif face == "f": + f_id = 1 + elif face == "r": + f_id = 2 + elif face == "l": + f_id = 3 + elif face == "d": + f_id = 4 + elif face == "b": + f_id = 5 + else: + raise Exception("Cara inválida: " + face) + temp = a[f_id][0][0] + a[f_id][0][0] = a[f_id][2][0] + a[f_id][2][0] = a[f_id][2][2] + a[f_id][2][2] = a[f_id][0][2] + a[f_id][0][2] = temp + temp = a[f_id][0][1] + a[f_id][0][1] = a[f_id][1][0] + a[f_id][1][0] = a[f_id][2][1] + a[f_id][2][1] = a[f_id][1][2] + a[f_id][1][2] = temp + + +# Mezcla aleatoriamente el cubo dado un número de movimientos, o dada una lista +# de movimientos +def scramble(moves=25): + global last_scramble, moves_list, solution_length, a + a = make_cube() + if hasattr(moves, '__iter__'): # mezcla dada una lista de movimientos + m(moves) + moves_list = [] + solution_length = 0 + temp = moves.split(' ') + last_scramble = temp + else: # mezcla aleatoriamente un cierto número de veces + moves_list = [] # reiniciar moves_list + last_scramble = [] # reiniciar última mezcla + prevMove = "" + for i in range(moves): + while True: + thisMove = "" + r = randint(0, 5) + if r == 0: + thisMove += "U" + elif r == 1: + thisMove += "F" + elif r == 2: + thisMove += "R" + elif r == 3: + thisMove += "L" + elif r == 4: + thisMove += "D" + elif r == 5: + thisMove += "B" + if thisMove == "U" and prevMove != "U" and prevMove != "D": + break + if thisMove == "F" and prevMove != "F" and prevMove != "B": + break + if thisMove == "R" and prevMove != "R" and prevMove != "L": + break + if thisMove == "L" and prevMove != "L" and prevMove != "R": + break + if thisMove == "D" and prevMove != "D" and prevMove != "U": + break + if thisMove == "B" and prevMove != "B" and prevMove != "F": + break + r = randint(0, 3) + if r == 1: + move(thisMove + "i") + last_scramble.append(thisMove + "i") + elif r == 2: + move(thisMove + "2") + last_scramble.append(thisMove + "2") + else: + move(thisMove) + last_scramble.append(thisMove) + prevMove = thisMove + + +# Resuelve el cruce superior como parte del paso OLL +def topCross(): + # si todos los bordes son iguales entre sí (todos siendo blancos) + if a[0][0][1] == a[0][1][0] == a[0][1][2] == a[0][2][1]: + # print("Cruce ya hecho, paso omitido") + return + # Si esto es cierto, tenemos nuestro cruce y podemos pasar al siguiente + # paso + else: + while a[0][0][1] != "W" or a[0][1][0] != "W" or a[0][1][2] != "W" or a[0][2][1] != "W": + if a[0][1][0] == a[0][1][2]: + # si tenemos una línea horizontal, solo haz el algoritmo + m("F R U Ri Ui Fi") + break # rompiendo sin tener que revisar las condiciones + # mientras de nuevo, esto nos dará un cruce + elif a[0][0][1] == a[0][2][1]: + # si tenemos una línea vertical, haz un U y luego el algoritmo + m("U F R U Ri Ui Fi") + break + elif a[0][0][1] != "W" and a[0][1][0] != "W" and a[0][1][2] != "W" and a[0][2][1] != "W": + # Esto significaría que tenemos un caso de punto, así que + # realiza el algoritmo + m("F U R Ui Ri Fi U F R U Ri Ui Fi") + break + elif a[0][1][2] == a[0][2][1] or a[0][0][1] == a[0][1][0]: + # Si tenemos un caso de L en la parte superior izquierda o la + # inferior derecha, nos dará una línea + m("F R U Ri Ui Fi") + else: + # Esto es si no tenemos una línea, punto, cruce, o L en la parte + # superior izquierda o inferior derecha + m("U") + + +# devuelve True si la parte superior está resuelta +def isTopSolved(): + # determina si la parte superior del cubo está resuelta. + if a[0][0][0] == a[0][0][1] == a[0][0][2] == a[0][1][0] == a[0][1][1] == a[0][1][2] == a[0][2][0] == a[0][2][1] == a[0][2][2]: + return True + else: + return False + + +# Coloca una sola pieza de borde en la ubicación correcta para el cruce +# Asume que el cruce está formado en la parte inferior y es la cara amarilla +# Verifica todos los bordes en la cara frontal/superior, luego en la parte trasera-derecha/izquierda si es necesario +def putCrossEdge(): + global moves_list + for i in range(3): + if i == 1: + m("Ri U R F2") # bring out back-right edge + elif i == 2: + m("L Ui Li F2") # bring out back-left edge + for j in range(4): + for k in range(4): + if "Y" in [a[4][0][1], a[1][2][1]]: + return + m("F") + m("U") + + +# Realiza el primer paso de la solución: el cruce +def cross(): + for i in range(4): + putCrossEdge() + assert "Y" in [a[4][0][1], a[1][2][1]] + if a[1][2][1] == "Y": + m("Fi R U Ri F2") # orient if necessary + m("Di") + + # permutar para corregir la cara: mueve la cara hacia abajo hasta que 2 + # estén alineadas, luego intercambia los otros 2 si necesitan ser + # intercambiados + condition = False + while not condition: + fSame = a[1][1][1] == a[1][2][1] + rSame = a[2][1][1] == a[2][1][2] + bSame = a[5][1][1] == a[5][0][1] + lSame = a[3][1][1] == a[3][1][0] + condition = (fSame, rSame, bSame, lSame).count(True) >= 2 + if not condition: + m("D") + if (fSame, rSame, bSame, lSame).count(True) == 4: + return + assert (fSame, rSame, bSame, lSame).count(True) == 2 + if not fSame and not bSame: + m("F2 U2 B2 U2 F2") # intercambiar frente-atras + elif not rSame and not lSame: + m("R2 U2 L2 U2 R2") # intercambiar derecha-izquierda + elif not fSame and not rSame: + m("F2 Ui R2 U F2") # intercambiar frente-derecha + elif not rSame and not bSame: + m("R2 Ui B2 U R2") # intercambiar derecha-atras + elif not bSame and not lSame: + m("B2 Ui L2 U B2") # intercambiar atras-izquierda + elif not lSame and not fSame: + m("L2 Ui F2 U L2") # intercambiar izquierda-frente + fSame = a[1][1][1] == a[1][2][1] + rSame = a[2][1][1] == a[2][1][2] + bSame = a[5][1][1] == a[5][0][1] + lSame = a[3][1][1] == a[3][1][0] + assert all([fSame, rSame, bSame, lSame]) + + +# Esto usa todos los algoritmos de f2l para resolver todos los casos posibles +def solveFrontSlot(): + # Esto será F2L, con los 42 casos + rmid = a[2][1][1] + fmid = a[1][1][1] + dmid = a[4][1][1] + # Orientaciones de las esquinas si están en la capa U, la primera letra + # indica la dirección en la que el color está mirando + fCorU = a[1][0][2] == dmid and a[0][2][2] == fmid and a[2][2][0] == rmid + rCorU = a[2][2][0] == dmid and a[1][0][2] == fmid and a[0][2][2] == rmid + uCorU = a[0][2][2] == dmid and a[2][2][0] == fmid and a[1][0][2] == rmid + # Orientaciones de las esquinas para la ubicación correcta en la capa D + fCorD = a[1][2][2] == dmid and a[2][2][2] == fmid and a[4][0][2] == rmid + rCorD = a[2][2][2] == dmid and a[4][0][2] == fmid and a[1][2][2] == rmid + # Este es el lugar resuelto + dCorD = a[4][0][2] == dmid and a[1][2][2] == fmid and a[2][2][2] == rmid + # Orientaciones de los bordes en la capa U, versión normal o invertida + # basada en la cara F + norEdgeFU = a[1][0][1] == fmid and a[0][2][1] == rmid + norEdgeLU = a[3][1][2] == fmid and a[0][1][0] == rmid + norEdgeBU = a[5][2][1] == fmid and a[0][0][1] == rmid + norEdgeRU = a[2][1][0] == fmid and a[0][1][2] == rmid + norEdgeAny = norEdgeFU or norEdgeLU or norEdgeBU or norEdgeRU + flipEdgeFU = a[0][2][1] == fmid and a[1][0][1] == rmid + flipEdgeLU = a[0][1][0] == fmid and a[3][1][2] == rmid + flipEdgeBU = a[0][0][1] == fmid and a[5][2][1] == rmid + flipEdgeRU = a[0][1][2] == fmid and a[2][1][0] == rmid + flipEdgeAny = flipEdgeFU or flipEdgeLU or flipEdgeBU or flipEdgeRU + # orientaciones de los bordes para la inserción normal o invertida en el + # lugar. + # Este es el lugar resuelto + norEdgeInsert = a[1][1][2] == fmid and a[2][2][1] == rmid + flipEdgeInsert = a[2][2][1] == fmid and a[1][1][2] == rmid + # estos son para si los espacios de la parte trasera derecha o delantera + # izquierda están abiertos o no + backRight = a[4][2][2] == dmid and a[5][1][2] == a[5][0][2] == a[5][1][1] and a[2][0][1] == a[2][0][2] == rmid + frontLeft = a[4][0][0] == dmid and a[1][1][0] == a[1][2][0] == fmid and a[3][2][0] == a[3][2][1] == a[3][1][1] + + + if dCorD and norEdgeInsert: + return + # Casos fáciles + elif fCorU and flipEdgeRU: # Caso 1 + m("U R Ui Ri") + elif rCorU and norEdgeFU: # Caso 2 + m("F Ri Fi R") + elif fCorU and norEdgeLU: # Caso 3 + m("Fi Ui F") + elif rCorU and flipEdgeBU: # Caso 4 + m("R U Ri") + # Reposicionar el borde + elif fCorU and flipEdgeBU: # Caso 5 + m("F2 Li Ui L U F2") + elif rCorU and norEdgeLU: # Caso 6 + m("R2 B U Bi Ui R2") + elif fCorU and flipEdgeLU: # Caso 7 + m("Ui R U2 Ri U2 R Ui Ri") + elif rCorU and norEdgeBU: # Caso 8 + m("U Fi U2 F Ui F Ri Fi R") + # Reposicionar el borde y voltear la esquina + elif fCorU and norEdgeBU: # Caso 9 + m("Ui R Ui Ri U Fi Ui F") + elif rCorU and flipEdgeLU: # Caso 10 + if not backRight: + m("Ri U R2 U Ri") + else: + m("Ui R U Ri U R U Ri") + elif fCorU and norEdgeRU: # Caso 11 + m("Ui R U2 Ri U Fi Ui F") + elif rCorU and flipEdgeFU: # Caso 12 + if not backRight: + m("Ri U2 R2 U Ri") + else: + m("Ri U2 R2 U R2 U R") + elif fCorU and norEdgeFU: # Caso 13 + if not backRight: + m("Ri U R Fi Ui F") + else: + m("U Fi U F Ui Fi Ui F") + elif rCorU and flipEdgeRU: # Caso 14 + m("Ui R Ui Ri U R U Ri") + # Separar el par yendo sobre + elif fCorU and flipEdgeFU: # Caso 15 + if not backRight: + m("Ui Ri U R Ui R U Ri") + elif not frontLeft: + m("U R Ui Ri D R Ui Ri Di") + else: + m("U Ri F R Fi U R U Ri") + elif rCorU and norEdgeRU: # Caso 16 + m("R Ui Ri U2 Fi Ui F") + elif uCorU and flipEdgeRU: # Caso 17 + m("R U2 Ri Ui R U Ri") + elif uCorU and norEdgeFU: # Caso 18 + m("Fi U2 F U Fi Ui F") + # Par hecho en el lado + elif uCorU and flipEdgeBU: # Caso 19 + m("U R U2 R2 F R Fi") + elif uCorU and norEdgeLU: # Caso 20 + m("Ui Fi U2 F2 Ri Fi R") + elif uCorU and flipEdgeLU: # Caso 21 + m("R B U2 Bi Ri") + elif uCorU and norEdgeBU: # Caso 22 + m("Fi Li U2 L F") + # Casos raros + elif uCorU and flipEdgeFU: # Caso 23 + m("U2 R2 U2 Ri Ui R Ui R2") + elif uCorU and norEdgeRU: # Caso 24 + m("U Fi Li U L F R U Ri") + # Esquina en su lugar, borde en la cara U (Todos estos casos también tienen movimientos de preparación en caso de que el borde esté en la orientación incorrecta) + elif dCorD and flipEdgeAny: # Caso 25 + if flipEdgeBU: + m("U") # movimiento de preparación + elif flipEdgeLU: + m("U2") # movimiento de preparación + elif flipEdgeFU: + m("Ui") # movimiento de preparación + if not backRight: + m("R2 Ui Ri U R2") + else: + m("Ri Fi R U R Ui Ri F") + elif dCorD and norEdgeAny: # Caso 26 + if norEdgeRU: + m("U") # movimiento de preparación + elif norEdgeBU: + m("U2") # movimiento de preparación + elif norEdgeLU: + m("Ui") # movimiento de preparación + m("U R Ui Ri F Ri Fi R") + elif fCorD and flipEdgeAny: # Caso 27 + if flipEdgeBU: + m("U") # movimiento de preparación + elif flipEdgeLU: + m("U2") # movimiento de preparación + elif flipEdgeFU: + m("Ui") # movimiento de preparación + m("R Ui Ri U R Ui Ri") + elif rCorD and norEdgeAny: # Caso 28 + if norEdgeRU: + m("U") # movimiento de preparación + elif norEdgeBU: + m("U2") # movimiento de preparación + elif norEdgeLU: + m("Ui") # movimiento de preparación + m("R U Ri Ui F Ri Fi R") + elif fCorD and norEdgeAny: # Caso 29 + if norEdgeRU: + m("U") # movimiento de preparación + elif norEdgeBU: + m("U2") # movimiento de preparación + elif norEdgeLU: + m("Ui") # movimiento de preparación + m("U2 R Ui Ri Fi Ui F") + elif rCorD and flipEdgeAny: # Caso 30 + if flipEdgeBU: + m("U") # movimiento de preparación + elif flipEdgeLU: + m("U2") # movimiento de preparación + elif flipEdgeFU: + m("Ui") # movimiento de preparación + m("R U Ri Ui R U Ri") + # Borde en su lugar, esquina en la cara U + elif uCorU and flipEdgeInsert: # Caso 31 + m("R U2 Ri Ui F Ri Fi R") + elif uCorU and norEdgeInsert: # Caso 32 + m("R2 U R2 U R2 U2 R2") + elif fCorU and norEdgeInsert: # Caso 33 + m("Ui R Ui Ri U2 R Ui Ri") + elif rCorU and norEdgeInsert: # Caso 34 + m("Ui R U2 Ri U R U Ri") + elif fCorU and flipEdgeInsert: # Caso 35 + m("U2 R Ui Ri Ui Fi Ui F") + elif rCorU and flipEdgeInsert: # Caso 36 + m("U Fi Ui F Ui R U Ri") + # Borde y esquina en su lugar + # Caso 37 es el caso Lol, ya completado + elif dCorD and flipEdgeInsert: # Caso 38 (Caso típico de par f2l invertido) + m("R2 U2 F R2 Fi U2 Ri U Ri") + elif fCorD and norEdgeInsert: # Caso 39 + m("R2 U2 Ri Ui R Ui Ri U2 Ri") + elif rCorD and norEdgeInsert: # Caso 40 + m("R U2 R U Ri U R U2 R2") + elif fCorD and flipEdgeInsert: # Caso 41 + m("F2 Li Ui L U F Ui F") + elif rCorD and flipEdgeInsert: # Caso 42 + m("R Ui Ri Fi Li U2 L F") + + +# Devuelve verdadero si la esquina f2l en el lugar FR está insertada y orientada correctamente +def f2lCorner(): + # Este es el lugar resuelto + return a[4][0][2] == a[4][1][1] and a[1][2][2] == a[1][1][1] and a[2][2][2] == a[2][1][1] + + +# Devuelve verdadero si el borde f2l en el lugar FR está insertado y orientado correctamente +def f2lEdge(): + # Este es el lugar resuelto + return a[1][1][2] == a[1][1][1] and a[2][2][1] == a[2][1][1] + + +# Devuelve verdadero si el borde f2l y la esquina están correctamente insertados y orientados en la posición FR +def f2lCorrect(): + return f2lCorner() and f2lEdge() + + +# Devuelve verdadero si el borde f2l está en la capa superior en absoluto +def f2lEdgeOnTop(): + rmid = a[2][1][1] + fmid = a[1][1][1] + dmid = a[4][1][1] + # orientaciones del borde en la capa U, versión normal o invertida basada en la cara F + norEdgeFU = a[1][0][1] == fmid and a[0][2][1] == rmid + norEdgeLU = a[3][1][2] == fmid and a[0][1][0] == rmid + norEdgeBU = a[5][2][1] == fmid and a[0][0][1] == rmid + norEdgeRU = a[2][1][0] == fmid and a[0][1][2] == rmid + norEdgeAny = norEdgeFU or norEdgeLU or norEdgeBU or norEdgeRU + flipEdgeFU = a[0][2][1] == fmid and a[1][0][1] == rmid + flipEdgeLU = a[0][1][0] == fmid and a[3][1][2] == rmid + flipEdgeBU = a[0][0][1] == fmid and a[5][2][1] == rmid + flipEdgeRU = a[0][1][2] == fmid and a[2][1][0] == rmid + flipEdgeAny = flipEdgeFU or flipEdgeLU or flipEdgeBU or flipEdgeRU + return norEdgeAny or flipEdgeAny + + +# Devuelve verdadero si el borde f2l está insertado. Puede estar correctamente orientado o invertido. +def f2lEdgeInserted(): + rmid = a[2][1][1] + fmid = a[1][1][1] + # orientaciones del borde para la inserción normal o invertida en el lugar + # Este es el lugar resuelto + norEdgeInsert = a[1][1][2] == fmid and a[2][2][1] == rmid + flipEdgeInsert = a[2][2][1] == fmid and a[1][1][2] == rmid + return norEdgeInsert or flipEdgeInsert + + +# Esto se usa para determinar si el borde f2l frontal está insertado o no, el parámetro es para el borde solicitado. toma BR, BL y FL como válidos +def f2lEdgeInserted2(p): + rmid = a[2][1][1] + fmid = a[1][1][1] + # orientaciones del borde para la inserción normal o invertida en el lugar + # Este es el lugar resuelto + norEdgeInsert = a[1][1][2] == fmid and a[2][2][1] == rmid + flipEdgeInsert = a[2][2][1] == fmid and a[1][1][2] == rmid + # Orientaciones del borde en comparación con los colores del Frente y el Derecho + BR = (a[5][1][2] == fmid and a[2][0][1] == rmid) or ( + a[5][1][2] == rmid and a[2][0][1] == fmid) + BL = (a[3][0][1] == fmid and a[5][1][0] == rmid) or ( + a[3][0][1] == rmid and a[5][1][0] == fmid) + FL = (a[3][2][1] == fmid and a[1][1][0] == rmid) or ( + a[3][2][1] == rmid and a[1][1][0] == fmid) + + if p == "BR": + if BR: + return True + else: + return False + elif p == "BL": + if BL: + return True + return False + elif p == "FL": + if FL: + return True + return False + elif p == "FR": + if norEdgeInsert or flipEdgeInsert: + return True + return False + + +# Devuelve verdadero si la esquina f2l está insertada, no tiene que estar orientada correctamente +def f2lCornerInserted(): + rmid = a[2][1][1] + fmid = a[1][1][1] + dmid = a[4][1][1] + # Orientaciones de la esquina para la ubicación correcta en la capa D + fCorD = a[1][2][2] == dmid and a[2][2][2] == fmid and a[4][0][2] == rmid + rCorD = a[2][2][2] == dmid and a[4][0][2] == fmid and a[1][2][2] == rmid + # Este es el lugar resuelto + dCorD = a[4][0][2] == dmid and a[1][2][2] == fmid and a[2][2][2] == rmid + return fCorD or rCorD or dCorD + + +# Devuelve verdadero si hay una esquina f2l ubicada en la orientación FR +def f2lFRCor(): + rmid = a[2][1][1] + fmid = a[1][1][1] + dmid = a[4][1][1] + # orientaciones de las esquinas si están en la capa U, la primera letra indica la dirección en la que el color está mirando + fCorU = a[1][0][2] == dmid and a[0][2][2] == fmid and a[2][2][0] == rmid + rCorU = a[2][2][0] == dmid and a[1][0][2] == fmid and a[0][2][2] == rmid + uCorU = a[0][2][2] == dmid and a[2][2][0] == fmid and a[1][0][2] == rmid + return fCorU or rCorU or uCorU + + +# Devuelve verdadero si hay un borde f2l ubicado en la posición FU +def f2lFUEdge(): + rmid = a[2][1][1] + fmid = a[1][1][1] + norEdgeFU = a[1][0][1] == fmid and a[0][2][1] == rmid + flipEdgeFU = a[0][2][1] == fmid and a[1][0][1] == rmid + return norEdgeFU or flipEdgeFU + + +# Devuelve verdadero si la esquina f2l está ubicada en la capa U +def f2lCornerOnTop(): + wasFound = False + for i in range(4): # Realiza 4 movimientos U para encontrar la esquina + if f2lFRCor(): + wasFound = True + m("U") + return wasFound + + +# Devolverá la ubicación de la esquina que pertenece al lugar FR. Devuelve BR, BL, FL o FR. +def f2lCornerCheck(): + r = "FR" + count = 0 + while count < 4: + if count == 0: + if f2lCornerInserted(): + r = "FR" + elif count == 1: + if f2lCornerInserted(): + r = "FL" + elif count == 2: + if f2lCornerInserted(): + r = "BL" + elif count == 3: + if f2lCornerInserted(): + r = "BR" + m("D") + count += 1 + return r + + +# Devolverá la ubicación del borde que pertenece al lugar FR. +# Devuelve BR, BL, FL o FR. +def f2lEdgeCheck(): + if f2lEdgeInserted2("FL"): + return "FL" + elif f2lEdgeInserted2("BL"): + return "BL" + elif f2lEdgeInserted2("BR"): + return "BR" + elif f2lEdgeInserted2("FR"): + return "FR" + else: + raise Exception("Excepción en f2lEdgeCheck()") + + +# Esto es para el caso en que el Borde está insertado, pero la esquina no +def f2lEdgeNoCorner(): + topEdgeTop = a[0][2][1] + topEdgeFront = a[1][0][1] + rmid = a[2][1][1] + bmid = a[5][1][1] + lmid = a[3][1][1] + fmid = a[1][1][1] + # Esto es para comparar el borde frontal con otros bordes diversos para algs avanzados/lookahead + BREdge = (topEdgeTop == rmid or topEdgeTop == bmid) and ( + topEdgeFront == rmid or topEdgeFront == bmid) + BLEdge = (topEdgeTop == lmid or topEdgeTop == bmid) and ( + topEdgeFront == lmid or topEdgeFront == bmid) + FLEdge = (topEdgeTop == fmid or topEdgeTop == lmid) and ( + topEdgeFront == fmid or topEdgeFront == lmid) + if f2lCornerOnTop(): + while True: + solveFrontSlot() + if f2lCorrect(): + break + m("U") + else: + if f2lCornerCheck() == "BR": + if BREdge: + m("Ri Ui R U2") + else: + m("Ri U R U") + elif f2lCornerCheck() == "BL": + if BLEdge: + m("L U Li U") + else: + m("L Ui Li U2") + elif f2lCornerCheck() == "FL": + if FLEdge: + m("Li U L Ui") + else: + m("Li Ui L") + solveFrontSlot() + + if not f2lCorrect(): + raise Exception("Excepción encontrada en f2lEdgeNoCorner()") + + +# Este es el caso para si la esquina está insertada, pero el borde no +def f2lCornerNoEdge(): + topEdgeTop = a[0][2][1] + topEdgeFront = a[1][0][1] + rmid = a[2][1][1] + bmid = a[5][1][1] + lmid = a[3][1][1] + fmid = a[1][1][1] + # Esto es para comparar el borde frontal con otros bordes diversos para algoritmos avanzados/lookahead + BREdge = (topEdgeTop == rmid or topEdgeTop == bmid) and ( + topEdgeFront == rmid or topEdgeFront == bmid) + BLEdge = (topEdgeTop == lmid or topEdgeTop == bmid) and ( + topEdgeFront == lmid or topEdgeFront == bmid) + FLEdge = (topEdgeTop == fmid or topEdgeTop == lmid) and ( + topEdgeFront == fmid or topEdgeFront == lmid) + if f2lEdgeOnTop(): + while True: + solveFrontSlot() + if f2lCorrect(): + break + m("U") + else: + if f2lEdgeCheck() == "BR": + if BREdge: + m("Ri Ui R U2") + else: + m("Ri U R U") + elif f2lEdgeCheck() == "BL": + if BLEdge: + m("L U Li U") + else: + m("L Ui Li U2") + elif f2lEdgeCheck() == "FL": + if FLEdge: + m("Li U L Ui") + else: + m("Li Ui L") + solveFrontSlot() + + if not f2lCorrect(): + raise Exception("Excepción encontrada en f2lCornerNoEdge()") + + +# Este es el caso para si la esquina está en la parte superior, y el borde no. Ninguno está insertado correctamente. El borde debe estar en otro lugar. +def f2lCornerTopNoEdge(): + topEdgeTop = a[0][2][1] + topEdgeFront = a[1][0][1] + rmid = a[2][1][1] + bmid = a[5][1][1] + lmid = a[3][1][1] + fmid = a[1][1][1] + # Esto es para comparar el borde frontal con otros bordes diversos para algoritmos avanzados/lookahead + BREdge = (topEdgeTop == rmid or topEdgeTop == bmid) and ( + topEdgeFront == rmid or topEdgeFront == bmid) + BLEdge = (topEdgeTop == lmid or topEdgeTop == bmid) and ( + topEdgeFront == lmid or topEdgeFront == bmid) + FLEdge = (topEdgeTop == fmid or topEdgeTop == lmid) and ( + topEdgeFront == fmid or topEdgeFront == lmid) + + # Gira la parte superior hasta que la esquina en la cara U esté en la posición correcta + while True: + if f2lFRCor(): + break + m("U") + # Verificaremos bordes adicionales para elegir un algoritmo más adecuado para buscar + if f2lEdgeCheck() == "BR": + if BREdge: + m("Ri Ui R") + else: + m("Ri U R") + elif f2lEdgeCheck() == "BL": + if BLEdge: + m("U2 L Ui Li") + else: + m("L Ui Li U") + elif f2lEdgeCheck() == "FL": + if FLEdge: + m("U2 Li Ui L U2") + else: + m("Li Ui L U") + solveFrontSlot() + + if not f2lCorrect(): + raise Exception("Excepción encontrada en f2lCornerTopNoEdge()") + + +# Este es el caso para si el borde está en la parte superior, y la esquina no. Ninguno está insertado correctamente. La esquina debe estar en otro lugar. +# La búsqueda para este paso es comparar el borde trasero con los lugares, en lugar del frontal como en otros casos +def f2lEdgeTopNoCorner(): + BackEdgeTop = a[0][0][1] + BackEdgeBack = a[5][2][1] + rmid = a[2][1][1] + bmid = a[5][1][1] + lmid = a[3][1][1] + fmid = a[1][1][1] + rs1 = BackEdgeTop == rmid or BackEdgeTop == bmid + rs2 = BackEdgeBack == rmid or BackEdgeBack == bmid + # Esto es para comparar el borde trasero con otros bordes diversos para algoritmos avanzados/lookahead + BREdge = rs1 and rs2 + BLEdge = (BackEdgeTop == lmid or BackEdgeTop == bmid) and ( + BackEdgeBack == lmid or BackEdgeBack == bmid) + FLEdge = (BackEdgeTop == fmid or BackEdgeTop == lmid) and ( + BackEdgeBack == fmid or BackEdgeBack == lmid) + + # Gira la parte superior hasta que el borde en la cara U esté en la posición correcta + while True: + if f2lFUEdge(): + break + m("U") + # Verificaremos bordes adicionales para elegir un algoritmo más adecuado para buscar + if f2lCornerCheck() == "BR": + if BREdge: + m("Ri U R U") + else: + m("Ui Ri U R U") + elif f2lCornerCheck() == "BL": + if BLEdge: + m("L Ui Li U2") + else: + m("U2 L U2 Li") + elif f2lCornerCheck() == "FL": + if FLEdge: + m("Li Ui L") + else: + m("U Li Ui L") + solveFrontSlot() + + if not f2lCorrect(): + raise Exception("Excepción encontrada en f2lEdgeTopNoCorner()") + + +# Este es el caso para si el borde o la esquina no están en la parte superior, y no están insertados correctamente. Ambos deben estar en otros lugares. +def f2lNoEdgeOrCorner(): + # La estrategia aquí es primero encontrar la esquina y sacarla. La colocaré en la posición FR donde corresponde + # Luego verificaré si tengo un caso, y si todo está resuelto. + # Si no lo tengo resuelto en este punto, tendré que seguir lo que ocurre en f2lCornerTopNoEdge() + BackEdgeTop = a[0][0][1] + BackEdgeBack = a[5][2][1] + rmid = a[2][1][1] + bmid = a[5][1][1] + lmid = a[3][1][1] + fmid = a[1][1][1] + # Esto es para comparar el borde trasero con otros bordes diversos para algoritmos avanzados/lookahead + BREdge = (BackEdgeTop == rmid or BackEdgeTop == bmid) and ( + BackEdgeBack == rmid or BackEdgeBack == bmid) + BLEdge = (BackEdgeTop == lmid or BackEdgeTop == bmid) and ( + BackEdgeBack == lmid or BackEdgeBack == bmid) + FLEdge = (BackEdgeTop == fmid or BackEdgeTop == lmid) and ( + BackEdgeBack == fmid or BackEdgeBack == lmid) + + # Verificaremos bordes adicionales para elegir un algoritmo más adecuado para buscar + if f2lCornerCheck() == "BR": + if BREdge: + m("Ri U R U") + else: + m("Ui Ri U R U") + elif f2lCornerCheck() == "BL": + if BLEdge: + m("L Ui Li U2") + else: + m("U2 L U2 Li") + elif f2lCornerCheck() == "FL": + if FLEdge: + m("Li Ui L") + else: + m("U Li Ui L") + solveFrontSlot() + + if f2lCorrect(): + return + else: + f2lCornerTopNoEdge() + + if not f2lCorrect(): + raise Exception("Excepción encontrada en f2lNoEdgeOrCorner()") + + +# Devolverá verdadero si el f2l está completado +def isf2lDone(): + rside = a[2][0][1] == a[2][0][2] == a[2][1][1] == a[2][1][2] == a[2][2][1] == a[2][2][2] + bside = a[5][0][0] == a[5][0][1] == a[5][0][2] == a[5][1][0] == a[5][1][1] == a[5][1][2] + lside = a[3][0][0] == a[3][0][1] == a[3][1][0] == a[3][1][1] == a[3][2][0] == a[3][2][1] + fside = a[1][1][0] == a[1][1][1] == a[1][1][2] == a[1][2][0] == a[1][2][1] == a[1][2][2] + return rside and bside and lside and fside + + +# f2l resolverá las primeras 2 capas, verifica cada caso, luego hace un movimiento Y para verificar el siguiente +def f2l(): + pairsSolved = 0 + uMoves = 0 + while pairsSolved < 4: + if not f2lCorrect(): + # mientras no esté correcto el f2l: + while uMoves < 4: # 4 movimientos antes de verificar casos raros + solveFrontSlot() + if f2lCorrect(): + pairsSolved += 1 + f2l_list.append("Caso Normal") + break + else: + f2l_list.append("Escaneando") + uMoves += 1 + m("U") + if not f2lCorrect(): + if not f2lCornerInserted() and f2lEdgeInserted(): + f2l_list.append("Caso raro 1") + f2lEdgeNoCorner() + pairsSolved += 1 + elif not f2lEdgeInserted() and f2lCornerInserted(): + f2l_list.append("Caso raro 2") + f2lCornerNoEdge() + pairsSolved += 1 + # En este punto, no pueden estar insertados, deben estar en la U u otro lugar + elif not f2lEdgeOnTop() and f2lCornerOnTop(): + f2l_list.append("Caso raro 3") + f2lCornerTopNoEdge() + pairsSolved += 1 + elif f2lEdgeOnTop() and not f2lCornerOnTop(): + f2l_list.append("Caso raro 4") + f2lEdgeTopNoCorner() + solveFrontSlot() + pairsSolved += 1 + elif not f2lEdgeOnTop() and not f2lCornerOnTop(): + f2l_list.append("Caso raro 5") + f2lNoEdgeOrCorner() + pairsSolved += 1 + else: + raise Exception("Excepción de Caso Imposible en f2l") + else: + pairsSolved += 1 + f2l_list.append("Tenemos ") + f2l_list.append(str(pairsSolved)) + uMoves = 0 + m("Y") + assert (isf2lDone()) + + +def fish(): + return [a[0][0][0], a[0][0][2], a[0][2][0], a[0][2][2]].count(a[0][1][1]) == 1 + + +def sune(): + m("R U Ri U R U2 Ri") + + +def antisune(): + m("R U2 Ri Ui R Ui Ri") + + +def getfish(): + for i in range(4): + if fish(): + return + sune() + if fish(): + return + antisune() + m("U") + assert fish() + + +def bOLL(): + getfish() + if fish(): + while a[0][0][2] != a[0][1][1]: + m("U") + if a[1][0][0] == a[0][1][1]: + antisune() + elif a[5][2][0] == a[0][1][1]: + m("U2") + sune() + else: + raise Exception("Algo salió mal") # Something went wrong + else: + raise Exception("Fish no configurado") # Fish not set up + assert isTopSolved() + + +def getCornerState(): + corner0 = a[1][0][0] == a[1][1][1] and a[3][2][2] == a[3][1][1] + corner1 = a[1][0][2] == a[1][1][1] and a[2][2][0] == a[2][1][1] + corner2 = a[5][2][2] == a[5][1][1] and a[2][0][0] == a[2][1][1] + corner3 = a[5][2][0] == a[5][1][1] and a[3][0][2] == a[3][1][1] + return [corner0, corner1, corner2, corner3] + + +# Permuta las esquinas de la capa superior, las orienta correctamente +def permuteCorners(): + for i in range(2): + for j in range(4): + num = getCornerState().count(True) + if num == 4: + return + if num == 1: + index = getCornerState().index(True) + for k in range(index): + m("Y") + if a[1][0][2] == a[2][1][1]: + m("R2 B2 R F Ri B2 R Fi R") + else: + m("Ri F Ri B2 R Fi Ri B2 R2") + for f in range(index): + m("Yi") + return + m("U") + m("R2 B2 R F Ri B2 R Fi R") + + +# Permuta los bordes de la capa superior, debe ser H, Z o U perms después de la orientación +def permuteEdges(): + if all(getEdgeState()): + return + if a[1][0][1] == a[5][1][1] and a[5][2][1] == a[1][1][1]: # Permutación H + m("R2 U2 R U2 R2 U2 R2 U2 R U2 R2") + elif a[1][0][1] == a[2][1][1] and a[2][1][0] == a[1][1][1]: # Permutación Z normal + m("U Ri Ui R Ui R U R Ui Ri U R U R2 Ui Ri U") + elif a[1][0][1] == a[3][1][1] and a[3][1][2] == a[1][1][1]: # Permutación Z no orientada + m("Ri Ui R Ui R U R Ui Ri U R U R2 Ui Ri U2") + else: + uNum = 0 + while True: + if a[5][2][0] == a[5][2][1] == a[5][2][2]: # la barra sólida está en la parte trasera + if a[3][1][2] == a[1][0][0]: # significa que tenemos que hacer un ciclo en sentido contrario a las agujas del reloj + m("R Ui R U R U R Ui Ri Ui R2") + break + else: + m("R2 U R U Ri Ui Ri Ui Ri U Ri") + break + else: + m("U") + uNum += 1 + for x in range(uNum): + m("Ui") + + +def getEdgeState(): + fEdge = a[1][0][1] == a[1][1][1] + rEdge = a[2][1][0] == a[2][1][1] + bEdge = a[5][2][1] == a[5][1][1] + lEdge = a[3][1][2] == a[3][1][1] + return [fEdge, rEdge, bEdge, lEdge] + + +def topCorners(): + permuteCorners() + assert all(getCornerState()) + + +def topEdges(): + permuteEdges() + assert all(getEdgeState()) + + +def bPLL(): + topCorners() + topEdges() + + +def isSolved(): + uside = a[0][0][0] == a[0][0][1] == a[0][0][2] == a[0][1][0] == a[0][1][1] == a[0][1][2] == a[0][2][0] == a[0][2][1] == a[0][2][2] + fside = a[1][0][0] == a[1][0][1] == a[1][0][2] == a[1][1][0] == a[1][1][1] == a[1][1][2] == a[1][2][0] == a[1][2][1] == a[1][2][2] + rside = a[2][0][0] == a[2][0][1] == a[2][0][2] == a[2][1][0] == a[2][1][1] == a[2][1][2] == a[2][2][0] == a[2][2][1] == a[2][2][2] + lside = a[3][0][0] == a[3][0][1] == a[3][0][2] == a[3][1][0] == a[3][1][1] == a[3][1][2] == a[3][2][0] == a[3][2][1] == a[3][2][2] + dside = a[4][0][0] == a[4][0][1] == a[4][0][2] == a[4][1][0] == a[4][1][1] == a[4][1][2] == a[4][2][0] == a[4][2][1] == a[4][2][2] + bside = a[5][0][0] == a[5][0][1] == a[5][0][2] == a[5][1][0] == a[5][1][1] == a[5][1][2] == a[5][2][0] == a[5][2][1] == a[5][2][2] + return uside and fside and rside and lside and dside and bside + + +def solve(): + cross() + simplify_moves() + step_moves_list[0] = solution_length + f2l() + simplify_moves() + step_moves_list[1] = solution_length - step_moves_list[0] + topCross() + getfish() + bOLL() + simplify_moves() + step_moves_list[2] = solution_length - \ + step_moves_list[1] - step_moves_list[0] + bPLL() + simplify_moves() + step_moves_list[3] = solution_length - step_moves_list[2] - \ + step_moves_list[1] - step_moves_list[0] + assert (isSolved()) + + +# Realiza simulaciones de resolución, devolverá una lista con el número de +# movimientos, cuál fue el mejor y el scramble utilizado para obtener el mejor. +# El peor, cuál fue el peor, y el scramble utilizado para obtener el peor. +# scimNum es el número de simulaciones a realizar, es un IntVar() +def simulation(simNum): + global a + bestScram = [] + worstScram = [] + best = 200 + worst = 0 + Bestnumber = 0 + WorstNumber = 0 + if simNum.get() >= 50000: + print("No hagas más de 50,000 resoluciones a la vez") + return + for i in range(simNum.get()): + a = make_cube() + step_moves_list = [0, 0, 0, 0] + f2l_list = [] + moves_list = [] + last_scramble = [] + scramble(25) + solve() + simplify_moves() + if solution_length < best: + best = solution_length + bestScram = get_scramble() + BestNumber = i + if solution_length > worst: + worst = solution_length + worstScram = get_scramble() + WorstNumber = i + return [best, BestNumber, bestScram, worst, WorstNumber, worstScram] + + +################################################################################ +# Abajo está todo el trabajo para la parte GUI del Resolutor de Cubos +################################################################################ +# Estos son todos los globales utilizados para la GUI +root = None +frame = None +canvas = None +ScrambleLabel = None +SolutionLabel = None +SolutionNumberLabel = None +isTransparent = None +F2LNumberLabel = None +CrossNumberLabel = None +OLLNumberLabel = None +PLLNumberLabel = None +SimulateBestLabel = None +SimulateWorstLabel = None + + +# cubePoints son todas las coordenadas x e y para los polígonos utilizados para +# los azulejos +def cubePoints(): + # h y w pueden cambiarse para permitir que el cubo se mueva por la pantalla + h = 125 + w = 115 + # cara derecha + # capa 1 + r00p = [0+w, 0+h, 0+w, 50+h, 33+w, 30+h, 33+w, -20+h] + r01p = [33+w, -20+h, 33+w, 30+h, 66+w, 10+h, 66+w, -40+h] + r02p = [66+w, -40+h, 66+w, 10+h, 99+w, -10+h, 99+w, -60+h] + # capa 2 + r10p = [0+w, 50+h, 0+w, 100+h, 33+w, 80+h, 33+w, 30+h] + r11p = [33+w, 30+h, 33+w, 80+h, 66+w, 60+h, 66+w, 10+h] + r12p = [66+w, 10+h, 66+w, 60+h, 99+w, 40+h, 99+w, -10+h] + # capa 3 + r20p = [0+w, 100+h, 0+w, 150+h, 33+w, 130+h, 33+w, 80+h] + r21p = [33+w, 80+h, 33+w, 130+h, 66+w, 110+h, 66+w, 60+h] + r22p = [66+w, 60+h, 66+w, 110+h, 99+w, 90+h, 99+w, 40+h] + # cara izquierda (la cara izquierda será la cara delantera, sin embargo se + # llama l para distinguir entre izquierda y derecha) + # capa 1 + l00p = [-66+w, -40+h, -66+w, 10+h, -99+w, -10+h, -99+w, -60+h] + l01p = [-33+w, -20+h, -33+w, 30+h, -66+w, 10+h, -66+w, -40+h] + l02p = [0+w, 0+h, 0+w, 50+h, -33+w, 30+h, -33+w, -20+h] + # capa 2 + l10p = [-66+w, 10+h, -66+w, 60+h, -99+w, 40+h, -99+w, -10+h] + l11p = [-33+w, 30+h, -33+w, 80+h, -66+w, 60+h, -66+w, 10+h] + l12p = [0+w, 50+h, 0+w, 100+h, -33+w, 80+h, -33+w, 30+h] + # capa 3 + l20p = [-66+w, 60+h, -66+w, 110+h, -99+w, 90+h, -99+w, 40+h] + l21p = [-33+w, 80+h, -33+w, 130+h, -66+w, 110+h, -66+w, 60+h] + l22p = [0+w, 100+h, 0+w, 150+h, -33+w, 130+h, -33+w, 80+h] + # cara superior + # capa 1 + u00p = [0+w, -75+h, -33+w, -94+h, 0+w, -111+h, 33+w, -94+h] + u01p = [36+w, -57+h, 0+w, -75+h, 33+w, -94+h, 69+w, -76+h] + u02p = [66+w, -40+h, 36+w, -57+h, 69+w, -76+h, 99+w, -60+h] + # capa 2 + u10p = [-33+w, -57+h, -66+w, -77+h, -33+w, -94+h, 0+w, -75+h] + u11p = [0+w, -38+h, -33+w, -57+h, 0+w, -75+h, 36+w, -57+h] + u12p = [33+w, -20+h, 0+w, -38+h, 36+w, -57+h, 66+w, -40+h] + # capa 3 + u20p = [-66+w, -40+h, -99+w, -60+h, -66+w, -77+h, -33+w, -57+h] + u21p = [-33+w, -20+h, -66+w, -40+h, -33+w, -57+h, 0+w, -38+h] + u22p = [0+w, 0+h, -33+w, -20+h, 0+w, -38+h, 33+w, -20+h] + + dh = h + 200 + dw = w + # cara inferior + # capa 1 + d00p = [0+dw, -75+dh, -33+dw, -94+dh, 0+dw, -111+dh, 33+dw, -94+dh] + d01p = [36+dw, -57+dh, 0+dw, -75+dh, 33+dw, -94+dh, 69+dw, -76+dh] + d02p = [66+dw, -40+dh, 36+dw, -57+dh, 69+dw, -76+dh, 99+dw, -60+dh] + # capa 2 + d10p = [-33+dw, -57+dh, -66+dw, -77+dh, -33+dw, -94+dh, 0+dw, -75+dh] + d11p = [0+dw, -38+dh, -33+dw, -57+dh, 0+dw, -75+dh, 36+dw, -57+dh] + d12p = [33+dw, -20+dh, 0+dw, -38+dh, 36+dw, -57+dh, 66+dw, -40+dh] + # capa 3 + d20p = [-66+dw, -40+dh, -99+dw, -60+dh, -66+dw, -77+dh, -33+dw, -57+dh] + d21p = [-33+dw, -20+dh, -66+dw, -40+dh, -33+dw, -57+dh, 0+dw, -38+dh] + d22p = [0+dw, 0+dh, -33+dw, -20+dh, 0+dw, -38+dh, 33+dw, -20+dh] + + return [[[u00p, u01p, u02p], + [u10p, u11p, u12p], + [u20p, u21p, u22p]], # Cara superior + + [[l00p, l01p, l02p], + [l10p, l11p, l12p], + # cara delantera (se usa l para denotar la cara izquierda que muestra) + [l20p, l21p, l22p]], + + [[r02p, r12p, r22p], + [r01p, r11p, r21p], + # cara derecha (diferente a otras caras porque está formateada de manera diferente) + [r00p, r10p, r20p]], + + [[d20p, d21p, d22p], + [d10p, d11p, d12p], + [d00p, d01p, d02p]]] # Cara inferior + + +def clickCanvas(canvas): + global isTransparent + isTransparent = not isTransparent + canvas.delete(ALL) + drawCube() + + +# DrawCanvas tomará el root y dibujará un nuevo canvas, también lo devolverá. +def drawCanvas(root): + canvas = tk.Canvas(root, width=225, height=330, background='white') + canvas.grid(row=0, column=0) + canvas.bind("