(FORKED) Rubiks Cube solver for NxNxN cubes https://github.com/dwalton76/rubiks-cube-NxNxN-solver
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5206 lines
190 KiB

7 years ago
from copy import copy
from collections import OrderedDict
from pprint import pformat
from rubikscubennnsolver.RubiksSide import Side, SolveError, StuckInALoop, ImplementThis
import itertools
7 years ago
import json
import logging
import math
import os
import random
import re
import shutil
import subprocess
import sys
log = logging.getLogger(__name__)
class InvalidCubeReduction(Exception):
pass
def reverse_steps(steps):
"""
Reverse the order of all steps and the direction of each individual step
"""
results = []
for step in reversed(steps):
if step.endswith("'"):
reverse_step = step[0:-1]
else:
reverse_step = step + "'"
results.append(reverse_step)
return results
7 years ago
def get_cube_layout(size):
"""
Example: size is 3, return the following string:
01 02 03
04 05 06
07 08 09
10 11 12 19 20 21 28 29 30 37 38 39
13 14 15 22 23 24 31 32 33 40 41 42
16 17 18 25 26 27 34 35 36 43 44 45
46 47 48
49 50 51
52 53 54
"""
result = []
squares = (size * size) * 6
square_index = 1
if squares >= 1000:
digits_size = 4
digits_format = "%04d "
elif squares >= 100:
digits_size = 3
digits_format = "%03d "
else:
digits_size = 2
digits_format = "%02d "
indent = ((digits_size * size) + size + 1) * ' '
rows = size * 3
for row in range(1, rows + 1):
7 years ago
line = []
if row <= size:
line.append(indent)
for col in range(1, size + 1):
7 years ago
line.append(digits_format % square_index)
square_index += 1
elif row > rows - size:
line.append(indent)
for col in range(1, size + 1):
7 years ago
line.append(digits_format % square_index)
square_index += 1
else:
init_square_index = square_index
last_col = size * 4
for col in range(1, last_col + 1):
7 years ago
line.append(digits_format % square_index)
if col == last_col:
square_index += 1
elif col % size == 0:
square_index += (size * size) - size + 1
line.append(' ')
else:
square_index += 1
if row % size:
square_index = init_square_index + size
result.append(''.join(line))
if row == size or row == rows - size:
result.append('')
return '\n'.join(result)
def rotate_2d_list(squares_list):
"""
http://stackoverflow.com/questions/8421337/rotating-a-two-dimensional-array-in-python
"""
return [x for x in zip(*squares_list[::-1])]
def rotate_clockwise(squares_list):
return rotate_2d_list(squares_list)
def rotate_counter_clockwise(squares_list):
squares_list = rotate_2d_list(squares_list)
squares_list = rotate_2d_list(squares_list)
squares_list = rotate_2d_list(squares_list)
return squares_list
def compress_2d_list(squares_list):
"""
Convert 2d list to a 1d list
"""
return [col for row in squares_list for col in row]
def find_index_for_value(list_foo, target, min_index):
for (index, value) in enumerate(list_foo):
if value == target and index >= min_index:
return index
raise SolveError("Did not find %s in list %s" % (target, pformat(list_foo)))
def get_swap_count(listA, listB, debug):
"""
How many swaps do we have to make in listB for it to match listA
Example:
A = [1, 2, 3, 0, 4]
B = [3, 4, 1, 0, 2]
would require 2 swaps
"""
A_length = len(listA)
B_length = len(listB)
swaps = 0
index = 0
if A_length != B_length:
log.info("listA %s" % ' '.join(listA))
log.info("listB %s" % ' '.join(listB))
assert False, "listA (len %d) and listB (len %d) must be the same length" % (A_length, B_length)
if debug:
log.info("INIT")
log.info("listA: %s" % ' '.join(listA))
log.info("listB: %s" % ' '.join(listB))
log.info("")
while listA != listB:
if listA[index] != listB[index]:
listA_value = listA[index]
listB_index_with_A_value = find_index_for_value(listB, listA_value, index+1)
tmp = listB[index]
listB[index] = listB[listB_index_with_A_value]
listB[listB_index_with_A_value] = tmp
swaps += 1
if debug:
log.info("index %d, swaps %d" % (index, swaps))
log.info("listA: %s" % ' '.join(listA))
log.info("listB: %s" % ' '.join(listB))
log.info("")
index += 1
if debug:
log.info("swaps: %d" % swaps)
log.info("")
return swaps
def apply_rotations(size, step, rotations):
"""
Apply the "rotations" to step and return the step. This is used by
compress_solution() to remove all of the whole cube rotations from
the solution.
"""
if step in ('CENTERS_SOLVED', 'EDGES_GROUPED'):
return step
for rotation in rotations:
# remove the number at the start of the rotation...for a 4x4x4 cube
# there might be a 4U rotation (to rotate about the y-axis) but we
# don't need to keep the '4' part.
if size <= 9:
rotation = rotation[1:]
elif size <= 99:
rotation = rotation[2:]
else:
rotation = rotation[3:] # For a 100x or larger cube!!
if rotation == "U" or rotation == "D'":
if "U" in step:
pass
elif "L" in step:
step = step.replace("L", "F")
elif "F" in step:
step = step.replace("F", "R")
elif "R" in step:
step = step.replace("R", "B")
elif "B" in step:
step = step.replace("B", "L")
elif "D" in step:
pass
elif rotation == "U'" or rotation == "D":
if "U" in step:
pass
elif "L" in step:
step = step.replace("L", "B")
elif "F" in step:
step = step.replace("F", "L")
elif "R" in step:
step = step.replace("R", "F")
elif "B" in step:
step = step.replace("B", "R")
elif "D" in step:
pass
elif rotation == "F" or rotation == "B'":
if "U" in step:
step = step.replace("U", "L")
elif "L" in step:
step = step.replace("L", "D")
elif "F" in step:
pass
elif "R" in step:
step = step.replace("R", "U")
elif "B" in step:
pass
elif "D" in step:
step = step.replace("D", "R")
elif rotation == "F'" or rotation == "B":
if "U" in step:
step = step.replace("U", "R")
elif "L" in step:
step = step.replace("L", "U")
elif "F" in step:
pass
elif "R" in step:
step = step.replace("R", "D")
elif "B" in step:
pass
elif "D" in step:
step = step.replace("D", "L")
elif rotation == "R" or rotation == "L'":
if "U" in step:
step = step.replace("U", "F")
elif "L" in step:
pass
elif "F" in step:
step = step.replace("F", "D")
elif "R" in step:
pass
elif "B" in step:
step = step.replace("B", "U")
elif "D" in step:
step = step.replace("D", "B")
elif rotation == "R'" or rotation == "L":
if "U" in step:
step = step.replace("U", "B")
elif "L" in step:
pass
elif "F" in step:
step = step.replace("F", "U")
elif "R" in step:
pass
elif "B" in step:
step = step.replace("B", "D")
elif "D" in step:
step = step.replace("D", "F")
else:
raise Exception("%s is an invalid rotation" % rotation)
return step
def orbit_matches(edges_per_side, orbit, edge_index):
if orbit is None:
return True
if orbit == 0:
if edge_index == 0 or edge_index == edges_per_side-1:
return True
return False
if orbit == 1:
if edge_index == 1 or edge_index == edges_per_side-2:
return True
return False
if edge_index == orbit or edge_index == (edges_per_side - 1 - orbit):
return True
7 years ago
7 years ago
return False
def get_important_square_indexes(size):
"""
Used for writing www pages
"""
squares_per_side = size * size
max_square = squares_per_side * 6
first_squares = []
last_squares = []
for index in range(1, max_square + 1):
if (index - 1) % squares_per_side == 0:
first_squares.append(index)
elif index % squares_per_side == 0:
last_squares.append(index)
last_UBD_squares = (last_squares[0], last_squares[4], last_squares[5])
return (first_squares, last_squares, last_UBD_squares)
def number_ranges(i):
"""
https://stackoverflow.com/questions/4628333/converting-a-list-of-integers-into-range-in-python
"""
for a, b in itertools.groupby(enumerate(i), lambda x_y: x_y[1] - x_y[0]):
b = list(b)
yield b[0][1], b[-1][1]
7 years ago
class RubiksCube(object):
def __init__(self, state_string, order, colormap=None, debug=False):
init_state = ['dummy', ]
init_state.extend(list(state_string))
self.squares_per_side = int((len(init_state) - 1)/6)
self.size = math.sqrt(self.squares_per_side)
assert str(self.size).endswith('.0'), "Cube has %d squares per side which is not possible" % self.squares_per_side
self.size = int(self.size)
self.solution = []
self.steps_to_rotate_cube = 0
self.steps_to_solve_centers = 0
self.steps_to_group_edges = 0
self.steps_to_solve_3x3x3 = 0
self.ida_count = 0
self._phase = None
self.lt_init_called = False
self.orient_edges = {}
self.cpu_mode = None
7 years ago
if colormap:
colormap = json.loads(colormap)
self.color_map = {}
self.color_map_html = {}
for (side_name, color) in list(colormap.items()):
7 years ago
side_name = str(side_name)
if color == 'Wh':
self.color_map[side_name] = 97
self.color_map_html[side_name] = (235, 254, 250)
elif color == 'Gr':
self.color_map[side_name] = 92
self.color_map_html[side_name] = (20, 105, 74)
elif color == 'Rd':
self.color_map[side_name] = 91
self.color_map_html[side_name] = (104, 4, 2)
elif color == 'Bu':
self.color_map[side_name] = 94
self.color_map_html[side_name] = (22, 57, 103)
elif color == 'OR':
self.color_map[side_name] = 90
self.color_map_html[side_name] = (148, 53, 9)
elif color == 'Ye':
self.color_map[side_name] = 93
self.color_map_html[side_name] = (210, 208, 2)
#log.warning("color_map:\n%s\n" % pformat(self.color_map))
else:
# Match the colors on alg.cubing.net to make life easier
7 years ago
self.color_map = {
'U': 97, # Wh
'L': 90, # Or
'F': 92, # Gr
'R': 91, # Rd
'B': 94, # Bu
7 years ago
'D': 93, # Ye
}
self.color_map_html = {
'U': (235, 254, 250), # Wh
'L': (148, 53, 9), # Or
'F': (20, 105, 74), # Gr
'R': (104, 4, 2), # Rd
'B': (22, 57, 103), # Bu
7 years ago
'D': (210, 208, 2), # Ye
'x': (0, 0, 0), # black
}
if debug:
log.setLevel(logging.DEBUG)
self.load_state(state_string, order)
7 years ago
self.sides = OrderedDict()
self.sides['U'] = Side(self, 'U')
self.sides['L'] = Side(self, 'L')
self.sides['F'] = Side(self, 'F')
self.sides['R'] = Side(self, 'R')
self.sides['B'] = Side(self, 'B')
self.sides['D'] = Side(self, 'D')
self.sideU = self.sides['U']
self.sideL = self.sides['L']
self.sideF = self.sides['F']
self.sideR = self.sides['R']
self.sideB = self.sides['B']
self.sideD = self.sides['D']
self.all_edge_positions = []
# U and B
for (pos1, pos2) in zip(self.sideU.edge_north_pos, reversed(self.sideB.edge_north_pos)):
self.all_edge_positions.append((pos1, pos2))
# U and L
for (pos1, pos2) in zip(self.sideU.edge_west_pos, self.sideL.edge_north_pos):
self.all_edge_positions.append((pos1, pos2))
# U and F
for (pos1, pos2) in zip(self.sideU.edge_south_pos, self.sideF.edge_north_pos):
self.all_edge_positions.append((pos1, pos2))
# U and R
for (pos1, pos2) in zip(self.sideU.edge_east_pos, reversed(self.sideR.edge_north_pos)):
self.all_edge_positions.append((pos1, pos2))
# F and L
for (pos1, pos2) in zip(self.sideF.edge_west_pos, self.sideL.edge_east_pos):
self.all_edge_positions.append((pos1, pos2))
# F and R
for (pos1, pos2) in zip(self.sideF.edge_east_pos, self.sideR.edge_west_pos):
self.all_edge_positions.append((pos1, pos2))
# F and D
for (pos1, pos2) in zip(self.sideF.edge_south_pos, self.sideD.edge_north_pos):
self.all_edge_positions.append((pos1, pos2))
# L and B
for (pos1, pos2) in zip(self.sideL.edge_west_pos, self.sideB.edge_east_pos):
self.all_edge_positions.append((pos1, pos2))
# L and D
for (pos1, pos2) in zip(self.sideL.edge_south_pos, reversed(self.sideD.edge_west_pos)):
self.all_edge_positions.append((pos1, pos2))
# R and D
for (pos1, pos2) in zip(self.sideR.edge_south_pos, self.sideD.edge_east_pos):
self.all_edge_positions.append((pos1, pos2))
# R and B
for (pos1, pos2) in zip(self.sideR.edge_east_pos, self.sideB.edge_west_pos):
self.all_edge_positions.append((pos1, pos2))
# B and D
for (pos1, pos2) in zip(reversed(self.sideB.edge_south_pos), self.sideD.edge_south_pos):
self.all_edge_positions.append((pos1, pos2))
for side in list(self.sides.values()):
7 years ago
side.calculate_wing_partners()
def __str__(self):
return "%dx%dx%d" % (self.size, self.size, self.size)
def _sanity_check(self, desc, indexes, expected_count):
count = {
'U' : 0,
'L' : 0,
'F' : 0,
'R' : 0,
'B' : 0,
'D' : 0,
'x' : 0,
}
for x in indexes:
count[self.state[x]] += 1
for (side, value) in count.items():
if side == 'x' or value == 0:
continue
if value != expected_count:
self.print_cube()
raise InvalidCubeReduction("side %s %s count is %d (should be %d)" % (desc, side, value, expected_count))
def sanity_check(self):
"""
Implemented by the various child classes to verify that
the 'state' content makes sense
"""
pass
def load_state(self, state_string, order):
# kociemba_string is in URFDLB order so split this apart and re-arrange it to
# be ULFRBD so that is is sequential with the normal square numbering scheme
foo = []
init_state = ['dummy', ]
init_state.extend(list(state_string))
if order == 'URFDLB':
foo.extend(init_state[1:self.squares_per_side + 1]) # U
foo.extend(init_state[(self.squares_per_side * 4) + 1 : (self.squares_per_side * 5) + 1]) # L
foo.extend(init_state[(self.squares_per_side * 2) + 1 : (self.squares_per_side * 3) + 1]) # F
foo.extend(init_state[(self.squares_per_side * 1) + 1 : (self.squares_per_side * 2) + 1]) # R
foo.extend(init_state[(self.squares_per_side * 5) + 1 : (self.squares_per_side * 6) + 1]) # B
foo.extend(init_state[(self.squares_per_side * 3) + 1 : (self.squares_per_side * 4) + 1]) # D
elif order == 'ULFRBD':
foo.extend(init_state[1:self.squares_per_side + 1]) # U
foo.extend(init_state[(self.squares_per_side * 1) + 1 : (self.squares_per_side * 2) + 1]) # L
foo.extend(init_state[(self.squares_per_side * 2) + 1 : (self.squares_per_side * 3) + 1]) # F
foo.extend(init_state[(self.squares_per_side * 3) + 1 : (self.squares_per_side * 4) + 1]) # R
foo.extend(init_state[(self.squares_per_side * 4) + 1 : (self.squares_per_side * 5) + 1]) # B
foo.extend(init_state[(self.squares_per_side * 5) + 1 : (self.squares_per_side * 6) + 1]) # D
else:
raise Exception("Add support for order %s" % order)
self.state = ['x', ]
for (square_index, side_name) in enumerate(foo):
self.state.append(side_name)
7 years ago
def is_even(self):
if self.size % 2 == 0:
return True
return False
def is_odd(self):
if self.size % 2 == 0:
return False
return True
def solved(self):
"""
Return True if the cube is solved
"""
for side in list(self.sides.values()):
7 years ago
if not side.solved():
return False
return True
def rotation_map(self, action):
"""
This returns a set of tuples
that correspond to the movements
of each piece on the cube
for the move "action".
"""
results = []
if action[-1] in ("'", "`"):
reverse = True
action = action[0:-1]
else:
reverse = False
# 2Uw, Uw and 2U all mean rotate the top 2 U rows
# 3Uw and 3U mean rotate the top 3 U rows
if len(action) >= 2 and action[0].isdigit() and action[1].isdigit():
rows_to_rotate = int(action[0:2])
action = action[2:]
elif action[0].isdigit():
rows_to_rotate = int(action[0])
action = action[1:]
else:
# Uw also means rotate the top 2 U rows
if 'w' in action:
rows_to_rotate = 2
else:
rows_to_rotate = 1
# We've accounted for this so remove it
if 'w' in action:
action = action.replace('w', '')
# The digit at the end indicates how many quarter turns to do
if action[-1].isdigit():
quarter_turns = int(action[-1])
action = action[0:-1]
else:
quarter_turns = 1
side_name = action
# Skip moves x, y, z
side = self.sides[side_name]
min_pos = side.min_pos
max_pos = side.max_pos
# Rotation of the squares of the face itself
for turn in range(quarter_turns):
# Number the squares of the faces
# in a 2D array, then re-use all the
# existing transforms
oldface = []
counter = min_pos
for ii in range(self.size):
facerow = []
for jj in range(self.size):
facerow.append(counter)
counter += 1
oldface.append(facerow)
# This is not what we want, because it returns
# the face colors, not the face index numbers:
#oldface = side.get_face_as_2d_list()
if reverse:
newface = rotate_counter_clockwise(oldface)
else:
newface = rotate_clockwise(oldface)
oldface = compress_2d_list(oldface)
newface = compress_2d_list(newface)
for (j,k) in zip(oldface,newface):
results.append((j,k))
# Again skip rotation of entire cube with x, y, z
if side_name == "U":
for turn in range(quarter_turns):
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
left_first_square = self.squares_per_side + 1 + (row * self.size)
left_last_square = left_first_square + self.size - 1
front_first_square = (self.squares_per_side * 2) + 1 + (row * self.size)
front_last_square = front_first_square + self.size - 1
right_first_square = (self.squares_per_side * 3) + 1 + (row * self.size)
right_last_square = right_first_square + self.size - 1
back_first_square = (self.squares_per_side * 4) + 1 + (row * self.size)
back_last_square = back_first_square + self.size - 1
if reverse:
for square_index in range(left_first_square, left_last_square + 1):
old_index = square_index
new_index = square_index + (3 * self.squares_per_side)
results.append((old_index,new_index))
for square_index in range(front_first_square, front_last_square + 1):
old_index = square_index
new_index = square_index - self.squares_per_side
results.append((old_index,new_index))
for square_index in range(right_first_square, right_last_square + 1):
old_index = square_index
new_index = square_index - self.squares_per_side
results.append((old_index,new_index))
for square_index in range(back_first_square, back_last_square + 1):
old_index = square_index
new_index = square_index - self.squares_per_side
results.append((old_index,new_index))
else:
for square_index in range(left_first_square, left_last_square + 1):
old_index = square_index
new_index = square_index + self.squares_per_side
results.append((old_index,new_index))
for square_index in range(front_first_square, front_last_square + 1):
old_index = square_index
new_index = square_index + self.squares_per_side
results.append((old_index,new_index))
for square_index in range(right_first_square, right_last_square + 1):
old_index = square_index
new_index = square_index + self.squares_per_side
results.append((old_index,new_index))
for square_index in range(back_first_square, back_last_square + 1):
old_index = square_index
new_index = square_index - (3 * self.squares_per_side)
results.append((old_index,new_index))
elif side_name == "L":
for turn in range(quarter_turns):
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
top_first_square = 1 + row
top_last_square = top_first_square + ((self.size - 1) * self.size)
front_first_square = (self.squares_per_side * 2) + 1 + row
front_last_square = front_first_square + ((self.size - 1) * self.size)
down_first_square = (self.squares_per_side * 5) + 1 + row
down_last_square = down_first_square + ((self.size - 1) * self.size)
back_first_square = (self.squares_per_side * 4) + self.size - row
back_last_square = back_first_square + ((self.size - 1) * self.size)
top_squares = []
for square_index in range(top_first_square, top_last_square + 1, self.size):
top_squares.append(square_index)
front_squares = []
for square_index in range(front_first_square, front_last_square + 1, self.size):
front_squares.append(square_index)
down_squares = []
for square_index in range(down_first_square, down_last_square + 1, self.size):
down_squares.append(square_index)
back_squares = []
for square_index in range(back_first_square, back_last_square + 1, self.size):
back_squares.append(square_index)
if reverse:
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1, self.size)):
old_index = square_index
new_index = front_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(front_first_square, front_last_square + 1, self.size)):
old_index = square_index
new_index = down_squares[index]
results.append((old_index,new_index))
back_squares = list(reversed(back_squares))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1, self.size)):
old_index = square_index
new_index = back_squares[index]
results.append((old_index,new_index))
top_squares = list(reversed(top_squares))
for (index, square_index) in enumerate(range(back_first_square, back_last_square + 1, self.size)):
old_index = square_index
new_index = top_squares[index]
results.append((old_index,new_index))
else:
back_squares = list(reversed(back_squares))
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1, self.size)):
old_index = square_index
new_index = back_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(front_first_square, front_last_square + 1, self.size)):
old_index = square_index
new_index = top_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1, self.size)):
old_index = square_index
new_index = front_squares[index]
results.append((old_index,new_index))
down_squares = list(reversed(down_squares))
for (index, square_index) in enumerate(range(back_first_square, back_last_square + 1, self.size)):
old_index = square_index
new_index = down_squares[index]
results.append((old_index,new_index))
elif side_name == "F":
for turn in range(quarter_turns):
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
top_first_square = (self.squares_per_side - self.size) + 1 - (row * self.size)
top_last_square = top_first_square + self.size - 1
left_first_square = self.squares_per_side + self.size - row
left_last_square = left_first_square + ((self.size - 1) * self.size)
down_first_square = (self.squares_per_side * 5) + 1 + (row * self.size)
down_last_square = down_first_square + self.size - 1
right_first_square = (self.squares_per_side * 3) + 1 + row
right_last_square = right_first_square + ((self.size - 1) * self.size)
#log.info("top first %d, last %d" % (top_first_square, top_last_square))
#log.info("left first %d, last %d" % (left_first_square, left_last_square))
#log.info("down first %d, last %d" % (down_first_square, down_last_square))
#log.info("right first %d, last %d" % (right_first_square, right_last_square))
top_squares = []
for square_index in range(top_first_square, top_last_square + 1):
top_squares.append(square_index)
left_squares = []
for square_index in range(left_first_square, left_last_square + 1, self.size):
left_squares.append(square_index)
down_squares = []
for square_index in range(down_first_square, down_last_square + 1):
down_squares.append(square_index)
right_squares = []
for square_index in range(right_first_square, right_last_square + 1, self.size):
right_squares.append(square_index)
if reverse:
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1)):
old_index = square_index
new_index = right_squares[index]
results.append((old_index,new_index))
top_squares = list(reversed(top_squares))
for (index, square_index) in enumerate(range(left_first_square, left_last_square + 1, self.size)):
old_index = square_index
new_index = top_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1)):
old_index = square_index
new_index = left_squares[index]
results.append((old_index,new_index))
down_squares = list(reversed(down_squares))
for (index, square_index) in enumerate(range(right_first_square, right_last_square + 1, self.size)):
old_index = square_index
new_index = down_squares[index]
results.append((old_index,new_index))
else:
left_squares = list(reversed(left_squares))
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1)):
old_index = square_index
new_index = left_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(left_first_square, left_last_square + 1, self.size)):
old_index = square_index
new_index = down_squares[index]
results.append((old_index,new_index))
right_squares = list(reversed(right_squares))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1)):
old_index = square_index
new_index = right_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(right_first_square, right_last_square + 1, self.size)):
old_index = square_index
new_index = top_squares[index]
results.append((old_index,new_index))
elif side_name == "R":
for turn in range(quarter_turns):
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
top_first_square = self.size - row
top_last_square = self.squares_per_side
front_first_square = (self.squares_per_side * 2) + self.size - row
front_last_square = front_first_square + ((self.size - 1) * self.size)
down_first_square = (self.squares_per_side * 5) + self.size - row
down_last_square = down_first_square + ((self.size - 1) * self.size)
back_first_square = (self.squares_per_side * 4) + 1 + row
back_last_square = back_first_square + ((self.size - 1) * self.size)
#log.info("top first %d, last %d" % (top_first_square, top_last_square))
#log.info("front first %d, last %d" % (front_first_square, front_last_square))
#log.info("down first %d, last %d" % (down_first_square, down_last_square))
#log.info("back first %d, last %d" % (back_first_square, back_last_square))
top_squares = []
for square_index in range(top_first_square, top_last_square + 1, self.size):
top_squares.append(square_index)
front_squares = []
for square_index in range(front_first_square, front_last_square + 1, self.size):
front_squares.append(square_index)
down_squares = []
for square_index in range(down_first_square, down_last_square + 1, self.size):
down_squares.append(square_index)
back_squares = []
for square_index in range(back_first_square, back_last_square + 1, self.size):
back_squares.append(square_index)
if reverse:
back_squares = list(reversed(back_squares))
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1, self.size)):
old_index = square_index
new_index = back_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(front_first_square, front_last_square + 1, self.size)):
old_index = square_index
new_index = top_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1, self.size)):
old_index = square_index
new_index = front_squares[index]
results.append((old_index,new_index))
down_squares = list(reversed(down_squares))
for (index, square_index) in enumerate(range(back_first_square, back_last_square + 1, self.size)):
old_index = square_index
new_index = down_squares[index]
results.append((old_index,new_index))
else:
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1, self.size)):
old_index = square_index
new_index = front_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(front_first_square, front_last_square + 1, self.size)):
old_index = square_index
new_index = down_squares[index]
results.append((old_index,new_index))
back_squares = list(reversed(back_squares))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1, self.size)):
old_index = square_index
new_index = back_squares[index]
results.append((old_index,new_index))
top_squares = list(reversed(top_squares))
for (index, square_index) in enumerate(range(back_first_square, back_last_square + 1, self.size)):
old_index = square_index
new_index = top_squares[index]
results.append((old_index,new_index))
elif side_name == "B":
for turn in range(quarter_turns):
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
top_first_square = 1 + (row * self.size)
top_last_square = top_first_square + self.size - 1
left_first_square = self.squares_per_side + 1 + row
left_last_square = left_first_square + ((self.size - 1) * self.size)
down_first_square = (self.squares_per_side * 6) - self.size + 1 - (row * self.size)
down_last_square = down_first_square + self.size - 1
right_first_square = (self.squares_per_side * 3) + self.size - row
right_last_square = right_first_square + ((self.size - 1) * self.size)
#log.info("top first %d, last %d" % (top_first_square, top_last_square))
#log.info("left first %d, last %d" % (left_first_square, left_last_square))
#log.info("down first %d, last %d" % (down_first_square, down_last_square))
#log.info("right first %d, last %d" % (right_first_square, right_last_square))
top_squares = []
for square_index in range(top_first_square, top_last_square + 1):
top_squares.append(square_index)
left_squares = []
for square_index in range(left_first_square, left_last_square + 1, self.size):
left_squares.append(square_index)
down_squares = []
for square_index in range(down_first_square, down_last_square + 1):
down_squares.append(square_index)
right_squares = []
for square_index in range(right_first_square, right_last_square + 1, self.size):
right_squares.append(square_index)
if reverse:
left_squares = list(reversed(left_squares))
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1)):
old_index = square_index
new_index = left_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(left_first_square, left_last_square + 1, self.size)):
old_index = square_index
new_index = down_squares[index]
results.append((old_index,new_index))
right_squares = list(reversed(right_squares))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1)):
old_index = square_index
new_index = right_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(right_first_square, right_last_square + 1, self.size)):
old_index = square_index
new_index = top_squares[index]
results.append((old_index,new_index))
else:
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1)):
old_index = square_index
new_index = right_squares[index]
results.append((old_index,new_index))
top_squares = list(reversed(top_squares))
for (index, square_index) in enumerate(range(left_first_square, left_last_square + 1, self.size)):
old_index = square_index
new_index = top_squares[index]
results.append((old_index,new_index))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1)):
old_index = square_index
new_index = left_squares[index]
results.append((old_index,new_index))
down_squares = list(reversed(down_squares))
for (index, square_index) in enumerate(range(right_first_square, right_last_square + 1, self.size)):
old_index = square_index
new_index = down_squares[index]
results.append((old_index,new_index))
elif side_name == "D":
for turn in range(quarter_turns):
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
left_first_square = (self.squares_per_side * 2) - self.size + 1 - (row * self.size)
left_last_square = left_first_square + self.size - 1
front_first_square = (self.squares_per_side * 3) - self.size + 1 - (row * self.size)
front_last_square = front_first_square + self.size - 1
right_first_square = (self.squares_per_side * 4) - self.size + 1 - (row * self.size)
right_last_square = right_first_square + self.size - 1
back_first_square = (self.squares_per_side * 5) - self.size + 1 - (row * self.size)
back_last_square = back_first_square + self.size - 1
#log.info("left first %d, last %d" % (left_first_square, left_last_square))
#log.info("front first %d, last %d" % (front_first_square, front_last_square))
#log.info("right first %d, last %d" % (right_first_square, right_last_square))
#log.info("back first %d, last %d" % (back_first_square, back_last_square))
if reverse:
for square_index in range(left_first_square, left_last_square + 1):
old_index = square_index
new_index = square_index + self.squares_per_side
results.append((old_index,new_index))
for square_index in range(front_first_square, front_last_square + 1):
old_index = square_index
new_index = square_index + self.squares_per_side
results.append((old_index,new_index))
for square_index in range(right_first_square, right_last_square + 1):
old_index = square_index
new_index = square_index + self.squares_per_side
results.append((old_index,new_index))
for square_index in range(back_first_square, back_last_square + 1):
old_index = square_index
new_index = square_index - (3 * self.squares_per_side)
results.append((old_index,new_index))
else:
for square_index in range(left_first_square, left_last_square + 1):
old_index = square_index
new_index = square_index + (3 * self.squares_per_side)
results.append((old_index,new_index))
for square_index in range(front_first_square, front_last_square + 1):
old_index = square_index
new_index = square_index - self.squares_per_side
results.append((old_index,new_index))
for square_index in range(right_first_square, right_last_square + 1):
old_index = square_index
new_index = square_index - self.squares_per_side
results.append((old_index,new_index))
for square_index in range(back_first_square, back_last_square + 1):
old_index = square_index
new_index = square_index - self.squares_per_side
results.append((old_index,new_index))
return results
7 years ago
def rotate(self, action):
"""
self.state is a dictionary where the key is the square_index and the
value is that square side name (U, F, etc)
"""
self.solution.append(action)
result = self.state[:]
# log.info("move %s" % action)
if action[-1] in ("'", "`"):
reverse = True
action = action[0:-1]
else:
reverse = False
# 2Uw, Uw and 2U all mean rotate the top 2 U rows
# 3Uw and 3U mean rotate the top 3 U rows
if len(action) >= 2 and action[0].isdigit() and action[1].isdigit():
rows_to_rotate = int(action[0:2])
action = action[2:]
elif action[0].isdigit():
rows_to_rotate = int(action[0])
action = action[1:]
else:
# Uw also means rotate the top 2 U rows
if 'w' in action:
rows_to_rotate = 2
else:
rows_to_rotate = 1
# We've accounted for this so remove it
if 'w' in action:
action = action.replace('w', '')
# The digit at the end indicates how many quarter turns to do
if action[-1].isdigit():
quarter_turns = int(action[-1])
action = action[0:-1]
else:
quarter_turns = 1
side_name = action
if side_name == 'x':
side_name = 'R'
rows_to_rotate = self.size
elif side_name == 'y':
side_name = 'U'
rows_to_rotate = self.size
elif side_name == 'z':
side_name = 'F'
rows_to_rotate = self.size
if side_name in ('CENTERS_SOLVED', 'EDGES_GROUPED'):
return
side = self.sides[side_name]
min_pos = side.min_pos
max_pos = side.max_pos
# rotate the face...this is the same for all sides
for turn in range(quarter_turns):
7 years ago
face = side.get_face_as_2d_list()
if reverse:
face = rotate_counter_clockwise(face)
else:
face = rotate_clockwise(face)
face = compress_2d_list(face)
for (index, value) in enumerate(face):
square_index = min_pos + index
result[square_index] = value
self.state = result[:]
# If we are rotating the entire self.state we must rotate the opposite face as well
if rows_to_rotate == self.size:
if side_name == 'U':
opp_side_name = 'D'
elif side_name == 'D':
opp_side_name = 'U'
elif side_name == 'L':
opp_side_name = 'R'
elif side_name == 'R':
opp_side_name = 'L'
elif side_name == 'B':
opp_side_name = 'F'
elif side_name == 'F':
opp_side_name = 'B'
else:
raise SolveError("")
opp_side = self.sides[opp_side_name]
opp_min_pos = opp_side.min_pos
face = opp_side.get_face_as_2d_list()
# This is reversed from what we did with the original layer
if reverse:
face = rotate_clockwise(face)
else:
face = rotate_counter_clockwise(face)
face = compress_2d_list(face)
for (index, value) in enumerate(face):
square_index = opp_min_pos + index
result[square_index] = value
self.state = result[:]
if side_name == "U":
for turn in range(quarter_turns):
7 years ago
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
7 years ago
left_first_square = self.squares_per_side + 1 + (row * self.size)
left_last_square = left_first_square + self.size - 1
front_first_square = (self.squares_per_side * 2) + 1 + (row * self.size)
front_last_square = front_first_square + self.size - 1
right_first_square = (self.squares_per_side * 3) + 1 + (row * self.size)
right_last_square = right_first_square + self.size - 1
back_first_square = (self.squares_per_side * 4) + 1 + (row * self.size)
back_last_square = back_first_square + self.size - 1
#log.info("left first %d, last %d" % (left_first_square, left_last_square))
#log.info("front first %d, last %d" % (front_first_square, front_last_square))
#log.info("right first %d, last %d" % (right_first_square, right_last_square))
#log.info("back first %d, last %d" % (back_first_square, back_last_square))
if reverse:
for square_index in range(left_first_square, left_last_square + 1):
7 years ago
result[square_index] = self.state[square_index + (3 * self.squares_per_side)]
for square_index in range(front_first_square, front_last_square + 1):
7 years ago
result[square_index] = self.state[square_index - self.squares_per_side]
for square_index in range(right_first_square, right_last_square + 1):
7 years ago
result[square_index] = self.state[square_index - self.squares_per_side]
for square_index in range(back_first_square, back_last_square + 1):
7 years ago
result[square_index] = self.state[square_index - self.squares_per_side]
else:
for square_index in range(left_first_square, left_last_square + 1):
7 years ago
result[square_index] = self.state[square_index + self.squares_per_side]
for square_index in range(front_first_square, front_last_square + 1):
7 years ago
result[square_index] = self.state[square_index + self.squares_per_side]
for square_index in range(right_first_square, right_last_square + 1):
7 years ago
result[square_index] = self.state[square_index + self.squares_per_side]
for square_index in range(back_first_square, back_last_square + 1):
7 years ago
result[square_index] = self.state[square_index - (3 * self.squares_per_side)]
self.state = result[:]
elif side_name == "L":
for turn in range(quarter_turns):
7 years ago
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
7 years ago
top_first_square = 1 + row
top_last_square = top_first_square + ((self.size - 1) * self.size)
front_first_square = (self.squares_per_side * 2) + 1 + row
front_last_square = front_first_square + ((self.size - 1) * self.size)
down_first_square = (self.squares_per_side * 5) + 1 + row
down_last_square = down_first_square + ((self.size - 1) * self.size)
back_first_square = (self.squares_per_side * 4) + self.size - row
back_last_square = back_first_square + ((self.size - 1) * self.size)
#log.info("top first %d, last %d" % (top_first_square, top_last_square))
#log.info("front first %d, last %d" % (front_first_square, front_last_square))
#log.info("down first %d, last %d" % (down_first_square, down_last_square))
#log.info("back first %d, last %d" % (back_first_square, back_last_square))
top_squares = []
for square_index in range(top_first_square, top_last_square + 1, self.size):
7 years ago
top_squares.append(self.state[square_index])
front_squares = []
for square_index in range(front_first_square, front_last_square + 1, self.size):
7 years ago
front_squares.append(self.state[square_index])
down_squares = []
for square_index in range(down_first_square, down_last_square + 1, self.size):
7 years ago
down_squares.append(self.state[square_index])
back_squares = []
for square_index in range(back_first_square, back_last_square + 1, self.size):
7 years ago
back_squares.append(self.state[square_index])
if reverse:
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1, self.size)):
7 years ago
result[square_index] = front_squares[index]
for (index, square_index) in enumerate(range(front_first_square, front_last_square + 1, self.size)):
7 years ago
result[square_index] = down_squares[index]
back_squares = list(reversed(back_squares))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1, self.size)):
7 years ago
result[square_index] = back_squares[index]
top_squares = list(reversed(top_squares))
for (index, square_index) in enumerate(range(back_first_square, back_last_square + 1, self.size)):
7 years ago
result[square_index] = top_squares[index]
else:
back_squares = list(reversed(back_squares))
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1, self.size)):
7 years ago
result[square_index] = back_squares[index]
for (index, square_index) in enumerate(range(front_first_square, front_last_square + 1, self.size)):
7 years ago
result[square_index] = top_squares[index]
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1, self.size)):
7 years ago
result[square_index] = front_squares[index]
down_squares = list(reversed(down_squares))
for (index, square_index) in enumerate(range(back_first_square, back_last_square + 1, self.size)):
7 years ago
result[square_index] = down_squares[index]
self.state = result[:]
elif side_name == "F":
for turn in range(quarter_turns):
7 years ago
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
7 years ago
top_first_square = (self.squares_per_side - self.size) + 1 - (row * self.size)
top_last_square = top_first_square + self.size - 1
left_first_square = self.squares_per_side + self.size - row
left_last_square = left_first_square + ((self.size - 1) * self.size)
down_first_square = (self.squares_per_side * 5) + 1 + (row * self.size)
down_last_square = down_first_square + self.size - 1
right_first_square = (self.squares_per_side * 3) + 1 + row
right_last_square = right_first_square + ((self.size - 1) * self.size)
#log.info("top first %d, last %d" % (top_first_square, top_last_square))
#log.info("left first %d, last %d" % (left_first_square, left_last_square))
#log.info("down first %d, last %d" % (down_first_square, down_last_square))
#log.info("right first %d, last %d" % (right_first_square, right_last_square))
top_squares = []
for square_index in range(top_first_square, top_last_square + 1):
7 years ago
top_squares.append(self.state[square_index])
left_squares = []
for square_index in range(left_first_square, left_last_square + 1, self.size):
7 years ago
left_squares.append(self.state[square_index])
down_squares = []
for square_index in range(down_first_square, down_last_square + 1):
7 years ago
down_squares.append(self.state[square_index])
right_squares = []
for square_index in range(right_first_square, right_last_square + 1, self.size):
7 years ago
right_squares.append(self.state[square_index])
if reverse:
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1)):
7 years ago
result[square_index] = right_squares[index]
top_squares = list(reversed(top_squares))
for (index, square_index) in enumerate(range(left_first_square, left_last_square + 1, self.size)):
7 years ago
result[square_index] = top_squares[index]
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1)):
7 years ago
result[square_index] = left_squares[index]
down_squares = list(reversed(down_squares))
for (index, square_index) in enumerate(range(right_first_square, right_last_square + 1, self.size)):
7 years ago
result[square_index] = down_squares[index]
else:
left_squares = list(reversed(left_squares))
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1)):
7 years ago
result[square_index] = left_squares[index]
for (index, square_index) in enumerate(range(left_first_square, left_last_square + 1, self.size)):
7 years ago
result[square_index] = down_squares[index]
right_squares = list(reversed(right_squares))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1)):
7 years ago
result[square_index] = right_squares[index]
for (index, square_index) in enumerate(range(right_first_square, right_last_square + 1, self.size)):
7 years ago
result[square_index] = top_squares[index]
self.state = result[:]
elif side_name == "R":
for turn in range(quarter_turns):
7 years ago
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
7 years ago
top_first_square = self.size - row
top_last_square = self.squares_per_side
front_first_square = (self.squares_per_side * 2) + self.size - row
front_last_square = front_first_square + ((self.size - 1) * self.size)
down_first_square = (self.squares_per_side * 5) + self.size - row
down_last_square = down_first_square + ((self.size - 1) * self.size)
back_first_square = (self.squares_per_side * 4) + 1 + row
back_last_square = back_first_square + ((self.size - 1) * self.size)
#log.info("top first %d, last %d" % (top_first_square, top_last_square))
#log.info("front first %d, last %d" % (front_first_square, front_last_square))
#log.info("down first %d, last %d" % (down_first_square, down_last_square))
#log.info("back first %d, last %d" % (back_first_square, back_last_square))
top_squares = []
for square_index in range(top_first_square, top_last_square + 1, self.size):
7 years ago
top_squares.append(self.state[square_index])
front_squares = []
for square_index in range(front_first_square, front_last_square + 1, self.size):
7 years ago
front_squares.append(self.state[square_index])
down_squares = []
for square_index in range(down_first_square, down_last_square + 1, self.size):
7 years ago
down_squares.append(self.state[square_index])
back_squares = []
for square_index in range(back_first_square, back_last_square + 1, self.size):
7 years ago
back_squares.append(self.state[square_index])
if reverse:
back_squares = list(reversed(back_squares))
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1, self.size)):
7 years ago
result[square_index] = back_squares[index]
for (index, square_index) in enumerate(range(front_first_square, front_last_square + 1, self.size)):
7 years ago
result[square_index] = top_squares[index]
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1, self.size)):
7 years ago
result[square_index] = front_squares[index]
down_squares = list(reversed(down_squares))
for (index, square_index) in enumerate(range(back_first_square, back_last_square + 1, self.size)):
7 years ago
result[square_index] = down_squares[index]
else:
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1, self.size)):
7 years ago
result[square_index] = front_squares[index]
for (index, square_index) in enumerate(range(front_first_square, front_last_square + 1, self.size)):
7 years ago
result[square_index] = down_squares[index]
back_squares = list(reversed(back_squares))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1, self.size)):
7 years ago
result[square_index] = back_squares[index]
top_squares = list(reversed(top_squares))
for (index, square_index) in enumerate(range(back_first_square, back_last_square + 1, self.size)):
7 years ago
result[square_index] = top_squares[index]
self.state = result[:]
elif side_name == "B":
for turn in range(quarter_turns):
7 years ago
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
7 years ago
top_first_square = 1 + (row * self.size)
top_last_square = top_first_square + self.size - 1
left_first_square = self.squares_per_side + 1 + row
left_last_square = left_first_square + ((self.size - 1) * self.size)
down_first_square = (self.squares_per_side * 6) - self.size + 1 - (row * self.size)
down_last_square = down_first_square + self.size - 1
right_first_square = (self.squares_per_side * 3) + self.size - row
right_last_square = right_first_square + ((self.size - 1) * self.size)
#log.info("top first %d, last %d" % (top_first_square, top_last_square))
#log.info("left first %d, last %d" % (left_first_square, left_last_square))
#log.info("down first %d, last %d" % (down_first_square, down_last_square))
#log.info("right first %d, last %d" % (right_first_square, right_last_square))
top_squares = []
for square_index in range(top_first_square, top_last_square + 1):
7 years ago
top_squares.append(self.state[square_index])
left_squares = []
for square_index in range(left_first_square, left_last_square + 1, self.size):
7 years ago
left_squares.append(self.state[square_index])
down_squares = []
for square_index in range(down_first_square, down_last_square + 1):
7 years ago
down_squares.append(self.state[square_index])
right_squares = []
for square_index in range(right_first_square, right_last_square + 1, self.size):
7 years ago
right_squares.append(self.state[square_index])
if reverse:
left_squares = list(reversed(left_squares))
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1)):
7 years ago
result[square_index] = left_squares[index]
for (index, square_index) in enumerate(range(left_first_square, left_last_square + 1, self.size)):
7 years ago
result[square_index] = down_squares[index]
right_squares = list(reversed(right_squares))
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1)):
7 years ago
result[square_index] = right_squares[index]
for (index, square_index) in enumerate(range(right_first_square, right_last_square + 1, self.size)):
7 years ago
result[square_index] = top_squares[index]
else:
for (index, square_index) in enumerate(range(top_first_square, top_last_square + 1)):
7 years ago
result[square_index] = right_squares[index]
top_squares = list(reversed(top_squares))
for (index, square_index) in enumerate(range(left_first_square, left_last_square + 1, self.size)):
7 years ago
result[square_index] = top_squares[index]
for (index, square_index) in enumerate(range(down_first_square, down_last_square + 1)):
7 years ago
result[square_index] = left_squares[index]
down_squares = list(reversed(down_squares))
for (index, square_index) in enumerate(range(right_first_square, right_last_square + 1, self.size)):
7 years ago
result[square_index] = down_squares[index]
self.state = result[:]
elif side_name == "D":
for turn in range(quarter_turns):
7 years ago
# rotate the connecting row(s) of the surrounding sides
for row in range(rows_to_rotate):
7 years ago
left_first_square = (self.squares_per_side * 2) - self.size + 1 - (row * self.size)
left_last_square = left_first_square + self.size - 1
front_first_square = (self.squares_per_side * 3) - self.size + 1 - (row * self.size)
front_last_square = front_first_square + self.size - 1
right_first_square = (self.squares_per_side * 4) - self.size + 1 - (row * self.size)
right_last_square = right_first_square + self.size - 1
back_first_square = (self.squares_per_side * 5) - self.size + 1 - (row * self.size)
back_last_square = back_first_square + self.size - 1
#log.info("left first %d, last %d" % (left_first_square, left_last_square))
#log.info("front first %d, last %d" % (front_first_square, front_last_square))
#log.info("right first %d, last %d" % (right_first_square, right_last_square))
#log.info("back first %d, last %d" % (back_first_square, back_last_square))
if reverse:
for square_index in range(left_first_square, left_last_square + 1):
7 years ago
result[square_index] = self.state[square_index + self.squares_per_side]
for square_index in range(front_first_square, front_last_square + 1):
7 years ago
result[square_index] = self.state[square_index + self.squares_per_side]
for square_index in range(right_first_square, right_last_square + 1):
7 years ago
result[square_index] = self.state[square_index + self.squares_per_side]
for square_index in range(back_first_square, back_last_square + 1):
7 years ago
result[square_index] = self.state[square_index - (3 * self.squares_per_side)]
else:
for square_index in range(left_first_square, left_last_square + 1):
7 years ago
result[square_index] = self.state[square_index + (3 * self.squares_per_side)]
for square_index in range(front_first_square, front_last_square + 1):
7 years ago
result[square_index] = self.state[square_index - self.squares_per_side]
for square_index in range(right_first_square, right_last_square + 1):
7 years ago
result[square_index] = self.state[square_index - self.squares_per_side]
for square_index in range(back_first_square, back_last_square + 1):
7 years ago
result[square_index] = self.state[square_index - self.squares_per_side]
self.state = result[:]
else:
raise Exception("Unsupported action %s" % action)
def print_cube_layout(self):
print((get_cube_layout(self.size) + '\n'))
7 years ago
def print_cube(self, print_positions=False):
7 years ago
side_names = ('U', 'L', 'F', 'R', 'B', 'D')
side_name_index = 0
rows = []
row_index = 0
for x in range(self.size * 3):
7 years ago
rows.append([])
all_digits = True
7 years ago
for (square_index, square_state) in enumerate(self.state):
if not square_state.isdigit():
all_digits = False
break
7 years ago
for (square_index, square_state) in enumerate(self.state):
# ignore the placeholder (x)
7 years ago
if square_index == 0:
continue
side_name = side_names[side_name_index]
color = self.color_map.get(square_state, None)
if color:
# end of the row
if square_index % self.size == 0:
rows[row_index].append("\033[%dm%s\033[0m%s " % (color, square_state, " (%4d) " % square_index if print_positions else ""))
7 years ago
row_index += 1
else:
rows[row_index].append("\033[%dm%s\033[0m%s" % (color, square_state, " (%4d) " % square_index if print_positions else ""))
7 years ago
else:
# end of the row
if square_index % self.size == 0:
if square_state.endswith('x'):
rows[row_index].append("%s " % square_state)
else:
if all_digits:
rows[row_index].append("%02d" % int(square_state))
else:
rows[row_index].append("%s" % square_state)
7 years ago
row_index += 1
else:
if square_state.endswith('x'):
rows[row_index].append("%s" % square_state)
else:
if all_digits:
rows[row_index].append("%02d" % int(square_state))
else:
rows[row_index].append("%s" % square_state)
7 years ago
# end of the side
if square_index % self.squares_per_side == 0:
if side_name in ('L', 'F', 'R'):
row_index = self.size
side_name_index += 1
for (row_index, row) in enumerate(rows):
if row_index < self.size or row_index >= (self.size * 2):
if all_digits:
7 years ago
sys.stdout.write(' ' * (self.size * 3))
else:
sys.stdout.write(' ' * (self.size + self.size + 1))
print((' '.join(row)))
7 years ago
if ((row_index+1) % self.size) == 0:
print('')
print('')
def print_case_statement_C(self, case, first_step):
7 years ago
"""
This is called via --rotate-printer, it is used to print the
case statements used by lookup-table-builder.c
"""
if first_step:
print((" if (strcmp(step, \"%s\") == 0) {" % case))
else:
print((" } else if (strcmp(step, \"%s\") == 0) {" % case))
7 years ago
for (key, value) in enumerate(self.state[1:]):
key += 1
if str(key) != str(value):
print((" cube[%s] = cube_tmp[%s];" % (key, value)))
7 years ago
print("")
def print_case_statement_python(self, case):
"""
This is called via utils/rotate-printer.py, it is used to print the
contents of rotate_xxx.py
7 years ago
"""
numbers = []
numbers.append(0)
for (key, value) in enumerate(self.state[1:]):
numbers.append(int(value))
7 years ago
'''
If you feed number_ranges()
[0, 1, 2, 3, 4, 7, 8, 9, 11]
7 years ago
It will return:
[(0, 4), (7, 9), (11, 11)]
'''
lists = []
indexes_outside_streak = []
7 years ago
for (start_index, last_index) in number_ranges(numbers):
7 years ago
if start_index == last_index:
indexes_outside_streak.append("cube[%d]" % start_index)
7 years ago
else:
if indexes_outside_streak:
# cube[11], cube[13]
lists.append("[%s]" % ','.join(indexes_outside_streak))
indexes_outside_streak = []
lists.append("cube[%d:%d]" % (start_index, last_index+1))
7 years ago
if indexes_outside_streak:
lists.append("[%s]" % ','.join(indexes_outside_streak))
indexes_outside_streak = []
7 years ago
print((" return %s" % ' + '.join(lists)))
7 years ago
def randomize(self):
"""
Perform a bunch of random moves to scramble a cube. This was used to generate test cases.
"""
if self.is_even():
max_rows = int(self.size/2)
else:
max_rows = int((self.size - 1)/2)
sides = ['U', 'L', 'F', 'R', 'B', 'D']
count = ((self.size * self.size) * 6) * 3
# uncomment to limit randomness of the scramble
# count = 12
for x in range(count):
7 years ago
rows = random.randint(1, max_rows)
side_index = random.randint(0, 5)
side = sides[side_index]
quarter_turns = random.randint(1, 2)
clockwise = random.randint(0, 1)
if rows > 1:
move = "%d%s" % (rows, side)
else:
move = side
if quarter_turns > 1:
move += str(quarter_turns)
if not clockwise:
move += "'"
self.rotate(move)
def get_side_for_index(self, square_index):
"""
Return the Side object that owns square_index
"""
for side in list(self.sides.values()):
7 years ago
if square_index >= side.min_pos and square_index <= side.max_pos:
return side
raise SolveError("We should not be here, square_index %s" % pformat(square_index))
def get_edge_colors(self, square_index):
side = self.get_side_for_index(square_index)
edge_indexes = None
if square_index in side.edge_north_pos:
edge_indexes = side.edge_north_pos
elif square_index in side.edge_west_pos:
edge_indexes = side.edge_west_pos
elif square_index in side.edge_south_pos:
edge_indexes = side.edge_south_pos
elif square_index in side.edge_east_pos:
edge_indexes = side.edge_east_pos
colors = []
for edge_index in edge_indexes:
partner_index = side.get_wing_partner(edge_index)
colors.append(tuple(sorted((self.state[edge_index], self.state[partner_index]))))
colors = sorted(list(set(colors)))
#log.info("%s colors %s" % (square_index, pformat(colors)))
return colors
def get_non_paired_wings(self):
return (self.sideU.non_paired_wings(True, True, True, True) +
self.sideF.non_paired_wings(False, True, False, True) +
self.sideB.non_paired_wings(False, True, False, True) +
self.sideD.non_paired_wings(True, True, True, True))
def get_non_paired_wings_count(self):
return len(self.get_non_paired_wings())
def get_non_paired_edges(self):
# north, west, south, east
return (self.sideU.non_paired_edges(True, True, True, True) +
self.sideF.non_paired_edges(False, True, False, True) +
self.sideB.non_paired_edges(False, True, False, True) +
self.sideD.non_paired_edges(True, True, True, True))
def get_non_paired_edges_count(self):
non_paired_edges = self.get_non_paired_edges()
result = len(non_paired_edges)
if result > 12:
raise SolveError("Found %d unpaired edges but a cube only has 12 edges" % result)
return result
def edges_paired(self):
if self.get_non_paired_edges_count() == 0:
return True
return False
7 years ago
def find_edge(self, color1, color2):
positions = []
for (pos1, pos2) in self.all_edge_positions:
if ((self.state[pos1] == color1 and self.state[pos2] == color2) or
(self.state[pos1] == color2 and self.state[pos2] == color1)):
positions.append((pos1, pos2))
return positions
def get_wings(self, pos1, remove_if_in_same_edge=False):
pos1_side = self.get_side_for_index(pos1)
pos2 = pos1_side.get_wing_partner(pos1)
pos2_side = self.get_side_for_index(pos2)
color1 = self.state[pos1]
color2 = self.state[pos2]
wings = self.find_edge(color1, color2)
wings_to_remove = []
#log.info("get_wings (%d, %d), pos1_side %s, remove_if_in_same_edge %s, %s" %
# (pos1, pos2, pos1_side, remove_if_in_same_edge, pformat(wings)))
for (wing_pos1, wing_pos2) in wings:
# Remove the one we started with
if (wing_pos1, wing_pos2) == (pos1, pos2):
wings_to_remove.append((wing_pos1, wing_pos2))
elif (wing_pos1, wing_pos2) == (pos2, pos1):
wings_to_remove.append((wing_pos1, wing_pos2))
# Some callers do not want wings that are part of the same edge as pos1
elif remove_if_in_same_edge:
wing_pos1_side = self.get_side_for_index(wing_pos1)
wing_pos2_side = self.get_side_for_index(wing_pos2)
#log.info("wing_pos1 %s, wing_pos1_side %s, wing_pos2 %s, wing_pos2_side %s" %
# (wing_pos1, wing_pos1_side, wing_pos2, wing_pos2_side))
if ((wing_pos1_side == pos1_side and wing_pos2_side == pos2_side) or
(wing_pos2_side == pos1_side and wing_pos1_side == pos2_side)):
wings_to_remove.append((wing_pos1, wing_pos2))
#log.info("get_wings wings_to_remove %s" % pformat(wings_to_remove))
for x in wings_to_remove:
wings.remove(x)
#log.info("get_wings returning %s\n" % pformat(wings))
return wings
def get_wing_in_middle_of_edge(self, pos1, remove_if_in_same_edge=False):
wings = self.get_wings(pos1, remove_if_in_same_edge)
for wing in wings:
wing_side = self.get_side_for_index(wing[0])
if wing_side.wing_is_middle_of_edge(wing[0]):
return wing
return None
def get_wings_on_edge(self, pos1, side1_name, side2_name):
wings = self.get_wings(pos1)
wings_to_keep = []
#log.info("get_wings_on_edge for pos1 %d, side1 %s, side2 %s, init_wings %s" % (pos1, side1_name, side2_name, pformat(wings)))
for (wing_pos1, wing_pos2) in wings:
wing_pos1_side = self.get_side_for_index(wing_pos1)
wing_pos2_side = self.get_side_for_index(wing_pos2)
#log.info("get_wings_on_edge wing_pos1 %d side %s, wing_pos2 %d side %s\n" %
# (wing_pos1, wing_pos1_side, wing_pos2, wing_pos2_side))
if ((wing_pos1_side.name == side1_name and wing_pos2_side.name == side2_name) or
(wing_pos2_side.name == side1_name and wing_pos1_side.name == side2_name)):
wings_to_keep.append((wing_pos1, wing_pos2))
#log.info("get_wings_on_edge keeping %s\n" % pformat(wings_to_keep))
return wings_to_keep
def rotate_edge_to_F_west(self, edge):
side = self.get_side_for_index(edge[0])
direction = side.has_wing(edge)
if side == self.sideU:
if direction == 'north':
self.rotate_y_reverse()
self.rotate_x_reverse()
elif direction == 'west':
self.rotate_x_reverse()
elif direction == 'south':
self.rotate_x_reverse()
self.rotate_z()
elif direction == 'east':
self.rotate_y()
self.rotate_y()
self.rotate_x_reverse()
elif side == self.sideL:
if direction == 'north':
self.rotate_x_reverse()
elif direction == 'west':
self.rotate_x_reverse()
self.rotate_x_reverse()
elif direction == 'south':
self.rotate_x()
elif direction == 'east':
pass
elif side == self.sideF:
if direction == 'north':
self.rotate_z_reverse()
elif direction == 'west':
pass
elif direction == 'south':
self.rotate_z()
elif direction == 'east':
self.rotate_z_reverse()
self.rotate_z_reverse()
elif side == self.sideR:
if direction == 'north':
self.rotate_y()
self.rotate_y()
self.rotate_x_reverse()
elif direction == 'west':
self.rotate_y()
elif direction == 'south':
self.rotate_x()
self.rotate_y()
elif direction == 'east':
self.rotate_y()
self.rotate_y()
elif side == self.sideB:
if direction == 'north':
self.rotate_y_reverse()
self.rotate_x_reverse()
elif direction == 'west':
self.rotate_y()
self.rotate_y()
elif direction == 'south':
self.rotate_z()
self.rotate_x()
self.rotate_x()
elif direction == 'east':
self.rotate_y_reverse()
elif side == self.sideD:
if direction == 'north':
self.rotate_z()
elif direction == 'west':
self.rotate_x()
elif direction == 'south':
self.rotate_y_reverse()
self.rotate_x()
elif direction == 'east':
self.rotate_y()
self.rotate_y()
self.rotate_x()
def move_wing_to_U_north(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
pass
elif wing_pos1 in self.sideU.edge_south_pos:
for step in ("U2", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_east_pos:
for step in ("U'", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_west_pos:
for step in ("U", ):
self.rotate(step)
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
for step in ("U", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_south_pos:
for step in ("L", "B'"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_east_pos:
for step in ("L2", "B'"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_west_pos:
for step in ("B'", ):
self.rotate(step)
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
for step in ("U2", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_south_pos:
for step in ("F2", "U2"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_east_pos:
for step in ("R", "U'"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_west_pos:
for step in ("F", "U2"):
self.rotate(step)
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
for step in ("U'", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_south_pos:
for step in ("R2", "U'"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_east_pos:
for step in ("B", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_west_pos:
for step in ("R", "U'"):
self.rotate(step)
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
pass
elif wing_pos1 in self.sideB.edge_south_pos:
for step in ("B2", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_east_pos:
for step in ("B'", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_west_pos:
for step in ("B", ):
self.rotate(step)
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
for step in ("F2", "U2"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_south_pos:
for step in ("B2", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_east_pos:
for step in ("R2", "U'"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_west_pos:
for step in ("L2", "U"):
self.rotate(step)
else:
raise ImplementThis("implement wing %s to U north" % str(wing))
def move_wing_to_U_west(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
for step in ("U'", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_south_pos:
for step in ("U", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_east_pos:
for step in ("U2", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_west_pos:
pass
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
pass
elif wing_pos1 in self.sideL.edge_south_pos:
for step in ("L2", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_east_pos:
for step in ("L'", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_west_pos:
for step in ("L", ):
self.rotate(step)
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
for step in ("U", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_south_pos:
for step in ("F2", "U"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_east_pos:
for step in ("F'", "U"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_west_pos:
for step in ("L'", ):
self.rotate(step)
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
for step in ("U2", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_south_pos:
for step in ("R2", "U2"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_east_pos:
for step in ("B", "U'"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_west_pos:
for step in ("R", "U2"):
self.rotate(step)
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
for step in ("U'", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_south_pos:
for step in ("B2", "U'"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_east_pos:
for step in ("L", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_west_pos:
for step in ("B", "U'"):
self.rotate(step)
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
for step in ("D'", "L2"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_south_pos:
for step in ("D", "L2"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_east_pos:
for step in ("D2", "L2"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_west_pos:
for step in ("L2", ):
self.rotate(step)
else:
raise ImplementThis("implement wing %s to U west" % str(wing))
def move_wing_to_U_south(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
for step in ("U2", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_south_pos:
pass
elif wing_pos1 in self.sideU.edge_east_pos:
for step in ("U", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_west_pos:
for step in ("U'", ):
self.rotate(step)
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
for step in ("U'", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_south_pos:
for step in ("L2", "U'"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_east_pos:
for step in ("F", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_west_pos:
for step in ("L", "U'"):
self.rotate(step)
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
pass
elif wing_pos1 in self.sideF.edge_south_pos:
for step in ("F2", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_east_pos:
for step in ("F'", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_west_pos:
for step in ("F", ):
self.rotate(step)
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
for step in ("U", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_south_pos:
for step in ("R2", "U"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_east_pos:
for step in ("R'", "U"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_west_pos:
for step in ("R", "U"):
self.rotate(step)
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
for step in ("U2", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_south_pos:
for step in ("B2", "U2"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_east_pos:
for step in ("B'", "U2"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_west_pos:
for step in ("B", "U2"):
self.rotate(step)
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
for step in ("F2", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_south_pos:
for step in ("D2", "F2"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_east_pos:
for step in ("D'", "F2"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_west_pos:
for step in ("D", "F2"):
self.rotate(step)
else:
raise ImplementThis("implement wing %s to U south" % str(wing))
def move_wing_to_U_east(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
for step in ("U", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_south_pos:
for step in ("U'", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_east_pos:
pass
elif wing_pos1 in self.sideU.edge_west_pos:
for step in ("U2", ):
self.rotate(step)
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
for step in ("U2", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_south_pos:
for step in ("L2", "U2"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_east_pos:
for step in ("F", "U'"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_west_pos:
for step in ("L", "U2"):
self.rotate(step)
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
for step in ("U'", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_south_pos:
for step in ("F'", "R"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_east_pos:
for step in ("R", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_west_pos:
for step in ("F", "U'"):
self.rotate(step)
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
pass
elif wing_pos1 in self.sideR.edge_south_pos:
for step in ("R2", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_east_pos:
for step in ("R'", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_west_pos:
for step in ("R", ):
self.rotate(step)
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
for step in ("U", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_south_pos:
for step in ("B", "R'"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_east_pos:
for step in ("B'", "U"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_west_pos:
for step in ("R'", ):
self.rotate(step)
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
for step in ("D", "R2"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_south_pos:
for step in ("D'", "R2"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_east_pos:
for step in ("R2", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_west_pos:
for step in ("D2", "R2"):
self.rotate(step)
else:
raise ImplementThis("implement wing %s to U east" % str(wing))
def move_wing_to_L_west(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
for step in ("B", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_south_pos:
for step in ("U2", "B"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_east_pos:
for step in ("U'", "B"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_west_pos:
for step in ("U", "B"):
self.rotate(step)
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
for step in ("L'", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_south_pos:
for step in ("L", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_east_pos:
for step in ("L2", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_west_pos:
pass
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
for step in ("F'", "L2"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_south_pos:
for step in ("F", "L2"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_east_pos:
for step in ("F2", "L2"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_west_pos:
for step in ("L2", ):
self.rotate(step)
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
for step in ("R", "B2"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_south_pos:
for step in ("R'", "B2"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_east_pos:
for step in ("B2", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_west_pos:
for step in ("R2", "B2"):
self.rotate(step)
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
for step in ("B", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_south_pos:
for step in ("B'", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_east_pos:
pass
elif wing_pos1 in self.sideB.edge_west_pos:
for step in ("B2", ):
self.rotate(step)
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
for step in ("D'", "L"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_south_pos:
for step in ("D", "L"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_east_pos:
for step in ("D2", "L"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_west_pos:
for step in ("L", ):
self.rotate(step)
else:
raise ImplementThis("implement wing %s to L west" % str(wing))
def move_wing_to_L_east(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
for step in ("U'", "L"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_south_pos:
self.rotate("F'")
elif wing_pos1 in self.sideU.edge_east_pos:
for step in ("U2", "L"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_west_pos:
self.rotate("L")
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
self.rotate("L")
elif wing_pos1 in self.sideL.edge_south_pos:
self.rotate("L'")
elif wing_pos1 in self.sideL.edge_east_pos:
pass
elif wing_pos1 in self.sideL.edge_west_pos:
self.rotate("L2")
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
self.rotate("F'")
elif wing_pos1 in self.sideF.edge_south_pos:
self.rotate("F")
elif wing_pos1 in self.sideF.edge_east_pos:
self.rotate("F2")
elif wing_pos1 in self.sideF.edge_west_pos:
pass
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
for step in ("U2", "L"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_south_pos:
for step in ("D2", "L'"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_east_pos:
for step in ("B2", "L2"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_west_pos:
self.rotate("F2")
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
for step in ("U'", "L"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_south_pos:
for step in ("B'", "L2"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_east_pos:
self.rotate("L2")
elif wing_pos1 in self.sideB.edge_west_pos:
for step in ("B2", "L2"):
self.rotate(step)
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
self.rotate("F")
elif wing_pos1 in self.sideD.edge_south_pos:
for step in ("D", "L'"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_east_pos:
for step in ("D2", "L'"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_west_pos:
self.rotate("L'")
else:
raise ImplementThis("implement wing %s to L east" % str(wing))
def move_wing_to_F_west(self, wing):
self.move_wing_to_L_east(wing)
def move_wing_to_R_west(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
for step in ("U", "R'"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_south_pos:
for step in ("U'", "R'"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_east_pos:
for step in ("R'",):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_west_pos:
for step in ("U2", "R'"):
self.rotate(step)
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
for step in ("U2", "R'"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_south_pos:
for step in ("D2", "R"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_east_pos:
for step in ("F2", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_west_pos:
for step in ("B2", "R2"):
self.rotate(step)
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
for step in ("F", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_south_pos:
for step in ("D", "R"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_east_pos:
pass
elif wing_pos1 in self.sideF.edge_west_pos:
for step in ("F2", ):
self.rotate(step)
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
for step in ("R'", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_south_pos:
for step in ("R", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_east_pos:
for step in ("R2",):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_west_pos:
pass
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
for step in ("U", "R'"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_south_pos:
for step in ("D'", "R"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_east_pos:
for step in ("B2", "R2"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_west_pos:
for step in ("R2",):
self.rotate(step)
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
for step in ("D", "R"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_south_pos:
for step in ("D'", "R"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_east_pos:
for step in ("R", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_west_pos:
for step in ("D2", "R"):
self.rotate(step)
else:
raise ImplementThis("implement wing %s to R west" % str(wing))
def move_wing_to_R_east(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
for step in ("B'", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_south_pos:
for step in ("U'", "R"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_east_pos:
for step in ("R", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_west_pos:
for step in ("U2", "R"):
self.rotate(step)
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
for step in ("L'", "B2"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_south_pos:
for step in ("L", "B2"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_east_pos:
for step in ("F2", "R2"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_west_pos:
for step in ("B2", ):
self.rotate(step)
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
for step in ("U'", "R"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_south_pos:
for step in ("F'", "R2"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_east_pos:
for step in ("R2", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_west_pos:
for step in ("F2", "R2"):
self.rotate(step)
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
for step in ("R", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_south_pos:
for step in ("R'", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_east_pos:
pass
elif wing_pos1 in self.sideR.edge_west_pos:
for step in ("R2", ):
self.rotate(step)
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
for step in ("B'", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_south_pos:
for step in ("B", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_east_pos:
for step in ("B2", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_west_pos:
pass
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
for step in ("D", "R'"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_south_pos:
for step in ("D'", "R'"):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_east_pos:
for step in ("R'", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_west_pos:
for step in ("D2", "R'"):
self.rotate(step)
else:
raise ImplementThis("implement wing %s to R east" % str(wing))
def move_wing_to_F_east(self, wing):
self.move_wing_to_R_west(wing)
def move_wing_to_D_north(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
for step in ("B2", "D2"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_south_pos:
for step in ("F2", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_east_pos:
for step in ("R2", "D'"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_west_pos:
for step in ("L2", "D"):
self.rotate(step)
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
for step in ("L2", "D"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_south_pos:
for step in ("D", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_east_pos:
for step in ("L", "D"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_west_pos:
for step in ("L'", "D"):
self.rotate(step)
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
for step in ("F2", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_south_pos:
pass
elif wing_pos1 in self.sideF.edge_east_pos:
for step in ("F", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_west_pos:
for step in ("F'", ):
self.rotate(step)
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
for step in ("R2", "D'"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_south_pos:
for step in ("D'", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_east_pos:
for step in ("R", "D'"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_west_pos:
for step in ("R'", "D'"):
self.rotate(step)
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
for step in ("B2", "D2"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_south_pos:
for step in ("D2", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_east_pos:
for step in ("B", "D2"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_west_pos:
for step in ("R", "D'"):
self.rotate(step)
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
pass
elif wing_pos1 in self.sideD.edge_south_pos:
for step in ("D2", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_east_pos:
for step in ("D'", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_west_pos:
for step in ("D", ):
self.rotate(step)
else:
raise ImplementThis("implement wing %s to D north" % str(wing))
def move_wing_to_D_west(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
for step in ("U'", "L2"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_south_pos:
for step in ("U", "L2"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_east_pos:
for step in ("U2", "L2"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_west_pos:
for step in ("L2", ):
self.rotate(step)
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
for step in ("L2", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_south_pos:
pass
elif wing_pos1 in self.sideL.edge_east_pos:
for step in ("L", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_west_pos:
for step in ("L'", ):
self.rotate(step)
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
for step in ("F'", "L"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_south_pos:
for step in ("D'", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_east_pos:
for step in ("F", "D'"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_west_pos:
for step in ("L", ):
self.rotate(step)
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
for step in ("R2", "D2"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_south_pos:
for step in ("D2", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_east_pos:
for step in ("R", "D2"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_west_pos:
for step in ("R'", "D2"):
self.rotate(step)
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
for step in ("B", "L'"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_south_pos:
for step in ("D", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_east_pos:
for step in ("L'", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_west_pos:
for step in ("B'", "D"):
self.rotate(step)
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
for step in ("D'", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_south_pos:
for step in ("D", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_east_pos:
for step in ("D2", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_west_pos:
pass
else:
raise ImplementThis("implement wing %s to D west" % str(wing))
def move_wing_to_D_south(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
for step in ("B2", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_south_pos:
for step in ("F2", "D2"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_east_pos:
for step in ("R2", "D"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_west_pos:
for step in ("L2", "D'"):
self.rotate(step)
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
for step in ("L2", "D'"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_south_pos:
for step in ("D'", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_east_pos:
for step in ("L", "D'"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_west_pos:
for step in ("L'", "D'"):
self.rotate(step)
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
for step in ("F2", "D2"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_south_pos:
for step in ("D2", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_east_pos:
for step in ("F", "D2"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_west_pos:
for step in ("F'", "D2"):
self.rotate(step)
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
for step in ("R2", "D"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_south_pos:
for step in ("D", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_east_pos:
for step in ("R", "D"):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_west_pos:
for step in ("R'", "D"):
self.rotate(step)
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
for step in ("B2", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_south_pos:
pass
elif wing_pos1 in self.sideB.edge_east_pos:
for step in ("B", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_west_pos:
for step in ("B'", ):
self.rotate(step)
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
for step in ("D2", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_south_pos:
pass
elif wing_pos1 in self.sideD.edge_east_pos:
for step in ("D", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_west_pos:
for step in ("D'", ):
self.rotate(step)
else:
raise ImplementThis("implement wing %s to D south" % str(wing))
def move_wing_to_D_east(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
wing_pos1 = wing[0]
else:
wing_pos1 = wing
# Upper
if wing_pos1 in self.sideU.edge_north_pos:
for step in ("U", "R2"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_south_pos:
for step in ("U'", "R2"):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_east_pos:
for step in ("R2", ):
self.rotate(step)
elif wing_pos1 in self.sideU.edge_west_pos:
for step in ("U2", "R2"):
self.rotate(step)
# Left
elif wing_pos1 in self.sideL.edge_north_pos:
for step in ("L2", "D2"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_south_pos:
for step in ("D2", ):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_east_pos:
for step in ("L", "D2"):
self.rotate(step)
elif wing_pos1 in self.sideL.edge_west_pos:
for step in ("L'", "D2"):
self.rotate(step)
# Front
elif wing_pos1 in self.sideF.edge_north_pos:
for step in ("F", "R'"):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_south_pos:
for step in ("D", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_east_pos:
for step in ("R'", ):
self.rotate(step)
elif wing_pos1 in self.sideF.edge_west_pos:
for step in ("F'", "D"):
self.rotate(step)
# Right
elif wing_pos1 in self.sideR.edge_north_pos:
for step in ("R2", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_south_pos:
pass
elif wing_pos1 in self.sideR.edge_east_pos:
for step in ("R", ):
self.rotate(step)
elif wing_pos1 in self.sideR.edge_west_pos:
for step in ("R'", ):
self.rotate(step)
# Back
elif wing_pos1 in self.sideB.edge_north_pos:
for step in ("B2", "D'"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_south_pos:
for step in ("D'", ):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_east_pos:
for step in ("B", "D'"):
self.rotate(step)
elif wing_pos1 in self.sideB.edge_west_pos:
for step in ("R", ):
self.rotate(step)
# Down
elif wing_pos1 in self.sideD.edge_north_pos:
for step in ("D", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_south_pos:
for step in ("D'", ):
self.rotate(step)
elif wing_pos1 in self.sideD.edge_east_pos:
pass
elif wing_pos1 in self.sideD.edge_west_pos:
for step in ("D2", ):
self.rotate(step)
else:
raise ImplementThis("implement wing %s to D east" % str(wing))
def rotate_x(self):
self.rotate("x")
7 years ago
def rotate_x_reverse(self):
self.rotate("x'")
7 years ago
def rotate_y(self):
self.rotate("y")
7 years ago
def rotate_y_reverse(self):
self.rotate("y'")
7 years ago
def rotate_z(self):
self.rotate("z")
7 years ago
def rotate_z_reverse(self):
self.rotate("z'")
7 years ago
def get_center_corner_state(self):
return ''.join([self.state[square_index] for side in (self.sideU, self.sideL, self.sideF, self.sideR, self.sideB, self.sideD) for square_index in side.center_corner_pos])
def centers_solved(self):
for side in list(self.sides.values()):
7 years ago
prev_pos = None
for pos in side.center_pos:
if prev_pos is not None:
if self.state[prev_pos] != self.state[pos]:
return False
prev_pos = pos
return True
def crosses_solved(self):
# side is a Side object
# added a cross_pos to the Side object
for side in list(self.sides.values()):
prev_pos = None
for pos in side.cross_pos:
if prev_pos is not None:
if self.state[prev_pos] != self.state[pos]:
return False
prev_pos = pos
return True
7 years ago
def UD_centers_staged(self):
for side in (self.sideU, self.sideD):
for pos in side.center_pos:
if self.state[pos] not in ('U', 'D'):
return False
return True
def LR_centers_staged(self):
for side in (self.sideL, self.sideR):
for pos in side.center_pos:
if self.state[pos] not in ('L', 'R'):
return False
return True
def rotate_side_X_to_Y(self, x, y):
#assert x in ('U', 'L', 'F', 'R', 'B', 'D'), "Invalid side %s" % x
#assert y in ('U', 'L', 'F', 'R', 'B', 'D'), "Invalid side %s" % y
if y == 'U':
side = self.sideU
elif y == 'L':
side = self.sideL
elif y == 'F':
side = self.sideF
elif y == 'R':
side = self.sideR
elif y == 'B':
side = self.sideB
elif y == 'D':
side = self.sideD
# odd cube
7 years ago
if side.mid_pos:
pos_to_check = side.mid_pos
F_pos_to_check = self.sideF.mid_pos
D_pos_to_check = self.sideD.mid_pos
# even cube
7 years ago
else:
# Use the top-right inner x-center
offset = int(((self.size/2) * self.size) - (self.size/2))
7 years ago
pos_to_check = side.min_pos + offset
F_pos_to_check = self.sideF.min_pos + offset
D_pos_to_check = self.sideD.min_pos + offset
count = 0
while self.state[pos_to_check] != x:
#log.info("%s (%s): rotate %s to %s, pos_to_check %s, state at pos_to_check %s" %
# (side, side.mid_pos, x, y, pos_to_check, self.state[pos_to_check]))
if self.state[F_pos_to_check] == x and y == 'U':
self.rotate_x()
elif self.state[F_pos_to_check] == x and y == 'D':
self.rotate_x_reverse()
elif self.state[D_pos_to_check] == x and y == 'F':
self.rotate_x()
elif self.state[D_pos_to_check] == x and y == 'U':
self.rotate_x()
self.rotate_x()
else:
self.rotate_y()
count += 1
if count > 30:
raise StuckInALoop("rotate %s to %s, %s, pos_to_check %s, state at pos_to_check %s" % (x, y, side, pos_to_check, self.state[pos_to_check]))
def rotate_U_to_U(self):
self.rotate_side_X_to_Y('U', 'U')
def rotate_F_to_F(self):
self.rotate_side_X_to_Y('F', 'F')
def get_kociemba_string(self, all_squares):
# kociemba uses order U R F D L B
foo = []
if all_squares:
# This is only used to print cubes for test cases (see --test-build)
for side_name in ('U', 'R', 'F', 'D', 'L', 'B'):
side = self.sides[side_name]
for square_index in range(side.min_pos, side.max_pos + 1):
7 years ago
foo.append(self.state[square_index])
else:
if self.size == 2:
for side_name in ('U', 'R', 'F', 'D', 'L', 'B'):
side = self.sides[side_name]
# first row
foo.append(self.state[side.corner_pos[0]])
foo.append(self.state[side.corner_pos[1]])
# second row
foo.append(self.state[side.corner_pos[2]])
foo.append(self.state[side.corner_pos[3]])
else:
for side_name in ('U', 'R', 'F', 'D', 'L', 'B'):
side = self.sides[side_name]
# first row
foo.append(self.state[side.corner_pos[0]])
foo.append(self.state[side.edge_north_pos[0]])
foo.append(self.state[side.corner_pos[1]])
# second row
foo.append(self.state[side.edge_west_pos[0]])
if side.mid_pos:
foo.append(self.state[side.mid_pos])
else:
offset = int(((self.size/2) * self.size) - (self.size/2))
7 years ago
pos_to_check = side.min_pos + offset
foo.append(self.state[pos_to_check])
foo.append(self.state[side.edge_east_pos[0]])
# third row
foo.append(self.state[side.corner_pos[2]])
foo.append(self.state[side.edge_south_pos[0]])
foo.append(self.state[side.corner_pos[3]])
kociemba_string = ''.join(foo)
log.debug('kociemba string: %s' % kociemba_string)
return kociemba_string
def prevent_OLL(self):
"""
Solving OLL at the end takes 26 moves, preventing it takes 10
"""
# OLL only applies for even cubes
if self.is_odd():
return False
7 years ago
orbits_with_oll_parity = self.center_solution_leads_to_oll_parity()
steps = None
if not orbits_with_oll_parity:
return False
7 years ago
if self.size == 4:
if orbits_with_oll_parity == [0]:
steps = "Rw U2 Rw U2 Rw U2 Rw U2 Rw U2"
else:
raise SolveError("prevent_OLL for %sx%sx%s, orbits %s have parity issues" %
(self.size, self.size, self.size, pformat(orbits_with_oll_parity)))
elif self.size == 6:
# 10 steps
if orbits_with_oll_parity == [0,1]:
steps = "3Rw U2 3Rw U2 3Rw U2 3Rw U2 3Rw U2"
# 10 steps
elif orbits_with_oll_parity == [0]:
steps = "Rw U2 Rw U2 Rw U2 Rw U2 Rw U2"
# 15 steps for an inside orbit
elif orbits_with_oll_parity == [1]:
steps = "3Rw Rw' U2 3Rw Rw' U2 3Rw Rw' U2 3Rw Rw' U2 3Rw Rw' U2"
else:
raise SolveError("prevent_OLL for %sx%sx%s, orbits %s have parity issues" %
(self.size, self.size, self.size, pformat(orbits_with_oll_parity)))
#else:
# raise ImplementThis("prevent_OLL for %sx%sx%s, orbits %s have parity issues" %
# (self.size, self.size, self.size, pformat(orbits_with_oll_parity)))
if steps:
for step in steps.split():
self.rotate(step)
return True
return False
def solve_OLL(self):
# Check all 12 edges, rotate the one with OLL to U-south
while True:
has_oll = False
if self.state[self.sideU.corner_pos[2]] == self.state[self.sideF.edge_north_pos[0]]:
has_oll = True
elif self.state[self.sideU.corner_pos[0]] == self.state[self.sideL.edge_north_pos[0]]:
has_oll = True
self.rotate_y_reverse()
elif self.state[self.sideU.corner_pos[3]] == self.state[self.sideR.edge_north_pos[0]]:
has_oll = True
self.rotate_y()
elif self.state[self.sideU.corner_pos[1]] == self.state[self.sideB.edge_north_pos[0]]:
has_oll = True
self.rotate_y()
self.rotate_y()
elif self.state[self.sideD.corner_pos[0]] == self.state[self.sideF.edge_south_pos[0]]:
has_oll = True
self.rotate_x()
elif self.state[self.sideD.corner_pos[0]] == self.state[self.sideL.edge_south_pos[0]]:
has_oll = True
self.rotate_y_reverse()
self.rotate_x()
elif self.state[self.sideD.corner_pos[1]] == self.state[self.sideR.edge_south_pos[0]]:
has_oll = True
self.rotate_y()
self.rotate_x()
elif self.state[self.sideD.corner_pos[2]] == self.state[self.sideB.edge_south_pos[0]]:
has_oll = True
self.rotate_y()
self.rotate_y()
self.rotate_x()
elif self.state[self.sideF.corner_pos[0]] == self.state[self.sideL.edge_east_pos[0]]:
has_oll = True
self.rotate_z()
elif self.state[self.sideF.corner_pos[1]] == self.state[self.sideR.edge_west_pos[0]]:
has_oll = True
self.rotate_z_reverse()
elif self.state[self.sideB.corner_pos[0]] == self.state[self.sideR.edge_east_pos[0]]:
has_oll = True
self.rotate_y()
self.rotate_z_reverse()
elif self.state[self.sideB.corner_pos[1]] == self.state[self.sideL.edge_west_pos[0]]:
has_oll = True
self.rotate_y_reverse()
self.rotate_z()
if has_oll:
# 26 moves :(
oll_solution = "%dRw2 R2 U2 %dRw2 R2 U2 %dRw R' U2 %dRw R' U2 %dRw' R' U2 B2 U %dRw' R U' B2 U %dRw R' U R2" % (self.size/2, self.size/2, self.size/2, self.size/2, self.size/2, self.size/2, self.size/2)
log.warning("Solving OLL %s" % oll_solution)
self.print_cube()
for step in oll_solution.split():
self.rotate(step)
else:
break
def solve_PLL(self):
pll_id = None
self.rotate_U_to_U()
self.rotate_F_to_F()
# rotate one of the hosed edges to U-south
if self.state[self.sideU.edge_south_pos[0]] != 'U':
pass
elif self.state[self.sideU.edge_north_pos[0]] != 'U':
self.rotate_y()
self.rotate_y()
elif self.state[self.sideU.edge_west_pos[0]] != 'U':
self.rotate_y_reverse()
elif self.state[self.sideU.edge_east_pos[0]] != 'U':
self.rotate_y()
elif self.state[self.sideL.edge_north_pos[0]] != 'L':
raise ImplementThis("pll")
elif self.state[self.sideL.edge_south_pos[0]] != 'L':
self.rotate_x()
self.rotate_x()
self.rotate_y_reverse()
elif self.state[self.sideL.edge_east_pos[0]] != 'L':
self.rotate_z()
elif self.state[self.sideL.edge_west_pos[0]] != 'L':
self.rotate_y_reverse()
self.rotate_z()
elif self.state[self.sideF.edge_north_pos[0]] != 'F':
raise ImplementThis("pll")
elif self.state[self.sideF.edge_south_pos[0]] != 'F':
self.rotate_x()
elif self.state[self.sideF.edge_east_pos[0]] != 'F':
self.rotate_z_reverse()
elif self.state[self.sideF.edge_west_pos[0]] != 'F':
raise ImplementThis("pll")
elif self.state[self.sideR.edge_north_pos[0]] != 'R':
raise ImplementThis("pll")
elif self.state[self.sideR.edge_south_pos[0]] != 'R':
self.rotate_y()
self.rotate_x()
elif self.state[self.sideR.edge_east_pos[0]] != 'R':
self.rotate_y()
self.rotate_z_reverse()
elif self.state[self.sideR.edge_west_pos[0]] != 'R':
raise ImplementThis("pll")
elif self.state[self.sideB.edge_north_pos[0]] != 'B':
raise ImplementThis("pll")
elif self.state[self.sideB.edge_south_pos[0]] != 'B':
self.rotate_x()
self.rotate_x()
elif self.state[self.sideB.edge_east_pos[0]] != 'B':
raise ImplementThis("pll")
elif self.state[self.sideB.edge_west_pos[0]] != 'B':
raise ImplementThis("pll")
elif self.state[self.sideD.edge_north_pos[0]] != 'D':
raise ImplementThis("pll")
elif self.state[self.sideD.edge_south_pos[0]] != 'D':
raise ImplementThis("pll")
elif self.state[self.sideD.edge_east_pos[0]] != 'D':
raise ImplementThis("pll")
elif self.state[self.sideD.edge_west_pos[0]] != 'D':
raise ImplementThis("pll")
else:
self.print_cube()
raise SolveError("we should not be here")
7 years ago
if self.state[self.sideF.edge_north_pos[0]] == 'F':
raise SolveError("F-north should have PLL edge")
# rotate the other hosed edges to U-west
if self.state[self.sideU.edge_south_pos[0]] != self.state[self.sideU.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideU.edge_north_pos[0]] != self.state[self.sideU.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideU.edge_west_pos[0]] != self.state[self.sideU.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideU.edge_east_pos[0]] != self.state[self.sideU.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideL.edge_north_pos[0]] != self.state[self.sideL.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideL.edge_south_pos[0]] != self.state[self.sideL.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideL.edge_east_pos[0]] != self.state[self.sideL.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideL.edge_west_pos[0]] != self.state[self.sideL.corner_pos[0]]:
self.rotate_y()
pll_id = 2
elif self.state[self.sideF.edge_south_pos[0]] != self.state[self.sideF.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideF.edge_east_pos[0]] != self.state[self.sideF.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideF.edge_west_pos[0]] != self.state[self.sideF.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideR.edge_north_pos[0]] != self.state[self.sideR.corner_pos[0]]:
self.rotate_y()
pll_id = 2
elif self.state[self.sideR.edge_south_pos[0]] != self.state[self.sideR.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideR.edge_east_pos[0]] != self.state[self.sideR.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideR.edge_west_pos[0]] != self.state[self.sideR.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideB.edge_north_pos[0]] != self.state[self.sideB.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideB.edge_south_pos[0]] != self.state[self.sideB.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideB.edge_east_pos[0]] != self.state[self.sideB.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideB.edge_west_pos[0]] != self.state[self.sideB.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideD.edge_north_pos[0]] != self.state[self.sideD.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideD.edge_south_pos[0]] != self.state[self.sideD.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideD.edge_east_pos[0]] != self.state[self.sideD.corner_pos[0]]:
raise ImplementThis("pll")
elif self.state[self.sideD.edge_west_pos[0]] != self.state[self.sideD.corner_pos[0]]:
raise ImplementThis("pll")
else:
raise Exception("we should not be here")
# http://www.speedcubing.com/chris/4speedsolve3.html
if pll_id == 2:
# Takes 12 steps
pll_solution = "L2 D %dFw2 %dLw2 F2 %dLw2 L2 F2 %dLw2 %dFw2 D' L2" % (self.size/2, self.size/2, self.size/2, self.size/2, self.size/2)
log.warning("Solving PLL ID %d: %s" % (pll_id, pll_solution))
self.print_cube()
for step in pll_solution.split():
self.rotate(step)
else:
raise ImplementThis("pll_id %s" % pll_id)
def solve_333(self):
if self.solved():
return
kociemba_string = self.get_kociemba_string(False)
try:
steps = subprocess.check_output(['kociemba', kociemba_string]).decode('ascii').splitlines()[-1].strip().split()
kociemba_ok = True
except Exception:
kociemba_ok = False
if not kociemba_ok:
#edge_swap_count = self.get_edge_swap_count(edges_paired=True, debug=True)
#corner_swap_count = self.get_corner_swap_count(debug=True)
#raise SolveError("parity error made kociemba barf, edge parity %d, corner parity %d, kociemba %s" %
# (edge_swap_count, corner_swap_count, kociemba_string))
raise SolveError("parity error made kociemba barf, kociemba %s" % kociemba_string)
log.debug("kociemba : %s" % kociemba_string)
log.debug("kociemba steps : %s" % ', '.join(steps))
for step in steps:
step = str(step)
self.rotate(step)
if not self.solved():
self.solve_OLL()
if not self.solved():
self.solve_PLL()
if not self.solved():
raise SolveError("We hit either OLL or PLL parity and could not solve it")
7 years ago
def get_corner_swap_count(self, debug=False):
needed_corners = [
'BLU',
'BRU',
'FLU',
'FRU',
'DFL',
'DFR',
'BDL',
'BDR']
to_check = [
(self.sideU.corner_pos[0], self.sideL.corner_pos[0], self.sideB.corner_pos[1]), # ULB
(self.sideU.corner_pos[1], self.sideR.corner_pos[1], self.sideB.corner_pos[0]), # URB
(self.sideU.corner_pos[2], self.sideL.corner_pos[1], self.sideF.corner_pos[0]), # ULF
(self.sideU.corner_pos[3], self.sideF.corner_pos[1], self.sideR.corner_pos[0]), # UFR
(self.sideD.corner_pos[0], self.sideL.corner_pos[3], self.sideF.corner_pos[2]), # DLF
(self.sideD.corner_pos[1], self.sideF.corner_pos[3], self.sideR.corner_pos[2]), # DFR
(self.sideD.corner_pos[2], self.sideL.corner_pos[2], self.sideB.corner_pos[3]), # DLB
(self.sideD.corner_pos[3], self.sideR.corner_pos[3], self.sideB.corner_pos[2]) # DRB
]
current_corners = []
for (square_index1, square_index2, square_index3) in to_check:
square1 = self.state[square_index1]
square2 = self.state[square_index2]
square3 = self.state[square_index3]
corner_str = ''.join(sorted([square1, square2, square3]))
current_corners.append(corner_str)
if debug:
log.info("to_check:\n%s" % pformat(to_check))
to_check_str = ''
for (a, b, c) in to_check:
to_check_str += "%4s" % a
log.info("to_check :%s" % to_check_str)
log.info("needed corners : %s" % ' '.join(needed_corners))
log.info("currnet corners: %s" % ' '.join(current_corners))
log.info("")
return get_swap_count(needed_corners, current_corners, debug)
def corner_swaps_even(self, debug=False):
if self.get_corner_swap_count(debug) % 2 == 0:
return True
return False
def corner_swaps_odd(self, debug=False):
if self.get_corner_swap_count(debug) % 2 == 1:
return True
return False
def get_edge_swap_count(self, edges_paired, orbit, debug=False):
needed_edges = []
to_check = []
# should not happen
if edges_paired and orbit is not None:
raise Exception("edges_paired is True and orbit is %s" % orbit)
edges_per_side = len(self.sideU.edge_north_pos)
# Upper
for (edge_index, square_index) in enumerate(self.sideU.edge_north_pos):
if edges_paired:
to_check.append(square_index)
needed_edges.append('UB')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('UB%d' % edge_index)
for (edge_index, square_index) in enumerate(reversed(self.sideU.edge_west_pos)):
if edges_paired:
to_check.append(square_index)
needed_edges.append('UL')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('UL%d' % edge_index)
for (edge_index, square_index) in enumerate(reversed(self.sideU.edge_south_pos)):
if edges_paired:
to_check.append(square_index)
needed_edges.append('UF')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('UF%d' % edge_index)
for (edge_index, square_index) in enumerate(self.sideU.edge_east_pos):
if edges_paired:
to_check.append(square_index)
needed_edges.append('UR')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('UR%d' % edge_index)
# Left
for (edge_index, square_index) in enumerate(reversed(self.sideL.edge_west_pos)):
if edges_paired:
to_check.append(square_index)
needed_edges.append('LB')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('LB%d' % edge_index)
for (edge_index, square_index) in enumerate(self.sideL.edge_east_pos):
if edges_paired:
to_check.append(square_index)
needed_edges.append('LF')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('LF%d' % edge_index)
# Right
for (edge_index, square_index) in enumerate(reversed(self.sideR.edge_west_pos)):
if edges_paired:
to_check.append(square_index)
needed_edges.append('RF')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('RF%d' % edge_index)
for (edge_index, square_index) in enumerate(self.sideR.edge_east_pos):
if edges_paired:
to_check.append(square_index)
needed_edges.append('RB')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('RB%d' % edge_index)
# Down
for (edge_index, square_index) in enumerate(self.sideD.edge_north_pos):
if edges_paired:
to_check.append(square_index)
needed_edges.append('DF')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('DF%d' % edge_index)
for (edge_index, square_index) in enumerate(reversed(self.sideD.edge_west_pos)):
if edges_paired:
to_check.append(square_index)
needed_edges.append('DL')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('DL%d' % edge_index)
for (edge_index, square_index) in enumerate(reversed(self.sideD.edge_south_pos)):
if edges_paired:
to_check.append(square_index)
needed_edges.append('DB')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('DB%d' % edge_index)
for (edge_index, square_index) in enumerate(self.sideD.edge_east_pos):
if edges_paired:
to_check.append(square_index)
needed_edges.append('DR')
break
else:
if orbit_matches(edges_per_side, orbit, edge_index):
to_check.append(square_index)
needed_edges.append('DR%d' % edge_index)
if debug:
to_check_str = ''
for x in to_check:
if edges_paired:
to_check_str += "%3s" % x
else:
to_check_str += "%4s" % x
log.info("to_check :%s" % to_check_str)
log.info("needed edges : %s" % ' '.join(needed_edges))
current_edges = []
for square_index in to_check:
side = self.get_side_for_index(square_index)
partner_index = side.get_wing_partner(square_index)
square1 = self.state[square_index]
square2 = self.state[partner_index]
if square1 in ('U', 'D'):
wing_str = square1 + square2
elif square2 in ('U', 'D'):
wing_str = square2 + square1
elif square1 in ('L', 'R'):
wing_str = square1 + square2
elif square2 in ('L', 'R'):
wing_str = square2 + square1
elif (square1, square2) == ('x', 'x'):
continue
7 years ago
else:
raise Exception("Could not determine wing_str for (%s, %s)" % (square1, square2))
if not edges_paired:
# - backup the current state
# - add an 'x' to the end of the square_index/partner_index
# - move square_index/partner_index to its final edge location
# - look for the 'x' to determine if this is the '0' vs '1' wing
# - restore the original state
square1_with_x = square1 + 'x'
square2_with_x = square2 + 'x'
original_state = self.state[:]
original_solution = self.solution[:]
self.state[square_index] = square1_with_x
self.state[partner_index] = square2_with_x
# 'UB0', 'UB1', 'UL0', 'UL1', 'UF0', 'UF1', 'UR0', 'UR1',
# 'LB0', 'LB1', 'LF0', 'LF1', 'RF0', 'RF1', 'RB0', 'RB1',
# 'DF0', 'DF1', 'DL0', 'DL1', 'DB0', 'DB1', 'DR0', 'DR1
if wing_str == 'UB':
self.move_wing_to_U_north(square_index)
edge_to_check = self.sideU.edge_north_pos
target_side = self.sideU
elif wing_str == 'UL':
self.move_wing_to_U_west(square_index)
edge_to_check = reversed(self.sideU.edge_west_pos)
target_side = self.sideU
elif wing_str == 'UF':
self.move_wing_to_U_south(square_index)
edge_to_check = reversed(self.sideU.edge_south_pos)
target_side = self.sideU
elif wing_str == 'UR':
self.move_wing_to_U_east(square_index)
edge_to_check = self.sideU.edge_east_pos
target_side = self.sideU
elif wing_str == 'LB':
self.move_wing_to_L_west(square_index)
edge_to_check = reversed(self.sideL.edge_west_pos)
target_side = self.sideL
elif wing_str == 'LF':
self.move_wing_to_L_east(square_index)
edge_to_check = self.sideL.edge_east_pos
target_side = self.sideL
elif wing_str == 'RF':
self.move_wing_to_R_west(square_index)
edge_to_check = reversed(self.sideR.edge_west_pos)
target_side = self.sideR
elif wing_str == 'RB':
self.move_wing_to_R_east(square_index)
edge_to_check = self.sideR.edge_east_pos
target_side = self.sideR
elif wing_str == 'DF':
self.move_wing_to_D_north(square_index)
edge_to_check = self.sideD.edge_north_pos
target_side = self.sideD
elif wing_str == 'DL':
self.move_wing_to_D_west(square_index)
edge_to_check = reversed(self.sideD.edge_west_pos)
target_side = self.sideD
elif wing_str == 'DB':
self.move_wing_to_D_south(square_index)
edge_to_check = reversed(self.sideD.edge_south_pos)
target_side = self.sideD
elif wing_str == 'DR':
self.move_wing_to_D_east(square_index)
edge_to_check = self.sideD.edge_east_pos
target_side = self.sideD
else:
raise SolveError("invalid wing %s" % wing_str)
for (edge_index, wing_index) in enumerate(edge_to_check):
wing_value = self.state[wing_index]
if wing_value.endswith('x'):
if wing_value.startswith(target_side.name):
wing_str += str(edge_index)
else:
max_edge_index = len(target_side.edge_east_pos) - 1
wing_str += str(max_edge_index - edge_index)
# This is commented out because we used this once upon a time to generate the
# orbit_index_444, etc dictionaries in https://github.com/dwalton76/rubiks-color-resolver
#
# The workflow was:
# - tweak code to call center_solution_leads_to_oll_parity() for odd cubes too
# - solve 500 cubes via "./utils/test.py --test-cubes utils/test_cubes.json --size 7x7x7"
# - sort /tmp/orbit_index.txt > /tmp/orbit_index_sorted.txt
# - cat /tmp/orbit_index_sorted.txt | uniq > /tmp/orbit_index_sorted_uniq.txt
#
# The lines in /tmp/orbit_index_sorted_uniq.txt are used to create orbit_index_777
'''
with open('/tmp/orbit_index.txt', 'a') as fh:
fh.write(" (%d, %d, '%s', '%s') : '%s',\n" % (square_index, partner_index, square1, square2, wing_str))
fh.write(" (%d, %d, '%s', '%s') : '%s',\n" % (partner_index, square_index, square2, square1, wing_str))
'''
7 years ago
break
else:
raise SolveError("Could not find wing %s (%d, %d) among %s" % (wing_str, square_index, partner_index, str(edge_to_check)))
self.state = original_state[:]
self.solution = original_solution[:]
current_edges.append(wing_str)
if debug:
log.info("current edges: %s" % ' '.join(current_edges))
return get_swap_count(needed_edges, current_edges, debug)
def edge_swaps_even(self, edges_paired, orbit, debug):
if self.get_edge_swap_count(edges_paired, orbit, debug) % 2 == 0:
return True
return False
def edge_swaps_odd(self, edges_paired, orbit, debug):
if self.get_edge_swap_count(edges_paired, orbit, debug) % 2 == 1:
return True
return False
def edge_solution_leads_to_pll_parity(self, debug=False):
self.rotate_U_to_U()
self.rotate_F_to_F()
if self.edge_swaps_even(edges_paired=True, orbit=None, debug=debug) == self.corner_swaps_even(debug):
if debug:
log.info("Predict we are free of PLL parity")
return False
if debug:
log.info("Predict we have PLL parity")
return True
def center_solution_leads_to_oll_parity(self, debug=False):
"""
http://www.speedcubing.com/chris/4speedsolve3.html
http://www.rubik.rthost.org/4x4x4_edges.htm
"""
if self.centers_solved():
self.rotate_U_to_U()
self.rotate_F_to_F()
7 years ago
orbits_with_oll_parity = []
orbits = int((self.size - 2) / 2)
7 years ago
for orbit in range(orbits):
7 years ago
# OLL Parity - "...is caused by solving the centers such that the edge permutation is odd"
# http://www.speedcubing.com/chris/4speedsolve3.html
if self.edge_swaps_odd(False, orbit, debug):
orbits_with_oll_parity.append(orbit)
#log.info("orbit %d has OLL parity" % orbit)
if not orbits_with_oll_parity:
log.debug("Predict we are free of OLL parity")
return orbits_with_oll_parity
def get_state_all(self):
result = []
for side in (self.sideU, self.sideL, self.sideF, self.sideR, self.sideB, self.sideD):
for square_index in range(side.min_pos, side.max_pos + 1):
7 years ago
result.append(self.state[square_index])
return ''.join(result)
def group_centers_guts(self):
raise ImplementThis("Child class must implement group_centers_guts")
def group_centers(self):
if self.is_odd():
self.rotate_U_to_U()
self.rotate_F_to_F()
7 years ago
if self.centers_solved():
self.rotate_U_to_U()
self.rotate_F_to_F()
7 years ago
log.info("group center solution: centers are already solved")
else:
log.info("")
log.info("")
log.info("")
self.group_centers_guts()
log.info("group center solution (%d steps in)" % (self.get_solution_len_minus_rotates(self.solution)))
if self.prevent_OLL():
log.info("prevented OLL (%d steps in)" % (self.get_solution_len_minus_rotates(self.solution)))
7 years ago
self.solution.append('CENTERS_SOLVED')
def get_wing_value(self, wing):
if isinstance(wing, tuple) or isinstance(wing, list):
square_index = wing[0]
else:
square_index = wing
side = self.get_side_for_index(square_index)
partner_index = side.get_wing_partner(square_index)
if square_index < partner_index:
return (self.state[square_index], self.state[partner_index])
else:
return (self.state[partner_index], self.state[square_index])
def get_solution_len_minus_rotates(self, solution):
count = 0
size_str = str(self.size)
for step in solution:
if step in ('CENTERS_SOLVED', 'EDGES_GROUPED'):
continue
7 years ago
if step in ("x", "x'", "x2",
"y", "y'", "y2",
"z", "z'", "z2"):
continue
7 years ago
if not step.startswith(size_str):
count += 1
return count
def compress_solution(self):
solution_string = []
for step in self.solution:
if step == "x":
step = "%dR" % self.size
elif step == "x'":
step = "%dR'" % self.size
elif step == "y":
step = "%dU" % self.size
elif step == "y'":
step = "%dU'" % self.size
elif step == "z":
step = "%dF" % self.size
elif step == "z'":
step = "%dF'" % self.size
solution_string.append(step)
moves = set(solution_string)
solution_string = ' '.join(solution_string)
7 years ago
while True:
original_solution_string = solution_string[:]
for move in moves:
if move in ('CENTERS_SOLVED', 'EDGES_GROUPED'):
continue
if move in ('x', 'y', 'z'):
raise Exception('compress_solution does not support move "%s"' % move)
if move.endswith("2'"):
raise Exception('compress_solution does not support move "%s"' % move)
if move.endswith("'"):
reverse_move = move[0:-1]
else:
reverse_move = move + "'"
# If the same half turn is done 2x in a row, remove it
if move.endswith("2"):
solution_string = solution_string.replace(" %s %s " % (move, move), " ")
else:
# If the same quarter turn is done 4x in a row, remove it
solution_string = solution_string.replace(" %s %s %s %s " % (move, move, move, move), " ")
# If the same quarter turn is done 3x in a row, replace it with one backwards move
solution_string = solution_string.replace(" %s %s %s " % (move, move, move), " %s " % reverse_move)
# If the same quarter turn is done 2x in a row, replace it with one half turn
# Do not bother doing this with whole cube rotations we will pull those out later
if not move.startswith(str(self.size)):
if move.endswith("'"):
solution_string = solution_string.replace(" %s %s " % (move, move), " %s2 " % move[0:-1])
else:
solution_string = solution_string.replace(" %s %s " % (move, move), " %s2 " % move)
# "F F'" and "F' F" will cancel each other out, remove them
solution_string = solution_string.replace(" %s %s " % (move, reverse_move), " ")
solution_string = solution_string.replace(" %s %s " % (reverse_move, move), " ")
if original_solution_string == solution_string:
break
# Remove full cube rotations by changing all of the steps that follow the cube rotation
steps = solution_string.strip().split()
final_steps = []
rotations = []
for (index, step) in enumerate(steps):
if step.startswith(str(self.size)):
rotations.append(apply_rotations(self.size, step, rotations))
else:
final_steps.append(apply_rotations(self.size, step, rotations))
solution_string = ' '.join(final_steps)
# We put some markers in the solution to track how many steps
# each stage took...remove those markers
solution_minus_markers = []
self.steps_to_rotate_cube = 0
self.steps_to_solve_centers = 0
self.steps_to_group_edges = 0
self.steps_to_solve_3x3x3 = 0
index = 0
# log.info("pre compress; %s" % ' '.join(self.solution))
for step in solution_string.split():
if step.startswith(str(self.size)):
self.steps_to_rotate_cube += 1
if step == 'CENTERS_SOLVED':
self.steps_to_solve_centers = index
index = 0
elif step == 'EDGES_GROUPED':
self.steps_to_group_edges = index
index = 0
else:
solution_minus_markers.append(step)
index += 1
self.steps_to_solve_3x3x3 = index
self.solution = solution_minus_markers
def solve(self):
"""
The RubiksCube222 and RubiksCube333 child classes will override
this since they don't need to group centers or edges
"""
solved_string = 'U' * self.squares_per_side +\
'L' * self.squares_per_side +\
'F' * self.squares_per_side +\
'R' * self.squares_per_side +\
'B' * self.squares_per_side +\
'D' * self.squares_per_side
if self.get_state_all() != solved_string:
self.group_centers()
self.group_edges()
self.rotate_U_to_U()
self.rotate_F_to_F()
self.solve_333()
self.compress_solution()
# Cube is solved, rotate it around so white is on top, etc
#self.rotate_U_to_U()
#self.rotate_F_to_F()
7 years ago
def print_solution(self):
# Print an alg.cubing.net URL for this setup/solution
url = "https://alg.cubing.net/?puzzle=%dx%dx%d&setup=" % (self.size, self.size, self.size)
url += '_'.join(reverse_steps(self.solution))
url += '&alg='
url += '_'.join(self.solution)
url = url.replace("'", "-")
print("\nURL : %s" % url)
print("\nSolution: %s" % ' '.join(self.solution))
7 years ago
if self.steps_to_rotate_cube:
print(("%d steps to rotate entire cube" % self.steps_to_rotate_cube))
7 years ago
if self.steps_to_solve_centers:
print(("%d steps to solve centers" % self.steps_to_solve_centers))
7 years ago
if self.steps_to_group_edges:
print(("%d steps to group edges" % self.steps_to_group_edges))
7 years ago
if self.steps_to_solve_3x3x3:
print(("%d steps to solve 3x3x3" % self.steps_to_solve_3x3x3))
7 years ago
print(("%d steps total" % len(self.solution)))
7 years ago
def edge_string_to_find(self, target_wing, sister_wing1, sister_wing2, sister_wing3):
edge_pos_square_index = (2, 3, 4, 6, 10, 11, 15, 16, 20, 22, 23, 24, 27,
28, 29, 31, 35, 36, 40, 41, 45, 47, 48, 49, 52, 53, 54, 56, 60, 61,
65, 66, 70, 72, 73, 74, 77, 78, 79, 81, 85, 86, 90, 91, 95, 97, 98,
99, 102, 103, 104, 106, 110, 111, 115, 116, 120, 122, 123, 124, 127,
128, 129, 131, 135, 136, 140, 141, 145, 147, 148, 149)
foo = {
target_wing[0] : 'A',
target_wing[1] : 'B',
sister_wing1[0] : 'C',
sister_wing1[1] : 'D',
sister_wing2[0] : 'E',
sister_wing2[1] : 'F',
sister_wing3[0] : 'G',
sister_wing3[1] : 'H',
}
return ''.join([foo.get(square_index, 'x') for square_index in edge_pos_square_index])
7 years ago
def nuke_corners(self):
for side in list(self.sides.values()):
for square_index in side.corner_pos:
self.state[square_index] = 'x'
def nuke_centers(self):
for side in list(self.sides.values()):
for square_index in side.center_pos:
self.state[square_index] = 'x'
def nuke_edges(self):
for side in list(self.sides.values()):
for square_index in side.edge_pos:
self.state[square_index] = 'x'
7 years ago
def www_header(self):
"""
Write the <head> including css
"""
side_margin = 10
square_size = 40
size = self.size # 3 for 3x3x3, etc
shutil.copy('www/solution.js', '/tmp/')
shutil.copy('www/Arrow-Next.png', '/tmp/')
shutil.copy('www/Arrow-Prev.png', '/tmp/')
with open('/tmp/solution.html', 'w') as fh:
fh.write("""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
div.clear {
clear: both;
}
div.clear_left {
clear: left;
}
.clickable {
cursor: pointer;
}
div.side {
margin: %dpx;
float: left;
}
a.prev_page {
float: left;
}
a.next_page {
float: right;
}
""" % side_margin)
for x in range(1, size-1):
fh.write("div.col%d,\n" % x)
fh.write("""div.col%d {
float: left;
}
div.col%d {
margin-left: %dpx;
}
div#upper,
div#down {
margin-left: %dpx;
}
""" % (size-1,
size,
(size - 1) * square_size,
(size * square_size) + (3 * side_margin)))
fh.write("""
span.square {
width: %dpx;
height: %dpx;
white-space-collapsing: discard;
display: inline-block;
color: black;
font-weight: bold;
line-height: %dpx;
text-align: center;
}
div.square {
width: %dpx;
height: %dpx;
color: black;
font-weight: bold;
line-height: %dpx;
text-align: center;
}
div.square span {
display: inline-block;
vertical-align: middle;
line-height: normal;
}
div.page {
display: none;
}
div#page_holder {
width: %dpx;
}
</style>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script type='text/javascript' src='http://code.jquery.com/ui/1.10.3/jquery-ui.min.js'></script>
<script type="text/javascript" src="solution.js"></script>
<title>CraneCuber</title>
</head>
<body>
<div id="page_holder">
""" % (square_size, square_size, square_size, square_size, square_size, square_size,
(square_size * size * 4) + square_size + (4 * side_margin)))
def www_write_cube(self, desc):
"""
'cube' is a list of (R,G,B) tuples
"""
cube = ['dummy',]
for square in self.state[1:]:
cube.append(self.color_map_html[square])
col = 1
squares_per_side = self.size * self.size
max_square = squares_per_side * 6
sides = ('upper', 'left', 'front', 'right', 'back', 'down')
side_index = -1
(first_squares, last_squares, last_UBD_squares) = get_important_square_indexes(self.size)
with open('/tmp/solution.html', 'a') as fh:
fh.write("<div class='page' style='display: none;'>\n")
fh.write("<h1>%s</h1>\n" % desc)
for index in range(1, max_square + 1):
if index in first_squares:
side_index += 1
fh.write("<div class='side' id='%s'>\n" % sides[side_index])
(red, green, blue) = cube[index]
fh.write(" <div class='square col%d' title='RGB (%d, %d, %d)' style='background-color: #%02x%02x%02x;'><span>%02d</span></div>\n" %
(col,
red, green, blue,
red, green, blue,
index))
if index in last_squares:
fh.write("</div>\n")
if index in last_UBD_squares:
fh.write("<div class='clear'></div>\n")
col += 1
if col == self.size + 1:
col = 1
fh.write("</div>\n")
def www_footer(self):
with open('/tmp/solution.html', 'a') as fh:
fh.write("""
<div id="sets-browse-controls">
<a class="prev_page" style="display: block;"><img src="Arrow-Prev.png" class="clickable" width="128"></a>
<a class="next_page" style="display: block;"><img src="Arrow-Next.png" class="clickable" width="128"></a>
</div>
</div>
</body>
</html>
""")
def test(self):
"""
Run some tests to sanity check some things
"""
for side in list(self.sides.values()):
for square_index in range(side.min_pos, side.max_pos+1):
7 years ago
self.state[square_index] = 'x'
original_state = self.state[:]
original_solution = self.solution[:]
for side in list(self.sides.values()):
7 years ago
for direction in ('north', 'south', 'east', 'west'):
if direction == 'north':
edges = side.edge_north_pos
elif direction == 'south':
edges = side.edge_south_pos
elif direction == 'east':
edges = side.edge_east_pos
elif direction == 'west':
edges = side.edge_west_pos
for edge_index in edges:
partner_index = side.get_wing_partner(edge_index)
self.state[edge_index] = 'U'
self.state[partner_index] = 'U'
tmp_state = self.state[:]
log.info("test move_wing for %s-%s (%d, %d)" % (side, direction, edge_index, partner_index))
# U-north
for index_to_test in (edge_index, partner_index):
self.move_wing_to_U_north(index_to_test)
for tmp_edge_index in self.sideU.edge_north_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_U_north failed")
self.state[:] = tmp_state
# U-south
for index_to_test in (edge_index, partner_index):
self.move_wing_to_U_south(index_to_test)
for tmp_edge_index in self.sideU.edge_south_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_U_south failed")
self.state[:] = tmp_state
# U-east
for index_to_test in (edge_index, partner_index):
self.move_wing_to_U_east(index_to_test)
for tmp_edge_index in self.sideU.edge_east_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_U_east failed")
self.state[:] = tmp_state
# U-west
for index_to_test in (edge_index, partner_index):
self.move_wing_to_U_west(index_to_test)
for tmp_edge_index in self.sideU.edge_west_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_U_west failed")
self.state[:] = tmp_state
# L-north
'''
for index_to_test in (edge_index, partner_index):
self.move_wing_to_L_north(index_to_test)
for tmp_edge_index in self.sideL.edge_north_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_L_north failed")
self.state[:] = tmp_state
'''
# L-south
'''
for index_to_test in (edge_index, partner_index):
self.move_wing_to_L_south(index_to_test)
for tmp_edge_index in self.sideL.edge_south_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_L_south failed")
self.state[:] = tmp_state
'''
# L-east
for index_to_test in (edge_index, partner_index):
self.move_wing_to_L_east(index_to_test)
for tmp_edge_index in self.sideL.edge_east_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_L_east failed for %d" % index_to_test)
self.state[:] = tmp_state
# L-west
for index_to_test in (edge_index, partner_index):
self.move_wing_to_L_west(index_to_test)
for tmp_edge_index in self.sideL.edge_west_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_L_west failed")
self.state[:] = tmp_state
# F-north
'''
for index_to_test in (edge_index, partner_index):
self.move_wing_to_F_north(index_to_test)
for tmp_edge_index in self.sideF.edge_north_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_F_north failed")
self.state[:] = tmp_state
'''
# F-south
'''
for index_to_test in (edge_index, partner_index):
self.move_wing_to_F_south(index_to_test)
for tmp_edge_index in self.sideF.edge_south_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_F_south failed")
self.state[:] = tmp_state
'''
# F-east
for index_to_test in (edge_index, partner_index):
self.move_wing_to_F_east(index_to_test)
for tmp_edge_index in self.sideF.edge_east_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_F_east failed")
self.state[:] = tmp_state
# F-west
for index_to_test in (edge_index, partner_index):
self.move_wing_to_F_west(index_to_test)
for tmp_edge_index in self.sideF.edge_west_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_F_west failed")
self.state[:] = tmp_state
# R-north
'''
for index_to_test in (edge_index, partner_index):
self.move_wing_to_R_north(index_to_test)
for tmp_edge_index in self.sideR.edge_north_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_R_north failed")
self.state[:] = tmp_state
'''
# R-south
'''
for index_to_test in (edge_index, partner_index):
self.move_wing_to_R_south(index_to_test)
for tmp_edge_index in self.sideR.edge_south_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_R_south failed")
self.state[:] = tmp_state
'''
# R-east
for index_to_test in (edge_index, partner_index):
self.move_wing_to_R_east(index_to_test)
for tmp_edge_index in self.sideR.edge_east_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_R_east failed")
self.state[:] = tmp_state
# R-west
for index_to_test in (edge_index, partner_index):
self.move_wing_to_R_west(index_to_test)
for tmp_edge_index in self.sideR.edge_west_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_R_west failed")
self.state[:] = tmp_state
# B-north
'''
for index_to_test in (edge_index, partner_index):
self.move_wing_to_B_north(index_to_test)
for tmp_edge_index in self.sideB.edge_north_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_B_north failed")
self.state[:] = tmp_state
'''
# B-south
'''
for index_to_test in (edge_index, partner_index):
self.move_wing_to_B_south(index_to_test)
for tmp_edge_index in self.sideB.edge_south_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_B_south failed")
self.state[:] = tmp_state
'''
# B-east
'''
for index_to_test in (edge_index, partner_index):
self.move_wing_to_B_east(index_to_test)
for tmp_edge_index in self.sideB.edge_east_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_B_east failed")
self.state[:] = tmp_state
'''
# B-west
'''
for index_to_test in (edge_index, partner_index):
self.move_wing_to_B_west(index_to_test)
for tmp_edge_index in self.sideB.edge_west_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_B_west failed")
self.state[:] = tmp_state
'''
# D-north
for index_to_test in (edge_index, partner_index):
self.move_wing_to_D_north(index_to_test)
for tmp_edge_index in self.sideD.edge_north_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_D_north failed")
self.state[:] = tmp_state
# D-south
for index_to_test in (edge_index, partner_index):
self.move_wing_to_D_south(index_to_test)
for tmp_edge_index in self.sideD.edge_south_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_D_south failed")
self.state[:] = tmp_state
# D-east
for index_to_test in (edge_index, partner_index):
self.move_wing_to_D_east(index_to_test)
for tmp_edge_index in self.sideD.edge_east_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_D_east failed")
self.state[:] = tmp_state
# D-west
for index_to_test in (edge_index, partner_index):
self.move_wing_to_D_west(index_to_test)
for tmp_edge_index in self.sideD.edge_west_pos:
if self.state[tmp_edge_index] == 'U':
break
else:
raise SolveError("move_wing_to_D_west failed")
self.state[:] = tmp_state
self.state[:] = original_state
self.state[:] = original_state
def rotate_to_side(self, upper_side_name, front_side_name):
if upper_side_name == front_side_name:
return False
if upper_side_name == 'U':
if front_side_name == 'D':
return False
if front_side_name == 'L':
self.rotate_y_reverse()
elif front_side_name == 'F':
pass
elif front_side_name == 'R':
self.rotate_y()
elif front_side_name == 'B':
self.rotate_y()
self.rotate_y()
elif upper_side_name == 'D':
if front_side_name == 'U':
return False
self.rotate_x()
self.rotate_x()
if front_side_name == 'L':
self.rotate_y_reverse()
elif front_side_name == 'F':
self.rotate_y()
self.rotate_y()
elif front_side_name == 'R':
self.rotate_y()
elif front_side_name == 'B':
pass
elif upper_side_name == 'L':
if front_side_name == 'R':
return False
self.rotate_y_reverse()
self.rotate_x()
# dwalton
if front_side_name == 'U':
self.rotate_y()
self.rotate_y()
elif front_side_name == 'F':
self.rotate_y()
elif front_side_name == 'D':
pass
elif front_side_name == 'B':
self.rotate_y_reverse()
elif upper_side_name == 'F':
if front_side_name == 'B':
return False
self.rotate_x()
if front_side_name == 'L':
self.rotate_y_reverse()
elif front_side_name == 'U':
self.rotate_y()
self.rotate_y()
elif front_side_name == 'R':
self.rotate_y()
elif front_side_name == 'D':
pass
elif upper_side_name == 'R':
if front_side_name == 'L':
return False
self.rotate_y()
self.rotate_x()
if front_side_name == 'U':
self.rotate_y()
self.rotate_y()
elif front_side_name == 'F':
self.rotate_y_reverse()
elif front_side_name == 'D':
pass
elif front_side_name == 'B':
self.rotate_y()
elif upper_side_name == 'B':
if front_side_name == 'F':
return False
self.rotate_x_reverse()
if front_side_name == 'L':
self.rotate_y_reverse()
elif front_side_name == 'U':
pass
elif front_side_name == 'R':
self.rotate_y()
elif front_side_name == 'D':
self.rotate_y()
self.rotate_y()
return True
def transform_x(self):
for side in (self.sideU, self.sideL, self.sideF, self.sideR, self.sideB, self.sideD):
for square_index in range(side.min_pos, side.max_pos+1):
if self.state[square_index] == 'U':
self.state[square_index] = 'B'
elif self.state[square_index] == 'L':
pass
elif self.state[square_index] == 'F':
self.state[square_index] = 'U'
elif self.state[square_index] == 'R':
pass
elif self.state[square_index] == 'B':
self.state[square_index] = 'D'
elif self.state[square_index] == 'D':
self.state[square_index] = 'F'
def transform_x_prime(self):
for side in (self.sideU, self.sideL, self.sideF, self.sideR, self.sideB, self.sideD):
for square_index in range(side.min_pos, side.max_pos+1):
if self.state[square_index] == 'U':
self.state[square_index] = 'F'
elif self.state[square_index] == 'L':
pass
elif self.state[square_index] == 'F':
self.state[square_index] = 'D'
elif self.state[square_index] == 'R':
pass
elif self.state[square_index] == 'B':
self.state[square_index] = 'U'
elif self.state[square_index] == 'D':
self.state[square_index] = 'B'
def transform_y(self):
for side in (self.sideU, self.sideL, self.sideF, self.sideR, self.sideB, self.sideD):
for square_index in range(side.min_pos, side.max_pos+1):
if self.state[square_index] == 'U':
pass
elif self.state[square_index] == 'L':
self.state[square_index] = 'B'
elif self.state[square_index] == 'F':
self.state[square_index] = 'L'
elif self.state[square_index] == 'R':
self.state[square_index] = 'F'
elif self.state[square_index] == 'B':
self.state[square_index] = 'R'
elif self.state[square_index] == 'D':
pass
def transform_y_prime(self):
for side in (self.sideU, self.sideL, self.sideF, self.sideR, self.sideB, self.sideD):
for square_index in range(side.min_pos, side.max_pos+1):
if self.state[square_index] == 'U':
pass
elif self.state[square_index] == 'L':
self.state[square_index] = 'F'
elif self.state[square_index] == 'F':
self.state[square_index] = 'R'
elif self.state[square_index] == 'R':
self.state[square_index] = 'B'
elif self.state[square_index] == 'B':
self.state[square_index] = 'L'
elif self.state[square_index] == 'D':
pass
def transform_z(self):
for side in (self.sideU, self.sideL, self.sideF, self.sideR, self.sideB, self.sideD):
for square_index in range(side.min_pos, side.max_pos+1):
if self.state[square_index] == 'U':
self.state[square_index] = 'R'
elif self.state[square_index] == 'L':
self.state[square_index] = 'U'
elif self.state[square_index] == 'F':
pass
elif self.state[square_index] == 'R':
self.state[square_index] = 'D'
elif self.state[square_index] == 'B':
pass
elif self.state[square_index] == 'D':
self.state[square_index] = 'L'
def transform_z_prime(self):
for side in (self.sideU, self.sideL, self.sideF, self.sideR, self.sideB, self.sideD):
for square_index in range(side.min_pos, side.max_pos+1):
if self.state[square_index] == 'U':
self.state[square_index] = 'L'
elif self.state[square_index] == 'L':
self.state[square_index] = 'D'
elif self.state[square_index] == 'F':
pass
elif self.state[square_index] == 'R':
self.state[square_index] = 'U'
elif self.state[square_index] == 'B':
pass
elif self.state[square_index] == 'D':
self.state[square_index] = 'R'
def transform(self, target):
"""
This should cover every scenario:
rotations = (
(),
("y",),
("y'",),
("y", "y"),
("x", "x", "y"),
("x", "x", "y'"),
("x", "x", "y", "y"),
("y'", "x", "y"),
("y'", "x", "y'"),
("y'", "x", "y", "y"),
("x", "y"),
("x", "y'"),
("x", "y", "y"),
("y", "x", "y"),
("y", "x", "y'"),
("y", "x", "y", "y"),
("x'", "y"),
("x'", "y'"),
("x'", "y", "y")
)
"""
if not target:
pass
elif target == "x":
self.transform_x()
elif target == "x'":
self.transform_x_prime()
elif target == "y":
self.transform_y()
elif target == "y'":
self.transform_y_prime()
elif target == "z":
self.transform_z()
elif target == "z'":
self.transform_z_prime()
else:
raise Exception("Implement target %s" % target)