aboutsummaryrefslogtreecommitdiff
path: root/src/nissy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nissy.c')
-rw-r--r--src/nissy.c300
1 files changed, 257 insertions, 43 deletions
diff --git a/src/nissy.c b/src/nissy.c
index 1829d5c..d37256a 100644
--- a/src/nissy.c
+++ b/src/nissy.c
@@ -109,20 +109,14 @@ distribution_equal(
109STATIC int64_t 109STATIC int64_t
110write_result(cube_t cube, char result[static 22]) 110write_result(cube_t cube, char result[static 22])
111{ 111{
112 if (!isconsistent(cube)) {
113 LOG("Error: resulting cube is invalid\n");
114 writecube("B32", ZERO_CUBE, result);
115 return 8;
116 }
117
118 writecube("B32", cube, result); 112 writecube("B32", cube, result);
119 113
120 if (!issolvable(cube)) { 114 if (!issolvable(cube)) {
121 LOG("Warning: resulting cube is not solvable\n"); 115 LOG("Warning: resulting cube is not solvable\n");
122 return 9; 116 return NISSY_WARNING_UNSOLVABLE;
123 } 117 }
124 118
125 return 0; 119 return NISSY_OK;
126} 120}
127 121
128int64_t 122int64_t
@@ -133,24 +127,37 @@ nissy_compose(
133) 127)
134{ 128{
135 cube_t c, p, res; 129 cube_t c, p, res;
130 int64_t err;
136 131
137 c = readcube("B32", cube); 132 c = readcube("B32", cube);
138 133
139 if (!isconsistent(c)) { 134 if (!isconsistent(c)) {
140 LOG("Error in nissy_compose: given cube is invalid\n"); 135 LOG("Error in nissy_compose: given cube is invalid\n");
141 return 1; 136 err = NISSY_ERROR_INVALID_CUBE;
137 goto nissy_compose_error;
142 } 138 }
143 139
144 p = readcube("B32", permutation); 140 p = readcube("B32", permutation);
145 141
146 if (!isconsistent(p)) { 142 if (!isconsistent(p)) {
147 LOG("Error in nissy_compose: given permutation is invalid\n"); 143 LOG("Error in nissy_compose: given permutation is invalid\n");
148 return 2; 144 err = NISSY_ERROR_INVALID_CUBE;
145 goto nissy_compose_error;
149 } 146 }
150 147
151 res = compose(c, p); 148 res = compose(c, p);
152 149
150 if (!isconsistent(res)) {
151 LOG("Unknown error: resulting cube is invalid\n");
152 err = NISSY_ERROR_UNKNOWN;
153 goto nissy_compose_error;
154 }
155
153 return write_result(res, result); 156 return write_result(res, result);
157
158nissy_compose_error:
159 writecube("B32", ZERO_CUBE, result);
160 return err;
154} 161}
155 162
156int64_t 163int64_t
@@ -160,17 +167,29 @@ nissy_inverse(
160) 167)
161{ 168{
162 cube_t c, res; 169 cube_t c, res;
170 int64_t err;
163 171
164 c = readcube("B32", cube); 172 c = readcube("B32", cube);
165 173
166 if (iserror(c)) { 174 if (iserror(c)) {
167 LOG("Error in nissy_inverse: given cube is invalid\n"); 175 LOG("Error in nissy_inverse: given cube is invalid\n");
168 return 1; 176 err = NISSY_ERROR_INVALID_CUBE;
177 goto nissy_inverse_error;
169 } 178 }
170 179
171 res = inverse(c); 180 res = inverse(c);
172 181
182 if (!isconsistent(res)) {
183 LOG("Unknown error: inverted cube is invalid\n");
184 err = NISSY_ERROR_UNKNOWN;
185 goto nissy_inverse_error;
186 }
187
173 return write_result(res, result); 188 return write_result(res, result);
189
190nissy_inverse_error:
191 writecube("B32", ZERO_CUBE, result);
192 return err;
174} 193}
175 194
176int64_t 195int64_t
@@ -181,17 +200,29 @@ nissy_applymoves(
181) 200)
182{ 201{
183 cube_t c, res; 202 cube_t c, res;
203 int64_t err;
184 204
185 c = readcube("B32", cube); 205 c = readcube("B32", cube);
186 206
187 if (!isconsistent(c)) { 207 if (!isconsistent(c)) {
188 LOG("Error in nissy_applymoves: given cube is invalid\n"); 208 LOG("Error in nissy_applymoves: given cube is invalid\n");
189 return 1; 209 err = NISSY_ERROR_INVALID_CUBE;
210 goto nissy_applymoves_error;
190 } 211 }
191 212
192 res = applymoves(c, moves); 213 res = applymoves(c, moves);
193 214
215 if (!isconsistent(res)) {
216 /* Assume we got a reasonable error message from applymoves */
217 err = NISSY_ERROR_INVALID_MOVES;
218 goto nissy_applymoves_error;
219 }
220
194 return write_result(res, result); 221 return write_result(res, result);
222
223nissy_applymoves_error:
224 writecube("B32", ZERO_CUBE, result);
225 return err;
195} 226}
196 227
197int64_t 228int64_t
@@ -202,17 +233,29 @@ nissy_applytrans(
202) 233)
203{ 234{
204 cube_t c, res; 235 cube_t c, res;
236 int64_t err;
205 237
206 c = readcube("B32", cube); 238 c = readcube("B32", cube);
207 239
208 if (!isconsistent(c)) { 240 if (!isconsistent(c)) {
209 LOG("Error in nissy_applytrans: given cube is invalid\n"); 241 LOG("Error in nissy_applytrans: given cube is invalid\n");
210 return 1; 242 err = NISSY_ERROR_INVALID_CUBE;
243 goto nissy_applytrans_error;
211 } 244 }
212 245
213 res = applytrans(c, transformation); 246 res = applytrans(c, transformation);
214 247
248 if (!isconsistent(res)) {
249 /* Assume we got a reasonable error message from applytrans */
250 err = NISSY_ERROR_INVALID_TRANS;
251 goto nissy_applytrans_error;
252 }
253
215 return write_result(res, result); 254 return write_result(res, result);
255
256nissy_applytrans_error:
257 writecube("B32", ZERO_CUBE, result);
258 return err;
216} 259}
217 260
218int64_t 261int64_t
@@ -222,15 +265,21 @@ nissy_frommoves(
222) 265)
223{ 266{
224 cube_t res; 267 cube_t res;
268 int64_t err;
225 269
226 res = applymoves(SOLVED_CUBE, moves); 270 res = applymoves(SOLVED_CUBE, moves);
227 271
228 if (!isconsistent(res)) { 272 if (!isconsistent(res)) {
229 /* Moves must be invalid */ 273 /* Assume we got a reasonable error message from applymoves */
230 return 1; 274 err = NISSY_ERROR_INVALID_MOVES;
275 goto nissy_frommoves_error;
231 } 276 }
232 277
233 return write_result(res, result); 278 return write_result(res, result);
279
280nissy_frommoves_error:
281 writecube("B32", ZERO_CUBE, result);
282 return err;
234} 283}
235 284
236int64_t 285int64_t
@@ -241,20 +290,35 @@ nissy_convert(
241 char *result 290 char *result
242) 291)
243{ 292{
244 int ret;
245 cube_t c; 293 cube_t c;
294 int ret;
295 int64_t err;
246 296
247 c = readcube(format_in, cube_string); 297 c = readcube(format_in, cube_string);
248 298
249 if (iserror(c)) 299 if (iserror(c)) {
250 return 1; 300 err = NISSY_ERROR_INVALID_CUBE;
301 goto nissy_convert_error;
302 }
251 303
252 ret = writecube(format_out, c, result); 304 ret = writecube(format_out, c, result);
253 305
254 if (ret != 0) 306 if (ret != 0) {
255 return 2; 307 /* Assume the format was invalid */
308 err = NISSY_ERROR_INVALID_FORMAT;
309 goto nissy_convert_error;
310 }
311
312 if (!isconsistent(c)) {
313 err = NISSY_ERROR_UNKNOWN;
314 goto nissy_convert_error;
315 }
316
317 return NISSY_OK;
256 318
257 return isconsistent(c) ? 0 : 3; 319nissy_convert_error:
320 /* We don't write anything to result, we don't know the format */
321 return err;
258} 322}
259 323
260int64_t 324int64_t
@@ -276,6 +340,13 @@ nissy_getcube(
276 340
277 c = getcube(ep, eo, cp, co); 341 c = getcube(ep, eo, cp, co);
278 342
343 if (!isconsistent(c)) {
344 LOG("Error: could not get cube with ep=%" PRId64 ", eo=%"
345 PRId64 ", cp=%" PRId64 ", co=%" PRId64 ".\n",
346 ep, eo, cp, co);
347 return NISSY_ERROR_OPTIONS;
348 }
349
279 return write_result(c, result); 350 return write_result(c, result);
280} 351}
281 352
@@ -290,14 +361,14 @@ nissy_datasize(
290 361
291int64_t 362int64_t
292nissy_datainfo( 363nissy_datainfo(
293 const void *table, 364 const void *data,
294 void (*write)(const char *, ...) 365 void (*write)(const char *, ...)
295) 366)
296{ 367{
297 uint8_t i; 368 uint8_t i;
298 tableinfo_t info; 369 tableinfo_t info;
299 370
300 readtableinfo(table, &info); 371 readtableinfo(data, &info);
301 372
302 write("\n---------\n\n"); 373 write("\n---------\n\n");
303 write("Table information for '%s'\n", info.solver); 374 write("Table information for '%s'\n", info.solver);
@@ -321,16 +392,15 @@ nissy_datainfo(
321 break; 392 break;
322 default: 393 default:
323 LOG("datainfo: unknown table type\n"); 394 LOG("datainfo: unknown table type\n");
324 return 1; 395 return NISSY_ERROR_DATA;
325 } 396 }
326 397
327 if (info.next != 0) { 398 if (info.next != 0)
328 return nissy_datainfo((char *)table + info.next, write); 399 return nissy_datainfo((char *)data + info.next, write);
329 }
330 400
331 write("\n---------\n"); 401 write("\n---------\n");
332 402
333 return 0; 403 return NISSY_OK;
334} 404}
335 405
336int64_t 406int64_t
@@ -340,20 +410,19 @@ nissy_gendata(
340) 410)
341{ 411{
342 int p; 412 int p;
343 int64_t ret;
344 gendata_h48_arg_t arg; 413 gendata_h48_arg_t arg;
345 414
346 arg.buf = data; 415 arg.buf = data;
347 if (!strncmp(solver, "h48", 3)) { 416 if (!strncmp(solver, "h48", 3)) {
348 p = parse_h48_solver(solver, &arg.h, &arg.k); 417 p = parse_h48_solver(solver, &arg.h, &arg.k);
349 arg.maxdepth = 20; 418 arg.maxdepth = 20;
350 ret = p == 0 ? (int64_t)gendata_h48(&arg) : -1; 419 if (p != 0)
420 return NISSY_ERROR_UNKNOWN;
421 return (int64_t)gendata_h48(&arg);
351 } else { 422 } else {
352 LOG("gendata: unknown solver %s\n", solver); 423 LOG("gendata: unknown solver %s\n", solver);
353 ret = -1; 424 return NISSY_ERROR_INVALID_SOLVER;
354 } 425 }
355
356 return ret;
357} 426}
358 427
359int64_t 428int64_t
@@ -369,20 +438,20 @@ nissy_checkdata(
369 if (!checkdata(buf, &info)) { 438 if (!checkdata(buf, &info)) {
370 LOG("Error: data for %s is inconsistent with info!\n", 439 LOG("Error: data for %s is inconsistent with info!\n",
371 info.solver); 440 info.solver);
372 return 1; 441 return NISSY_ERROR_DATA;
373 } 442 }
374 if (info.next == 0) 443 if (info.next == 0)
375 break; 444 break;
376 } 445 }
377 446
378 return 0; 447 return NISSY_OK;
379} 448}
380 449
381int64_t 450int64_t
382nissy_solve( 451nissy_solve(
383 const char cube[static 22], 452 const char cube[static 22],
384 const char *solver, 453 const char *solver,
385 const char *nisstype, 454 uint8_t nissflag,
386 int8_t minmoves, 455 int8_t minmoves,
387 int8_t maxmoves, 456 int8_t maxmoves,
388 int64_t maxsolutions, 457 int64_t maxsolutions,
@@ -397,9 +466,14 @@ nissy_solve(
397 466
398 c = readcube_B32(cube); 467 c = readcube_B32(cube);
399 468
469 if (!isconsistent(c)) {
470 LOG("solve: cube is invalid\n");
471 return NISSY_ERROR_INVALID_CUBE;
472 }
473
400 if (!issolvable(c)) { 474 if (!issolvable(c)) {
401 LOG("solve: cube is not solvable\n"); 475 LOG("solve: cube is not solvable\n");
402 return -1; 476 return NISSY_ERROR_UNSOLVABLE_CUBE;
403 } 477 }
404 478
405 if (minmoves < 0) { 479 if (minmoves < 0) {
@@ -414,7 +488,7 @@ nissy_solve(
414 488
415 if (maxsolutions < 0) { 489 if (maxsolutions < 0) {
416 LOG("solve: 'maxsols' is negative, stopping\n"); 490 LOG("solve: 'maxsols' is negative, stopping\n");
417 return -1; 491 return NISSY_ERROR_OPTIONS;
418 } 492 }
419 493
420 if (maxsolutions == 0) { 494 if (maxsolutions == 0) {
@@ -424,7 +498,7 @@ nissy_solve(
424 498
425 if (solutions == NULL) { 499 if (solutions == NULL) {
426 LOG("solve: return parameter 'solutions' is NULL, stopping\n"); 500 LOG("solve: return parameter 'solutions' is NULL, stopping\n");
427 return -1; 501 return NISSY_ERROR_NULL_POINTER;
428 } 502 }
429 503
430 if (!strncmp(solver, "h48", 3)) { 504 if (!strncmp(solver, "h48", 3)) {
@@ -433,7 +507,8 @@ nissy_solve(
433 507
434 p = parse_h48_solver(solver, &h, &k); 508 p = parse_h48_solver(solver, &h, &k);
435 if (p != 0) { 509 if (p != 0) {
436 return -1; 510 LOG("solve: unknown solver %s\n", solver);
511 return NISSY_ERROR_INVALID_SOLVER;
437 } else { 512 } else {
438 return THREADS > 1 ? 513 return THREADS > 1 ?
439 solve_h48_multithread(c, minmoves, 514 solve_h48_multithread(c, minmoves,
@@ -446,12 +521,151 @@ nissy_solve(
446 c, minmoves, maxmoves, maxsolutions, optimal, solutions); 521 c, minmoves, maxmoves, maxsolutions, optimal, solutions);
447 } else { 522 } else {
448 LOG("solve: unknown solver '%s'\n", solver); 523 LOG("solve: unknown solver '%s'\n", solver);
449 return -1; 524 return NISSY_ERROR_INVALID_SOLVER;
450 } 525 }
451} 526}
452 527
453void 528int64_t
454nissy_setlogger(void (*log)(const char *, ...)) 529nissy_setlogger(
530 void (*log)(const char *, ...)
531)
455{ 532{
456 nissy_log = log; 533 nissy_log = log;
534
535 if (log == NULL)
536 return NISSY_WARNING_NULL_CALLBACK;
537
538 return NISSY_OK;
539}
540
541int64_t
542nissy_explainerror(
543 int64_t error_code,
544 void (*write)(const char *, ...)
545)
546{
547 if (write == NULL)
548 return NISSY_WARNING_NULL_CALLBACK;
549
550 switch (error_code) {
551 case NISSY_OK:
552 write(
553 "The value %" PRId64 " denotes a success.\n"
554 "If returned by solve, it means that no solutions has "
555 "been found.\n", NISSY_OK
556 );
557 return NISSY_OK;
558 case NISSY_WARNING_UNSOLVABLE:
559 write(
560 "The value %" PRId64 " is a warning. It means that the "
561 "operation was completed succesfully, but the resulting "
562 "cube is in an unsolvable state. This could be intended, "
563 "for example if the user has provided an unsolvable cube "
564 "as input.\n", NISSY_WARNING_UNSOLVABLE
565 );
566 return NISSY_OK;
567 case NISSY_WARNING_NULL_CALLBACK:
568 write(
569 "The value %" PRId64 " is a warning. It means that the "
570 "provided pointer to a writer function is NULL.\n"
571 "If returned by nissy_setlogger, it means that any future "
572 "log messages will not be printed.\n",
573 NISSY_WARNING_NULL_CALLBACK
574 );
575 return NISSY_OK;
576 case NISSY_ERROR_INVALID_CUBE:
577 write(
578 "The value %" PRId64 " means that the provided cube is "
579 "invalid. It could be written in an unknown format, or "
580 "in a format different from what specified, or simply "
581 "ill-formed.\n", NISSY_ERROR_INVALID_CUBE
582 );
583 return NISSY_OK;
584 case NISSY_ERROR_UNSOLVABLE_CUBE:
585 write(
586 "The value %" PRId64 " means that the provided cube is "
587 "in an unsolvable state.\n", NISSY_ERROR_INVALID_CUBE
588 );
589 return NISSY_OK;
590 case NISSY_ERROR_INVALID_MOVES:
591 write(
592 "The value %" PRId64 " means that the given moves are "
593 "invalid.\n", NISSY_ERROR_INVALID_MOVES
594 );
595 return NISSY_OK;
596 case NISSY_ERROR_INVALID_TRANS:
597 write(
598 "The value %" PRId64 " means that the given transformation "
599 "is invalid.\n", NISSY_ERROR_INVALID_TRANS
600 );
601 return NISSY_OK;
602 case NISSY_ERROR_INVALID_FORMAT:
603 write(
604 "The value %" PRId64 " means that the given format is not "
605 "known.\n", NISSY_ERROR_INVALID_FORMAT
606 );
607 return NISSY_OK;
608 case NISSY_ERROR_INVALID_SOLVER:
609 write(
610 "The value %" PRId64 " means that the given solver is not "
611 "known.\n", NISSY_ERROR_INVALID_SOLVER
612 );
613 return NISSY_OK;
614 case NISSY_ERROR_NULL_POINTER:
615 write(
616 "The value %" PRId64 " means that one of the provided "
617 "pointer arguments is NULL. For example, it may be "
618 "returned by solve when called with a solver that "
619 "requires some pre-computed data, but the provided data "
620 "is NULL.\n", NISSY_ERROR_NULL_POINTER
621 );
622 return NISSY_OK;
623 case NISSY_ERROR_DATA:
624 write(
625 "The value %" PRId64 " means that the provided data is "
626 "invalid. For example, it may be returned by solve when "
627 "called with incompatible solver and data arguments.\n",
628 NISSY_ERROR_DATA
629 );
630 return NISSY_OK;
631 case NISSY_ERROR_OPTIONS:
632 write(
633 "The value %" PRId64 " means that one or more of the "
634 "given options are invalid. For example, it may be "
635 "returned by solve when called with a negative maximum "
636 "number of solutions.\n", NISSY_ERROR_OPTIONS
637 );
638 return NISSY_OK;
639 case NISSY_ERROR_INVALID_CODE:
640 write(
641 "The value %" PRId64 " means that the given error code "
642 "is not known. It may be returned by explainerror.\n",
643 NISSY_ERROR_INVALID_CODE
644 );
645 return NISSY_OK;
646 case NISSY_ERROR_UNKNOWN:
647 write(
648 "The value %" PRId64 " denotes an unexpected error. It "
649 "probably means that there some bug in this library.\n"
650 "If you can, report any error of this kind to "
651 "sebastiano@tronto.net. Thanks!\n", NISSY_ERROR_UNKNOWN
652 );
653 return NISSY_OK;
654 default:
655 break;
656 }
657
658 if (error_code > 0) {
659 write(
660 "A positive return values does not denote an error\n"
661 "If returned by gendata or datasize, it denotes the size "
662 "of the data, in bytes\n"
663 "If returned by solve, it denotes the number of solutions "
664 "found.\n"
665 );
666 return NISSY_OK;
667 } else {
668 write("Unknown error code %" PRId64 "\n", error_code);
669 return NISSY_ERROR_INVALID_CODE;
670 }
457} 671}

Generated with cgit - Back to sebastiano.tronto.net