├── README.md └── cube.py /README.md: -------------------------------------------------------------------------------- 1 | # Rubiks-Cube-Solver 2 | Rubik's Cube Solver coded in Python. 3 | Solver Coded by Lucas and Tom Brannan 4 | 5 | To run the Solver, run the cube.py file. The GUI will automatically start up. If you get errors, there is a chance that you do not have tkinter installed. That is necessary to have in order to run the GUI. 6 | 7 | ### Features 8 | Just read the instructions to see some of the features that are included in the Solver. 9 | Various features included are: 10 | * User or program generated scrambles 11 | * The ability to make custom moves 12 | * The ability to hit either the solve button, or each step of the solve to see it solve step-by-step 13 | * The ability to run simulations with a user defined amount of solves (be careful, too many could make the program freeze) 14 | * Ability to copy scrambles or solutions to the clipboard, as well as view externally. 15 | * Clicking on the 2D cube will allow you to see the other bottom tiles that are not normally visible 16 | 17 |

18 | Solver Screenshot 19 |

20 | 21 | 22 | ### Various Commands 23 | If you don't want to use the GUI, you can also just type function commands in the interpreter. Here are some of the useful ones: 24 | * print_cube() Prints the cube in text format 25 | * scramble() You can either provide a number, a scramble in string format, or nothing for a 25 move default scramble 26 | * get_scramble() Prints the previous scramble 27 | * solve() Will solve the cube 28 | * get_moves() Prints out the Solution that was generated upon using solve() 29 | * simulation(num) The number provided is the amount of solves you want to simulate. Will return you the best solve with it's scramble, as well as the worst solve and it's scramble. 30 | 31 | 32 | The Solver itself is based upon a CFOP (Fridrich) method of solving. It solves the Cross, does the F2L step, does a 2-look OLL, and a 2-look PLL. As for notation, basic notation used in the cubing world is used, however, a counterclockwise move can be denoted with either an apostrophe (standard way), or using the letter i (denoting i for inverse). 33 | -------------------------------------------------------------------------------- /cube.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | import tkinter as tk 3 | import copy, webbrowser, os 4 | from tkinter import * 5 | 6 | #This is the Cube Solver 7 | #This version contains a GUI 8 | #Last Edited on: 12/5/2014 9 | #Written by: Lucas Liberacki & Tom Brannan 10 | 11 | 12 | #globals 13 | moves_list = [] 14 | last_scramble = [] 15 | f2l_list = [] 16 | step_moves_list = [] 17 | solution_length = 0 18 | 19 | #creates a 3d list representing a solved cube 20 | def make_cube(): 21 | global step_moves_list, f2l_list, moves_list 22 | step_moves_list = [0,0,0,0] 23 | f2l_list = [] 24 | moves_list = [] 25 | return [ [['W', 'W', 'W'], 26 | ['W', 'W', 'W'], 27 | ['W', 'W', 'W']], #Up/white 28 | 29 | [['G', 'G', 'G'], 30 | ['G', 'G', 'G'], 31 | ['G', 'G', 'G']], #front/green 32 | 33 | [['R', 'R', 'R'], 34 | ['R', 'R', 'R'], 35 | ['R', 'R', 'R']], #right/red 36 | 37 | [['O', 'O', 'O'], 38 | ['O', 'O', 'O'], 39 | ['O', 'O', 'O']], #left/orange 40 | 41 | [['Y', 'Y', 'Y'], 42 | ['Y', 'Y', 'Y'], 43 | ['Y', 'Y', 'Y']], #down/yellow 44 | 45 | [['B', 'B', 'B'], 46 | ['B', 'B', 'B'], 47 | ['B', 'B', 'B']]] #back/blue 48 | 49 | a = make_cube() 50 | 51 | #prints a string representation of the cube to the interpreter 52 | def print_cube(): 53 | print('\t\t'+str(a[5][0])+'\n\t\t'+str(a[5][1])+'\n\t\t'+str(a[5][2])) 54 | print(str(a[3][0])+' '+str(a[0][0])+' '+str(a[2][0])) 55 | print(str(a[3][1])+' '+str(a[0][1])+' '+str(a[2][1])) 56 | print(str(a[3][2])+' '+str(a[0][2])+' '+str(a[2][2])) 57 | print('\t\t'+str(a[1][0])+'\n\t\t'+str(a[1][1])+'\n\t\t'+str(a[1][2])) 58 | print('\t\t'+str(a[4][0])+'\n\t\t'+str(a[4][1])+'\n\t\t'+str(a[4][2])) 59 | 60 | #simplifies the list of moves and returns a string representation of the moves 61 | def get_moves(): 62 | simplify_moves() 63 | s = "" 64 | for i in moves_list: 65 | s += str(i) + " " 66 | s = str.replace(s, "i", "'")[:-1] 67 | return s 68 | 69 | #returns a string representation of the last scramble 70 | def get_scramble(): 71 | s = "" 72 | for i in last_scramble: 73 | s += str(i) + " " 74 | s = str.replace(s, "i", "'")[:-1] 75 | return s 76 | 77 | #helper function: returns True if all elements in a set are equal 78 | def all_same(items): 79 | return all(x == items[0] for x in items) 80 | 81 | #Transforms a given move into the corresponding move after a Y-rotation 82 | def yTransform(move): 83 | if move[0] in ["U", "D"]: 84 | return move 85 | if move[0] == "F": 86 | return "R" + move[1:] 87 | if move[0] == "R": 88 | return "B" + move[1:] 89 | if move[0] == "B": 90 | return "L" + move[1:] 91 | if move[0] == "L": 92 | return "F" + move[1:] 93 | raise Exception("Invalid move to yTransform: " + move) 94 | 95 | #modifies the global moves list by removing redundancies 96 | def simplify_moves(): 97 | global moves_list, solution_length 98 | new_list = [] 99 | prev_move = "" 100 | yCount = 0 101 | for move in moves_list: 102 | if move == "Y": 103 | yCount += 1 104 | yCount %= 4 105 | continue 106 | if move == "Yi": 107 | yCount += 3 108 | yCount %= 4 109 | continue 110 | if move == "Y2": 111 | yCount += 2 112 | yCount %= 4 113 | continue 114 | if yCount > 0: 115 | for i in range(yCount): 116 | move = yTransform(move) 117 | if prev_move == "" or prev_move == '': 118 | prev_move = move 119 | new_list.append(move) 120 | continue 121 | if move[0] == prev_move[0]: 122 | if len(move) == 1: 123 | if len(prev_move) <= 1: 124 | del new_list[-1] 125 | mv = move[0] + "2" 126 | new_list.append(mv) 127 | prev_move = mv 128 | continue 129 | if prev_move[1] == "i": 130 | del new_list[-1] 131 | prev_move = new_list[-1] if len(new_list) > 0 else "" 132 | continue 133 | if prev_move[1] == "2": 134 | del new_list[-1] 135 | mv = move[0] + "i" 136 | new_list.append(mv) 137 | prev_move = mv 138 | continue 139 | if move[1] == "i": 140 | if len(prev_move) == 1: 141 | del new_list[-1] 142 | prev_move = new_list[-1] if len(new_list) > 0 else "" 143 | continue 144 | if prev_move[1] == "i": 145 | del new_list[-1] 146 | mv = move[0] + "2" 147 | new_list.append(mv) 148 | prev_move = mv 149 | continue 150 | if prev_move[1] == "2": 151 | del new_list[-1] 152 | mv = move[0] 153 | new_list.append(mv) 154 | prev_move = mv 155 | continue 156 | if move[1] == "2": 157 | if len(prev_move) == 1: 158 | del new_list[-1] 159 | mv = move[0] + "i" 160 | new_list.append(mv) 161 | prev_move = mv 162 | continue 163 | if prev_move[1] == "i": 164 | del new_list[-1] 165 | mv = move[0] 166 | new_list.append(mv) 167 | prev_move = mv 168 | continue 169 | if prev_move[1] == "2": 170 | del new_list[-1] 171 | prev_move = new_list[-1] if len(new_list) > 0 else "" 172 | continue 173 | new_list.append(move) 174 | prev_move = move 175 | solution_length = len(new_list) 176 | moves_list = new_list 177 | 178 | #sets up the cube to perform a move by rotating that face to the top 179 | def setup(face): 180 | face = str.lower(face) 181 | if face == "f": 182 | move("X") 183 | elif face == "r": 184 | move("Zi") 185 | elif face == "l": 186 | move("Z") 187 | elif face == "d": 188 | move("X2") 189 | elif face == "b": 190 | move("Xi") 191 | else: 192 | raise Exception("Invalid setup; face: " + face) 193 | 194 | #performs the inverse of setup to restore the cube's previous orientation 195 | def undo(face): 196 | face = str.lower(face) 197 | if face == "f": 198 | move("Xi") 199 | elif face == "r": 200 | move("Z") 201 | elif face == "l": 202 | move("Zi") 203 | elif face == "d": 204 | move("X2") 205 | elif face == "b": 206 | move("X") 207 | else: 208 | raise Exception("Invalid undo; face: " + face) 209 | 210 | #Tokenizes a string of moves 211 | def m(s): 212 | s = str.replace(s, "'", "i") 213 | k = s.split(' ') 214 | global moves_list, solution_length 215 | solution_length += len(k) 216 | for word in k: 217 | moves_list.append(word) 218 | move(word) 219 | 220 | #performs a move by setting up, performing U moves, and undoing the setup 221 | def move(mv): 222 | mv = str.lower(mv) 223 | if mv == "u": 224 | U() 225 | elif mv == "u2": 226 | move("U"); move("U"); 227 | elif mv == "ui": 228 | move("U"); move("U"); move("U"); 229 | elif mv == "f": 230 | setup("F"); U(); undo("F"); 231 | elif mv == "f2": 232 | move("F"); move("F"); 233 | elif mv == "fi": 234 | move("F"); move("F"); move("F"); 235 | elif mv == "r": 236 | setup("R"); U(); undo("R"); 237 | elif mv == "r2": 238 | move("R"); move("R"); 239 | elif mv == "ri": 240 | move("R"); move("R"); move("R"); 241 | elif mv == "l": 242 | setup("L"); U(); undo("L"); 243 | elif mv == "l2": 244 | move("L"); move("L"); 245 | elif mv == "li": 246 | move("L"); move("L"); move("L"); 247 | elif mv == "b": 248 | setup("B"); U(); undo("B"); 249 | elif mv == "b2": 250 | move("B"); move("B"); 251 | elif mv == "bi": 252 | move("B"); move("B"); move("B"); 253 | elif mv == "d": 254 | setup("D"); U(); undo("D"); 255 | elif mv == "d2": 256 | move("D"); move("D"); 257 | elif mv == "di": 258 | move("D"); move("D"); move("D"); 259 | elif mv == "x": 260 | rotate("X") 261 | elif mv == "x2": 262 | move("X"); move("X"); 263 | elif mv == "xi": 264 | move("X"); move("X"); move("X"); 265 | elif mv == "y": 266 | rotate("Y") 267 | elif mv == "y2": 268 | move("Y"); move("Y"); 269 | elif mv == "yi": 270 | move("Y"); move("Y"); move("Y"); 271 | elif mv == "z": 272 | rotate("Z") 273 | elif mv == "z2": 274 | move("Z"); move("Z"); 275 | elif mv == "zi": 276 | move("Z"); move("Z"); move("Z"); 277 | elif mv == "uw": 278 | move("D"); move("Y"); 279 | elif mv == "uw2": 280 | move("UW"); move("UW"); 281 | elif mv == "uwi": 282 | move("UW"); move("UW"); move("UW"); 283 | elif mv == "m": 284 | move("Li"); move("R"); move("Xi"); 285 | elif mv == "mi": 286 | move("M"); move("M"); move("M"); 287 | elif mv == "m2": 288 | move("M"); move("M"); 289 | elif mv == "rw": 290 | move("L"); move("X"); 291 | elif mv == "rwi": 292 | move("RW"); move("RW"); move("RW"); 293 | elif mv == "rw2": 294 | move("RW"); move("RW"); 295 | elif mv == "fw": 296 | move("Bi"); move("Z"); 297 | elif mv == "fwi": 298 | move("FW"); move("FW"); move("FW"); 299 | elif mv == "fw2": 300 | move("FW"); move("FW"); 301 | elif mv == "lw": 302 | move("R"); move("Xi"); 303 | elif mv == "lwi": 304 | move("LW"); move("LW"); move("LW"); 305 | elif mv == "lw2": 306 | move("LW"); move("LW"); 307 | elif mv == "bw": 308 | move("F"); move("Zi"); 309 | elif mv == "bwi": 310 | move("BW"); move("BW"); move("BW"); 311 | elif mv == "bw2": 312 | move("BW"); move("BW"); 313 | elif mv == "dw": 314 | move("U"); move("Yi"); 315 | elif mv == "dwi": 316 | move("DW"); move("DW"); move("DW"); 317 | elif mv == "dw2": 318 | move("DW"); move("DW"); 319 | else: 320 | raise Exception("Invalid Move: " + str(mv)) 321 | 322 | #rotates the entire cube along a particular axis 323 | def rotate(axis): 324 | axis = str.lower(axis) 325 | if axis == 'x': #R 326 | temp = a[0] 327 | a[0] = a[1] 328 | a[1] = a[4] 329 | a[4] = a[5] 330 | a[5] = temp 331 | rotate_face_counterclockwise("L") 332 | rotate_face_clockwise("R") 333 | elif axis == 'y': #U 334 | temp = a[1] 335 | a[1] = a[2] 336 | a[2] = a[5] 337 | a[5] = a[3] 338 | a[3] = temp 339 | #after swaps, 340 | rotate_face_clockwise("L") 341 | rotate_face_clockwise("F") 342 | rotate_face_clockwise("R") 343 | rotate_face_clockwise("B") 344 | rotate_face_clockwise("U") 345 | rotate_face_counterclockwise("D") 346 | elif axis == 'z': #F 347 | temp = a[0] 348 | a[0] = a[3] 349 | a[3] = a[4] 350 | a[4] = a[2] 351 | a[2] = temp 352 | rotate_face_clockwise("L"); rotate_face_clockwise("L"); 353 | rotate_face_clockwise("D"); rotate_face_clockwise("D"); 354 | rotate_face_clockwise("F") 355 | rotate_face_counterclockwise("B") 356 | else: 357 | raise Exception("Invalid rotation: " + axis) 358 | 359 | #performs a U move 360 | def U(): 361 | #rotate U face 362 | temp = a[0][0][0] 363 | a[0][0][0] = a[0][2][0] 364 | a[0][2][0] = a[0][2][2] 365 | a[0][2][2] = a[0][0][2] 366 | a[0][0][2] = temp 367 | temp = a[0][0][1] 368 | a[0][0][1] = a[0][1][0] 369 | a[0][1][0] = a[0][2][1] 370 | a[0][2][1] = a[0][1][2] 371 | a[0][1][2] = temp 372 | 373 | #rotate others 374 | temp = a[5][2][0] 375 | a[5][2][0] = a[3][2][2] 376 | a[3][2][2] = a[1][0][2] 377 | a[1][0][2] = a[2][0][0] 378 | a[2][0][0] = temp 379 | temp = a[5][2][1] 380 | a[5][2][1] = a[3][1][2] 381 | a[3][1][2] = a[1][0][1] 382 | a[1][0][1] = a[2][1][0] 383 | a[2][1][0] = temp 384 | temp = a[5][2][2] 385 | a[5][2][2] = a[3][0][2] 386 | a[3][0][2] = a[1][0][0] 387 | a[1][0][0] = a[2][2][0] 388 | a[2][2][0] = temp 389 | 390 | #Rotates a particular face counter-clockwise 391 | def rotate_face_counterclockwise(face): 392 | rotate_face_clockwise(face) 393 | rotate_face_clockwise(face) 394 | rotate_face_clockwise(face) 395 | 396 | #Rotates a particular face clockwise 397 | def rotate_face_clockwise(face): 398 | f_id = -1 399 | face = str.lower(face) 400 | if face == "u": 401 | f_id = 0 402 | elif face == "f": 403 | f_id = 1 404 | elif face == "r": 405 | f_id = 2 406 | elif face == "l": 407 | f_id = 3 408 | elif face == "d": 409 | f_id = 4 410 | elif face == "b": 411 | f_id = 5 412 | else: 413 | raise Exception("Invalid face: " + face) 414 | temp = a[f_id][0][0] 415 | a[f_id][0][0] = a[f_id][2][0] 416 | a[f_id][2][0] = a[f_id][2][2] 417 | a[f_id][2][2] = a[f_id][0][2] 418 | a[f_id][0][2] = temp 419 | temp = a[f_id][0][1] 420 | a[f_id][0][1] = a[f_id][1][0] 421 | a[f_id][1][0] = a[f_id][2][1] 422 | a[f_id][2][1] = a[f_id][1][2] 423 | a[f_id][1][2] = temp 424 | 425 | #Randomly scrambles the cube given a number of moves, or given a list of moves 426 | def scramble(moves=25): 427 | global last_scramble, moves_list, solution_length, a 428 | a = make_cube() 429 | if hasattr(moves, '__iter__'): #scramble given a list of moves 430 | m(moves) 431 | moves_list = [] 432 | solution_length = 0 433 | temp = moves.split(' ') 434 | last_scramble = temp 435 | else: #scramble randomly a certain number of times 436 | moves_list = [] #reset moves_list 437 | last_scramble = [] #reset last scramble 438 | prevMove = "" 439 | for i in range(moves): 440 | while True: 441 | thisMove = "" 442 | r = randint(0, 5) 443 | if r == 0: 444 | thisMove += "U" 445 | elif r == 1: 446 | thisMove += "F" 447 | elif r == 2: 448 | thisMove += "R" 449 | elif r == 3: 450 | thisMove += "L" 451 | elif r == 4: 452 | thisMove += "D" 453 | elif r == 5: 454 | thisMove += "B" 455 | if thisMove == "U" and prevMove != "U" and prevMove != "D": 456 | break 457 | if thisMove == "F" and prevMove != "F" and prevMove != "B": 458 | break 459 | if thisMove == "R" and prevMove != "R" and prevMove != "L": 460 | break 461 | if thisMove == "L" and prevMove != "L" and prevMove != "R": 462 | break 463 | if thisMove == "D" and prevMove != "D" and prevMove != "U": 464 | break 465 | if thisMove == "B" and prevMove != "B" and prevMove != "F": 466 | break 467 | r = randint(0, 3) 468 | if r == 1: 469 | move(thisMove + "i") 470 | last_scramble.append(thisMove + "i") 471 | elif r == 2: 472 | move(thisMove + "2") 473 | last_scramble.append(thisMove + "2") 474 | else: 475 | move(thisMove) 476 | last_scramble.append(thisMove) 477 | prevMove = thisMove 478 | 479 | #Solves the top cross as part of the OLL step 480 | def topCross(): 481 | # if all the edges are all equal to eachother (all being white) 482 | if a[0][0][1] == a[0][1][0] == a[0][1][2] == a[0][2][1]: 483 | #print("Cross already done, step skipped") 484 | return 485 | #If this is true, we have our cross and we can go onto the next step 486 | else: 487 | while a[0][0][1] != "W" or a[0][1][0] != "W" or a[0][1][2] != "W" or a[0][2][1] != "W": 488 | if a[0][1][0] == a[0][1][2]: 489 | #if we have a horizontal line Just do alg 490 | m("F R U Ri Ui Fi") 491 | break #breaking w/o having to recheck while conditions again, this will give us a cross 492 | elif a[0][0][1] == a[0][2][1]: 493 | # if we have a vertical line, do a U then alg 494 | m("U F R U Ri Ui Fi") 495 | break 496 | elif a[0][0][1] != "W" and a[0][1][0] != "W" and a[0][1][2] != "W" and a[0][2][1] != "W": 497 | #This would mean we have a dot case, so perform 498 | m("F U R Ui Ri Fi U F R U Ri Ui Fi") 499 | break 500 | elif a[0][1][2] == a[0][2][1] or a[0][0][1] == a[0][1][0]: 501 | # If we have an L case in the top left or the bottom right, will give us a line 502 | m("F R U Ri Ui Fi") 503 | else: 504 | #This is we dont have a line, dot, cross, or L in top left or bottom right 505 | m("U") 506 | 507 | #returns True if the top is solved 508 | def isTopSolved(): 509 | #determines if the top of the cube is solved. 510 | 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]: 511 | return True 512 | else: 513 | return False 514 | 515 | #puts a single edge piece in the proper location for the cross 516 | #Assumes the cross is formed on the bottom and is the yellow face 517 | #Checks all edges in front/up face, then back-right/left if needed 518 | def putCrossEdge(): 519 | global moves_list 520 | for i in range(3): 521 | if i == 1: 522 | m("Ri U R F2") #bring out back-right edge 523 | elif i == 2: 524 | m("L Ui Li F2") #bring out back-left edge 525 | for j in range(4): 526 | for k in range(4): 527 | if "Y" in [a[4][0][1], a[1][2][1]]: 528 | return 529 | m("F") 530 | m("U") 531 | 532 | #Performs the first step of the solution: the cross 533 | def cross(): 534 | for i in range(4): 535 | putCrossEdge() 536 | assert "Y" in [a[4][0][1], a[1][2][1]] 537 | if a[1][2][1] == "Y": 538 | m("Fi R U Ri F2") #orient if necessary 539 | m("Di") 540 | 541 | #permute to correct face: move down face until 2 are lined up, 542 | #then swap the other 2 if they need to be swapped 543 | condition = False 544 | while not condition: 545 | fSame = a[1][1][1] == a[1][2][1] 546 | rSame = a[2][1][1] == a[2][1][2] 547 | bSame = a[5][1][1] == a[5][0][1] 548 | lSame = a[3][1][1] == a[3][1][0] 549 | condition = (fSame, rSame, bSame, lSame).count(True) >= 2 550 | if not condition: 551 | m("D") 552 | if (fSame, rSame, bSame, lSame).count(True) == 4: 553 | return 554 | assert (fSame, rSame, bSame, lSame).count(True) == 2 555 | if not fSame and not bSame: 556 | m("F2 U2 B2 U2 F2") #swap front-back 557 | elif not rSame and not lSame: 558 | m("R2 U2 L2 U2 R2") #swap right-left 559 | elif not fSame and not rSame: 560 | m("F2 Ui R2 U F2") #swap front-right 561 | elif not rSame and not bSame: 562 | m("R2 Ui B2 U R2") #swap right-back 563 | elif not bSame and not lSame: 564 | m("B2 Ui L2 U B2") #swap back-left 565 | elif not lSame and not fSame: 566 | m("L2 Ui F2 U L2") #swap left-front 567 | fSame = a[1][1][1] == a[1][2][1] 568 | rSame = a[2][1][1] == a[2][1][2] 569 | bSame = a[5][1][1] == a[5][0][1] 570 | lSame = a[3][1][1] == a[3][1][0] 571 | assert all([fSame, rSame, bSame, lSame]) 572 | 573 | #This is uses all the f2l algs to solve all the cases possible 574 | def solveFrontSlot(): 575 | #This will be F2L, with all 42 cases 576 | rmid = a[2][1][1] 577 | fmid = a[1][1][1] 578 | dmid = a[4][1][1] 579 | #corner orientations if in U layer, first letter means the direction that the color is facing 580 | fCorU = a[1][0][2] == dmid and a[0][2][2] == fmid and a[2][2][0] == rmid 581 | rCorU = a[2][2][0] == dmid and a[1][0][2] == fmid and a[0][2][2] == rmid 582 | uCorU = a[0][2][2] == dmid and a[2][2][0] == fmid and a[1][0][2] == rmid 583 | #Corner orientations for correct location in D layer 584 | fCorD = a[1][2][2] == dmid and a[2][2][2] == fmid and a[4][0][2] == rmid 585 | rCorD = a[2][2][2] == dmid and a[4][0][2] == fmid and a[1][2][2] == rmid 586 | dCorD = a[4][0][2] == dmid and a[1][2][2] == fmid and a[2][2][2] == rmid #This is solved spot 587 | #edge orientations on U layer, normal or flipped version based on F face 588 | norEdgeFU = a[1][0][1] == fmid and a[0][2][1] == rmid 589 | norEdgeLU = a[3][1][2] == fmid and a[0][1][0] == rmid 590 | norEdgeBU = a[5][2][1] == fmid and a[0][0][1] == rmid 591 | norEdgeRU = a[2][1][0] == fmid and a[0][1][2] == rmid 592 | norEdgeAny = norEdgeFU or norEdgeLU or norEdgeBU or norEdgeRU 593 | flipEdgeFU = a[0][2][1] == fmid and a[1][0][1] == rmid 594 | flipEdgeLU = a[0][1][0] == fmid and a[3][1][2] == rmid 595 | flipEdgeBU = a[0][0][1] == fmid and a[5][2][1] == rmid 596 | flipEdgeRU = a[0][1][2] == fmid and a[2][1][0] == rmid 597 | flipEdgeAny = flipEdgeFU or flipEdgeLU or flipEdgeBU or flipEdgeRU 598 | #edge orientations for normal or flipped insertion into slot 599 | norEdgeInsert = a[1][1][2] == fmid and a[2][2][1] == rmid #This is solved spot 600 | flipEdgeInsert = a[2][2][1] == fmid and a[1][1][2] == rmid 601 | #these are for if the back right or front left slots are open or not 602 | 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 603 | 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] 604 | 605 | if dCorD and norEdgeInsert: 606 | return 607 | #Easy Cases 608 | elif fCorU and flipEdgeRU: #Case 1 609 | m("U R Ui Ri") 610 | elif rCorU and norEdgeFU: #Case 2 611 | m("F Ri Fi R") 612 | elif fCorU and norEdgeLU: #Case 3 613 | m("Fi Ui F") 614 | elif rCorU and flipEdgeBU: #Case 4 615 | m("R U Ri") 616 | #Reposition Edge 617 | elif fCorU and flipEdgeBU: #Case 5 618 | m("F2 Li Ui L U F2") 619 | elif rCorU and norEdgeLU: #Case 6 620 | m("R2 B U Bi Ui R2") 621 | elif fCorU and flipEdgeLU: #Case 7 622 | m("Ui R U2 Ri U2 R Ui Ri") 623 | elif rCorU and norEdgeBU: #Case 8 624 | m("U Fi U2 F Ui F Ri Fi R") 625 | # Reposition edge and Corner Flip 626 | elif fCorU and norEdgeBU: #Case 9 627 | m("Ui R Ui Ri U Fi Ui F") 628 | elif rCorU and flipEdgeLU: #Case 10 629 | if not backRight: 630 | m("Ri U R2 U Ri") 631 | else: 632 | m("Ui R U Ri U R U Ri") 633 | elif fCorU and norEdgeRU: #Case 11 634 | m("Ui R U2 Ri U Fi Ui F") 635 | elif rCorU and flipEdgeFU: # Case 12 636 | if not backRight: 637 | m("Ri U2 R2 U Ri") 638 | else: 639 | m("Ri U2 R2 U R2 U R") 640 | elif fCorU and norEdgeFU: #Case 13 641 | if not backRight: 642 | m("Ri U R Fi Ui F") 643 | else: 644 | m("U Fi U F Ui Fi Ui F") 645 | elif rCorU and flipEdgeRU: #Case 14 646 | m("Ui R Ui Ri U R U Ri") 647 | # Split Pair by Going Over 648 | elif fCorU and flipEdgeFU: #Case 15 649 | if not backRight: 650 | m("Ui Ri U R Ui R U Ri") 651 | elif not frontLeft: 652 | m("U R Ui Ri D R Ui Ri Di") 653 | else: 654 | m("U Ri F R Fi U R U Ri") 655 | elif rCorU and norEdgeRU: # Case 16 656 | m("R Ui Ri U2 Fi Ui F") 657 | elif uCorU and flipEdgeRU: #Case 17 658 | m("R U2 Ri Ui R U Ri") 659 | elif uCorU and norEdgeFU: # Case 18 660 | m("Fi U2 F U Fi Ui F") 661 | # Pair made on side 662 | elif uCorU and flipEdgeBU: #Case 19 663 | m("U R U2 R2 F R Fi") 664 | elif uCorU and norEdgeLU: #Case 20 665 | m("Ui Fi U2 F2 Ri Fi R") 666 | elif uCorU and flipEdgeLU: #Case 21 667 | m("R B U2 Bi Ri") 668 | elif uCorU and norEdgeBU: #Case 22 669 | m("Fi Li U2 L F") 670 | #Weird Cases 671 | elif uCorU and flipEdgeFU: #Case 23 672 | m("U2 R2 U2 Ri Ui R Ui R2") 673 | elif uCorU and norEdgeRU: #Case 24 674 | m("U Fi Li U L F R U Ri") 675 | #Corner in Place, edge in the U face (All these cases also have set-up moves in case the edge is in the wrong orientation 676 | elif dCorD and flipEdgeAny: #Case 25 677 | if flipEdgeBU: 678 | m("U") #set-up move 679 | elif flipEdgeLU: 680 | m("U2") #set-up move 681 | elif flipEdgeFU: 682 | m("Ui") #set-up move 683 | if not backRight: 684 | m("R2 Ui Ri U R2") 685 | else: 686 | m("Ri Fi R U R Ui Ri F") 687 | elif dCorD and norEdgeAny: #Case 26 688 | if norEdgeRU: 689 | m("U") #set-up move 690 | elif norEdgeBU: 691 | m("U2") #set-up move 692 | elif norEdgeLU: 693 | m("Ui") #set-up move 694 | m("U R Ui Ri F Ri Fi R") 695 | elif fCorD and flipEdgeAny: #Case 27 696 | if flipEdgeBU: 697 | m("U") #set-up move 698 | elif flipEdgeLU: 699 | m("U2") #set-up move 700 | elif flipEdgeFU: 701 | m("Ui") #set-up move 702 | m("R Ui Ri U R Ui Ri") 703 | elif rCorD and norEdgeAny: #Case 28 704 | if norEdgeRU: 705 | m("U") #set-up move 706 | elif norEdgeBU: 707 | m("U2") #set-up move 708 | elif norEdgeLU: 709 | m("Ui") #set-up move 710 | m("R U Ri Ui F Ri Fi R") 711 | elif fCorD and norEdgeAny: #Case 29 712 | if norEdgeRU: 713 | m("U") #set-up move 714 | elif norEdgeBU: 715 | m("U2") #set-up move 716 | elif norEdgeLU: 717 | m("Ui") #set-up move 718 | m("U2 R Ui Ri Fi Ui F") 719 | elif rCorD and flipEdgeAny: #Case 30 720 | if flipEdgeBU: 721 | m("U") #set-up move 722 | elif flipEdgeLU: 723 | m("U2") #set-up move 724 | elif flipEdgeFU: 725 | m("Ui") #set-up move 726 | m("R U Ri Ui R U Ri") 727 | #Edge in place, corner in U Face 728 | elif uCorU and flipEdgeInsert: # Case 31 729 | m("R U2 Ri Ui F Ri Fi R") 730 | elif uCorU and norEdgeInsert: # Case 32 731 | m("R2 U R2 U R2 U2 R2") 732 | elif fCorU and norEdgeInsert: # Case 33 733 | m("Ui R Ui Ri U2 R Ui Ri") 734 | elif rCorU and norEdgeInsert: # Case 34 735 | m("Ui R U2 Ri U R U Ri") 736 | elif fCorU and flipEdgeInsert: # Case 35 737 | m("U2 R Ui Ri Ui Fi Ui F") 738 | elif rCorU and flipEdgeInsert: # Case 36 739 | m("U Fi Ui F Ui R U Ri") 740 | #Edge and Corner in place 741 | #Case 37 is Lol case, already completed 742 | elif dCorD and flipEdgeInsert: #Case 38 (Typical flipped f2l pair case 743 | m("R2 U2 F R2 Fi U2 Ri U Ri") 744 | elif fCorD and norEdgeInsert: # Case 39 745 | m("R2 U2 Ri Ui R Ui Ri U2 Ri") 746 | elif rCorD and norEdgeInsert: # Case 40 747 | m("R U2 R U Ri U R U2 R2") 748 | elif fCorD and flipEdgeInsert: #Case 41 749 | m("F2 Li Ui L U F Ui F") 750 | elif rCorD and flipEdgeInsert: # Case 42 751 | m("R Ui Ri Fi Li U2 L F") 752 | 753 | #Returns true if the f2l Corner in FR spot is inserted and oriented correctly 754 | def f2lCorner(): 755 | 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] #This is solved spot 756 | 757 | #Returns true if the f2l edge in FR spot is inserted and oriented correctly 758 | def f2lEdge(): 759 | return a[1][1][2] == a[1][1][1] and a[2][2][1] == a[2][1][1] #This is solved spot 760 | 761 | #Returns true if the f2l edge and corner are properly inserted and orientated in the FR position 762 | def f2lCorrect(): 763 | return f2lCorner() and f2lEdge() 764 | 765 | # returns if the f2l edge is on the top layer at all 766 | def f2lEdgeOnTop(): 767 | rmid = a[2][1][1] 768 | fmid = a[1][1][1] 769 | dmid = a[4][1][1] 770 | #edge orientations on U layer, normal or flipped version based on F face 771 | norEdgeFU = a[1][0][1] == fmid and a[0][2][1] == rmid 772 | norEdgeLU = a[3][1][2] == fmid and a[0][1][0] == rmid 773 | norEdgeBU = a[5][2][1] == fmid and a[0][0][1] == rmid 774 | norEdgeRU = a[2][1][0] == fmid and a[0][1][2] == rmid 775 | norEdgeAny = norEdgeFU or norEdgeLU or norEdgeBU or norEdgeRU 776 | flipEdgeFU = a[0][2][1] == fmid and a[1][0][1] == rmid 777 | flipEdgeLU = a[0][1][0] == fmid and a[3][1][2] == rmid 778 | flipEdgeBU = a[0][0][1] == fmid and a[5][2][1] == rmid 779 | flipEdgeRU = a[0][1][2] == fmid and a[2][1][0] == rmid 780 | flipEdgeAny = flipEdgeFU or flipEdgeLU or flipEdgeBU or flipEdgeRU 781 | return norEdgeAny or flipEdgeAny 782 | 783 | #returns true if the f2l edge is inserted. Can be properly orientated, or flipped. 784 | def f2lEdgeInserted(): 785 | rmid = a[2][1][1] 786 | fmid = a[1][1][1] 787 | #edge orientations for normal or flipped insertion into slot 788 | norEdgeInsert = a[1][1][2] == fmid and a[2][2][1] == rmid #This is solved spot 789 | flipEdgeInsert = a[2][2][1] == fmid and a[1][1][2] == rmid 790 | return norEdgeInsert or flipEdgeInsert 791 | 792 | #This is used to determine if the front f2l edge is inserted or not, the parameter is for the requested edge. takes BR, BL, and FL as valid 793 | def f2lEdgeInserted2(p): 794 | rmid = a[2][1][1] 795 | fmid = a[1][1][1] 796 | #edge orientations for normal or flipped insertion into slot 797 | norEdgeInsert = a[1][1][2] == fmid and a[2][2][1] == rmid #This is solved spot 798 | flipEdgeInsert = a[2][2][1] == fmid and a[1][1][2] == rmid 799 | #Edge orientations in comparison to Front and Right colors 800 | BR = (a[5][1][2] == fmid and a[2][0][1] == rmid) or (a[5][1][2] == rmid and a[2][0][1] == fmid) 801 | BL = (a[3][0][1] == fmid and a[5][1][0] == rmid) or (a[3][0][1] == rmid and a[5][1][0] == fmid) 802 | FL = (a[3][2][1] == fmid and a[1][1][0] == rmid) or (a[3][2][1] == rmid and a[1][1][0] == fmid) 803 | 804 | if p == "BR": 805 | if BR: 806 | return True 807 | else: 808 | return False 809 | elif p == "BL": 810 | if BL: 811 | return True 812 | return False 813 | elif p == "FL": 814 | if FL: 815 | return True 816 | return False 817 | elif p == "FR": 818 | if norEdgeInsert or flipEdgeInsert: 819 | return True 820 | return False 821 | 822 | 823 | #returns true if f2l corner is inserted, doesn't have to be orientated correctly 824 | def f2lCornerInserted(): 825 | rmid = a[2][1][1] 826 | fmid = a[1][1][1] 827 | dmid = a[4][1][1] 828 | #Corner orientations for correct location in D layer 829 | fCorD = a[1][2][2] == dmid and a[2][2][2] == fmid and a[4][0][2] == rmid 830 | rCorD = a[2][2][2] == dmid and a[4][0][2] == fmid and a[1][2][2] == rmid 831 | dCorD = a[4][0][2] == dmid and a[1][2][2] == fmid and a[2][2][2] == rmid #This is solved spot 832 | return fCorD or rCorD or dCorD 833 | 834 | #Returns true if there is an f2l corner located in the FR orientation 835 | def f2lFRCor(): 836 | rmid = a[2][1][1] 837 | fmid = a[1][1][1] 838 | dmid = a[4][1][1] 839 | #corner orientations if in U layer, first letter means the direction that the color is facing 840 | fCorU = a[1][0][2] == dmid and a[0][2][2] == fmid and a[2][2][0] == rmid 841 | rCorU = a[2][2][0] == dmid and a[1][0][2] == fmid and a[0][2][2] == rmid 842 | uCorU = a[0][2][2] == dmid and a[2][2][0] == fmid and a[1][0][2] == rmid 843 | return fCorU or rCorU or uCorU 844 | 845 | #Returns true if there is an f2l Edge located in the FU position 846 | def f2lFUEdge(): 847 | rmid = a[2][1][1] 848 | fmid = a[1][1][1] 849 | norEdgeFU = a[1][0][1] == fmid and a[0][2][1] == rmid 850 | flipEdgeFU = a[0][2][1] == fmid and a[1][0][1] == rmid 851 | return norEdgeFU or flipEdgeFU 852 | 853 | #returns true if f2l corner is located on the U layer 854 | def f2lCornerOnTop(): 855 | wasFound = False 856 | for i in range(4): #Does 4 U moves to find the corner 857 | if f2lFRCor(): 858 | wasFound = True 859 | m("U") 860 | return wasFound 861 | 862 | #Will return the loction of the corner that belongs in the FR spot. Either returns BR, BL, FL, or FR. 863 | def f2lCornerCheck(): 864 | r = "FR" 865 | count = 0 866 | while count < 4: 867 | if count == 0: 868 | if f2lCornerInserted(): 869 | r = "FR" 870 | elif count == 1: 871 | if f2lCornerInserted(): 872 | r = "FL" 873 | elif count == 2: 874 | if f2lCornerInserted(): 875 | r = "BL" 876 | elif count == 3: 877 | if f2lCornerInserted(): 878 | r = "BR" 879 | m("D") 880 | count += 1 881 | return r 882 | 883 | #Will return the loction of the edge that belongs in the FR spot. 884 | #Either returns BR, BL, FL, or FR. 885 | def f2lEdgeCheck(): 886 | if f2lEdgeInserted2("FL"): 887 | return "FL" 888 | elif f2lEdgeInserted2("BL"): 889 | return "BL" 890 | elif f2lEdgeInserted2("BR"): 891 | return "BR" 892 | elif f2lEdgeInserted2("FR"): 893 | return "FR" 894 | else: 895 | raise Exception("f2lEdgeCheck() Exception") 896 | 897 | #This is for the case where the Edge is inserted, but the corner is not 898 | def f2lEdgeNoCorner(): 899 | topEdgeTop = a[0][2][1] 900 | topEdgeFront = a[1][0][1] 901 | rmid = a[2][1][1] 902 | bmid = a[5][1][1] 903 | lmid = a[3][1][1] 904 | fmid = a[1][1][1] 905 | #This is for comparing the front edge to other various edges for advanced algs/lookahead 906 | BREdge = (topEdgeTop == rmid or topEdgeTop == bmid) and (topEdgeFront == rmid or topEdgeFront == bmid) 907 | BLEdge = (topEdgeTop == lmid or topEdgeTop == bmid) and (topEdgeFront == lmid or topEdgeFront == bmid) 908 | FLEdge = (topEdgeTop == fmid or topEdgeTop == lmid) and (topEdgeFront == fmid or topEdgeFront == lmid) 909 | if f2lCornerOnTop(): 910 | while True: 911 | solveFrontSlot() 912 | if f2lCorrect(): 913 | break 914 | m("U") 915 | else: 916 | if f2lCornerCheck() == "BR": 917 | if BREdge: 918 | m("Ri Ui R U2") 919 | else: 920 | m("Ri U R U") 921 | elif f2lCornerCheck() == "BL": 922 | if BLEdge: 923 | m("L U Li U") 924 | else: 925 | m("L Ui Li U2") 926 | elif f2lCornerCheck() == "FL": 927 | if FLEdge: 928 | m("Li U L Ui") 929 | else: 930 | m("Li Ui L") 931 | solveFrontSlot() 932 | 933 | if not f2lCorrect(): 934 | raise Exception("Exception found in f2lEdgeNoCorner()") 935 | 936 | 937 | #This is the case for if the corner is inserted, but the edge is not 938 | def f2lCornerNoEdge(): 939 | topEdgeTop = a[0][2][1] 940 | topEdgeFront = a[1][0][1] 941 | rmid = a[2][1][1] 942 | bmid = a[5][1][1] 943 | lmid = a[3][1][1] 944 | fmid = a[1][1][1] 945 | #This is for comparing the front edge to other various edges for advanced algs/lookahead 946 | BREdge = (topEdgeTop == rmid or topEdgeTop == bmid) and (topEdgeFront == rmid or topEdgeFront == bmid) 947 | BLEdge = (topEdgeTop == lmid or topEdgeTop == bmid) and (topEdgeFront == lmid or topEdgeFront == bmid) 948 | FLEdge = (topEdgeTop == fmid or topEdgeTop == lmid) and (topEdgeFront == fmid or topEdgeFront == lmid) 949 | if f2lEdgeOnTop(): 950 | while True: 951 | solveFrontSlot() 952 | if f2lCorrect(): 953 | break 954 | m("U") 955 | else: 956 | if f2lEdgeCheck() == "BR": 957 | if BREdge: 958 | m("Ri Ui R U2") 959 | else: 960 | m("Ri U R U") 961 | elif f2lEdgeCheck() == "BL": 962 | if BLEdge: 963 | m("L U Li U") 964 | else: 965 | m("L Ui Li U2") 966 | elif f2lEdgeCheck() == "FL": 967 | if FLEdge: 968 | m("Li U L Ui") 969 | else: 970 | m("Li Ui L") 971 | solveFrontSlot() 972 | 973 | if not f2lCorrect(): 974 | raise Exception("Exception found in f2lCornerNoEdge()") 975 | 976 | #this is the case for if the corner is on top, and the edge is not. Neither are inserted properly. Edge must be in another slot. 977 | def f2lCornerTopNoEdge(): 978 | topEdgeTop = a[0][2][1] 979 | topEdgeFront = a[1][0][1] 980 | rmid = a[2][1][1] 981 | bmid = a[5][1][1] 982 | lmid = a[3][1][1] 983 | fmid = a[1][1][1] 984 | #This is for comparing the front edge to other various edges for advanced algs/lookahead 985 | BREdge = (topEdgeTop == rmid or topEdgeTop == bmid) and (topEdgeFront == rmid or topEdgeFront == bmid) 986 | BLEdge = (topEdgeTop == lmid or topEdgeTop == bmid) and (topEdgeFront == lmid or topEdgeFront == bmid) 987 | FLEdge = (topEdgeTop == fmid or topEdgeTop == lmid) and (topEdgeFront == fmid or topEdgeFront == lmid) 988 | 989 | #Turn the top until the corner on the U face is in the proper position 990 | while True: 991 | if f2lFRCor(): 992 | break 993 | m("U") 994 | #We will be checking additional edges to choose a more fitting alg for the sake of looking ahead 995 | if f2lEdgeCheck() == "BR": 996 | if BREdge: 997 | m("Ri Ui R") 998 | else: 999 | m("Ri U R") 1000 | elif f2lEdgeCheck() == "BL": 1001 | if BLEdge: 1002 | m("U2 L Ui Li") 1003 | else: 1004 | m("L Ui Li U") 1005 | elif f2lEdgeCheck() == "FL": 1006 | if FLEdge: 1007 | m("U2 Li Ui L U2") 1008 | else: 1009 | m("Li Ui L U") 1010 | solveFrontSlot() 1011 | 1012 | if not f2lCorrect(): 1013 | raise Exception("Exception found in f2lCornerTopNoEdge()") 1014 | 1015 | #This is the case for if the edge is on top, and the corner is not. Neither are inserted properly. Corner must be in another slot. 1016 | #The lookahead for this step is comparing the back edge to the slots, rather than the front one like other cases have 1017 | def f2lEdgeTopNoCorner(): 1018 | BackEdgeTop = a[0][0][1] 1019 | BackEdgeBack = a[5][2][1] 1020 | rmid = a[2][1][1] 1021 | bmid = a[5][1][1] 1022 | lmid = a[3][1][1] 1023 | fmid = a[1][1][1] 1024 | rs1 = BackEdgeTop == rmid or BackEdgeTop == bmid 1025 | rs2 = BackEdgeBack == rmid or BackEdgeBack == bmid 1026 | #This is for comparing the back edge to other various edges for advanced algs/lookahead 1027 | BREdge = rs1 and rs2 1028 | BLEdge = (BackEdgeTop == lmid or BackEdgeTop == bmid) and (BackEdgeBack == lmid or BackEdgeBack == bmid) 1029 | FLEdge = (BackEdgeTop == fmid or BackEdgeTop == lmid) and (BackEdgeBack == fmid or BackEdgeBack == lmid) 1030 | 1031 | #Turn the top until the corner on the U face is in the proper position 1032 | while True: 1033 | if f2lFUEdge(): 1034 | break 1035 | m("U") 1036 | #We will be checking additional edges to choose a more fitting alg for the sake of looking ahead 1037 | if f2lCornerCheck() == "BR": 1038 | if BREdge: 1039 | m("Ri U R U") 1040 | else: 1041 | m("Ui Ri U R U") 1042 | elif f2lCornerCheck() == "BL": 1043 | if BLEdge: 1044 | m("L Ui Li U2") 1045 | else: 1046 | m("U2 L U2 Li") 1047 | elif f2lCornerCheck() == "FL": 1048 | if FLEdge: 1049 | m("Li Ui L") 1050 | else: 1051 | m("U Li Ui L") 1052 | solveFrontSlot() 1053 | 1054 | if not f2lCorrect(): 1055 | raise Exception("Exception found in f2lEdgeTopNoCorner()") 1056 | 1057 | 1058 | #This is the case for if the edge or corner are not on top, and not inserted properly. They must both be in other slots. 1059 | def f2lNoEdgeOrCorner(): 1060 | #The strategy here is to first find the corner and get it out. I will place it in the FR position where it belongs 1061 | #I will then check if I have a case, and if we are all solved. 1062 | #If I don't have it solved at this point, I will have to follow what happens in f2lCornerTopNoEdge() 1063 | 1064 | BackEdgeTop = a[0][0][1] 1065 | BackEdgeBack = a[5][2][1] 1066 | rmid = a[2][1][1] 1067 | bmid = a[5][1][1] 1068 | lmid = a[3][1][1] 1069 | fmid = a[1][1][1] 1070 | #This is for comparing the back edge to other various edges for advanced algs/lookahead 1071 | BREdge = (BackEdgeTop == rmid or BackEdgeTop == bmid) and (BackEdgeBack == rmid or BackEdgeBack == bmid) 1072 | BLEdge = (BackEdgeTop == lmid or BackEdgeTop == bmid) and (BackEdgeBack == lmid or BackEdgeBack == bmid) 1073 | FLEdge = (BackEdgeTop == fmid or BackEdgeTop == lmid) and (BackEdgeBack == fmid or BackEdgeBack == lmid) 1074 | 1075 | #We will be checking additional edges to choose a more fitting alg for the sake of looking ahead 1076 | if f2lCornerCheck() == "BR": 1077 | if BREdge: 1078 | m("Ri U R U") 1079 | else: 1080 | m("Ui Ri U R U") 1081 | elif f2lCornerCheck() == "BL": 1082 | if BLEdge: 1083 | m("L Ui Li U2") 1084 | else: 1085 | m("U2 L U2 Li") 1086 | elif f2lCornerCheck() == "FL": 1087 | if FLEdge: 1088 | m("Li Ui L") 1089 | else: 1090 | m("U Li Ui L") 1091 | solveFrontSlot() 1092 | 1093 | if f2lCorrect(): 1094 | return 1095 | else: 1096 | f2lCornerTopNoEdge() 1097 | 1098 | if not f2lCorrect(): 1099 | raise Exception("Exception found in f2lNoEdgeOrCorner()") 1100 | 1101 | #Will return true if the f2l is completed 1102 | def isf2lDone(): 1103 | 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] 1104 | 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] 1105 | 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] 1106 | 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] 1107 | return rside and bside and lside and fside 1108 | 1109 | #f2l will solve the first 2 layers, checks for each case, then does a Y move to check the next 1110 | def f2l(): 1111 | pairsSolved = 0 1112 | uMoves = 0 1113 | while pairsSolved < 4: 1114 | if not f2lCorrect(): 1115 | #while not f2lCorrect(): 1116 | while uMoves < 4: #4 moves before checking rare cases 1117 | solveFrontSlot() 1118 | if f2lCorrect(): 1119 | pairsSolved += 1 1120 | f2l_list.append("Normal Case") 1121 | break 1122 | else: 1123 | f2l_list.append("Scanning") 1124 | uMoves += 1 1125 | m("U") 1126 | if not f2lCorrect(): 1127 | if not f2lCornerInserted() and f2lEdgeInserted(): 1128 | f2l_list.append("Rare case 1") 1129 | f2lEdgeNoCorner() 1130 | pairsSolved += 1 1131 | elif not f2lEdgeInserted() and f2lCornerInserted(): 1132 | f2l_list.append("Rare case 2") 1133 | f2lCornerNoEdge() 1134 | pairsSolved += 1 1135 | #At this point, they can't be inserted, must be in U or other spot 1136 | elif not f2lEdgeOnTop() and f2lCornerOnTop(): 1137 | f2l_list.append("Rare Case 3") 1138 | f2lCornerTopNoEdge() 1139 | pairsSolved += 1 1140 | elif f2lEdgeOnTop() and not f2lCornerOnTop(): 1141 | f2l_list.append("Rare Case 4") 1142 | f2lEdgeTopNoCorner() 1143 | solveFrontSlot() 1144 | pairsSolved += 1 1145 | elif not f2lEdgeOnTop() and not f2lCornerOnTop(): 1146 | f2l_list.append("Rare Case 5") 1147 | f2lNoEdgeOrCorner() 1148 | pairsSolved += 1 1149 | else: 1150 | raise Exception("f2l Impossible Case Exception") 1151 | else: 1152 | pairsSolved += 1 1153 | f2l_list.append("We have ") 1154 | f2l_list.append(str(pairsSolved)) 1155 | uMoves = 0 1156 | m("Y") 1157 | assert(isf2lDone()) 1158 | 1159 | 1160 | def fish(): 1161 | return [a[0][0][0], a[0][0][2], a[0][2][0], a[0][2][2]].count(a[0][1][1]) == 1 1162 | 1163 | def sune(): 1164 | m("R U Ri U R U2 Ri") 1165 | 1166 | def antisune(): 1167 | m("R U2 Ri Ui R Ui Ri") 1168 | 1169 | def getfish(): 1170 | for i in range(4): 1171 | if fish(): 1172 | return 1173 | sune() 1174 | if fish(): 1175 | return 1176 | antisune() 1177 | m("U") 1178 | assert fish() 1179 | 1180 | def bOLL(): 1181 | getfish() 1182 | if fish(): 1183 | while a[0][0][2] != a[0][1][1]: 1184 | m("U") 1185 | if a[1][0][0] == a[0][1][1]: 1186 | antisune() 1187 | elif a[5][2][0] == a[0][1][1]: 1188 | m("U2"); sune(); 1189 | else: 1190 | raise Exception("Something went wrong") 1191 | else: 1192 | raise Exception("Fish not set up") 1193 | assert isTopSolved() 1194 | 1195 | def getCornerState(): 1196 | corner0 = a[1][0][0] == a[1][1][1] and a[3][2][2] == a[3][1][1] 1197 | corner1 = a[1][0][2] == a[1][1][1] and a[2][2][0] == a[2][1][1] 1198 | corner2 = a[5][2][2] == a[5][1][1] and a[2][0][0] == a[2][1][1] 1199 | corner3 = a[5][2][0] == a[5][1][1] and a[3][0][2] == a[3][1][1] 1200 | return [corner0, corner1, corner2, corner3] 1201 | 1202 | #Does permutation of the top layer corners, orients them properly 1203 | def permuteCorners(): 1204 | for i in range(2): 1205 | for j in range(4): 1206 | num = getCornerState().count(True) 1207 | if num == 4: 1208 | return 1209 | if num == 1: 1210 | index = getCornerState().index(True) 1211 | for k in range(index): 1212 | m("Y") 1213 | if a[1][0][2] == a[2][1][1]: 1214 | m("R2 B2 R F Ri B2 R Fi R") 1215 | else: 1216 | m("Ri F Ri B2 R Fi Ri B2 R2") 1217 | for f in range(index): 1218 | m("Yi") 1219 | return 1220 | m("U") 1221 | m("R2 B2 R F Ri B2 R Fi R") 1222 | 1223 | #Does permutation of the top layer edges, must be H, Z or U perms after orientation 1224 | def permuteEdges(): 1225 | if all(getEdgeState()): 1226 | return 1227 | if a[1][0][1] == a[5][1][1] and a[5][2][1] == a[1][1][1]: #H perm 1228 | m("R2 U2 R U2 R2 U2 R2 U2 R U2 R2") 1229 | elif a[1][0][1] == a[2][1][1] and a[2][1][0] == a[1][1][1]: #Normal Z perm 1230 | m("U Ri Ui R Ui R U R Ui Ri U R U R2 Ui Ri U") 1231 | elif a[1][0][1] == a[3][1][1] and a[3][1][2] == a[1][1][1]: # Not oriented Z perm 1232 | m("Ri Ui R Ui R U R Ui Ri U R U R2 Ui Ri U2") 1233 | else: 1234 | uNum = 0 1235 | while True: 1236 | if a[5][2][0] == a[5][2][1] == a[5][2][2]: #solid bar is on back then 1237 | if a[3][1][2] == a[1][0][0]: #means we have to do counterclockwise cycle 1238 | m("R Ui R U R U R Ui Ri Ui R2") 1239 | break 1240 | else: 1241 | m("R2 U R U Ri Ui Ri Ui Ri U Ri") 1242 | break 1243 | else: 1244 | m("U") 1245 | uNum += 1 1246 | for x in range(uNum): 1247 | m("Ui") 1248 | 1249 | def getEdgeState(): 1250 | fEdge = a[1][0][1] == a[1][1][1] 1251 | rEdge = a[2][1][0] == a[2][1][1] 1252 | bEdge = a[5][2][1] == a[5][1][1] 1253 | lEdge = a[3][1][2] == a[3][1][1] 1254 | return [fEdge, rEdge, bEdge, lEdge] 1255 | 1256 | def topCorners(): 1257 | permuteCorners() 1258 | assert all(getCornerState()) 1259 | 1260 | def topEdges(): 1261 | permuteEdges() 1262 | assert all(getEdgeState()) 1263 | 1264 | def bPLL(): 1265 | topCorners() 1266 | topEdges() 1267 | 1268 | def isSolved(): 1269 | 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] 1270 | 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] 1271 | 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] 1272 | 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] 1273 | 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] 1274 | 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] 1275 | return uside and fside and rside and lside and dside and bside 1276 | 1277 | def solve(): 1278 | cross() 1279 | simplify_moves() 1280 | step_moves_list[0] = solution_length 1281 | f2l() 1282 | simplify_moves() 1283 | step_moves_list[1] = solution_length - step_moves_list[0] 1284 | topCross() 1285 | getfish() 1286 | bOLL() 1287 | simplify_moves() 1288 | step_moves_list[2] = solution_length - step_moves_list[1] - step_moves_list[0] 1289 | bPLL() 1290 | simplify_moves() 1291 | step_moves_list[3] = solution_length - step_moves_list[2] - step_moves_list[1] - step_moves_list[0] 1292 | assert(isSolved()) 1293 | 1294 | #Performs solve simulations, will return a list with the number of moves, which one was the best 1295 | # and the scramble used to get the best. The worst, which one was the worst, and the scramble 1296 | # used to get the worst. scimNum is the number of simulations to perform, it is an IntVar() 1297 | def simulation(simNum): 1298 | global a 1299 | bestScram = [] 1300 | worstScram = [] 1301 | best = 200 1302 | worst = 0 1303 | Bestnumber = 0 1304 | WorstNumber = 0 1305 | if simNum.get() >= 50000: 1306 | print("Don't do over 50,000 solves at once") 1307 | return 1308 | for i in range(simNum.get()): 1309 | a = make_cube() 1310 | step_moves_list = [0,0,0,0] 1311 | f2l_list = [] 1312 | moves_list = [] 1313 | last_scramble=[] 1314 | scramble(25) 1315 | solve() 1316 | simplify_moves() 1317 | if solution_length < best: 1318 | best = solution_length 1319 | bestScram = get_scramble() 1320 | BestNumber = i 1321 | if solution_length > worst: 1322 | worst = solution_length 1323 | worstScram = get_scramble() 1324 | WorstNumber = i 1325 | return [best, BestNumber, bestScram, worst, WorstNumber, worstScram] 1326 | 1327 | 1328 | 1329 | ###################################################################################################### 1330 | #Below is all the work for the GUI portion of the Cube Solver 1331 | ###################################################################################################### 1332 | #These are all the globals used for the GUI 1333 | root = None 1334 | frame = None 1335 | canvas = None 1336 | ScrambleLabel = None 1337 | SolutionLabel = None 1338 | SolutionNumberLabel = None 1339 | isTransparent = None 1340 | F2LNumberLabel = None 1341 | CrossNumberLabel = None 1342 | OLLNumberLabel = None 1343 | PLLNumberLabel = None 1344 | SimulateBestLabel = None 1345 | SimulateWorstLabel = None 1346 | 1347 | #cubePoints are all of the x and y coordinates for the polygons used for the tiles 1348 | def cubePoints(): 1349 | #h and w may be changed to allow the cube to be moved around the screen 1350 | h = 125 1351 | w = 115 1352 | #right face 1353 | #layer 1 1354 | r00p = [0+w, 0+h, 0+w, 50+h, 33+w, 30+h, 33+w, -20+h] 1355 | r01p = [33+w, -20+h, 33+w, 30+h, 66+w, 10+h, 66+w, -40+h] 1356 | r02p = [66+w, -40+h, 66+w, 10+h, 99+w, -10+h, 99+w, -60+h] 1357 | #layer 2 1358 | r10p = [0+w, 50+h, 0+w, 100+h, 33+w, 80+h, 33+w, 30+h] 1359 | r11p = [33+w, 30+h, 33+w, 80+h, 66+w, 60+h, 66+w, 10+h] 1360 | r12p = [66+w, 10+h, 66+w, 60+h, 99+w, 40+h, 99+w, -10+h] 1361 | #layer 3 1362 | r20p = [0+w, 100+h, 0+w, 150+h, 33+w, 130+h, 33+w, 80+h] 1363 | r21p = [33+w, 80+h, 33+w, 130+h, 66+w, 110+h, 66+w, 60+h] 1364 | r22p = [66+w, 60+h, 66+w, 110+h, 99+w, 90+h, 99+w, 40+h] 1365 | #left face (left face will be front face, however called l face to distinguish between the left and right) 1366 | #layer 1 1367 | l00p = [-66+w, -40+h, -66+w, 10+h, -99+w, -10+h, -99+w, -60+h] 1368 | l01p = [-33+w, -20+h, -33+w, 30+h, -66+w, 10+h, -66+w, -40+h] 1369 | l02p = [0+w, 0+h, 0+w, 50+h, -33+w, 30+h, -33+w, -20+h] 1370 | #layer 2 1371 | l10p = [-66+w, 10+h, -66+w, 60+h, -99+w, 40+h, -99+w, -10+h] 1372 | l11p = [-33+w, 30+h, -33+w, 80+h, -66+w, 60+h, -66+w, 10+h] 1373 | l12p = [0+w, 50+h, 0+w, 100+h, -33+w, 80+h, -33+w, 30+h] 1374 | #layer 3 1375 | l20p = [-66+w, 60+h, -66+w, 110+h, -99+w, 90+h, -99+w, 40+h] 1376 | l21p = [-33+w, 80+h, -33+w, 130+h, -66+w, 110+h, -66+w, 60+h] 1377 | l22p = [0+w, 100+h, 0+w, 150+h, -33+w, 130+h, -33+w, 80+h] 1378 | #up face 1379 | #layer 1 1380 | u00p = [0+w, -75+h, -33+w, -94+h, 0+w, -111+h, 33+w, -94+h] 1381 | u01p = [36+w, -57+h, 0+w, -75+h, 33+w, -94+h, 69+w, -76+h] 1382 | u02p = [66+w, -40+h, 36+w, -57+h, 69+w, -76+h, 99+w, -60+h] 1383 | #layer 2 1384 | u10p = [-33+w, -57+h, -66+w, -77+h, -33+w, -94+h, 0+w, -75+h] 1385 | u11p = [0+w, -38+h, -33+w, -57+h, 0+w, -75+h, 36+w, -57+h] 1386 | u12p = [33+w, -20+h, 0+w, -38+h, 36+w, -57+h, 66+w, -40+h] 1387 | #layer 3 1388 | u20p = [-66+w, -40+h, -99+w, -60+h, -66+w, -77+h, -33+w, -57+h] 1389 | u21p = [-33+w, -20+h, -66+w, -40+h, -33+w, -57+h, 0+w, -38+h] 1390 | u22p = [0+w, 0+h, -33+w, -20+h, 0+w, -38+h, 33+w, -20+h] 1391 | 1392 | dh = h + 200 1393 | dw = w 1394 | #d face 1395 | #layer 1 1396 | d00p = [0+dw, -75+dh, -33+dw, -94+dh, 0+dw, -111+dh, 33+dw, -94+dh] 1397 | d01p = [36+dw, -57+dh, 0+dw, -75+dh, 33+dw, -94+dh, 69+dw, -76+dh] 1398 | d02p = [66+dw, -40+dh, 36+dw, -57+dh, 69+dw, -76+dh, 99+dw, -60+dh] 1399 | #layer 2 1400 | d10p = [-33+dw, -57+dh, -66+dw, -77+dh, -33+dw, -94+dh, 0+dw, -75+dh] 1401 | d11p = [0+dw, -38+dh, -33+dw, -57+dh, 0+dw, -75+dh, 36+dw, -57+dh] 1402 | d12p = [33+dw, -20+dh, 0+dw, -38+dh, 36+dw, -57+dh, 66+dw, -40+dh] 1403 | #layer 3 1404 | d20p = [-66+dw, -40+dh, -99+dw, -60+dh, -66+dw, -77+dh, -33+dw, -57+dh] 1405 | d21p = [-33+dw, -20+dh, -66+dw, -40+dh, -33+dw, -57+dh, 0+dw, -38+dh] 1406 | d22p = [0+dw, 0+dh, -33+dw, -20+dh, 0+dw, -38+dh, 33+dw, -20+dh] 1407 | 1408 | return [ [[u00p, u01p, u02p], 1409 | [u10p, u11p, u12p], 1410 | [u20p, u21p, u22p]], #Upside 1411 | 1412 | [[l00p, l01p, l02p], 1413 | [l10p, l11p, l12p], 1414 | [l20p, l21p, l22p]], #front face (used l to denote the left showing face) 1415 | 1416 | [[r02p, r12p, r22p], 1417 | [r01p, r11p, r21p], 1418 | [r00p, r10p, r20p]], # right face (different than other faces because it is formatted differently) 1419 | 1420 | [[d20p, d21p, d22p], 1421 | [d10p, d11p, d12p], 1422 | [d00p, d01p, d02p]]] #downside 1423 | 1424 | def clickCanvas(canvas): 1425 | global isTransparent 1426 | isTransparent = not isTransparent 1427 | canvas.delete(ALL) 1428 | drawCube() 1429 | 1430 | 1431 | #DrawCanvas will take the root and draw a new canvas, also returning it. 1432 | def drawCanvas(root): 1433 | canvas=tk.Canvas(root, width=225, height=330, background='white') 1434 | canvas.grid(row=0,column=0) 1435 | canvas.bind("", lambda e: clickCanvas(canvas)) 1436 | return canvas 1437 | 1438 | #Used to get the word for each color, used in drawCube(canvas() 1439 | def getColor(element): 1440 | if element == 'B': 1441 | return "#06F" #Nice shade of blue 1442 | elif element == 'W': 1443 | return "white" 1444 | elif element == 'G': 1445 | return "green" 1446 | elif element == 'Y': 1447 | return "yellow" 1448 | elif element == 'O': 1449 | return "orange" 1450 | elif element == 'R': 1451 | return "#D11" 1452 | 1453 | #drawCube() will take the already created canvas and draw the cube with polygons whose points are defined in cubePoints() 1454 | def drawCube(): 1455 | global isTransparent, canvas 1456 | pts = cubePoints() 1457 | for j in range(3): 1458 | for k in range(3): 1459 | canvas.create_polygon(pts[3][j][k], fill=getColor(a[4][j][k]), outline="#000", width=2) 1460 | for i in range(3): 1461 | for j in range(3): 1462 | for k in range(3): 1463 | if isTransparent: 1464 | frontTiles = (i == 1) and ((j == 1 and k == 2) or (j == 2 and k == 2) or (j == 2 and k == 1)) 1465 | rightTiles = (i == 2) and ((j == 1 and k == 2) or (j == 2 and k == 2) or (j == 2 and k == 1)) 1466 | if frontTiles or rightTiles: 1467 | canvas.create_polygon(pts[i][j][k], fill="", outline="#000", width=2) 1468 | else: 1469 | canvas.create_polygon(pts[i][j][k], fill=getColor(a[i][j][k]), outline="#000", width=2) 1470 | else: 1471 | canvas.create_polygon(pts[i][j][k], fill=getColor(a[i][j][k]), outline="#000", width=2) 1472 | 1473 | # Used to create a new instance of a cube to be solved, changes scramble and solution labels as well 1474 | def GUInewCube(): 1475 | global canvas, ScrambleLabel, SolutionLabel, SolutionNumberLabel, a, step_moves_list 1476 | global PLLNumberLabel,F2LNumberLabel, CrossNumberLabel,OLLNumberLabel, f2l_list, moves_list 1477 | step_moves_list = [0,0,0,0] 1478 | a = make_cube() 1479 | f2l_list = [] 1480 | moves_list = [] 1481 | ScrambleLabel.configure(text="Scramble will be displayed here") 1482 | SolutionLabel.configure(text="Solution will be displayed here") 1483 | SolutionNumberLabel.configure(text=0) 1484 | CrossNumberLabel.configure(text=step_moves_list[0]) 1485 | F2LNumberLabel.configure(text=step_moves_list[1]) 1486 | OLLNumberLabel.configure(text=step_moves_list[2]) 1487 | PLLNumberLabel.configure(text=step_moves_list[3]) 1488 | canvas.delete(ALL) 1489 | drawCube() 1490 | 1491 | #GUImakeMove is used to make moves based on what is in the EntryBox. After clicking Draw, it will redraw the canvas with the updated cube 1492 | def GUImakeMove(move): 1493 | global canvas 1494 | if move.get() == "": 1495 | return 1496 | m(move.get()) 1497 | canvas.delete(ALL) 1498 | drawCube() 1499 | 1500 | #GUIScramble will do a scramble of 25 on the cube, then update the canvas with the new cube 1501 | def GUIScramble(): 1502 | global ScrambleLabel, canvas 1503 | scramble(25) 1504 | ScrambleLabel.configure(text=get_scramble()) 1505 | canvas.delete(ALL) 1506 | drawCube() 1507 | 1508 | #Used to allow user to enter in their own scramble in the Entry, will display scramble in scramble label as well 1509 | def GUIcustomScramble(scram): 1510 | global ScrambleLabel, canvas 1511 | if scram.get() == "": 1512 | ScrambleLabel.configure(text="Scramble will be displayed here") 1513 | return 1514 | scramble(scram.get()) 1515 | ScrambleLabel.configure(text=get_scramble()) 1516 | canvas.delete(ALL) 1517 | drawCube() 1518 | 1519 | #GUISolve will wolve the cube using the solve function, then update the canvas with the new, solved, cube 1520 | def GUISolve(): 1521 | global canvas, SolutionLabel, SolutionNumberLabel, step_moves_list 1522 | global PLLNumberLabel,F2LNumberLabel, CrossNumberLabel,OLLNumberLabel 1523 | solve() 1524 | SolutionLabel.configure(text=get_moves()) 1525 | SolutionNumberLabel.configure(text=solution_length) 1526 | CrossNumberLabel.configure(text=step_moves_list[0]) 1527 | F2LNumberLabel.configure(text=step_moves_list[1]) 1528 | OLLNumberLabel.configure(text=step_moves_list[2]) 1529 | PLLNumberLabel.configure(text=step_moves_list[3]) 1530 | canvas.delete(ALL) 1531 | drawCube() 1532 | 1533 | # This will allow the user to go through the solve one step at a time, the parameter step should be 1534 | #either cross, f2l, OLL, or PLL. Depending on it, it will do a different step 1535 | def GUIsetSolve(step): 1536 | global SolutionLabel, SolutionNumberLabel, canvas, step_moves_list 1537 | global PLLNumberLabel,F2LNumberLabel, CrossNumberLabel,OLLNumberLabel 1538 | if step == "cross": 1539 | cross() 1540 | simplify_moves() 1541 | step_moves_list[0] = solution_length 1542 | elif step == "f2l" or step == "F2L": 1543 | f2l() 1544 | simplify_moves() 1545 | step_moves_list[1] = solution_length - step_moves_list[0] 1546 | elif step == "OLL": 1547 | topCross() 1548 | getfish 1549 | bOLL() 1550 | simplify_moves() 1551 | step_moves_list[2] = solution_length - step_moves_list[1] - step_moves_list[0] 1552 | elif step == "PLL": 1553 | bPLL() 1554 | simplify_moves() 1555 | step_moves_list[3] = solution_length - step_moves_list[2] - step_moves_list[1] - step_moves_list[0] 1556 | assert(isSolved()) 1557 | 1558 | SolutionLabel.configure(text=get_moves()) 1559 | SolutionNumberLabel.configure(text=solution_length) 1560 | CrossNumberLabel.configure(text=step_moves_list[0]) 1561 | F2LNumberLabel.configure(text=step_moves_list[1]) 1562 | OLLNumberLabel.configure(text=step_moves_list[2]) 1563 | PLLNumberLabel.configure(text=step_moves_list[3]) 1564 | canvas.delete(ALL) 1565 | drawCube() 1566 | 1567 | #This is used to copy the given string to the users clipboard 1568 | def GUItoClipboard(word): 1569 | r = Tk() 1570 | r.withdraw() 1571 | r.clipboard_clear() 1572 | r.clipboard_append(word) 1573 | r.destroy() 1574 | ''' 1575 | This was the attempt at using a timer to automate a solve, to use, be sure to reactivate the button and import time 1576 | #This is used to the a slow, but automatic solve. It uses the timer features to do a couple moves per second or so 1577 | def GUIautomateSolve(): 1578 | global canvas, a 1579 | b = copy.deepcopy(a) 1580 | solve() 1581 | simplify_moves() 1582 | a = b 1583 | for i in moves_list: 1584 | move(i) 1585 | canvas.after(200, drawCube()) 1586 | ''' 1587 | 1588 | #This is used to export the solve and solution to alg.cubing.net. It will check if it can open with 1589 | #Google Chrome, if it can't, it will try firefox, otherwise it will use the default web browser on the system 1590 | def GUIexportSolve(): 1591 | sCopy = copy.deepcopy(get_scramble()) 1592 | mCopy = copy.deepcopy(get_moves()) 1593 | 1594 | sCopy = str.replace(sCopy, "'", "-") 1595 | sCopy = str.replace(sCopy, " ", "_") 1596 | mCopy = str.replace(mCopy, "'", "-") 1597 | mCopy = str.replace(mCopy, " ", "_") 1598 | 1599 | url = "alg.cubing.net/?setup=" + sCopy + "&alg=" + mCopy 1600 | chrome_path = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe" 1601 | firefox_path = "C:/Program Files/Mozilla Firefox/Firefox.exe" 1602 | if os.path.exists(chrome_path): 1603 | webbrowser.get(chrome_path + " %s").open(url) 1604 | elif os.path.exists(firefox_path): 1605 | webbrowser.get(firefox_path + " %s").open(url) 1606 | else: 1607 | webbrowser.open_new(url) 1608 | 1609 | #This is used for the rotation of the cube with buttons. It takes in either a Yi or Y move to be executed 1610 | def GUIyRotation(given): 1611 | global canvas 1612 | if given == "Y" or given == "y": 1613 | move('y') 1614 | elif given == "Yi" or given == "Y'" or given == "yi" or given == "y'": 1615 | move('yi') 1616 | canvas.delete(ALL) 1617 | drawCube() 1618 | 1619 | #This will create a new Information GUI, after it is closed, the main GUI() is ran 1620 | def InfoGUI(): 1621 | rt = tk.Tk() 1622 | rt.geometry("550x135+50+50") #size of the starting frame 1623 | rt.wm_title("Cube Solver Info") 1624 | rt.resizable(False, True) #Only allows the height to be resized, not the width 1625 | InfoGUIy(rt) 1626 | rt.mainloop() 1627 | GUI() 1628 | 1629 | #This will be called within InfoGUI(), it will create a nice GUI with instructions 1630 | def InfoGUIy(rt): 1631 | frame = Frame(rt) 1632 | frame.grid(row=0,column=0) 1633 | wel = "\t\t\tWelcome to the cube solver, here are some features:" 1634 | instruct1 = "* Enter in your own moves, then click 'execute' to execute them" 1635 | instruct2 = "* Click scramble to generate a scramble, or make your own and select 'custom scramble'" 1636 | instruct3 = "* Click the two solve buttons to solve, or solve it step by step with the blue buttons" 1637 | instruct4 = "* You can copy the scramble or solution to the clipboard, or export to alg.cubing.net for viewing" 1638 | instruct5 = "* Run some simulations by entering the number of scrambles to simulate" 1639 | InfoLabel = Label(frame, text=wel +"\n"+instruct1+"\n"+instruct2+"\n"+instruct3+"\n"+instruct4+"\n"+instruct5, justify=LEFT) 1640 | InfoLabel.grid(row=0, column=0) 1641 | InfoQuitButton = Button(frame,text="Start Cubing", fg="red",command=lambda: rt.destroy()) 1642 | InfoQuitButton.grid(row=1,column=0) 1643 | 1644 | #This is used to run simulations, uses the simulation function. this is the GUI portion of the simulations 1645 | def GUISimulation(simNum): 1646 | global SimulateBestLabel, SimulateWorstLabel 1647 | simResults = simulation(simNum) 1648 | s = StringVar(value=simResults[2]) 1649 | GUIcustomScramble(s) 1650 | GUISolve() 1651 | SimulateBestLabel.configure(text = str(simResults[1] + 1) + " out of " + str(simNum.get()) + " with " + str(solution_length) + " moves") 1652 | SimulateWorstLabel.configure(text = str(simResults[4] +1) + " out of " + str(simNum.get()) + " with " + str(simResults[3]) + " moves") 1653 | 1654 | #GUI is the main GUI that will be created, it calls GUIy which actually does all the work for the GUI 1655 | def GUI(): 1656 | global root 1657 | root = tk.Tk() 1658 | root.geometry("550x550+50+50") #size of the starting frame 1659 | root.wm_title("Cube Solver") 1660 | root.resizable(True, True) #Only allows the height to be resized, not the width 1661 | GUIy() 1662 | root.mainloop() 1663 | 1664 | #GUIy, after the GUI itself is created with GUI(), this will create all the buttons, labels, etc.. and add them into a frame. This is the behind the 1665 | #scenes work for the GUI itself. 1666 | def GUIy(): 1667 | global root, canvas, ScrambleLabel, SolutionLabel, SolutionNumberLabel, frame,isTransparent 1668 | global PLLNumberLabel,F2LNumberLabel, CrossNumberLabel,OLLNumberLabel, SimulateBestLabel, SimulateWorstLabel 1669 | 1670 | isTransparent = False 1671 | canvas = drawCanvas(root) 1672 | drawCube() 1673 | 1674 | #locals 1675 | move = StringVar(value="") 1676 | scram = StringVar(value="Enter Scramble Here") 1677 | simNum = IntVar()#Simulation Number 1678 | 1679 | #Frame for controls 1680 | frame = Frame(root) 1681 | frame.grid(row=0,column=1, sticky="n") 1682 | 1683 | #Frame for cube rotations 1684 | Rframe = Frame(root) 1685 | Rframe.grid(row=0, column=0, sticky = "n") 1686 | 1687 | #row 1 - welcome label and new cube button 1688 | Welcome = Label(frame, text = "Welcome to the Cube Solver").grid(row=1,column=0) 1689 | NewCubeButton = Button(frame,text="New Cube", command = lambda: GUInewCube()) 1690 | NewCubeButton.grid(row=1, column=1) 1691 | #row 2 - label to tell you to enter a move for execution 1692 | EnterMove = Label(frame, text ="Enter move(s):").grid(row=2,column=0) 1693 | #row 3 - Has entry for custom moves as well as button to execute them 1694 | MoveEntry = Entry(frame, textvariable=move).grid(row = 3, column=0) 1695 | DrawCubeButton=Button(frame,text="Execute", command = lambda: GUImakeMove(move)).grid(row = 3,column = 1, sticky="w") 1696 | #row 4 - The label that will print out the current scramble after generation 1697 | ScrambleLabel = Label(frame, text="Scramble will be displayed here",wraplength=180, justify=CENTER, height = 2) 1698 | ScrambleLabel.grid(row=4,column=0, columnspan=2) 1699 | #row 5 - The scramble button to generate new scramble and copy scramble to clipboard 1700 | ScrambleButton = Button(frame, text="Scramble",bg="lightgreen", command = lambda: GUIScramble()).grid(row = 5, column = 0) 1701 | CopyScrambleButton = Button(frame, text="Copy Scramble",bg="#EF9", command = lambda: GUItoClipboard(get_scramble())).grid(row = 5, column = 1) 1702 | #row 6 - entry for custom scramble and button to apply custom scramble to cube 1703 | CustomScramEntry = Entry(frame, textvariable=scram) 1704 | CustomScramEntry.grid(row=6,column=0,sticky="w") 1705 | CustomScramButton = Button(frame,text="Custom Scramble",bg="lightgreen", command = lambda: GUIcustomScramble(scram)) 1706 | CustomScramButton.grid(row=6,column=1) 1707 | #row 7 - Slow solve (using timer to do it slowly), instant solve(quick and instant solution), copy solution to clipboard buttons 1708 | #SolveTimerButton = Button(frame, text="Slow Solve", bg="#D53", command = lambda: GUIautomateSolve()).grid(row=7, column=0, sticky="w", pady=5) 1709 | SolveButton = Button(frame, text="Solve Cube",bg="#D53",command = lambda: GUISolve()).grid(row = 7, column = 0) #sticky="e" if using timer button as well 1710 | CopyScrambleButton = Button(frame, text="Copy Solution",bg="#EF9", command = lambda: GUItoClipboard(get_moves())).grid(row = 7, column = 1) 1711 | #row 8 -Solve buttons to do steps independantly 1712 | CrossButton = Button(frame, text="Cross",bg="lightblue", command = lambda: GUIsetSolve("cross")) 1713 | CrossButton.grid(row=8, column=0) 1714 | F2LButton = Button(frame, text="F2l",bg="lightblue", command = lambda: GUIsetSolve("F2L")) 1715 | F2LButton.grid(row=8, column=0, sticky="e", padx= 15) 1716 | OLLButton = Button(frame, text="OLL",bg="lightblue", command = lambda: GUIsetSolve("OLL")) 1717 | OLLButton.grid(row=8, column=1, sticky = "w") 1718 | PLLButton = Button(frame, text="PLL",bg="lightblue", command = lambda: GUIsetSolve("PLL")) 1719 | PLLButton.grid(row=8, column=1, sticky = "e", padx=30) 1720 | #row 9 - the label that contains the solution that will be generated 1721 | SolutionLabel = Label(frame, text="Solution will be displayed here", wraplength = 250, justify=CENTER, height = 8) 1722 | SolutionLabel.grid(row=9, column=0, columnspan=2) 1723 | #row 10 - Labels for number of moves needed to solve 1724 | SolutionNumberInfoLabel = Label(frame, text="Total number of moves used:") 1725 | SolutionNumberInfoLabel.grid(row=10, column=0,sticky="e") 1726 | SolutionNumberLabel = Label(frame, text="0") 1727 | SolutionNumberLabel.grid(row=10, column=1,sticky="w") 1728 | #row 11, 12, 13, 14 - Labels for number of moves for the different steps 1729 | CrossInfoLabel = Label(frame, text="Moves needed for Cross:") 1730 | CrossInfoLabel.grid(row=11,column=0,sticky="e") 1731 | CrossNumberLabel = Label(frame,text="0") 1732 | CrossNumberLabel.grid(row=11, column=1,sticky="w") 1733 | F2LInfoLabel = Label(frame, text= "Moves needed for F2L:") 1734 | F2LInfoLabel.grid(row = 12, column=0,sticky="e") 1735 | F2LNumberLabel = Label(frame,text="0") 1736 | F2LNumberLabel.grid(row=12, column=1,sticky="w") 1737 | OLLInfoLabel = Label(frame,text="Moves needed for OLL:") 1738 | OLLInfoLabel.grid(row=13, column=0,sticky="e") 1739 | OLLNumberLabel = Label(frame,text="0") 1740 | OLLNumberLabel.grid(row=13, column=1,sticky="w") 1741 | PLLInfoLabel = Label(frame,text="Moves needed for PLL:") 1742 | PLLInfoLabel.grid(row=14, column=0,sticky="e") 1743 | PLLNumberLabel = Label(frame, text="0") 1744 | PLLNumberLabel.grid(row=14, column=1,sticky="w") 1745 | #row 15 - Exporting to alg.cubing.net 1746 | ExportSolveButton = Button(frame, text="Export to alg.cubing.net", command = lambda: GUIexportSolve()) 1747 | ExportSolveButton.grid(row=15,column=0) 1748 | #row 16 - Simulations for Best solve 1749 | SimulateEntry = Entry(frame, textvariable = simNum) 1750 | SimulateEntry.grid(row=16, column=0) 1751 | SimulateButton = Button(frame, text="Start Simulations", command = lambda: GUISimulation(simNum)) 1752 | SimulateButton.grid(row=16,column=1) 1753 | #row 17 - Which best was found 1754 | SimulateBestInfo = Label(frame, text="Best Simulation: ") 1755 | SimulateBestInfo.grid(row=17,column=0) 1756 | SimulateBestLabel = Label(frame,text="") 1757 | SimulateBestLabel.grid(row=17,column=1,sticky="w") 1758 | #row 18 Which worst was found 1759 | SimulateWorstInfo = Label(frame, text="Worst Simulation: ") 1760 | SimulateWorstInfo.grid(row=18, column=0) 1761 | SimulateWorstLabel = Label(frame,text="") 1762 | SimulateWorstLabel.grid(row=18, column=1) 1763 | 1764 | #In Rframe, buttons for rotation 1765 | RotationLabel = Label(Rframe,text="Use the buttons below to rotate the cube").grid(row=0,column=0, columnspan=2) 1766 | YrotationButton = Button(Rframe, text="<---- Y", command = lambda: GUIyRotation("Y")) 1767 | YrotationButton.grid(row=1, column=0) 1768 | YirotationButton = Button(Rframe, text="Y' ---->", command = lambda: GUIyRotation("Yi")) 1769 | YirotationButton.grid(row=1, column=1) 1770 | 1771 | InfoGUI() 1772 | --------------------------------------------------------------------------------