diff --git a/README.md b/README.md index a554bfc..b89ce77 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,19 @@ This package is published on PyPI and can be installed with: It was tested under Python 2.7 and 3.5. -The package exposes just one function ```solve()```, which accepts a cube definition string and returns a solution string in standard notation (see below): +On some systems you might need to install libffi system library beforehand. For example, on Debian-based distributions (e.g. Raspbian) you would run `sudo apt-get install libffi-dev`. + +The package exposes just one function ```solve()```, which accepts a cube definition string and returns a solution string in standard notation (see below). +Optional second argument allows solving to a specific pattern. ```python >>> import kociemba + >>> kociemba.solve('DRLUUBFBRBLURRLRUBLRDDFDLFUFUFFDBRDUBRUFLLFDDBFLUBLRBD') u"D2 R' D' F2 B D R2 D2 R' F2 D' F2 U' B2 L2 U2 D R2 U" + +>>> kociemba.solve('FLBUULFFLFDURRDBUBUUDDFFBRDDBLRDRFLLRLRULFUDRRBDBBBUFL', 'BBURUDBFUFFFRRFUUFLULUFUDLRRDBBDBDBLUDDFLLRRBRLLLBRDDF') +u"R' D2 R' U2 R F2 D B2 U' R F' U R2 D L2 D' B2 R2 B2 U' B2" ``` ## Standalone tool diff --git a/kociemba/__init__.py b/kociemba/__init__.py index 4274e8e..f4a7cc3 100644 --- a/kociemba/__init__.py +++ b/kociemba/__init__.py @@ -9,8 +9,9 @@ class SlowContextWarning(Warning): 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')) + def _solve(cube, pattern): + pattern_utf8 = pattern.encode('utf-8') if pattern is not None else ffi.NULL + res = lib.solve(cube.encode('utf-8'), pattern_utf8, cache_dir.encode('utf-8')) if res != ffi.NULL: return ffi.string(res).strip().decode('utf-8') else: @@ -26,7 +27,7 @@ def _solve(s): SlowContextWarning) from .pykociemba import search - def _solve(s): + def _solve(cube, pattern): errors = { 'Error 1': 'There is not exactly one facelet of each colour', 'Error 2': 'Not all 12 edges exist exactly once', @@ -37,21 +38,26 @@ def _solve(s): '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 pattern is not None: + cube = search.patternize(cube, pattern) + res = search.Search().solution(cube, 24, 1000, False).strip() if res in errors: raise ValueError(errors[res]) else: return res -def solve(cubestring): +def solve(cubestring, patternstring=None): """ Solve a Rubik's cube using two-phase algorithm. >>> solve("BBURUDBFUFFFRRFUUFLULUFUDLRRDBBDBDBLUDDFLLRRBRLLLBRDDF") "B U' L' D' R' D' L2 D' L F' L' D F2 R2 U R2 B2 U2 L2 F2 D'" + + >>> kociemba.solve('FLBUULFFLFDURRDBUBUUDDFFBRDDBLRDRFLLRLRULFUDRRBDBBBUFL', 'BBURUDBFUFFFRRFUUFLULUFUDLRRDBBDBDBLUDDFLLRRBRLLLBRDDF') + u"R' D2 R' U2 R F2 D B2 U' R F' U R2 D L2 D' B2 R2 B2 U' B2" """ - return _solve(cubestring) + return _solve(cubestring, patternstring) __all__ = ['solve'] diff --git a/kociemba/build_ckociemba.py b/kociemba/build_ckociemba.py index 535db62..1a80d44 100644 --- a/kociemba/build_ckociemba.py +++ b/kociemba/build_ckociemba.py @@ -8,8 +8,14 @@ #include #include - char* solve(char *cubestring, char *cache_dir) + char* solve(char *cubestring, char *patternstring, char *cache_dir) { + char patternized[64]; + if (patternstring) { + patternize(cubestring, patternstring, patternized); + cubestring = patternized; + } + char *sol = solution( cubestring, 24, @@ -26,9 +32,9 @@ 'kociemba/ckociemba/cubiecube.c', 'kociemba/ckociemba/facecube.c', 'kociemba/ckociemba/search.c'], - extra_compile_args=['-std=c99']) + extra_compile_args=['-std=c99', '-O3', '-D_XOPEN_SOURCE=700']) -ffi.cdef("char* solve(char *cubestring, char *cache_dir);") +ffi.cdef("char* solve(char *cubestring, char *patternstring, char *cache_dir);") if __name__ == "__main__": ffi.compile(verbose=True) diff --git a/kociemba/ckociemba/Makefile b/kociemba/ckociemba/Makefile index afecee8..d693b00 100644 --- a/kociemba/ckociemba/Makefile +++ b/kociemba/ckociemba/Makefile @@ -1,6 +1,6 @@ CKOCIEMBA_SRC = coordcube.c cubiecube.c facecube.c search.c CKOCIEMBA_INCLUDE = include -CFLAGS = -std=c99 +CFLAGS = -std=c99 -O3 BINDIR = bin BIN = kociemba diff --git a/kociemba/ckociemba/coordcube.c b/kociemba/ckociemba/coordcube.c index 610669b..1a619d5 100644 --- a/kociemba/ckociemba/coordcube.c +++ b/kociemba/ckociemba/coordcube.c @@ -20,10 +20,10 @@ short URtoDF_Move[N_URtoDF][N_MOVE] = {{0}}; short URtoUL_Move[N_URtoUL][N_MOVE] = {{0}}; short UBtoDF_Move[N_UBtoDF][N_MOVE] = {{0}}; short MergeURtoULandUBtoDF[336][336] = {{0}}; -char Slice_URFtoDLF_Parity_Prun[N_SLICE2 * N_URFtoDLF * N_PARITY / 2] = {0}; -char Slice_URtoDF_Parity_Prun[N_SLICE2 * N_URtoDF * N_PARITY / 2] = {0}; -char Slice_Twist_Prun[N_SLICE1 * N_TWIST / 2 + 1] = {0}; -char Slice_Flip_Prun[N_SLICE1 * N_FLIP / 2] = {0}; +signed char Slice_URFtoDLF_Parity_Prun[N_SLICE2 * N_URFtoDLF * N_PARITY / 2] = {0}; +signed char Slice_URtoDF_Parity_Prun[N_SLICE2 * N_URtoDF * N_PARITY / 2] = {0}; +signed char Slice_Twist_Prun[N_SLICE1 * N_TWIST / 2 + 1] = {0}; +signed char Slice_Flip_Prun[N_SLICE1 * N_FLIP / 2] = {0}; int PRUNING_INITED = 0; @@ -46,7 +46,7 @@ void move(coordcube_t* coordcube, int m, const char *cache_dir) char * join_path(const char *dir, const char *filename) { - int path_len = strnlen(dir, 200); + size_t path_len = strnlen(dir, 200); if (path_len == 200) { return NULL; } @@ -81,7 +81,8 @@ int check_cached_table(const char* name, void* ptr, int len, const char *cache_d void read_from_file(void* ptr, int len, const char* name) { FILE* f = fopen(name, "r"); - fread(ptr, len, 1, f); + if (!fread(ptr, len, 1, f)) + ((void)0); // suppress -Wunused-result warning fclose(f); } @@ -256,7 +257,7 @@ void initPruning(const char *cache_dir) for (int i = 0; i < N_SLICE2 * N_URFtoDLF * N_PARITY / 2; i++) Slice_URFtoDLF_Parity_Prun[i] = -1; depth = 0; - setPruning(Slice_URFtoDLF_Parity_Prun, 0, (char) 0); + setPruning(Slice_URFtoDLF_Parity_Prun, 0, 0); done = 1; while (done != N_SLICE2 * N_URFtoDLF * N_PARITY) { for (int i = 0; i < N_SLICE2 * N_URFtoDLF * N_PARITY; i++) { @@ -284,7 +285,7 @@ void initPruning(const char *cache_dir) newParity = parityMove[parity][j]; if (getPruning(Slice_URFtoDLF_Parity_Prun, (N_SLICE2 * newURFtoDLF + newSlice) * 2 + newParity) == 0x0f) { setPruning(Slice_URFtoDLF_Parity_Prun, (N_SLICE2 * newURFtoDLF + newSlice) * 2 + newParity, - (char) (depth + 1)); + (signed char) (depth + 1)); done++; } } @@ -300,7 +301,7 @@ void initPruning(const char *cache_dir) for (int i = 0; i < N_SLICE2 * N_URtoDF * N_PARITY / 2; i++) Slice_URtoDF_Parity_Prun[i] = -1; depth = 0; - setPruning(Slice_URtoDF_Parity_Prun, 0, (char) 0); + setPruning(Slice_URtoDF_Parity_Prun, 0, 0); done = 1; while (done != N_SLICE2 * N_URtoDF * N_PARITY) { for (int i = 0; i < N_SLICE2 * N_URtoDF * N_PARITY; i++) { @@ -328,7 +329,7 @@ void initPruning(const char *cache_dir) newParity = parityMove[parity][j]; if (getPruning(Slice_URtoDF_Parity_Prun, (N_SLICE2 * newURtoDF + newSlice) * 2 + newParity) == 0x0f) { setPruning(Slice_URtoDF_Parity_Prun, (N_SLICE2 * newURtoDF + newSlice) * 2 + newParity, - (char) (depth + 1)); + (signed char) (depth + 1)); done++; } } @@ -344,7 +345,7 @@ void initPruning(const char *cache_dir) for (int i = 0; i < N_SLICE1 * N_TWIST / 2 + 1; i++) Slice_Twist_Prun[i] = -1; depth = 0; - setPruning(Slice_Twist_Prun, 0, (char) 0); + setPruning(Slice_Twist_Prun, 0, 0); done = 1; while (done != N_SLICE1 * N_TWIST) { for (int i = 0; i < N_SLICE1 * N_TWIST; i++) { @@ -354,7 +355,7 @@ void initPruning(const char *cache_dir) int newSlice = FRtoBR_Move[slice * 24][j] / 24; int newTwist = twistMove[twist][j]; if (getPruning(Slice_Twist_Prun, N_SLICE1 * newTwist + newSlice) == 0x0f) { - setPruning(Slice_Twist_Prun, N_SLICE1 * newTwist + newSlice, (char) (depth + 1)); + setPruning(Slice_Twist_Prun, N_SLICE1 * newTwist + newSlice, (signed char) (depth + 1)); done++; } } @@ -369,7 +370,7 @@ void initPruning(const char *cache_dir) for (int i = 0; i < N_SLICE1 * N_FLIP / 2; i++) Slice_Flip_Prun[i] = -1; depth = 0; - setPruning(Slice_Flip_Prun, 0, (char) 0); + setPruning(Slice_Flip_Prun, 0, 0); done = 1; while (done != N_SLICE1 * N_FLIP) { for (int i = 0; i < N_SLICE1 * N_FLIP; i++) { @@ -379,7 +380,7 @@ void initPruning(const char *cache_dir) int newSlice = FRtoBR_Move[slice * 24][j] / 24; int newFlip = flipMove[flip][j]; if (getPruning(Slice_Flip_Prun, N_SLICE1 * newFlip + newSlice) == 0x0f) { - setPruning(Slice_Flip_Prun, N_SLICE1 * newFlip + newSlice, (char) (depth + 1)); + setPruning(Slice_Flip_Prun, N_SLICE1 * newFlip + newSlice, (signed char) (depth + 1)); done++; } } @@ -393,7 +394,7 @@ void initPruning(const char *cache_dir) PRUNING_INITED = 1; } -void setPruning(char *table, int index, char value) { +void setPruning(signed char *table, int index, signed char value) { if ((index & 1) == 0) table[index / 2] &= 0xf0 | value; else @@ -401,8 +402,8 @@ void setPruning(char *table, int index, char value) { } // Extract pruning value -char getPruning(char *table, int index) { - char res; +signed char getPruning(signed char *table, int index) { + signed char res; if ((index & 1) == 0) res = (table[index / 2] & 0x0f); diff --git a/kociemba/ckociemba/cubiecube.c b/kociemba/ckociemba/cubiecube.c index 64f9874..7c4115f 100644 --- a/kociemba/ckociemba/cubiecube.c +++ b/kociemba/ckociemba/cubiecube.c @@ -5,30 +5,30 @@ cubiecube_t * get_moveCube() { static cubiecube_t moveCube[6]; static int moveCube_initialized = 0; - static const corner_t cpU[8] = { UBR, URF, UFL, ULB, DFR, DLF, DBL, DRB }; - static const char coU[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - static const edge_t epU[12] = { UB, UR, UF, UL, DR, DF, DL, DB, FR, FL, BL, BR }; - static const char eoU[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - static const corner_t cpR[8] = { DFR, UFL, ULB, URF, DRB, DLF, DBL, UBR }; - static const char coR[8] = { 2, 0, 0, 1, 1, 0, 0, 2 }; - static const edge_t epR[12] = { FR, UF, UL, UB, BR, DF, DL, DB, DR, FL, BL, UR }; - static const char eoR[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - static const corner_t cpF[8] = { UFL, DLF, ULB, UBR, URF, DFR, DBL, DRB }; - static const char coF[8] = { 1, 2, 0, 0, 2, 1, 0, 0 }; - static const edge_t epF[12] = { UR, FL, UL, UB, DR, FR, DL, DB, UF, DF, BL, BR }; - static const char eoF[12] = { 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0 }; - static const corner_t cpD[8] = { URF, UFL, ULB, UBR, DLF, DBL, DRB, DFR }; - static const char coD[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - static const edge_t epD[12] = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR }; - static const char eoD[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - static const corner_t cpL[8] = { URF, ULB, DBL, UBR, DFR, UFL, DLF, DRB }; - static const char coL[8] = { 0, 1, 2, 0, 0, 2, 1, 0 }; - static const edge_t epL[12] = { UR, UF, BL, UB, DR, DF, FL, DB, FR, UL, DL, BR }; - static const char eoL[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - static const corner_t cpB[8] = { URF, UFL, UBR, DRB, DFR, DLF, ULB, DBL }; - static const char coB[8] = { 0, 0, 1, 2, 0, 0, 2, 1 }; - static const edge_t epB[12] = { UR, UF, UL, BR, DR, DF, DL, BL, FR, FL, UB, DB }; - static const char eoB[12] = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 }; + static const corner_t cpU[8] = { UBR, URF, UFL, ULB, DFR, DLF, DBL, DRB }; + static const signed char coU[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + static const edge_t epU[12] = { UB, UR, UF, UL, DR, DF, DL, DB, FR, FL, BL, BR }; + static const signed char eoU[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + static const corner_t cpR[8] = { DFR, UFL, ULB, URF, DRB, DLF, DBL, UBR }; + static const signed char coR[8] = { 2, 0, 0, 1, 1, 0, 0, 2 }; + static const edge_t epR[12] = { FR, UF, UL, UB, BR, DF, DL, DB, DR, FL, BL, UR }; + static const signed char eoR[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + static const corner_t cpF[8] = { UFL, DLF, ULB, UBR, URF, DFR, DBL, DRB }; + static const signed char coF[8] = { 1, 2, 0, 0, 2, 1, 0, 0 }; + static const edge_t epF[12] = { UR, FL, UL, UB, DR, FR, DL, DB, UF, DF, BL, BR }; + static const signed char eoF[12] = { 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0 }; + static const corner_t cpD[8] = { URF, UFL, ULB, UBR, DLF, DBL, DRB, DFR }; + static const signed char coD[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + static const edge_t epD[12] = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR }; + static const signed char eoD[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + static const corner_t cpL[8] = { URF, ULB, DBL, UBR, DFR, UFL, DLF, DRB }; + static const signed char coL[8] = { 0, 1, 2, 0, 0, 2, 1, 0 }; + static const edge_t epL[12] = { UR, UF, BL, UB, DR, DF, FL, DB, FR, UL, DL, BR }; + static const signed char eoL[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + static const corner_t cpB[8] = { URF, UFL, UBR, DRB, DFR, DLF, ULB, DBL }; + static const signed char coB[8] = { 0, 0, 1, 2, 0, 0, 2, 1 }; + static const edge_t epB[12] = { UR, UF, UL, BR, DR, DF, DL, BL, FR, FL, UB, DB }; + static const signed char eoB[12] = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 }; if (!moveCube_initialized) { memcpy(moveCube[0].cp, cpU, sizeof(cpU)); @@ -65,9 +65,9 @@ cubiecube_t* get_cubiecube() cubiecube_t* result = (cubiecube_t *) calloc(1, sizeof(cubiecube_t)); static const corner_t cp[8] = { URF, UFL, ULB, UBR, DFR, DLF, DBL, DRB }; - static const char co[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + static const signed char co[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static const edge_t ep[12] = { UR, UF, UL, UB, DR, DF, DL, DB, FR, FL, BL, BR }; - static const char eo[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + static const signed char eo[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; memcpy(result->cp, cp, sizeof(cp)); memcpy(result->co, co, sizeof(co)); @@ -133,7 +133,7 @@ facecube_t* toFaceCube(cubiecube_t* cubiecube) for(int i = 0; i < CORNER_COUNT; i++) { int j = cubiecube->cp[i];// cornercubie with index j is at // cornerposition with index i - char ori = cubiecube->co[i];// Orientation of this cubie + signed char ori = cubiecube->co[i];// Orientation of this cubie for (int n = 0; n < 3; n++) fcRet->f[cornerFacelet[i][(n + ori) % 3]] = cornerColor[j][n]; } @@ -141,7 +141,7 @@ facecube_t* toFaceCube(cubiecube_t* cubiecube) { int j = cubiecube->ep[i];// edgecubie with index j is at edgeposition // with index i - char ori = cubiecube->eo[i];// Orientation of this cubie + signed char ori = cubiecube->eo[i];// Orientation of this cubie for (int n = 0; n < 2; n++) fcRet->f[edgeFacelet[i][(n + ori) % 2]] = edgeColor[j][n]; } @@ -151,17 +151,17 @@ facecube_t* toFaceCube(cubiecube_t* cubiecube) void cornerMultiply(cubiecube_t* cubiecube, cubiecube_t* b) { corner_t cPerm[8] = {0}; - char cOri[8] = {0}; + signed char cOri[8] = {0}; for (int corn = 0; corn < CORNER_COUNT; corn++) { cPerm[corn] = cubiecube->cp[b->cp[corn]]; - char oriA = cubiecube->co[b->cp[corn]]; - char oriB = b->co[corn]; - char ori = 0; + signed char oriA = cubiecube->co[b->cp[corn]]; + signed char oriB = b->co[corn]; + signed char ori = 0; if (oriA < 3 && oriB < 3) // if both cubes are regular cubes... { - ori = (char) (oriA + oriB); // just do an addition modulo 3 here + ori = oriA + oriB; // just do an addition modulo 3 here if (ori >= 3) ori -= 3; // the composition is a regular cube @@ -169,19 +169,19 @@ void cornerMultiply(cubiecube_t* cubiecube, cubiecube_t* b) } else if (oriA < 3 && oriB >= 3) // if cube b is in a mirrored // state... { - ori = (char) (oriA + oriB); + ori = oriA + oriB; if (ori >= 6) ori -= 3; // the composition is a mirrored cube } else if (oriA >= 3 && oriB < 3) // if cube a is an a mirrored // state... { - ori = (char) (oriA - oriB); + ori = oriA - oriB; if (ori < 3) ori += 3; // the composition is a mirrored cube } else if (oriA >= 3 && oriB >= 3) // if both cubes are in mirrored // states... { - ori = (char) (oriA - oriB); + ori = oriA - oriB; if (ori < 0) ori += 3; // the composition is a regular cube // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -197,11 +197,11 @@ void cornerMultiply(cubiecube_t* cubiecube, cubiecube_t* b) void edgeMultiply(cubiecube_t* cubiecube, cubiecube_t* b) { edge_t ePerm[12] = {0}; - char eOri[12] = {0}; + signed char eOri[12] = {0}; for(int edge = 0; edge < EDGE_COUNT; edge++) { ePerm[edge] = cubiecube->ep[b->ep[edge]]; - eOri[edge] = (char) ((b->eo[edge] + cubiecube->eo[b->ep[edge]]) % 2); + eOri[edge] = (b->eo[edge] + cubiecube->eo[b->ep[edge]]) % 2; } for(int e = 0; e < EDGE_COUNT; e++) { cubiecube->ep[e] = ePerm[e]; @@ -212,7 +212,7 @@ void edgeMultiply(cubiecube_t* cubiecube, cubiecube_t* b) void multiply(cubiecube_t* cubiecube, cubiecube_t* b) { cornerMultiply(cubiecube, b); - // edgeMultiply(cubiecube, b); + edgeMultiply(cubiecube, b); } void invCubieCube(cubiecube_t* cubiecube, cubiecube_t* c) @@ -224,12 +224,12 @@ void invCubieCube(cubiecube_t* cubiecube, cubiecube_t* c) for (int corn = 0; corn < CORNER_COUNT; corn++) c->cp[cubiecube->cp[corn]] = corn; for (int corn = 0; corn < CORNER_COUNT; corn++) { - char ori = cubiecube->co[c->cp[corn]]; + signed char ori = cubiecube->co[c->cp[corn]]; if (ori >= 3)// Just for completeness. We do not invert mirrored // cubes in the program. c->co[corn] = ori; else {// the standard case - c->co[corn] = (char) -ori; + c->co[corn] = -ori; if (c->co[corn] < 0) c->co[corn] += 3; } @@ -248,10 +248,10 @@ void setTwist(cubiecube_t* cubiecube, short twist) { int twistParity = 0; for (int i = DRB - 1; i >= URF; i--) { - twistParity += cubiecube->co[i] = (char) (twist % 3); + twistParity += cubiecube->co[i] = (signed char) (twist % 3); twist /= 3; } - cubiecube->co[DRB] = (char) ((3 - twistParity % 3) % 3); + cubiecube->co[DRB] = (signed char) ((3 - twistParity % 3) % 3); } short getFlip(cubiecube_t* cubiecube) @@ -266,10 +266,10 @@ void setFlip(cubiecube_t* cubiecube, short flip) { int flipParity = 0; for (int i = BR - 1; i >= UR; i--) { - flipParity += cubiecube->eo[i] = (char) (flip % 2); + flipParity += cubiecube->eo[i] = (signed char) (flip % 2); flip /= 2; } - cubiecube->eo[BR] = (char) ((2 - flipParity % 2) % 2); + cubiecube->eo[BR] = (signed char) ((2 - flipParity % 2) % 2); } short cornerParity(cubiecube_t* cubiecube) diff --git a/kociemba/ckociemba/facecube.c b/kociemba/ckociemba/facecube.c index e851a0d..cfee5de 100644 --- a/kociemba/ckociemba/facecube.c +++ b/kociemba/ckociemba/facecube.c @@ -81,7 +81,7 @@ void to_String(facecube_t* facecube, char* res) cubiecube_t* toCubieCube(facecube_t* facecube) { - unsigned char ori; + signed char ori; cubiecube_t* ccRet = (cubiecube_t*) calloc(1, sizeof(cubiecube_t)); for (int i = 0; i < 8; i++) ccRet->cp[i] = URF;// invalidate corners @@ -100,7 +100,7 @@ cubiecube_t* toCubieCube(facecube_t* facecube) if (col1 == cornerColor[j][1] && col2 == cornerColor[j][2]) { // in cornerposition i we have cornercubie j ccRet->cp[i] = j; - ccRet->co[i] = (char) (ori % 3); + ccRet->co[i] = ori % 3; break; } } diff --git a/kociemba/ckociemba/include/coordcube.h b/kociemba/ckociemba/include/coordcube.h index a6ae84f..cf16181 100644 --- a/kociemba/ckociemba/include/coordcube.h +++ b/kociemba/ckociemba/include/coordcube.h @@ -84,28 +84,28 @@ extern short MergeURtoULandUBtoDF[336][336]; // Pruning table for the permutation of the corners and the UD-slice edges in phase2. // The pruning table entries give a lower estimation for the number of moves to reach the solved cube. -extern char Slice_URFtoDLF_Parity_Prun[N_SLICE2 * N_URFtoDLF * N_PARITY / 2]; +extern signed char Slice_URFtoDLF_Parity_Prun[N_SLICE2 * N_URFtoDLF * N_PARITY / 2]; // Pruning table for the permutation of the edges in phase2. // The pruning table entries give a lower estimation for the number of moves to reach the solved cube. -extern char Slice_URtoDF_Parity_Prun[N_SLICE2 * N_URtoDF * N_PARITY / 2]; +extern signed char Slice_URtoDF_Parity_Prun[N_SLICE2 * N_URtoDF * N_PARITY / 2]; // Pruning table for the twist of the corners and the position (not permutation) of the UD-slice edges in phase1 // The pruning table entries give a lower estimation for the number of moves to reach the H-subgroup. -extern char Slice_Twist_Prun[N_SLICE1 * N_TWIST / 2 + 1]; +extern signed char Slice_Twist_Prun[N_SLICE1 * N_TWIST / 2 + 1]; // Pruning table for the flip of the edges and the position (not permutation) of the UD-slice edges in phase1 // The pruning table entries give a lower estimation for the number of moves to reach the H-subgroup. -extern char Slice_Flip_Prun[N_SLICE1 * N_FLIP / 2]; +extern signed char Slice_Flip_Prun[N_SLICE1 * N_FLIP / 2]; extern int PRUNING_INITED; void initPruning(const char *cache_dir); // Set pruning value in table. Two values are stored in one char. -void setPruning(char *table, int index, char value); +void setPruning(signed char *table, int index, signed char value); // Extract pruning value -char getPruning(char *table, int index); +signed char getPruning(signed char *table, int index); coordcube_t* get_coordcube(cubiecube_t* cubiecube); void move(coordcube_t* coordcube, int m, const char *cache_dir); diff --git a/kociemba/ckociemba/include/cubiecube.h b/kociemba/ckociemba/include/cubiecube.h index 6bbec06..61f1eae 100644 --- a/kociemba/ckociemba/include/cubiecube.h +++ b/kociemba/ckociemba/include/cubiecube.h @@ -8,21 +8,25 @@ #include "edge.h" //Cube on the cubie level -typedef struct { +struct cubiecube { // initialize to Id-Cube // corner permutation corner_t cp[8]; // corner orientation - char co[8]; + signed char co[8]; // edge permutation edge_t ep[12]; // edge orientation - char eo[12]; -} cubiecube_t; + signed char eo[12]; +}; +typedef struct cubiecube cubiecube_t; + +// forward declaration +struct facecube; // this CubieCube array represents the 6 basic cube moves -cubiecube_t* get_moveCube(); -cubiecube_t* get_cubiecube(); +cubiecube_t* get_moveCube(void); +cubiecube_t* get_cubiecube(void); // n choose k int Cnk(int n, int k); @@ -30,7 +34,7 @@ void rotateLeft_corner(corner_t* arr, int l, int r); void rotateRight_corner(corner_t* arr, int l, int r); void rotateLeft_edge(edge_t* arr, int l, int r); void rotateRight_edge(edge_t* arr, int l, int r); -// facecube_t* toFaceCube(cubiecube_t* cubiecube); +struct facecube* toFaceCube(cubiecube_t* cubiecube); void cornerMultiply(cubiecube_t* cubiecube, cubiecube_t* b); void edgeMultiply(cubiecube_t* cubiecube, cubiecube_t* b); void multiply(cubiecube_t* cubiecube, cubiecube_t* b); diff --git a/kociemba/ckociemba/include/facecube.h b/kociemba/ckociemba/include/facecube.h index 687dff3..aeaf376 100644 --- a/kociemba/ckociemba/include/facecube.h +++ b/kociemba/ckociemba/include/facecube.h @@ -5,12 +5,15 @@ #include "color.h" #include "corner.h" #include "edge.h" -#include "cubiecube.h" //Cube on the facelet level -typedef struct { +struct facecube { color_t f[54]; -} facecube_t; +}; +typedef struct facecube facecube_t; + +// forward declaration +struct cubiecube; // Map the corner positions to facelet positions. cornerFacelet[URF.ordinal()][0] e.g. gives the position of the // facelet in the URF corner position, which defines the orientation.
@@ -29,10 +32,10 @@ extern color_t cornerColor[8][3]; // Map the edge positions to facelet colors. extern color_t edgeColor[12][2]; -facecube_t* get_facecube(); +facecube_t* get_facecube(void); facecube_t* get_facecube_fromstring(char* cubeString); void to_String(facecube_t* facecube, char* res); -cubiecube_t* toCubieCube(facecube_t* facecube); +struct cubiecube* toCubieCube(facecube_t* facecube); #endif diff --git a/kociemba/ckociemba/include/search.h b/kociemba/ckociemba/include/search.h index 0a6a1b1..76a25ea 100644 --- a/kociemba/ckociemba/include/search.h +++ b/kociemba/ckociemba/include/search.h @@ -17,7 +17,7 @@ typedef struct { int minDistPhase2[31]; } search_t; -search_t* get_search(); +search_t* get_search(void); // generate the solution string from the array data including a separator between phase1 and phase2 moves char* solutionToString(search_t* search, int length, int depthPhase1); @@ -55,4 +55,9 @@ char* solution(char* facelets, int maxDepth, long timeOut, int useSeparator, con // U,D,R2,F2,L2 and B2 are allowed. int totalDepth(search_t* search, int depthPhase1, int maxDepth); + +// Add a pattern to the state of a cube, so that the solution for new_facelets +// applied to facelets will result into the given pattern +void patternize(char* facelets, char* pattern, char* patternized); + #endif diff --git a/kociemba/ckociemba/search.c b/kociemba/ckociemba/search.c index 59237b1..ca0e0bb 100644 --- a/kociemba/ckociemba/search.c +++ b/kociemba/ckociemba/search.c @@ -300,3 +300,22 @@ int totalDepth(search_t* search, int depthPhase1, int maxDepth) } while (search->minDistPhase2[n + 1] != 0); return depthPhase1 + depthPhase2; } + +void patternize(char* facelets, char* pattern, char* patternized) +{ + facecube_t* start_fc = get_facecube_fromstring(facelets); + facecube_t* pattern_fc = get_facecube_fromstring(pattern); + cubiecube_t* start_cc = toCubieCube(start_fc); + cubiecube_t* pattern_cc = toCubieCube(pattern_fc); + cubiecube_t* inv_pattern_cc = get_cubiecube(); + invCubieCube(pattern_cc, inv_pattern_cc); + multiply(inv_pattern_cc, start_cc); + facecube_t* fc = toFaceCube(inv_pattern_cc); + to_String(fc, patternized); + free(start_fc); + free(pattern_fc); + free(start_cc); + free(pattern_cc); + free(inv_pattern_cc); + free(fc); +} diff --git a/kociemba/ckociemba/solve.c b/kociemba/ckociemba/solve.c index 3d3467e..af8cd4b 100644 --- a/kociemba/ckociemba/solve.c +++ b/kociemba/ckociemba/solve.c @@ -5,8 +5,14 @@ int main(int argc, char **argv) { if (argc > 1) { + char patternized[64]; + char* facelets = argv[1]; + if (argc > 2) { + patternize(facelets, argv[2], patternized); + facelets = patternized; + } char *sol = solution( - argv[1], + facelets, 24, 1000, 0, diff --git a/kociemba/command_line.py b/kociemba/command_line.py index 1bdbcb9..3ae084c 100644 --- a/kociemba/command_line.py +++ b/kociemba/command_line.py @@ -3,7 +3,9 @@ def main(): - if len(sys.argv) > 1: + if len(sys.argv) == 2: print(solve(sys.argv[1])) + elif len(sys.argv) == 3: + print(solve(sys.argv[1], sys.argv[2])) else: - print('Usage: kociemba \nfor example:\nkociemba DRLUUBFBRBLURRLRUBLRDDFDLFUFUFFDBRDUBRUFLLFDDBFLUBLRBD') + print('Usage: kociemba [resulting_cubestring]\nfor example:\nkociemba DRLUUBFBRBLURRLRUBLRDDFDLFUFUFFDBRDUBRUFLLFDDBFLUBLRBD BBURUDBFUFFFRRFUUFLULUFUDLRRDBBDBDBLUDDFLLRRBRLLLBRDDF') diff --git a/kociemba/pykociemba/coordcube.py b/kociemba/pykociemba/coordcube.py index 8b61f69..e2fd768 100644 --- a/kociemba/pykociemba/coordcube.py +++ b/kociemba/pykociemba/coordcube.py @@ -114,7 +114,7 @@ def move(self, m): # ******************************************Phase 1 move tables***************************************************** - log.info('Preparing move table for the twists of the corners...') + log.debug('Preparing move table for the twists of the corners...') # Move table for the twists of the corners # twist < 2187 in phase 2. # twist = 0 in phase 2. @@ -136,7 +136,7 @@ def move(self, m): # Move table for the flips of the edges # flip < 2048 in phase 1 # flip = 0 in phase 2. - log.info('Preparing move table for the flips of the edges') + log.debug('Preparing move table for the flips of the edges') flipMove = load_cachetable('flipMove') if not flipMove: @@ -161,7 +161,7 @@ def move(self, m): ] # ***********************************Phase 1 and 2 movetable******************************************************** - log.info('Preparing move table for the four UD-slice edges FR, FL, Bl and BR') + log.debug('Preparing move table for the four UD-slice edges FR, FL, Bl and BR') # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Move table for the four UD-slice edges FR, FL, Bl and BR # FRtoBRMove < 11880 in phase 1 @@ -188,7 +188,7 @@ def move(self, m): # URFtoDLF < 20160 in phase 1 # URFtoDLF < 20160 in phase 2 # URFtoDLF = 0 for solved cube. - log.info('Preparing move table for permutation of six corners. The positions of the DBL and DRB corners are determined by the parity.') + log.debug('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 range(N_URFtoDLF)] # new short[N_URFtoDLF][N_MOVE] @@ -208,7 +208,7 @@ def move(self, m): # URtoDF < 665280 in phase 1 # URtoDF < 20160 in phase 2 # URtoDF = 0 for solved cube. - 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') + log.debug('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 range(N_URtoDF)] # new short[N_URtoDF][N_MOVE] @@ -227,7 +227,7 @@ def move(self, m): # **************************helper move tables to compute URtoDF for the beginning of phase2************************ # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Move table for the three edges UR,UF and UL in phase1. - log.info('Preparing move table for the three edges UR,UF and UL in phase1.') + log.debug('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 range(N_URtoUL)] # new short[N_URtoUL][N_MOVE] @@ -243,7 +243,7 @@ def move(self, m): # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Move table for the three edges UB,DR and DF in phase1. - log.info('Preparing move table for the three edges UB,DR and DF in phase1.') + log.debug('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 range(N_UBtoDF)] # new short[N_UBtoDF][N_MOVE] @@ -259,7 +259,7 @@ def move(self, m): # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Table to merge the coordinates of the UR,UF,UL and UB,DR,DF edges at the beginning of phase2 - log.info('Preparing table to merge the coordinates of the UR,UF,UL and UB,DR,DF edges at the beginning of phase2') + log.debug('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 range(336)] # new short[336][336] @@ -274,7 +274,7 @@ def move(self, m): # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Pruning table for the permutation of the corners and the UD-slice edges in phase2. # The pruning table entries give a lower estimation for the number of moves to reach the solved cube. - log.info('Preparing pruning table for the permutation of the corners and the UD-slice edges in phase2.') + log.debug('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] @@ -309,7 +309,7 @@ def move(self, m): # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Pruning table for the permutation of the edges in phase2. # The pruning table entries give a lower estimation for the number of moves to reach the solved cube. - log.info('Preparing pruning table for the permutation of the edges in phase2.') + log.debug('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] @@ -343,7 +343,7 @@ def move(self, m): # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Pruning table for the twist of the corners and the position (not permutation) of the UD-slice edges in phase1 # The pruning table entries give a lower estimation for the number of moves to reach the H-subgroup. - log.info('Pruning table for the twist of the corners and the position (not permutation) of the UD-slice edges in phase1') + log.debug('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] @@ -369,7 +369,7 @@ def move(self, m): # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Pruning table for the flip of the edges and the position (not permutation) of the UD-slice edges in phase1 # The pruning table entries give a lower estimation for the number of moves to reach the H-subgroup. - log.info('Pruning table for the flip of the edges and the position (not permutation) of the UD-slice edges in phase1') + log.debug('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] diff --git a/kociemba/pykociemba/cubiecube.py b/kociemba/pykociemba/cubiecube.py index 41c7c37..c81afee 100644 --- a/kociemba/pykociemba/cubiecube.py +++ b/kociemba/pykociemba/cubiecube.py @@ -6,7 +6,6 @@ from .facecube import FaceCube -# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # n choose k def Cnk(n, k): if n < k: @@ -62,16 +61,16 @@ class CubieCube(object): def __init__(self, cp=None, co=None, ep=None, eo=None): # corner permutation - self.cp = copy.copy(cp) if cp else [ URF, UFL, ULB, UBR, DFR, DLF, DBL, DRB ] + self.cp = copy.copy(cp) if cp else [URF, UFL, ULB, UBR, DFR, DLF, DBL, DRB] # corner orientation - self.co = copy.copy(co) if co else [ 0, 0, 0, 0, 0, 0, 0, 0 ] + self.co = copy.copy(co) if co else [0, 0, 0, 0, 0, 0, 0, 0] # edge permutation - self.ep = copy.copy(ep) if ep else [ UR, UF, UL, UB, DR, DF, DL, DB, FR, FL, BL, BR ] + self.ep = copy.copy(ep) if ep else [UR, UF, UL, UB, DR, DF, DL, DB, FR, FL, BL, BR] # edge orientation - self.eo = copy.copy(eo) if eo else [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] + self.eo = copy.copy(eo) if eo else [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] def toFaceCube(self): """return cube in facelet representation""" @@ -119,7 +118,7 @@ def cornerMultiply(self, b): if ori >= 3: ori -= 3 # the composition is a regular cube - # +++++++++++++++++++++not used in this implementation +++++++++++++++++++++++++++++++++++ + # +++++++++++++++++++++not used in this implementation +++++++++++++ elif oriA < 3 and oriB >= 3: # if cube b is in a mirrored # state... ori = (oriA + oriB) & 0xff @@ -135,7 +134,7 @@ def cornerMultiply(self, b): ori = (oriA - oriB) & 0xff if ori < 0: ori += 3 # the composition is a regular cube - # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cOri.append(ori) @@ -169,7 +168,7 @@ def multiply(self, b): """ self.cornerMultiply(b) - # edgeMultiply(b) + self.edgeMultiply(b) def invCubieCube(self, c): """ @@ -195,7 +194,7 @@ def invCubieCube(self, c): if c.co[i] < 0: c.co[i] += 3 - # ********************************************* Get and set coordinates ********************************************* + # ********************* Get and set coordinates *************************** def getTwist(self): """return the twist of the 8 corners. 0 <= twist < 3^7""" @@ -269,8 +268,8 @@ def getFRtoBR(self): return (24 * a + b) & 0xffff def setFRtoBR(self, idx): - sliceEdge = [ FR, FL, BL, BR ] - otherEdge = [ UR, UF, UL, UB, DR, DF, DL, DB ] + sliceEdge = [FR, FL, BL, BR] + otherEdge = [UR, UF, UL, UB, DR, DF, DL, DB] b = idx % 24 # Permutation a = idx // 24 # Combination for i in edge_values: @@ -319,8 +318,8 @@ def getURFtoDLF(self): return (720 * a + b) & 0xffff def setURFtoDLF(self, idx): - corner6 = [ URF, UFL, ULB, UBR, DFR, DLF ] - otherCorner = [ DBL, DRB ] + corner6 = [URF, UFL, ULB, UBR, DFR, DLF] + otherCorner = [DBL, DRB] b = idx % 720 # Permutation a = idx // 720 # Combination for i in corner_values: @@ -367,8 +366,8 @@ def getURtoDF(self): return 720 * a + b def setURtoDF(self, idx): - edge6 = [ UR, UF, UL, UB, DR, DF ] - otherEdge = [ DL, DB, FR, FL, BL, BR ] + edge6 = [UR, UF, UL, UB, DR, DF] + otherEdge = [DL, DB, FR, FL, BL, BR] b = idx % 720 # Permutation a = idx // 720 # Combination for i in edge_values: @@ -416,7 +415,7 @@ def getURtoUL(self): return (6 * a + b) & 0xffff def setURtoUL(self, idx): - edge3 = [ UR, UF, UL ] + edge3 = [UR, UF, UL] b = idx % 6 # Permutation a = idx // 6 # Combination for i in edge_values: @@ -457,7 +456,7 @@ def getUBtoDF(self): return (6 * a + b) & 0xffff def setUBtoDF(self, idx): - edge3 = [ UB, DR, DF ] + edge3 = [UB, DR, DF] b = idx % 6 # Permutation a = idx // 6 # Combination for i in edge_values: @@ -490,7 +489,7 @@ def getURFtoDLB(self): return b def setURFtoDLB(self, idx): - perm = [ URF, UFL, ULB, UBR, DFR, DLF, DBL, DRB ] + perm = [URF, UFL, ULB, UBR, DFR, DLF, DBL, DRB] for j in range(1, 8): k = idx % (j + 1) idx //= j + 1 @@ -515,7 +514,7 @@ def getURtoBR(self): return b def setURtoBR(self, idx): - perm = [ UR, UF, UL, UB, DR, DF, DL, DB, FR, FL, BL, BR ] + perm = [UR, UF, UL, UB, DR, DF, DL, DB, FR, FL, BL, BR] for j in range(1, 12): k = idx % (j + 1) idx //= j + 1 @@ -570,69 +569,40 @@ def verify(self): return 0 # cube ok -# ************************************** Moves on the cubie level *************************************************** - -cpU = [ UBR, URF, UFL, ULB, DFR, DLF, DBL, DRB ] -coU = [ 0, 0, 0, 0, 0, 0, 0, 0 ] -epU = [ UB, UR, UF, UL, DR, DF, DL, DB, FR, FL, BL, BR ] -eoU = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] - -cpR = [ DFR, UFL, ULB, URF, DRB, DLF, DBL, UBR ] -coR = [ 2, 0, 0, 1, 1, 0, 0, 2 ] -epR = [ FR, UF, UL, UB, BR, DF, DL, DB, DR, FL, BL, UR ] -eoR = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] -cpF = [ UFL, DLF, ULB, UBR, URF, DFR, DBL, DRB ] -coF = [ 1, 2, 0, 0, 2, 1, 0, 0 ] -epF = [ UR, FL, UL, UB, DR, FR, DL, DB, UF, DF, BL, BR ] -eoF = [ 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0 ] -cpD = [ URF, UFL, ULB, UBR, DLF, DBL, DRB, DFR ] -coD = [ 0, 0, 0, 0, 0, 0, 0, 0 ] -epD = [ UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR ] -eoD = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] -cpL = [ URF, ULB, DBL, UBR, DFR, UFL, DLF, DRB ] -coL = [ 0, 1, 2, 0, 0, 2, 1, 0 ] -epL = [ UR, UF, BL, UB, DR, DF, FL, DB, FR, UL, DL, BR ] -eoL = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] -cpB = [ URF, UFL, UBR, DRB, DFR, DLF, ULB, DBL ] -coB = [ 0, 0, 1, 2, 0, 0, 2, 1 ] -epB = [ UR, UF, UL, BR, DR, DF, DL, BL, FR, FL, UB, DB ] -eoB = [ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 ] +# ************************ Moves on the cubie level **************************** + +cpU = [UBR, URF, UFL, ULB, DFR, DLF, DBL, DRB] +coU = [0, 0, 0, 0, 0, 0, 0, 0] +epU = [UB, UR, UF, UL, DR, DF, DL, DB, FR, FL, BL, BR] +eoU = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + +cpR = [DFR, UFL, ULB, URF, DRB, DLF, DBL, UBR] +coR = [2, 0, 0, 1, 1, 0, 0, 2] +epR = [FR, UF, UL, UB, BR, DF, DL, DB, DR, FL, BL, UR] +eoR = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +cpF = [UFL, DLF, ULB, UBR, URF, DFR, DBL, DRB] +coF = [1, 2, 0, 0, 2, 1, 0, 0] +epF = [UR, FL, UL, UB, DR, FR, DL, DB, UF, DF, BL, BR] +eoF = [0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0] +cpD = [URF, UFL, ULB, UBR, DLF, DBL, DRB, DFR] +coD = [0, 0, 0, 0, 0, 0, 0, 0] +epD = [UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR] +eoD = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +cpL = [URF, ULB, DBL, UBR, DFR, UFL, DLF, DRB] +coL = [0, 1, 2, 0, 0, 2, 1, 0] +epL = [UR, UF, BL, UB, DR, DF, FL, DB, FR, UL, DL, BR] +eoL = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +cpB = [URF, UFL, UBR, DRB, DFR, DLF, ULB, DBL] +coB = [0, 0, 1, 2, 0, 0, 2, 1] +epB = [UR, UF, UL, BR, DR, DF, DL, BL, FR, FL, UB, DB] +eoB = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1] # this CubieCube array represents the 6 basic cube moves -moveCube = [None] * 6 # new CubieCube[6] - -moveCube[0] = CubieCube() -moveCube[0].cp = cpU -moveCube[0].co = coU -moveCube[0].ep = epU -moveCube[0].eo = eoU - -moveCube[1] = CubieCube() -moveCube[1].cp = cpR -moveCube[1].co = coR -moveCube[1].ep = epR -moveCube[1].eo = eoR - -moveCube[2] = CubieCube() -moveCube[2].cp = cpF -moveCube[2].co = coF -moveCube[2].ep = epF -moveCube[2].eo = eoF - -moveCube[3] = CubieCube() -moveCube[3].cp = cpD -moveCube[3].co = coD -moveCube[3].ep = epD -moveCube[3].eo = eoD - -moveCube[4] = CubieCube() -moveCube[4].cp = cpL -moveCube[4].co = coL -moveCube[4].ep = epL -moveCube[4].eo = eoL - -moveCube[5] = CubieCube() -moveCube[5].cp = cpB -moveCube[5].co = coB -moveCube[5].ep = epB -moveCube[5].eo = eoB +moveCube = [ + CubieCube(cp=cpU, co=coU, ep=epU, eo=eoU), + CubieCube(cp=cpR, co=coR, ep=epR, eo=eoR), + CubieCube(cp=cpF, co=coF, ep=epF, eo=eoF), + CubieCube(cp=cpD, co=coD, ep=epD, eo=eoD), + CubieCube(cp=cpL, co=coL, ep=epL, eo=eoL), + CubieCube(cp=cpB, co=coB, ep=epB, eo=eoB), +] diff --git a/kociemba/pykociemba/facecube.py b/kociemba/pykociemba/facecube.py index 03668a5..7883bca 100644 --- a/kociemba/pykociemba/facecube.py +++ b/kociemba/pykociemba/facecube.py @@ -53,7 +53,7 @@ def __init__(self, cubeString="UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBB # Gives string representation of a facelet cube def to_String(self): - return ''.join(self.f) + return ''.join(color_keys[c] for c in self.f) # Gives CubieCube representation of a faceletcube def toCubieCube(self): diff --git a/kociemba/pykociemba/search.py b/kociemba/pykociemba/search.py index de49bd3..855de54 100644 --- a/kociemba/pykociemba/search.py +++ b/kociemba/pykociemba/search.py @@ -3,7 +3,7 @@ from .color import colors from .facecube import FaceCube from .coordcube import CoordCube, getPruning - +from .cubiecube import CubieCube class Search(object): """Class Search implements the Two-Phase-Algorithm.""" @@ -312,3 +312,10 @@ def totalDepth(self, depthPhase1, maxDepth): break return depthPhase1 + depthPhase2 + +def patternize(facelets, pattern): + facelets_cc = FaceCube(facelets).toCubieCube() + patternized_cc = CubieCube() + FaceCube(pattern).toCubieCube().invCubieCube(patternized_cc) + patternized_cc.multiply(facelets_cc) + return patternized_cc.toFaceCube().to_String() diff --git a/kociemba/pykociemba/tools.py b/kociemba/pykociemba/tools.py index 5fe34f5..08e008b 100644 --- a/kociemba/pykociemba/tools.py +++ b/kociemba/pykociemba/tools.py @@ -54,3 +54,24 @@ def randomCube(): break fc = cc.toFaceCube() return fc.to_String() + + +def randomLastLayerCube(): + """ + Generates a cube with a random last layer. + @return A cube with a random last layer and otherwise solved facelets in the string representation. + """ + cc = CubieCube() + cc.setFlip(random.choice([0, 24, 40, 48, 72, 80, 96, 120])) + cc.setTwist(random.randint(0, 26)) + while True: + perms = [0, 624, 3744, 3840, 4344, 4440, 26064, 26160, 26664, 26760, + 27360, 27984, 30384, 30480, 30984, 31080, 31680, 32304, 35304, + 35400, 36000, 36624, 39744, 39840] + cc.setURFtoDLB(random.choice(perms)) + cc.setURtoBR(random.choice(perms)) + + if (cc.edgeParity() ^ cc.cornerParity()) == 0: + break + fc = cc.toFaceCube() + return fc.to_String() diff --git a/tests/test_solve.py b/tests/test_solve.py index e447ca4..74a7cdc 100644 --- a/tests/test_solve.py +++ b/tests/test_solve.py @@ -307,6 +307,49 @@ def test_solve_function(input, expected): assert solve(input) == expected +@pytest.mark.parametrize("input,pattern,expected", [ + ("UUFDUBFDUBRUFRULRDDBRRFDUUBRLDBDDDLBLLLFLFRLFLBBRBURFF", + "FBULUBBULFRFFRDBRBRLDLFDFUDLFLFDDRULRBUULFDRURDDLBRUBB", + "U' L2 F' B2 U2 D' B2 R U B' U2 R' D' B2 R2 U' F2 R2 U' D2 F2"), + + ("UUFLUFBULDLRURUUFBUBBFFLDBRFDBLDRDRRFDLBLDFBRURLFBRDDL", + "RRRUUFRLBLDFRRDULLUBDBFUULLRUFFDFLLDBFBRLUURFDDDBBBFDB", + "B2 D' F2 D2 B' D' R2 F D' R F2 R2 D2 R2 U B2 U2 R2 F2"), + + ("DLLLUULDRBFUFRRFFLFBDRFRUBRBUUDDLBLFFDDRLDDFRBBRBBUUUL", + "UULRUFDFBRDFFRDFBDFRURFUUFLLLDDDLDDBRURBLBLRBULFLBURBB", + "U2 F B L' U' B2 D F' B2 U2 D2 R' U2 R2 U R2 D' B2 U2 R2 B2 L2"), + + ("FBURUFDDLFDBLRLUBBFLDRFFRBFBLRFDUBRDLDRFLBURDLDUUBULUR", + "LFBRUULLLUFRDRDUDFDDFRFRUBFLRRLDBUBDFFBBLURUBDLDFBURLB", + "L' U' D2 B2 L D' B R L' B U2 D2 R2 F2 B2 U' B2 U2 L2 F2"), + + ("LRDBURRFDFBFBRUBLBUDRRFLLLRUFDFDURRLDDBDLDUUFLUBBBLUFF", + "LDLLUBFRUBDBLRFLBRUBRDFDRBDDUFRDLLUDUFRULFUFFDRFUBRBLB", + "U D2 B D' R' U' F' D' F' L2 F' U2 F2 D L2 U R2 U' L2 U'"), + + ("BBLFUFFRRBDFDRLUBURBDUFRUDBRLLRDUDBRLRDLLFFUFULDUBFBDL", + "ULLFUUDURDRBLRDUBDLBFFFDLLRBUBRDRUBBFRFLLUFDUDFLFBBRDR", + "R' D2 B' R F D2 F2 D F R' L2 F2 U' R2 D F2 U D R2 D'"), + + ("DRLLUUURBRBFBRUDLULBUFFDLDFDFLRDDDLFFBBRLUBFBUURLBDRFR", + "LFFFUBDLDRLUBRRLDBFUBDFDRRBFBDFDRBUUFRRDLFLLULUDUBLRBU", + "U' F R2 U B2 L' B2 U2 B R F U R2 B2 U D F2 U' B2 D'"), + + ("DDULUULFDFRRBRURDDDURFFDUBULRFUDFLFBLBBDLRFBBBLFLBRRLU", + "FRLLULDFLFFUDRBRRRFDDUFRDBDBLBBDFUBULURDLFRDLBUUUBLFRB", + "F L D R B U2 L B' L2 D2 R' D' B2 D F2 B2 D L2 D B2 R2"), + + ("DBBUUBUDBRRDRRDLUFLFUDFFRUFBLUFDRFBDLFBBLRRLDLUFLBLRDU", + "RBRFULBBLUUUDRDBRRLUFBFLRLLDFUUDUDFDUDDRLLFFFFDBRBBBRL", + "R' F' R B2 R D B L D2 L F' U' L2 D2 F2 U' B2 R2 F2 L2 D'"), + + ("DRFFUBLBFDRDBRULRRUDLLFURRBFFDFDDLDBRUFDLBULURUBLBLUFB", + "DLUDUFUFRURFBRULLLLDBUFDDUFFRULDUDBDRRBBLFLFRRDBBBLFRB", + "U2 R U2 R B' L' D B D F L' U B2 D2 R2 D2 R2 D L2 U B2") +]) +def test_solve_pattern_function(input, pattern, expected): + assert solve(input, pattern) == expected if __name__ == '__main__': import sys