def random(): """Generates a random cube and sets the corresponding facelet colors.""" cc = cubie.CubieCube() cc.randomize() fc = cc.to_facelet_cube() idx = 0 for f in range(6): for row in range(3): for col in range(3): canvas.itemconfig(facelet_id[f][row][col], fill=cols[fc.f[idx]]) idx += 1
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 generate_training_data(file_path, games=1, moves=12, verbose=False): cc = cubie.CubieCube() print('Generating {} ...'.format(file_path)) with open(file_path, 'w+') as f: for g in range(games): move_list = [] for m in range(moves): move = random.randint(0, 17) move_list.append(move) cc.multiply(cubie.moveCube[move]) f.write(cc.to_facelet_cube().to_string()) f.write('\n{}\n{}\n'.format(reverse_move(move), m + 2)) if verbose: print(move_list)
def random(): """Generates a random cube and sets the corresponding facelet colors.""" global cubestring display2.delete(1.0, END) # clear output window cc = cubie.CubieCube() cc.randomize() fc = cc.to_facelet_cube() show_text(fc) cubestring=str(fc) idx = 0 for f in range(6): for row in range(3): for col in range(3): canvas.itemconfig(facelet_id[f][row][col], fill=cols[fc.f[idx]] ) idx += 1
def test(n, t): """ :param n: The number of generated random cubes :param t: The time in seconds to spend on each cube :return: A dictioneary with the solving statistics """ cc = cubie.CubieCube() cnt = [0] * 31 for i in range(n): cc.randomize() fc = cc.to_facelet_cube() s = fc.to_string() print(s) s = sv.solve(s, 0, t) print(s) print() cnt[int(s.split('(')[1].split('f')[0])] += 1 avr = 0 for i in range(31): avr += i * cnt[i] avr /= n return 'average ' + '%.2f' % avr + ' moves', dict(zip(range(31), cnt))
# ################### Movetables describe the transformation of the coordinates by cube moves. ######################### from os import path import array as ar import cubie as cb import enums from 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. twist < 2187 in phase 1, twist = 0 in phase 2. ################# # The twist coordinate describes the 3^7 = 2187 possible orientations of the 8 corners 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) fh.close()
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(path.join(defs.FOLDER, 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 k in range(1, 16): sym >>= 1 if sym % 2 == 1: twist2 = sy.twist_conj[ (twist1 << 4) + k] # 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(path.join(defs.FOLDER, fname), "wb") flipslice_twist_depth3.tofile(fh) else: print("loading " + fname + " table...") fh = open(path.join(defs.FOLDER, 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(path.join(defs.FOLDER, 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 k in range(1, 16): sym >>= 1 if sym % 2 == 1: ud_edge2 = sy.ud_edges_conj[ (ud_edge1 << 4) + k] # 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(path.join(defs.FOLDER, fname), "wb") corners_ud_edges_depth3.tofile(fh) else: print("loading " + fname + " table...") fh = open(path.join(defs.FOLDER, fname), "rb") corners_ud_edges_depth3 = ar.array('L') corners_ud_edges_depth3.fromfile(fh, total // 16) fh.close()
epROT_F2 = [Ed.DL, Ed.DF, Ed.DR, Ed.DB, Ed.UL, Ed.UF, Ed.UR, Ed.UB, Ed.FL, Ed.FR, Ed.BR, Ed.BL] eoROT_F2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # 90° clockwise rotation around the axis through the U and D centers cpROT_U4 = [Co.UBR, Co.URF, Co.UFL, Co.ULB, Co.DRB, Co.DFR, Co.DLF, Co.DBL] coROT_U4 = [0, 0, 0, 0, 0, 0, 0, 0] 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): for f2 in range(2): for u4 in range(4):