nissy-core

The "engine" of nissy, including the H48 optimal solver.
git clone https://git.tronto.net/nissy-core
Download | Log | Files | Refs | README | LICENSE

commit 8b72e391c7185e3da0dfbf0ab60068ac37e4d5cc
parent 510a7471348788fccba6b7c4b9f7b7cc9aee6ba9
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Tue, 22 Apr 2025 09:00:15 +0200

Removed old scripts and updated public API

Diffstat:
Acpp/examples/move.cpp | 17+++++++++++++++++
Dcpp/examples/move_convert.cpp | 24------------------------
Mcpp/nissy.cpp | 66++++++++++++++++++++++--------------------------------------------
Mcpp/nissy.h | 7+------
Mpython/nissy_module.c | 59+++++++++++++++--------------------------------------------
Mshell/shell.c | 97++++++++++++-------------------------------------------------------------------
Msrc/core/core.h | 1-
Msrc/core/cube.h | 190+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/core/io_formats.h | 403-------------------------------------------------------------------------------
Msrc/nissy.c | 80++++++++++++++++++-------------------------------------------------------------
Msrc/nissy.h | 98++++++++++++++++++++++++-------------------------------------------------------
Mtools/300_solve_small/solve_small.c | 2+-
Mtools/301_solve_file/solve_file.c | 2+-
Mtools/302_solve_multisol/solve_multisol.c | 2+-
Mtools/400_solvetest/solve_test.c | 2+-
Autils/convert.c | 409+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dutils/genmovecode.sh | 15---------------
Dutils/genmoveswitch.sh | 8--------
Dutils/gentranscode.sh | 25-------------------------
Dutils/gentransswitch.sh | 14--------------
Dutils/gentranstests.sh | 35-----------------------------------
Dutils/h48_to_lst.c | 22----------------------
Dutils/invert.c | 19-------------------
Dutils/mirror.sh | 3---
24 files changed, 720 insertions(+), 880 deletions(-)

