nissy-classic

Stable branch of nissy
git clone https://git.tronto.net/nissy-classic
Download | Log | Files | Refs | README | LICENSE

steps.c (36298B)


      1 #include "steps.h"
      2 
      3 #define UPDATECHECKSTOP(a, b, c)     if ((a=(MAX((a),(b))))>(c)) return (a);
      4 
      5 /* Checkers, estimators and validators ***************************************/
      6 
      7 static bool             check_centers(Cube cube);
      8 static bool             check_coud_HTM(Cube cube);
      9 static bool             check_coud_URF(Cube cube);
     10 static bool             check_corners_HTM(Cube cube);
     11 static bool             check_corners_URF(Cube cube);
     12 static bool             check_cornershtr(Cube cube);
     13 static bool             check_eofb(Cube cube);
     14 static bool             check_drud(Cube cube);
     15 static bool             check_drud_or_drrl(Cube cube);
     16 static bool             check_htr(Cube cube);
     17 static bool             check_drudslice(Cube cube);
     18 
     19 static int              estimate_eofb_HTM(DfsArg *arg);
     20 static int              estimate_coud_HTM(DfsArg *arg);
     21 static int              estimate_coud_URF(DfsArg *arg);
     22 static int              estimate_corners_HTM(DfsArg *arg);
     23 static int              estimate_cornershtr_HTM(DfsArg *arg);
     24 static int              estimate_corners_URF(DfsArg *arg);
     25 static int              estimate_cornershtr_URF(DfsArg *arg);
     26 static int              estimate_drud_HTM(DfsArg *arg);
     27 static int              estimate_drud_eofb(DfsArg *arg);
     28 static int              estimate_dr_eofb(DfsArg *arg);
     29 static int              estimate_drudfin_drud(DfsArg *arg);
     30 static int              estimate_drudslice_drud(DfsArg *arg);
     31 static int              estimate_htr_drud(DfsArg *arg);
     32 static int              estimate_cp_drud(DfsArg *arg);
     33 static int              estimate_htrfin_htr(DfsArg *arg);
     34 static int              estimate_nxopt31_HTM(DfsArg *arg);
     35 static int              estimate_light_HTM(DfsArg *arg);
     36 static int              estimate_nxoptlike(DfsArg *arg, PruneData *pd);
     37 
     38 static bool             always_valid(Alg *alg);
     39 static bool             validate_singlecw_ending(Alg *alg);
     40 static bool             validate_htr(Alg *alg);
     41 
     42 /* Pre-transformation detectors **********************************************/
     43 
     44 static int              detect_pretrans_eofb(Cube cube, Trans *ret);
     45 static int              detect_pretrans_drud(Cube cube, Trans *ret);
     46 static int              detect_pretrans_void_3axis(Cube cube, Trans *ret);
     47 
     48 /* Messages for when cube is not ready ***************************************/
     49 
     50 static char check_centers_msg[100] = "cube must be oriented (centers solved)";
     51 static char check_eo_msg[100]      = "EO must be solved on given axis";
     52 static char check_dr_msg[100]      = "DR must be solved on given axis";
     53 static char check_htr_msg[100]     = "HTR must be solved";
     54 static char check_drany_msg[100]   = "DR must be solved on at least one axis";
     55 static char check_co_msg[100]      = "CO must be solved on the given axis";
     56 static char check_coany_msg[100]   = "CO must be solved on at least one axis";
     57 
     58 /* Steps *********************************************************************/
     59 
     60 /* Optimal solvers *******************/
     61 
     62 Step
     63 optimal_HTM = {
     64 	.shortname = "optimal",
     65 	.name      = "Optimal solve (in HTM)",
     66 
     67 	.final     = true,
     68 	.is_done   = is_solved,
     69 	.estimate  = estimate_nxopt31_HTM,
     70 	.ready     = check_centers,
     71 	.ready_msg = check_centers_msg,
     72 	.is_valid  = always_valid,
     73 	.moveset   = &moveset_HTM,
     74 
     75 	.pre_trans = uf,
     76 
     77 	.tables    = {&pd_nxopt31_HTM, &pd_corners_HTM},
     78 	.ntables   = 2,
     79 };
     80 
     81 Step
     82 optimal_light_HTM = {
     83 	.shortname = "light",
     84 	.name      = "Optimal solve (in HTM), small table (500Mb RAM total)",
     85 
     86 	.final     = true,
     87 	.is_done   = is_solved,
     88 	.estimate  = estimate_light_HTM,
     89 	.ready     = check_centers,
     90 	.ready_msg = check_centers_msg,
     91 	.is_valid  = always_valid,
     92 	.moveset   = &moveset_HTM,
     93 
     94 	.pre_trans = uf,
     95 
     96 	.tables    = {&pd_drud_sym16_HTM, &pd_corners_HTM},
     97 	.ntables   = 2,
     98 };
     99 
    100 /* Optimal after EO ******************/
    101 
    102 Step
    103 eofin_eo = {
    104 	.shortname = "eofin",
    105 	.name      = "Optimal solve after EO without breaking EO (detected)",
    106 
    107 	.final     = true,
    108 	.is_done   = is_solved,
    109 	.estimate  = estimate_nxopt31_HTM,
    110 	.ready     = check_eofb,
    111 	.ready_msg = check_eo_msg,
    112 	.is_valid  = always_valid,
    113 	.moveset   = &moveset_eofb,
    114 
    115 	.detect    = detect_pretrans_eofb,
    116 
    117 	.tables    = {&pd_nxopt31_HTM, &pd_corners_HTM},
    118 	.ntables   = 2,
    119 };
    120 
    121 Step
    122 eofbfin_eofb = {
    123 	.shortname = "eofbfin",
    124 	.name      = "Optimal after EO on F/B without breaking EO",
    125 
    126 	.final     = true,
    127 	.is_done   = is_solved,
    128 	.estimate  = estimate_nxopt31_HTM,
    129 	.ready     = check_eofb,
    130 	.ready_msg = check_eo_msg,
    131 	.is_valid  = always_valid,
    132 	.moveset   = &moveset_eofb,
    133 
    134 	.pre_trans = uf,
    135 
    136 	.tables    = {&pd_nxopt31_HTM, &pd_corners_HTM},
    137 	.ntables   = 2,
    138 };
    139 
    140 Step
    141 eorlfin_eorl = {
    142 	.shortname = "eorlfin",
    143 	.name      = "Optimal after EO on R/L without breaking EO",
    144 
    145 	.final     = true,
    146 	.is_done   = is_solved,
    147 	.estimate  = estimate_nxopt31_HTM,
    148 	.ready     = check_eofb,
    149 	.ready_msg = check_eo_msg,
    150 	.is_valid  = always_valid,
    151 	.moveset   = &moveset_eofb,
    152 
    153 	.pre_trans = ur,
    154 
    155 	.tables    = {&pd_nxopt31_HTM, &pd_corners_HTM},
    156 	.ntables   = 2,
    157 };
    158 
    159 Step
    160 eoudfin_eoud = {
    161 	.shortname = "eoudfin",
    162 	.name      = "Optimal after EO on U/D without breaking EO",
    163 
    164 	.final     = true,
    165 	.is_done   = is_solved,
    166 	.estimate  = estimate_nxopt31_HTM,
    167 	.ready     = check_eofb,
    168 	.ready_msg = check_eo_msg,
    169 	.is_valid  = always_valid,
    170 	.moveset   = &moveset_eofb,
    171 
    172 	.pre_trans = fd,
    173 
    174 	.tables    = {&pd_nxopt31_HTM, &pd_corners_HTM},
    175 	.ntables   = 2,
    176 };
    177 
    178 /* EO steps **************************/
    179 Step
    180 eoany_HTM = {
    181 	.shortname = "eo",
    182 	.name      = "EO on any axis",
    183 
    184 	.final     = false,
    185 	.is_done   = check_eofb,
    186 	.estimate  = estimate_eofb_HTM,
    187 	.ready     = check_centers,
    188 	.ready_msg = check_centers_msg,
    189 	.is_valid  = validate_singlecw_ending,
    190 	.moveset   = &moveset_HTM,
    191 
    192 	.detect    = detect_pretrans_void_3axis,
    193 
    194 	.tables    = {&pd_eofb_HTM},
    195 	.ntables   = 1,
    196 };
    197 
    198 Step
    199 eofb_HTM = {
    200 	.shortname = "eofb",
    201 	.name      = "EO on F/B",
    202 
    203 	.final     = false,
    204 	.is_done   = check_eofb,
    205 	.estimate  = estimate_eofb_HTM,
    206 	.ready     = check_centers,
    207 	.ready_msg = check_centers_msg,
    208 	.is_valid  = validate_singlecw_ending,
    209 	.moveset   = &moveset_HTM,
    210 
    211 	.pre_trans = uf,
    212 
    213 	.tables    = {&pd_eofb_HTM},
    214 	.ntables   = 1,
    215 };
    216 
    217 Step
    218 eorl_HTM = {
    219 	.shortname = "eorl",
    220 	.name      = "EO on R/L",
    221 
    222 	.final     = false,
    223 	.is_done   = check_eofb,
    224 	.estimate  = estimate_eofb_HTM,
    225 	.ready     = check_centers,
    226 	.ready_msg = check_centers_msg,
    227 	.is_valid  = validate_singlecw_ending,
    228 	.moveset   = &moveset_HTM,
    229 
    230 	.pre_trans = ur,
    231 
    232 	.tables    = {&pd_eofb_HTM},
    233 	.ntables   = 1,
    234 };
    235 
    236 Step
    237 eoud_HTM = {
    238 	.shortname = "eoud",
    239 	.name      = "EO on U/D",
    240 
    241 	.final     = false,
    242 	.is_done   = check_eofb,
    243 	.estimate  = estimate_eofb_HTM,
    244 	.ready     = check_centers,
    245 	.ready_msg = check_centers_msg,
    246 	.is_valid  = validate_singlecw_ending,
    247 	.moveset   = &moveset_HTM,
    248 
    249 	.pre_trans = fd,
    250 
    251 	.tables    = {&pd_eofb_HTM},
    252 	.ntables   = 1,
    253 };
    254 
    255 /* CO steps **************************/
    256 Step
    257 coany_HTM = {
    258 	.shortname = "co",
    259 	.name      = "CO on any axis",
    260 
    261 	.final     = false,
    262 	.is_done   = check_coud_HTM,
    263 	.estimate  = estimate_coud_HTM,
    264 	.ready     = NULL,
    265 	.is_valid  = validate_singlecw_ending,
    266 	.moveset   = &moveset_HTM,
    267 
    268 	.detect    = detect_pretrans_void_3axis,
    269 
    270 	.tables    = {&pd_coud_HTM},
    271 	.ntables   = 1,
    272 };
    273 
    274 Step
    275 coud_HTM = {
    276 	.shortname = "coud",
    277 	.name      = "CO on U/D",
    278 
    279 	.final     = false,
    280 	.is_done   = check_coud_HTM,
    281 	.estimate  = estimate_coud_HTM,
    282 	.ready     = NULL,
    283 	.is_valid  = validate_singlecw_ending,
    284 	.moveset   = &moveset_HTM,
    285 
    286 	.pre_trans = uf,
    287 
    288 	.tables    = {&pd_coud_HTM},
    289 	.ntables   = 1,
    290 };
    291 
    292 Step
    293 corl_HTM = {
    294 	.shortname = "corl",
    295 	.name      = "CO on R/L",
    296 
    297 	.final     = false,
    298 	.is_done   = check_coud_HTM,
    299 	.estimate  = estimate_coud_HTM,
    300 	.ready     = NULL,
    301 	.is_valid  = validate_singlecw_ending,
    302 	.moveset   = &moveset_HTM,
    303 
    304 	.pre_trans = rf,
    305 
    306 	.tables    = {&pd_coud_HTM},
    307 	.ntables   = 1,
    308 };
    309 
    310 Step
    311 cofb_HTM = {
    312 	.shortname = "cofb",
    313 	.name      = "CO on F/B",
    314 
    315 	.final     = false,
    316 	.is_done   = check_coud_HTM,
    317 	.estimate  = estimate_coud_HTM,
    318 	.ready     = NULL,
    319 	.is_valid  = validate_singlecw_ending,
    320 	.moveset   = &moveset_HTM,
    321 
    322 	.pre_trans = fd,
    323 
    324 	.tables    = {&pd_coud_HTM},
    325 	.ntables   = 1,
    326 };
    327 
    328 Step
    329 coany_URF = {
    330 	.shortname = "co-URF",
    331 	.name      = "CO any axis (URF moveset)",
    332 
    333 	.final     = false,
    334 	.is_done   = check_coud_URF,
    335 	.estimate  = estimate_coud_URF,
    336 	.ready     = NULL,
    337 	.is_valid  = validate_singlecw_ending,
    338 	.moveset   = &moveset_URF,
    339 
    340 	.detect    = detect_pretrans_void_3axis,
    341 
    342 	.tables    = {&pd_coud_HTM},
    343 	.ntables   = 1,
    344 };
    345 
    346 Step
    347 coud_URF = {
    348 	.shortname = "coud-URF",
    349 	.name      = "CO on U/D (URF moveset)",
    350 
    351 	.final     = false,
    352 	.is_done   = check_coud_URF,
    353 	.estimate  = estimate_coud_URF,
    354 	.ready     = NULL,
    355 	.is_valid  = validate_singlecw_ending,
    356 	.moveset   = &moveset_URF,
    357 
    358 	.pre_trans = uf,
    359 
    360 	.tables    = {&pd_coud_HTM},
    361 	.ntables   = 1,
    362 };
    363 
    364 Step
    365 corl_URF = {
    366 	.shortname = "corl-URF",
    367 	.name      = "CO on R/L (URF moveset)",
    368 
    369 	.final     = false,
    370 	.is_done   = check_coud_URF,
    371 	.estimate  = estimate_coud_URF,
    372 	.ready     = NULL,
    373 	.is_valid  = validate_singlecw_ending,
    374 	.moveset   = &moveset_URF,
    375 
    376 	.pre_trans = rf,
    377 
    378 	.tables    = {&pd_coud_HTM},
    379 	.ntables   = 1,
    380 };
    381 
    382 Step
    383 cofb_URF = {
    384 	.shortname = "cofb-URF",
    385 	.name      = "CO on F/B (URF moveset)",
    386 
    387 	.final     = false,
    388 	.is_done   = check_coud_URF,
    389 	.estimate  = estimate_coud_URF,
    390 	.ready     = NULL,
    391 	.is_valid  = validate_singlecw_ending,
    392 	.moveset   = &moveset_URF,
    393 
    394 	.pre_trans = fd,
    395 
    396 	.tables    = {&pd_coud_HTM},
    397 	.ntables   = 1,
    398 };
    399 
    400 /* Misc corner steps *****************/
    401 Step
    402 cornershtr_HTM = {
    403 	.shortname = "chtr",
    404 	.name      = "Solve corners to HTR state",
    405 
    406 	.final     = false,
    407 	.is_done   = check_cornershtr,
    408 	.estimate  = estimate_cornershtr_HTM,
    409 	.ready     = NULL,
    410 	.is_valid  = validate_htr,
    411 	.moveset   = &moveset_HTM,
    412 
    413 	.pre_trans = uf,
    414 
    415 	.tables    = {&pd_cornershtr_HTM},
    416 	.ntables   = 1,
    417 };
    418 
    419 Step
    420 cornershtr_URF = {
    421 	.shortname = "chtr-URF",
    422 	.name      = "Solve corners to HTR state (URF moveset)",
    423 
    424 	.final     = false,
    425 	.is_done   = check_cornershtr,
    426 	.estimate  = estimate_cornershtr_URF,
    427 	.ready     = NULL,
    428 	.is_valid  = validate_singlecw_ending,
    429 	.moveset   = &moveset_URF,
    430 
    431 	.pre_trans = uf,
    432 
    433 	.tables    = {&pd_cornershtr_HTM},
    434 	.ntables   = 1,
    435 };
    436 
    437 Step
    438 corners_HTM = {
    439 	.shortname = "corners",
    440 	.name      = "Solve corners",
    441 
    442 	.final     = true,
    443 	.is_done   = check_corners_HTM,
    444 	.estimate  = estimate_corners_HTM,
    445 	.ready     = NULL,
    446 	.is_valid  = always_valid,
    447 	.moveset   = &moveset_HTM,
    448 
    449 	.pre_trans = uf,
    450 
    451 	.tables    = {&pd_corners_HTM},
    452 	.ntables   = 1,
    453 };
    454 
    455 Step
    456 corners_URF = {
    457 	.shortname = "corners-URF",
    458 	.name      = "Solve corners (URF moveset)",
    459 
    460 	.final     = true, /* TODO: check if this works with reorient */
    461 	.is_done   = check_corners_URF,
    462 	.estimate  = estimate_corners_URF,
    463 	.ready     = NULL,
    464 	.is_valid  = always_valid,
    465 	.moveset   = &moveset_URF,
    466 
    467 	.pre_trans = uf,
    468 
    469 	.tables    = {&pd_corners_HTM},
    470 	.ntables   = 1,
    471 };
    472 
    473 /* DR steps **************************/
    474 Step
    475 drany_HTM = {
    476 	.shortname = "dr",
    477 	.name      = "DR on any axis",
    478 
    479 	.final     = false,
    480 	.is_done   = check_drud,
    481 	.estimate  = estimate_drud_HTM,
    482 	.ready     = check_centers,
    483 	.ready_msg = check_centers_msg,
    484 	.is_valid  = validate_singlecw_ending,
    485 	.moveset   = &moveset_HTM,
    486 
    487 	.detect    = detect_pretrans_void_3axis,
    488 
    489 	.tables    = {&pd_drud_sym16_HTM},
    490 	.ntables   = 1,
    491 };
    492 
    493 Step
    494 drud_HTM = {
    495 	.shortname = "drud",
    496 	.name      = "DR on U/D",
    497 
    498 	.final     = false,
    499 	.is_done   = check_drud,
    500 	.estimate  = estimate_drud_HTM,
    501 	.ready     = check_centers,
    502 	.ready_msg = check_centers_msg,
    503 	.is_valid  = validate_singlecw_ending,
    504 	.moveset   = &moveset_HTM,
    505 
    506 	.pre_trans = uf,
    507 
    508 	.tables    = {&pd_drud_sym16_HTM},
    509 	.ntables   = 1,
    510 };
    511 
    512 Step
    513 drrl_HTM = {
    514 	.shortname = "drrl",
    515 	.name      = "DR on R/L",
    516 
    517 	.final     = false,
    518 	.is_done   = check_drud,
    519 	.estimate  = estimate_drud_HTM,
    520 	.ready     = check_centers,
    521 	.ready_msg = check_centers_msg,
    522 	.is_valid  = validate_singlecw_ending,
    523 	.moveset   = &moveset_HTM,
    524 
    525 	.pre_trans = rf,
    526 
    527 	.tables    = {&pd_drud_sym16_HTM},
    528 	.ntables   = 1,
    529 };
    530 
    531 Step
    532 drfb_HTM = {
    533 	.shortname = "drfb",
    534 	.name      = "DR on F/B",
    535 
    536 	.final     = false,
    537 	.is_done   = check_drud,
    538 	.estimate  = estimate_drud_HTM,
    539 	.ready     = check_centers,
    540 	.ready_msg = check_centers_msg,
    541 	.is_valid  = validate_singlecw_ending,
    542 	.moveset   = &moveset_HTM,
    543 
    544 	.pre_trans = fd,
    545 
    546 	.tables    = {&pd_drud_sym16_HTM},
    547 	.ntables   = 1,
    548 };
    549 
    550 /* DR from EO */
    551 Step
    552 dr_eo = {
    553 	.shortname = "dr-eo",
    554 	.name      = "DR without breaking EO (automatically detected)",
    555 
    556 	.final     = false,
    557 	.is_done   = check_drud_or_drrl,
    558 	.estimate  = estimate_dr_eofb,
    559 	.ready     = check_eofb,
    560 	.ready_msg = check_eo_msg,
    561 	.is_valid  = validate_singlecw_ending,
    562 	.moveset   = &moveset_eofb,
    563 
    564 	.detect    = detect_pretrans_eofb,
    565 
    566 	.tables    = {&pd_drud_eofb},
    567 	.ntables   = 1,
    568 };
    569 
    570 Step
    571 dr_eofb = {
    572 	.shortname = "dr-eofb",
    573 	.name      = "DR on U/D or R/L without breaking EO on F/B",
    574 
    575 	.final     = false,
    576 	.is_done   = check_drud_or_drrl,
    577 	.estimate  = estimate_dr_eofb,
    578 	.ready     = check_eofb,
    579 	.ready_msg = check_eo_msg,
    580 	.is_valid  = validate_singlecw_ending,
    581 	.moveset   = &moveset_eofb,
    582 
    583 	.pre_trans = uf,
    584 
    585 	.tables    = {&pd_drud_eofb},
    586 	.ntables   = 1,
    587 };
    588 
    589 Step
    590 dr_eorl = {
    591 	.shortname = "dr-eorl",
    592 	.name      = "DR on U/D or F/B without breaking EO on R/L",
    593 
    594 	.final     = false,
    595 	.is_done   = check_drud_or_drrl,
    596 	.estimate  = estimate_dr_eofb,
    597 	.ready     = check_eofb,
    598 	.ready_msg = check_eo_msg,
    599 	.is_valid  = validate_singlecw_ending,
    600 	.moveset   = &moveset_eofb,
    601 
    602 	.pre_trans = ur,
    603 
    604 	.tables    = {&pd_drud_eofb},
    605 	.ntables   = 1,
    606 };
    607 
    608 Step
    609 dr_eoud = {
    610 	.shortname = "dr-eoud",
    611 	.name      = "DR on R/L or F/B without breaking EO on U/D",
    612 
    613 	.final     = false,
    614 	.is_done   = check_drud_or_drrl,
    615 	.estimate  = estimate_dr_eofb,
    616 	.ready     = check_eofb,
    617 	.ready_msg = check_eo_msg,
    618 	.is_valid  = validate_singlecw_ending,
    619 	.moveset   = &moveset_eofb,
    620 
    621 	.pre_trans = fd,
    622 
    623 	.tables    = {&pd_drud_eofb},
    624 	.ntables   = 1,
    625 };
    626 
    627 Step
    628 drud_eofb = {
    629 	.shortname = "drud-eofb",
    630 	.name      = "DR on U/D without breaking EO on F/B",
    631 
    632 	.final     = false,
    633 	.is_done   = check_drud,
    634 	.estimate  = estimate_drud_eofb,
    635 	.ready     = check_eofb,
    636 	.ready_msg = check_eo_msg,
    637 	.is_valid  = validate_singlecw_ending,
    638 	.moveset   = &moveset_eofb,
    639 
    640 	.pre_trans = uf,
    641 
    642 	.tables    = {&pd_drud_eofb},
    643 	.ntables   = 1,
    644 };
    645 
    646 Step
    647 drrl_eofb = {
    648 	.shortname = "drrl-eofb",
    649 	.name      = "DR on R/L without breaking EO on F/B",
    650 
    651 	.final     = false,
    652 	.is_done   = check_drud,
    653 	.estimate  = estimate_drud_eofb,
    654 	.ready     = check_eofb,
    655 	.ready_msg = check_eo_msg,
    656 	.is_valid  = validate_singlecw_ending,
    657 	.moveset   = &moveset_eofb,
    658 
    659 	.pre_trans = rf,
    660 
    661 	.tables    = {&pd_drud_eofb},
    662 	.ntables   = 1,
    663 };
    664 
    665 Step
    666 drud_eorl = {
    667 	.shortname = "drud-eorl",
    668 	.name      = "DR on U/D without breaking EO on R/L",
    669 
    670 	.final     = false,
    671 	.is_done   = check_drud,
    672 	.estimate  = estimate_drud_eofb,
    673 	.ready     = check_eofb,
    674 	.ready_msg = check_eo_msg,
    675 	.is_valid  = validate_singlecw_ending,
    676 	.moveset   = &moveset_eofb,
    677 
    678 	.pre_trans = ur,
    679 
    680 	.tables    = {&pd_drud_eofb},
    681 	.ntables   = 1,
    682 };
    683 
    684 Step
    685 drfb_eorl = {
    686 	.shortname = "drfb-eorl",
    687 	.name      = "DR on F/B without breaking EO on R/L",
    688 
    689 	.final     = false,
    690 	.is_done   = check_drud,
    691 	.estimate  = estimate_drud_eofb,
    692 	.ready     = check_eofb,
    693 	.ready_msg = check_eo_msg,
    694 	.is_valid  = validate_singlecw_ending,
    695 	.moveset   = &moveset_eofb,
    696 
    697 	.pre_trans = fr,
    698 
    699 	.tables    = {&pd_drud_eofb},
    700 	.ntables   = 1,
    701 };
    702 
    703 Step
    704 drfb_eoud = {
    705 	.shortname = "drfb-eoud",
    706 	.name      = "DR on F/B without breaking EO on U/D",
    707 
    708 	.final     = false,
    709 	.is_done   = check_drud,
    710 	.estimate  = estimate_drud_eofb,
    711 	.ready     = check_eofb,
    712 	.ready_msg = check_eo_msg,
    713 	.is_valid  = validate_singlecw_ending,
    714 	.moveset   = &moveset_eofb,
    715 
    716 	.pre_trans = fd,
    717 
    718 	.tables    = {&pd_drud_eofb},
    719 	.ntables   = 1,
    720 };
    721 
    722 Step
    723 drrl_eoud = {
    724 	.shortname = "drrl-eoud",
    725 	.name      = "DR on R/L without breaking EO on U/D",
    726 
    727 	.final     = false,
    728 	.is_done   = check_drud,
    729 	.estimate  = estimate_drud_eofb,
    730 	.ready     = check_eofb,
    731 	.ready_msg = check_eo_msg,
    732 	.is_valid  = validate_singlecw_ending,
    733 	.moveset   = &moveset_eofb,
    734 
    735 	.pre_trans = rd,
    736 
    737 	.tables    = {&pd_drud_eofb},
    738 	.ntables   = 1,
    739 };
    740 
    741 /* DR finish minus slice steps */
    742 Step
    743 dranyslice_DR = {
    744 	.shortname = "drslice",
    745 	.name      = "DR finish minus slice on any axis without breaking DR",
    746 
    747 	.final     = true,
    748 	.is_done   = check_drudslice,
    749 	.estimate  = estimate_drudslice_drud,
    750 	.ready     = check_drud,
    751 	.ready_msg = check_drany_msg,
    752 	.is_valid  = always_valid,
    753 	.moveset   = &moveset_drud_noD,
    754 
    755 	.detect    = detect_pretrans_drud,
    756 
    757 	.tables    = {&pd_drudfin_noE_sym16_drud},
    758 	.ntables   = 1,
    759 };
    760 
    761 Step
    762 drudslice_drud = {
    763 	.shortname = "drudslice",
    764 	.name      = "DR finish minus slice on U/D without breaking DR",
    765 
    766 	.final     = true,
    767 	.is_done   = check_drudslice,
    768 	.estimate  = estimate_drudslice_drud,
    769 	.ready     = check_drud,
    770 	.ready_msg = check_dr_msg,
    771 	.is_valid  = always_valid,
    772 	.moveset   = &moveset_drud_noD,
    773 
    774 	.pre_trans = uf,
    775 
    776 	.tables    = {&pd_drudfin_noE_sym16_drud},
    777 	.ntables   = 1,
    778 };
    779 
    780 Step
    781 drrlslice_drrl = {
    782 	.shortname = "drrlslice",
    783 	.name      = "DR finish minus slice on R/L without breaking DR",
    784 
    785 	.final     = true,
    786 	.is_done   = check_drudslice,
    787 	.estimate  = estimate_drudslice_drud,
    788 	.ready     = check_drud,
    789 	.ready_msg = check_dr_msg,
    790 	.is_valid  = always_valid,
    791 	.moveset   = &moveset_drud_noD,
    792 
    793 	.pre_trans = rf,
    794 
    795 	.tables    = {&pd_drudfin_noE_sym16_drud},
    796 	.ntables   = 1,
    797 };
    798 
    799 Step
    800 drfbslice_drfb = {
    801 	.shortname = "drfbslice",
    802 	.name      = "DR finish minus slice on F/B without breaking DR",
    803 
    804 	.final     = true,
    805 	.is_done   = check_drudslice,
    806 	.estimate  = estimate_drudslice_drud,
    807 	.ready     = check_drud,
    808 	.ready_msg = check_dr_msg,
    809 	.is_valid  = always_valid,
    810 	.moveset   = &moveset_drud_noD,
    811 
    812 	.pre_trans = fd,
    813 
    814 	.tables    = {&pd_drudfin_noE_sym16_drud},
    815 	.ntables   = 1,
    816 };
    817 
    818 /* DR finish steps */
    819 Step
    820 dranyfin_DR = {
    821 	.shortname = "drfin",
    822 	.name      = "DR finish on any axis without breaking DR",
    823 
    824 	.final     = true,
    825 	.is_done   = is_solved,
    826 	.estimate  = estimate_drudfin_drud,
    827 	.ready     = check_drud,
    828 	.ready_msg = check_drany_msg,
    829 	.is_valid  = always_valid,
    830 	.moveset   = &moveset_drud,
    831 
    832 	.detect    = detect_pretrans_drud,
    833 
    834 	.tables    = {&pd_drudfin_noE_sym16_drud},
    835 	.ntables   = 1,
    836 };
    837 
    838 Step
    839 drudfin_drud = {
    840 	.shortname = "drudfin",
    841 	.name      = "DR finish on U/D without breaking DR",
    842 
    843 	.final     = true,
    844 	.is_done   = is_solved,
    845 	.estimate  = estimate_drudfin_drud,
    846 	.ready     = check_drud,
    847 	.ready_msg = check_dr_msg,
    848 	.is_valid  = always_valid,
    849 	.moveset   = &moveset_drud,
    850 
    851 	.pre_trans = uf,
    852 
    853 	.tables    = {&pd_drudfin_noE_sym16_drud},
    854 	.ntables   = 1,
    855 };
    856 
    857 Step
    858 drrlfin_drrl = {
    859 	.shortname = "drrlfin",
    860 	.name      = "DR finish on R/L without breaking DR",
    861 
    862 	.final     = true,
    863 	.is_done   = is_solved,
    864 	.estimate  = estimate_drudfin_drud,
    865 	.ready     = check_drud,
    866 	.ready_msg = check_dr_msg,
    867 	.is_valid  = always_valid,
    868 	.moveset   = &moveset_drud,
    869 
    870 	.pre_trans = rf,
    871 
    872 	.tables    = {&pd_drudfin_noE_sym16_drud},
    873 	.ntables   = 1,
    874 };
    875 
    876 Step
    877 drfbfin_drfb = {
    878 	.shortname = "drfbfin",
    879 	.name      = "DR finish on F/B without breaking DR",
    880 
    881 	.final     = true,
    882 	.is_done   = is_solved,
    883 	.estimate  = estimate_drudfin_drud,
    884 	.ready     = check_drud,
    885 	.ready_msg = check_dr_msg,
    886 	.is_valid  = always_valid,
    887 	.moveset   = &moveset_drud,
    888 
    889 	.pre_trans = fd,
    890 
    891 	.tables    = {&pd_drudfin_noE_sym16_drud},
    892 	.ntables   = 1,
    893 };
    894 
    895 /* HTR from DR */
    896 Step
    897 htr_any = {
    898 	.shortname = "htr",
    899 	.name      = "HTR from DR",
    900 
    901 	.final     = false,
    902 	.is_done   = check_htr,
    903 	.estimate  = estimate_htr_drud,
    904 	.ready     = check_drud,
    905 	.ready_msg = check_drany_msg,
    906 	.is_valid  = validate_htr,
    907 	.moveset   = &moveset_drud,
    908 
    909 	.detect    = detect_pretrans_drud,
    910 
    911 	.tables    = {&pd_htr_drud},
    912 	.ntables   = 1,
    913 };
    914 
    915 Step
    916 htr_drud = {
    917 	.shortname = "htr-drud",
    918 	.name      = "HTR from DR on U/D",
    919 
    920 	.final     = false,
    921 	.is_done   = check_htr,
    922 	.estimate  = estimate_htr_drud,
    923 	.ready     = check_drud,
    924 	.ready_msg = check_dr_msg,
    925 	.is_valid  = validate_htr,
    926 	.moveset   = &moveset_drud,
    927 
    928 	.pre_trans = uf,
    929 
    930 	.tables    = {&pd_htr_drud},
    931 	.ntables   = 1,
    932 };
    933 
    934 Step
    935 htr_drrl = {
    936 	.shortname = "htr-drrl",
    937 	.name      = "HTR from DR on R/L",
    938 
    939 	.final     = false,
    940 	.is_done   = check_htr,
    941 	.estimate  = estimate_htr_drud,
    942 	.ready     = check_drud,
    943 	.ready_msg = check_dr_msg,
    944 	.is_valid  = validate_htr,
    945 	.moveset   = &moveset_drud,
    946 
    947 	.pre_trans = rf,
    948 
    949 	.tables    = {&pd_htr_drud},
    950 	.ntables   = 1,
    951 };
    952 
    953 Step
    954 htr_drfb = {
    955 	.shortname = "htr-drfb",
    956 	.name      = "HTR from DR on F/B",
    957 
    958 	.final     = false,
    959 	.is_done   = check_htr,
    960 	.estimate  = estimate_htr_drud,
    961 	.ready     = check_drud,
    962 	.ready_msg = check_dr_msg,
    963 	.is_valid  = validate_htr,
    964 	.moveset   = &moveset_drud,
    965 
    966 	.pre_trans = fd,
    967 
    968 	.tables    = {&pd_htr_drud},
    969 	.ntables   = 1,
    970 };
    971 
    972 /* Corners from DR */
    973 Step
    974 corners_dr_any = {
    975 	.shortname = "corners-dr",
    976 	.name      = "Solve corners from DR",
    977 
    978 	.final     = true,
    979 	.is_done   = check_corners_HTM,
    980 	.estimate  = estimate_cp_drud,
    981 	.ready     = check_coud_HTM,
    982 	.ready_msg = check_coany_msg,
    983 	.is_valid  = always_valid,
    984 	.moveset   = &moveset_drud,
    985 
    986 	.detect    = detect_pretrans_drud,
    987 
    988 	.tables    = {&pd_cp_drud},
    989 	.ntables   = 1,
    990 };
    991 
    992 Step
    993 corners_drud = {
    994 	.shortname = "corners-drud",
    995 	.name      = "Solve corners from DR on U/D",
    996 
    997 	.final     = true,
    998 	.is_done   = check_corners_HTM,
    999 	.estimate  = estimate_cp_drud,
   1000 	.ready     = check_coud_HTM,
   1001 	.ready_msg = check_co_msg,
   1002 	.is_valid  = always_valid,
   1003 	.moveset   = &moveset_drud,
   1004 
   1005 	.pre_trans = uf,
   1006 
   1007 	.tables    = {&pd_cp_drud},
   1008 	.ntables   = 1,
   1009 };
   1010 
   1011 Step
   1012 corners_drrl = {
   1013 	.shortname = "corners-drrl",
   1014 	.name      = "Solve corners from DR on R/L",
   1015 
   1016 	.final     = true,
   1017 	.is_done   = check_corners_HTM,
   1018 	.estimate  = estimate_cp_drud,
   1019 	.ready     = check_coud_HTM,
   1020 	.ready_msg = check_co_msg,
   1021 	.is_valid  = always_valid,
   1022 	.moveset   = &moveset_drud,
   1023 
   1024 	.pre_trans = rf,
   1025 
   1026 	.tables    = {&pd_cp_drud},
   1027 	.ntables   = 1,
   1028 };
   1029 
   1030 Step
   1031 corners_drfb = {
   1032 	.shortname = "corners-drfb",
   1033 	.name      = "Solve corners from DR on F/B",
   1034 
   1035 	.final     = true,
   1036 	.is_done   = check_corners_HTM,
   1037 	.estimate  = estimate_cp_drud,
   1038 	.ready     = check_coud_HTM,
   1039 	.ready_msg = check_co_msg,
   1040 	.is_valid  = always_valid,
   1041 	.moveset   = &moveset_drud,
   1042 
   1043 	.pre_trans = fd,
   1044 
   1045 	.tables    = {&pd_cp_drud},
   1046 	.ntables   = 1,
   1047 };
   1048 
   1049 /* HTR finish */
   1050 Step
   1051 htrfin_htr = {
   1052 	.shortname = "htrfin",
   1053 	.name      = "HTR finish without breaking HTR",
   1054 
   1055 	.final     = true,
   1056 	.is_done   = is_solved,
   1057 	.estimate  = estimate_htrfin_htr,
   1058 	.ready     = check_htr,
   1059 	.ready_msg = check_htr_msg,
   1060 	.is_valid  = always_valid,
   1061 	.moveset   = &moveset_htr,
   1062 
   1063 	.pre_trans = uf,
   1064 
   1065 	.tables    = {&pd_htrfin_htr},
   1066 	.ntables   = 1,
   1067 };
   1068 
   1069 Step *steps[] = {
   1070 	&optimal_HTM, /* first is default */
   1071 	&optimal_light_HTM,
   1072 
   1073 	&eofin_eo,
   1074 	&eofbfin_eofb,
   1075 	&eorlfin_eorl,
   1076 	&eoudfin_eoud,
   1077 
   1078 	&eoany_HTM,
   1079 	&eofb_HTM,
   1080 	&eorl_HTM,
   1081 	&eoud_HTM,
   1082 
   1083 	&coany_HTM,
   1084 	&coud_HTM,
   1085 	&corl_HTM,
   1086 	&cofb_HTM,
   1087 
   1088 	&coany_URF,
   1089 	&coud_URF,
   1090 	&corl_URF,
   1091 	&cofb_URF,
   1092 
   1093 	&drany_HTM,
   1094 	&drud_HTM,
   1095 	&drrl_HTM,
   1096 	&drfb_HTM,
   1097 
   1098 	&dr_eo,
   1099 	&dr_eofb,
   1100 	&dr_eorl,
   1101 	&dr_eoud,
   1102 	&drud_eofb,
   1103 	&drrl_eofb,
   1104 	&drud_eorl,
   1105 	&drfb_eorl,
   1106 	&drfb_eoud,
   1107 	&drrl_eoud,
   1108 
   1109 	&dranyfin_DR,
   1110 	&drudfin_drud,
   1111 	&drrlfin_drrl,
   1112 	&drfbfin_drfb,
   1113 
   1114 	&dranyslice_DR,
   1115 	&drudslice_drud,
   1116 	&drrlslice_drrl,
   1117 	&drfbslice_drfb,
   1118 
   1119 	&htr_any,
   1120 	&htr_drud,
   1121 	&htr_drrl,
   1122 	&htr_drfb,
   1123 
   1124 	&corners_dr_any,
   1125 	&corners_drud,
   1126 	&corners_drrl,
   1127 	&corners_drfb,
   1128 
   1129 	&htrfin_htr,
   1130 
   1131 	&cornershtr_HTM,
   1132 	&cornershtr_URF,
   1133 	&corners_HTM,
   1134 	&corners_URF,
   1135 
   1136 	NULL
   1137 };
   1138 
   1139 /* Checkers, estimators and validators ***************************************/
   1140 
   1141 static bool
   1142 check_centers(Cube cube)
   1143 {
   1144 	return cube.cpos == 0;
   1145 }
   1146 
   1147 static bool
   1148 check_coud_HTM(Cube cube)
   1149 {
   1150 	return cube.coud == 0;
   1151 }
   1152 
   1153 static bool
   1154 check_coud_URF(Cube cube)
   1155 {
   1156 	Cube c2, c3;
   1157 
   1158 	c2 = apply_move(z, cube);
   1159 	c3 = apply_move(x, cube);
   1160 
   1161 	return cube.coud == 0 || c2.coud == 0 || c3.coud == 0;
   1162 }
   1163 
   1164 static bool
   1165 check_corners_URF(Cube cube)
   1166 {
   1167 	Cube c;
   1168 	Trans i;
   1169 
   1170 	for (i = 0; i < NROTATIONS; i++) {
   1171 		c = apply_alg(rotation_alg(i), cube);
   1172 		if (c.cp && c.coud)
   1173 			return true;
   1174 	}
   1175 
   1176 	return false;
   1177 }
   1178 
   1179 static bool
   1180 check_corners_HTM(Cube cube)
   1181 {
   1182 	return cube.cp == 0 && cube.coud == 0;
   1183 }
   1184 
   1185 static bool
   1186 check_cornershtr(Cube cube)
   1187 {
   1188 	return coord_cornershtr.index(cube) == 0;
   1189 }
   1190 
   1191 static bool
   1192 check_eofb(Cube cube)
   1193 {
   1194 	return cube.eofb == 0;
   1195 }
   1196 
   1197 static bool
   1198 check_drud(Cube cube)
   1199 {
   1200 	return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
   1201 }
   1202 
   1203 static bool
   1204 check_drud_or_drrl(Cube cube)
   1205 {
   1206 	return check_drud(cube) || check_drud(apply_trans(rf, cube));
   1207 }
   1208 
   1209 static bool
   1210 check_htr(Cube cube)
   1211 {
   1212 	return check_drud(cube) && coord_htr_drud.index(cube) == 0;
   1213 }
   1214 
   1215 static bool
   1216 check_drudslice(Cube cube)
   1217 {
   1218 	int i;
   1219 	Cube aux;
   1220 
   1221 	aux = cube;
   1222 	for (i = 0; i < 4; i++, aux = apply_move(y, aux))
   1223 		if (coord_cp.index(aux) == 0 &&
   1224 		    coord_epud.index(aux) == 0)
   1225 			return true;
   1226 
   1227 	return false;
   1228 }
   1229 
   1230 static int
   1231 estimate_eofb_HTM(DfsArg *arg)
   1232 {
   1233 	return ptableval(&pd_eofb_HTM, arg->cube);
   1234 }
   1235 
   1236 static int
   1237 estimate_coud_HTM(DfsArg *arg)
   1238 {
   1239 	return ptableval(&pd_coud_HTM, arg->cube);
   1240 }
   1241 
   1242 static int
   1243 estimate_coud_URF(DfsArg *arg)
   1244 {
   1245 	/* TODO: I can improve this by checking first the orientation of
   1246 	 * the corner in DBL and use that as a reference */
   1247 
   1248 	Cube c;
   1249 
   1250 	c = arg->cube;
   1251 
   1252 	int ud = estimate_coud_HTM(arg);
   1253 	arg->cube = apply_move(z, c);
   1254 	int rl = estimate_coud_HTM(arg);
   1255 	arg->cube = apply_move(x, c);
   1256 	int fb = estimate_coud_HTM(arg);
   1257 
   1258 	arg->cube = c;
   1259 
   1260 	return MIN(ud, MIN(rl, fb));
   1261 }
   1262 
   1263 static int
   1264 estimate_corners_HTM(DfsArg *arg)
   1265 {
   1266 	return ptableval(&pd_corners_HTM, arg->cube);
   1267 }
   1268 
   1269 static int
   1270 estimate_cornershtr_HTM(DfsArg *arg)
   1271 {
   1272 	return ptableval(&pd_cornershtr_HTM, arg->cube);
   1273 }
   1274 
   1275 static int
   1276 estimate_cornershtr_URF(DfsArg *arg)
   1277 {
   1278 	/* TODO: I can improve this by checking first the corner in DBL
   1279 	 * and use that as a reference */
   1280 
   1281 	int ret;
   1282 	Cube c;
   1283 	Trans i;
   1284 
   1285 	c = arg->cube;
   1286 	ret = 15;
   1287 
   1288 	for (i = 0; i < NROTATIONS; i++) {
   1289 		arg->cube = apply_alg(rotation_alg(i), c);
   1290 		ret = MIN(ret, estimate_cornershtr_HTM(arg));
   1291 	}
   1292 
   1293 	arg->cube = c;
   1294 
   1295 	return ret;
   1296 }
   1297 
   1298 static int
   1299 estimate_corners_URF(DfsArg *arg)
   1300 {
   1301 	/* TODO: I can improve this by checking first the corner in DBL
   1302 	 * and use that as a reference */
   1303 
   1304 	int ret;
   1305 	Cube c;
   1306 	Trans i;
   1307 
   1308 	c = arg->cube;
   1309 	ret = 15;
   1310 
   1311 	for (i = 0; i < NROTATIONS; i++) {
   1312 		arg->cube = apply_alg(rotation_alg(i), c);
   1313 		ret = MIN(ret, estimate_corners_HTM(arg));
   1314 	}
   1315 
   1316 	arg->cube = c;
   1317 
   1318 	return ret;
   1319 }
   1320 
   1321 static int
   1322 estimate_drud_HTM(DfsArg *arg)
   1323 {
   1324 	return ptableval(&pd_drud_sym16_HTM, arg->cube);
   1325 }
   1326 
   1327 static int
   1328 estimate_drud_eofb(DfsArg *arg)
   1329 {
   1330 	return ptableval(&pd_drud_eofb, arg->cube);
   1331 }
   1332 
   1333 static int
   1334 estimate_dr_eofb(DfsArg *arg)
   1335 {
   1336 	int r1, r2;
   1337 
   1338 	r1 = ptableval(&pd_drud_eofb, arg->cube);
   1339 	r2 = ptableval(&pd_drud_eofb, apply_trans(rf, arg->cube));
   1340 
   1341 	return MIN(r1, r2);
   1342 }
   1343 
   1344 static int
   1345 estimate_drudfin_drud(DfsArg *arg)
   1346 {
   1347 	int val = ptableval(&pd_drudfin_noE_sym16_drud, arg->cube);
   1348 
   1349 	if (val != 0)
   1350 		return val;
   1351 
   1352 	return arg->cube.epose % 24 == 0 ? 0 : 1;
   1353 }
   1354 
   1355 static int
   1356 estimate_drudslice_drud(DfsArg *arg)
   1357 {
   1358 	int i, ret = 20;
   1359 	Cube aux;
   1360 
   1361 	aux = arg->cube;
   1362 	for (i = 0; i < 4; i++, aux = apply_move(y, aux))
   1363 		ret = MIN(ret, ptableval(&pd_drudfin_noE_sym16_drud, aux));
   1364 
   1365 	return ret;
   1366 }
   1367 
   1368 static int
   1369 estimate_htr_drud(DfsArg *arg)
   1370 {
   1371 	return ptableval(&pd_htr_drud, arg->cube);
   1372 }
   1373 
   1374 static int
   1375 estimate_cp_drud(DfsArg *arg)
   1376 {
   1377 	return ptableval(&pd_cp_drud, arg->cube);
   1378 }
   1379 
   1380 static int
   1381 estimate_htrfin_htr(DfsArg *arg)
   1382 {
   1383 	return ptableval(&pd_htrfin_htr, arg->cube);
   1384 }
   1385 
   1386 static int
   1387 estimate_nxopt31_HTM(DfsArg *arg)
   1388 {
   1389 	return estimate_nxoptlike(arg, &pd_nxopt31_HTM);
   1390 }
   1391 
   1392 /* TODO: also use generic procedure for this */
   1393 static int
   1394 estimate_light_HTM(DfsArg *arg)
   1395 {
   1396 	int target, ret;
   1397 	Cube aux;
   1398 
   1399 	static const uint64_t udmask = (1<<U) | (1<<U2) | (1<<U3) |
   1400 				       (1<<D) | (1<<D2) | (1<<D3);
   1401 	static const uint64_t rlmask = (1<<R) | (1<<R2) | (1<<R3) |
   1402 				       (1<<L) | (1<<L2) | (1<<L3);
   1403 	static const uint64_t fbmask = (1<<F) | (1<<F2) | (1<<F3) |
   1404 				       (1<<B) | (1<<B2) | (1<<B3);
   1405 	static const uint64_t htmask = (1<<U2) | (1<<D2) |
   1406 				       (1<<R2) | (1<<L2) |
   1407 				       (1<<F2) | (1<<B2);
   1408 
   1409 	ret              = -1;
   1410 	target           = arg->d - arg->current_alg->len;
   1411 	arg->inverse     = (Cube){0};
   1412 	arg->badmovesinv = 0;
   1413 	arg->badmoves    = 0;
   1414 
   1415 	/* Corners */
   1416 	arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube);
   1417 	UPDATECHECKSTOP(ret, arg->ed->corners, target);
   1418 
   1419 	/* Normal probing */
   1420 	arg->ed->normal_ud = ptableval(&pd_drud_sym16_HTM, arg->cube);
   1421 	UPDATECHECKSTOP(ret, arg->ed->normal_ud, target);
   1422 	aux = apply_trans(fd, arg->cube);
   1423 	arg->ed->normal_fb = ptableval(&pd_drud_sym16_HTM, aux);
   1424 	UPDATECHECKSTOP(ret, arg->ed->normal_fb, target);
   1425 	aux = apply_trans(rf, arg->cube);
   1426 	arg->ed->normal_rl = ptableval(&pd_drud_sym16_HTM, aux);
   1427 	UPDATECHECKSTOP(ret, arg->ed->normal_rl, target);
   1428 
   1429 	/* If ret == 0, it's solved (corners + triple slice solved) */
   1430 	if (ret == 0)
   1431 		return is_solved(arg->cube) ? 0 : 1;
   1432 
   1433 	/* Michel de Bondt's trick*/
   1434 	if (arg->ed->normal_ud == arg->ed->normal_fb &&
   1435 	    arg->ed->normal_fb == arg->ed->normal_rl) {
   1436 		UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target);
   1437 	}
   1438 
   1439 	/* Inverse probing */
   1440 	if (!((1<<arg->last1) & htmask)) {
   1441 		aux = arg->inverse = inverse_cube(arg->cube);
   1442 		if (!((1<<arg->last1) & udmask) || (arg->ed->inverse_ud==-1)) {
   1443 			arg->ed->inverse_ud =
   1444 			    ptableval(&pd_drud_sym16_HTM, aux);
   1445 		}
   1446 		UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target);
   1447 		if (!((1<<arg->last1) & fbmask) || (arg->ed->inverse_fb==-1)) {
   1448 			aux = apply_trans(fd, arg->inverse);
   1449 			arg->ed->inverse_fb =
   1450 			    ptableval(&pd_drud_sym16_HTM, aux);
   1451 		}
   1452 		UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target);
   1453 		if (!((1<<arg->last1) & rlmask) || (arg->ed->inverse_rl==-1)) {
   1454 			aux = apply_trans(rf, arg->inverse);
   1455 			arg->ed->inverse_rl =
   1456 			    ptableval(&pd_drud_sym16_HTM, aux);
   1457 		}
   1458 		UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target);
   1459 	} else {
   1460 		UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target);
   1461 		UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target);
   1462 		UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target);
   1463 	}
   1464 
   1465 	/* Michel de Bondt's trick*/
   1466 	if (arg->ed->inverse_ud == arg->ed->inverse_fb &&
   1467 	    arg->ed->inverse_fb == arg->ed->inverse_rl) {
   1468 		UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target);
   1469 	}
   1470 
   1471 	/* nxopt trick + half turn trick */
   1472 	if (arg->ed->normal_ud == target)
   1473 		arg->badmovesinv |= udmask | htmask;
   1474 	if (arg->ed->normal_fb == target)
   1475 		arg->badmovesinv |= fbmask | htmask;
   1476 	if (arg->ed->normal_rl == target)
   1477 		arg->badmovesinv |= rlmask | htmask;
   1478 
   1479 	if (arg->ed->inverse_ud == target)
   1480 		arg->badmoves |= udmask | htmask;
   1481 	if (arg->ed->inverse_fb == target)
   1482 		arg->badmoves |= fbmask | htmask;
   1483 	if (arg->ed->inverse_rl == target)
   1484 		arg->badmoves |= rlmask | htmask;
   1485 
   1486 	return arg->ed->oldret = ret;
   1487 }
   1488 
   1489 static int
   1490 estimate_nxoptlike(DfsArg *arg, PruneData *pd)
   1491 {
   1492 	int target, ret;
   1493 	Cube aux;
   1494 
   1495 	static const uint64_t udmask = (1<<U) | (1<<U2) | (1<<U3) |
   1496 				       (1<<D) | (1<<D2) | (1<<D3);
   1497 	static const uint64_t rlmask = (1<<R) | (1<<R2) | (1<<R3) |
   1498 				       (1<<L) | (1<<L2) | (1<<L3);
   1499 	static const uint64_t fbmask = (1<<F) | (1<<F2) | (1<<F3) |
   1500 				       (1<<B) | (1<<B2) | (1<<B3);
   1501 
   1502 	ret              = -1;
   1503 	target           = arg->d - arg->current_alg->len;
   1504 	arg->inverse     = (Cube){0};
   1505 	arg->badmovesinv = 0;
   1506 	arg->badmoves    = 0;
   1507 
   1508 	/* Corners */
   1509 	arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube);
   1510 	UPDATECHECKSTOP(ret, arg->ed->corners, target);
   1511 
   1512 	/* Normal probing */
   1513 	arg->ed->normal_ud = ptableval(pd, arg->cube);
   1514 	UPDATECHECKSTOP(ret, arg->ed->normal_ud, target);
   1515 	aux = apply_trans(fd, arg->cube);
   1516 	arg->ed->normal_fb = ptableval(pd, aux);
   1517 	UPDATECHECKSTOP(ret, arg->ed->normal_fb, target);
   1518 	aux = apply_trans(rf, arg->cube);
   1519 	arg->ed->normal_rl = ptableval(pd, aux);
   1520 	UPDATECHECKSTOP(ret, arg->ed->normal_rl, target);
   1521 
   1522 	if (ret == 0)
   1523 		return arg->step->is_done(arg->cube) ? 0 : 1;
   1524 
   1525 	/* Michel de Bondt's trick*/
   1526 	if (arg->ed->normal_ud == arg->ed->normal_fb &&
   1527 	    arg->ed->normal_fb == arg->ed->normal_rl) {
   1528 		UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target);
   1529 	}
   1530 
   1531 	/* Inverse probing */
   1532 	aux = arg->inverse = inverse_cube(arg->cube);
   1533 	if (!((1<<arg->last1) & udmask) || (arg->ed->inverse_ud == -1)) {
   1534 		arg->ed->inverse_ud = ptableval(pd, aux);
   1535 	}
   1536 	UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target);
   1537 	if (!((1<<arg->last1) & fbmask) || (arg->ed->inverse_fb == -1)) {
   1538 		aux = apply_trans(fd, arg->inverse);
   1539 		arg->ed->inverse_fb = ptableval(pd, aux);
   1540 	}
   1541 	UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target);
   1542 	if (!((1<<arg->last1) & rlmask) || (arg->ed->inverse_rl == -1)) {
   1543 		aux = apply_trans(rf, arg->inverse);
   1544 		arg->ed->inverse_rl = ptableval(pd, aux);
   1545 	}
   1546 	UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target);
   1547 
   1548 	/* Michel de Bondt's trick*/
   1549 	if (arg->ed->inverse_ud == arg->ed->inverse_fb &&
   1550 	    arg->ed->inverse_fb == arg->ed->inverse_rl) {
   1551 		UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target);
   1552 	}
   1553 
   1554 	/* nxopt trick */
   1555 	if (arg->ed->normal_ud == target)
   1556 		arg->badmovesinv |= udmask;
   1557 	if (arg->ed->normal_fb == target)
   1558 		arg->badmovesinv |= fbmask;
   1559 	if (arg->ed->normal_rl == target)
   1560 		arg->badmovesinv |= rlmask;
   1561 
   1562 	if (arg->ed->inverse_ud == target)
   1563 		arg->badmoves |= udmask;
   1564 	if (arg->ed->inverse_fb == target)
   1565 		arg->badmoves |= fbmask;
   1566 	if (arg->ed->inverse_rl == target)
   1567 		arg->badmoves |= rlmask;
   1568 
   1569 	return arg->ed->oldret = ret;
   1570 }
   1571 
   1572 static bool
   1573 always_valid(Alg *alg)
   1574 {
   1575 	return true;
   1576 }
   1577 
   1578 static bool
   1579 validate_singlecw_ending(Alg *alg)
   1580 {
   1581 	int i;
   1582 	bool nor, inv;
   1583 	Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE;
   1584 
   1585 	for (i = 0; i < alg->len; i++) {
   1586 		if (alg->inv[i]) {
   1587 			l2i = l1i;
   1588 			l1i = alg->move[i];
   1589 		} else {
   1590 			l2 = l1;
   1591 			l1 = alg->move[i];
   1592 		}
   1593 	}
   1594 
   1595 	nor = l1 ==base_move(l1)  && (!commute(l1, l2) ||l2 ==base_move(l2));
   1596 	inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i));
   1597 
   1598 	return nor && inv;
   1599 }
   1600 
   1601 static bool
   1602 validate_htr(Alg *alg)
   1603 {
   1604 	int i, lastqt_n, lastqt_i;
   1605 	Move m, b;
   1606 
   1607 	if (!validate_singlecw_ending(alg))
   1608 		return false;
   1609 
   1610 	lastqt_n = lastqt_i = -1;
   1611 	for (i = 0; i < alg->len; i++) {
   1612 		m = alg->move[i];
   1613 		b = base_move(m);
   1614 		if (m == b+1)
   1615 			continue;
   1616 		if (alg->inv[i] && lastqt_i == -1)
   1617 			lastqt_i = i;
   1618 		if (!alg->inv[i])
   1619 			lastqt_n = i;
   1620 	}
   1621 
   1622 	for (i = 0; i < alg->len; i++)
   1623 		if (base_move(alg->move[i]) == D &&
   1624 		    i != lastqt_i && i != lastqt_n)
   1625 			return false;
   1626 
   1627 	return true;
   1628 }
   1629 
   1630 /* Pre-transformation detectors **********************************************/
   1631 
   1632 static int
   1633 detect_pretrans_eofb(Cube cube, Trans *ret)
   1634 {
   1635 	int i, n;
   1636 	static Trans tt[3] = {uf, ur, fd};
   1637 
   1638 	for (i = 0, n = 0; i < 3; i++)
   1639 		if (check_eofb(apply_trans(tt[i], cube)))
   1640 			ret[n++] = tt[i];
   1641 
   1642 	return n;
   1643 }
   1644 
   1645 static int
   1646 detect_pretrans_drud(Cube cube, Trans *ret)
   1647 {
   1648 	int i, n;
   1649 	static Trans tt[3] = {uf, fr, rd};
   1650 
   1651 	for (i = 0, n = 0; i < 3; i++)
   1652 		if (check_drud(apply_trans(tt[i], cube)))
   1653 			ret[n++] = tt[i];
   1654 
   1655 	return n;
   1656 }
   1657 
   1658 static int
   1659 detect_pretrans_void_3axis(Cube cube, Trans *ret)
   1660 {
   1661 	ret[0] = uf;
   1662 	ret[1] = fr;
   1663 	ret[2] = rd;
   1664 
   1665 	return 3;
   1666 }
   1667 
   1668 /* Public functions **********************************************************/
   1669 
   1670 void
   1671 copy_estimatedata(EstimateData *src, EstimateData *dst)
   1672 {
   1673 	dst->corners    = src->corners;
   1674 	dst->normal_ud  = src->normal_ud;
   1675 	dst->normal_fb  = src->normal_fb;
   1676 	dst->normal_rl  = src->normal_rl;
   1677 	dst->inverse_ud = src->inverse_ud;
   1678 	dst->inverse_fb = src->inverse_fb;
   1679 	dst->inverse_rl = src->inverse_rl;
   1680 	dst->oldret     = src->oldret;
   1681 }
   1682 
   1683 void
   1684 invert_estimatedata(EstimateData *ed)
   1685 {
   1686 	swap(&(ed->normal_ud), &(ed->inverse_ud));
   1687 	swap(&(ed->normal_fb), &(ed->inverse_fb));
   1688 	swap(&(ed->normal_rl), &(ed->inverse_rl));
   1689 }
   1690 
   1691 void
   1692 reset_estimatedata(EstimateData *ed)
   1693 {
   1694 	ed->corners    = -1;
   1695 	ed->normal_ud  = -1;
   1696 	ed->normal_fb  = -1;
   1697 	ed->normal_rl  = -1;
   1698 	ed->inverse_ud = -1;
   1699 	ed->inverse_fb = -1;
   1700 	ed->inverse_rl = -1;
   1701 	ed->oldret     = -1;
   1702 }
   1703 
   1704 void
   1705 prepare_step(Step *step, SolveOptions *opts)
   1706 {
   1707 	int i;
   1708 
   1709 	if (step->final && opts->nisstype != NORMAL) {
   1710 		opts->nisstype = NORMAL;
   1711 		fprintf(stderr, "Step is final, NISS not used"
   1712 				" (-N and -L ignored)\n");
   1713 	}
   1714 
   1715 	for (i = 0; i < step->ntables; i++) {
   1716 		genptable(step->tables[i], opts->nthreads);
   1717 		if (step->tables[i]->compact)
   1718 			genptable(step->tables[i]->fallback, opts->nthreads);
   1719 	}
   1720 }