def create_phase2_edgemerge_table(): """phase2_edgemerge retrieves the initial phase 2 ud_edges coordinate from the u_edges and d_edges coordinates.""" fname = "phase2_edgemerge" global u_edges_plus_d_edges_to_ud_edges c_u = cb.CubieCube() c_d = cb.CubieCube() c_ud = cb.CubieCube() edge_u = [Ed.UR, Ed.UF, Ed.UL, Ed.UB] edge_d = [Ed.DR, Ed.DF, Ed.DL, Ed.DB] edge_ud = [Ed.UR, Ed.UF, Ed.UL, Ed.UB, Ed.DR, Ed.DF, Ed.DL, Ed.DB] if not path.isfile(fname): cnt = 0 print("creating " + fname + " table...") u_edges_plus_d_edges_to_ud_edges = ar.array( 'H', [0 for i in range(N_U_EDGES_PHASE2 * N_PERM_4)]) for i in range(N_U_EDGES_PHASE2): c_u.set_u_edges(i) for j in range(N_CHOOSE_8_4): c_d.set_d_edges(j * N_PERM_4) invalid = False for e in edge_ud: c_ud.ep[e] = -1 # invalidate edges if c_u.ep[e] in edge_u: c_ud.ep[e] = c_u.ep[e] if c_d.ep[e] in edge_d: c_ud.ep[e] = c_d.ep[e] if c_ud.ep[e] == -1: invalid = True # edge collision break if not invalid: for k in range(N_PERM_4): c_d.set_d_edges(j * N_PERM_4 + k) for e in edge_ud: if c_u.ep[e] in edge_u: c_ud.ep[e] = c_u.ep[e] if c_d.ep[e] in edge_d: c_ud.ep[e] = c_d.ep[e] u_edges_plus_d_edges_to_ud_edges[ N_PERM_4 * i + k] = c_ud.get_ud_edges() cnt += 1 if cnt % 2000 == 0: print('.', end='', flush=True) print() fh = open(fname, "wb") u_edges_plus_d_edges_to_ud_edges.tofile(fh) fh.close() print() else: fh = open(fname, "rb") u_edges_plus_d_edges_to_ud_edges = ar.array('H') u_edges_plus_d_edges_to_ud_edges.fromfile(fh, N_U_EDGES_PHASE2 * N_PERM_4)
def run(self): cb = None if self.rot == 0: # no rotation cb = cubie.CubieCube(self.cb_cube.cp, self.cb_cube.co, self.cb_cube.ep, self.cb_cube.eo) elif self.rot == 1: # conjugation by 120° rotation cb = cubie.CubieCube(sy.symCube[32].cp, sy.symCube[32].co, sy.symCube[32].ep, sy.symCube[32].eo) cb.multiply(self.cb_cube) cb.multiply(sy.symCube[16]) elif self.rot == 2: # conjugation by 240° rotation cb = cubie.CubieCube(sy.symCube[16].cp, sy.symCube[16].co, sy.symCube[16].ep, sy.symCube[16].eo) cb.multiply(self.cb_cube) cb.multiply(sy.symCube[32]) if self.inv == 1: # invert cube tmp = cubie.CubieCube() cb.inv_cubie_cube(tmp) cb = tmp self.co_cube = coord.CoordCube(cb) # the rotated/inverted cube in coordinate representation dist = self.co_cube.get_depth_phase1() for togo1 in range(dist, 20): # iterative deepening, solution has at least dist moves self.sofar_phase1 = [] self.search(self.co_cube.flip, self.co_cube.twist, self.co_cube.slice_sorted, dist, togo1)
def create_phase1_prun_table(): """Create/load the flipslice_twist_depth3 pruning table for phase 1.""" global flipslice_twist_depth3 total = defs.N_FLIPSLICE_CLASS * defs.N_TWIST fname = "phase1_prun" if not path.isfile(fname): print("creating " + fname + " table...") print('This may take half an hour or even longer, depending on the hardware.') flipslice_twist_depth3 = ar.array('L', [0xffffffff] * (total // 16 + 1)) # #################### create table with the symmetries of the flipslice classes ############################### cc = cb.CubieCube() fs_sym = ar.array('H', [0] * defs.N_FLIPSLICE_CLASS) for i in range(defs.N_FLIPSLICE_CLASS): if (i + 1) % 1000 == 0: print('.', end='', flush=True) rep = sy.flipslice_rep[i] cc.set_slice(rep // defs.N_FLIP) cc.set_flip(rep % defs.N_FLIP) for s in range(defs.N_SYM_D4h): ss = cb.CubieCube(sy.symCube[s].cp, sy.symCube[s].co, sy.symCube[s].ep, sy.symCube[s].eo) # copy cube ss.edge_multiply(cc) # s*cc ss.edge_multiply(sy.symCube[sy.inv_idx[s]]) # s*cc*s^-1 if ss.get_slice() == rep // defs.N_FLIP and ss.get_flip() == rep % defs.N_FLIP: fs_sym[i] |= 1 << s print() # ################################################################################################################## fs_classidx = 0 # value for solved phase 1 twist = 0 set_flipslice_twist_depth3(defs.N_TWIST * fs_classidx + twist, 0) done = 1 depth = 0 backsearch = False print('depth:', depth, 'done: ' + str(done) + '/' + str(total)) while done != total: depth3 = depth % 3 if depth == 9: # backwards search is faster for depth >= 9 print('flipping to backwards search...') backsearch = True if depth < 8: mult = 5 # controls the output a few lines below else: mult = 1 idx = 0 for fs_classidx in range(defs.N_FLIPSLICE_CLASS): if (fs_classidx + 1) % (200 * mult) == 0: print('.', end='', flush=True) if (fs_classidx + 1) % (16000 * mult) == 0: print('') twist = 0 while twist < defs.N_TWIST: # ########## if table entries are not populated, this is very fast: ################################ if not backsearch and idx % 16 == 0 and flipslice_twist_depth3[idx // 16] == 0xffffffff \ and twist < defs.N_TWIST - 16: twist += 16 idx += 16 continue #################################################################################################### if backsearch: match = (get_flipslice_twist_depth3(idx) == 3) else: match = (get_flipslice_twist_depth3(idx) == depth3) if match: flipslice = sy.flipslice_rep[fs_classidx] flip = flipslice % 2048 # defs.N_FLIP = 2048 slice_ = flipslice >> 11 # // defs.N_FLIP for m in enums.Move: twist1 = mv.twist_move[18 * twist + m] # defs.N_MOVE = 18 flip1 = mv.flip_move[18 * flip + m] slice1 = mv.slice_sorted_move[432 * slice_ + m] // 24 # defs.N_PERM_4 = 24, 18*24 = 432 flipslice1 = (slice1 << 11) + flip1 fs1_classidx = sy.flipslice_classidx[flipslice1] fs1_sym = sy.flipslice_sym[flipslice1] twist1 = sy.twist_conj[(twist1 << 4) + fs1_sym] idx1 = 2187 * fs1_classidx + twist1 # defs.N_TWIST = 2187 if not backsearch: if get_flipslice_twist_depth3(idx1) == 3: # entry not yet filled set_flipslice_twist_depth3(idx1, (depth + 1) % 3) done += 1 # ####symmetric position has eventually more than one representation ############### sym = fs_sym[fs1_classidx] if sym != 1: for j in range(1, 16): sym >>= 1 if sym % 2 == 1: twist2 = sy.twist_conj[(twist1 << 4) + j] # fs2_classidx = fs1_classidx due to symmetry idx2 = 2187 * fs1_classidx + twist2 if get_flipslice_twist_depth3(idx2) == 3: set_flipslice_twist_depth3(idx2, (depth + 1) % 3) done += 1 #################################################################################### else: # backwards search if get_flipslice_twist_depth3(idx1) == depth3: set_flipslice_twist_depth3(idx, (depth + 1) % 3) done += 1 break twist += 1 idx += 1 # idx = defs.N_TWIST * fs_class + twist depth += 1 print() print('depth:', depth, 'done: ' + str(done) + '/' + str(total)) fh = open(fname, "wb") flipslice_twist_depth3.tofile(fh) else: print("loading " + fname + " table...") fh = open(fname, "rb") flipslice_twist_depth3 = ar.array('L') flipslice_twist_depth3.fromfile(fh, total // 16 + 1) fh.close()
def create_phase2_prun_table(): """Create/load the corners_ud_edges_depth3 pruning table for phase 2.""" total = defs.N_CORNERS_CLASS * defs.N_UD_EDGES fname = "phase2_prun" global corners_ud_edges_depth3 if not path.isfile(fname): print("creating " + fname + " table...") corners_ud_edges_depth3 = ar.array('L', [0xffffffff] * (total // 16)) # ##################### create table with the symmetries of the corners classes ################################ cc = cb.CubieCube() c_sym = ar.array('H', [0] * defs.N_CORNERS_CLASS) for i in range(defs.N_CORNERS_CLASS): if (i + 1) % 1000 == 0: print('.', end='', flush=True) rep = sy.corner_rep[i] cc.set_corners(rep) for s in range(defs.N_SYM_D4h): ss = cb.CubieCube(sy.symCube[s].cp, sy.symCube[s].co, sy.symCube[s].ep, sy.symCube[s].eo) # copy cube ss.corner_multiply(cc) # s*cc ss.corner_multiply(sy.symCube[sy.inv_idx[s]]) # s*cc*s^-1 if ss.get_corners() == rep: c_sym[i] |= 1 << s print() ################################################################################################################ c_classidx = 0 # value for solved phase 2 ud_edge = 0 set_corners_ud_edges_depth3(defs.N_UD_EDGES * c_classidx + ud_edge, 0) done = 1 depth = 0 print('depth:', depth, 'done: ' + str(done) + '/' + str(total)) while depth < 10: # we fill the table only do depth 9 + 1 depth3 = depth % 3 idx = 0 mult = 2 if depth > 9: mult = 1 for c_classidx in range(defs.N_CORNERS_CLASS): if (c_classidx + 1) % (20 * mult) == 0: print('.', end='', flush=True) if (c_classidx + 1) % (1600 * mult) == 0: print('') ud_edge = 0 while ud_edge < defs.N_UD_EDGES: # ################ if table entries are not populated, this is very fast: ########################## if idx % 16 == 0 and corners_ud_edges_depth3[idx // 16] == 0xffffffff \ and ud_edge < defs.N_UD_EDGES - 16: ud_edge += 16 idx += 16 continue #################################################################################################### if get_corners_ud_edges_depth3(idx) == depth3: corner = sy.corner_rep[c_classidx] # only iterate phase 2 moves for m in (enums.Move.U1, enums.Move.U2, enums.Move.U3, enums.Move.R2, enums.Move.F2, enums.Move.D1, enums.Move.D2, enums.Move.D3, enums.Move.L2, enums.Move.B2): ud_edge1 = mv.ud_edges_move[18 * ud_edge + m] corner1 = mv.corners_move[18 * corner + m] c1_classidx = sy.corner_classidx[corner1] c1_sym = sy.corner_sym[corner1] ud_edge1 = sy.ud_edges_conj[(ud_edge1 << 4) + c1_sym] idx1 = 40320 * c1_classidx + ud_edge1 # N_UD_EDGES = 40320 if get_corners_ud_edges_depth3(idx1) == 3: # entry not yet filled set_corners_ud_edges_depth3(idx1, (depth + 1) % 3) # depth + 1 <= 10 done += 1 # ######symmetric position has eventually more than one representation ############# sym = c_sym[c1_classidx] if sym != 1: for j in range(1, 16): sym >>= 1 if sym % 2 == 1: ud_edge2 = sy.ud_edges_conj[(ud_edge1 << 4) + j] # c1_classidx does not change idx2 = 40320 * c1_classidx + ud_edge2 if get_corners_ud_edges_depth3(idx2) == 3: set_corners_ud_edges_depth3(idx2, (depth + 1) % 3) done += 1 #################################################################################### ud_edge += 1 idx += 1 # idx = defs.N_UD_EDGEPERM * corner_classidx + ud_edge depth += 1 print() print('depth:', depth, 'done: ' + str(done) + '/' + str(total)) print('remaining unfilled entries have depth >=11') fh = open(fname, "wb") corners_ud_edges_depth3.tofile(fh) else: print("loading " + fname + " table...") fh = open(fname, "rb") corners_ud_edges_depth3 = ar.array('L') corners_ud_edges_depth3.fromfile(fh, total // 16) fh.close()
# ################### Movetables describe the transformation of the coordinates by cube moves. ######################### from os import path import array as ar import marcs.TwoPhaseSolver.cubie as cb import marcs.TwoPhaseSolver.enums from marcs.TwoPhaseSolver.defs import N_TWIST, N_FLIP, N_SLICE_SORTED, N_CORNERS, N_UD_EDGES, N_MOVE a = cb.CubieCube() # ######################################### Move table for the twists of the corners. ################################## # The twist coordinate describes the 3^7 = 2187 possible orientations of the 8 corners # 0 <= twist < 2187 in phase 1, twist = 0 in phase 2 fname = "move_twist" if not path.isfile(fname): print("creating " + fname + " table...") twist_move = ar.array('H', [0 for i in range(N_TWIST * N_MOVE)]) for i in range(N_TWIST): a.set_twist(i) for j in enums.Color: # six faces U, R, F, D, L, B for k in range(3): # three moves for each face, for example U, U2, U3 = U' a.corner_multiply(cb.basicMoveCube[j]) twist_move[N_MOVE * i + 3 * j + k] = a.get_twist() a.corner_multiply(cb.basicMoveCube[j]) # 4. move restores face fh = open(fname, "wb") twist_move.tofile(fh) else: print("loading " + fname + " table...") fh = open(fname, "rb") twist_move = ar.array('H') twist_move.fromfile(fh, N_TWIST * N_MOVE)
epROT_U4 = [ Ed.UB, Ed.UR, Ed.UF, Ed.UL, Ed.DB, Ed.DR, Ed.DF, Ed.DL, Ed.BR, Ed.FR, Ed.FL, Ed.BL ] eoROT_U4 = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1] # reflection at the plane through the U, D, F, B centers cpMIRR_LR2 = [Co.UFL, Co.URF, Co.UBR, Co.ULB, Co.DLF, Co.DFR, Co.DRB, Co.DBL] coMIRR_LR2 = [3, 3, 3, 3, 3, 3, 3, 3] epMIRR_LR2 = [ Ed.UL, Ed.UF, Ed.UR, Ed.UB, Ed.DL, Ed.DF, Ed.DR, Ed.DB, Ed.FL, Ed.FR, Ed.BR, Ed.BL ] eoMIRR_LR2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] basicSymCube = [cb.CubieCube()] * 4 basicSymCube[BS.ROT_URF3] = cb.CubieCube(cpROT_URF3, coROT_URF3, epROT_URF3, eoROT_URF3) basicSymCube[BS.ROT_F2] = cb.CubieCube(cpROT_F2, coROT_F2, epROT_F2, eoROT_F2) basicSymCube[BS.ROT_U4] = cb.CubieCube(cpROT_U4, coROT_U4, epROT_U4, eoROT_U4) basicSymCube[BS.MIRR_LR2] = cb.CubieCube(cpMIRR_LR2, coMIRR_LR2, epMIRR_LR2, eoMIRR_LR2) # ###################################################################################################################### # ######################################## Fill SymCube list ########################################################### # 48 CubieCubes will represent the 48 cube symmetries symCube = [] cc = cb.CubieCube() # Identity cube idx = 0 for urf3 in range(3):