├── 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 |
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 |
--------------------------------------------------------------------------------