nissy.c (6637B)
1 #include <inttypes.h> 2 #include <stdarg.h> 3 #include <stdbool.h> 4 #include <string.h> 5 6 #include "utils/utils.h" 7 #include "arch/arch.h" 8 #include "core/core.h" 9 #include "solvers/solvers.h" 10 11 #include "nissy.h" 12 13 STATIC int parse_h48_options(const char *, uint8_t *, uint8_t *, uint8_t *); 14 STATIC int64_t write_result(cube_t, char [static 22]); 15 16 /* TODO: add option to get DR, maybe C-only, E-only, eo... */ 17 #define GETCUBE_OPTIONS(S, F) { .option = S, .fix = F } 18 struct { 19 char *option; 20 void (*fix)(int64_t *, int64_t *, int64_t *, int64_t *); 21 } getcube_options[] = { 22 GETCUBE_OPTIONS("fix", getcube_fix), 23 GETCUBE_OPTIONS(NULL, NULL) 24 }; 25 26 STATIC int 27 parse_h48_options(const char *buf, uint8_t *h, uint8_t *k, uint8_t *maxdepth) 28 { 29 bool h_valid, k_valid, maxdepth_valid; 30 int i; 31 32 /* TODO temporarily, options are in the form "h;k;maxdepth" */ 33 if (h != NULL) 34 *h = atoi(buf); 35 h_valid = h == NULL || *h <= 11; 36 37 for (i = 0; buf[i] != ';'; i++) 38 if (buf[i] == 0) 39 goto parse_h48_options_error; 40 41 if (k != NULL) 42 *k = atoi(&buf[i+1]); 43 k_valid = k == NULL || (*k == 2 || *k == 4); 44 45 for (i = i+1; buf[i] != ';'; i++) 46 if (buf[i] == 0) 47 goto parse_h48_options_error; 48 49 if (maxdepth != NULL) 50 *maxdepth = atoi(&buf[i+1]); 51 maxdepth_valid = maxdepth == NULL || *maxdepth <= 20; 52 53 return h_valid && k_valid && maxdepth_valid ? 0 : 1; 54 55 parse_h48_options_error: 56 *h = 0; 57 *k = 0; 58 *maxdepth = 0; 59 LOG("Error parsing options: must be in \"h;k;maxdepth\" format " 60 " (instead it was \"%s\")\n", buf); 61 return -1; 62 } 63 64 STATIC int64_t 65 write_result(cube_t cube, char result[static 22]) 66 { 67 if (!isconsistent(cube)) { 68 writecube("B32", ZERO_CUBE, result); 69 return 2; 70 } 71 72 writecube("B32", cube, result); 73 74 return issolvable(cube) ? 0 : 1; 75 } 76 77 int64_t 78 nissy_compose( 79 const char cube[static 22], 80 const char permutation[static 22], 81 char result[static 22] 82 ) 83 { 84 cube_t c, p, res; 85 86 c = readcube("B32", cube); 87 p = readcube("B32", permutation); 88 res = compose(c, p); 89 90 return write_result(res, result); 91 } 92 93 int64_t 94 nissy_inverse( 95 const char cube[static 22], 96 char result[static 22] 97 ) 98 { 99 cube_t c, res; 100 101 c = readcube("B32", cube); 102 res = inverse(c); 103 104 return write_result(res, result); 105 } 106 107 int64_t 108 nissy_applymoves( 109 const char cube[static 22], 110 const char *moves, 111 char result[static 22] 112 ) 113 { 114 cube_t c, res; 115 116 c = readcube("B32", cube); 117 res = applymoves(c, moves); 118 119 return write_result(res, result); 120 } 121 122 int64_t 123 nissy_applytrans( 124 const char cube[static 22], 125 const char *transformation, 126 char result[static 22] 127 ) 128 { 129 cube_t c, res; 130 131 c = readcube("B32", cube); 132 res = applytrans(c, transformation); 133 134 return write_result(res, result); 135 } 136 137 int64_t 138 nissy_frommoves( 139 const char *moves, 140 char result[static 22] 141 ) 142 { 143 cube_t res; 144 145 res = applymoves(SOLVED_CUBE, moves); 146 147 return write_result(res, result); 148 } 149 150 int64_t 151 nissy_convert( 152 const char *format_in, 153 const char *format_out, 154 const char *cube_string, 155 char *result 156 ) 157 { 158 cube_t c; 159 160 c = readcube(format_in, cube_string); 161 writecube(format_out, c, result); 162 163 return isconsistent(c) ? 0 : 2; 164 } 165 166 int64_t 167 nissy_getcube( 168 int64_t ep, 169 int64_t eo, 170 int64_t cp, 171 int64_t co, 172 const char *options, 173 char result[static 22] 174 ) 175 { 176 int i; 177 cube_t c; 178 179 for (i = 0; getcube_options[i].option != NULL; i++) 180 if (!strcmp(options, getcube_options[i].option)) 181 getcube_options[i].fix(&ep, &eo, &cp, &co); 182 183 c = getcube(ep, eo, cp, co); 184 185 return write_result(c, result); 186 } 187 188 int64_t 189 nissy_datasize( 190 const char *solver, 191 const char *options 192 ) 193 { 194 /* gendata() handles a NULL *data as a "dryrun" request */ 195 return nissy_gendata(solver, options, NULL); 196 } 197 198 int64_t 199 nissy_datainfo( 200 const void *table, 201 void (*write)(const char *, ...) 202 ) 203 { 204 uint8_t i; 205 tableinfo_t info; 206 207 readtableinfo(table, &info); 208 209 write("\n---------\n\n"); 210 write("Table information for '%s'\n", info.solver); 211 write("\n"); 212 write("Size: %" PRIu64 " bytes\n", info.fullsize); 213 write("Entries: %" PRIu64 " (%" PRIu8 " bits per entry)", 214 info.entries, info.bits); 215 write("\n"); 216 217 switch (info.type) { 218 case TABLETYPE_PRUNING: 219 write("\n"); 220 write("Table distribution:\nValue\tPositions\n"); 221 for (i = 0; i <= info.maxvalue; i++) { 222 write("%" PRIu8 "\t%" PRIu64 "\n", 223 i + info.base, info.distribution[i]); 224 } 225 break; 226 case TABLETYPE_SPECIAL: 227 write("This is an ad-hoc table\n"); 228 break; 229 default: 230 LOG("datainfo: unknown table type\n"); 231 return 1; 232 } 233 234 if (info.next != 0) { 235 return nissy_datainfo((char *)table + info.next, write); 236 } 237 238 write("\n---------\n"); 239 240 return 0; 241 } 242 243 int64_t 244 nissy_gendata( 245 const char *solver, 246 const char *options, 247 void *data 248 ) 249 { 250 int p; 251 int64_t ret; 252 gendata_h48_arg_t arg; 253 254 arg.buf = data; 255 if (!strcmp(solver, "h48")) { 256 p = parse_h48_options(options, &arg.h, &arg.k, &arg.maxdepth); 257 if (p != 0) { 258 LOG("gendata: could not parse options\n"); 259 ret = -1; 260 } else { 261 ret = gendata_h48(&arg); 262 } 263 } else if (!strcmp(solver, "h48stats")) { 264 arg.h = 0; 265 arg.k = 4; 266 arg.maxdepth = 20; 267 ret = gendata_h48(&arg); 268 } else { 269 LOG("gendata: implemented only for h48 solver\n"); 270 ret = -1; 271 } 272 273 return ret; 274 } 275 276 int64_t 277 nissy_solve( 278 const char cube[static 22], 279 const char *solver, 280 const char *options, 281 const char *nisstype, 282 int8_t minmoves, 283 int8_t maxmoves, 284 int64_t maxsolutions, 285 int8_t optimal, 286 const void *data, 287 char *solutions 288 ) 289 { 290 cube_t c; 291 int p; 292 int64_t ret; 293 uint8_t h, k; 294 295 c = readcube_B32(cube); 296 297 if (!issolvable(c)) { 298 LOG("solve: cube is not solvable\n"); 299 return -1; 300 } 301 302 if (minmoves < 0) { 303 LOG("solve: 'minmoves' is negative, setting it to 0\n"); 304 minmoves = 0; 305 } 306 307 if (maxmoves < 0) { 308 LOG("solve: 'maxmoves' is negative, setting it to 20\n"); 309 maxmoves = 20; 310 } 311 312 if (maxsolutions < 0) { 313 LOG("solve: 'maxsols' is negative, stopping\n"); 314 return -1; 315 } 316 317 if (maxsolutions == 0) { 318 LOG("solve: 'maxsols' is 0, returning no solution\n"); 319 return 0; 320 } 321 322 if (solutions == NULL) { 323 LOG("solve: return parameter 'solutions' is NULL, stopping\n"); 324 return -1; 325 } 326 327 /* TODO define and use solve_options_t */ 328 if (!strcmp(solver, "h48")) { 329 p = parse_h48_options(options, &h, &k, NULL); 330 if (p != 0) { 331 LOG("gendata: could not parse options\n"); 332 ret = -1; 333 } else { 334 ret = solve_h48(c, minmoves, maxmoves, maxsolutions, 335 data, solutions); 336 } 337 } else if (!strcmp(solver, "h48stats")) { 338 ret = solve_h48stats(c, maxmoves, data, solutions); 339 } else if (!strcmp(solver, "simple")) { 340 ret = solve_simple( 341 c, minmoves, maxmoves, maxsolutions, optimal, solutions); 342 } else { 343 LOG("solve: unknown solver '%s'\n", solver); 344 ret = -1; 345 } 346 347 return ret; 348 } 349 350 void 351 nissy_setlogger(void (*log)(const char *, ...)) 352 { 353 nissy_log = log; 354 }