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 + +

+ Captura de pantalla del solucionador +

+ +### 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("", lambda e: clickCanvas(canvas)) + return canvas + + +# Se usa para obtener la palabra para cada color, usada en drawCube(canvas) +def getColor(element): + if element == 'B': + return "#06F" # Bonito tono de azul + elif element == 'W': + return "white" + elif element == 'G': + return "green" + elif element == 'Y': + return "yellow" + elif element == 'O': + return "orange" + elif element == 'R': + return "#D11" + + +# drawCube() tomará el canvas ya creado y dibujará el cubo con polígonos cuyos puntos están definidos en cubePoints() +def drawCube(): + global isTransparent, canvas + pts = cubePoints() + for j in range(3): + for k in range(3): + canvas.create_polygon(pts[3][j][k], fill=getColor( + a[4][j][k]), outline="#000", width=2) + for i in range(3): + for j in range(3): + for k in range(3): + if isTransparent: + frontTiles = (i == 1) and ((j == 1 and k == 2) or ( + j == 2 and k == 2) or (j == 2 and k == 1)) + rightTiles = (i == 2) and ((j == 1 and k == 2) or ( + j == 2 and k == 2) or (j == 2 and k == 1)) + if frontTiles or rightTiles: + canvas.create_polygon( + pts[i][j][k], fill="", outline="#000", width=2) + else: + canvas.create_polygon(pts[i][j][k], fill=getColor( + a[i][j][k]), outline="#000", width=2) + else: + canvas.create_polygon(pts[i][j][k], fill=getColor( + a[i][j][k]), outline="#000", width=2) + + +# Se usa para crear una nueva instancia de un cubo para resolver, cambia las etiquetas de scramble y solución también +def GUInewCube(): + global canvas, ScrambleLabel, SolutionLabel, SolutionNumberLabel, a, step_moves_list + global PLLNumberLabel, F2LNumberLabel, CrossNumberLabel, OLLNumberLabel, f2l_list, moves_list + step_moves_list = [0, 0, 0, 0] + a = make_cube() + f2l_list = [] + moves_list = [] + ScrambleLabel.configure(text="El scramble se mostrará aquí") + SolutionLabel.configure(text="La solución se mostrará aquí") + SolutionNumberLabel.configure(text=0) + CrossNumberLabel.configure(text=step_moves_list[0]) + F2LNumberLabel.configure(text=step_moves_list[1]) + OLLNumberLabel.configure(text=step_moves_list[2]) + PLLNumberLabel.configure(text=step_moves_list[3]) + canvas.delete(ALL) + drawCube() + + +# GUImakeMove se usa para hacer movimientos basados en lo que está en la +# EntryBox. Después de hacer clic en Dibujar, redibujará el canvas con el cubo +# actualizado +def GUImakeMove(move): + global canvas + if move.get() == "": + return + m(move.get()) + canvas.delete(ALL) + drawCube() + + +# GUIScramble hará un scramble de 25 en el cubo, luego actualizará el canvas con el nuevo cubo +def GUIScramble(): + global ScrambleLabel, canvas + scramble(25) + ScrambleLabel.configure(text=get_scramble()) + canvas.delete(ALL) + drawCube() + + +# Se usa para permitir al usuario ingresar su propio scramble en la Entry, +# también mostrará el scramble en la etiqueta de scramble +def GUIcustomScramble(scram): + global ScrambleLabel, canvas + if scram.get() == "": + ScrambleLabel.configure(text="El scramble se mostrará aquí") + return + scramble(scram.get()) + ScrambleLabel.configure(text=get_scramble()) + canvas.delete(ALL) + drawCube() + + +# GUISolve resolverá el cubo usando la función solve, luego actualizará el +# canvas con el cubo resuelto +def GUISolve(): + global canvas, SolutionLabel, SolutionNumberLabel, step_moves_list + global PLLNumberLabel, F2LNumberLabel, CrossNumberLabel, OLLNumberLabel + solve() + SolutionLabel.configure(text=get_moves()) + SolutionNumberLabel.configure(text=solution_length) + CrossNumberLabel.configure(text=step_moves_list[0]) + F2LNumberLabel.configure(text=step_moves_list[1]) + OLLNumberLabel.configure(text=step_moves_list[2]) + PLLNumberLabel.configure(text=step_moves_list[3]) + canvas.delete(ALL) + drawCube() + + +# Esto permitirá al usuario avanzar por la solución un paso a la vez, el +# parámetro step debe ser ya sea cross, f2l, OLL o PLL. Dependiendo de ello, +# hará un paso diferente +def GUIsetSolve(step): + global SolutionLabel, SolutionNumberLabel, canvas, step_moves_list + global PLLNumberLabel, F2LNumberLabel, CrossNumberLabel, OLLNumberLabel + if step == "cross": + cross() + simplify_moves() + step_moves_list[0] = solution_length + elif step == "f2l" or step == "F2L": + f2l() + simplify_moves() + step_moves_list[1] = solution_length - step_moves_list[0] + elif step == "OLL": + topCross() + getfish + bOLL() + simplify_moves() + step_moves_list[2] = solution_length - \ + step_moves_list[1] - step_moves_list[0] + elif step == "PLL": + bPLL() + simplify_moves() + step_moves_list[3] = solution_length - step_moves_list[2] - \ + step_moves_list[1] - step_moves_list[0] + assert (isSolved()) + + SolutionLabel.configure(text=get_moves()) + SolutionNumberLabel.configure(text=solution_length) + CrossNumberLabel.configure(text=step_moves_list[0]) + F2LNumberLabel.configure(text=step_moves_list[1]) + OLLNumberLabel.configure(text=step_moves_list[2]) + PLLNumberLabel.configure(text=step_moves_list[3]) + canvas.delete(ALL) + drawCube() + + +# Esto se usa para copiar el string dado al portapapeles del usuario +def GUItoClipboard(word): + r = Tk() + r.withdraw() + r.clipboard_clear() + r.clipboard_append(word) + r.destroy() + + +''' +Este era el intento de usar un temporizador para automatizar una solución, para usarlo, asegúrate de reactivar el botón e importar time +#Esto se usa para una solución lenta pero automática. Utiliza las funciones del temporizador para hacer un par de movimientos por segundo o algo así +def GUIautomateSolve(): + global canvas, a + b = copy.deepcopy(a) + solve() + simplify_moves() + a = b + for i in moves_list: + move(i) + canvas.after(200, drawCube()) +''' + + +# Esto se usa para exportar la solución y resolución a alg.cubing.net. Verificará si puede abrirse con +# Google Chrome, si no puede, intentará Firefox, de lo contrario, usará el navegador web predeterminado del sistema +def GUIexportSolve(): + sCopy = copy.deepcopy(get_scramble()) + mCopy = copy.deepcopy(get_moves()) + + sCopy = str.replace(sCopy, "'", "-") + sCopy = str.replace(sCopy, " ", "_") + mCopy = str.replace(mCopy, "'", "-") + mCopy = str.replace(mCopy, " ", "_") + + url = "alg.cubing.net/?setup=" + sCopy + "&alg=" + mCopy + chrome_path = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe" + firefox_path = "C:/Program Files/Mozilla Firefox/Firefox.exe" + if os.path.exists(chrome_path): + webbrowser.get(chrome_path + " %s").open(url) + elif os.path.exists(firefox_path): + webbrowser.get(firefox_path + " %s").open(url) + else: + webbrowser.open_new(url) + + +# Esto se usa para la rotación del cubo con botones. Toma un movimiento Yi o Y +# para ser ejecutado +def GUIyRotation(given): + global canvas + if given == "Y" or given == "y": + move('y') + elif given == "Yi" or given == "Y'" or given == "yi" or given == "y'": + move('yi') + canvas.delete(ALL) + drawCube() + + +# Esto creará una nueva GUI de Información, después de cerrarla, se ejecutará la GUI principal() +def InfoGUI(): + rt = tk.Tk() + rt.geometry("600x140+50+50") # tamaño del marco inicial + rt.wm_title("Información del Resolutor de Cubos") + # Solo permite que se ajuste la altura, no el ancho + rt.resizable(True, True) + InfoGUIy(rt) + rt.mainloop() + GUI() + + +# Esto se llamará dentro de InfoGUI(), creará una bonita GUI con instrucciones +def InfoGUIy(rt): + frame = Frame(rt) + frame.grid(row=0, column=0) + wel = "Bienvenido al resolutor de cubos, aquí tienes algunas características:" + instruct1 = "* Introduce tus propios movimientos, luego haz clic en 'ejecutar' para ejecutarlos" + instruct2 = "* Haz clic en scramble para generar uno, o crea uno propio seleccionando 'scramble personalizado'" + instruct3 = "* Haz clic en los dos botones de resolver para resolver, o resuelve paso a paso con los botones azules" + instruct4 = "* Puedes copiar el scramble o la solución al portapapeles, o exportar a alg.cubing.net para visualizarlo" + instruct5 = "* Ejecuta algunas simulaciones ingresando el número de scrambles a simular" + InfoLabel = Label(frame, text=wel + "\n"+instruct1+"\n"+instruct2 + + "\n"+instruct3+"\n"+instruct4+"\n"+instruct5, justify=LEFT) + InfoLabel.grid(row=0, column=0) + InfoQuitButton = Button(frame, text="Empezar a Resolver", + fg="red", command=lambda: rt.destroy()) + InfoQuitButton.grid(row=1, column=0) + + +# Esto se usa para ejecutar simulaciones, utiliza la función de simulación. +# Esta es la parte de la GUI para las simulaciones +def GUISimulation(simNum): + global SimulateBestLabel, SimulateWorstLabel + simResults = simulation(simNum) + s = StringVar(value=simResults[2]) + GUIcustomScramble(s) + GUISolve() + SimulateBestLabel.configure(text=str(simResults[1] + 1) + " de " + str( + simNum.get()) + " con " + str(solution_length) + " movimientos") + SimulateWorstLabel.configure(text=str(simResults[4] + 1) + " de " + str( + simNum.get()) + " con " + str(simResults[3]) + " movimientos") + + +# GUI es la GUI principal que se creará, llama a GUIy que en realidad hace todo +# el trabajo para la GUI +def GUI(): + global root + root = tk.Tk() + root.geometry("700x600+50+50") # tamaño del marco inicial + root.wm_title("Resolutor de Cubos") + # Solo permite que se ajuste la altura, no el ancho + root.resizable(True, True) + GUIy() + root.mainloop() + + +# GUIy, después de que la GUI misma se cree con GUI(), esto creará todos los +# botones, etiquetas, etc., y los añadirá a un marco. Este es el trabajo detrás +# de escenas para la propia GUI. +def GUIy(): + global root, canvas, ScrambleLabel, SolutionLabel, SolutionNumberLabel, frame, isTransparent + global PLLNumberLabel, F2LNumberLabel, CrossNumberLabel, OLLNumberLabel, SimulateBestLabel, SimulateWorstLabel + + isTransparent = False + canvas = drawCanvas(root) + drawCube() + + # locales + move = StringVar(value="") + scram = StringVar(value="Introduce el Scramble Aquí") + simNum = IntVar() # Número de Simulación + + # Marco para controles + frame = Frame(root) + frame.grid(row=0, column=1, sticky="n") + + # Marco para rotaciones del cubo + Rframe = Frame(root) + Rframe.grid(row=0, column=0, sticky="n") + + # fila 1 - etiqueta de bienvenida y botón de nuevo cubo + Welcome = Label(frame, text="Bienvenido al Resolutor de Cubos").grid( + row=1, column=0) + NewCubeButton = Button(frame, text="Nuevo Cubo", + command=lambda: GUInewCube()) + NewCubeButton.grid(row=1, column=1) + # fila 2 - etiqueta para indicar que introduzcas un movimiento para ejecutar + EnterMove = Label(frame, text="Introduce movimiento(s):").grid(row=2, column=0) + # fila 3 - Tiene entrada para movimientos personalizados así como botón para ejecutarlos + MoveEntry = Entry(frame, textvariable=move).grid(row=3, column=0) + DrawCubeButton = Button(frame, text="Ejecutar", command=lambda: GUImakeMove( + move)).grid(row=3, column=1, sticky="w") + # fila 4 - La etiqueta que imprimirá el scramble actual después de la generación + ScrambleLabel = Label(frame, text="El scramble se mostrará aquí", + wraplength=180, justify=CENTER, height=2) + ScrambleLabel.grid(row=4, column=0, columnspan=2) + # fila 5 - El botón scramble para generar un nuevo scramble y copiar scramble al portapapeles + ScrambleButton = Button(frame, text="Scramble", bg="lightgreen", + command=lambda: GUIScramble()).grid(row=5, column=0) + CopyScrambleButton = Button(frame, text="Copiar Scramble", bg="#EF9", + command=lambda: GUItoClipboard(get_scramble())).grid(row=5, column=1) + # fila 6 - entrada para scramble personalizado y botón para aplicar scramble personalizado al cubo + CustomScramEntry = Entry(frame, textvariable=scram) + CustomScramEntry.grid(row=6, column=0, sticky="w") + CustomScramButton = Button(frame, text="Scramble Personalizado", + bg="lightgreen", command=lambda: GUIcustomScramble(scram)) + CustomScramButton.grid(row=6, column=1) + # fila 7 - Solución lenta (usando temporizador para hacerlo lentamente), solución instantánea (solución rápida e instantánea), copiar solución al portapapeles + # SolveTimerButton = Button(frame, text="Solución Lenta", bg="#D53", command = lambda: GUIautomateSolve()).grid(row=7, column=0, sticky="w", pady=5) + SolveButton = Button(frame, text="Resolver Cubo", bg="#D53", command=lambda: GUISolve( + )).grid(row=7, column=0) # sticky="e" si también se usa el botón de temporizador + CopyScrambleButton = Button(frame, text="Copiar Solución", bg="#EF9", + command=lambda: GUItoClipboard(get_moves())).grid(row=7, column=1) + # fila 8 - Botones de solución para hacer pasos independientemente + CrossButton = Button(frame, text="Cross", bg="lightblue", + command=lambda: GUIsetSolve("cross")) + CrossButton.grid(row=8, column=0) + F2LButton = Button(frame, text="F2l", bg="lightblue", + command=lambda: GUIsetSolve("F2L")) + F2LButton.grid(row=8, column=0, sticky="e", padx=15) + OLLButton = Button(frame, text="OLL", bg="lightblue", + command=lambda: GUIsetSolve("OLL")) + OLLButton.grid(row=8, column=1, sticky="w") + PLLButton = Button(frame, text="PLL", bg="lightblue", + command=lambda: GUIsetSolve("PLL")) + PLLButton.grid(row=8, column=1, sticky="e", padx=30) + # fila 9 - la etiqueta que contiene la solución que se generará + SolutionLabel = Label(frame, text="La solución se mostrará aquí", + wraplength=250, justify=CENTER, height=8) + SolutionLabel.grid(row=9, column=0, columnspan=2) + # fila 10 - Etiquetas para el número de movimientos necesarios para resolver + SolutionNumberInfoLabel = Label(frame, text="Número total de movimientos utilizados:") + SolutionNumberInfoLabel.grid(row=10, column=0, sticky="e") + SolutionNumberLabel = Label(frame, text="0") + SolutionNumberLabel.grid(row=10, column=1, sticky="w") + # fila 11, 12, 13, 14 - Etiquetas para el número de movimientos para los diferentes pasos + CrossInfoLabel = Label(frame, text="Movimientos necesarios para Cross:") + CrossInfoLabel.grid(row=11, column=0, sticky="e") + CrossNumberLabel = Label(frame, text="0") + CrossNumberLabel.grid(row=11, column=1, sticky="w") + F2LInfoLabel = Label(frame, text="Movimientos necesarios para F2L:") + F2LInfoLabel.grid(row=12, column=0, sticky="e") + F2LNumberLabel = Label(frame, text="0") + F2LNumberLabel.grid(row=12, column=1, sticky="w") + OLLInfoLabel = Label(frame, text="Movimientos necesarios para OLL:") + OLLInfoLabel.grid(row=13, column=0, sticky="e") + OLLNumberLabel = Label(frame, text="0") + OLLNumberLabel.grid(row=13, column=1, sticky="w") + PLLInfoLabel = Label(frame, text="Movimientos necesarios para PLL:") + PLLInfoLabel.grid(row=14, column=0, sticky="e") + PLLNumberLabel = Label(frame, text="0") + PLLNumberLabel.grid(row=14, column=1, sticky="w") + # fila 15 - Exportando a alg.cubing.net + ExportSolveButton = Button( + frame, text="Exportar a alg.cubing.net", command=lambda: GUIexportSolve()) + ExportSolveButton.grid(row=15, column=0) + # fila 16 - Simulaciones para la mejor solución + SimulateEntry = Entry(frame, textvariable=simNum) + SimulateEntry.grid(row=16, column=0) + SimulateButton = Button(frame, text="Iniciar Simulaciones", + command=lambda: GUISimulation(simNum)) + SimulateButton.grid(row=16, column=1) + # fila 17 - Qué mejor se encontró + SimulateBestInfo = Label(frame, text="Mejor Simulación: ") + SimulateBestInfo.grid(row=17, column=0) + SimulateBestLabel = Label(frame, text="") + SimulateBestLabel.grid(row=17, column=1, sticky="w") + # fila 18 Qué peor se encontró + SimulateWorstInfo = Label(frame, text="Peor Simulación: ") + SimulateWorstInfo.grid(row=18, column=0) + SimulateWorstLabel = Label(frame, text="") + SimulateWorstLabel.grid(row=18, column=1) + + # En Rframe, botones para rotación + RotationLabel = Label(Rframe, text="Usa los botones de abajo para rotar el cubo").grid( + row=0, column=0, columnspan=2) + YrotationButton = Button(Rframe, text="<---- Y", + command=lambda: GUIyRotation("Y")) + YrotationButton.grid(row=1, column=0) + YirotationButton = Button(Rframe, text="Y' ---->", + command=lambda: GUIyRotation("Yi")) + YirotationButton.grid(row=1, column=1) + + +InfoGUI() diff --git a/catch-all/README.md b/catch-all/README.md index a60948a..323385e 100644 --- a/catch-all/README.md +++ b/catch-all/README.md @@ -16,3 +16,4 @@ Aquí iré dejando scripts y ejercicios que se me ocurran, con lo que no hay un | [Bots Telegram](./06_bots_telegram/README.md) | Bots de Telegram con Python | avanzado | | [Diagram as code](./07_diagrams_as_code/README.md) | Diagramas de infraestructuras con Python | fácil | | [urlf4ck3r](./08_urlf4ck3r/README.md) | Script para buscar enlaces en una web y guardarlos en un fichero | intermedio | +| [Solucionador Rubik](./09_rubiks-cube-solver/README.md) | Script para resolver un cubo de Rubik | fácil |