diff --git a/cpp/examples/move.cpp b/cpp/examples/move.cpp @@ -0,0 +1,17 @@ +/* A simple example showing how to move a cube and print it in H48 format. */ + +#include "../nissy.h" +#include <iostream> + +int main() { + nissy::cube c; + if (!c.move("R' U' F").ok()) { + std::cout << "Error moving the cube!" << std::endl; + return 1; + } + + auto str = c.to_string(); + std::cout << "Cube after R' U' F:" << std::endl << str << std::endl; + + return 0; +} diff --git a/cpp/examples/move_convert.cpp b/cpp/examples/move_convert.cpp @@ -1,24 +0,0 @@ -/* A simple example showing how to move a cube and print it in H48 format. */ - -#include "../nissy.h" -#include <iostream> - -int main() { - nissy::cube c; - if (!c.move("R' U' F").ok()) { - std::cout << "Error moving the cube!" << std::endl; - return 1; - } - - auto string_or_error = c.to_string("H48"); - if (std::holds_alternative<nissy::error>(string_or_error)) { - std::cout << "Error converting cube!" << std::endl; - return 1; - } - - auto str = std::get<std::string>(string_or_error); - std::cout << "Cube in H48 format after R' U' F:" << std::endl - << str << std::endl; - - return 0; -} diff --git a/cpp/nissy.cpp b/cpp/nissy.cpp @@ -13,8 +13,6 @@ extern "C" { long long nissy_inverse(const char *, char *); long long nissy_applymoves(const char *, const char *, char *); long long nissy_applytrans(const char *, const char *, char *); - long long nissy_convert(const char *, const char *, const char *, - unsigned, char *); long long nissy_getcube(long long, long long, long long, long long, const char *, char *); long long nissy_solverinfo(const char *, char *); @@ -43,7 +41,6 @@ namespace nissy { const error error::UNSOLVABLE_CUBE{-11}; const error error::INVALID_MOVES{-20}; const error error::INVALID_TRANS{-30}; - const error error::INVALID_FORMAT{-40}; const error error::INVALID_SOLVER{-50}; const error error::NULL_POINTER{-60}; const error error::BUFFER_SIZE{-61}; @@ -52,9 +49,7 @@ namespace nissy { const error error::UNKNOWN{-999}; namespace size { - constexpr size_t B32 = 22; - constexpr size_t H48 = 88; - constexpr size_t CUBE_MAX = H48; + constexpr size_t CUBE = 22; constexpr size_t TRANSFORMATION = 12; constexpr size_t DATAID = 255; } @@ -65,71 +60,54 @@ namespace nissy { error cube::move(const std::string& moves) { - char result[size::B32]; + char result[size::CUBE]; long long err = nissy_applymoves( - m_b32.c_str(), moves.c_str(), result); + m_str.c_str(), moves.c_str(), result); if (err < 0) return error{err}; - m_b32 = result; + m_str = result; return error::OK; } error cube::transform(const std::string& trans) { - char result[size::B32]; + char result[size::CUBE]; long long err = nissy_applytrans( - m_b32.c_str(), trans.c_str(), result); + m_str.c_str(), trans.c_str(), result); if (err < 0) return error{err}; - m_b32 = result; + m_str = result; return error::OK; } void cube::invert() { - char result[size::B32]; - nissy_inverse(m_b32.c_str(), result); - m_b32 = result; + char result[size::CUBE]; + nissy_inverse(m_str.c_str(), result); + m_str = result; } void cube::compose(const cube& other) { - char result[size::B32]; + char result[size::CUBE]; nissy_compose( - m_b32.c_str(), other.to_string().c_str(), result); - m_b32 = result; + m_str.c_str(), other.to_string().c_str(), result); + m_str = result; } - std::string cube::to_string() const { return m_b32; } - - std::variant<std::string, error> - cube::to_string(const std::string& format) const - { - char result[size::CUBE_MAX]; - auto err = nissy_convert("B32", format.c_str(), - m_b32.c_str(), size::CUBE_MAX, result); - if (err < 0) - return error{err}; - else - return result; - } + std::string cube::to_string() const { return m_str; } std::variant<cube, error> cube::from_string(const std::string& str) { - return from_string(str, "B32"); - } - - std::variant<cube, error> - cube::from_string(const std::string& str, const std::string& format) - { - char result[size::B32]; - cube c; - auto err = nissy_convert(format.c_str(), - "B32", c.m_b32.c_str(), size::B32, result); + /* Check that the cube is valid by making a single move */ + char result[size::CUBE]; + auto err = nissy_applymoves(str.c_str(), "U", result); if (err < 0) return error{err}; - c.m_b32 = result; + + cube c; + c.m_str = str; return c; } @@ -143,13 +121,13 @@ namespace nissy { cube::get(long long ep, long long eo, long long cp, long long co, const std::string& options) { - char result[size::B32]; + char result[size::CUBE]; cube c; auto err = nissy_getcube( ep, eo, cp, co, options.c_str(), result); if (err < 0) return error{err}; - c.m_b32 = result; + c.m_str = result; return c; } diff --git a/cpp/nissy.h b/cpp/nissy.h @@ -38,7 +38,6 @@ namespace nissy { static const error UNSOLVABLE_CUBE; static const error INVALID_MOVES; static const error INVALID_TRANS; - static const error INVALID_FORMAT; static const error INVALID_SOLVER; static const error NULL_POINTER; static const error BUFFER_SIZE; @@ -55,13 +54,9 @@ namespace nissy { void invert(); void compose(const cube&); std::string to_string() const; - std::variant<std::string, error> to_string( - const std::string& format) const; static std::variant<cube, error> from_string( const std::string&); - static std::variant<cube, error> from_string( - const std::string& str, const std::string& format); static std::variant<cube, error> get( long long ep, long long eo, long long cp, long long co); static std::variant<cube, error> get( @@ -69,7 +64,7 @@ namespace nissy { const std::string& options); private: - std::string m_b32{"ABCDEFGH=ABCDEFGHIJKL"}; + std::string m_str{"ABCDEFGH=ABCDEFGHIJKL=A"}; }; class solver { diff --git a/python/nissy_module.c b/python/nissy_module.c @@ -4,7 +4,6 @@ #include "../src/nissy.h" -#define MAX_CUBE_STR_LEN 1024 /* Update when adding formats */ #define MAX_SOLUTIONS_SIZE 250000 static bool @@ -24,7 +23,6 @@ check_error(long long err) case NISSY_ERROR_UNSOLVABLE_CUBE: /* Fallthrough */ case NISSY_ERROR_INVALID_MOVES: case NISSY_ERROR_INVALID_TRANS: - case NISSY_ERROR_INVALID_FORMAT: case NISSY_ERROR_INVALID_SOLVER: case NISSY_ERROR_NULL_POINTER: case NISSY_ERROR_BUFFER_SIZE: @@ -70,17 +68,17 @@ PyDoc_STRVAR(compose_doc, "Apply 'permutation' on 'cube'.\n" "\n" "Parameters:\n" -" - cube: a cube in B32 format\n" -" - permutation: another cube in B32 format\n" +" - cube: a cube\n" +" - permutation: another cube\n" "\n" -"Returns: the resulting cube string in B32 format\n" +"Returns: the resulting cube string\n" ); static PyObject * compose(PyObject *self, PyObject *args) { long long err; const char *cube, *permutation; - char result[NISSY_SIZE_B32]; + char result[NISSY_SIZE_CUBE]; if (!PyArg_ParseTuple(args, "ss", &cube, &permutation)) return NULL; @@ -95,16 +93,16 @@ PyDoc_STRVAR(inverse_doc, "Invert 'cube'.\n" "\n" "Parameters:\n" -" - cube: a cube in B32 format\n" +" - cube: a cube in\n" "\n" -"Returns: the inverse cube in B32 format\n" +"Returns: the inverse cube\n" ); static PyObject * inverse(PyObject *self, PyObject *args) { long long err; const char *cube; - char result[NISSY_SIZE_B32]; + char result[NISSY_SIZE_CUBE]; if (!PyArg_ParseTuple(args, "s", &cube)) return NULL; @@ -119,17 +117,17 @@ PyDoc_STRVAR(applymoves_doc, "Apply 'moves' to 'cube'.\n" "\n" "Parameters:\n" -" - cube: a cube in B32 format\n" +" - cube: a cube in\n" " - moves: the moves to apply on the cube\n" "\n" -"Returns: the resulting cube in B32 format\n" +"Returns: the resulting cube\n" ); static PyObject * applymoves(PyObject *self, PyObject *args) { long long err; const char *cube, *moves; - char result[NISSY_SIZE_B32]; + char result[NISSY_SIZE_CUBE]; if (!PyArg_ParseTuple(args, "ss", &cube, &moves)) return NULL; @@ -144,19 +142,19 @@ PyDoc_STRVAR(applytrans_doc, "Apply 'transformation' to 'cube'.\n" "\n" "Parameters:\n" -" - cube: a cube in B32 format\n" +" - cube: a cube\n" " - transformation: the transformation to apply on the cube, formatted as\n" " (rotation|mirrored) (2 letters)\n" " for example 'mirrored ur' or 'rotation lf'\n" "\n" -"Returns: the resulting cube in B32 format\n" +"Returns: the resulting cube\n" ); static PyObject * applytrans(PyObject *self, PyObject *args) { long long err; const char *cube, *trans; - char result[NISSY_SIZE_B32]; + char result[NISSY_SIZE_CUBE]; if (!PyArg_ParseTuple(args, "ss", &cube, &trans)) return NULL; @@ -165,32 +163,6 @@ applytrans(PyObject *self, PyObject *args) return string_result(err, result); } -PyDoc_STRVAR(convert_doc, -"convert(fin, fout, cube)\n" -"--\n\n" -"Convert 'cube' from format 'fin' to format 'fout'.\n" -"\n" -"Parameters:\n" -" - fin: the format in which 'cube' is given\n" -" - fout: the format to which 'cube' has to be converted\n" -" - cube: a cube in B32 format\n" -"\n" -"Returns: 'cube' in 'fout' format\n" -); -static PyObject * -convert(PyObject *self, PyObject *args) -{ - long long err; - const char *fin, *fout, *cube; - char result[MAX_CUBE_STR_LEN]; - - if (!PyArg_ParseTuple(args, "sss", &fin, &fout, &cube)) - return NULL; - - err = nissy_convert(fin, fout, cube, MAX_CUBE_STR_LEN, result); - return string_result(err, result); -} - PyDoc_STRVAR(getcube_doc, "getcube(ep, eo, cp, co, options)\n" "--\n\n" @@ -210,7 +182,7 @@ getcube(PyObject *self, PyObject *args) { long long ep, eo, cp, co, err; const char *options; - char result[NISSY_SIZE_B32]; + char result[NISSY_SIZE_CUBE]; if (!PyArg_ParseTuple(args, "LLLLs", &ep, &eo, &cp, &co, &options)) return NULL; @@ -321,7 +293,7 @@ PyDoc_STRVAR(solve_doc, "See the documentation for libnissy (in nissy.h) for details.\n" "\n" "Parameters:\n" -" - cube: a cube in B32 format\n" +" - cube: a cube\n" " - solver: the solver to use\n" " - minmoves: the minimum number of moves to use\n" " - maxmoves: the maximum number of moves to use\n" @@ -400,7 +372,6 @@ static PyMethodDef nissy_methods[] = { { "inverse", inverse, METH_VARARGS, inverse_doc }, { "applymoves", applymoves, METH_VARARGS, applymoves_doc }, { "applytrans", applytrans, METH_VARARGS, applytrans_doc }, - { "convert", convert, METH_VARARGS, convert_doc }, { "getcube", getcube, METH_VARARGS, getcube_doc }, { "solverinfo", solverinfo, METH_VARARGS, solverinfo_doc }, { "gendata", gendata, METH_VARARGS, gendata_doc }, diff --git a/shell/shell.c b/shell/shell.c @@ -18,9 +18,6 @@ #define FLAG_PERM "-perm" #define FLAG_COMMAND "-command" #define FLAG_STR_CUBE "-cubestr" -#define FLAG_FORMAT "-format" -#define FLAG_FORMAT_IN "-fin" -#define FLAG_FORMAT_OUT "-fout" #define FLAG_MOVES "-moves" #define FLAG_TRANS "-trans" #define FLAG_SOLVER "-solver" @@ -31,23 +28,18 @@ #define FLAG_MAXSOLUTIONS "-n" #define FLAG_THREADS "-t" -#define INFO_CUBEFORMAT(cube) cube " must be given in B32 format." #define INFO_MOVESFORMAT "The accepted moves are U, D, R, L, F and B, " \ "optionally followed by a 2, a ' or a 3." #define INFO_TRANSFORMAT "The transformation must be given in the format " \ "(rotation|mirrored) (2 letters), for exmple " \ "'rotation UF' or 'mirrored BL'." -#define INFO_FORMATS "The available formats are H48, B32 and SRC." typedef struct { int command_index; - char cube[22]; - char cube_perm[22]; + char cube[NISSY_SIZE_CUBE]; + char cube_perm[NISSY_SIZE_CUBE]; char *str_command; char *str_cube; - char *str_format; - char *str_format_in; - char *str_format_out; char *str_moves; char *str_trans; char *str_solver; @@ -64,7 +56,6 @@ static int64_t inverse_exec(args_t *); static int64_t applymoves_exec(args_t *); static int64_t applytrans_exec(args_t *); static int64_t frommoves_exec(args_t *); -static int64_t convert_exec(args_t *); static int64_t randomcube_exec(args_t *); static int64_t solverinfo_exec(args_t *); static int64_t gendata_exec(args_t *); @@ -81,9 +72,6 @@ static bool set_cube(int, char **, args_t *); static bool set_cube_perm(int, char **, args_t *); static bool set_str_command(int, char **, args_t *); static bool set_str_cube(int, char **, args_t *); -static bool set_str_format(int, char **, args_t *); -static bool set_str_format_in(int, char **, args_t *); -static bool set_str_format_out(int, char **, args_t *); static bool set_str_moves(int, char **, args_t *); static bool set_str_trans(int, char **, args_t *); static bool set_str_solver(int, char **, args_t *); @@ -107,9 +95,6 @@ struct { OPTION(FLAG_PERM, 1, set_cube_perm), OPTION(FLAG_COMMAND, 1, set_str_command), OPTION(FLAG_STR_CUBE, 1, set_str_cube), - OPTION(FLAG_FORMAT, 1, set_str_format), - OPTION(FLAG_FORMAT_IN, 1, set_str_format_in), - OPTION(FLAG_FORMAT_OUT, 1, set_str_format_out), OPTION(FLAG_MOVES, 1, set_str_moves), OPTION(FLAG_TRANS, 1, set_str_trans), OPTION(FLAG_SOLVER, 1, set_str_solver), @@ -133,29 +118,27 @@ struct { COMMAND( "compose", "compose " FLAG_CUBE " CUBE " FLAG_PERM " PERM", - "Apply on CUBE the permutation defined by PERM. " - INFO_CUBEFORMAT("CUBE and PERM"), + "Apply on CUBE the permutation defined by PERM.", compose_exec ), COMMAND( "inverse", "inverse " FLAG_CUBE " CUBE ", - "Compute the inverse of the given CUBE. " - INFO_CUBEFORMAT("CUBE"), + "Compute the inverse of the given CUBE.", inverse_exec ), COMMAND( "applymoves", "applymoves " FLAG_CUBE " CUBE " FLAG_MOVES " MOVES", "Apply the given MOVES to the given CUBE. " - INFO_CUBEFORMAT("CUBE") " " INFO_MOVESFORMAT, + INFO_MOVESFORMAT, applymoves_exec ), COMMAND( "applytrans", "applytrans " FLAG_CUBE " CUBE " FLAG_TRANS " TRANS", "Apply the single transformation TRANS to the given CUBE. " - INFO_CUBEFORMAT("CUBE") " " INFO_TRANSFORMAT, + INFO_TRANSFORMAT, applytrans_exec ), COMMAND( @@ -166,19 +149,9 @@ struct { frommoves_exec ), COMMAND( - "convert", - "convert " FLAG_STR_CUBE " CUBESTR " - FLAG_FORMAT_IN " FORMAT_IN " FLAG_FORMAT_OUT " FORMAT_OUT", - "Convert the cube described by CUBESTR from FORMAT_IN to " - "FORMAT_OUT." - INFO_FORMATS " " - "CUBESTR must be a valid cube in the FORMAT_IN format.", - convert_exec - ), - COMMAND( "randomcube", "randomcube", - "Returns a random cube in B32 format.", + "Returns a random.", randomcube_exec ), COMMAND( @@ -202,8 +175,7 @@ struct { FLAG_CUBE " CUBE" FLAG_THREADS " T", "Solve the given CUBE using SOLVER, " - "using at least n and at most N moves, and T threads. " - INFO_CUBEFORMAT("CUBE"), + "using at least n and at most N moves, and T threads.", solve_exec ), COMMAND( @@ -254,7 +226,7 @@ rand64(void) static int64_t compose_exec(args_t *args) { - char result[22]; + char result[NISSY_SIZE_CUBE]; int64_t ret; ret = nissy_compose(args->cube, args->cube_perm, result); @@ -267,7 +239,7 @@ compose_exec(args_t *args) static int64_t inverse_exec(args_t *args) { - char result[22]; + char result[NISSY_SIZE_CUBE]; int64_t ret; ret = nissy_inverse(args->cube, result); @@ -280,7 +252,7 @@ inverse_exec(args_t *args) static int64_t applymoves_exec(args_t *args) { - char result[22]; + char result[NISSY_SIZE_CUBE]; int64_t ret; ret = nissy_applymoves(args->cube, args->str_moves, result); @@ -293,7 +265,7 @@ applymoves_exec(args_t *args) static int64_t applytrans_exec(args_t *args) { - char result[22]; + char result[NISSY_SIZE_CUBE]; int64_t ret; ret = nissy_applytrans(args->cube, args->str_trans, result); @@ -311,20 +283,6 @@ frommoves_exec(args_t *args) } static int64_t -convert_exec(args_t *args) -{ - char result[PRINTCUBE_BUFFER_SIZE]; - int64_t ret; - - ret = nissy_convert(args->str_format_in, args->str_format_out, - args->str_cube, PRINTCUBE_BUFFER_SIZE, result); - if (ret == NISSY_OK || ret == NISSY_WARNING_UNSOLVABLE) - printf("%s\n", result); - - return ret; -} - -static int64_t randomcube_exec(args_t *args) { char result[PRINTCUBE_BUFFER_SIZE]; @@ -575,9 +533,6 @@ parse_args(int argc, char **argv, args_t *args) .cube = "", .cube_perm = "", .str_cube = "", - .str_format = "", - .str_format_in = "", - .str_format_out = "", .str_moves = "", .str_trans = "", .str_solver = "", @@ -668,7 +623,7 @@ parse_nisstype(const char *arg) static bool set_cube(int argc, char **argv, args_t *args) { - memcpy(args->cube, argv[0], 22); + memcpy(args->cube, argv[0], NISSY_SIZE_CUBE); args->cube[21] = 0; return true; @@ -677,7 +632,7 @@ set_cube(int argc, char **argv, args_t *args) static bool set_cube_perm(int argc, char **argv, args_t *args) { - memcpy(args->cube_perm, argv[0], 22); + memcpy(args->cube_perm, argv[0], NISSY_SIZE_CUBE); args->cube_perm[21] = 0; return true; @@ -700,30 +655,6 @@ set_str_cube(int argc, char **argv, args_t *args) } static bool -set_str_format(int argc, char **argv, args_t *args) -{ - args->str_format = argv[0]; - - return true; -} - -static bool -set_str_format_in(int argc, char **argv, args_t *args) -{ - args->str_format_in = argv[0]; - - return true; -} - -static bool -set_str_format_out(int argc, char **argv, args_t *args) -{ - args->str_format_out = argv[0]; - - return true; -} - -static bool set_str_moves(int argc, char **argv, args_t *args) { args->str_moves = argv[0]; diff --git a/src/core/core.h b/src/core/core.h @@ -1,5 +1,4 @@ #include "constant_cubes.h" #include "cube.h" -#include "io_formats.h" #include "moves.h" #include "transform.h" diff --git a/src/core/cube.h b/src/core/cube.h @@ -174,3 +174,193 @@ getcube(int64_t ep, int64_t eo, int64_t cp, int64_t co) return cubefromarray(carr, earr); } + + +/******************************************************************************/ + +STATIC cube_t readcube(const char *, const char *); +STATIC int64_t writecube(const char *, cube_t, size_t n, char [n]); +STATIC uint8_t readco(const char *); +STATIC uint8_t readcp(const char *); +STATIC uint8_t readeo(const char *); +STATIC uint8_t readep(const char *); + +STATIC cube_t readcube_B32(const char *); +STATIC int64_t writecube_B32(cube_t, size_t n, char [n]); + +STATIC uint8_t b32toedge(char); +STATIC uint8_t b32tocorner(char); +STATIC char edgetob32(uint8_t); +STATIC char cornertob32(uint8_t); + +STATIC cube_t +readcube(const char *format, const char *buf) +{ + return readcube_B32(buf); +} + +STATIC int64_t +writecube(const char *format, cube_t cube, size_t buf_size, char buf[buf_size]) +{ + return writecube_B32(cube, buf_size, buf); +} + +STATIC uint8_t +readco(const char *str) +{ + if (*str == '0') + return 0; + if (*str == '1') + return CTWIST_CW; + if (*str == '2') + return CTWIST_CCW; + + LOG("Error reading CO\n"); + return UINT8_ERROR; +} + +STATIC uint8_t +readcp(const char *str) +{ + uint8_t c; + + for (c = 0; c < 8; c++) + if (!strncmp(str, cornerstr[c], 3) || + !strncmp(str, cornerstralt[c], 3)) + return c; + + LOG("Error reading CP\n"); + return UINT8_ERROR; +} + +STATIC uint8_t +readeo(const char *str) +{ + if (*str == '0') + return 0; + if (*str == '1') + return EFLIP; + + LOG("Error reading EO\n"); + return UINT8_ERROR; +} + +STATIC uint8_t +readep(const char *str) +{ + uint8_t e; + + for (e = 0; e < 12; e++) + if (!strncmp(str, edgestr[e], 2)) + return e; + + LOG("Error reading EP\n"); + return UINT8_ERROR; +} + +STATIC cube_t +readcube_B32(const char *buf) +{ + int i; + uint8_t c[8], e[12]; + + for (i = 0; i < 8; i++) { + c[i] = b32tocorner(buf[i]); + if (c[i] == UINT8_ERROR) { + LOG("Error reading B32 corner %d ", i); + if (buf[i] == 0) { + LOG("(string terminated early)\n"); + } else { + LOG("(char '%c')\n", buf[i]); + } + return ZERO_CUBE; + } + } + + if (buf[8] != '=') { + LOG("Error reading B32 separator: a single '=' " + "must be used to separate edges and corners\n"); + return ZERO_CUBE; + } + + for (i = 0; i < 12; i++) { + e[i] = b32toedge(buf[i+9]); + if (e[i] == UINT8_ERROR) { + LOG("Error reading B32 edge %d ", i); + if (buf[i+9] == 0) { + LOG("(string terminated early)\n"); + } else { + LOG("(char '%c')\n", buf[i+9]); + } + return ZERO_CUBE; + } + } + + return cubefromarray(c, e); +} + +STATIC int64_t +writecube_B32(cube_t cube, size_t buf_size, char buf[buf_size]) +{ + int i; + uint8_t corner[8], edge[12]; + + if (buf_size < NISSY_SIZE_CUBE) { + LOG("Cannot write cube: buffer size must be at least %u " + "bytes, but the provided one is %zu bytes.\n", + NISSY_SIZE_CUBE, buf_size); + return NISSY_ERROR_BUFFER_SIZE; + } + + pieces(&cube, corner, edge); + + for (i = 0; i < 8; i++) + buf[i] = cornertob32(corner[i]); + + buf[8] = '='; + + for (i = 0; i < 12; i++) + buf[i+9] = edgetob32(edge[i]); + + buf[21] = '\0'; + + return NISSY_OK; +} + +STATIC uint8_t +b32toedge(char c) +{ + if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f'))) + return UINT8_ERROR; + + return c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26; +} + +STATIC uint8_t +b32tocorner(char c) { + uint8_t val; + + if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f'))) + return UINT8_ERROR; + + val = c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26; + + return (val & 7) | ((val & 24) << 2); +} + +STATIC char +edgetob32(uint8_t edge) +{ + return edge < 26 ? 'A' + (char)edge : 'a' + (char)(edge - 26); +} + +STATIC char +cornertob32(uint8_t corner) +{ + uint8_t val; + + val = (corner & 7) | ((corner & 96) >> 2); + + return val < 26 ? 'A' + (char)val : 'a' + (char)(val - 26); +} +/******************************************************************************/ diff --git a/src/core/io_formats.h b/src/core/io_formats.h @@ -1,403 +0,0 @@ -STATIC cube_t readcube(const char *, const char *); -STATIC int64_t writecube(const char *, cube_t, size_t n, char [n]); -STATIC void log_available_formats(void); -STATIC uint8_t readco(const char *); -STATIC uint8_t readcp(const char *); -STATIC uint8_t readeo(const char *); -STATIC uint8_t readep(const char *); -STATIC cube_t readcube_B32(const char *); -STATIC cube_t readcube_H48(const char *); -STATIC uint8_t readpiece_LST(const char **); -STATIC cube_t readcube_LST(const char *); - -STATIC int64_t writepiece_LST(uint8_t, size_t n, char [n]); -STATIC int64_t writecube_B32(cube_t, size_t n, char [n]); -STATIC int64_t writecube_H48(cube_t, size_t n, char [n]); -STATIC int64_t writecube_LST(cube_t, size_t n, char [n]); - -STATIC uint8_t b32toedge(char); -STATIC uint8_t b32tocorner(char); -STATIC char edgetob32(uint8_t); -STATIC char cornertob32(uint8_t); - -STATIC struct { - const char *name; - cube_t (*read)(const char *); - int64_t (*write)(cube_t, size_t n, char [n]); -} ioformat[] = -{ - { .name = "B32", .read = readcube_B32, .write = writecube_B32 }, - { .name = "LST", .read = readcube_LST, .write = writecube_LST }, - { .name = "H48", .read = readcube_H48, .write = writecube_H48 }, - { .name = "NONE", .read = NULL, .write = NULL }, -}; - -STATIC cube_t -readcube(const char *format, const char *buf) -{ - int i; - - for (i = 0; ioformat[i].read != NULL; i++) - if (!strcmp(format, ioformat[i].name)) - return ioformat[i].read(buf); - - LOG("Cannot read cube: unknown format '%s'\n", format); - log_available_formats(); - return ZERO_CUBE; -} - -STATIC int64_t -writecube(const char *format, cube_t cube, size_t buf_size, char buf[buf_size]) -{ - int i; - - for (i = 0; ioformat[i].write != NULL; i++) - if (!strcmp(format, ioformat[i].name)) - return ioformat[i].write(cube, buf_size, buf); - - LOG("Cannot write cube: unknown format '%s'\n", format); - log_available_formats(); - return NISSY_ERROR_INVALID_FORMAT; -} - -STATIC void -log_available_formats(void) -{ - int i; - - LOG("Available formats: "); - for (i = 0; ioformat[i].read != NULL; i++) - LOG("'%s' ", ioformat[i].name); - LOG("\n"); -} - -STATIC uint8_t -readco(const char *str) -{ - if (*str == '0') - return 0; - if (*str == '1') - return CTWIST_CW; - if (*str == '2') - return CTWIST_CCW; - - LOG("Error reading CO\n"); - return UINT8_ERROR; -} - -STATIC uint8_t -readcp(const char *str) -{ - uint8_t c; - - for (c = 0; c < 8; c++) - if (!strncmp(str, cornerstr[c], 3) || - !strncmp(str, cornerstralt[c], 3)) - return c; - - LOG("Error reading CP\n"); - return UINT8_ERROR; -} - -STATIC uint8_t -readeo(const char *str) -{ - if (*str == '0') - return 0; - if (*str == '1') - return EFLIP; - - LOG("Error reading EO\n"); - return UINT8_ERROR; -} - -STATIC uint8_t -readep(const char *str) -{ - uint8_t e; - - for (e = 0; e < 12; e++) - if (!strncmp(str, edgestr[e], 2)) - return e; - - LOG("Error reading EP\n"); - return UINT8_ERROR; -} - -STATIC cube_t -readcube_B32(const char *buf) -{ - int i; - uint8_t c[8], e[12]; - - for (i = 0; i < 8; i++) { - c[i] = b32tocorner(buf[i]); - if (c[i] == UINT8_ERROR) { - LOG("Error reading B32 corner %d ", i); - if (buf[i] == 0) { - LOG("(string terminated early)\n"); - } else { - LOG("(char '%c')\n", buf[i]); - } - return ZERO_CUBE; - } - } - - if (buf[8] != '=') { - LOG("Error reading B32 separator: a single '=' " - "must be used to separate edges and corners\n"); - return ZERO_CUBE; - } - - for (i = 0; i < 12; i++) { - e[i] = b32toedge(buf[i+9]); - if (e[i] == UINT8_ERROR) { - LOG("Error reading B32 edge %d ", i); - if (buf[i+9] == 0) { - LOG("(string terminated early)\n"); - } else { - LOG("(char '%c')\n", buf[i+9]); - } - return ZERO_CUBE; - } - } - - return cubefromarray(c, e); -} - -STATIC cube_t -readcube_H48(const char *buf) -{ - int i; - uint8_t piece, orient, c[8], e[12]; - const char *b; - - b = buf; - - for (i = 0; i < 12; i++) { - while (*b == ' ' || *b == '\t' || *b == '\n') - b++; - if ((piece = readep(b)) == UINT8_ERROR) - return ZERO_CUBE; - b += 2; - if ((orient = readeo(b)) == UINT8_ERROR) - return ZERO_CUBE; - b++; - e[i] = piece | orient; - } - for (i = 0; i < 8; i++) { - while (*b == ' ' || *b == '\t' || *b == '\n') - b++; - if ((piece = readcp(b)) == UINT8_ERROR) - return ZERO_CUBE; - b += 3; - if ((orient = readco(b)) == UINT8_ERROR) - return ZERO_CUBE; - b++; - c[i] = piece | orient; - } - - return cubefromarray(c, e); -} - -STATIC uint8_t -readpiece_LST(const char **b) -{ - uint8_t ret; - bool read; - - while (**b == ',' || **b == ' ' || **b == '\t' || **b == '\n') - (*b)++; - - for (ret = 0, read = false; **b >= '0' && **b <= '9'; (*b)++) { - read = true; - ret = ret * 10 + (**b) - '0'; - } - - return read ? ret : UINT8_ERROR; -} - -STATIC cube_t -readcube_LST(const char *buf) -{ - int i; - uint8_t c[8], e[12]; - - for (i = 0; i < 8; i++) - c[i] = readpiece_LST(&buf); - - for (i = 0; i < 12; i++) - e[i] = readpiece_LST(&buf); - - return cubefromarray(c, e); -} - -STATIC int64_t -writepiece_LST(uint8_t piece, size_t buf_size, char buf[buf_size]) -{ - char digits[3]; - size_t i, len; - - if (piece > 99 || buf_size < 3) - return 0; - - len = 0; - while (piece != 0) { - digits[len++] = (piece % 10) + '0'; - piece /= 10; - } - - if (buf_size < len+2) - return 0; - - if (len == 0) - digits[len++] = '0'; - - for (i = 0; i < len; i++) - buf[i] = digits[len-i-1]; - - buf[len] = ','; - buf[len+1] = ' '; - - return len+2; -} - -STATIC int64_t -writecube_B32(cube_t cube, size_t buf_size, char buf[buf_size]) -{ - int i; - uint8_t corner[8], edge[12]; - - if (buf_size < NISSY_SIZE_B32) { - LOG("Cannot write cube in B32 format: buffer size must be at " - "least %u bytes, but the provided one is %zu bytes.\n", - NISSY_SIZE_B32, buf_size); - return NISSY_ERROR_BUFFER_SIZE; - } - - pieces(&cube, corner, edge); - - for (i = 0; i < 8; i++) - buf[i] = cornertob32(corner[i]); - - buf[8] = '='; - - for (i = 0; i < 12; i++) - buf[i+9] = edgetob32(edge[i]); - - buf[21] = '\0'; - - return NISSY_OK; -} - -STATIC int64_t -writecube_H48(cube_t cube, size_t buf_size, char buf[buf_size]) -{ - uint8_t piece, perm, orient, corner[8], edge[12]; - int i; - - if (buf_size < NISSY_SIZE_H48) { - LOG("Cannot write cube in H48 format: buffer size must be " - "at least %u bytes, but the provided one is %zu bytes.\n", - NISSY_SIZE_H48, buf_size); - return NISSY_ERROR_BUFFER_SIZE; - } - - pieces(&cube, corner, edge); - - for (i = 0; i < 12; i++) { - piece = edge[i]; - perm = piece & PBITS; - orient = (piece & EOBIT) >> EOSHIFT; - buf[4*i ] = edgestr[perm][0]; - buf[4*i + 1] = edgestr[perm][1]; - buf[4*i + 2] = orient + '0'; - buf[4*i + 3] = ' '; - } - for (i = 0; i < 8; i++) { - piece = corner[i]; - perm = piece & PBITS; - orient = (piece & COBITS) >> COSHIFT; - buf[48 + 5*i ] = cornerstr[perm][0]; - buf[48 + 5*i + 1] = cornerstr[perm][1]; - buf[48 + 5*i + 2] = cornerstr[perm][2]; - buf[48 + 5*i + 3] = orient + '0'; - buf[48 + 5*i + 4] = ' '; - } - - buf[48+39] = '\0'; - - return NISSY_OK; -} - -STATIC int64_t -writecube_LST(cube_t cube, size_t buf_size, char buf[buf_size]) -{ - int i; - uint64_t ptr; - uint8_t piece, corner[8], edge[12]; - - ptr = 0; - pieces(&cube, corner, edge); - - for (i = 0; i < 8; i++) { - piece = corner[i]; - ptr += writepiece_LST(piece, buf_size - ptr, buf + ptr); - if (ptr == 0) - goto writecube_LST_error; - } - - for (i = 0; i < 12; i++) { - piece = edge[i]; - ptr += writepiece_LST(piece, buf_size - ptr, buf + ptr); - if (ptr == 0) - goto writecube_LST_error; - } - - *(buf+ptr-2) = '\0'; - - return NISSY_OK; - -writecube_LST_error: - LOG("Cannot write cube in LST: buffer is too small (%" PRIu64 - " bytes given). The LST format has a variable size, try a " - "larger buffer.\n", buf_size); - return NISSY_ERROR_BUFFER_SIZE; -} - -STATIC uint8_t -b32toedge(char c) -{ - if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f'))) - return UINT8_ERROR; - - return c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26; -} - -STATIC uint8_t -b32tocorner(char c) { - uint8_t val; - - if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f'))) - return UINT8_ERROR; - - val = c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26; - - return (val & 7) | ((val & 24) << 2); -} - -STATIC char -edgetob32(uint8_t edge) -{ - return edge < 26 ? 'A' + (char)edge : 'a' + (char)(edge - 26); -} - -STATIC char -cornertob32(uint8_t corner) -{ - uint8_t val; - - val = (corner & 7) | ((corner & 96) >> 2); - - return val < 26 ? 'A' + (char)val : 'a' + (char)(val - 26); -} diff --git a/src/nissy.c b/src/nissy.c @@ -17,7 +17,7 @@ long long parse_h48_solver( STATIC bool checkdata(const unsigned char *, const tableinfo_t [static 1]); STATIC bool distribution_equal(const uint64_t [static INFO_DISTRIBUTION_LEN], const uint64_t [static INFO_DISTRIBUTION_LEN], uint8_t); -STATIC long long write_result(cube_t, char [static NISSY_SIZE_B32]); +STATIC long long write_result(cube_t, char [static NISSY_SIZE_CUBE]); STATIC size_t my_strnlen(const char *, size_t); STATIC long long nissy_dataid(const char *, char [static NISSY_SIZE_DATAID]); STATIC long long nissy_gendata_unsafe( @@ -117,9 +117,9 @@ distribution_equal( } STATIC long long -write_result(cube_t cube, char result[static NISSY_SIZE_B32]) +write_result(cube_t cube, char result[static NISSY_SIZE_CUBE]) { - writecube("B32", cube, NISSY_SIZE_B32, result); + writecube("B32", cube, NISSY_SIZE_CUBE, result); if (!issolvable(cube)) { LOG("Warning: resulting cube is not solvable\n"); @@ -143,9 +143,9 @@ my_strnlen(const char *str, size_t maxlen) long long nissy_compose( - const char cube[static NISSY_SIZE_B32], - const char permutation[static NISSY_SIZE_B32], - char result[static NISSY_SIZE_B32] + const char cube[static NISSY_SIZE_CUBE], + const char permutation[static NISSY_SIZE_CUBE], + char result[static NISSY_SIZE_CUBE] ) { cube_t c, p, res; @@ -178,14 +178,14 @@ nissy_compose( return write_result(res, result); nissy_compose_error: - writecube("B32", ZERO_CUBE, NISSY_SIZE_B32, result); + writecube("B32", ZERO_CUBE, NISSY_SIZE_CUBE, result); return err; } long long nissy_inverse( - const char cube[static NISSY_SIZE_B32], - char result[static NISSY_SIZE_B32] + const char cube[static NISSY_SIZE_CUBE], + char result[static NISSY_SIZE_CUBE] ) { cube_t c, res; @@ -210,15 +210,15 @@ nissy_inverse( return write_result(res, result); nissy_inverse_error: - writecube("B32", ZERO_CUBE, NISSY_SIZE_B32, result); + writecube("B32", ZERO_CUBE, NISSY_SIZE_CUBE, result); return err; } long long nissy_applymoves( - const char cube[static NISSY_SIZE_B32], + const char cube[static NISSY_SIZE_CUBE], const char *moves, - char result[static NISSY_SIZE_B32] + char result[static NISSY_SIZE_CUBE] ) { cube_t c, res; @@ -249,15 +249,15 @@ nissy_applymoves( return write_result(res, result); nissy_applymoves_error: - writecube("B32", ZERO_CUBE, NISSY_SIZE_B32, result); + writecube("B32", ZERO_CUBE, NISSY_SIZE_CUBE, result); return err; } long long nissy_applytrans( - const char cube[static NISSY_SIZE_B32], + const char cube[static NISSY_SIZE_CUBE], const char transformation[static NISSY_SIZE_TRANSFORMATION], - char result[static NISSY_SIZE_B32] + char result[static NISSY_SIZE_CUBE] ) { cube_t c, res; @@ -282,51 +282,7 @@ nissy_applytrans( return write_result(res, result); nissy_applytrans_error: - writecube("B32", ZERO_CUBE, NISSY_SIZE_B32, result); - return err; -} - -long long -nissy_convert( - const char *format_in, - const char *format_out, - const char *cube_string, - unsigned result_size, - char result[result_size] -) -{ - cube_t c; - long long err; - - if (format_in == NULL) { - LOG("[convert] Error: 'format_in' argument is NULL\n"); - err = NISSY_ERROR_NULL_POINTER; - goto nissy_convert_error; - } - - if (format_out == NULL) { - LOG("[convert] Error: 'format_out' argument is NULL\n"); - err = NISSY_ERROR_NULL_POINTER; - goto nissy_convert_error; - } - - if (cube_string == NULL) { - LOG("[convert] Error: 'cube_string' argument is NULL\n"); - err = NISSY_ERROR_NULL_POINTER; - goto nissy_convert_error; - } - - c = readcube(format_in, cube_string); - - if (!isconsistent(c)) { - err = NISSY_ERROR_INVALID_CUBE; - goto nissy_convert_error; - } - - return writecube(format_out, c, result_size, result); - -nissy_convert_error: - result[0] = '\0'; + writecube("B32", ZERO_CUBE, NISSY_SIZE_CUBE, result); return err; } @@ -337,7 +293,7 @@ nissy_getcube( long long cp, long long co, const char *options, - char result[static NISSY_SIZE_B32] + char result[static NISSY_SIZE_CUBE] ) { int i; @@ -526,7 +482,7 @@ nissy_checkdata( long long nissy_solve( - const char cube[static NISSY_SIZE_B32], + const char cube[static NISSY_SIZE_CUBE], const char *solver, unsigned nissflag, unsigned minmoves, diff --git a/src/nissy.h b/src/nissy.h @@ -5,12 +5,11 @@ All the functions return 0 or a positive integer in case of success and a negative integer in case of error, unless otherwise specified. See at the bottom of this file for the list of error codes and their meaning. -All cube arguments are in B32 formats, unless otherwise specified. -Other available formats are H48 and SRC. See README.md for more info on -these formats. +TODO: explain cube format Accepted moves are U, D, R, L, F and B, optionally followed by a 2, a ' or a 3. +TODO update when we accept also wide moves, slices and rotations A transformation must be given in the format (rotation|mirrored) (2 letters) @@ -21,9 +20,7 @@ for example 'rotation UF' or 'mirrored BL'. /* Constants *****************************************************************/ /* Some constants for size for I/O buffers */ -#define NISSY_SIZE_B32 22U -#define NISSY_SIZE_H48 88U -#define NISSY_SIZE_CUBE_MAX NISSY_SIZE_H48 +#define NISSY_SIZE_CUBE 24U #define NISSY_SIZE_TRANSFORMATION 12U #define NISSY_SIZE_SOLVE_STATS 10U #define NISSY_SIZE_DATAID 255U @@ -37,8 +34,8 @@ for example 'rotation UF' or 'mirrored BL'. #define NISSY_NISSFLAG_ALL \ (NISSY_NISSFLAG_NORMAL | NISSY_NISSFLAG_INVERSE | NISSY_NISSFLAG_MIXED) -/* The solved cube in B32 format */ -#define NISSY_SOLVED_CUBE "ABCDEFGH=ABCDEFGHIJKL" +/* The solved cube */ +#define NISSY_SOLVED_CUBE "ABCDEFGH=ABCDEFGHIJKL=A" /* Error codes ***************************************************************/ @@ -58,8 +55,7 @@ provided an unsolvable cube as input. /* The value NISSY_ERROR_INVALID_CUBE means that the provided cube is -invalid. It could be written in an unknown format, or in a format -different from what specified, or simply ill-formed. +invalid. It could be written in an unknown format, or be ill-formed. */ #define NISSY_ERROR_INVALID_CUBE -10LL @@ -85,12 +81,6 @@ is invalid. #define NISSY_ERROR_INVALID_TRANS -30LL /* -The value NISSY_ERROR_INVALID_FORMAT means that the given format is -not known. -*/ -#define NISSY_ERROR_INVALID_FORMAT -40LL - -/* The value NISSY_ERROR_INVALID_SOLVER means that the given solver is not known. */ @@ -139,10 +129,10 @@ of this kind to sebastiano@tronto.net. Thanks! Apply the secod argument as a permutation on the first argument. Parameters: - cube - The first cube, in B32 format. - permutation - The second cube, in B32 format. This cube is treated as a - permutation and "applied" to the first cube. - result - The return parameter for the resulting cube, in B32 format. + cube - The first cube. + permutation - The second cub. This cube is treated as a permutation and + "applied" to the first cube. + result - The return parameter for the resulting cube. Return values: NISSY_OK - The cubes were composed succesfully. @@ -155,17 +145,17 @@ Return values: */ long long nissy_compose( - const char cube[static NISSY_SIZE_B32], - const char permutation[static NISSY_SIZE_B32], - char result[static NISSY_SIZE_B32] + const char cube[static NISSY_SIZE_CUBE], + const char permutation[static NISSY_SIZE_CUBE], + char result[static NISSY_SIZE_CUBE] ); /* Compute the inverse of the given cube. Parameters: - cube - The cube to be inverted, in B32 format. - result - The return parameter for the resulting cube, in B32 format. + cube - The cube to be inverted. + result - The return parameter for the resulting cube. Return values: NISSY_OK - The cube was inverted succesfully. @@ -177,17 +167,17 @@ Return values: */ long long nissy_inverse( - const char cube[static NISSY_SIZE_B32], - char result[static NISSY_SIZE_B32] + const char cube[static NISSY_SIZE_CUBE], + char result[static NISSY_SIZE_CUBE] ); /* Apply the given sequence of moves on the given cube. Parameters: - cube - The cube to move, in B32 format. + cube - The cube to move. moves - The moves to apply to the cube. Must be a NULL-terminated string. - result - The return parameter for the resulting cube, in B32 format. + result - The return parameter for the resulting cube. Return values: NISSY_OK - The moves were applied succesfully. @@ -200,18 +190,18 @@ Return values: */ long long nissy_applymoves( - const char cube[static NISSY_SIZE_B32], + const char cube[static NISSY_SIZE_CUBE], const char *moves, - char result[static NISSY_SIZE_B32] + char result[static NISSY_SIZE_CUBE] ); /* Apply the single given transformation to the given cube. Parameters: - cube - The cube to be transformed, in B32 format. - transformation - The transformation in (rotation|mirrored) xy format. - result - The return parameter for the resulting cube, in B32 format. + cube - The cube to be transformed. + transformation - The transformation in "(rotation|mirrored) __" format. + result - The return parameter for the resulting cube. Return values: NISSY_OK - The transformation was performed succesfully. @@ -222,37 +212,9 @@ Return values: */ long long nissy_applytrans( - const char cube[static NISSY_SIZE_B32], + const char cube[static NISSY_SIZE_CUBE], const char transformation[static NISSY_SIZE_TRANSFORMATION], - char result[static NISSY_SIZE_B32] -); - -/* -Convert the given cube between the two given formats. - -Parameters: - format_in - The input format. - format_out - The output format. - cube_string - The cube, in format_in format. - result_size - The allocated size of the result array. - result - Return parameter for the cube in format_out format. - -Return values: - NISSY_OK - The conversion was performed succesfully. - NISSY_ERROR_BUFFER_SIZE - The given buffer is too small for the result. - NISSY_ERROR_INVALID_CUBE - The given cube is invalid. - NISSY_ERROR_INVALID_FORMAT - At least one of the given formats is invalid. - NISSY_ERROR_UNKNOWN - An unknown error occurred. - NISSY_ERROR_NULL_POINTER - At least one of 'format_in', 'format_out' or - 'cube_string' arguments is NULL. -*/ -long long -nissy_convert( - const char *format_in, - const char *format_out, - const char *cube_string, - unsigned result_size, - char result[result_size] + char result[static NISSY_SIZE_CUBE] ); /* @@ -267,7 +229,7 @@ Parameters: cp - The corner permutation, 0 <= cp <= 40320 (8!) co - The corner orientation, 0 <= co <= 2187 (3^7) options - Other options. - result - The return parameter for the resulting cube, in B32 format. + result - The return parameter for the resulting cube. Return values: NISSY_OK - The cube was generated succesfully. @@ -281,7 +243,7 @@ nissy_getcube( long long cp, long long co, const char *options, - char result[static NISSY_SIZE_B32] + char result[static NISSY_SIZE_CUBE] ); /* @@ -354,7 +316,7 @@ nissy_checkdata( Solve the given cube using the given solver and options. Parameters: - cube - The cube to solver, in B32 format. + cube - The cube to solver. solver - The name of the solver. nissflag - The flags for NISS (linear, inverse, mixed, or combinations). minmoves - The minimum number of moves for a solution. @@ -386,7 +348,7 @@ Return values: */ long long nissy_solve( - const char cube[static NISSY_SIZE_B32], + const char cube[static NISSY_SIZE_CUBE], const char *solver, unsigned nissflag, unsigned minmoves, diff --git a/tools/300_solve_small/solve_small.c b/tools/300_solve_small/solve_small.c @@ -25,7 +25,7 @@ void run(void) { int i; int64_t n; long long stats[NISSY_SIZE_SOLVE_STATS]; - char sol[SOL_BUFFER_LEN], cube[22]; + char sol[SOL_BUFFER_LEN], cube[NISSY_SIZE_CUBE]; printf("Solved the following scrambles:\n\n"); for (i = 0; scrambles[i] != NULL; i++) { diff --git a/tools/301_solve_file/solve_file.c b/tools/301_solve_file/solve_file.c @@ -12,7 +12,7 @@ char scrambles[MAX_SCR][MAX_SCR_LEN]; void run(void) { int64_t i, nsols; long long stats[NISSY_SIZE_SOLVE_STATS]; - char sol[SOL_BUFFER_LEN], cube[22]; + char sol[SOL_BUFFER_LEN], cube[NISSY_SIZE_CUBE]; printf("Solved the following scrambles:\n\n"); for (i = 0; i < N; i++) { diff --git a/tools/302_solve_multisol/solve_multisol.c b/tools/302_solve_multisol/solve_multisol.c @@ -18,7 +18,7 @@ void run(void) { int i; int64_t n; long long stats[NISSY_SIZE_SOLVE_STATS]; - char sol[SOL_BUFFER_LEN], cube[22]; + char sol[SOL_BUFFER_LEN], cube[NISSY_SIZE_CUBE]; printf("Solved the following scrambles:\n\n"); for (i = 0; scrambles[i] != NULL; i++) { diff --git a/tools/400_solvetest/solve_test.c b/tools/400_solvetest/solve_test.c @@ -45,7 +45,7 @@ void run(void) { int i; int64_t n; long long stats[NISSY_SIZE_SOLVE_STATS]; - char sol[SOL_BUFFER_LEN], cube[22]; + char sol[SOL_BUFFER_LEN], cube[NISSY_SIZE_CUBE]; for (i = 0; s[i].scramble[0]; i++) { printf("\n%d. %s\n", i, s[i].scramble); diff --git a/utils/convert.c b/utils/convert.c @@ -0,0 +1,409 @@ +/* +This file contains code related to cube format conversion that used to +be in src/core. It is to be adapted into a standalone tool for cube +format conversion. +*/ + +STATIC cube_t readcube(const char *, const char *); +STATIC int64_t writecube(const char *, cube_t, size_t n, char [n]); +STATIC void log_available_formats(void); +STATIC uint8_t readco(const char *); +STATIC uint8_t readcp(const char *); +STATIC uint8_t readeo(const char *); +STATIC uint8_t readep(const char *); +STATIC cube_t readcube_B32(const char *); +STATIC cube_t readcube_H48(const char *); +STATIC uint8_t readpiece_LST(const char **); +STATIC cube_t readcube_LST(const char *); + +STATIC int64_t writepiece_LST(uint8_t, size_t n, char [n]); +STATIC int64_t writecube_B32(cube_t, size_t n, char [n]); +STATIC int64_t writecube_H48(cube_t, size_t n, char [n]); +STATIC int64_t writecube_LST(cube_t, size_t n, char [n]); + +STATIC uint8_t b32toedge(char); +STATIC uint8_t b32tocorner(char); +STATIC char edgetob32(uint8_t); +STATIC char cornertob32(uint8_t); + +STATIC struct { + const char *name; + cube_t (*read)(const char *); + int64_t (*write)(cube_t, size_t n, char [n]); +} ioformat[] = +{ + { .name = "B32", .read = readcube_B32, .write = writecube_B32 }, + { .name = "LST", .read = readcube_LST, .write = writecube_LST }, + { .name = "H48", .read = readcube_H48, .write = writecube_H48 }, + { .name = "NONE", .read = NULL, .write = NULL }, +}; + +STATIC cube_t +readcube(const char *format, const char *buf) +{ + int i; + + for (i = 0; ioformat[i].read != NULL; i++) + if (!strcmp(format, ioformat[i].name)) + return ioformat[i].read(buf); + + LOG("Cannot read cube: unknown format '%s'\n", format); + log_available_formats(); + return ZERO_CUBE; +} + +STATIC int64_t +writecube(const char *format, cube_t cube, size_t buf_size, char buf[buf_size]) +{ + int i; + + for (i = 0; ioformat[i].write != NULL; i++) + if (!strcmp(format, ioformat[i].name)) + return ioformat[i].write(cube, buf_size, buf); + + LOG("Cannot write cube: unknown format '%s'\n", format); + log_available_formats(); + return NISSY_ERROR_INVALID_FORMAT; +} + +STATIC void +log_available_formats(void) +{ + int i; + + LOG("Available formats: "); + for (i = 0; ioformat[i].read != NULL; i++) + LOG("'%s' ", ioformat[i].name); + LOG("\n"); +} + +STATIC uint8_t +readco(const char *str) +{ + if (*str == '0') + return 0; + if (*str == '1') + return CTWIST_CW; + if (*str == '2') + return CTWIST_CCW; + + LOG("Error reading CO\n"); + return UINT8_ERROR; +} + +STATIC uint8_t +readcp(const char *str) +{ + uint8_t c; + + for (c = 0; c < 8; c++) + if (!strncmp(str, cornerstr[c], 3) || + !strncmp(str, cornerstralt[c], 3)) + return c; + + LOG("Error reading CP\n"); + return UINT8_ERROR; +} + +STATIC uint8_t +readeo(const char *str) +{ + if (*str == '0') + return 0; + if (*str == '1') + return EFLIP; + + LOG("Error reading EO\n"); + return UINT8_ERROR; +} + +STATIC uint8_t +readep(const char *str) +{ + uint8_t e; + + for (e = 0; e < 12; e++) + if (!strncmp(str, edgestr[e], 2)) + return e; + + LOG("Error reading EP\n"); + return UINT8_ERROR; +} + +STATIC cube_t +readcube_B32(const char *buf) +{ + int i; + uint8_t c[8], e[12]; + + for (i = 0; i < 8; i++) { + c[i] = b32tocorner(buf[i]); + if (c[i] == UINT8_ERROR) { + LOG("Error reading B32 corner %d ", i); + if (buf[i] == 0) { + LOG("(string terminated early)\n"); + } else { + LOG("(char '%c')\n", buf[i]); + } + return ZERO_CUBE; + } + } + + if (buf[8] != '=') { + LOG("Error reading B32 separator: a single '=' " + "must be used to separate edges and corners\n"); + return ZERO_CUBE; + } + + for (i = 0; i < 12; i++) { + e[i] = b32toedge(buf[i+9]); + if (e[i] == UINT8_ERROR) { + LOG("Error reading B32 edge %d ", i); + if (buf[i+9] == 0) { + LOG("(string terminated early)\n"); + } else { + LOG("(char '%c')\n", buf[i+9]); + } + return ZERO_CUBE; + } + } + + return cubefromarray(c, e); +} + +STATIC cube_t +readcube_H48(const char *buf) +{ + int i; + uint8_t piece, orient, c[8], e[12]; + const char *b; + + b = buf; + + for (i = 0; i < 12; i++) { + while (*b == ' ' || *b == '\t' || *b == '\n') + b++; + if ((piece = readep(b)) == UINT8_ERROR) + return ZERO_CUBE; + b += 2; + if ((orient = readeo(b)) == UINT8_ERROR) + return ZERO_CUBE; + b++; + e[i] = piece | orient; + } + for (i = 0; i < 8; i++) { + while (*b == ' ' || *b == '\t' || *b == '\n') + b++; + if ((piece = readcp(b)) == UINT8_ERROR) + return ZERO_CUBE; + b += 3; + if ((orient = readco(b)) == UINT8_ERROR) + return ZERO_CUBE; + b++; + c[i] = piece | orient; + } + + return cubefromarray(c, e); +} + +STATIC uint8_t +readpiece_LST(const char **b) +{ + uint8_t ret; + bool read; + + while (**b == ',' || **b == ' ' || **b == '\t' || **b == '\n') + (*b)++; + + for (ret = 0, read = false; **b >= '0' && **b <= '9'; (*b)++) { + read = true; + ret = ret * 10 + (**b) - '0'; + } + + return read ? ret : UINT8_ERROR; +} + +STATIC cube_t +readcube_LST(const char *buf) +{ + int i; + uint8_t c[8], e[12]; + + for (i = 0; i < 8; i++) + c[i] = readpiece_LST(&buf); + + for (i = 0; i < 12; i++) + e[i] = readpiece_LST(&buf); + + return cubefromarray(c, e); +} + +STATIC int64_t +writepiece_LST(uint8_t piece, size_t buf_size, char buf[buf_size]) +{ + char digits[3]; + size_t i, len; + + if (piece > 99 || buf_size < 3) + return 0; + + len = 0; + while (piece != 0) { + digits[len++] = (piece % 10) + '0'; + piece /= 10; + } + + if (buf_size < len+2) + return 0; + + if (len == 0) + digits[len++] = '0'; + + for (i = 0; i < len; i++) + buf[i] = digits[len-i-1]; + + buf[len] = ','; + buf[len+1] = ' '; + + return len+2; +} + +STATIC int64_t +writecube_B32(cube_t cube, size_t buf_size, char buf[buf_size]) +{ + int i; + uint8_t corner[8], edge[12]; + + if (buf_size < NISSY_SIZE_B32) { + LOG("Cannot write cube in B32 format: buffer size must be at " + "least %u bytes, but the provided one is %zu bytes.\n", + NISSY_SIZE_B32, buf_size); + return NISSY_ERROR_BUFFER_SIZE; + } + + pieces(&cube, corner, edge); + + for (i = 0; i < 8; i++) + buf[i] = cornertob32(corner[i]); + + buf[8] = '='; + + for (i = 0; i < 12; i++) + buf[i+9] = edgetob32(edge[i]); + + buf[21] = '\0'; + + return NISSY_OK; +} + +STATIC int64_t +writecube_H48(cube_t cube, size_t buf_size, char buf[buf_size]) +{ + uint8_t piece, perm, orient, corner[8], edge[12]; + int i; + + if (buf_size < NISSY_SIZE_H48) { + LOG("Cannot write cube in H48 format: buffer size must be " + "at least %u bytes, but the provided one is %zu bytes.\n", + NISSY_SIZE_H48, buf_size); + return NISSY_ERROR_BUFFER_SIZE; + } + + pieces(&cube, corner, edge); + + for (i = 0; i < 12; i++) { + piece = edge[i]; + perm = piece & PBITS; + orient = (piece & EOBIT) >> EOSHIFT; + buf[4*i ] = edgestr[perm][0]; + buf[4*i + 1] = edgestr[perm][1]; + buf[4*i + 2] = orient + '0'; + buf[4*i + 3] = ' '; + } + for (i = 0; i < 8; i++) { + piece = corner[i]; + perm = piece & PBITS; + orient = (piece & COBITS) >> COSHIFT; + buf[48 + 5*i ] = cornerstr[perm][0]; + buf[48 + 5*i + 1] = cornerstr[perm][1]; + buf[48 + 5*i + 2] = cornerstr[perm][2]; + buf[48 + 5*i + 3] = orient + '0'; + buf[48 + 5*i + 4] = ' '; + } + + buf[48+39] = '\0'; + + return NISSY_OK; +} + +STATIC int64_t +writecube_LST(cube_t cube, size_t buf_size, char buf[buf_size]) +{ + int i; + uint64_t ptr; + uint8_t piece, corner[8], edge[12]; + + ptr = 0; + pieces(&cube, corner, edge); + + for (i = 0; i < 8; i++) { + piece = corner[i]; + ptr += writepiece_LST(piece, buf_size - ptr, buf + ptr); + if (ptr == 0) + goto writecube_LST_error; + } + + for (i = 0; i < 12; i++) { + piece = edge[i]; + ptr += writepiece_LST(piece, buf_size - ptr, buf + ptr); + if (ptr == 0) + goto writecube_LST_error; + } + + *(buf+ptr-2) = '\0'; + + return NISSY_OK; + +writecube_LST_error: + LOG("Cannot write cube in LST: buffer is too small (%" PRIu64 + " bytes given). The LST format has a variable size, try a " + "larger buffer.\n", buf_size); + return NISSY_ERROR_BUFFER_SIZE; +} + +STATIC uint8_t +b32toedge(char c) +{ + if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f'))) + return UINT8_ERROR; + + return c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26; +} + +STATIC uint8_t +b32tocorner(char c) { + uint8_t val; + + if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f'))) + return UINT8_ERROR; + + val = c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26; + + return (val & 7) | ((val & 24) << 2); +} + +STATIC char +edgetob32(uint8_t edge) +{ + return edge < 26 ? 'A' + (char)edge : 'a' + (char)(edge - 26); +} + +STATIC char +cornertob32(uint8_t corner) +{ + uint8_t val; + + val = (corner & 7) | ((corner & 96) >> 2); + + return val < 26 ? 'A' + (char)val : 'a' + (char)(val - 26); +} diff --git a/utils/genmovecode.sh b/utils/genmovecode.sh @@ -1,15 +0,0 @@ -#!/bin/sh - -cc -DDEBUG h48_to_lst.c ../src/nissy.c -o h48_to_lst - -gen() { - for f in cubes/move_??_*.txt; do - move="$(echo "$f" | sed 's/.*_// ; s/\.txt//')" - printf '#define _move_cube_%s fastcube( \\\n ' "$move" - ./h48_to_lst <"$f" - printf ')\n' - done -} - -gen -rm -f h48_to_lst invert diff --git a/utils/genmoveswitch.sh b/utils/genmoveswitch.sh @@ -1,8 +0,0 @@ -#!/bin/sh - -printf '\tswitch (m) {\n' -for f in cubes/move_??_*.txt; do - t="$(echo "$f" | sed 's/.*_// ; s/\.txt//')" - printf '\tcase %s:\n\t\treturn _move(%s, c);\n' "$t" "$t" -done -printf '\t}\n' diff --git a/utils/gentranscode.sh b/utils/gentranscode.sh @@ -1,25 +0,0 @@ -#!/bin/sh - -cc -DDEBUG h48_to_lst.c ../src/nissy.c -o h48_to_lst -cc -DDEBUG invert.c ../src/nissy.c -o invert - -lineavx() { printf '#define _trans_cube_%s ' "$1"; } -linesrc() { printf '_static cube_fast_t _trans_cube_%s = ' "$1"; } -sedavx() { sed '1,2s/$/ \\/ ; 3s/$/)/ ; 3q'; } -sedsrc() { sed '3s/$/ };/ ; 3q'; } - -gen() { - for f in cubes/transform_??_???.txt; do - trans="$(echo "$f" | sed 's/.*_// ; s/\.txt//')" - printf '#define _trans_cube_%s fastcube( \\\n ' "$trans" - ./h48_to_lst <"$f" - printf ')\n' - printf '#define _trans_cube_%s_inverse fastcube( \\\n ' \ - "$trans" - ./invert <"$f" | ./h48_to_lst - printf ')\n' - done -} - -gen -rm -f h48_to_lst invert diff --git a/utils/gentransswitch.sh b/utils/gentransswitch.sh @@ -1,14 +0,0 @@ -#!/bin/sh - -printf '\tswitch (t) {\n' -for f in cubes/transform_??_???.txt; do - t="$(echo "$f" | sed 's/.*_// ; s/\.txt//')" - mirror_or_rotation="$(echo "$t" | grep m)" - if [ -z "$mirror_or_rotation" ]; then - m="rotation" - else - m="mirrored" - fi - printf '\tcase %s:\n\t\treturn _trans_%s(%s, c);\n' "$t" "$m" "$t" -done -printf '\t}\n' diff --git a/utils/gentranstests.sh b/utils/gentranstests.sh @@ -1,35 +0,0 @@ -#!/bin/sh - -outdir="./generated_trans_tests" - -mkdir -p "$outdir" -i=100 - -while read -r line; do - [ -z "$line" ] && continue - - trans_piece="$(echo "$line" | awk '{print $1}' | tr -d 'rm')" - move1="$(echo "$line" | awk '{print $2}')" - move2="$(echo "$line" | awk '{print $3}')" - - rotation="rotation $trans_piece" - - file1="$(ls cubes | grep "move_.*_${move1}.txt")" - file2="$(ls cubes | grep "move_.*_${move2}.txt")" - echo "$rotation" >"$outdir/${i}_${trans_piece}r_${move1}.in" - cat "cubes/$file1" >>"$outdir/${i}_${trans_piece}r_${move1}.in" - cp "cubes/$file2" "$outdir/${i}_${trans_piece}r_${move1}.out" - - i=$((i+1)) - - mirrored="mirrored $trans_piece" - move2m="$(echo "${move2}" | tr 'LR' 'RL')3" - - file1="$(ls cubes | grep "move_.*_${move1}.txt")" - file2="$(ls cubes | grep "move_.*_${move2m}.txt")" - echo "$mirrored" >"$outdir/${i}_${trans_piece}m_${move1}.in" - cat "cubes/$file1" >>"$outdir/${i}_${trans_piece}m_${move1}.in" - cp "cubes/$file2" "$outdir/${i}_${trans_piece}m_${move1}.out" - - i=$((i+1)) -done <transform_moves.txt diff --git a/utils/h48_to_lst.c b/utils/h48_to_lst.c @@ -1,22 +0,0 @@ -#include <stdio.h> -#include <inttypes.h> -#include <stdbool.h> - -#include "../src/nissy.h" - -#define STRLENMAX 1000 - -int main(void) { - char strin[STRLENMAX], strout[STRLENMAX]; - int result; - - fgets(strin, STRLENMAX, stdin); - - result = nissy_convertcube("H48", "LST", strin, strout); - if (result) - fprintf(stderr, "Error converting cube: code %d\n", result); - - fputs(strout, stdout); - - return 0; -} diff --git a/utils/invert.c b/utils/invert.c @@ -1,19 +0,0 @@ -#include <stdio.h> -#include <inttypes.h> -#include <stdbool.h> - -#include "../src/nissy.h" - -#define STRLENMAX 1000 - -int main(void) { - char str[STRLENMAX], cube[22], inv[22]; - - fgets(str, STRLENMAX, stdin); - nissy_readcube("H48", str, cube); - nissy_inverse(cube, inv); - nissy_writecube("H48", inv, str); - fputs(str, stdout); - - return 0; -} diff --git a/utils/mirror.sh b/utils/mirror.sh @@ -1,3 +0,0 @@ -#!/bin/sh - -tr 'LR' 'RL'