Skip to content

Commit

Permalink
Merge pull request #3 from muodov/python-package
Browse files Browse the repository at this point in the history
Python package
  • Loading branch information
muodov committed Dec 23, 2015
2 parents 92e0a5a + 0033933 commit acabaa8
Show file tree
Hide file tree
Showing 58 changed files with 585 additions and 452 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
kociemba/ckociemba/bin/*
kociemba/ckociemba/cache/*

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

# C extensions
*.so
*.o

# Distribution / packaging
.Python
Expand Down
7 changes: 0 additions & 7 deletions Makefile

This file was deleted.

40 changes: 40 additions & 0 deletions kociemba/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import warnings


class SlowContextWarning(Warning):
pass

try:
import os
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()
else:
raise ValueError('Error. Probably cubestring is invalid')
except ImportError:
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. "
"If performance is important to you, check official "
"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()


def solve(cubestring):
"""
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'"
"""

return _solve(cubestring)

__all__ = ['solve']
34 changes: 34 additions & 0 deletions kociemba/build_ckociemba.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import cffi

ffi = cffi.FFI()
ffi.set_source(
"kociemba.ckociembawrapper",
"""
#include <stdio.h>
#include <stdlib.h>
#include <search.h>
char* solve(char *cubestring, char *cache_dir)
{
char *sol = solution(
cubestring,
24,
1000,
0,
cache_dir
);
return sol;
}
""",
include_dirs=['kociemba/ckociemba/include'],
sources=[
'kociemba/ckociemba/coordcube.c',
'kociemba/ckociemba/cubiecube.c',
'kociemba/ckociemba/facecube.c',
'kociemba/ckociemba/search.c'],
extra_compile_args=['-std=c99'])

ffi.cdef("char* solve(char *cubestring, char *cache_dir);")

if __name__ == "__main__":
ffi.compile(verbose=True)
10 changes: 10 additions & 0 deletions kociemba/ckociemba/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CKOCIEMBA_SRC = coordcube.c cubiecube.c facecube.c search.c
CKOCIEMBA_INCLUDE = include
CFLAGS = -std=c99
BINDIR = bin
BIN = kociemba

solve: solve.c $(CKOCIEMBA_SRC)
mkdir -p $(BINDIR)
gcc $(CFLAGS) $(CKOCIEMBA_SRC) -I$(CKOCIEMBA_INCLUDE) solve.c -o $(BINDIR)/$(BIN)

126 changes: 74 additions & 52 deletions ckociemba/coordcube.c → kociemba/ckociemba/coordcube.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@ short parityMove[2][18] = {
{ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0 }
};
short FRtoBR_Move[N_FRtoBR][N_MOVE];
short URFtoDLF_Move[N_URFtoDLF][N_MOVE] = {0};
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};
short URFtoDLF_Move[N_URFtoDLF][N_MOVE] = {{0}};
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};

int PRUNING_INITED = 0;

void move(coordcube_t* coordcube, int m)
void move(coordcube_t* coordcube, int m, const char *cache_dir)
{
if (PRUNING_INITED == 0) {
initPruning();
initPruning(cache_dir);
}
coordcube->twist = twistMove[coordcube->twist][m];
coordcube->flip = flipMove[coordcube->flip][m];
Expand All @@ -44,42 +44,63 @@ void move(coordcube_t* coordcube, int m)
coordcube->URtoDF = MergeURtoULandUBtoDF[coordcube->URtoUL][coordcube->UBtoDF];
}

int check_cached_table(const char* name, void* ptr, int len)
char * join_path(const char *dir, const char *filename)
{
char fname[100] = "prunetables/";
strncat(fname, name, 30);
int path_len = strnlen(dir, 200);
if (path_len == 200) {
return NULL;
}
char *fpath = calloc(path_len + 32, 1);
strcpy(fpath, dir);
strcat(fpath, "/");
strncat(fpath, filename, 30);
return fpath;
}

int check_cached_table(const char* name, void* ptr, int len, const char *cache_dir)
{
char *fname = join_path(cache_dir, name);
if (fname == NULL) {
fprintf(stderr, "Path to cache tables is too long\n");
return -1;
}
int res = 0;
if (access(fname, F_OK | R_OK) != -1) {
fprintf(stderr, "Found cache for %s. Loading...", name);
read_from_file(ptr, len, name);
fprintf(stderr, "done.\n");
return 0;
// fprintf(stderr, "Found cache for %s. Loading...", name);
read_from_file(ptr, len, fname);
// fprintf(stderr, "done.\n");
res = 0;
} else {
fprintf(stderr, "Cache for %s was not found. Recalculating.\n", name);
return -1;
fprintf(stderr, "Cache table %s was not found. Recalculating.\n", fname);
res = 1;
}
free(fname);
return res;
}

void read_from_file(void* ptr, int len, const char* name)
{
char fname[100] = "prunetables/";
strncat(fname, name, 30);
FILE* f = fopen(fname, "r");
FILE* f = fopen(name, "r");
fread(ptr, len, 1, f);
fclose(f);
}

void dump_to_file(void* ptr, int len, const char* name)
void dump_to_file(void* ptr, int len, const char* name, const char *cache_dir)
{
int status;
status = mkdir("prunetables", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
status = mkdir(cache_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (status == 0 || errno == EEXIST) {
char fname[100] = "prunetables/";
strncat(fname, name, 30);
FILE* f = fopen(fname, "w");
fwrite(ptr, len, 1, f);
fclose(f);
char *fname = join_path(cache_dir, name);
if (fname == NULL) {
fprintf(stderr, "Path to cache tables is too long\n");
} else {
FILE* f = fopen(fname, "w");
fwrite(ptr, len, 1, f);
free(fname);
fclose(f);
}
} else {
fprintf(stderr, "cannot create prunetables/ directory\n");
fprintf(stderr, "cannot create cache tables directory\n");
}
}

Expand All @@ -99,11 +120,12 @@ coordcube_t* get_coordcube(cubiecube_t* cubiecube)
return result;
}

void initPruning()
void initPruning(const char *cache_dir)
{
cubiecube_t* a;
cubiecube_t* moveCube = get_moveCube();

if(check_cached_table("twistMove", (void*) twistMove, sizeof(twistMove)) != 0) {
if(check_cached_table("twistMove", (void*) twistMove, sizeof(twistMove), cache_dir) != 0) {
a = get_cubiecube();
for (short i = 0; i < N_TWIST; i++) {
setTwist(a, i);
Expand All @@ -116,10 +138,10 @@ void initPruning()
}
}
free(a);
dump_to_file((void*) twistMove, sizeof(twistMove), "twistMove");
dump_to_file((void*) twistMove, sizeof(twistMove), "twistMove", cache_dir);
}

if(check_cached_table("flipMove", (void*) flipMove, sizeof(flipMove)) != 0) {
if(check_cached_table("flipMove", (void*) flipMove, sizeof(flipMove), cache_dir) != 0) {
a = get_cubiecube();
for (short i = 0; i < N_FLIP; i++) {
setFlip(a, i);
Expand All @@ -132,10 +154,10 @@ void initPruning()
}
}
free(a);
dump_to_file((void*) flipMove, sizeof(flipMove), "flipMove");
dump_to_file((void*) flipMove, sizeof(flipMove), "flipMove", cache_dir);
}

if(check_cached_table("FRtoBR_Move", (void*) FRtoBR_Move, sizeof(FRtoBR_Move)) != 0) {
if(check_cached_table("FRtoBR_Move", (void*) FRtoBR_Move, sizeof(FRtoBR_Move), cache_dir) != 0) {
a = get_cubiecube();
for (short i = 0; i < N_FRtoBR; i++) {
setFRtoBR(a, i);
Expand All @@ -148,10 +170,10 @@ void initPruning()
}
}
free(a);
dump_to_file((void*) FRtoBR_Move, sizeof(FRtoBR_Move), "FRtoBR_Move");
dump_to_file((void*) FRtoBR_Move, sizeof(FRtoBR_Move), "FRtoBR_Move", cache_dir);
}

if(check_cached_table("URFtoDLF_Move", (void*) URFtoDLF_Move, sizeof(URFtoDLF_Move)) != 0) {
if(check_cached_table("URFtoDLF_Move", (void*) URFtoDLF_Move, sizeof(URFtoDLF_Move), cache_dir) != 0) {
a = get_cubiecube();
for (short i = 0; i < N_URFtoDLF; i++) {
setURFtoDLF(a, i);
Expand All @@ -164,10 +186,10 @@ void initPruning()
}
}
free(a);
dump_to_file((void*) URFtoDLF_Move, sizeof(URFtoDLF_Move), "URFtoDLF_Move");
dump_to_file((void*) URFtoDLF_Move, sizeof(URFtoDLF_Move), "URFtoDLF_Move", cache_dir);
}

if(check_cached_table("URtoDF_Move", (void*) URtoDF_Move, sizeof(URtoDF_Move)) != 0) {
if(check_cached_table("URtoDF_Move", (void*) URtoDF_Move, sizeof(URtoDF_Move), cache_dir) != 0) {
a = get_cubiecube();
for (short i = 0; i < N_URtoDF; i++) {
setURtoDF(a, i);
Expand All @@ -182,10 +204,10 @@ void initPruning()
}
}
free(a);
dump_to_file((void*) URtoDF_Move, sizeof(URtoDF_Move), "URtoDF_Move");
dump_to_file((void*) URtoDF_Move, sizeof(URtoDF_Move), "URtoDF_Move", cache_dir);
}

if(check_cached_table("URtoUL_Move", (void*) URtoUL_Move, sizeof(URtoUL_Move)) != 0) {
if(check_cached_table("URtoUL_Move", (void*) URtoUL_Move, sizeof(URtoUL_Move), cache_dir) != 0) {
a = get_cubiecube();
for (short i = 0; i < N_URtoUL; i++) {
setURtoUL(a, i);
Expand All @@ -198,10 +220,10 @@ void initPruning()
}
}
free(a);
dump_to_file((void*) URtoUL_Move, sizeof(URtoUL_Move), "URtoUL_Move");
dump_to_file((void*) URtoUL_Move, sizeof(URtoUL_Move), "URtoUL_Move", cache_dir);
}

if(check_cached_table("UBtoDF_Move", (void*) UBtoDF_Move, sizeof(UBtoDF_Move)) != 0) {
if(check_cached_table("UBtoDF_Move", (void*) UBtoDF_Move, sizeof(UBtoDF_Move), cache_dir) != 0) {
a = get_cubiecube();
for (short i = 0; i < N_UBtoDF; i++) {
setUBtoDF(a, i);
Expand All @@ -214,23 +236,23 @@ void initPruning()
}
}
free(a);
dump_to_file((void*) UBtoDF_Move, sizeof(UBtoDF_Move), "UBtoDF_Move");
dump_to_file((void*) UBtoDF_Move, sizeof(UBtoDF_Move), "UBtoDF_Move", cache_dir);
}

if(check_cached_table("MergeURtoULandUBtoDF", (void*) MergeURtoULandUBtoDF, sizeof(MergeURtoULandUBtoDF)) != 0) {
if(check_cached_table("MergeURtoULandUBtoDF", (void*) MergeURtoULandUBtoDF, sizeof(MergeURtoULandUBtoDF), cache_dir) != 0) {
// 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 (short uRtoUL = 0; uRtoUL < 336; uRtoUL++) {
for (short uBtoDF = 0; uBtoDF < 336; uBtoDF++) {
MergeURtoULandUBtoDF[uRtoUL][uBtoDF] = (short) getURtoDF_standalone(uRtoUL, uBtoDF);
}
}
dump_to_file((void*) MergeURtoULandUBtoDF, sizeof(MergeURtoULandUBtoDF), "MergeURtoULandUBtoDF");
dump_to_file((void*) MergeURtoULandUBtoDF, sizeof(MergeURtoULandUBtoDF), "MergeURtoULandUBtoDF", cache_dir);
}

int depth, done;

if(check_cached_table("Slice_URFtoDLF_Parity_Prun", (void*) Slice_URFtoDLF_Parity_Prun, sizeof(Slice_URFtoDLF_Parity_Prun)) != 0) {
if(check_cached_table("Slice_URFtoDLF_Parity_Prun", (void*) Slice_URFtoDLF_Parity_Prun, sizeof(Slice_URFtoDLF_Parity_Prun), cache_dir) != 0) {
for (int i = 0; i < N_SLICE2 * N_URFtoDLF * N_PARITY / 2; i++)
Slice_URFtoDLF_Parity_Prun[i] = -1;
depth = 0;
Expand Down Expand Up @@ -271,10 +293,10 @@ void initPruning()
}
depth++;
}
dump_to_file((void*) Slice_URFtoDLF_Parity_Prun, sizeof(Slice_URFtoDLF_Parity_Prun), "Slice_URFtoDLF_Parity_Prun");
dump_to_file((void*) Slice_URFtoDLF_Parity_Prun, sizeof(Slice_URFtoDLF_Parity_Prun), "Slice_URFtoDLF_Parity_Prun", cache_dir);
}

if(check_cached_table("Slice_URtoDF_Parity_Prun", (void*) Slice_URtoDF_Parity_Prun, sizeof(Slice_URtoDF_Parity_Prun)) != 0) {
if(check_cached_table("Slice_URtoDF_Parity_Prun", (void*) Slice_URtoDF_Parity_Prun, sizeof(Slice_URtoDF_Parity_Prun), cache_dir) != 0) {
for (int i = 0; i < N_SLICE2 * N_URtoDF * N_PARITY / 2; i++)
Slice_URtoDF_Parity_Prun[i] = -1;
depth = 0;
Expand Down Expand Up @@ -315,10 +337,10 @@ void initPruning()
}
depth++;
}
dump_to_file((void*) Slice_URtoDF_Parity_Prun, sizeof(Slice_URtoDF_Parity_Prun), "Slice_URtoDF_Parity_Prun");
dump_to_file((void*) Slice_URtoDF_Parity_Prun, sizeof(Slice_URtoDF_Parity_Prun), "Slice_URtoDF_Parity_Prun", cache_dir);
}

if(check_cached_table("Slice_Twist_Prun", (void*) Slice_Twist_Prun, sizeof(Slice_Twist_Prun)) != 0) {
if(check_cached_table("Slice_Twist_Prun", (void*) Slice_Twist_Prun, sizeof(Slice_Twist_Prun), cache_dir) != 0) {
for (int i = 0; i < N_SLICE1 * N_TWIST / 2 + 1; i++)
Slice_Twist_Prun[i] = -1;
depth = 0;
Expand All @@ -340,10 +362,10 @@ void initPruning()
}
depth++;
}
dump_to_file((void*) Slice_Twist_Prun, sizeof(Slice_Twist_Prun), "Slice_Twist_Prun");
dump_to_file((void*) Slice_Twist_Prun, sizeof(Slice_Twist_Prun), "Slice_Twist_Prun", cache_dir);
}

if(check_cached_table("Slice_Flip_Prun", (void*) Slice_Flip_Prun, sizeof(Slice_Flip_Prun)) != 0) {
if(check_cached_table("Slice_Flip_Prun", (void*) Slice_Flip_Prun, sizeof(Slice_Flip_Prun), cache_dir) != 0) {
for (int i = 0; i < N_SLICE1 * N_FLIP / 2; i++)
Slice_Flip_Prun[i] = -1;
depth = 0;
Expand All @@ -365,7 +387,7 @@ void initPruning()
}
depth++;
}
dump_to_file((void*) Slice_Flip_Prun, sizeof(Slice_Flip_Prun), "Slice_Flip_Prun");
dump_to_file((void*) Slice_Flip_Prun, sizeof(Slice_Flip_Prun), "Slice_Flip_Prun", cache_dir);
}

PRUNING_INITED = 1;
Expand Down
Loading

0 comments on commit acabaa8

Please sign in to comment.