def make_cube(): from solve import simplify_algorithm from cube import Rotation scramble = [ Rotation(step) for step in "R2 U R U' B U' L F' L' D2".split() ] cross_solve = [Rotation(step) for step in "D' B2 D' F B".split()] setup = simplify_algorithm(scramble + cross_solve) print('Scrambling:', ' '.join(map(str, setup))) return Cube(setup)
def solve(self): u_cubies = set( filter( lambda cubie: Side.U in cubie.faces and len(cubie.faces) > 1, self.cube.cubies)) positions = { _positions[_cubie_set(cubie.faces)]: _positions[_cubie_set(cubie.faces.values())] for cubie in u_cubies } positions = tuple(positions[i] for i in range(len(positions))) prefix = '' while positions not in cases: prefix += 'U ' positions = tuple(positions[-2:] + positions[:-2]) if not simplify_algorithm([Rotation(s) for s in prefix.split()]): raise NotImplementedError(f"Case not handled: {positions}") return simplify_algorithm( [Rotation(step) for step in (prefix + cases[positions]).split()])
def solve(self): solved_cube = Cube() goals = {self.cross_state(solved_cube): []} for i in range(3): for state, path in tuple(filter(lambda kv: len(kv[1]) == i, goals.items())): successors = self.successors(path, solved_cube) goals.update({s: p for s, p in successors.items() if s not in goals}) # Reverse algorithms in goals goals = {k: [Rotation(r).reverse().name for r in v[::-1]] for k, v in goals.items()} goals_set = set(goals) start_state = self.cross_state(self.cube) paths = new_paths = {start_state: []} while not (goals_set & set(new_paths)): next_paths = {} for state, path in new_paths.items(): successors = self.successors(path) next_paths.update({s: p for s, p in successors.items() if s not in paths}) paths.update(next_paths) new_paths = next_paths state = (goals_set & set(paths)).pop() return [Rotation(step) for step in paths[state] + goals[state]]
def solve(self): # Get list of how many clockwise twists/flips each cubie needs, starting with LUB and working clockwise u_cycle = Rotation('U').seq cubies = [ self.cube['U' + loc] for loc in ('LB', 'B', 'RB', 'R', 'RF', 'F', 'LF', 'L') ] def count_rotations(cubie): u_loc = {v: k for k, v in cubie.faces.items()}[Side.U] if u_loc == Side.U: return 0 elif u_cycle[u_loc] in cubie.faces: return 2 else: return 1 states = tuple(count_rotations(c) for c in cubies) prefix = '' while states not in cases: prefix += 'U ' states = tuple(states[-2:] + states[:-2]) return simplify_algorithm( [Rotation(step) for step in (prefix + cases[states]).split()])
def _combine_rotations(r1, r2): if isinstance(r1, str): r1 = Rotation(r1) if isinstance(r2, str): r2 = Rotation(r2) if r1.face != r2.face: raise ValueError("Cannot combine rotations from different faces") base_seq = Rotation(r1.face.name).seq seq = {k: r2.seq[v] for k, v in r1.seq.items()} count_seq = {k: k for k in seq} quarter_turns = 0 while count_seq != seq: count_seq = {k: base_seq[v] for k, v in count_seq.items()} quarter_turns += 1 if quarter_turns == 0: return Rotation(None) modifier = {1: '', 2: '2', 3: "'"}[quarter_turns] rot = Rotation(r1) rot.seq = seq rot.name = rot.name[0] + modifier return rot
def get_case_solution(pair): permuter = Rotation('U') permuter.seq[Side.U] = Side.U permuter.seq[Side.D] = Side.D edge, corner = pair.edge.copy(), pair.corner.copy() if all(k == v for k, v in edge.faces.items()) and all( k == v for k, v in corner.faces.items()): return [] algorithm = [] if Side.U not in edge.faces and set(edge.faces) != set( edge.faces.values()): # The edge is not in the U layer, but it's also not in its own slot. Come back to this pair. return None if Side.D in corner.faces and set(corner.faces) != set( corner.faces.values()): # The corner is in the D layer, but it's also not in its own slot. Come back to this pair. return None # There are two types of transformation to be used. The transform rotation is the number of y turns to do in order # to simplify the case down to the RF edge pair, which simplifies algorithm lookup. The alignment rotation is the # number of U turns to prepend to the algorithm. transform_rotations = 0 while not set(edge.faces.values()) == {Side.R, Side.F}: edge.faces = { permuter.seq[k]: permuter.seq[v] for k, v in edge.faces.items() } corner.faces = { permuter.seq[k]: permuter.seq[v] for k, v in corner.faces.items() } transform_rotations -= 1 transform_rotations %= 4 # How many U turns are needed to align? If the corner is in the U face, then in needs to be in the RUF position. # Otherwise, the edge needs to be lined up so that the side lines up (UF->RF or RU->RF) if Side.U in corner.faces: while not set(edge.faces.values()) <= set(corner.faces): edge.faces = {permuter.seq[k]: v for k, v in edge.faces.items()} corner.faces = { permuter.seq[k]: v for k, v in corner.faces.items() } algorithm.append(Rotation('U')) elif Side.U in edge.faces: while not any(k == v for k, v in edge.faces.items()): edge.faces = { permuter.seq[k2]: v2 for k2, v2 in edge.faces.items() } algorithm.append(Rotation('U')) # List the cases! 42 total. Case numbers are according to https://www.speedsolving.com/wiki/index.php/F2L base = '' if Side.D in corner.faces: # Corner in place if Side.U in edge.faces: # Edge in U layer if corner.D == Side.D: # Corner oriented if edge.U == Side.F: # Case 25 base = "U' R' F R F' R U R'" else: # Case 26 base = "U R U' R' U' F' U F" elif corner.F == Side.D: # D color on F face if edge.U == Side.F: # Case 27 base = "R U' R' U R U' R'" else: # Case 29 base = "F' U' F U F' U' F" elif corner.R == Side.D: # D color on R face if edge.U == Side.F: # Case 30 base = "R U R' U' R U R'" else: # Case 28 base = "R U R' U' F R' F' R" else: # Edge in place if all(k == v for k, v in edge.faces.items()): # Edge solved if corner.D == Side.D: # Corner is in place and oriented # Case 37 (solved) pass elif corner.F == Side.D: # Case 39 base = "R U' R' U' R U R' U2 R U' R'" else: # Case 40 base = "R U' R' U R U2 R' U R U' R'" else: # Edge twisted if corner.D == Side.D: # Corner in place and oriented # Case 38 base = "R' F R F' R U' R' U R U' R' U2 R U' R'" elif corner.F == Side.D: # Case 41 base = "R U' R' U F' U' F U' F' U' F" else: # Case 42 base = "R U' R' U2 F' U' F U' F' U F" else: # Corner in U face if Side.U in edge.faces: # Edge in U layer if corner.F == Side.D: # D color on F face if edge.U == Side.F: if Side.L in edge.faces: # Case 7 base = "U' R U2 R' U2 R U' R'" elif Side.R in edge.faces: # Case 1 base = "U R U' R'" elif Side.F in edge.faces: # Case 15 base = "R B L U' L' B' R'" elif Side.B in edge.faces: # Case 5 base = "U' R U R' U2 R U' R'" else: # Edge's R color on U face if Side.L in edge.faces: # Case 3 base = "F' U' F" elif Side.R in edge.faces: # Case 11 base = "U' R U2 R' U F' U' F" elif Side.F in edge.faces: # Case 13 base = "U F' U F U' F' U' F" elif Side.B in edge.faces: # Case 9 base = "U' R U' R' U F' U' F" elif corner.R == Side.D: # D color on R face if edge.U == Side.F: if Side.L in edge.faces: # Case 10 base = "U' R U R' U R U R'" elif Side.R in edge.faces: # Case 14 base = "U' R U' R' U R U R'" elif Side.F in edge.faces: # Case 12 base = "R U' R' U R U' R' U2 R U' R'" elif Side.B in edge.faces: # Case 4 base = "R U R'" else: # Edge's R color on U face if Side.L in edge.faces: # Case 6 base = "U F' U' F U2 F' U F" elif Side.R in edge.faces: # Case 16 base = "R U' R' U2 F' U' F" elif Side.F in edge.faces: # Case 2 base = "U' F' U F" else: # Side.B # Case 8 base = "U F' U2 F U2 F' U F" else: # D color on U face if edge.U == Side.F: if Side.L in edge.faces: # Case 21 base = "R U' R' U2 R U R'" elif Side.R in edge.faces: # Case 17 base = "R U2 R' U' R U R'" elif Side.F in edge.faces: # Case 23 base = "U2 R2 U2 R' U' R U' R2" else: # Side.B # Case 19 base = "U R U2 R2 F R F'" else: # Edge's R color on U face if Side.L in edge.faces: # Case 20 base = "U' F' U2 F2 R' F' R" elif Side.R in edge.faces: # Case 24 base = "U F' L' U L F R U R'" elif Side.F in edge.faces: # Case 18 base = "F' U2 F U F' U' F" else: # Side.B # Case 22 base = "F' U F U2 F' U' F" else: # (Corner in U Face), Edge in place if all(k == v for k, v in edge.faces.items()): # Edge solved if corner.U == Side.U: # Case 32 base = "R U R' U' R U R' U' R U R'" elif corner.F == Side.U: # Case 33 base = "U' R U' R' U2 R U' R'" else: # Case 34 base = "U F' U F U2 F' U F" else: # Edge twisted if corner.U == Side.U: # Case 31 base = "R U' R' U F' U F" elif corner.F == Side.U: # Case 35 base = "U' R U R' U F' U' F" else: # Case 36 base = "U F' U' F U' R U R'" algorithm.extend([Rotation(step) for step in base.split()]) return rotate_algorithm(simplify_algorithm(algorithm), transform_rotations)
def map_rotation(rotation): new_base = mapping[rotation.name[0]] name = new_base + rotation.name[1:] return Rotation(name)
scramble = "F' U' B2 U2 L2 D' B L' U B L2 D B L F' R' B' R' F2 D F' R D' L2 U'" my_cube = Cube(scramble) my_cube.ascii() # cross_solve = CrossSolver(my_cube).solve() cross_solve = "B2 L2 D R' D' B' R" my_cube.do(cross_solve) # print('Cross solved:', ' '.join(r.name for r in cross_solve)) # my_cube.ascii() # f2l_solve = F2LSolver(cube).solve() f2l_solve = "L' U' L U2 R U2 R2 F R F' U' B' U B U2 B' U' B B U' B' U' R' U R" my_cube.do(f2l_solve) # print('F2L solved', ' '.join(r.name for r in f2l_solve)) print('Post-F2L:') my_cube.ascii() sleep(1) print( 'Full prep:', ' '.join(s.name for s in simplify_algorithm( [Rotation(s) for s in scramble.split()] + [Rotation(s) for s in cross_solve.split()] + [Rotation(s) for s in f2l_solve.split()]))) oll_solve = OLLSolver(my_cube).solve() my_cube.do(oll_solve) print('OLL solved', oll_solve) my_cube.ascii()