diff --git a/kociemba/__init__.py b/kociemba/__init__.py index 107fa90..4274e8e 100644 --- a/kociemba/__init__.py +++ b/kociemba/__init__.py @@ -6,16 +6,17 @@ class SlowContextWarning(Warning): try: import os - from ckociembawrapper import ffi, lib + from .ckociembawrapper import ffi, lib cache_dir = os.path.join(os.path.dirname(__file__), 'cprunetables') def _solve(s): res = lib.solve(s.encode('utf-8'), cache_dir.encode('utf-8')) if res != ffi.NULL: - return ffi.string(res).strip() + return ffi.string(res).strip().decode('utf-8') else: raise ValueError('Error. Probably cubestring is invalid') -except ImportError: +except ImportError as e: + print(e) warnings.warn("Native version of the package is not available. " "We have to fallback to pure-Python implementation of " "the algorithm, which is usually many times slower. " @@ -23,8 +24,24 @@ def _solve(s): "project page for a native implementation: " "https://github.com/muodov/kociemba", SlowContextWarning) - import pykociemba.search - _solve = lambda s: pykociemba.search.Search().solution(s, 24, 1000, False).strip() + from .pykociemba import search + + def _solve(s): + errors = { + 'Error 1': 'There is not exactly one facelet of each colour', + 'Error 2': 'Not all 12 edges exist exactly once', + 'Error 3': 'Flip error: One edge has to be flipped', + 'Error 4': 'Not all corners exist exactly once', + 'Error 5': 'Twist error: One corner has to be twisted', + 'Error 6': 'Parity error: Two corners or two edges have to be exchanged', + 'Error 7': 'No solution exists for the given maxDepth', + 'Error 8': 'Timeout, no solution within given time' + } + res = search.Search().solution(s, 24, 1000, False).strip() + if res in errors: + raise ValueError(errors[res]) + else: + return res def solve(cubestring): diff --git a/kociemba/pykociemba/coordcube.py b/kociemba/pykociemba/coordcube.py index b9d60d9..8b61f69 100644 --- a/kociemba/pykociemba/coordcube.py +++ b/kociemba/pykociemba/coordcube.py @@ -1,6 +1,11 @@ +from builtins import range import logging import os.path -import cPickle + +try: + import cPickle +except ImportError: + import pickle as cPickle from .cubiecube import CubieCube, moveCube, getURtoDF @@ -8,35 +13,39 @@ cache_dir = os.path.join(os.path.dirname(__file__), 'prunetables') + def setPruning(table, index, value): """Set pruning value in table. Two values are stored in one byte.""" if ((index & 1) == 0): - table[index / 2] &= 0xf0 | value + table[index // 2] &= 0xf0 | value else: - table[index / 2] &= 0x0f | (value << 4) + table[index // 2] &= 0x0f | (value << 4) # table[index] = value & 0xf + def getPruning(table, index): """Extract pruning value""" if ((index & 1) == 0): - res = table[index / 2] & 0x0f + res = table[index // 2] & 0x0f else: - res = (table[index / 2] & 0xf0) >> 4 + res = (table[index // 2] & 0xf0) >> 4 return res # return table[index] & 0xf + def load_cachetable(name): obj = None try: - with open(os.path.join(cache_dir, name + '.pkl')) as f: + with open(os.path.join(cache_dir, name + '.pkl'), 'rb') as f: obj = cPickle.load(f) except IOError as e: log.warning('could not read cache for %s: %s. Recalculating it...', name, e) return obj + def dump_cachetable(obj, name): - with open(os.path.join(cache_dir, name + '.pkl'), 'w') as f: + with open(os.path.join(cache_dir, name + '.pkl'), 'wb') as f: cPickle.dump(obj, f) @@ -111,12 +120,12 @@ def move(self, m): # twist = 0 in phase 2. twistMove = load_cachetable('twistMove') if not twistMove: - twistMove = [[0] * N_MOVE for i in xrange(N_TWIST)] # new short[N_TWIST][N_MOVE] + twistMove = [[0] * N_MOVE for i in range(N_TWIST)] # new short[N_TWIST][N_MOVE] a = CubieCube() - for i in xrange(N_TWIST): + for i in range(N_TWIST): a.setTwist(i) - for j in xrange(6): - for k in xrange(3): + for j in range(6): + for k in range(3): a.cornerMultiply(moveCube[j]) twistMove[i][3 * j + k] = a.getTwist() a.cornerMultiply(moveCube[j]) # 4. faceturn restores @@ -131,12 +140,12 @@ def move(self, m): flipMove = load_cachetable('flipMove') if not flipMove: - flipMove = [[0] * N_MOVE for i in xrange(N_FLIP)] # new short[N_FLIP][N_MOVE] + flipMove = [[0] * N_MOVE for i in range(N_FLIP)] # new short[N_FLIP][N_MOVE] a = CubieCube() - for i in xrange(N_FLIP): + for i in range(N_FLIP): a.setFlip(i) - for j in xrange(6): - for k in xrange(3): + for j in range(6): + for k in range(3): a.edgeMultiply(moveCube[j]) flipMove[i][3 * j + k] = a.getFlip() a.edgeMultiply(moveCube[j]) @@ -147,8 +156,8 @@ def move(self, m): # Parity of the corner permutation. This is the same as the parity for the edge permutation of a valid cube. # parity has values 0 and 1 parityMove = [ - [ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 ], - [ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0 ], + [1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1], + [0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0], ] # ***********************************Phase 1 and 2 movetable******************************************************** @@ -161,12 +170,12 @@ def move(self, m): FRtoBR_Move = load_cachetable('FRtoBR_Move') if not FRtoBR_Move: - FRtoBR_Move = [[0] * N_MOVE for i in xrange(N_FRtoBR)] # new short[N_FRtoBR][N_MOVE] + FRtoBR_Move = [[0] * N_MOVE for i in range(N_FRtoBR)] # new short[N_FRtoBR][N_MOVE] a = CubieCube() - for i in xrange(N_FRtoBR): + for i in range(N_FRtoBR): a.setFRtoBR(i) - for j in xrange(6): - for k in xrange(3): + for j in range(6): + for k in range(3): a.edgeMultiply(moveCube[j]) FRtoBR_Move[i][3 * j + k] = a.getFRtoBR() a.edgeMultiply(moveCube[j]) @@ -182,12 +191,12 @@ def move(self, m): log.info('Preparing move table for permutation of six corners. The positions of the DBL and DRB corners are determined by the parity.') URFtoDLF_Move = load_cachetable('URFtoDLF_Move') if not URFtoDLF_Move: - URFtoDLF_Move = [[0] * N_MOVE for i in xrange(N_URFtoDLF)] # new short[N_URFtoDLF][N_MOVE] + URFtoDLF_Move = [[0] * N_MOVE for i in range(N_URFtoDLF)] # new short[N_URFtoDLF][N_MOVE] a = CubieCube() - for i in xrange(N_URFtoDLF): + for i in range(N_URFtoDLF): a.setURFtoDLF(i) - for j in xrange(6): - for k in xrange(3): + for j in range(6): + for k in range(3): a.cornerMultiply(moveCube[j]) URFtoDLF_Move[i][3 * j + k] = a.getURFtoDLF() a.cornerMultiply(moveCube[j]) @@ -202,12 +211,12 @@ def move(self, m): log.info('Preparing move table for the permutation of six U-face and D-face edges in phase2. The positions of the DL and DB edges are') URtoDF_Move = load_cachetable('URtoDF_Move') if not URtoDF_Move: - URtoDF_Move = [[0] * N_MOVE for i in xrange(N_URtoDF)] # new short[N_URtoDF][N_MOVE] + URtoDF_Move = [[0] * N_MOVE for i in range(N_URtoDF)] # new short[N_URtoDF][N_MOVE] a = CubieCube() - for i in xrange(N_URtoDF): + for i in range(N_URtoDF): a.setURtoDF(i) - for j in xrange(6): - for k in xrange(3): + for j in range(6): + for k in range(3): a.edgeMultiply(moveCube[j]) URtoDF_Move[i][3 * j + k] = a.getURtoDF() # Table values are only valid for phase 2 moves! @@ -221,12 +230,12 @@ def move(self, m): log.info('Preparing move table for the three edges UR,UF and UL in phase1.') URtoUL_Move = load_cachetable('URtoUL_Move') if not URtoUL_Move: - URtoUL_Move = [[0] * N_MOVE for i in xrange(N_URtoUL)] # new short[N_URtoUL][N_MOVE] + URtoUL_Move = [[0] * N_MOVE for i in range(N_URtoUL)] # new short[N_URtoUL][N_MOVE] a = CubieCube() - for i in xrange(N_URtoUL): + for i in range(N_URtoUL): a.setURtoUL(i) - for j in xrange(6): - for k in xrange(3): + for j in range(6): + for k in range(3): a.edgeMultiply(moveCube[j]) URtoUL_Move[i][3 * j + k] = a.getURtoUL() a.edgeMultiply(moveCube[j]) @@ -237,12 +246,12 @@ def move(self, m): log.info('Preparing move table for the three edges UB,DR and DF in phase1.') UBtoDF_Move = load_cachetable('UBtoDF_Move') if not UBtoDF_Move: - UBtoDF_Move = [[0] * N_MOVE for i in xrange(N_UBtoDF)] # new short[N_UBtoDF][N_MOVE] + UBtoDF_Move = [[0] * N_MOVE for i in range(N_UBtoDF)] # new short[N_UBtoDF][N_MOVE] a = CubieCube() - for i in xrange(N_UBtoDF): + for i in range(N_UBtoDF): a.setUBtoDF(i) - for j in xrange(6): - for k in xrange(3): + for j in range(6): + for k in range(3): a.edgeMultiply(moveCube[j]) UBtoDF_Move[i][3 * j + k] = a.getUBtoDF() a.edgeMultiply(moveCube[j]) @@ -253,11 +262,11 @@ def move(self, m): log.info('Preparing table to merge the coordinates of the UR,UF,UL and UB,DR,DF edges at the beginning of phase2') MergeURtoULandUBtoDF = load_cachetable('MergeURtoULandUBtoDF') if not MergeURtoULandUBtoDF: - MergeURtoULandUBtoDF = [[0] * 336 for i in xrange(336)] # new short[336][336] + MergeURtoULandUBtoDF = [[0] * 336 for i in range(336)] # new short[336][336] # for i, j <336 the six edges UR,UF,UL,UB,DR,DF are not in the # UD-slice and the index is <20160 - for uRtoUL in xrange(336): - for uBtoDF in xrange(336): + for uRtoUL in range(336): + for uBtoDF in range(336): MergeURtoULandUBtoDF[uRtoUL][uBtoDF] = getURtoDF(uRtoUL, uBtoDF) dump_cachetable(MergeURtoULandUBtoDF, 'MergeURtoULandUBtoDF') @@ -268,18 +277,18 @@ def move(self, m): log.info('Preparing pruning table for the permutation of the corners and the UD-slice edges in phase2.') Slice_URFtoDLF_Parity_Prun = load_cachetable('Slice_URFtoDLF_Parity_Prun') if not Slice_URFtoDLF_Parity_Prun: - Slice_URFtoDLF_Parity_Prun = [-1] * (N_SLICE2 * N_URFtoDLF * N_PARITY / 2) # new byte[N_SLICE2 * N_URFtoDLF * N_PARITY / 2] + Slice_URFtoDLF_Parity_Prun = [-1] * (N_SLICE2 * N_URFtoDLF * N_PARITY // 2) # new byte[N_SLICE2 * N_URFtoDLF * N_PARITY / 2] # Slice_URFtoDLF_Parity_Prun = [-1] * (N_SLICE2 * N_URFtoDLF * N_PARITY) depth = 0 setPruning(Slice_URFtoDLF_Parity_Prun, 0, 0) done = 1 while (done != N_SLICE2 * N_URFtoDLF * N_PARITY): - for i in xrange(N_SLICE2 * N_URFtoDLF * N_PARITY): + for i in range(N_SLICE2 * N_URFtoDLF * N_PARITY): parity = i % 2 - URFtoDLF = (i / 2) / N_SLICE2 - _slice = (i / 2) % N_SLICE2 + URFtoDLF = (i // 2) // N_SLICE2 + _slice = (i // 2) % N_SLICE2 if getPruning(Slice_URFtoDLF_Parity_Prun, i) == depth: - for j in xrange(18): + for j in range(18): if j in (3, 5, 6, 8, 12, 14, 15, 17): continue else: @@ -303,18 +312,18 @@ def move(self, m): log.info('Preparing pruning table for the permutation of the edges in phase2.') Slice_URtoDF_Parity_Prun = load_cachetable('Slice_URtoDF_Parity_Prun') if not Slice_URtoDF_Parity_Prun: - Slice_URtoDF_Parity_Prun = [-1] * (N_SLICE2 * N_URtoDF * N_PARITY / 2) # new byte[N_SLICE2 * N_URtoDF * N_PARITY / 2] + Slice_URtoDF_Parity_Prun = [-1] * (N_SLICE2 * N_URtoDF * N_PARITY // 2) # new byte[N_SLICE2 * N_URtoDF * N_PARITY / 2] # Slice_URtoDF_Parity_Prun = [-1] * (N_SLICE2 * N_URtoDF * N_PARITY) # new byte[N_SLICE2 * N_URtoDF * N_PARITY / 2] depth = 0 setPruning(Slice_URtoDF_Parity_Prun, 0, 0) done = 1 while (done != N_SLICE2 * N_URtoDF * N_PARITY): - for i in xrange(N_SLICE2 * N_URtoDF * N_PARITY): + for i in range(N_SLICE2 * N_URtoDF * N_PARITY): parity = i % 2 - URtoDF = (i / 2) / N_SLICE2 - _slice = (i / 2) % N_SLICE2 + URtoDF = (i // 2) // N_SLICE2 + _slice = (i // 2) % N_SLICE2 if (getPruning(Slice_URtoDF_Parity_Prun, i) == depth): - for j in xrange(18): + for j in range(18): if j in (3, 5, 6, 8, 12, 14, 15, 17): continue else: @@ -337,18 +346,18 @@ def move(self, m): log.info('Pruning table for the twist of the corners and the position (not permutation) of the UD-slice edges in phase1') Slice_Twist_Prun = load_cachetable('Slice_Twist_Prun') if not Slice_Twist_Prun: - Slice_Twist_Prun = [-1] * (N_SLICE1 * N_TWIST / 2 + 1) # new byte[N_SLICE1 * N_TWIST / 2 + 1] + Slice_Twist_Prun = [-1] * (N_SLICE1 * N_TWIST // 2 + 1) # new byte[N_SLICE1 * N_TWIST / 2 + 1] # Slice_Twist_Prun = [-1] * (N_SLICE1 * N_TWIST + 1) # new byte[N_SLICE1 * N_TWIST / 2 + 1] depth = 0 setPruning(Slice_Twist_Prun, 0, 0) done = 1 while (done != N_SLICE1 * N_TWIST): - for i in xrange(N_SLICE1 * N_TWIST): - twist = i / N_SLICE1 + for i in range(N_SLICE1 * N_TWIST): + twist = i // N_SLICE1 _slice = i % N_SLICE1 if (getPruning(Slice_Twist_Prun, i) == depth): - for j in xrange(18): - newSlice = FRtoBR_Move[_slice * 24][j] / 24 + for j in range(18): + newSlice = FRtoBR_Move[_slice * 24][j] // 24 newTwist = twistMove[twist][j] if (getPruning(Slice_Twist_Prun, N_SLICE1 * newTwist + newSlice) == 0x0f): setPruning(Slice_Twist_Prun, N_SLICE1 * newTwist + newSlice, (depth + 1) & 0xff) @@ -363,18 +372,18 @@ def move(self, m): log.info('Pruning table for the flip of the edges and the position (not permutation) of the UD-slice edges in phase1') Slice_Flip_Prun = load_cachetable('Slice_Flip_Prun') if not Slice_Flip_Prun: - Slice_Flip_Prun = [-1] * (N_SLICE1 * N_FLIP / 2) # new byte[N_SLICE1 * N_FLIP / 2] + Slice_Flip_Prun = [-1] * (N_SLICE1 * N_FLIP // 2) # new byte[N_SLICE1 * N_FLIP / 2] # Slice_Flip_Prun = [-1] * (N_SLICE1 * N_FLIP) # new byte[N_SLICE1 * N_FLIP / 2] depth = 0 setPruning(Slice_Flip_Prun, 0, 0) done = 1 while (done != N_SLICE1 * N_FLIP): - for i in xrange(N_SLICE1 * N_FLIP): - flip = i / N_SLICE1 + for i in range(N_SLICE1 * N_FLIP): + flip = i // N_SLICE1 _slice = i % N_SLICE1 if (getPruning(Slice_Flip_Prun, i) == depth): - for j in xrange(18): - newSlice = FRtoBR_Move[_slice * 24][j] / 24 + for j in range(18): + newSlice = FRtoBR_Move[_slice * 24][j] // 24 newFlip = flipMove[flip][j] if (getPruning(Slice_Flip_Prun, N_SLICE1 * newFlip + newSlice) == 0x0f): setPruning(Slice_Flip_Prun, N_SLICE1 * newFlip + newSlice, (depth + 1) & 0xff) diff --git a/kociemba/pykociemba/cubiecube.py b/kociemba/pykociemba/cubiecube.py index b6a7f3e..41c7c37 100644 --- a/kociemba/pykociemba/cubiecube.py +++ b/kociemba/pykociemba/cubiecube.py @@ -1,8 +1,8 @@ import copy +from builtins import range from .corner import URF, UFL, ULB, UBR, DFR, DLF, DBL, DRB, corner_values from .edge import UR, UF, UL, UB, DR, DF, DL, DB, FR, FL, BL, BR, edge_values -from .facelet import facelet_values from .facecube import FaceCube @@ -11,14 +11,14 @@ def Cnk(n, k): if n < k: return 0 - if k > n / 2: + if k > n // 2: k = n - k s = 1 i = n j = 1 while i != n - k: s *= i - s /= j + s //= j i -= 1 j += 1 return s @@ -27,7 +27,7 @@ def Cnk(n, k): def rotateLeft(arr, l, r): """Left rotation of all array elements between l and r""" temp = arr[l] - for i in xrange(l, r): + for i in range(l, r): arr[i] = arr[i + 1] arr[r] = temp @@ -35,7 +35,7 @@ def rotateLeft(arr, l, r): def rotateRight(arr, l, r): """Right rotation of all array elements between l and r""" temp = arr[r] - for i in xrange(r, l, -1): + for i in range(r, l, -1): arr[i] = arr[i - 1] arr[l] = temp @@ -46,7 +46,7 @@ def getURtoDF(idx1, idx2): b = CubieCube() a.setURtoUL(idx1) b.setUBtoDF(idx2) - for i in xrange(8): + for i in range(8): if a.ep[i] != BR: if b.ep[i] != BR: # collision return -1 @@ -80,12 +80,12 @@ def toFaceCube(self): for i in corner_values: j = self.cp[i] # cornercubie with index j is at cornerposition with index i ori = self.co[i] # Orientation of this cubie - for n in xrange(3): + for n in range(3): _butya = FaceCube.cornerFacelet[i][(n + ori) % 3] fcRet.f[_butya] = FaceCube.cornerColor[j][n] for i in edge_values: ori = self.eo[i] # Orientation of this cubie - for n in xrange(2): + for n in range(2): _butya = FaceCube.edgeFacelet[i][(n + ori) % 2] fcRet.f[_butya] = FaceCube.edgeColor[self.ep[i]][n] return fcRet @@ -201,39 +201,39 @@ def getTwist(self): """return the twist of the 8 corners. 0 <= twist < 3^7""" ret = 0 - for i in xrange(URF, DRB): + for i in range(URF, DRB): ret = (3 * ret + self.co[i]) & 0xffff return ret def setTwist(self, twist): twistParity = 0 - for i in xrange(DRB - 1, URF - 1, -1): + for i in range(DRB - 1, URF - 1, -1): self.co[i] = (twist % 3) & 0xff twistParity += self.co[i] - twist /= 3 + twist //= 3 self.co[DRB] = ((3 - twistParity % 3) % 3) & 0xff def getFlip(self): """return the flip of the 12 edges. 0<= flip < 2^11""" ret = 0 - for i in xrange(UR, BR): + for i in range(UR, BR): ret = (2 * ret + self.eo[i]) & 0xffff return ret def setFlip(self, flip): flipParity = 0 - for i in xrange(BR - 1, UR - 1, -1): + for i in range(BR - 1, UR - 1, -1): self.eo[i] = (flip % 2) & 0xff flipParity += self.eo[i] - flip /= 2 + flip //= 2 self.eo[BR] = ((2 - flipParity % 2) % 2) & 0xff def cornerParity(self): """Parity of the corner permutation""" s = 0 - for i in xrange(DRB, URF, -1): - for j in xrange(i - 1, URF - 1, -1): + for i in range(DRB, URF, -1): + for j in range(i - 1, URF - 1, -1): if self.cp[j] > self.cp[i]: s += 1 return (s % 2) & 0xffff @@ -241,8 +241,8 @@ def cornerParity(self): def edgeParity(self): """Parity of the edges permutation. Parity of corners and edges are the same if the cube is solvable.""" s = 0 - for i in xrange(BR, UR, -1): - for j in xrange(i - 1, UR - 1, -1): + for i in range(BR, UR, -1): + for j in range(i - 1, UR - 1, -1): if self.ep[j] > self.ep[i]: s += 1 return (s % 2) & 0xffff @@ -253,14 +253,14 @@ def getFRtoBR(self): x = 0 edge4 = [None] * 4 # new Edge[4] # compute the index a < (12 choose 4) and the permutation array perm. - for j in xrange(BR, UR - 1, -1): + for j in range(BR, UR - 1, -1): if (FR <= self.ep[j] and self.ep[j] <= BR): a += Cnk(11 - j, x + 1) edge4[3 - x] = self.ep[j] x += 1 b = 0 - for j in xrange(3, 0, -1): # compute the index b < 4! for the permutation in perm + for j in range(3, 0, -1): # compute the index b < 4! for the permutation in perm k = 0 while (edge4[j] != j + 8): rotateLeft(edge4, 0, j) @@ -272,26 +272,26 @@ def setFRtoBR(self, idx): sliceEdge = [ FR, FL, BL, BR ] otherEdge = [ UR, UF, UL, UB, DR, DF, DL, DB ] b = idx % 24 # Permutation - a = idx / 24 # Combination + a = idx // 24 # Combination for i in edge_values: self.ep[i] = DB # Use UR to invalidate all edges - for j in xrange(1, 4): # generate permutation from index b + for j in range(1, 4): # generate permutation from index b k = b % (j + 1) - b /= j + 1 + b //= j + 1 while k > 0: # while (k-- > 0) #???????????????? k -= 1 rotateRight(sliceEdge, 0, j) x = 3 # generate combination and set slice edges - for j in xrange(UR, BR + 1): + for j in range(UR, BR + 1): if a - Cnk(11 - j, x + 1) >= 0: self.ep[j] = sliceEdge[3 - x] a -= Cnk(11 - j, x + 1) x -= 1 x = 0 # set the remaining edges UR..DB - for j in xrange(UR, BR + 1): + for j in range(UR, BR + 1): if self.ep[j] == DB: self.ep[j] = otherEdge[x] x += 1 @@ -302,14 +302,14 @@ def getURFtoDLF(self): x = 0 corner6 = [] # new Corner[6] # compute the index a < (8 choose 6) and the corner permutation. - for j in xrange(URF, DRB + 1): + for j in range(URF, DRB + 1): if self.cp[j] <= DLF: a += Cnk(j, x + 1) corner6.append(self.cp[j]) x += 1 b = 0 - for j in xrange(5, 0, -1): # compute the index b < 6! for the + for j in range(5, 0, -1): # compute the index b < 6! for the # permutation in corner6 k = 0 while corner6[j] != j: @@ -322,25 +322,25 @@ def setURFtoDLF(self, idx): corner6 = [ URF, UFL, ULB, UBR, DFR, DLF ] otherCorner = [ DBL, DRB ] b = idx % 720 # Permutation - a = idx / 720 # Combination + a = idx // 720 # Combination for i in corner_values: self.cp[i] = DRB # Use DRB to invalidate all corners - for j in xrange(1, 6): # generate permutation from index b + for j in range(1, 6): # generate permutation from index b k = b % (j + 1) - b /= j + 1 + b //= j + 1 while k > 0: k -= 1 rotateRight(corner6, 0, j) x = 5 # generate combination and set corners - for j in xrange(DRB, -1, -1): + for j in range(DRB, -1, -1): if a - Cnk(j, x + 1) >= 0: self.cp[j] = corner6[x] a -= Cnk(j, x + 1) x -= 1 x = 0 - for j in xrange(URF, DRB + 1): + for j in range(URF, DRB + 1): if self.cp[j] == DRB: self.cp[j] = otherCorner[x] x += 1 @@ -351,14 +351,14 @@ def getURtoDF(self): x = 0 edge6 = [] # new Edge[6] # compute the index a < (12 choose 6) and the edge permutation. - for j in xrange(UR, BR + 1): + for j in range(UR, BR + 1): if self.ep[j] <= DF: a += Cnk(j, x + 1) edge6.append(self.ep[j]) x += 1 b = 0 - for j in xrange(5, 0, -1): # compute the index b < 6! for the permutation in edge6 + for j in range(5, 0, -1): # compute the index b < 6! for the permutation in edge6 k = 0 while edge6[j] != j: rotateLeft(edge6, 0, j) @@ -370,26 +370,26 @@ def setURtoDF(self, idx): edge6 = [ UR, UF, UL, UB, DR, DF ] otherEdge = [ DL, DB, FR, FL, BL, BR ] b = idx % 720 # Permutation - a = idx / 720 # Combination + a = idx // 720 # Combination for i in edge_values: self.ep[i] = BR # Use BR to invalidate all edges - for j in xrange(1, 6): # generate permutation from index b + for j in range(1, 6): # generate permutation from index b k = b % (j + 1) - b /= j + 1 + b //= j + 1 while k > 0: k -= 1 rotateRight(edge6, 0, j) x = 5 # generate combination and set edges - for j in xrange(BR, -1, -1): + for j in range(BR, -1, -1): if a - Cnk(j, x + 1) >= 0: self.ep[j] = edge6[x] a -= Cnk(j, x + 1) x -= 1 x = 0 # set the remaining edges DL..BR - for j in xrange(UR, BR + 1): + for j in range(UR, BR + 1): if self.ep[j] == BR: self.ep[j] = otherEdge[x] x += 1 @@ -400,14 +400,14 @@ def getURtoUL(self): x = 0 edge3 = [] # new Edge[3] # compute the index a < (12 choose 3) and the edge permutation. - for j in xrange(UR, BR + 1): + for j in range(UR, BR + 1): if self.ep[j] <= UL: a += Cnk(j, x + 1) edge3.append(self.ep[j]) x += 1 b = 0 - for j in xrange(2, 0, -1): # compute the index b < 3! for the permutation in edge3 + for j in range(2, 0, -1): # compute the index b < 3! for the permutation in edge3 k = 0 while edge3[j] != j: rotateLeft(edge3, 0, j) @@ -418,18 +418,18 @@ def getURtoUL(self): def setURtoUL(self, idx): edge3 = [ UR, UF, UL ] b = idx % 6 # Permutation - a = idx / 6 # Combination + a = idx // 6 # Combination for i in edge_values: self.ep[i] = BR # Use BR to invalidate all edges - for j in xrange(1, 3): # generate permutation from index b + for j in range(1, 3): # generate permutation from index b k = b % (j + 1) - b /= j + 1 + b //= j + 1 while k > 0: k -= 1 rotateRight(edge3, 0, j) x = 2 # generate combination and set edges - for j in xrange(BR, -1, -1): + for j in range(BR, -1, -1): if a - Cnk(j, x + 1) >= 0: self.ep[j] = edge3[x] a -= Cnk(j, x + 1) @@ -441,14 +441,14 @@ def getUBtoDF(self): x = 0 edge3 = [] # new Edge[3] # compute the index a < (12 choose 3) and the edge permutation. - for j in xrange(UR, BR + 1): + for j in range(UR, BR + 1): if UB <= self.ep[j] and self.ep[j] <= DF: a += Cnk(j, x + 1) edge3.append(self.ep[j]) x += 1 b = 0 - for j in xrange(2, 0, -1): # compute the index b < 3! for the permutation in edge3 + for j in range(2, 0, -1): # compute the index b < 3! for the permutation in edge3 k = 0 while edge3[j] != UB + j: rotateLeft(edge3, 0, j) @@ -459,20 +459,20 @@ def getUBtoDF(self): def setUBtoDF(self, idx): edge3 = [ UB, DR, DF ] b = idx % 6 # Permutation - a = idx / 6 # Combination + a = idx // 6 # Combination for i in edge_values: self.ep[i] = BR # Use BR to invalidate all edges - for j in xrange(1, 3): + for j in range(1, 3): # generate permutation from index b k = b % (j + 1) - b /= j + 1 + b //= j + 1 while k > 0: k -= 1 rotateRight(edge3, 0, j) x = 2 # generate combination and set edges - for j in xrange(BR, -1, -1): + for j in range(BR, -1, -1): if a - Cnk(j, x + 1) >= 0: self.ep[j] = edge3[x] a -= Cnk(j, x + 1) @@ -481,7 +481,7 @@ def setUBtoDF(self, idx): def getURFtoDLB(self): perm = copy.copy(self.cp) b = 0 - for j in xrange(7, 0, -1): # compute the index b < 8! for the permutation in perm + for j in range(7, 0, -1): # compute the index b < 8! for the permutation in perm k = 0 while perm[j] != j: rotateLeft(perm, 0, j) @@ -491,22 +491,22 @@ def getURFtoDLB(self): def setURFtoDLB(self, idx): perm = [ URF, UFL, ULB, UBR, DFR, DLF, DBL, DRB ] - for j in xrange(1, 8): + for j in range(1, 8): k = idx % (j + 1) - idx /= j + 1 + idx //= j + 1 while k > 0: k -= 1 rotateRight(perm, 0, j) x = 7 # set corners - for j in xrange(7, -1, -1): + for j in range(7, -1, -1): self.cp[j] = perm[x] x -= 1 def getURtoBR(self): perm = copy.copy(self.ep) b = 0 - for j in xrange(11, 0, -1): # compute the index b < 12! for the permutation in perm + for j in range(11, 0, -1): # compute the index b < 12! for the permutation in perm k = 0 while perm[j] != j: rotateLeft(perm, 0, j) @@ -516,14 +516,14 @@ def getURtoBR(self): def setURtoBR(self, idx): perm = [ UR, UF, UL, UB, DR, DF, DL, DB, FR, FL, BL, BR ] - for j in xrange(1, 12): + for j in range(1, 12): k = idx % (j + 1) - idx /= j + 1 + idx //= j + 1 while k > 0: k -= 1 rotateRight(perm, 0, j) x = 11 # set edges - for j in xrange(11, -1, -1): + for j in range(11, -1, -1): self.ep[j] = perm[x] x -= 1 @@ -542,11 +542,11 @@ def verify(self): edgeCount = [0] * 12 # new int[12] for i in edge_values: edgeCount[self.ep[i]] += 1 - for i in xrange(12): + for i in range(12): if edgeCount[i] != 1: return -2 - for i in xrange(12): + for i in range(12): sum += self.eo[i] if sum % 2 != 0: return -3 @@ -554,12 +554,12 @@ def verify(self): cornerCount = [0] * 8 # new int[8] for i in corner_values: cornerCount[self.cp[i]] += 1 - for i in xrange(8): + for i in range(8): if cornerCount[i] != 1: return -4 # missing corners sum = 0 - for i in xrange(8): + for i in range(8): sum += self.co[i] if sum % 3 != 0: return -5 # twisted corner diff --git a/kociemba/pykociemba/facecube.py b/kociemba/pykociemba/facecube.py index 1376b14..03668a5 100644 --- a/kociemba/pykociemba/facecube.py +++ b/kociemba/pykociemba/facecube.py @@ -1,3 +1,5 @@ +from builtins import range + from .facelet import ( U1, U2, U3, U4, U5, U6, U7, U8, U9, R1, R2, R3, R4, R5, R6, R7, R8, R9, F1, F2, F3, F4, F5, F6, F7, F8, F9, D1, D2, D3, D4, D5, D6, D7, D8, D9, @@ -58,14 +60,14 @@ def toCubieCube(self): from .cubiecube import CubieCube ccRet = CubieCube() - for i in xrange(8): + for i in range(8): ccRet.cp[i] = URF # invalidate corners - for i in xrange(12): + for i in range(12): ccRet.ep[i] = UR # and edges for i in corner_values: # get the colors of the cubie at corner i, starting with U/D - for ori in xrange(3): + for ori in range(3): if (self.f[self.cornerFacelet[i][ori]] == U or self.f[self.cornerFacelet[i][ori]] == D): break diff --git a/kociemba/pykociemba/search.py b/kociemba/pykociemba/search.py index ebbb61a..de49bd3 100644 --- a/kociemba/pykociemba/search.py +++ b/kociemba/pykociemba/search.py @@ -1,4 +1,5 @@ import time +from builtins import range from .color import colors from .facecube import FaceCube from .coordcube import CoordCube, getPruning @@ -29,7 +30,7 @@ def solutionToString(self, length, depthPhase1=None): """generate the solution string from the array data""" s = "" - for i in xrange(length): + for i in range(length): s += self.ax_to_s[self.ax[i]] s += self.po_to_s[self.po[i]] if depthPhase1 is not None and i == depthPhase1 - 1: @@ -69,13 +70,13 @@ def solution(self, facelets, maxDepth, timeOut, useSeparator): # +++++++++++++++++++++check for wrong input +++++++++++++++++++++++++++++ count = [0] * 6 try: - for i in xrange(54): + for i in range(54): assert facelets[i] in colors count[colors[facelets[i]]] += 1 - except Exception as e: + except Exception: return "Error 1" - for i in xrange(6): + for i in range(6): if count[i] != 9: return "Error 1" @@ -93,7 +94,7 @@ def solution(self, facelets, maxDepth, timeOut, useSeparator): self.flip[0] = c.flip self.twist[0] = c.twist self.parity[0] = c.parity - self.slice[0] = c.FRtoBR / 24 + self.slice[0] = c.FRtoBR // 24 self.URFtoDLF[0] = c.URFtoDLF self.FRtoBR[0] = c.FRtoBR self.URtoUL[0] = c.URtoUL @@ -159,7 +160,7 @@ def solution(self, facelets, maxDepth, timeOut, useSeparator): mv = 3 * self.ax[n] + self.po[n] - 1 self.flip[n + 1] = CoordCube.flipMove[self.flip[n]][mv] self.twist[n + 1] = CoordCube.twistMove[self.twist[n]][mv] - self.slice[n + 1] = CoordCube.FRtoBR_Move[self.slice[n] * 24][mv] / 24 + self.slice[n + 1] = CoordCube.FRtoBR_Move[self.slice[n] * 24][mv] // 24 self.minDistPhase1[n + 1] = max( getPruning( CoordCube.Slice_Flip_Prun, @@ -193,7 +194,7 @@ def totalDepth(self, depthPhase1, maxDepth): d1 = 0 d2 = 0 maxDepthPhase2 = min(10, maxDepth - depthPhase1) # Allow only max 10 moves in phase2 - for i in xrange(depthPhase1): + for i in range(depthPhase1): mv = 3 * self.ax[i] + self.po[i] - 1 self.URFtoDLF[i + 1] = CoordCube.URFtoDLF_Move[self.URFtoDLF[i]][mv] self.FRtoBR[i + 1] = CoordCube.FRtoBR_Move[self.FRtoBR[i]][mv] @@ -206,7 +207,7 @@ def totalDepth(self, depthPhase1, maxDepth): if d1 > maxDepthPhase2: return -1 - for i in xrange(depthPhase1): + for i in range(depthPhase1): mv = 3 * self.ax[i] + self.po[i] - 1 self.URtoUL[i + 1] = CoordCube.URtoUL_Move[self.URtoUL[i]][mv] self.UBtoDF[i + 1] = CoordCube.UBtoDF_Move[self.UBtoDF[i]][mv] diff --git a/kociemba/pykociemba/tools.py b/kociemba/pykociemba/tools.py index ec56718..5fe34f5 100644 --- a/kociemba/pykociemba/tools.py +++ b/kociemba/pykociemba/tools.py @@ -1,10 +1,12 @@ import random +from builtins import range from .facecube import FaceCube from .cubiecube import CubieCube from .coordcube import CoordCube from .color import colors + def verify(s): """ Check if the cube definition string s represents a solvable cube. @@ -20,13 +22,13 @@ def verify(s): """ count = [0] * 6 # new int[6] try: - for i in xrange(54): + for i in range(54): assert s[i] in colors count[colors[s[i]]] += 1 except: return -1 - for i in xrange(6): + for i in range(6): if count[i] != 9: return -1 diff --git a/setup.py b/setup.py index 5e901c1..ba5377a 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='kociemba', - version='1.0.1', + version='1.0.2', description='Python/C implementation of Herbert Kociemba\'s Two-Phase algorithm for solving Rubik\'s Cube', keywords='kociemba rubik cube solver twophase', url='https://github.com/muodov/kociemba', @@ -30,5 +30,5 @@ tests_require=['pytest', ], zip_safe=False, cffi_modules=["kociemba/build_ckociemba.py:ffi"], - install_requires=["cffi>=1.0.0"], + install_requires=["cffi>=1.0.0", 'future'], )