From e889d5536b4a4d743f99a5b5fe1ece37b4af088e Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 20 Aug 2008 20:23:19 +0000 Subject: [PATCH] - introduce Michael Reid's optimal solver code in its original state (a.out, no work on cpushare integration here) - introduce rubikutils, basicaly MR's structures and cube functions, but adding cube orientation to the cube structure - rubikutils' main() inputs and validate a cube with center faces. - input order is: F R U B L D UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/research@2739 92316355-f0b4-4df1-b90c-862c8a59935f --- 2008-rubik/rubikutils/rubik.c | 640 ++++ 2008-rubik/solver/optimal/README | 136 + 2008-rubik/solver/optimal/optimal.c | 4316 +++++++++++++++++++++++++++ 3 files changed, 5092 insertions(+) create mode 100644 2008-rubik/rubikutils/rubik.c create mode 100644 2008-rubik/solver/optimal/README create mode 100644 2008-rubik/solver/optimal/optimal.c diff --git a/2008-rubik/rubikutils/rubik.c b/2008-rubik/rubikutils/rubik.c new file mode 100644 index 0000000..5c5e98c --- /dev/null +++ b/2008-rubik/rubikutils/rubik.c @@ -0,0 +1,640 @@ +#include +#include + +#define MAX_CHECK_PERM_N 24 + +#define CORNER_UFR 0 +#define CORNER_URB 1 +#define CORNER_UBL 2 +#define CORNER_ULF 3 +#define CORNER_DRF 4 +#define CORNER_DFL 5 +#define CORNER_DLB 6 +#define CORNER_DBR 7 + +#define CORNER_FRU 8 +#define CORNER_RBU 9 +#define CORNER_BLU 10 +#define CORNER_LFU 11 +#define CORNER_RFD 12 +#define CORNER_FLD 13 +#define CORNER_LBD 14 +#define CORNER_BRD 15 + +#define CORNER_RUF 16 +#define CORNER_BUR 17 +#define CORNER_LUB 18 +#define CORNER_FUL 19 +#define CORNER_FDR 20 +#define CORNER_LDF 21 +#define CORNER_BDL 22 +#define CORNER_RDB 23 + + +#define EDGE_UF 0 +#define EDGE_UR 1 +#define EDGE_UB 2 +#define EDGE_UL 3 +#define EDGE_DF 4 +#define EDGE_DR 5 +#define EDGE_DB 6 +#define EDGE_DL 7 +#define EDGE_FR 8 +#define EDGE_FL 9 +#define EDGE_BR 10 +#define EDGE_BL 11 + +#define EDGE_FU 12 +#define EDGE_RU 13 +#define EDGE_BU 14 +#define EDGE_LU 15 +#define EDGE_FD 16 +#define EDGE_RD 17 +#define EDGE_BD 18 +#define EDGE_LD 19 +#define EDGE_RF 20 +#define EDGE_LF 21 +#define EDGE_RB 22 +#define EDGE_LB 23 + +#define FACE_F 0 +#define FACE_R 1 +#define FACE_U 2 +#define FACE_B 3 +#define FACE_L 4 +#define FACE_D 5 + + +typedef struct cube + { + int centers[6]; + int edges[24]; + int corners[24]; + } + Cube; + + +static char *center_cubie_str[] = {"F", "R", "U", + "B", "L", "D"}; + +static char *edge_cubie_str[] = {"UF", "UR", "UB", "UL", + "DF", "DR", "DB", "DL", + "FR", "FL", "BR", "BL", + "FU", "RU", "BU", "LU", + "FD", "RD", "BD", "LD", + "RF", "LF", "RB", "LB"}; + +static char *corner_cubie_str[] = {"UFR", "URB", "UBL", "ULF", + "DRF", "DFL", "DLB", "DBR", + "FRU", "RBU", "BLU", "LFU", + "RFD", "FLD", "LBD", "BRD", + "RUF", "BUR", "LUB", "FUL", + "FDR", "LDF", "BDL", "RDB"}; + +/* ========================================================================= */ + void two_cycle(int array[], int ind0, int ind1) +/* ------------------------------------------------------------------------- */ + +{ +int temp; + + +temp = array[ind0]; +array[ind0] = array[ind1]; +array[ind1] = temp; + +return; +} + + +/* ========================================================================= */ + void three_cycle(int array[], int ind0, int ind1, int ind2) +/* ------------------------------------------------------------------------- */ + +{ +int temp; + + +temp = array[ind0]; +array[ind0] = array[ind1]; +array[ind1] = array[ind2]; +array[ind2] = temp; + +return; +} + + +/* ========================================================================= */ + void four_cycle(int array[], int ind0, int ind1, int ind2, int ind3) +/* ------------------------------------------------------------------------- */ + +{ +int temp; + + +temp = array[ind0]; +array[ind0] = array[ind1]; +array[ind1] = array[ind2]; +array[ind2] = array[ind3]; +array[ind3] = temp; + +return; +} + + +/* ========================================================================= */ + void print_cube(Cube *p_cube) +/* ------------------------------------------------------------------------- */ + +{ +printf("%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n", + center_cubie_str[p_cube->centers[0]], center_cubie_str[p_cube->centers[1]], + center_cubie_str[p_cube->centers[2]], center_cubie_str[p_cube->centers[3]], + center_cubie_str[p_cube->centers[4]], center_cubie_str[p_cube->centers[5]], + edge_cubie_str[p_cube->edges[0]], edge_cubie_str[p_cube->edges[1]], + edge_cubie_str[p_cube->edges[2]], edge_cubie_str[p_cube->edges[3]], + edge_cubie_str[p_cube->edges[4]], edge_cubie_str[p_cube->edges[5]], + edge_cubie_str[p_cube->edges[6]], edge_cubie_str[p_cube->edges[7]], + edge_cubie_str[p_cube->edges[8]], edge_cubie_str[p_cube->edges[9]], + edge_cubie_str[p_cube->edges[10]], edge_cubie_str[p_cube->edges[11]], + corner_cubie_str[p_cube->corners[0]], corner_cubie_str[p_cube->corners[1]], + corner_cubie_str[p_cube->corners[2]], corner_cubie_str[p_cube->corners[3]], + corner_cubie_str[p_cube->corners[4]], corner_cubie_str[p_cube->corners[5]], + corner_cubie_str[p_cube->corners[6]], corner_cubie_str[p_cube->corners[7]]); + +return; +} + +/* ========================================================================= */ + void perm_n_init(int nn, int array_out[]) +/* ------------------------------------------------------------------------- */ + +{ +int ii; + + +for (ii = 0; ii < nn; ii++) + array_out[ii] = ii; + +return; +} + + +/* ========================================================================= */ + void cube_init(Cube *p_cube) +/* ------------------------------------------------------------------------- */ + +{ +perm_n_init(6, p_cube->centers); +perm_n_init(24, p_cube->edges); +perm_n_init(24, p_cube->corners); + +return; +} + +/* ========================================================================= */ + int cube_compare(Cube *cube0, Cube *cube1) +/* ------------------------------------------------------------------------- */ + +{ +int ii; + +for (ii = 0; ii < 6; ii++) + { + if (cube0->centers[ii] < cube1->centers[ii]) + return -1; + else if (cube0->centers[ii] > cube1->centers[ii]) + return 1; + } + +for (ii = 0; ii < 24; ii++) + { + if (cube0->edges[ii] < cube1->edges[ii]) + return -1; + else if (cube0->edges[ii] > cube1->edges[ii]) + return 1; + } + +for (ii = 0; ii < 24; ii++) + { + if (cube0->corners[ii] < cube1->corners[ii]) + return -1; + else if (cube0->corners[ii] > cube1->corners[ii]) + return 1; + } + +return 0; +} + +#if 0 +/* ========================================================================= */ + void cube_compose(Cube *in_cube0, Cube *in_cube1, Cube *out_cube) +/* ------------------------------------------------------------------------- */ + +{ +perm_n_compose(6, in_cube0->centers, in_cube1->centers, out_cube->centers); +perm_n_compose(24, in_cube0->edges, in_cube1->edges, out_cube->edges); +perm_n_compose(24, in_cube0->corners, in_cube1->corners, out_cube->corners); + +return; +} +#endif + +/* ========================================================================= */ + int perm_n_check(int nn, int array_in[]) +/* ------------------------------------------------------------------------- */ + +{ +int count[MAX_CHECK_PERM_N], ii; + + +for (ii = 0; ii < nn; ii++) + count[ii] = 0; + +for (ii = 0; ii < nn; ii++) + { + if ((array_in[ii] < 0) || (array_in[ii] >= nn)) + return 1; + + count[array_in[ii]]++; + } + +for (ii = 0; ii < nn; ii++) + if (count[ii] != 1) + return 1; + +return 0; +} + +/* ========================================================================= */ + int perm_n_parity(int nn, int array_in[]) +/* ------------------------------------------------------------------------- */ + +{ +int temp_array[MAX_CHECK_PERM_N]; +int ii, jj, n_cycles; + + +for (ii = 0; ii < nn; ii++) + temp_array[ii] = 0; + +n_cycles = 0; + +for (ii = 0; ii < nn; ii++) + if (temp_array[ii] == 0) + { + n_cycles++; + jj = ii; + while (temp_array[jj] == 0) + { + temp_array[jj] = 1; + jj = array_in[jj]; + } + } + +return (n_cycles + nn) % 2; +} + + + +/* ========================================================================= */ + int centers_check(int array_in[]) +/* return -1 if invalid, 0 if even cube configuration, 1 for odd */ +/* ------------------------------------------------------------------------- */ + +{ + int parity = 0; + int i; + + int clone[6]; + for(i = 0; i < 6; i++) + clone[i] = array_in[i]; + + // put FACE_UP upwards + for (i = 0; i<6; i++) + if(clone[i] == FACE_U) + break; + + switch(i) { + case FACE_U: + break; + case FACE_F: + four_cycle(clone, FACE_U, FACE_F, FACE_D, FACE_B); + parity++; + break; + case FACE_L: + four_cycle(clone, FACE_U, FACE_L, FACE_D, FACE_R); + parity++; + break; + case FACE_R: + four_cycle(clone, FACE_U, FACE_R, FACE_D, FACE_L); + parity++; + break; + case FACE_B: + four_cycle(clone, FACE_U, FACE_B, FACE_D, FACE_F); + parity++; + break; + case FACE_D: + two_cycle(clone, FACE_U, FACE_D); + two_cycle(clone, FACE_F, FACE_B); + break; + case 6: + return -1; + } + + // now put FACE_FRONT in place + for (i = 0; i<6; i++) + if(clone[i] == FACE_F) + break; + switch(i) { + case FACE_F: + break; + case FACE_L: + four_cycle(clone, FACE_F, FACE_L, FACE_B, FACE_R); + parity++; + break; + case FACE_R: + four_cycle(clone, FACE_F, FACE_R, FACE_B, FACE_L); + parity++; + break; + case FACE_B: + two_cycle(clone, FACE_F, FACE_B); + two_cycle(clone, FACE_L, FACE_R); + break; + case FACE_U: // this is not possible + case FACE_D: + case 6: + return -1; + } + + if(clone[FACE_R] != FACE_R || clone[FACE_L] != FACE_L + || clone[FACE_B] != FACE_B || clone[FACE_D] != FACE_D) + return -1; + + return parity & 1; +} + +/* ========================================================================= */ + int string_to_cube(char string[], Cube *p_cube, int give_err_msg) +/* ------------------------------------------------------------------------- */ + +/* input: string[] */ + +{ +char center_str[6][2], edge_str[12][3], corner_str[8][4]; +int center_arr[6], edge_arr[12], corner_arr[8]; +int ii, jj, twist, flip, edge_par, corner_par, center_par; +int stat; + + +stat = 0; + +if (sscanf(string, "%1s %1s %1s %1s %1s %1s %2s %2s %2s %2s %2s %2s %2s %2s %2s %2s %2s %2s %3s %3s %3s %3s %3s %3s %3s %3s", + center_str[0], center_str[1], center_str[2], + center_str[3], center_str[4], center_str[5], + edge_str[0], edge_str[1], edge_str[2], edge_str[3], + edge_str[4], edge_str[5], edge_str[6], edge_str[7], + edge_str[8], edge_str[9], edge_str[10], edge_str[11], + corner_str[0], corner_str[1], corner_str[2], corner_str[3], + corner_str[4], corner_str[5], corner_str[6], corner_str[7]) < 20) + { + if (give_err_msg) + printf("invalid input!\n"); + return 1; + } + +for (ii = 0; ii < 6 ; ii++) + { + for (jj = 0; jj < 6; jj++) + if(strcmp(center_str[ii], center_cubie_str[jj]) == 0) + { + p_cube->centers[ii] = jj; + break; + } + if(jj == 6) + { + if (give_err_msg) + printf("invalid center cubie: %s\n", center_str[ii]); + stat = 1; + } + } + +for (ii = 0; ii < 12; ii++) + { + for (jj = 0; jj < 24; jj++) + if (strcmp(edge_str[ii], edge_cubie_str[jj]) == 0) + { + p_cube->edges[ii] = jj; + break; + } + if (jj == 24) + { + if (give_err_msg) + printf("invalid edge cubie: %s\n", edge_str[ii]); + stat = 1; + } + } + +for (ii = 0; ii < 8; ii++) + { + for (jj = 0; jj < 24; jj++) + if (strcmp(corner_str[ii], corner_cubie_str[jj]) == 0) + { + p_cube->corners[ii] = jj; + break; + } + if (jj == 24) + { + if (give_err_msg) + printf("invalid corner cubie: %s\n", corner_str[ii]); + stat = 1; + } + } + +if (stat) + return stat; + +/* fill out the remaining oriented edges and corners */ + +for (ii = 12; ii < 24; ii++) + p_cube->edges[ii] = (12 + p_cube->edges[ii - 12]) % 24; + +for (ii = 8; ii < 24; ii++) + p_cube->corners[ii] = (8 + p_cube->corners[ii - 8]) % 24; + +/* now check to see that it's a legal cube */ + +center_par = centers_check(p_cube->centers); +if (center_par == -1) + { + if (give_err_msg) + printf("bad center cubies\n"); + stat = 1; + } + +if (perm_n_check(24, p_cube->edges)) + { + if (give_err_msg) + printf("bad edge cubies\n"); + stat = 1; + } + +if (perm_n_check(24, p_cube->corners)) + { + if (give_err_msg) + printf("bad corner cubies\n"); + stat = 1; + } + +if (stat) + return stat; + +flip = 0; +for (ii = 0; ii < 12; ii++) + flip += (p_cube->edges[ii] / 12); + +if ((flip % 2) != 0) + { + if (give_err_msg) + printf("flip any edge cubie!\n"); + stat = 1; + } + +twist = 0; +for (ii = 0; ii < 8; ii++) + twist += (p_cube->corners[ii] / 8); + +twist %= 3; + +if (twist != 0) + { + if (give_err_msg) + printf("twist any corner cubie %sclockwise!\n", + (twist == 1) ? "counter" : ""); + stat = 1; + } + +for (ii = 0; ii < 12; ii++) + edge_arr[ii] = p_cube->edges[ii] % 12; + +edge_par = perm_n_parity(12, edge_arr); + +for (ii = 0; ii < 8; ii++) + corner_arr[ii] = p_cube->corners[ii] % 8; + +corner_par = perm_n_parity(8, corner_arr); + +if (((edge_par + corner_par + center_par) & 1) == 1) + { + if (give_err_msg) + printf("swap any two edge cubies or any two corner cubies!\n"); + stat = 1; + } + +return stat; +} + + +/* ========================================================================= */ + int user_enters_cube(Cube *p_cube) +/* ------------------------------------------------------------------------- */ + +{ +char line_str[256]; + + +printf("\nenter cube (Ctrl-D to exit):\n"); + +line_str[0] = '\n'; + +while (line_str[0] == '\n') /* ignore blank lines */ + { + if (fgets(line_str, 256, stdin) == NULL) + return -1; + + if (line_str[0] == '%') /* echo comments */ + { + printf("%s", line_str); + line_str[0] = '\n'; + } + } + +return string_to_cube(line_str, p_cube, 1); +} + + + +/* ========================================================================= */ + void pretty_print_unsigned_int(unsigned int nn) +/* ------------------------------------------------------------------------- */ + +{ +int digits[4], ii, started; + + +for (ii = 0; ii < 4; ii++) + { + digits[ii] = nn % 1000; + nn /= 1000; + } + +started = 0; + +for (ii = 3; ii >= 0; ii--) + { + if (started) + { + if (digits[ii] >= 100) + printf("%3d", digits[ii]); + else if (digits[ii] >= 10) + printf("0%2d", digits[ii]); + else + printf("00%1d", digits[ii]); + } + else + { + if (digits[ii] >= 100) + { + printf("%3d", digits[ii]); + started = 1; + } + else if (digits[ii] >= 10) + { + printf(" %2d", digits[ii]); + started = 1; + } + else if ((digits[ii] >= 1) || (ii == 0)) + { + printf(" %1d", digits[ii]); + started = 1; + } + else + printf(" "); + } + + if (ii > 0) + printf("%c", started ? ',' : ' '); + } + +return; +} + + +/* ========================================================================= */ + int main(void) +/* ------------------------------------------------------------------------- */ + +{ +Cube cube_struct; +int stat; + +while (1) + { + stat = user_enters_cube(&cube_struct); + if (stat < 0) + break; + } +exit(EXIT_SUCCESS); + +return 0; /* haha */ +} diff --git a/2008-rubik/solver/optimal/README b/2008-rubik/solver/optimal/README new file mode 100644 index 0000000..2c351b3 --- /dev/null +++ b/2008-rubik/solver/optimal/README @@ -0,0 +1,136 @@ +README file for optimal Rubik's cube solver + + +1. Preliminaries. + +After you gunzip and untar the file you should have (besides the +tar file) three files: + + % ls -l + -rw------- 1 501 100 4629 2004-06-03 00:05 README + -rw------- 1 501 100 133158 2004-06-03 00:05 optimal.c + -rw------- 1 501 100 20552 2004-06-03 00:05 twist.c + +README is the file you are presently examining. optimal.c is the +source code for the optimal solver. twist.c is the source code to +a related utility (see below). + + +2. System requirements + +At least 80Mb RAM for the optimal cube solver. With less than 80Mb +it probably won't run at any reasonable speed. I'm not even sure it +will run well with 80Mb, so 88Mb or 96Mb is preferred. + +If you get it running on your system, I would appreciate if you let me +know, so that I know it works on that type of system. Please send me +e-mail to let me know that you have it working!! + +The program was developed on a Linux system, but should use only +ANSI standard C. + + +3. Compiling the optimal solver + +The source file is optimal.c . It is presently configured to search by +quarter turns. If you want to search by face turns, change line #5 to + + #define USE_METRIC FACE_TURN_METRIC + +You can also change the value of SEARCH_LIMIT if you desire. +This will limit how far the program searches. The default value of 0 +means no limit. + +My preferred method of compilation is + + % gcc -Wall -O2 optimal.c + +but feel free to use something else. + + +4. Startup time + +Startup time is significant. On my processor (200 MHz PentiumPro), it +takes about 11 minutes to generate all the tables. While it's working +on this, be sure to read the next section about input format. + +This is greatly reduced on newer computers. On a 933MHz P3, it should +only take 2 or 3 minutes. + + +5. Input to the optimal solver + +A solved cube is represented as + + UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR + +To input a scrambled cube, first give the cubie that's in the UF location, +then the cubie in the UR location, and so forth, according to this list +above. For example, "cube in a cube" would be + + UF UR RD RB LU LF DB DL FR UB DF BL UFR RFD RDB RBU LFU LUB DLB LDF + +This input should all be on one line. Some people have expressed their +displeasure with this system. I can't say I disagree, but I can't think +of any system that's easy. So your ideas here would be useful. Read on +to the next section about using "twist.c" to convert a sequence of twists +into a cube in the desired format. + +Sequences that are produced as output solve the cube from the input state. + +You may also interrupt a search by typing Ctrl-C . Instead of exiting, +it will prompt you for another cube. (To exit, type Ctrl-D .) + + +6. Using "twist.c" + +This is just a hack. Input to this program is a sequence of twists, all +on one line. It outputs two cubes, the position created by applying the +sequence to a solved cube, and the inverse position. The twists should +be in the form F F2 F' etc. this program doesn't require any +optimization. I compile it using + + % gcc -o twist.out -Wall twist.c + + +7. Miscellaneous + +The number of nodes overflows on long searches. With gcc this can be +fixed by changing the global variable n_nodes to type long long int. + + +8. To do list + + a. Experiment with other "pattern databases." + b. Perhaps unroll subfunctions in initialize_distance_table + to reduce startup time. + c. Consider solving the inverse position if this is a little + bit easier + + +9. Changes since last version + +The main change is that I have implemented automatic symmetry reductions. +This means that the program will analyze the symmetry of the input +position, and use this to reduce the search space. If you input a +position with 12-fold symmetry, it will run 12 times as fast. +This feature is turned on by default. You can turn it off by #define-ing +the symbol USE_SYMMETRY to 0 . + +Some other minor things: fixed a bug in twist.c when there's white +space at the end of the input line. I also reverted to new-style +function declarations. And the program should run fine without needing +excess stack space. + + +10. Feedback + +e-mail me with any questions, comments, etc. at reid@math.ucf.edu . +Currently, there is a pointer to the files on the web page + + http://www.math.ucf.edu/~reid/Rubik/optimal_solver.html + +Good luck, and enjoy the program. If you make any interesting discoveries +with the program, please share them with me and the cube-lovers mailing list. + +June 3, 2004 diff --git a/2008-rubik/solver/optimal/optimal.c b/2008-rubik/solver/optimal/optimal.c new file mode 100644 index 0000000..e9073ef --- /dev/null +++ b/2008-rubik/solver/optimal/optimal.c @@ -0,0 +1,4316 @@ +/* optimal cube solver by michael reid reid@math.ucf.edu */ +/* version 2.1 june 3, 2004 */ +/* symmetry mechanism added */ +/* malloc.h removed, long string fixed */ + + +#define USE_METRIC QUARTER_TURN_METRIC +#define SEARCH_LIMIT 0 +#define USE_SYMMETRY 1 +#define ONE_SOLUTION_ONLY 0 + + +#include +#include +#include +#include +#include + + +#define QUARTER_TURN_METRIC 0 +#define FACE_TURN_METRIC 1 + +#define N_SYM 16 +#define N_TWIST 18 +#define N_CORNER 2187 +#define N_ELOC 495 +#define N_ELOC_CONV 4096 +#define N_EFLIP 2048 +#define N_FULLEDGE (N_ELOC * N_EFLIP) +#define N_EDGEQUOT 64430 +#define N_CORNERPERM 40320 +#define N_SLICEEDGE 11880 + +#define N_CUBESYM 48 +#define N_SYMSUBGRP 98 +#define SUBGRP_TRIVIAL 97 + +#define N_DIST_CHARS ((N_EDGEQUOT * N_CORNER) / 2) +#define BACKWARDS_SWITCH_POINT ((2 * N_EDGEQUOT * N_CORNER) / 5) + +#define CORNER_START 0 +#define EDGE_START 64244 +#define CORNERPERM_START 0 +#define UD_SLICEEDGE_START 494 +#define RL_SLICEEDGE_START 54 +#define FB_SLICEEDGE_START 209 + +#define MAX_PERM_N 12 +#define MAX_CHECK_PERM_N 24 + +#define MAX_TWISTS 43 + +#define TWIST_F 0 +#define TWIST_F2 1 +#define TWIST_F3 2 +#define TWIST_R 3 +#define TWIST_R2 4 +#define TWIST_R3 5 +#define TWIST_U 6 +#define TWIST_U2 7 +#define TWIST_U3 8 +#define TWIST_B 9 +#define TWIST_B2 10 +#define TWIST_B3 11 +#define TWIST_L 12 +#define TWIST_L2 13 +#define TWIST_L3 14 +#define TWIST_D 15 +#define TWIST_D2 16 +#define TWIST_D3 17 + +#define CORNER_UFR 0 +#define CORNER_URB 1 +#define CORNER_UBL 2 +#define CORNER_ULF 3 +#define CORNER_DRF 4 +#define CORNER_DFL 5 +#define CORNER_DLB 6 +#define CORNER_DBR 7 + +#define CORNER_FRU 8 +#define CORNER_RBU 9 +#define CORNER_BLU 10 +#define CORNER_LFU 11 +#define CORNER_RFD 12 +#define CORNER_FLD 13 +#define CORNER_LBD 14 +#define CORNER_BRD 15 + +#define CORNER_RUF 16 +#define CORNER_BUR 17 +#define CORNER_LUB 18 +#define CORNER_FUL 19 +#define CORNER_FDR 20 +#define CORNER_LDF 21 +#define CORNER_BDL 22 +#define CORNER_RDB 23 + + +#define EDGE_UF 0 +#define EDGE_UR 1 +#define EDGE_UB 2 +#define EDGE_UL 3 +#define EDGE_DF 4 +#define EDGE_DR 5 +#define EDGE_DB 6 +#define EDGE_DL 7 +#define EDGE_FR 8 +#define EDGE_FL 9 +#define EDGE_BR 10 +#define EDGE_BL 11 + +#define EDGE_FU 12 +#define EDGE_RU 13 +#define EDGE_BU 14 +#define EDGE_LU 15 +#define EDGE_FD 16 +#define EDGE_RD 17 +#define EDGE_BD 18 +#define EDGE_LD 19 +#define EDGE_RF 20 +#define EDGE_LF 21 +#define EDGE_RB 22 +#define EDGE_LB 23 + + +#define FACE_F 0 +#define FACE_R 1 +#define FACE_U 2 +#define FACE_B 3 +#define FACE_L 4 +#define FACE_D 5 + + +#define N_FOLLOW 873 + +#define FOLLOW_INVALID 0 + +#define N_SYLLABLE 32 + +#define SYLLABLE_INVALID 0 +#define SYLLABLE_NONE 1 +#define SYLLABLE_F 2 +#define SYLLABLE_F2 3 +#define SYLLABLE_F3 4 +#define SYLLABLE_R 5 +#define SYLLABLE_R2 6 +#define SYLLABLE_R3 7 +#define SYLLABLE_U 8 +#define SYLLABLE_U2 9 +#define SYLLABLE_U3 10 +#define SYLLABLE_B 11 +#define SYLLABLE_B2 12 +#define SYLLABLE_B3 13 +#define SYLLABLE_L 14 +#define SYLLABLE_L2 15 +#define SYLLABLE_L3 16 +#define SYLLABLE_D 17 +#define SYLLABLE_D2 18 +#define SYLLABLE_D3 19 +#define SYLLABLE_FB 20 +#define SYLLABLE_FB2 21 +#define SYLLABLE_FB3 22 +#define SYLLABLE_F2B2 23 +#define SYLLABLE_RL 24 +#define SYLLABLE_RL2 25 +#define SYLLABLE_RL3 26 +#define SYLLABLE_R2L2 27 +#define SYLLABLE_UD 28 +#define SYLLABLE_UD2 29 +#define SYLLABLE_UD3 30 +#define SYLLABLE_U2D2 31 + + + +#define DIST(c, e) (((e) & 0x1) ? (((int)distance[c][(e) >> 1]) >> 4) \ + : (((int)distance[c][(e) >> 1]) & 0xF)) + + +typedef struct cube + { + int edges[24]; + int corners[24]; + } + Cube; + + +typedef struct coset_coord + { + int corner_state; + int edge_state; + int sym_state; + } + Coset_coord; + + +typedef struct full_cube + { + Cube cubies; + int cornerperm; + int ud_sliceedge; + int rl_sliceedge; + int fb_sliceedge; + Coset_coord ud; + Coset_coord rl; + Coset_coord fb; + int parity; + int sym_subgrp; + } + Full_cube; + + +typedef struct search_data + { + int depth; + int found; + int found_quot; + int *multiplicities; + int *stabilizers; + } + Search_data; + + +typedef struct search_node + { + int remain_depth; + int twist; + int follow_type; + Coset_coord ud; + Coset_coord rl; + Coset_coord fb; + } + Search_node; + + +typedef struct metric_data + { + int metric; + char metric_char; + int twist_length[N_TWIST]; + int increment; + } + Metric_data; + + +typedef struct options + { + int use_symmetry; + int search_limit; + int one_solution_only; + } + Options; + + +typedef struct subgroup_list + { + int n_subgroups; + int (*subgroups)[N_CUBESYM]; + } + Subgroup_list; + + + +static unsigned char *sym_x_invsym_to_sym[N_SYM]; + +static unsigned char *invsym_on_twist_ud[N_SYM]; +static unsigned char *invsym_on_twist_rl[N_SYM]; +static unsigned char *invsym_on_twist_fb[N_SYM]; + +static unsigned short *twist_on_corner[N_TWIST]; +static unsigned short *sym_on_corner[N_SYM]; + +static unsigned short *fulledge_to_edge; +static unsigned char *fulledge_to_sym; + +static unsigned short *twist_on_edge[N_TWIST]; +static unsigned char *twist_x_edge_to_sym[N_TWIST]; + +static unsigned short *twist_on_cornerperm[N_TWIST]; +static unsigned short *twist_on_sliceedge[N_TWIST]; + +static unsigned short *twist_on_follow[N_TWIST]; + +static unsigned char *distance[N_CORNER]; + +static char *edge_cubie_str[] = {"UF", "UR", "UB", "UL", + "DF", "DR", "DB", "DL", + "FR", "FL", "BR", "BL", + "FU", "RU", "BU", "LU", + "FD", "RD", "BD", "LD", + "RF", "LF", "RB", "LB"}; + +static char *corner_cubie_str[] = {"UFR", "URB", "UBL", "ULF", + "DRF", "DFL", "DLB", "DBR", + "FRU", "RBU", "BLU", "LFU", + "RFD", "FLD", "LBD", "BRD", + "RUF", "BUR", "LUB", "FUL", + "FDR", "LDF", "BDL", "RDB"}; + +static Metric_data *p_current_metric; +static Options *p_current_options; + +static unsigned int n_nodes; +static unsigned int n_tests; +static int sol_found; + +static sigjmp_buf jump_env; + + +/* ========================================================================= */ + void exit_w_error_message(char *msg) +/* ------------------------------------------------------------------------- */ + +{ +printf("\n%s\n", msg); +exit(EXIT_FAILURE); + +return; +} + + +/* ========================================================================= */ + void user_interrupt(int unused_arg) +/* ------------------------------------------------------------------------- */ + +{ +printf("\n-- user interrupt --\n"); +fflush(stdout); +siglongjmp(jump_env, 1); + +return; +} + + +/* ========================================================================= */ + void perm_n_unpack(int nn, int indx, int array_out[]) +/* ------------------------------------------------------------------------- */ + +{ +int ii, jj; + + +for (ii = nn - 1; ii >= 0; ii--) + { + array_out[ii] = indx % (nn - ii); + indx /= (nn - ii); + + for (jj = ii + 1; jj < nn; jj++) + if (array_out[jj] >= array_out[ii]) + array_out[jj]++; + } + +return; +} + + +/* ========================================================================= */ + int perm_n_pack(int nn, int array_in[]) +/* ------------------------------------------------------------------------- */ + +{ +int indx, ii, jj; + + +indx = 0; + +for (ii = 0; ii < nn; ii++) + { + indx *= (nn - ii); + + for (jj = ii + 1; jj < nn; jj++) + if (array_in[jj] < array_in[ii]) + indx++; + } + +return indx; +} + + +/* ========================================================================= */ + int perm_n_check(int nn, int array_in[]) +/* ------------------------------------------------------------------------- */ + +{ +int count[MAX_CHECK_PERM_N], ii; + + +for (ii = 0; ii < nn; ii++) + count[ii] = 0; + +for (ii = 0; ii < nn; ii++) + { + if ((array_in[ii] < 0) || (array_in[ii] >= nn)) + return 1; + + count[array_in[ii]]++; + } + +for (ii = 0; ii < nn; ii++) + if (count[ii] != 1) + return 1; + +return 0; +} + + +/* ========================================================================= */ + int perm_n_parity(int nn, int array_in[]) +/* ------------------------------------------------------------------------- */ + +{ +int temp_array[MAX_CHECK_PERM_N]; +int ii, jj, n_cycles; + + +for (ii = 0; ii < nn; ii++) + temp_array[ii] = 0; + +n_cycles = 0; + +for (ii = 0; ii < nn; ii++) + if (temp_array[ii] == 0) + { + n_cycles++; + jj = ii; + while (temp_array[jj] == 0) + { + temp_array[jj] = 1; + jj = array_in[jj]; + } + } + +return (n_cycles + nn) % 2; +} + + +/* ========================================================================= */ + void perm_n_init(int nn, int array_out[]) +/* ------------------------------------------------------------------------- */ + +{ +int ii; + + +for (ii = 0; ii < nn; ii++) + array_out[ii] = ii; + +return; +} + + +/* ========================================================================= */ + void perm_n_compose(int nn, int perm0_in[], int perm1_in[], + int perm_out[]) +/* ------------------------------------------------------------------------- */ + +{ +int ii; + + +for (ii = 0; ii < nn; ii++) + perm_out[ii] = perm0_in[perm1_in[ii]]; + +return; +} + + +/* ========================================================================= */ + void perm_n_conjugate(int nn, int arr_in[], int conjugator[], + int array_out[]) +/* ------------------------------------------------------------------------- */ + +{ +int ii; + + +for (ii = 0; ii < nn; ii++) + array_out[conjugator[ii]] = conjugator[arr_in[ii]]; + +return; +} + + +/* ========================================================================= */ + void two_cycle(int array[], int ind0, int ind1) +/* ------------------------------------------------------------------------- */ + +{ +int temp; + + +temp = array[ind0]; +array[ind0] = array[ind1]; +array[ind1] = temp; + +return; +} + + +/* ========================================================================= */ + void three_cycle(int array[], int ind0, int ind1, int ind2) +/* ------------------------------------------------------------------------- */ + +{ +int temp; + + +temp = array[ind0]; +array[ind0] = array[ind1]; +array[ind1] = array[ind2]; +array[ind2] = temp; + +return; +} + + +/* ========================================================================= */ + void four_cycle(int array[], int ind0, int ind1, int ind2, int ind3) +/* ------------------------------------------------------------------------- */ + +{ +int temp; + + +temp = array[ind0]; +array[ind0] = array[ind1]; +array[ind1] = array[ind2]; +array[ind2] = array[ind3]; +array[ind3] = temp; + +return; +} + + +/* ========================================================================= */ + void print_cube(Cube *p_cube) +/* ------------------------------------------------------------------------- */ + +{ +printf("%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n", + edge_cubie_str[p_cube->edges[0]], edge_cubie_str[p_cube->edges[1]], + edge_cubie_str[p_cube->edges[2]], edge_cubie_str[p_cube->edges[3]], + edge_cubie_str[p_cube->edges[4]], edge_cubie_str[p_cube->edges[5]], + edge_cubie_str[p_cube->edges[6]], edge_cubie_str[p_cube->edges[7]], + edge_cubie_str[p_cube->edges[8]], edge_cubie_str[p_cube->edges[9]], + edge_cubie_str[p_cube->edges[10]], edge_cubie_str[p_cube->edges[11]], + corner_cubie_str[p_cube->corners[0]], corner_cubie_str[p_cube->corners[1]], + corner_cubie_str[p_cube->corners[2]], corner_cubie_str[p_cube->corners[3]], + corner_cubie_str[p_cube->corners[4]], corner_cubie_str[p_cube->corners[5]], + corner_cubie_str[p_cube->corners[6]], corner_cubie_str[p_cube->corners[7]]); + +return; +} + + +/* ========================================================================= */ + void cube_init(Cube *p_cube) +/* ------------------------------------------------------------------------- */ + +{ +perm_n_init(24, p_cube->edges); +perm_n_init(24, p_cube->corners); + +return; +} + + +/* ========================================================================= */ + int cube_compare(Cube *cube0, Cube *cube1) +/* ------------------------------------------------------------------------- */ + +{ +int ii; + +for (ii = 0; ii < 24; ii++) + { + if (cube0->edges[ii] < cube1->edges[ii]) + return -1; + else if (cube0->edges[ii] > cube1->edges[ii]) + return 1; + } + +for (ii = 0; ii < 24; ii++) + { + if (cube0->corners[ii] < cube1->corners[ii]) + return -1; + else if (cube0->corners[ii] > cube1->corners[ii]) + return 1; + } + +return 0; +} + + +/* ========================================================================= */ + void cube_compose(Cube *in_cube0, Cube *in_cube1, Cube *out_cube) +/* ------------------------------------------------------------------------- */ + +{ +perm_n_compose(24, in_cube0->edges, in_cube1->edges, out_cube->edges); +perm_n_compose(24, in_cube0->corners, in_cube1->corners, out_cube->corners); + +return; +} + + +/* ========================================================================= */ + void cube_conjugate(Cube *p_cube_in, Cube *p_conjugator, + Cube *p_cube_out) +/* ------------------------------------------------------------------------- */ + +{ +perm_n_conjugate(24, p_cube_in->edges, p_conjugator->edges, p_cube_out->edges); +perm_n_conjugate(24, p_cube_in->corners, p_conjugator->corners, + p_cube_out->corners); + +return; +} + + +/* ========================================================================= */ + int cube_is_solved(Cube *p_cube) +/* ------------------------------------------------------------------------- */ + +{ +Cube temp_cube; + + +cube_init(&temp_cube); + +return (cube_compare(p_cube, &temp_cube) == 0); +} + + +/* ========================================================================= */ + int metric_q_length(int twist) +/* ------------------------------------------------------------------------- */ + +{ +if ((twist == TWIST_F) || (twist == TWIST_F3) || + (twist == TWIST_R) || (twist == TWIST_R3) || + (twist == TWIST_U) || (twist == TWIST_U3) || + (twist == TWIST_B) || (twist == TWIST_B3) || + (twist == TWIST_L) || (twist == TWIST_L3) || + (twist == TWIST_D) || (twist == TWIST_D3)) + return 1; +else if ((twist == TWIST_F2) || (twist == TWIST_R2) || (twist == TWIST_U2) || + (twist == TWIST_B2) || (twist == TWIST_L2) || (twist == TWIST_D2)) + return 2; +else + exit_w_error_message("metric_q_length : invalid twist"); + +return 0; +} + + +/* ========================================================================= */ + int metric_f_length(int twist) +/* ------------------------------------------------------------------------- */ + +{ +if ((twist == TWIST_F) || (twist == TWIST_F2) || (twist == TWIST_F3) || + (twist == TWIST_R) || (twist == TWIST_R2) || (twist == TWIST_R3) || + (twist == TWIST_U) || (twist == TWIST_U2) || (twist == TWIST_U3) || + (twist == TWIST_B) || (twist == TWIST_B2) || (twist == TWIST_B3) || + (twist == TWIST_L) || (twist == TWIST_L2) || (twist == TWIST_L3) || + (twist == TWIST_D) || (twist == TWIST_D2) || (twist == TWIST_D3)) + return 1; +else + exit_w_error_message("metric_f_length : invalid twist"); + +return 0; +} + + +/* ========================================================================= */ + void calc_metric_q_length(int lengths[N_TWIST]) +/* ------------------------------------------------------------------------- */ + +{ +int twist; + + +for (twist = 0; twist < N_TWIST; twist++) + lengths[twist] = metric_q_length(twist); + +return; +} + + +/* ========================================================================= */ + void calc_metric_f_length(int lengths[N_TWIST]) +/* ------------------------------------------------------------------------- */ + +{ +int twist; + + +for (twist = 0; twist < N_TWIST; twist++) + lengths[twist] = metric_f_length(twist); + +return; +} + + +/* ========================================================================= */ + void init_metric(Metric_data *p_metric_data, int use_metric) +/* ------------------------------------------------------------------------- */ + +{ +if ((use_metric != QUARTER_TURN_METRIC) && (use_metric != FACE_TURN_METRIC)) + exit_w_error_message("init_metric : unknown metric"); + +p_metric_data->metric = use_metric; + +if (p_metric_data->metric == QUARTER_TURN_METRIC) + { + printf("using quarter turn metric\n"); + p_metric_data->metric_char = 'q'; + calc_metric_q_length(p_metric_data->twist_length); + p_metric_data->increment = 2; + } +else + { + printf("using face turn metric\n"); + p_metric_data->metric_char = 'f'; + calc_metric_f_length(p_metric_data->twist_length); + p_metric_data->increment = 1; + } + +p_current_metric = p_metric_data; + +return; +} + + +/* ========================================================================= */ + void init_options(Metric_data *p_metric_data, Options *p_user_options) +/* ------------------------------------------------------------------------- */ + +{ +init_metric(p_metric_data, USE_METRIC); + +p_user_options->search_limit = SEARCH_LIMIT; +if (p_user_options->search_limit <= 0) + printf("no search limit\n"); +else + printf("search limit: %d%c\n", p_user_options->search_limit, + p_current_metric->metric_char); + +p_user_options->use_symmetry = USE_SYMMETRY; +if (p_user_options->use_symmetry) + printf("using symmetry reductions\n"); +else + printf("not using symmetry reductions\n"); + +p_user_options->one_solution_only = ONE_SOLUTION_ONLY; +if (p_user_options->one_solution_only) + printf("only finding one solution\n"); +else + printf("finding all solutions\n"); + +printf("\n"); +p_current_options = p_user_options; + +return; +} + + +/* ========================================================================= */ + void calc_group_table(int group_table[N_CUBESYM][N_CUBESYM]) +/* ------------------------------------------------------------------------- */ + +{ +int sym_array[N_CUBESYM][6]; +int sym_pack[N_CUBESYM]; +int temp_array[6]; +int ii, jj, kk, pack; + + +perm_n_init(6, sym_array[0]); +perm_n_init(6, sym_array[1]); + +four_cycle(sym_array[1], FACE_F, FACE_L, FACE_B, FACE_R); + +for (ii = 2; ii < 4; ii++) + perm_n_compose(6, sym_array[1], sym_array[ii - 1], sym_array[ii]); + +perm_n_init(6, sym_array[4]); + +two_cycle(sym_array[4], FACE_U, FACE_D); +two_cycle(sym_array[4], FACE_R, FACE_L); + +for (ii = 5; ii < 8; ii++) + perm_n_compose(6, sym_array[4], sym_array[ii - 4], sym_array[ii]); + +perm_n_init(6, sym_array[8]); + +two_cycle(sym_array[8], FACE_U, FACE_D); + +for (ii = 9; ii < 16; ii++) + perm_n_compose(6, sym_array[8], sym_array[ii - 8], sym_array[ii]); + +perm_n_init(6, sym_array[16]); + +three_cycle(sym_array[16], FACE_U, FACE_F, FACE_R); +three_cycle(sym_array[16], FACE_D, FACE_B, FACE_L); + +for (ii = 17; ii < 48; ii++) + perm_n_compose(6, sym_array[16], sym_array[ii - 16], sym_array[ii]); + +for (ii = 0; ii < N_CUBESYM; ii++) + sym_pack[ii] = perm_n_pack(6, sym_array[ii]); + +for (ii = 0; ii < N_CUBESYM; ii++) + for (jj = 0; jj < N_CUBESYM; jj++) + { + perm_n_compose(6, sym_array[ii], sym_array[jj], temp_array); + pack = perm_n_pack(6, temp_array); + + for (kk = 0; kk < N_CUBESYM; kk++) + if (sym_pack[kk] == pack) + { + group_table[ii][jj] = kk; + break; + } + + if (kk == N_CUBESYM) + exit_w_error_message("calc_group_table : product not found"); + } + +return; +} + + +/* ========================================================================= */ + void init_sym_x_invsym_to_sym(void) +/* ------------------------------------------------------------------------- */ + +{ +unsigned char (*mem_ptr)[N_SYM]; +int group_table[N_CUBESYM][N_CUBESYM]; +int group_inverse[N_CUBESYM]; +int ii, jj; + + +/* initialize global array sym_x_invsym_to_sym */ + +mem_ptr = + (unsigned char (*)[N_SYM])malloc(sizeof(unsigned char [N_SYM][N_SYM])); +if (mem_ptr == NULL) + exit_w_error_message("init_sym_x_invsym_to_sym : couldn't get memory"); + +for (ii = 0; ii < N_SYM; ii++) + sym_x_invsym_to_sym[ii] = mem_ptr[ii]; + +calc_group_table(group_table); + +for (ii = 0; ii < N_SYM; ii++) + { + for (jj = 0; jj < N_SYM; jj++) + if (group_table[ii][jj] == 0) + { + group_inverse[ii] = jj; + break; + } + + if (jj == N_SYM) + exit_w_error_message("init_sym_x_invsym_to_sym : inverse not found"); + } + +for (ii = 0; ii < N_SYM; ii++) + for (jj = 0; jj < N_SYM; jj++) + sym_x_invsym_to_sym[ii][jj] = + (unsigned char)group_table[ii][group_inverse[jj]]; + +return; +} + + +/* ========================================================================= */ + void calc_sym_on_twist(int sym_on_twist[N_CUBESYM][N_TWIST]) +/* ------------------------------------------------------------------------- */ + +{ +int sym; + + +perm_n_init(N_TWIST, sym_on_twist[0]); +perm_n_init(N_TWIST, sym_on_twist[1]); + +four_cycle(sym_on_twist[1], TWIST_F , TWIST_L , TWIST_B , TWIST_R ); +four_cycle(sym_on_twist[1], TWIST_F2, TWIST_L2, TWIST_B2, TWIST_R2); +four_cycle(sym_on_twist[1], TWIST_F3, TWIST_L3, TWIST_B3, TWIST_R3); + +for (sym = 2; sym < 4; sym++) + perm_n_compose(N_TWIST, sym_on_twist[1], sym_on_twist[sym - 1], + sym_on_twist[sym]); + +perm_n_init(N_TWIST, sym_on_twist[4]); + +two_cycle(sym_on_twist[4], TWIST_R , TWIST_L ); +two_cycle(sym_on_twist[4], TWIST_R2, TWIST_L2); +two_cycle(sym_on_twist[4], TWIST_R3, TWIST_L3); +two_cycle(sym_on_twist[4], TWIST_U , TWIST_D ); +two_cycle(sym_on_twist[4], TWIST_U2, TWIST_D2); +two_cycle(sym_on_twist[4], TWIST_U3, TWIST_D3); + +for (sym = 5; sym < 8; sym++) + perm_n_compose(N_TWIST, sym_on_twist[4], sym_on_twist[sym - 4], + sym_on_twist[sym]); + +perm_n_init(N_TWIST, sym_on_twist[8]); + +two_cycle(sym_on_twist[8], TWIST_F, TWIST_F3); +two_cycle(sym_on_twist[8], TWIST_R, TWIST_R3); +two_cycle(sym_on_twist[8], TWIST_B, TWIST_B3); +two_cycle(sym_on_twist[8], TWIST_L, TWIST_L3); +two_cycle(sym_on_twist[8], TWIST_U , TWIST_D3); +two_cycle(sym_on_twist[8], TWIST_U2, TWIST_D2); +two_cycle(sym_on_twist[8], TWIST_U3, TWIST_D ); + +for (sym = 9; sym < 16; sym++) + perm_n_compose(N_TWIST, sym_on_twist[8], sym_on_twist[sym - 8], + sym_on_twist[sym]); + +perm_n_init(N_TWIST, sym_on_twist[16]); + +three_cycle(sym_on_twist[16], TWIST_F , TWIST_R , TWIST_U ); +three_cycle(sym_on_twist[16], TWIST_F2, TWIST_R2, TWIST_U2); +three_cycle(sym_on_twist[16], TWIST_F3, TWIST_R3, TWIST_U3); +three_cycle(sym_on_twist[16], TWIST_B , TWIST_L , TWIST_D ); +three_cycle(sym_on_twist[16], TWIST_B2, TWIST_L2, TWIST_D2); +three_cycle(sym_on_twist[16], TWIST_B3, TWIST_L3, TWIST_D3); + +for (sym = 17; sym < 48; sym++) + perm_n_compose(N_TWIST, sym_on_twist[16], sym_on_twist[sym - 16], + sym_on_twist[sym]); + +return; +} + + +/* ========================================================================= */ + void init_invsym_on_twist(void) +/* ------------------------------------------------------------------------- */ + +{ +unsigned char (*mem_ptr)[N_SYM][N_TWIST]; +int sym_on_twist[N_CUBESYM][N_TWIST]; +int ud_to_rl[N_TWIST], sym, twist; + + +/* allocate and initialize global arrays */ +/* invsym_on_twist_ud , invsym_on_twist_fb and invsym_on_twist_rl */ + +mem_ptr = (unsigned char (*)[N_SYM][N_TWIST]) + malloc(sizeof(unsigned char [3][N_SYM][N_TWIST])); +if (mem_ptr == NULL) + exit_w_error_message("init_invsym_on_twist : couldn't get memory"); + +for (sym = 0; sym < N_SYM; sym++) + { + invsym_on_twist_ud[sym] = mem_ptr[0][sym]; + invsym_on_twist_rl[sym] = mem_ptr[1][sym]; + invsym_on_twist_fb[sym] = mem_ptr[2][sym]; + } + +calc_sym_on_twist(sym_on_twist); + +for (sym = 0; sym < N_SYM; sym++) + for (twist = 0; twist < N_TWIST; twist++) + invsym_on_twist_ud[sym][twist] = + (unsigned char)sym_on_twist[(int)sym_x_invsym_to_sym[0][sym]][twist]; + +perm_n_init(N_TWIST, ud_to_rl); + +three_cycle(ud_to_rl, TWIST_F , TWIST_R , TWIST_U ); +three_cycle(ud_to_rl, TWIST_F2, TWIST_R2, TWIST_U2); +three_cycle(ud_to_rl, TWIST_F3, TWIST_R3, TWIST_U3); +three_cycle(ud_to_rl, TWIST_B , TWIST_L , TWIST_D ); +three_cycle(ud_to_rl, TWIST_B2, TWIST_L2, TWIST_D2); +three_cycle(ud_to_rl, TWIST_B3, TWIST_L3, TWIST_D3); + +for (sym = 0; sym < N_SYM; sym++) + for (twist = 0; twist < N_TWIST; twist++) + invsym_on_twist_rl[sym][twist] = + invsym_on_twist_ud[sym][ud_to_rl[twist]]; + +for (sym = 0; sym < N_SYM; sym++) + for (twist = 0; twist < N_TWIST; twist++) + invsym_on_twist_fb[sym][twist] = + invsym_on_twist_rl[sym][ud_to_rl[twist]]; + +return; +} + + +/* ========================================================================= */ + void generate_subgroup(int group_table[N_CUBESYM][N_CUBESYM], + int gen_set[N_CUBESYM]) +/* ------------------------------------------------------------------------- */ + +/* gen_set[] is both input and output */ + +{ +int found, ii, jj; + + +gen_set[0] = 1; +found = 1; + +while (found) + { + found = 0; + + for (ii = 0; ii < N_CUBESYM; ii++) + if (gen_set[ii] != 0) + for (jj = 0; jj < N_CUBESYM; jj++) + if ((gen_set[jj] != 0) && (gen_set[group_table[ii][jj]] == 0)) + { + gen_set[group_table[ii][jj]] = 1; + found = 1; + } + } + +return; +} + + +/* ========================================================================= */ + void calc_subgroups_recursive(int group_table[N_CUBESYM][N_CUBESYM], + int contain_list[N_CUBESYM], + int avoid_list[N_CUBESYM], + Subgroup_list *p_output) +/* ------------------------------------------------------------------------- */ + +{ +int local_contain_list[N_CUBESYM], ii, jj; + + +for (ii = 0; ii < N_CUBESYM; ii++) + if (contain_list[ii] && avoid_list[ii]) + return; + +for (ii = 0; ii < N_CUBESYM; ii++) + if ((contain_list[ii] == 0) && (avoid_list[ii] == 0)) + break; + +if (ii < N_CUBESYM) + { + for (jj = 0; jj < N_CUBESYM; jj++) + local_contain_list[jj] = contain_list[jj]; + local_contain_list[ii] = 1; + generate_subgroup(group_table, local_contain_list); + calc_subgroups_recursive(group_table, local_contain_list, avoid_list, + p_output); + avoid_list[ii] = 1; + calc_subgroups_recursive(group_table, contain_list, avoid_list, p_output); + avoid_list[ii] = 0; + } +else + { + if (p_output->n_subgroups >= N_SYMSUBGRP) + exit_w_error_message("calc_subgroups_recursive : too many subgroups"); + + for (ii = 0; ii < N_CUBESYM; ii++) + p_output->subgroups[p_output->n_subgroups][ii] = contain_list[ii]; + + p_output->n_subgroups++; + } + +return; +} + + +/* ========================================================================= */ + void calc_subgroup_list(int subgroup_list[N_SYMSUBGRP][N_CUBESYM]) +/* ------------------------------------------------------------------------- */ + +{ +Subgroup_list output_list; +int group_table[N_CUBESYM][N_CUBESYM]; +int contain_list[N_CUBESYM]; +int avoid_list[N_CUBESYM]; +int ii; + + +calc_group_table(group_table); + +output_list.n_subgroups = 0; +output_list.subgroups = subgroup_list; + +contain_list[0] = 1; + +for (ii = 1; ii < N_CUBESYM; ii++) + contain_list[ii] = 0; + +for (ii = 0; ii < N_CUBESYM; ii++) + avoid_list[ii] = 0; + +calc_subgroups_recursive(group_table, contain_list, avoid_list, &output_list); + +if (output_list.n_subgroups != N_SYMSUBGRP) + exit_w_error_message("calc_subgroup_list : wrong number of subgroups"); + +return; +} + + +/* ========================================================================= */ + int is_single_twist(int syllable) +/* ------------------------------------------------------------------------- */ + +{ +if ((syllable == SYLLABLE_F) || (syllable == SYLLABLE_F2) || + (syllable == SYLLABLE_F3) || + (syllable == SYLLABLE_R) || (syllable == SYLLABLE_R2) || + (syllable == SYLLABLE_R3) || + (syllable == SYLLABLE_U) || (syllable == SYLLABLE_U2) || + (syllable == SYLLABLE_U3) || + (syllable == SYLLABLE_B) || (syllable == SYLLABLE_B2) || + (syllable == SYLLABLE_B3) || + (syllable == SYLLABLE_L) || (syllable == SYLLABLE_L2) || + (syllable == SYLLABLE_L3) || + (syllable == SYLLABLE_D) || (syllable == SYLLABLE_D2) || + (syllable == SYLLABLE_D3)) + return 1; + +return 0; +} + + +/* ========================================================================= */ + int syllable_to_twist(int syllable) +/* ------------------------------------------------------------------------- */ + +{ +if (syllable == SYLLABLE_F) + return TWIST_F; +else if (syllable == SYLLABLE_F2) + return TWIST_F2; +else if (syllable == SYLLABLE_F3) + return TWIST_F3; +else if (syllable == SYLLABLE_R) + return TWIST_R; +else if (syllable == SYLLABLE_R2) + return TWIST_R2; +else if (syllable == SYLLABLE_R3) + return TWIST_R3; +else if (syllable == SYLLABLE_U) + return TWIST_U; +else if (syllable == SYLLABLE_U2) + return TWIST_U2; +else if (syllable == SYLLABLE_U3) + return TWIST_U3; +else if (syllable == SYLLABLE_B) + return TWIST_B; +else if (syllable == SYLLABLE_B2) + return TWIST_B2; +else if (syllable == SYLLABLE_B3) + return TWIST_B3; +else if (syllable == SYLLABLE_L) + return TWIST_L; +else if (syllable == SYLLABLE_L2) + return TWIST_L2; +else if (syllable == SYLLABLE_L3) + return TWIST_L3; +else if (syllable == SYLLABLE_D) + return TWIST_D; +else if (syllable == SYLLABLE_D2) + return TWIST_D2; +else if (syllable == SYLLABLE_D3) + return TWIST_D3; +else + exit_w_error_message("syllable_to_twist : invalid input"); + +return -1; +} + + +/* ========================================================================= */ + void syllable_to_two_twists(int syllable, int twists_out[2]) +/* ------------------------------------------------------------------------- */ + +{ +if (syllable == SYLLABLE_FB) + { + twists_out[0] = TWIST_F; + twists_out[1] = TWIST_B; + } +else if (syllable == SYLLABLE_FB2) + { + twists_out[0] = TWIST_F; + twists_out[1] = TWIST_B2; + } +else if (syllable == SYLLABLE_FB3) + { + twists_out[0] = TWIST_F; + twists_out[1] = TWIST_B3; + } +else if (syllable == SYLLABLE_F2B2) + { + twists_out[0] = TWIST_F2; + twists_out[1] = TWIST_B2; + } +else if (syllable == SYLLABLE_RL) + { + twists_out[0] = TWIST_R; + twists_out[1] = TWIST_L; + } +else if (syllable == SYLLABLE_RL2) + { + twists_out[0] = TWIST_R; + twists_out[1] = TWIST_L2; + } +else if (syllable == SYLLABLE_RL3) + { + twists_out[0] = TWIST_R; + twists_out[1] = TWIST_L3; + } +else if (syllable == SYLLABLE_R2L2) + { + twists_out[0] = TWIST_R2; + twists_out[1] = TWIST_L2; + } +else if (syllable == SYLLABLE_UD) + { + twists_out[0] = TWIST_U; + twists_out[1] = TWIST_D; + } +else if (syllable == SYLLABLE_UD2) + { + twists_out[0] = TWIST_U; + twists_out[1] = TWIST_D2; + } +else if (syllable == SYLLABLE_UD3) + { + twists_out[0] = TWIST_U; + twists_out[1] = TWIST_D3; + } +else if (syllable == SYLLABLE_U2D2) + { + twists_out[0] = TWIST_U2; + twists_out[1] = TWIST_D2; + } +else + exit_w_error_message("syllable_to_two_twists : invalid input"); + +return; +} + + +/* ========================================================================= */ + int twists_in_wrong_order(int twists[2]) +/* ------------------------------------------------------------------------- */ + +{ +if (((twists[0] == TWIST_B) || (twists[0] == TWIST_B2) || + (twists[0] == TWIST_B3)) && + ((twists[1] == TWIST_F) || (twists[1] == TWIST_F2) || + (twists[1] == TWIST_F3))) + return 1; + +if (((twists[0] == TWIST_L) || (twists[0] == TWIST_L2) || + (twists[0] == TWIST_L3)) && + ((twists[1] == TWIST_R) || (twists[1] == TWIST_R2) || + (twists[1] == TWIST_R3))) + return 1; + +if (((twists[0] == TWIST_D) || (twists[0] == TWIST_D2) || + (twists[0] == TWIST_D3)) && + ((twists[1] == TWIST_U) || (twists[1] == TWIST_U2) || + (twists[1] == TWIST_U3))) + return 1; + +return 0; +} + + +/* ========================================================================= */ + void clean_up_sequence(int twist_sequence[], int n_twists) +/* ------------------------------------------------------------------------- */ + +{ +int ii; + + +for (ii = 1; ii < n_twists; ii++) + if (twists_in_wrong_order(&twist_sequence[ii - 1]) != 0) + two_cycle(twist_sequence, ii - 1, ii); + +return; +} + + +/* ========================================================================= */ + int which_subgroup(int subgroup[N_CUBESYM], + int subgroup_list[N_SYMSUBGRP][N_CUBESYM]) +/* ------------------------------------------------------------------------- */ + +{ +int subgrp, sym; + + +for (subgrp = 0; subgrp < N_SYMSUBGRP; subgrp++) + { + for (sym = 0; sym < N_CUBESYM; sym++) + if ((subgroup[sym] == 0) != (subgroup_list[subgrp][sym] == 0)) + break; + + if (sym == N_CUBESYM) + return subgrp; + } + +return -1; +} + + +/* ========================================================================= */ + void calc_syllable_on_sym(int subgroup_list[N_SYMSUBGRP][N_CUBESYM], + int sym_on_twist[N_CUBESYM][N_TWIST], + int syllable_on_sym[N_SYLLABLE][N_SYMSUBGRP]) +/* ------------------------------------------------------------------------- */ + +{ +int subgroup[N_CUBESYM], temp_subgroup[N_CUBESYM]; +int twist_arr[2], temp_arr[2]; +int syllable, sym, subgrp, twist; + + +for (syllable = 0; syllable < N_SYLLABLE; syllable++) + { + if ((syllable == SYLLABLE_INVALID) || (syllable == SYLLABLE_NONE)) + { + subgroup[0] = 1; + for (sym = 1; sym < N_CUBESYM; sym++) + subgroup[sym] = 0; + } + else if (is_single_twist(syllable)) + { + twist = syllable_to_twist(syllable); + for (sym = 0; sym < N_CUBESYM; sym++) + subgroup[sym] = (sym_on_twist[sym][twist] == twist); + } + else + { + syllable_to_two_twists(syllable, twist_arr); + + for (sym = 0; sym < N_CUBESYM; sym++) + { + temp_arr[0] = sym_on_twist[sym][twist_arr[0]]; + temp_arr[1] = sym_on_twist[sym][twist_arr[1]]; + clean_up_sequence(temp_arr, 2); + if ((temp_arr[0] == twist_arr[0]) && + (temp_arr[1] == twist_arr[1])) + subgroup[sym] = 1; + else + subgroup[sym] = 0; + } + } + + for (subgrp = 0; subgrp < N_SYMSUBGRP; subgrp++) + { + for (sym = 0; sym < N_CUBESYM; sym++) + temp_subgroup[sym] = (subgroup[sym] && subgroup_list[subgrp][sym]); + + syllable_on_sym[syllable][subgrp] = which_subgroup(temp_subgroup, + subgroup_list); + if (syllable_on_sym[syllable][subgrp] < 0) + exit_w_error_message("calc_syllable_on_sym : subgroup not found"); + } + } + +return; +} + + +/* ========================================================================= */ + int twist_on_syllable(int twist, int syllable) +/* ------------------------------------------------------------------------- */ + +{ +if (syllable == SYLLABLE_INVALID) + return SYLLABLE_INVALID; + +if (twist == TWIST_F) + { + if ((syllable == SYLLABLE_F) || (syllable == SYLLABLE_F2) || + (syllable == SYLLABLE_F3) || + (syllable == SYLLABLE_B) || (syllable == SYLLABLE_B2) || + (syllable == SYLLABLE_B3) || + (syllable == SYLLABLE_FB) || (syllable == SYLLABLE_FB2) || + (syllable == SYLLABLE_FB3) || (syllable == SYLLABLE_F2B2)) + return SYLLABLE_INVALID; + else + return SYLLABLE_F; + } +else if (twist == TWIST_F2) + { + if ((syllable == SYLLABLE_F) || (syllable == SYLLABLE_F2) || + (syllable == SYLLABLE_F3) || + (syllable == SYLLABLE_B) || (syllable == SYLLABLE_B2) || + (syllable == SYLLABLE_B3) || + (syllable == SYLLABLE_FB) || (syllable == SYLLABLE_FB2) || + (syllable == SYLLABLE_FB3) || (syllable == SYLLABLE_F2B2)) + return SYLLABLE_INVALID; + else + return SYLLABLE_F2; + } +else if (twist == TWIST_F3) + { + if ((syllable == SYLLABLE_F) || (syllable == SYLLABLE_F2) || + (syllable == SYLLABLE_F3) || + (syllable == SYLLABLE_B) || (syllable == SYLLABLE_B2) || + (syllable == SYLLABLE_B3) || + (syllable == SYLLABLE_FB) || (syllable == SYLLABLE_FB2) || + (syllable == SYLLABLE_FB3) || (syllable == SYLLABLE_F2B2)) + return SYLLABLE_INVALID; + else + return SYLLABLE_F3; + } +else if (twist == TWIST_R) + { + if ((syllable == SYLLABLE_R) || (syllable == SYLLABLE_R2) || + (syllable == SYLLABLE_R3) || + (syllable == SYLLABLE_L) || (syllable == SYLLABLE_L2) || + (syllable == SYLLABLE_L3) || + (syllable == SYLLABLE_RL) || (syllable == SYLLABLE_RL2) || + (syllable == SYLLABLE_RL3) || (syllable == SYLLABLE_R2L2)) + return SYLLABLE_INVALID; + else + return SYLLABLE_R; + } +else if (twist == TWIST_R2) + { + if ((syllable == SYLLABLE_R) || (syllable == SYLLABLE_R2) || + (syllable == SYLLABLE_R3) || + (syllable == SYLLABLE_L) || (syllable == SYLLABLE_L2) || + (syllable == SYLLABLE_L3) || + (syllable == SYLLABLE_RL) || (syllable == SYLLABLE_RL2) || + (syllable == SYLLABLE_RL3) || (syllable == SYLLABLE_R2L2)) + return SYLLABLE_INVALID; + else + return SYLLABLE_R2; + } +else if (twist == TWIST_R3) + { + if ((syllable == SYLLABLE_R) || (syllable == SYLLABLE_R2) || + (syllable == SYLLABLE_R3) || + (syllable == SYLLABLE_L) || (syllable == SYLLABLE_L2) || + (syllable == SYLLABLE_L3) || + (syllable == SYLLABLE_RL) || (syllable == SYLLABLE_RL2) || + (syllable == SYLLABLE_RL3) || (syllable == SYLLABLE_R2L2)) + return SYLLABLE_INVALID; + else + return SYLLABLE_R3; + } +else if (twist == TWIST_U) + { + if ((syllable == SYLLABLE_U) || (syllable == SYLLABLE_U2) || + (syllable == SYLLABLE_U3) || + (syllable == SYLLABLE_D) || (syllable == SYLLABLE_D2) || + (syllable == SYLLABLE_D3) || + (syllable == SYLLABLE_UD) || (syllable == SYLLABLE_UD2) || + (syllable == SYLLABLE_UD3) || (syllable == SYLLABLE_U2D2)) + return SYLLABLE_INVALID; + else + return SYLLABLE_U; + } +else if (twist == TWIST_U2) + { + if ((syllable == SYLLABLE_U) || (syllable == SYLLABLE_U2) || + (syllable == SYLLABLE_U3) || + (syllable == SYLLABLE_D) || (syllable == SYLLABLE_D2) || + (syllable == SYLLABLE_D3) || + (syllable == SYLLABLE_UD) || (syllable == SYLLABLE_UD2) || + (syllable == SYLLABLE_UD3) || (syllable == SYLLABLE_U2D2)) + return SYLLABLE_INVALID; + else + return SYLLABLE_U2; + } +else if (twist == TWIST_U3) + { + if ((syllable == SYLLABLE_U) || (syllable == SYLLABLE_U2) || + (syllable == SYLLABLE_U3) || + (syllable == SYLLABLE_D) || (syllable == SYLLABLE_D2) || + (syllable == SYLLABLE_D3) || + (syllable == SYLLABLE_UD) || (syllable == SYLLABLE_UD2) || + (syllable == SYLLABLE_UD3) || (syllable == SYLLABLE_U2D2)) + return SYLLABLE_INVALID; + else + return SYLLABLE_U3; + } +else if (twist == TWIST_B) + { + if ((syllable == SYLLABLE_B) || (syllable == SYLLABLE_B2) || + (syllable == SYLLABLE_B3) || + (syllable == SYLLABLE_FB) || (syllable == SYLLABLE_FB2) || + (syllable == SYLLABLE_FB3) || (syllable == SYLLABLE_F2B2)) + return SYLLABLE_INVALID; + else if (syllable == SYLLABLE_F) + return SYLLABLE_FB; + else if (syllable == SYLLABLE_F2) + return SYLLABLE_FB2; + else if (syllable == SYLLABLE_F3) + return SYLLABLE_FB3; + else + return SYLLABLE_B; + } +else if (twist == TWIST_B2) + { + if ((syllable == SYLLABLE_B) || (syllable == SYLLABLE_B2) || + (syllable == SYLLABLE_B3) || + (syllable == SYLLABLE_FB) || (syllable == SYLLABLE_FB2) || + (syllable == SYLLABLE_FB3) || (syllable == SYLLABLE_F2B2)) + return SYLLABLE_INVALID; + else if ((syllable == SYLLABLE_F) || (syllable == SYLLABLE_F3)) + return SYLLABLE_FB2; + else if (syllable == SYLLABLE_F2) + return SYLLABLE_F2B2; + else + return SYLLABLE_B2; + } +else if (twist == TWIST_B3) + { + if ((syllable == SYLLABLE_B) || (syllable == SYLLABLE_B2) || + (syllable == SYLLABLE_B3) || + (syllable == SYLLABLE_FB) || (syllable == SYLLABLE_FB2) || + (syllable == SYLLABLE_FB3) || (syllable == SYLLABLE_F2B2)) + return SYLLABLE_INVALID; + else if (syllable == SYLLABLE_F) + return SYLLABLE_FB3; + else if (syllable == SYLLABLE_F2) + return SYLLABLE_FB2; + else if (syllable == SYLLABLE_F3) + return SYLLABLE_FB; + else + return SYLLABLE_B3; + } +else if (twist == TWIST_L) + { + if ((syllable == SYLLABLE_L) || (syllable == SYLLABLE_L2) || + (syllable == SYLLABLE_L3) || + (syllable == SYLLABLE_RL) || (syllable == SYLLABLE_RL2) || + (syllable == SYLLABLE_RL3) || (syllable == SYLLABLE_R2L2)) + return SYLLABLE_INVALID; + else if (syllable == SYLLABLE_R) + return SYLLABLE_RL; + else if (syllable == SYLLABLE_R2) + return SYLLABLE_RL2; + else if (syllable == SYLLABLE_R3) + return SYLLABLE_RL3; + else + return SYLLABLE_L; + } +else if (twist == TWIST_L2) + { + if ((syllable == SYLLABLE_L) || (syllable == SYLLABLE_L2) || + (syllable == SYLLABLE_L3) || + (syllable == SYLLABLE_RL) || (syllable == SYLLABLE_RL2) || + (syllable == SYLLABLE_RL3) || (syllable == SYLLABLE_R2L2)) + return SYLLABLE_INVALID; + else if ((syllable == SYLLABLE_R) || (syllable == SYLLABLE_R3)) + return SYLLABLE_RL2; + else if (syllable == SYLLABLE_R2) + return SYLLABLE_R2L2; + else + return SYLLABLE_L2; + } +else if (twist == TWIST_L3) + { + if ((syllable == SYLLABLE_L) || (syllable == SYLLABLE_L2) || + (syllable == SYLLABLE_L3) || + (syllable == SYLLABLE_RL) || (syllable == SYLLABLE_RL2) || + (syllable == SYLLABLE_RL3) || (syllable == SYLLABLE_R2L2)) + return SYLLABLE_INVALID; + else if (syllable == SYLLABLE_R) + return SYLLABLE_RL3; + else if (syllable == SYLLABLE_R2) + return SYLLABLE_RL2; + else if (syllable == SYLLABLE_R3) + return SYLLABLE_RL; + else + return SYLLABLE_L3; + } +else if (twist == TWIST_D) + { + if ((syllable == SYLLABLE_D) || (syllable == SYLLABLE_D2) || + (syllable == SYLLABLE_D3) || + (syllable == SYLLABLE_UD) || (syllable == SYLLABLE_UD2) || + (syllable == SYLLABLE_UD3) || (syllable == SYLLABLE_U2D2)) + return SYLLABLE_INVALID; + else if (syllable == SYLLABLE_U) + return SYLLABLE_UD; + else if (syllable == SYLLABLE_U2) + return SYLLABLE_UD2; + else if (syllable == SYLLABLE_U3) + return SYLLABLE_UD3; + else + return SYLLABLE_D; + } +else if (twist == TWIST_D2) + { + if ((syllable == SYLLABLE_D) || (syllable == SYLLABLE_D2) || + (syllable == SYLLABLE_D3) || + (syllable == SYLLABLE_UD) || (syllable == SYLLABLE_UD2) || + (syllable == SYLLABLE_UD3) || (syllable == SYLLABLE_U2D2)) + return SYLLABLE_INVALID; + else if ((syllable == SYLLABLE_U) || (syllable == SYLLABLE_U3)) + return SYLLABLE_UD2; + else if (syllable == SYLLABLE_U2) + return SYLLABLE_U2D2; + else + return SYLLABLE_D2; + } +else if (twist == TWIST_D3) + { + if ((syllable == SYLLABLE_D) || (syllable == SYLLABLE_D2) || + (syllable == SYLLABLE_D3) || + (syllable == SYLLABLE_UD) || (syllable == SYLLABLE_UD2) || + (syllable == SYLLABLE_UD3) || (syllable == SYLLABLE_U2D2)) + return SYLLABLE_INVALID; + else if (syllable == SYLLABLE_U) + return SYLLABLE_UD3; + else if (syllable == SYLLABLE_U2) + return SYLLABLE_UD2; + else if (syllable == SYLLABLE_U3) + return SYLLABLE_UD; + else + return SYLLABLE_D3; + } +else + exit_w_error_message("twist_on_syllable : invalid twist"); + +return SYLLABLE_INVALID; +} + + +/* ========================================================================= */ + int not_minimal_one_twist(int subgroup[N_CUBESYM], + int sym_on_twist[N_CUBESYM][N_TWIST], + int twist) +/* ------------------------------------------------------------------------- */ + +{ +int sym; + + +for (sym = 0; sym < N_CUBESYM; sym++) + if (subgroup[sym] && (sym_on_twist[sym][twist] < twist)) + return 1; + +return 0; +} + + +/* ========================================================================= */ + int not_minimal_two_twists(int subgroup[N_CUBESYM], + int sym_on_twist[N_CUBESYM][N_TWIST], + int twist0, int twist1) +/* ------------------------------------------------------------------------- */ + +{ +int twist_arr[2], sym; + + +for (sym = 0; sym < N_CUBESYM; sym++) + if (subgroup[sym]) + { + twist_arr[0] = sym_on_twist[sym][twist0]; + twist_arr[1] = sym_on_twist[sym][twist1]; + clean_up_sequence(twist_arr, 2); + if ((twist_arr[0] < twist0) || + ((twist_arr[0] == twist0) && (twist_arr[1] < twist1))) + return 1; + } + +return 0; +} + + +/* ========================================================================= */ + void calc_twist_on_sylsubgrp(int + tw_on_sylsubgrp[N_TWIST][N_SYLLABLE * N_SYMSUBGRP]) +/* ------------------------------------------------------------------------- */ + +{ +int subgroup_list[N_SYMSUBGRP][N_CUBESYM]; +int sym_on_twist[N_CUBESYM][N_TWIST]; +int syllable_on_subgrp[N_SYLLABLE][N_SYMSUBGRP]; +int syllable, subgrp, subgrp_before, subgrp_after, twist; +int new_syllable, new_subgrp; + + +calc_subgroup_list(subgroup_list); +calc_sym_on_twist(sym_on_twist); +calc_syllable_on_sym(subgroup_list, sym_on_twist, syllable_on_subgrp); + +for (syllable = 0; syllable < N_SYLLABLE; syllable++) + for (subgrp = 0; subgrp < N_SYMSUBGRP; subgrp++) + { + if (is_single_twist(syllable)) + { + subgrp_before = subgrp; + subgrp_after = syllable_on_subgrp[syllable][subgrp]; + } + else + { + subgrp_before = SUBGRP_TRIVIAL; + + if (syllable == SYLLABLE_INVALID) + subgrp_after = SUBGRP_TRIVIAL; + else + subgrp_after = subgrp; + } + + for (twist = 0; twist < N_TWIST; twist++) + { + new_syllable = twist_on_syllable(twist, syllable); + + if (is_single_twist(new_syllable)) + { + if (not_minimal_one_twist(subgroup_list[subgrp_after], + sym_on_twist, syllable_to_twist(new_syllable))) + new_syllable = SYLLABLE_INVALID; + } + else if (new_syllable != SYLLABLE_INVALID) + { + if (not_minimal_two_twists(subgroup_list[subgrp_before], + sym_on_twist, syllable_to_twist(syllable), twist)) + new_syllable = SYLLABLE_INVALID; + } + + if (new_syllable == SYLLABLE_INVALID) + new_subgrp = SUBGRP_TRIVIAL; + else if (is_single_twist(new_syllable)) + new_subgrp = subgrp_after; + else + new_subgrp = syllable_on_subgrp[new_syllable][subgrp_before]; + + tw_on_sylsubgrp[twist][syllable * N_SYMSUBGRP + subgrp] = + new_syllable * N_SYMSUBGRP + new_subgrp; + } + } + +return; +} + + +/* ========================================================================= */ + void init_twist_on_follow(void) +/* ------------------------------------------------------------------------- */ + +{ +unsigned short (*mem_ptr)[N_FOLLOW]; +int tw_on_sylsubgrp[N_TWIST][N_SYLLABLE * N_SYMSUBGRP]; +int occurs[N_SYLLABLE * N_SYMSUBGRP]; +int sylsubgrp_to_follow[N_SYLLABLE * N_SYMSUBGRP]; +int follow_to_sylsubgrp[N_FOLLOW]; +int syllable, subgrp, found, twist, count, follow; + + +calc_twist_on_sylsubgrp(tw_on_sylsubgrp); + +for (syllable = 0; syllable < N_SYLLABLE; syllable++) + for (subgrp = 0; subgrp < N_SYMSUBGRP; subgrp++) + occurs[syllable * N_SYMSUBGRP + subgrp] = 0; + +for (subgrp = 0; subgrp < N_SYMSUBGRP; subgrp++) + occurs[SYLLABLE_NONE * N_SYMSUBGRP + subgrp] = 1; + +found = 1; + +while (found) + { + found = 0; + for (syllable = 0; syllable < N_SYLLABLE; syllable++) + for (subgrp = 0; subgrp < N_SYMSUBGRP; subgrp++) + for (twist = 0; twist < N_TWIST; twist++) + if (occurs[tw_on_sylsubgrp[twist] + [syllable * N_SYMSUBGRP + subgrp]] == 0) + { + occurs[tw_on_sylsubgrp[twist] + [syllable * N_SYMSUBGRP + subgrp]] = 1; + found = 1; + } + } + +count = 0; + +for (syllable = 0; syllable < N_SYLLABLE; syllable++) + for (subgrp = 0; subgrp < N_SYMSUBGRP; subgrp++) + { + if (occurs[syllable * N_SYMSUBGRP + subgrp] == 0) + sylsubgrp_to_follow[syllable * N_SYMSUBGRP + subgrp] = -1; + else + { + sylsubgrp_to_follow[syllable * N_SYMSUBGRP + subgrp] = count; + follow_to_sylsubgrp[count] = syllable * N_SYMSUBGRP + subgrp; + count++; + } + } + +if (count != N_FOLLOW) + exit_w_error_message("init_twist_on_follow : wrong number of follow's"); + +for (subgrp = 0; subgrp < N_SYMSUBGRP; subgrp++) + if (sylsubgrp_to_follow[SYLLABLE_NONE * N_SYMSUBGRP + subgrp] + != 1 + subgrp) + exit_w_error_message("init_twist_on_follow : indexing error"); + +mem_ptr = (unsigned short (*)[N_FOLLOW]) + malloc(sizeof(unsigned short [N_TWIST][N_FOLLOW])); +if (mem_ptr == NULL) + exit_w_error_message("init_twist_on_follow : couldn't get memory"); + +for (twist = 0; twist < N_TWIST; twist++) + twist_on_follow[twist] = mem_ptr[twist]; + +for (twist = 0; twist < N_TWIST; twist++) + for (follow = 0; follow < N_FOLLOW; follow++) + twist_on_follow[twist][follow] = + (unsigned short)sylsubgrp_to_follow[tw_on_sylsubgrp[twist] + [follow_to_sylsubgrp[follow]]]; + +return; +} + + +/* ========================================================================= */ + void corner_unpack(int corner, int array_out[8]) +/* ------------------------------------------------------------------------- */ + +/* input: corner + output: array_out[] */ + +{ +int ii; + + +for (ii = 0; ii < 7; ii++) + { + array_out[ii] = corner % 3; + corner = corner / 3; + } + +array_out[7] = (2 * (array_out[0] + array_out[1] + array_out[2] + array_out[3] + + array_out[4] + array_out[5] + array_out[6])) % 3; + +return; +} + + +/* ========================================================================= */ + int corner_pack(int array_in[8]) +/* ------------------------------------------------------------------------- */ + +/* input: array_in[] */ + +{ +int corner, ii; + + +corner = 0; +for (ii = 6; ii >= 0; ii--) + corner = 3 * corner + array_in[ii]; + +return corner; +} + + +/* ========================================================================= */ + void corner_adjust(int array[8], int ind0, int ind1, int ind2, + int ind3) +/* ------------------------------------------------------------------------- */ + +{ +array[ind0] = (array[ind0] + 1) % 3; +array[ind1] = (array[ind1] + 2) % 3; +array[ind2] = (array[ind2] + 1) % 3; +array[ind3] = (array[ind3] + 2) % 3; + +return; +} + + +/* ========================================================================= */ + int twist_f_on_corner(int corner) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +corner_unpack(corner, temp_arr); +four_cycle(temp_arr, CORNER_DFL, CORNER_DRF, CORNER_UFR, CORNER_ULF); +corner_adjust(temp_arr, CORNER_DFL, CORNER_DRF, CORNER_UFR, CORNER_ULF); + +return corner_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_r_on_corner(int corner) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +corner_unpack(corner, temp_arr); +four_cycle(temp_arr, CORNER_DRF, CORNER_DBR, CORNER_URB, CORNER_UFR); +corner_adjust(temp_arr, CORNER_DRF, CORNER_DBR, CORNER_URB, CORNER_UFR); + +return corner_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_u_on_corner(int corner) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +corner_unpack(corner, temp_arr); +four_cycle(temp_arr, CORNER_UFR, CORNER_URB, CORNER_UBL, CORNER_ULF); + +return corner_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_b_on_corner(int corner) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +corner_unpack(corner, temp_arr); +four_cycle(temp_arr, CORNER_DBR, CORNER_DLB, CORNER_UBL, CORNER_URB); +corner_adjust(temp_arr, CORNER_DBR, CORNER_DLB, CORNER_UBL, CORNER_URB); + +return corner_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_l_on_corner(int corner) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +corner_unpack(corner, temp_arr); +four_cycle(temp_arr, CORNER_DLB, CORNER_DFL, CORNER_ULF, CORNER_UBL); +corner_adjust(temp_arr, CORNER_DLB, CORNER_DFL, CORNER_ULF, CORNER_UBL); + +return corner_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_d_on_corner(int corner) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +corner_unpack(corner, temp_arr); +four_cycle(temp_arr, CORNER_DFL, CORNER_DLB, CORNER_DBR, CORNER_DRF); + +return corner_pack(temp_arr); +} + + +/* ========================================================================= */ + void init_twist_on_corner(void) +/* ------------------------------------------------------------------------- */ + +{ +int twist, corner; + + +/* allocate and initialize global array twist_on_corner */ + +twist_on_corner[0] = + (unsigned short *)malloc(sizeof(unsigned short [N_TWIST][N_CORNER])); +if (twist_on_corner[0] == NULL) + exit_w_error_message("init_twist_on_corner : couldn't get memory"); + +for (twist = 1; twist < N_TWIST; twist++) + twist_on_corner[twist] = &twist_on_corner[0][twist * N_CORNER]; + +for (corner = 0; corner < N_CORNER; corner++) + { + twist_on_corner[TWIST_F][corner] = + (unsigned short)twist_f_on_corner(corner); + twist_on_corner[TWIST_R][corner] = + (unsigned short)twist_r_on_corner(corner); + twist_on_corner[TWIST_U][corner] = + (unsigned short)twist_u_on_corner(corner); + twist_on_corner[TWIST_B][corner] = + (unsigned short)twist_b_on_corner(corner); + twist_on_corner[TWIST_L][corner] = + (unsigned short)twist_l_on_corner(corner); + twist_on_corner[TWIST_D][corner] = + (unsigned short)twist_d_on_corner(corner); + } +for (corner = 0; corner < N_CORNER; corner++) + { + twist_on_corner[TWIST_F2][corner] = + twist_on_corner[TWIST_F][(int)twist_on_corner[TWIST_F][corner]]; + twist_on_corner[TWIST_R2][corner] = + twist_on_corner[TWIST_R][(int)twist_on_corner[TWIST_R][corner]]; + twist_on_corner[TWIST_U2][corner] = + twist_on_corner[TWIST_U][(int)twist_on_corner[TWIST_U][corner]]; + twist_on_corner[TWIST_B2][corner] = + twist_on_corner[TWIST_B][(int)twist_on_corner[TWIST_B][corner]]; + twist_on_corner[TWIST_L2][corner] = + twist_on_corner[TWIST_L][(int)twist_on_corner[TWIST_L][corner]]; + twist_on_corner[TWIST_D2][corner] = + twist_on_corner[TWIST_D][(int)twist_on_corner[TWIST_D][corner]]; + } +for (corner = 0; corner < N_CORNER; corner++) + { + twist_on_corner[TWIST_F3][corner] = + twist_on_corner[TWIST_F2][(int)twist_on_corner[TWIST_F][corner]]; + twist_on_corner[TWIST_R3][corner] = + twist_on_corner[TWIST_R2][(int)twist_on_corner[TWIST_R][corner]]; + twist_on_corner[TWIST_U3][corner] = + twist_on_corner[TWIST_U2][(int)twist_on_corner[TWIST_U][corner]]; + twist_on_corner[TWIST_B3][corner] = + twist_on_corner[TWIST_B2][(int)twist_on_corner[TWIST_B][corner]]; + twist_on_corner[TWIST_L3][corner] = + twist_on_corner[TWIST_L2][(int)twist_on_corner[TWIST_L][corner]]; + twist_on_corner[TWIST_D3][corner] = + twist_on_corner[TWIST_D2][(int)twist_on_corner[TWIST_D][corner]]; + } + +return; +} + + +/* ========================================================================= */ + int sym_cu_on_corner(int corner) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +corner_unpack(corner, temp_arr); +four_cycle(temp_arr, CORNER_UFR, CORNER_URB, CORNER_UBL, CORNER_ULF); +four_cycle(temp_arr, CORNER_DRF, CORNER_DBR, CORNER_DLB, CORNER_DFL); + +return corner_pack(temp_arr); +} + + +/* ========================================================================= */ + int sym_cf2_on_corner(int corner) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +corner_unpack(corner, temp_arr); +two_cycle(temp_arr, CORNER_UFR, CORNER_DFL); +two_cycle(temp_arr, CORNER_ULF, CORNER_DRF); +two_cycle(temp_arr, CORNER_UBL, CORNER_DBR); +two_cycle(temp_arr, CORNER_URB, CORNER_DLB); + +return corner_pack(temp_arr); +} + + +/* ========================================================================= */ + int sym_rud_on_corner(int corner) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8], ii; + + +corner_unpack(corner, temp_arr); +two_cycle(temp_arr, CORNER_UFR, CORNER_DRF); +two_cycle(temp_arr, CORNER_ULF, CORNER_DFL); +two_cycle(temp_arr, CORNER_UBL, CORNER_DLB); +two_cycle(temp_arr, CORNER_URB, CORNER_DBR); + +for (ii = 0; ii < 8; ii++) + temp_arr[ii] = (2 * temp_arr[ii]) % 3; + +return corner_pack(temp_arr); +} + + +/* ========================================================================= */ + void init_sym_on_corner(void) +/* ------------------------------------------------------------------------- */ + +{ +int corner, sym; + + +/* allocate and initialize global array sym_on_corner */ + +sym_on_corner[0] = + (unsigned short *)malloc(sizeof(unsigned short [N_SYM][N_CORNER])); +if (sym_on_corner[0] == NULL) + exit_w_error_message("init_sym_on_corner : couldn't get memory"); + +for (sym = 1; sym < N_SYM; sym++) + sym_on_corner[sym] = &sym_on_corner[0][sym * N_CORNER]; + +for (corner = 0; corner < N_CORNER; corner++) + sym_on_corner[0][corner] = (unsigned short)corner; + +for (corner = 0; corner < N_CORNER; corner++) + sym_on_corner[1][corner] = (unsigned short)sym_cu_on_corner(corner); + +for (sym = 2; sym < 4; sym++) + for (corner = 0; corner < N_CORNER; corner++) + sym_on_corner[sym][corner] = + sym_on_corner[1][(int)sym_on_corner[sym - 1][corner]]; + +for (corner = 0; corner < N_CORNER; corner++) + sym_on_corner[4][corner] = (unsigned short)sym_cf2_on_corner(corner); + +for (sym = 5; sym < 8; sym++) + for (corner = 0; corner < N_CORNER; corner++) + sym_on_corner[sym][corner] = + sym_on_corner[4][(int)sym_on_corner[sym - 4][corner]]; + +for (corner = 0; corner < N_CORNER; corner++) + sym_on_corner[8][corner] = (unsigned short)sym_rud_on_corner(corner); + +for (sym = 9; sym < 16; sym++) + for (corner = 0; corner < N_CORNER; corner++) + sym_on_corner[sym][corner] = + sym_on_corner[8][(int)sym_on_corner[sym - 8][corner]]; + +return; +} + + +/* ========================================================================= */ + void calc_edgeloc_conv(int conv_tab[N_ELOC], int unconv_tab[N_ELOC_CONV]) +/* ------------------------------------------------------------------------- */ + +{ +int ii, loc0, loc1, loc2, loc3, count; + + +for (ii = 0; ii < N_ELOC; ii++) + conv_tab[ii] = -1; + +for (ii = 0; ii < N_ELOC_CONV; ii++) + unconv_tab[ii] = -1; + +count = 0; +for (loc0 = 0; loc0 < 9; loc0++) + for (loc1 = loc0 + 1; loc1 < 10; loc1++) + for (loc2 = loc1 + 1; loc2 < 11; loc2++) + for (loc3 = loc2 + 1; loc3 < 12; loc3++) + { + if (count >= N_ELOC) + exit_w_error_message("calc_edgeloc_conv : too many eloc's"); + conv_tab[count] = (1 << loc0) | (1 << loc1) | + (1 << loc2) | (1 << loc3); + unconv_tab[conv_tab[count]] = count; + count++; + } + +if (count != N_ELOC) + exit_w_error_message("calc_edgeloc_conv : wrong number of eloc's"); + +return; +} + + +/* ========================================================================= */ + int edgeloc_conv_or_unconv(int eloc_conv_or_unconv, int convert_flag) +/* ------------------------------------------------------------------------- */ + +{ +static int eloc_conv[N_ELOC]; +static int eloc_unconv[N_ELOC_CONV]; +static int initialized = 0; +int el_conv, el_unconv; + + +if (initialized == 0) + { + calc_edgeloc_conv(eloc_conv, eloc_unconv); + initialized = 1; + } + +if (convert_flag) + { + if ((eloc_conv_or_unconv < 0) || (eloc_conv_or_unconv >= N_ELOC)) + exit_w_error_message("edgeloc_conv_or_unconv : invalid input"); + + el_conv = eloc_conv[eloc_conv_or_unconv]; + + if (el_conv < 0) + exit_w_error_message("edgeloc_conv_or_unconv : corrupted data"); + + return el_conv; + } +else + { + if ((eloc_conv_or_unconv < 0) || (eloc_conv_or_unconv >= N_ELOC_CONV)) + exit_w_error_message("edgeloc_conv_or_unconv : invalid input"); + + el_unconv = eloc_unconv[eloc_conv_or_unconv]; + + if (el_unconv < 0) + exit_w_error_message("edgeloc_conv_or_unconv : corrupted data"); + + return el_unconv; + } +} + + +/* ========================================================================= */ + int edgeloc_conv(int eloc_unconv) +/* ------------------------------------------------------------------------- */ + +{ +return edgeloc_conv_or_unconv(eloc_unconv, 1); +} + + +/* ========================================================================= */ + int edgeloc_unconv(int eloc_conv) +/* ------------------------------------------------------------------------- */ + +{ +return edgeloc_conv_or_unconv(eloc_conv, 0); +} + + +/* ========================================================================= */ + void eloc_unpack(int eloc, int array_out[12]) +/* ------------------------------------------------------------------------- */ + +/* input: eloc + output: array_out[] */ + +{ +int conv, ii; + + +conv = edgeloc_conv(eloc); + +for (ii = 0; ii < 12; ii++) + { + array_out[ii] = conv % 2; + conv = conv / 2; + } + +return; +} + + +/* ========================================================================= */ + int eloc_pack(int array_in[12]) +/* ------------------------------------------------------------------------- */ + +{ +int ii, conv; + + +conv = 0; +for (ii = 11; ii >= 0; ii--) + conv = 2 * conv + array_in[ii]; + +return edgeloc_unconv(conv); +} + + +/* ========================================================================= */ + int twist_f_on_eloc(int eloc) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eloc_unpack(eloc, temp_arr); +four_cycle(temp_arr, EDGE_FL, EDGE_DF, EDGE_FR, EDGE_UF); + +return eloc_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_r_on_eloc(int eloc) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eloc_unpack(eloc, temp_arr); +four_cycle(temp_arr, EDGE_FR, EDGE_DR, EDGE_BR, EDGE_UR); + +return eloc_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_u_on_eloc(int eloc) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eloc_unpack(eloc, temp_arr); +four_cycle(temp_arr, EDGE_UF, EDGE_UR, EDGE_UB, EDGE_UL); + +return eloc_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_b_on_eloc(int eloc) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eloc_unpack(eloc, temp_arr); +four_cycle(temp_arr, EDGE_BR, EDGE_DB, EDGE_BL, EDGE_UB); + +return eloc_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_l_on_eloc(int eloc) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eloc_unpack(eloc, temp_arr); +four_cycle(temp_arr, EDGE_BL, EDGE_DL, EDGE_FL, EDGE_UL); + +return eloc_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_d_on_eloc(int eloc) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eloc_unpack(eloc, temp_arr); +four_cycle(temp_arr, EDGE_DF, EDGE_DL, EDGE_DB, EDGE_DR); + +return eloc_pack(temp_arr); +} + + +/* ========================================================================= */ + void calc_twist_on_eloc(int table[N_TWIST][N_ELOC]) +/* ------------------------------------------------------------------------- */ + +{ +int edgeloc; + + +for (edgeloc = 0; edgeloc < N_ELOC; edgeloc++) + { + table[TWIST_F][edgeloc] = twist_f_on_eloc(edgeloc); + table[TWIST_R][edgeloc] = twist_r_on_eloc(edgeloc); + table[TWIST_U][edgeloc] = twist_u_on_eloc(edgeloc); + table[TWIST_B][edgeloc] = twist_b_on_eloc(edgeloc); + table[TWIST_L][edgeloc] = twist_l_on_eloc(edgeloc); + table[TWIST_D][edgeloc] = twist_d_on_eloc(edgeloc); + } + +perm_n_compose(N_ELOC, table[TWIST_F], table[TWIST_F], table[TWIST_F2]); +perm_n_compose(N_ELOC, table[TWIST_R], table[TWIST_R], table[TWIST_R2]); +perm_n_compose(N_ELOC, table[TWIST_U], table[TWIST_U], table[TWIST_U2]); +perm_n_compose(N_ELOC, table[TWIST_B], table[TWIST_B], table[TWIST_B2]); +perm_n_compose(N_ELOC, table[TWIST_L], table[TWIST_L], table[TWIST_L2]); +perm_n_compose(N_ELOC, table[TWIST_D], table[TWIST_D], table[TWIST_D2]); + +perm_n_compose(N_ELOC, table[TWIST_F2], table[TWIST_F], table[TWIST_F3]); +perm_n_compose(N_ELOC, table[TWIST_R2], table[TWIST_R], table[TWIST_R3]); +perm_n_compose(N_ELOC, table[TWIST_U2], table[TWIST_U], table[TWIST_U3]); +perm_n_compose(N_ELOC, table[TWIST_B2], table[TWIST_B], table[TWIST_B3]); +perm_n_compose(N_ELOC, table[TWIST_L2], table[TWIST_L], table[TWIST_L3]); +perm_n_compose(N_ELOC, table[TWIST_D2], table[TWIST_D], table[TWIST_D3]); + +return; +} + + +/* ========================================================================= */ + int sym_cu_on_eloc(int eloc) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eloc_unpack(eloc, temp_arr); +four_cycle(temp_arr, EDGE_UF, EDGE_UR, EDGE_UB, EDGE_UL); +four_cycle(temp_arr, EDGE_DF, EDGE_DR, EDGE_DB, EDGE_DL); +four_cycle(temp_arr, EDGE_FR, EDGE_BR, EDGE_BL, EDGE_FL); + +return eloc_pack(temp_arr); +} + + +/* ========================================================================= */ + int sym_cf2_on_eloc(int eloc) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eloc_unpack(eloc, temp_arr); +two_cycle(temp_arr, EDGE_UF, EDGE_DF); +two_cycle(temp_arr, EDGE_UR, EDGE_DL); +two_cycle(temp_arr, EDGE_UB, EDGE_DB); +two_cycle(temp_arr, EDGE_UL, EDGE_DR); +two_cycle(temp_arr, EDGE_FR, EDGE_FL); +two_cycle(temp_arr, EDGE_BR, EDGE_BL); + +return eloc_pack(temp_arr); +} + + +/* ========================================================================= */ + int sym_rud_on_eloc(int eloc) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eloc_unpack(eloc, temp_arr); +two_cycle(temp_arr, EDGE_UF, EDGE_DF); +two_cycle(temp_arr, EDGE_UR, EDGE_DR); +two_cycle(temp_arr, EDGE_UB, EDGE_DB); +two_cycle(temp_arr, EDGE_UL, EDGE_DL); + +return eloc_pack(temp_arr); +} + + +/* ========================================================================= */ + void calc_sym_on_eloc(int table[N_SYM][N_ELOC]) +/* ------------------------------------------------------------------------- */ + +{ +int edgeloc, sym; + + +perm_n_init(N_ELOC, table[0]); + +for (edgeloc = 0; edgeloc < N_ELOC; edgeloc++) + table[1][edgeloc] = sym_cu_on_eloc(edgeloc); + +for (sym = 2; sym < 4; sym++) + perm_n_compose(N_ELOC, table[1], table[sym - 1], table[sym]); + +for (edgeloc = 0; edgeloc < N_ELOC; edgeloc++) + table[4][edgeloc] = sym_cf2_on_eloc(edgeloc); + +for (sym = 5; sym < 8; sym++) + perm_n_compose(N_ELOC, table[4], table[sym - 4], table[sym]); + +for (edgeloc = 0; edgeloc < N_ELOC; edgeloc++) + table[8][edgeloc] = sym_rud_on_eloc(edgeloc); + +for (sym = 9; sym < 16; sym++) + perm_n_compose(N_ELOC, table[8], table[sym - 8], table[sym]); + +return; +} + + +/* ========================================================================= */ + void eflip_unpack(int eflip, int array_out[12]) +/* ------------------------------------------------------------------------- */ + +{ +int ii; + + +for (ii = 0; ii < 11; ii++) + { + array_out[ii] = eflip % 2; + eflip = eflip / 2; + } + +array_out[11] = (array_out[0] + array_out[1] + array_out[2] + array_out[3] + + array_out[4] + array_out[5] + array_out[6] + array_out[7] + + array_out[8] + array_out[9] + array_out[10]) % 2; + +return; +} + + +/* ========================================================================= */ + int eflip_pack(int array_in[12]) +/* ------------------------------------------------------------------------- */ + +{ +int eflip, ii; + + +eflip = 0; +for (ii = 10; ii >= 0; ii--) + eflip = 2 * eflip + array_in[ii]; + +return eflip; +} + + +/* ========================================================================= */ + void eflip_adjust(int array[12], int ind0, int ind1, int ind2, + int ind3) +/* ------------------------------------------------------------------------- */ + +{ +array[ind0] = 1 - array[ind0]; +array[ind1] = 1 - array[ind1]; +array[ind2] = 1 - array[ind2]; +array[ind3] = 1 - array[ind3]; + +return; +} + + +/* ========================================================================= */ + int twist_f_on_eflip(int eflip) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eflip_unpack(eflip, temp_arr); +four_cycle(temp_arr, EDGE_FL, EDGE_DF, EDGE_FR, EDGE_UF); +eflip_adjust(temp_arr, EDGE_FL, EDGE_DF, EDGE_FR, EDGE_UF); + +return eflip_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_r_on_eflip(int eflip) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eflip_unpack(eflip, temp_arr); +four_cycle(temp_arr, EDGE_FR, EDGE_DR, EDGE_BR, EDGE_UR); + +return eflip_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_u_on_eflip(int eflip) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eflip_unpack(eflip, temp_arr); +four_cycle(temp_arr, EDGE_UR, EDGE_UB, EDGE_UL, EDGE_UF); + +return eflip_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_b_on_eflip(int eflip) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eflip_unpack(eflip, temp_arr); +four_cycle(temp_arr, EDGE_BR, EDGE_DB, EDGE_BL, EDGE_UB); +eflip_adjust(temp_arr, EDGE_BR, EDGE_DB, EDGE_BL, EDGE_UB); + +return eflip_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_l_on_eflip(int eflip) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eflip_unpack(eflip, temp_arr); +four_cycle(temp_arr, EDGE_BL, EDGE_DL, EDGE_FL, EDGE_UL); + +return eflip_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_d_on_eflip(int eflip) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eflip_unpack(eflip, temp_arr); +four_cycle(temp_arr, EDGE_DL, EDGE_DB, EDGE_DR, EDGE_DF); + +return eflip_pack(temp_arr); +} + + +/* ========================================================================= */ + void calc_twist_on_eflip(int table[N_TWIST][N_EFLIP]) +/* ------------------------------------------------------------------------- */ + +{ +int edgeflip; + + +for (edgeflip = 0; edgeflip < N_EFLIP; edgeflip++) + { + table[TWIST_F][edgeflip] = twist_f_on_eflip(edgeflip); + table[TWIST_R][edgeflip] = twist_r_on_eflip(edgeflip); + table[TWIST_U][edgeflip] = twist_u_on_eflip(edgeflip); + table[TWIST_B][edgeflip] = twist_b_on_eflip(edgeflip); + table[TWIST_L][edgeflip] = twist_l_on_eflip(edgeflip); + table[TWIST_D][edgeflip] = twist_d_on_eflip(edgeflip); + } + +perm_n_compose(N_EFLIP, table[TWIST_F], table[TWIST_F], table[TWIST_F2]); +perm_n_compose(N_EFLIP, table[TWIST_R], table[TWIST_R], table[TWIST_R2]); +perm_n_compose(N_EFLIP, table[TWIST_U], table[TWIST_U], table[TWIST_U2]); +perm_n_compose(N_EFLIP, table[TWIST_B], table[TWIST_B], table[TWIST_B2]); +perm_n_compose(N_EFLIP, table[TWIST_L], table[TWIST_L], table[TWIST_L2]); +perm_n_compose(N_EFLIP, table[TWIST_D], table[TWIST_D], table[TWIST_D2]); + +perm_n_compose(N_EFLIP, table[TWIST_F2], table[TWIST_F], table[TWIST_F3]); +perm_n_compose(N_EFLIP, table[TWIST_R2], table[TWIST_R], table[TWIST_R3]); +perm_n_compose(N_EFLIP, table[TWIST_U2], table[TWIST_U], table[TWIST_U3]); +perm_n_compose(N_EFLIP, table[TWIST_B2], table[TWIST_B], table[TWIST_B3]); +perm_n_compose(N_EFLIP, table[TWIST_L2], table[TWIST_L], table[TWIST_L3]); +perm_n_compose(N_EFLIP, table[TWIST_D2], table[TWIST_D], table[TWIST_D3]); + +return; +} + + +/* ========================================================================= */ + int sym_cu2_on_eflip(int eflip) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eflip_unpack(eflip, temp_arr); +two_cycle(temp_arr, EDGE_UF, EDGE_UB); +two_cycle(temp_arr, EDGE_UR, EDGE_UL); +two_cycle(temp_arr, EDGE_DF, EDGE_DB); +two_cycle(temp_arr, EDGE_DR, EDGE_DL); +two_cycle(temp_arr, EDGE_FR, EDGE_BL); +two_cycle(temp_arr, EDGE_FL, EDGE_BR); + +return eflip_pack(temp_arr); +} + + +/* ========================================================================= */ + int sym_cf2_on_eflip(int eflip) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eflip_unpack(eflip, temp_arr); +two_cycle(temp_arr, EDGE_UF, EDGE_DF); +two_cycle(temp_arr, EDGE_UR, EDGE_DL); +two_cycle(temp_arr, EDGE_UB, EDGE_DB); +two_cycle(temp_arr, EDGE_UL, EDGE_DR); +two_cycle(temp_arr, EDGE_FR, EDGE_FL); +two_cycle(temp_arr, EDGE_BR, EDGE_BL); + +return eflip_pack(temp_arr); +} + + +/* ========================================================================= */ + int sym_rud_on_eflip(int eflip) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +eflip_unpack(eflip, temp_arr); +two_cycle(temp_arr, EDGE_UF, EDGE_DF); +two_cycle(temp_arr, EDGE_UR, EDGE_DR); +two_cycle(temp_arr, EDGE_UB, EDGE_DB); +two_cycle(temp_arr, EDGE_UL, EDGE_DL); + +return eflip_pack(temp_arr); +} + + +/* ========================================================================= */ + void calc_sym_on_eflip(int table[N_SYM / 2][N_EFLIP]) +/* ------------------------------------------------------------------------- */ + +{ +int edgeflip, sym; + + +perm_n_init(N_EFLIP, table[0]); + +for (edgeflip = 0; edgeflip < N_EFLIP; edgeflip++) + table[1][edgeflip] = sym_cu2_on_eflip(edgeflip); + +for (edgeflip = 0; edgeflip < N_EFLIP; edgeflip++) + table[2][edgeflip] = sym_cf2_on_eflip(edgeflip); + +perm_n_compose(N_EFLIP, table[2], table[1], table[3]); + +for (edgeflip = 0; edgeflip < N_EFLIP; edgeflip++) + table[4][edgeflip] = sym_rud_on_eflip(edgeflip); + +for (sym = 5; sym < 8; sym++) + perm_n_compose(N_EFLIP, table[4], table[sym - 4], table[sym]); + +return; +} + + +/* ========================================================================= */ + int sym_cu_on_fulledge(int fulledge) +/* ------------------------------------------------------------------------- */ + +{ +int edgeloc_arr[12], edgeflip_arr[12], temp_arr[12], ii; + + +eloc_unpack(fulledge / N_EFLIP, edgeloc_arr); +eflip_unpack(fulledge % N_EFLIP, edgeflip_arr); + +for (ii = 0; ii < 12; ii++) + temp_arr[ii] = (edgeloc_arr[ii] != edgeflip_arr[ii]); + +four_cycle(temp_arr, EDGE_UR, EDGE_UB, EDGE_UL, EDGE_UF); +four_cycle(temp_arr, EDGE_DR, EDGE_DB, EDGE_DL, EDGE_DF); +four_cycle(temp_arr, EDGE_BR, EDGE_BL, EDGE_FL, EDGE_FR); +eflip_adjust(temp_arr, EDGE_FR, EDGE_FL, EDGE_BR, EDGE_BL); + +return sym_cu_on_eloc(fulledge / N_EFLIP) * N_EFLIP + eflip_pack(temp_arr); +} + + +/* ========================================================================= */ + void init_fulledge_to_edgequot(int sym_on_eloc[N_SYM][N_ELOC], + int sym_on_eflip[N_SYM / 2][N_EFLIP], + int edge_to_fulledge[N_EDGEQUOT], + int stabilizers[N_EDGEQUOT], + int multiplicities[N_EDGEQUOT]) +/* ------------------------------------------------------------------------- */ + +{ +int count, sym_count, fulledge, cu_fulledge, sym, min_sym; +int min_full, new_full, stab; + + +fulledge_to_edge = + (unsigned short *)malloc(sizeof(unsigned short [N_FULLEDGE])); +fulledge_to_sym = (unsigned char *)malloc(sizeof(unsigned char [N_FULLEDGE])); + +if ((fulledge_to_edge == NULL) || (fulledge_to_sym == NULL)) + exit_w_error_message("init_fulledge_to_edgequot : couldn't get memory"); + +count = 0; + +for (fulledge = 0; fulledge < N_FULLEDGE; fulledge++) + { + min_full = fulledge; + min_sym = 0; + stab = 0; + sym_count = 0; + cu_fulledge = sym_cu_on_fulledge(fulledge); + + for (sym = 0; sym < (N_SYM / 2); sym++) + { + new_full = sym_on_eloc[2 * sym][fulledge / N_EFLIP] * N_EFLIP + + sym_on_eflip[sym][fulledge % N_EFLIP]; + if (min_full > new_full) + { + min_full = new_full; + min_sym = 2 * sym; + } + else if (min_full == new_full) + { + stab |= (1 << (2 * sym)); + sym_count++; + } + + new_full = sym_on_eloc[2 * sym][cu_fulledge / N_EFLIP] * N_EFLIP + + sym_on_eflip[sym][cu_fulledge % N_EFLIP]; + if (min_full > new_full) + { + min_full = new_full; + min_sym = 2 * sym + 1; + } + else if (min_full == new_full) + { + stab |= (1 << (2 * sym + 1)); + sym_count++; + } + } + + if (min_sym == 0) + { + if (count >= N_EDGEQUOT) + exit_w_error_message( + "init_fulledge_to_edgequot : too many edgequot's"); + edge_to_fulledge[count] = fulledge; + stabilizers[count] = stab; + multiplicities[count] = N_SYM / sym_count; + fulledge_to_edge[fulledge] = (unsigned short)count; + fulledge_to_sym[fulledge] = sym_x_invsym_to_sym[0][0]; + count++; + } + else + { + fulledge_to_edge[fulledge] = fulledge_to_edge[min_full]; + fulledge_to_sym[fulledge] = sym_x_invsym_to_sym[0][min_sym]; + } + } + +if (count != N_EDGEQUOT) + exit_w_error_message( + "init_fulledge_to_edgequot : wrong number of edgequot's"); + +return; +} + + +/* ========================================================================= */ + void init_twist_on_edge(int twist_on_eloc[N_TWIST][N_ELOC], + int twist_on_eflip[N_TWIST][N_EFLIP], + int edge_to_fulledge[N_EDGEQUOT]) +/* ------------------------------------------------------------------------- */ + +{ +int twist, edge, fulledge, new_edge; + + +/* allocate and initialize global arrays */ +/* twist_on_edge and twist_x_edge_to_sym */ + +twist_on_edge[0] = + (unsigned short *)malloc(sizeof(unsigned short [N_TWIST][N_EDGEQUOT])); +twist_x_edge_to_sym[0] = + (unsigned char *)malloc(sizeof(unsigned char [N_TWIST][N_EDGEQUOT])); + +if ((twist_on_edge[0] == NULL) || (twist_x_edge_to_sym[0] == NULL)) + exit_w_error_message("init_twist_on_edge : couldn't get memory"); + +for (twist = 1; twist < N_TWIST; twist++) + { + twist_on_edge[twist] = &twist_on_edge[0][twist * N_EDGEQUOT]; + twist_x_edge_to_sym[twist] = &twist_x_edge_to_sym[0][twist * N_EDGEQUOT]; + } + +for (twist = 0; twist < N_TWIST; twist++) + for (edge = 0; edge < N_EDGEQUOT; edge++) + { + fulledge = edge_to_fulledge[edge]; + new_edge = twist_on_eloc[twist][fulledge / N_EFLIP] * N_EFLIP + + twist_on_eflip[twist][fulledge % N_EFLIP]; + twist_on_edge[twist][edge] = fulledge_to_edge[new_edge]; + twist_x_edge_to_sym[twist][edge] = + sym_x_invsym_to_sym[0][(int)fulledge_to_sym[new_edge]]; + } + +return; +} + + +/* ========================================================================= */ + void init_edge_quotient(int stabilizers[N_EDGEQUOT], + int multiplicities[N_EDGEQUOT]) +/* ------------------------------------------------------------------------- */ + +{ +int twist_on_eloc[N_TWIST][N_ELOC]; +int twist_on_eflip[N_TWIST][N_EFLIP]; +int sym_on_eloc[N_SYM][N_ELOC]; +int sym_on_eflip[N_SYM / 2][N_EFLIP]; +int edge_to_fulledge[N_EDGEQUOT]; + + +calc_twist_on_eloc(twist_on_eloc); +calc_sym_on_eloc(sym_on_eloc); +calc_twist_on_eflip(twist_on_eflip); +calc_sym_on_eflip(sym_on_eflip); +init_fulledge_to_edgequot(sym_on_eloc, sym_on_eflip, edge_to_fulledge, + stabilizers, multiplicities); +init_twist_on_edge(twist_on_eloc, twist_on_eflip, edge_to_fulledge); + +return; +} + + +/* ========================================================================= */ + void cornerperm_unpack(int cperm, int array_out[8]) +/* ------------------------------------------------------------------------- */ + +{ +perm_n_unpack(8, cperm, array_out); + +return; +} + + +/* ========================================================================= */ + int cornerperm_pack(int array_in[8]) +/* ------------------------------------------------------------------------- */ + +{ +return perm_n_pack(8, array_in); +} + + +/* ========================================================================= */ + int twist_f_on_cperm(int cperm) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +cornerperm_unpack(cperm, temp_arr); +four_cycle(temp_arr, CORNER_DFL, CORNER_DRF, CORNER_UFR, CORNER_ULF); + +return cornerperm_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_r_on_cperm(int cperm) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +cornerperm_unpack(cperm, temp_arr); +four_cycle(temp_arr, CORNER_DRF, CORNER_DBR, CORNER_URB, CORNER_UFR); + +return cornerperm_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_u_on_cperm(int cperm) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +cornerperm_unpack(cperm, temp_arr); +four_cycle(temp_arr, CORNER_URB, CORNER_UBL, CORNER_ULF, CORNER_UFR); + +return cornerperm_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_b_on_cperm(int cperm) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +cornerperm_unpack(cperm, temp_arr); +four_cycle(temp_arr, CORNER_DBR, CORNER_DLB, CORNER_UBL, CORNER_URB); + +return cornerperm_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_l_on_cperm(int cperm) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +cornerperm_unpack(cperm, temp_arr); +four_cycle(temp_arr, CORNER_DLB, CORNER_DFL, CORNER_ULF, CORNER_UBL); + +return cornerperm_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_d_on_cperm(int cperm) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[8]; + + +cornerperm_unpack(cperm, temp_arr); +four_cycle(temp_arr, CORNER_DFL, CORNER_DLB, CORNER_DBR, CORNER_DRF); + +return cornerperm_pack(temp_arr); +} + + +/* ========================================================================= */ + void init_twist_on_cornerperm(void) +/* ------------------------------------------------------------------------- */ + +{ +int cp, twist; + + +/* allocate and initialize global array twist_on_cornerperm */ + +twist_on_cornerperm[0] = + (unsigned short *)malloc(sizeof(unsigned short [N_TWIST][N_CORNERPERM])); +if (twist_on_cornerperm[0] == NULL) + exit_w_error_message("init_twist_on_cornerperm : couldn't get memory"); + +for (twist = 1; twist < N_TWIST; twist++) + twist_on_cornerperm[twist] = &twist_on_cornerperm[0][twist * N_CORNERPERM]; + +for (cp = 0; cp < N_CORNERPERM; cp++) + { + twist_on_cornerperm[TWIST_F][cp] = (unsigned short)twist_f_on_cperm(cp); + twist_on_cornerperm[TWIST_R][cp] = (unsigned short)twist_r_on_cperm(cp); + twist_on_cornerperm[TWIST_U][cp] = (unsigned short)twist_u_on_cperm(cp); + twist_on_cornerperm[TWIST_B][cp] = (unsigned short)twist_b_on_cperm(cp); + twist_on_cornerperm[TWIST_L][cp] = (unsigned short)twist_l_on_cperm(cp); + twist_on_cornerperm[TWIST_D][cp] = (unsigned short)twist_d_on_cperm(cp); + } +for (cp = 0; cp < N_CORNERPERM; cp++) + { + twist_on_cornerperm[TWIST_F2][cp] = + twist_on_cornerperm[TWIST_F][(int)twist_on_cornerperm[TWIST_F][cp]]; + twist_on_cornerperm[TWIST_R2][cp] = + twist_on_cornerperm[TWIST_R][(int)twist_on_cornerperm[TWIST_R][cp]]; + twist_on_cornerperm[TWIST_U2][cp] = + twist_on_cornerperm[TWIST_U][(int)twist_on_cornerperm[TWIST_U][cp]]; + twist_on_cornerperm[TWIST_B2][cp] = + twist_on_cornerperm[TWIST_B][(int)twist_on_cornerperm[TWIST_B][cp]]; + twist_on_cornerperm[TWIST_L2][cp] = + twist_on_cornerperm[TWIST_L][(int)twist_on_cornerperm[TWIST_L][cp]]; + twist_on_cornerperm[TWIST_D2][cp] = + twist_on_cornerperm[TWIST_D][(int)twist_on_cornerperm[TWIST_D][cp]]; + } +for (cp = 0; cp < N_CORNERPERM; cp++) + { + twist_on_cornerperm[TWIST_F3][cp] = + twist_on_cornerperm[TWIST_F2][(int)twist_on_cornerperm[TWIST_F][cp]]; + twist_on_cornerperm[TWIST_R3][cp] = + twist_on_cornerperm[TWIST_R2][(int)twist_on_cornerperm[TWIST_R][cp]]; + twist_on_cornerperm[TWIST_U3][cp] = + twist_on_cornerperm[TWIST_U2][(int)twist_on_cornerperm[TWIST_U][cp]]; + twist_on_cornerperm[TWIST_B3][cp] = + twist_on_cornerperm[TWIST_B2][(int)twist_on_cornerperm[TWIST_B][cp]]; + twist_on_cornerperm[TWIST_L3][cp] = + twist_on_cornerperm[TWIST_L2][(int)twist_on_cornerperm[TWIST_L][cp]]; + twist_on_cornerperm[TWIST_D3][cp] = + twist_on_cornerperm[TWIST_D2][(int)twist_on_cornerperm[TWIST_D][cp]]; + } + +return; +} + + +/* ========================================================================= */ + void sliceedge_unpack(int sliceedge, int array_out[12]) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[4], ii, count; + + +eloc_unpack(sliceedge % N_ELOC, array_out); +perm_n_unpack(4, sliceedge / N_ELOC, temp_arr); + +count = 0; +for (ii = 0; ii < 12; ii++) + if (array_out[ii] != 0) + { + if (count >= 4) + exit_w_error_message("sliceedge_unpack : corrupted data"); + + array_out[ii] = 1 + temp_arr[count++]; + } + +return; +} + + +/* ========================================================================= */ + int sliceedge_pack(int array_in[12]) +/* ------------------------------------------------------------------------- */ + +{ +int eloc_arr[12], temp_arr[4], ii, count; + + +count = 0; +for (ii = 0; ii < 12; ii++) + { + if (array_in[ii] != 0) + { + if (count >= 4) + exit_w_error_message("sliceedge_pack : invalid input"); + + temp_arr[count++] = array_in[ii] - 1; + } + + eloc_arr[ii] = (array_in[ii] != 0); + } + +return perm_n_pack(4, temp_arr) * N_ELOC + eloc_pack(eloc_arr); +} + + +/* ========================================================================= */ + int twist_f_on_sliceedge(int sliceedge) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +sliceedge_unpack(sliceedge, temp_arr); +four_cycle(temp_arr, EDGE_FL, EDGE_DF, EDGE_FR, EDGE_UF); + +return sliceedge_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_r_on_sliceedge(int sliceedge) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +sliceedge_unpack(sliceedge, temp_arr); +four_cycle(temp_arr, EDGE_FR, EDGE_DR, EDGE_BR, EDGE_UR); + +return sliceedge_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_u_on_sliceedge(int sliceedge) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +sliceedge_unpack(sliceedge, temp_arr); +four_cycle(temp_arr, EDGE_UR, EDGE_UB, EDGE_UL, EDGE_UF); + +return sliceedge_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_b_on_sliceedge(int sliceedge) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +sliceedge_unpack(sliceedge, temp_arr); +four_cycle(temp_arr, EDGE_BR, EDGE_DB, EDGE_BL, EDGE_UB); + +return sliceedge_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_l_on_sliceedge(int sliceedge) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +sliceedge_unpack(sliceedge, temp_arr); +four_cycle(temp_arr, EDGE_BL, EDGE_DL, EDGE_FL, EDGE_UL); + +return sliceedge_pack(temp_arr); +} + + +/* ========================================================================= */ + int twist_d_on_sliceedge(int sliceedge) +/* ------------------------------------------------------------------------- */ + +{ +int temp_arr[12]; + + +sliceedge_unpack(sliceedge, temp_arr); +four_cycle(temp_arr, EDGE_DL, EDGE_DB, EDGE_DR, EDGE_DF); + +return sliceedge_pack(temp_arr); +} + + +/* ========================================================================= */ + void init_twist_on_sliceedge(void) +/* ------------------------------------------------------------------------- */ + +{ +int twist, sl; + + +/* allocate and initialize global array twist_on_sliceedge */ + +twist_on_sliceedge[0] = + (unsigned short *)malloc(sizeof(unsigned short [N_TWIST][N_SLICEEDGE])); +if (twist_on_sliceedge[0] == NULL) + exit_w_error_message("init_twist_on_sliceedge : couldn't get memory"); + +for (twist = 1; twist < N_TWIST; twist++) + twist_on_sliceedge[twist] = &twist_on_sliceedge[0][twist * N_SLICEEDGE]; + +for (sl = 0; sl < N_SLICEEDGE; sl++) + { + twist_on_sliceedge[TWIST_F][sl] = (unsigned short)twist_f_on_sliceedge(sl); + twist_on_sliceedge[TWIST_R][sl] = (unsigned short)twist_r_on_sliceedge(sl); + twist_on_sliceedge[TWIST_U][sl] = (unsigned short)twist_u_on_sliceedge(sl); + twist_on_sliceedge[TWIST_B][sl] = (unsigned short)twist_b_on_sliceedge(sl); + twist_on_sliceedge[TWIST_L][sl] = (unsigned short)twist_l_on_sliceedge(sl); + twist_on_sliceedge[TWIST_D][sl] = (unsigned short)twist_d_on_sliceedge(sl); + } +for (sl = 0; sl < N_SLICEEDGE; sl++) + { + twist_on_sliceedge[TWIST_F2][sl] = + twist_on_sliceedge[TWIST_F][(int)twist_on_sliceedge[TWIST_F][sl]]; + twist_on_sliceedge[TWIST_R2][sl] = + twist_on_sliceedge[TWIST_R][(int)twist_on_sliceedge[TWIST_R][sl]]; + twist_on_sliceedge[TWIST_U2][sl] = + twist_on_sliceedge[TWIST_U][(int)twist_on_sliceedge[TWIST_U][sl]]; + twist_on_sliceedge[TWIST_B2][sl] = + twist_on_sliceedge[TWIST_B][(int)twist_on_sliceedge[TWIST_B][sl]]; + twist_on_sliceedge[TWIST_L2][sl] = + twist_on_sliceedge[TWIST_L][(int)twist_on_sliceedge[TWIST_L][sl]]; + twist_on_sliceedge[TWIST_D2][sl] = + twist_on_sliceedge[TWIST_D][(int)twist_on_sliceedge[TWIST_D][sl]]; + } +for (sl = 0; sl < N_SLICEEDGE; sl++) + { + twist_on_sliceedge[TWIST_F3][sl] = + twist_on_sliceedge[TWIST_F2][(int)twist_on_sliceedge[TWIST_F][sl]]; + twist_on_sliceedge[TWIST_R3][sl] = + twist_on_sliceedge[TWIST_R2][(int)twist_on_sliceedge[TWIST_R][sl]]; + twist_on_sliceedge[TWIST_U3][sl] = + twist_on_sliceedge[TWIST_U2][(int)twist_on_sliceedge[TWIST_U][sl]]; + twist_on_sliceedge[TWIST_B3][sl] = + twist_on_sliceedge[TWIST_B2][(int)twist_on_sliceedge[TWIST_B][sl]]; + twist_on_sliceedge[TWIST_L3][sl] = + twist_on_sliceedge[TWIST_L2][(int)twist_on_sliceedge[TWIST_L][sl]]; + twist_on_sliceedge[TWIST_D3][sl] = + twist_on_sliceedge[TWIST_D2][(int)twist_on_sliceedge[TWIST_D][sl]]; + } + +return; +} + + +/* ========================================================================= */ + int make_current(int corner, int edge, Search_data *p_data) +/* ------------------------------------------------------------------------- */ + +{ +if (DIST(corner, edge) > p_data->depth) + { + if (edge & 0x1) + { + distance[corner][edge >> 1] &= 0x0F; + distance[corner][edge >> 1] |= (unsigned char)((p_data->depth) << 4); + } + else + { + distance[corner][edge >> 1] &= 0xF0; + distance[corner][edge >> 1] |= (unsigned char)(p_data->depth); + } + + p_data->found_quot++; + p_data->found += (p_data->multiplicities)[edge]; + + return 1; + } + +return 0; +} + + +/* ========================================================================= */ + void make_current_all(int corner, int edge, Search_data *p_data) +/* ------------------------------------------------------------------------- */ + +{ +int sym, stab; + + +if (make_current(corner, edge, p_data)) + { + stab = (p_data->stabilizers)[edge]; + for (sym = 1; sym < N_SYM; sym++) + { + stab /= 2; + + if (stab % 2) + make_current((int)sym_on_corner[sym][corner], edge, p_data); + } + } + +return; +} + + +/* ========================================================================= */ + void make_neighbors_current(int corner, int edge, Search_data *p_data) +/* ------------------------------------------------------------------------- */ + +{ +int twist, new_edge, new_corner, sym; + + +for (twist = 0; twist < N_TWIST; twist++) + { + if (p_current_metric->twist_length[twist] != 1) + continue; + + new_edge = (int)twist_on_edge[twist][edge]; + sym = (int)twist_x_edge_to_sym[twist][edge]; + new_corner = (int)sym_on_corner[sym][(int)twist_on_corner[twist][corner]]; + make_current_all(new_corner, new_edge, p_data); + } + +return; +} + + +/* ========================================================================= */ + int neighbors_are_previous(int corner, int edge, Search_data *p_data) +/* ------------------------------------------------------------------------- */ + +{ +int twist, new_edge, sym, new_corner; + + +for (twist = 0; twist < N_TWIST; twist++) + { + if (p_current_metric->twist_length[twist] != 1) + continue; + + new_edge = (int)twist_on_edge[twist][edge]; + sym = (int)twist_x_edge_to_sym[twist][edge]; + new_corner = (int)sym_on_corner[sym][(int)twist_on_corner[twist][corner]]; + + if (DIST(new_corner, new_edge) < p_data->depth) + return 1; + } + +return 0; +} + + +/* ========================================================================= */ + void init_distance_table(int edge_stabilizers[N_EDGEQUOT], + int edge_multiplicities[N_EDGEQUOT]) +/* ------------------------------------------------------------------------- */ + +{ +Search_data sdata_struc; +int total_found_quot, corner, edge, ii, msg_given; + + +/* allocate and initialize global array distance */ + +distance[0] = (unsigned char *)malloc(sizeof(unsigned char [N_DIST_CHARS])); +if (distance[0] == NULL) + exit_w_error_message("init_distance_table : couldn't get memory"); + +for (corner = 1; corner < N_CORNER; corner++) + distance[corner] = &distance[0][corner * (N_EDGEQUOT / 2)]; + +for (ii = 0; ii < N_DIST_CHARS; ii++) + distance[0][ii] = (unsigned char)255; + +msg_given = 0; + +sdata_struc.depth = 0; +sdata_struc.found_quot = 0; +sdata_struc.found = 0; +sdata_struc.stabilizers = edge_stabilizers; +sdata_struc.multiplicities = edge_multiplicities; +total_found_quot = 0; + +printf("distance positions (quotient)\n"); + +make_current_all(CORNER_START, EDGE_START, &sdata_struc); + +while (sdata_struc.found) + { + printf("%7d%c %13d (%8d)\n", sdata_struc.depth, + p_current_metric->metric_char, sdata_struc.found, + sdata_struc.found_quot); + total_found_quot += sdata_struc.found_quot; + sdata_struc.found_quot = 0; + sdata_struc.found = 0; + + if (++(sdata_struc.depth) == 15) + break; /* shouldn't happen */ + + if (total_found_quot == 2 * N_DIST_CHARS) + break; + + if (total_found_quot < BACKWARDS_SWITCH_POINT) /* search forward */ + { + for (corner = 0; corner < N_CORNER; corner++) + for (edge = 0; edge < N_EDGEQUOT; edge++) + if (DIST(corner, edge) == sdata_struc.depth - 1) + make_neighbors_current(corner, edge, &sdata_struc); + } + else /* search backward */ + { + if (msg_given == 0) + { + printf(" switching to backwards searching\n"); + msg_given = 1; + } + + for (corner = 0; corner < N_CORNER; corner++) + for (edge = 0; edge < N_EDGEQUOT; edge++) + if ((DIST(corner, edge) == 15) && + neighbors_are_previous(corner, edge, &sdata_struc)) + make_current_all(corner, edge, &sdata_struc); + } + } + +return; +} + + +/* ========================================================================= */ + void init_globals(void) +/* ------------------------------------------------------------------------- */ + +{ +int *edge_stabilizers; +int *edge_multiplicities; + + +printf("initializing transformation tables\n"); +init_sym_x_invsym_to_sym(); +init_invsym_on_twist(); +init_twist_on_follow(); +init_twist_on_corner(); +init_sym_on_corner(); + +edge_stabilizers = (int *)malloc(sizeof(int [2 * N_EDGEQUOT])); +if (edge_stabilizers == NULL) + exit_w_error_message("init_globals : couldn't get memory"); + +edge_multiplicities = &edge_stabilizers[N_EDGEQUOT]; + +init_edge_quotient(edge_stabilizers, edge_multiplicities); +init_twist_on_cornerperm(); +init_twist_on_sliceedge(); +printf("initializing distance table ... this will take several minutes\n"); +init_distance_table(edge_stabilizers, edge_multiplicities); + +free((void *)edge_stabilizers); + +return; +} + + +/* ========================================================================= */ + int string_to_cube(char string[], Cube *p_cube, int give_err_msg) +/* ------------------------------------------------------------------------- */ + +/* input: string[] */ + +{ +char edge_str[12][3], corner_str[8][4]; +int edge_arr[12], corner_arr[8]; +int ii, jj, twist, flip, edge_par, corner_par, stat; + + +stat = 0; + +if (sscanf(string, "%2s %2s %2s %2s %2s %2s %2s %2s %2s %2s %2s %2s %3s %3s %3s %3s %3s %3s %3s %3s", + edge_str[0], edge_str[1], edge_str[2], edge_str[3], + edge_str[4], edge_str[5], edge_str[6], edge_str[7], + edge_str[8], edge_str[9], edge_str[10], edge_str[11], + corner_str[0], corner_str[1], corner_str[2], corner_str[3], + corner_str[4], corner_str[5], corner_str[6], corner_str[7]) < 20) + { + if (give_err_msg) + printf("invalid input!\n"); + return 1; + } + +for (ii = 0; ii < 12; ii++) + { + for (jj = 0; jj < 24; jj++) + if (strcmp(edge_str[ii], edge_cubie_str[jj]) == 0) + { + p_cube->edges[ii] = jj; + break; + } + if (jj == 24) + { + if (give_err_msg) + printf("invalid edge cubie: %s\n", edge_str[ii]); + stat = 1; + } + } + +for (ii = 0; ii < 8; ii++) + { + for (jj = 0; jj < 24; jj++) + if (strcmp(corner_str[ii], corner_cubie_str[jj]) == 0) + { + p_cube->corners[ii] = jj; + break; + } + if (jj == 24) + { + if (give_err_msg) + printf("invalid corner cubie: %s\n", corner_str[ii]); + stat = 1; + } + } + +if (stat) + return stat; + +/* fill out the remaining oriented edges and corners */ + +for (ii = 12; ii < 24; ii++) + p_cube->edges[ii] = (12 + p_cube->edges[ii - 12]) % 24; + +for (ii = 8; ii < 24; ii++) + p_cube->corners[ii] = (8 + p_cube->corners[ii - 8]) % 24; + +/* now check to see that it's a legal cube */ + +if (perm_n_check(24, p_cube->edges)) + { + if (give_err_msg) + printf("bad edge cubies\n"); + stat = 1; + } + +if (perm_n_check(24, p_cube->corners)) + { + if (give_err_msg) + printf("bad corner cubies\n"); + stat = 1; + } + +if (stat) + return stat; + +flip = 0; +for (ii = 0; ii < 12; ii++) + flip += (p_cube->edges[ii] / 12); + +if ((flip % 2) != 0) + { + if (give_err_msg) + printf("flip any edge cubie!\n"); + stat = 1; + } + +twist = 0; +for (ii = 0; ii < 8; ii++) + twist += (p_cube->corners[ii] / 8); + +twist %= 3; + +if (twist != 0) + { + if (give_err_msg) + printf("twist any corner cubie %sclockwise!\n", + (twist == 1) ? "counter" : ""); + stat = 1; + } + +for (ii = 0; ii < 12; ii++) + edge_arr[ii] = p_cube->edges[ii] % 12; + +edge_par = perm_n_parity(12, edge_arr); + +for (ii = 0; ii < 8; ii++) + corner_arr[ii] = p_cube->corners[ii] % 8; + +corner_par = perm_n_parity(8, corner_arr); + +if (edge_par != corner_par) + { + if (give_err_msg) + printf("swap any two edge cubies or any two corner cubies!\n"); + stat = 1; + } + +return stat; +} + + +/* ========================================================================= */ + int user_enters_cube(Cube *p_cube) +/* ------------------------------------------------------------------------- */ + +{ +char line_str[256]; + + +printf("\nenter cube (Ctrl-D to exit):\n"); + +line_str[0] = '\n'; + +while (line_str[0] == '\n') /* ignore blank lines */ + { + if (fgets(line_str, 256, stdin) == NULL) + return -1; + + if (line_str[0] == '%') /* echo comments */ + { + printf("%s", line_str); + line_str[0] = '\n'; + } + } + +return string_to_cube(line_str, p_cube, 1); +} + + +/* ========================================================================= */ + void calc_cube_urf(Cube *p_cube) +/* ------------------------------------------------------------------------- */ + +{ +cube_init(p_cube); +three_cycle(p_cube->edges, EDGE_UF, EDGE_FR, EDGE_RU); +three_cycle(p_cube->edges, EDGE_UB, EDGE_FL, EDGE_RD); +three_cycle(p_cube->edges, EDGE_DB, EDGE_BL, EDGE_LD); +three_cycle(p_cube->edges, EDGE_DF, EDGE_BR, EDGE_LU); +three_cycle(p_cube->edges, EDGE_FU, EDGE_RF, EDGE_UR); +three_cycle(p_cube->edges, EDGE_BU, EDGE_LF, EDGE_DR); +three_cycle(p_cube->edges, EDGE_BD, EDGE_LB, EDGE_DL); +three_cycle(p_cube->edges, EDGE_FD, EDGE_RB, EDGE_UL); +three_cycle(p_cube->corners, CORNER_UFR, CORNER_FRU, CORNER_RUF); +three_cycle(p_cube->corners, CORNER_DLB, CORNER_BDL, CORNER_LBD); +three_cycle(p_cube->corners, CORNER_URB, CORNER_FUL, CORNER_RFD); +three_cycle(p_cube->corners, CORNER_UBL, CORNER_FLD, CORNER_RDB); +three_cycle(p_cube->corners, CORNER_RBU, CORNER_ULF, CORNER_FDR); +three_cycle(p_cube->corners, CORNER_BLU, CORNER_LDF, CORNER_DBR); +three_cycle(p_cube->corners, CORNER_BUR, CORNER_LFU, CORNER_DRF); +three_cycle(p_cube->corners, CORNER_LUB, CORNER_DFL, CORNER_BRD); + +return; +} + + +/* ========================================================================= */ + void cube_to_coset_coord(Cube *p_cube, Coset_coord *p_coset_coord) +/* ------------------------------------------------------------------------- */ + +/* output: *p_coset_coord */ + +{ +int corner_arr[8], edge_arr[12]; +int ii, eflip, eloc, sym, corner; + + +for (ii = 0; ii < 12; ii++) + edge_arr[ii] = p_cube->edges[ii] / 12; +eflip = eflip_pack(edge_arr); + +for (ii = 0; ii < 12; ii++) + edge_arr[ii] = (p_cube->edges[ii] % 12) / 8; +eloc = eloc_pack(edge_arr); + +p_coset_coord->edge_state = (int)fulledge_to_edge[eloc * N_EFLIP + eflip]; +p_coset_coord->sym_state = sym = (int)fulledge_to_sym[eloc * N_EFLIP + eflip]; + +for (ii = 0; ii < 8; ii++) + corner_arr[ii] = p_cube->corners[ii] / 8; + +corner = corner_pack(corner_arr); +p_coset_coord->corner_state = + (int)sym_on_corner[(int)sym_x_invsym_to_sym[0][sym]][corner]; + +return; +} + + +/* ========================================================================= */ + void process_full_cube(Full_cube *p_cube) +/* ------------------------------------------------------------------------- */ + +{ +Cube cube1, cube2, cube_urf; +int edges_to_ud[12], edges_to_rl[12], edges_to_fb[12]; +int cornerperm_arr[8], sliceedge_arr[12], ii; + + +/* p_cube->cubies already filled in */ +/* fill in other fields of p_cube */ + +for (ii = 0; ii < 8; ii++) + cornerperm_arr[ii] = p_cube->cubies.corners[ii] % 8; + +p_cube->cornerperm = cornerperm_pack(cornerperm_arr); +p_cube->parity = perm_n_parity(8, cornerperm_arr); + + +for (ii = 0; ii < 12; ii++) + edges_to_ud[ii] = edges_to_fb[ii] = edges_to_rl[ii] = 0; + +edges_to_ud[EDGE_FR] = 1; +edges_to_ud[EDGE_FL] = 2; +edges_to_ud[EDGE_BR] = 3; +edges_to_ud[EDGE_BL] = 4; + +edges_to_rl[EDGE_UF] = 1; +edges_to_rl[EDGE_UB] = 2; +edges_to_rl[EDGE_DF] = 3; +edges_to_rl[EDGE_DB] = 4; + +edges_to_fb[EDGE_UR] = 1; +edges_to_fb[EDGE_UL] = 2; +edges_to_fb[EDGE_DR] = 3; +edges_to_fb[EDGE_DL] = 4; + + +for (ii = 0; ii < 12; ii++) + sliceedge_arr[ii] = edges_to_ud[(p_cube->cubies.edges[ii]) % 12]; +p_cube->ud_sliceedge = sliceedge_pack(sliceedge_arr); + +for (ii = 0; ii < 12; ii++) + sliceedge_arr[ii] = edges_to_fb[(p_cube->cubies.edges[ii]) % 12]; +p_cube->fb_sliceedge = sliceedge_pack(sliceedge_arr); + +for (ii = 0; ii < 12; ii++) + sliceedge_arr[ii] = edges_to_rl[(p_cube->cubies.edges[ii]) % 12]; +p_cube->rl_sliceedge = sliceedge_pack(sliceedge_arr); + + +cube_to_coset_coord(&p_cube->cubies, &p_cube->ud); + +calc_cube_urf(&cube_urf); + +cube_conjugate(&p_cube->cubies, &cube_urf, &cube1); +cube_to_coset_coord(&cube1, &p_cube->rl); + +cube_conjugate(&cube1, &cube_urf, &cube2); +cube_to_coset_coord(&cube2, &p_cube->fb); + +return; +} + + +/* ========================================================================= */ + void set_cube_symmetry(Full_cube *p_cube, Cube sym_cubes[N_CUBESYM], + int subgroup_list[N_SYMSUBGRP][N_CUBESYM]) +/* ------------------------------------------------------------------------- */ + +{ +Cube temp_cube; +int subgroup[N_CUBESYM], sym, count; + + +if (p_current_options->use_symmetry) + { + count = 0; + + for (sym = 0; sym < N_CUBESYM; sym++) + { + cube_conjugate(&p_cube->cubies, &sym_cubes[sym], &temp_cube); + subgroup[sym] = (cube_compare(&p_cube->cubies, &temp_cube) == 0); + if (subgroup[sym]) + count++; + } + + p_cube->sym_subgrp = which_subgroup(subgroup, subgroup_list); + + if (p_cube->sym_subgrp < 0) + exit_w_error_message("set_cube_symmetry : unknown symmetry group"); + + if (count > 1) + printf("position has %d-fold symmetry (subgroup #%d)\n", count, + p_cube->sym_subgrp); + else + printf("asymmetric position\n"); + } +else + p_cube->sym_subgrp = SUBGRP_TRIVIAL; + +return; +} + + +/* ========================================================================= */ + void output_solution(Search_node *node_arr) +/* ------------------------------------------------------------------------- */ + +{ +static char *twist_string[] = {"F ", "F2", "F'", "R ", "R2", "R'", + "U ", "U2", "U'", "B ", "B2", "B'", + "L ", "L2", "L'", "D ", "D2", "D'"}; +Search_node *p_node; +int turn_list[MAX_TWISTS]; +int ii, count, q_length, f_length; + + +count = 0; + +for (p_node = node_arr; p_node->remain_depth > 0; p_node++) + turn_list[count++] = p_node[1].twist; + +q_length = f_length = 0; + +for (ii = 0; ii < count; ii++) + { + q_length += metric_q_length(turn_list[ii]); + f_length += metric_f_length(turn_list[ii]); + } + +for (ii = 0; ii < count; ii++) + printf(" %s", twist_string[turn_list[ii]]); + +if (p_current_metric->metric == QUARTER_TURN_METRIC) + printf(" (%dq*, %df)\n", q_length, f_length); +else + printf(" (%df*, %dq)\n", f_length, q_length); +fflush(stdout); + +sol_found = 1; + +return; +} + + +/* ========================================================================= */ + int test_for_solution(Full_cube *p_cube, Search_node *node_arr) +/* ------------------------------------------------------------------------- */ + +{ +register Search_node *p_node; +register int cornerperm, sliceedge; + + +n_tests++; + +cornerperm = p_cube->cornerperm; +for (p_node = node_arr; p_node->remain_depth > 0; p_node++) + cornerperm = (int)twist_on_cornerperm[p_node[1].twist][cornerperm]; + +if (cornerperm != CORNERPERM_START) + return 0; /* not a solution */ + +sliceedge = p_cube->ud_sliceedge; +for (p_node = node_arr; p_node->remain_depth > 0; p_node++) + sliceedge = (int)twist_on_sliceedge[p_node[1].twist][sliceedge]; + +if (sliceedge != UD_SLICEEDGE_START) + return 0; /* not a solution */ + +sliceedge = p_cube->rl_sliceedge; +for (p_node = node_arr; p_node->remain_depth > 0; p_node++) + sliceedge = (int)twist_on_sliceedge[p_node[1].twist][sliceedge]; + +if (sliceedge != RL_SLICEEDGE_START) + return 0; /* not a solution */ + +sliceedge = p_cube->fb_sliceedge; +for (p_node = node_arr; p_node->remain_depth > 0; p_node++) + sliceedge = (int)twist_on_sliceedge[p_node[1].twist][sliceedge]; + +if (sliceedge != FB_SLICEEDGE_START) + return 0; /* not a solution */ + +output_solution(node_arr); /* solution ! */ + +return 1; +} + + +/* ========================================================================= */ + void search_tree(Full_cube *p_cube, Search_node *node_arr) +/* ------------------------------------------------------------------------- */ + +{ +register Search_node *p_node; +register int twist, virtual_twist, new_sym_factor; + + +p_node = node_arr; + +while (p_node >= node_arr) + { + if (p_node->remain_depth == 0) + { + if (test_for_solution(p_cube, node_arr) && + p_current_options->one_solution_only) + return; + p_node--; + } + else + { + for (twist = p_node[1].twist + 1; twist < N_TWIST; twist++) + { + p_node[1].follow_type = + (int)twist_on_follow[twist][p_node->follow_type]; + + if (p_node[1].follow_type == FOLLOW_INVALID) + continue; + + p_node[1].remain_depth = p_node->remain_depth - + p_current_metric->twist_length[twist]; + if (p_node[1].remain_depth < 0) + continue; + + n_nodes++; + + virtual_twist = + (int)invsym_on_twist_ud[p_node->ud.sym_state][twist]; + new_sym_factor = + (int)twist_x_edge_to_sym[virtual_twist][p_node->ud.edge_state]; + p_node[1].ud.edge_state = + (int)twist_on_edge[virtual_twist][p_node->ud.edge_state]; + p_node[1].ud.sym_state = + (int)sym_x_invsym_to_sym[p_node->ud.sym_state][new_sym_factor]; + p_node[1].ud.corner_state = (int)sym_on_corner[new_sym_factor] + [(int)twist_on_corner[virtual_twist][p_node->ud.corner_state]]; + + if (p_node[1].remain_depth < + DIST(p_node[1].ud.corner_state, p_node[1].ud.edge_state)) + continue; + + + virtual_twist = + (int)invsym_on_twist_rl[p_node->rl.sym_state][twist]; + new_sym_factor = + (int)twist_x_edge_to_sym[virtual_twist][p_node->rl.edge_state]; + p_node[1].rl.edge_state = + (int)twist_on_edge[virtual_twist][p_node->rl.edge_state]; + p_node[1].rl.sym_state = + (int)sym_x_invsym_to_sym[p_node->rl.sym_state][new_sym_factor]; + p_node[1].rl.corner_state = (int)sym_on_corner[new_sym_factor] + [(int)twist_on_corner[virtual_twist][p_node->rl.corner_state]]; + + if (p_node[1].remain_depth < + DIST(p_node[1].rl.corner_state, p_node[1].rl.edge_state)) + continue; + + + virtual_twist = + (int)invsym_on_twist_fb[p_node->fb.sym_state][twist]; + new_sym_factor = + (int)twist_x_edge_to_sym[virtual_twist][p_node->fb.edge_state]; + p_node[1].fb.edge_state = + (int)twist_on_edge[virtual_twist][p_node->fb.edge_state]; + p_node[1].fb.sym_state = + (int)sym_x_invsym_to_sym[p_node->fb.sym_state][new_sym_factor]; + p_node[1].fb.corner_state = (int)sym_on_corner[new_sym_factor] + [(int)twist_on_corner[virtual_twist][p_node->fb.corner_state]]; + + if (p_node[1].remain_depth < + DIST(p_node[1].fb.corner_state, p_node[1].fb.edge_state)) + continue; + + + p_node[1].twist = twist; + break; + } + + if (twist == N_TWIST) + p_node--; + else + { + p_node++; + p_node[1].twist = -1; + } + } + } + +return; +} + + +/* ========================================================================= */ + void calc_sym_cubes(Cube sym_conj[N_CUBESYM]) +/* ------------------------------------------------------------------------- */ + +{ +int ii; + + +cube_init(&sym_conj[0]); +cube_init(&sym_conj[1]); + +four_cycle(sym_conj[1].edges, EDGE_UF, EDGE_UL, EDGE_UB, EDGE_UR); +four_cycle(sym_conj[1].edges, EDGE_DF, EDGE_DL, EDGE_DB, EDGE_DR); +four_cycle(sym_conj[1].edges, EDGE_FR, EDGE_LF, EDGE_BL, EDGE_RB); +four_cycle(sym_conj[1].edges, EDGE_FU, EDGE_LU, EDGE_BU, EDGE_RU); +four_cycle(sym_conj[1].edges, EDGE_FD, EDGE_LD, EDGE_BD, EDGE_RD); +four_cycle(sym_conj[1].edges, EDGE_RF, EDGE_FL, EDGE_LB, EDGE_BR); +four_cycle(sym_conj[1].corners, CORNER_UFR, CORNER_ULF, CORNER_UBL, CORNER_URB); +four_cycle(sym_conj[1].corners, CORNER_DRF, CORNER_DFL, CORNER_DLB, CORNER_DBR); +four_cycle(sym_conj[1].corners, CORNER_FRU, CORNER_LFU, CORNER_BLU, CORNER_RBU); +four_cycle(sym_conj[1].corners, CORNER_RFD, CORNER_FLD, CORNER_LBD, CORNER_BRD); +four_cycle(sym_conj[1].corners, CORNER_RUF, CORNER_FUL, CORNER_LUB, CORNER_BUR); +four_cycle(sym_conj[1].corners, CORNER_FDR, CORNER_LDF, CORNER_BDL, CORNER_RDB); + +for (ii = 2; ii < 4; ii++) + cube_compose(&sym_conj[1], &sym_conj[ii - 1], &sym_conj[ii]); + +cube_init(&sym_conj[4]); + +two_cycle(sym_conj[4].edges, EDGE_UF, EDGE_DF); +two_cycle(sym_conj[4].edges, EDGE_UR, EDGE_DL); +two_cycle(sym_conj[4].edges, EDGE_UB, EDGE_DB); +two_cycle(sym_conj[4].edges, EDGE_UL, EDGE_DR); +two_cycle(sym_conj[4].edges, EDGE_FR, EDGE_FL); +two_cycle(sym_conj[4].edges, EDGE_BR, EDGE_BL); +two_cycle(sym_conj[4].edges, EDGE_FU, EDGE_FD); +two_cycle(sym_conj[4].edges, EDGE_RU, EDGE_LD); +two_cycle(sym_conj[4].edges, EDGE_BU, EDGE_BD); +two_cycle(sym_conj[4].edges, EDGE_LU, EDGE_RD); +two_cycle(sym_conj[4].edges, EDGE_RF, EDGE_LF); +two_cycle(sym_conj[4].edges, EDGE_RB, EDGE_LB); +two_cycle(sym_conj[4].corners, CORNER_UFR, CORNER_DFL); +two_cycle(sym_conj[4].corners, CORNER_ULF, CORNER_DRF); +two_cycle(sym_conj[4].corners, CORNER_UBL, CORNER_DBR); +two_cycle(sym_conj[4].corners, CORNER_URB, CORNER_DLB); +two_cycle(sym_conj[4].corners, CORNER_FRU, CORNER_FLD); +two_cycle(sym_conj[4].corners, CORNER_LFU, CORNER_RFD); +two_cycle(sym_conj[4].corners, CORNER_BLU, CORNER_BRD); +two_cycle(sym_conj[4].corners, CORNER_RBU, CORNER_LBD); +two_cycle(sym_conj[4].corners, CORNER_RUF, CORNER_LDF); +two_cycle(sym_conj[4].corners, CORNER_FUL, CORNER_FDR); +two_cycle(sym_conj[4].corners, CORNER_LUB, CORNER_RDB); +two_cycle(sym_conj[4].corners, CORNER_BUR, CORNER_BDL); + +for (ii = 5; ii < 8; ii++) + cube_compose(&sym_conj[4], &sym_conj[ii - 4], &sym_conj[ii]); + +cube_init(&sym_conj[8]); + +two_cycle(sym_conj[8].edges, EDGE_UF, EDGE_DF); +two_cycle(sym_conj[8].edges, EDGE_UR, EDGE_DR); +two_cycle(sym_conj[8].edges, EDGE_UB, EDGE_DB); +two_cycle(sym_conj[8].edges, EDGE_UL, EDGE_DL); +two_cycle(sym_conj[8].edges, EDGE_FU, EDGE_FD); +two_cycle(sym_conj[8].edges, EDGE_RU, EDGE_RD); +two_cycle(sym_conj[8].edges, EDGE_BU, EDGE_BD); +two_cycle(sym_conj[8].edges, EDGE_LU, EDGE_LD); +two_cycle(sym_conj[8].corners, CORNER_UFR, CORNER_DRF); +two_cycle(sym_conj[8].corners, CORNER_ULF, CORNER_DFL); +two_cycle(sym_conj[8].corners, CORNER_UBL, CORNER_DLB); +two_cycle(sym_conj[8].corners, CORNER_URB, CORNER_DBR); +two_cycle(sym_conj[8].corners, CORNER_FRU, CORNER_FDR); +two_cycle(sym_conj[8].corners, CORNER_LFU, CORNER_LDF); +two_cycle(sym_conj[8].corners, CORNER_BLU, CORNER_BDL); +two_cycle(sym_conj[8].corners, CORNER_RBU, CORNER_RDB); +two_cycle(sym_conj[8].corners, CORNER_RUF, CORNER_RFD); +two_cycle(sym_conj[8].corners, CORNER_FUL, CORNER_FLD); +two_cycle(sym_conj[8].corners, CORNER_LUB, CORNER_LBD); +two_cycle(sym_conj[8].corners, CORNER_BUR, CORNER_BRD); + +for (ii = 9; ii < 16; ii++) + cube_compose(&sym_conj[8], &sym_conj[ii - 8], &sym_conj[ii]); + +calc_cube_urf(&sym_conj[16]); + +for (ii = 17; ii < 48; ii++) + cube_compose(&sym_conj[16], &sym_conj[ii - 16], &sym_conj[ii]); + +return; +} + + +/* ========================================================================= */ + void pretty_print_unsigned_int(unsigned int nn) +/* ------------------------------------------------------------------------- */ + +{ +int digits[4], ii, started; + + +for (ii = 0; ii < 4; ii++) + { + digits[ii] = nn % 1000; + nn /= 1000; + } + +started = 0; + +for (ii = 3; ii >= 0; ii--) + { + if (started) + { + if (digits[ii] >= 100) + printf("%3d", digits[ii]); + else if (digits[ii] >= 10) + printf("0%2d", digits[ii]); + else + printf("00%1d", digits[ii]); + } + else + { + if (digits[ii] >= 100) + { + printf("%3d", digits[ii]); + started = 1; + } + else if (digits[ii] >= 10) + { + printf(" %2d", digits[ii]); + started = 1; + } + else if ((digits[ii] >= 1) || (ii == 0)) + { + printf(" %1d", digits[ii]); + started = 1; + } + else + printf(" "); + } + + if (ii > 0) + printf("%c", started ? ',' : ' '); + } + +return; +} + + +/* ========================================================================= */ + void solve_cube(Cube *p_cube) +/* ------------------------------------------------------------------------- */ + +{ +static Cube sym_cubes[N_CUBESYM]; +static int subgroup_list[N_SYMSUBGRP][N_CUBESYM]; +static int initialized = 0; +Full_cube full_cube_struct; +Search_node node_arr[MAX_TWISTS]; +int ii, start_depth, search_limit; + + +if (initialized == 0) + { + calc_sym_cubes(sym_cubes); + calc_subgroup_list(subgroup_list); + initialized = 1; + } + +print_cube(p_cube); +if (cube_is_solved(p_cube)) + { + printf("cube is already solved!\n"); + return; + } + +cube_conjugate(p_cube, &sym_cubes[0], &full_cube_struct.cubies); +process_full_cube(&full_cube_struct); + +set_cube_symmetry(&full_cube_struct, sym_cubes, subgroup_list); + +node_arr[0].follow_type = 1 + full_cube_struct.sym_subgrp; +node_arr[0].ud.corner_state = full_cube_struct.ud.corner_state; +node_arr[0].ud.edge_state = full_cube_struct.ud.edge_state; +node_arr[0].ud.sym_state = full_cube_struct.ud.sym_state; + +node_arr[0].rl.corner_state = full_cube_struct.rl.corner_state; +node_arr[0].rl.edge_state = full_cube_struct.rl.edge_state; +node_arr[0].rl.sym_state = full_cube_struct.rl.sym_state; + +node_arr[0].fb.corner_state = full_cube_struct.fb.corner_state; +node_arr[0].fb.edge_state = full_cube_struct.fb.edge_state; +node_arr[0].fb.sym_state = full_cube_struct.fb.sym_state; + +sol_found = 0; +if ((p_current_metric->metric == QUARTER_TURN_METRIC) && + (full_cube_struct.parity == 0)) + start_depth = 2; +else + start_depth = 1; + +search_limit = p_current_options->search_limit; +if ((search_limit <= 0) || (search_limit >= MAX_TWISTS)) + search_limit = MAX_TWISTS - 1; + +for (ii = start_depth; ii <= search_limit; ii += p_current_metric->increment) + { + n_nodes = (long long int)0; + n_tests = (unsigned int)0; + node_arr[0].remain_depth = ii; + node_arr[1].twist = -1; + search_tree(&full_cube_struct, node_arr); + + if ((p_current_options->one_solution_only == 0) || (sol_found == 0)) + { + printf("depth %2d%c completed (", ii, p_current_metric->metric_char); + pretty_print_unsigned_int(n_nodes); + printf(" nodes, "); + pretty_print_unsigned_int(n_tests); + printf(" tests)\n"); + fflush(stdout); + } + + if (sol_found) + break; + } + +return; +} + + +/* ========================================================================= */ + int main(void) +/* ------------------------------------------------------------------------- */ + +{ +Metric_data metric_data; +Options user_options; +Cube cube_struct; +int stat; + + +init_options(&metric_data, &user_options); +init_globals(); + +signal(SIGINT, SIG_IGN); + +while (1) + { + stat = user_enters_cube(&cube_struct); + if (stat < 0) + break; + + if (stat == 0) + { + if (sigsetjmp(jump_env, 1) == 0) + { + signal(SIGINT, user_interrupt); + solve_cube(&cube_struct); + } + + signal(SIGINT, SIG_IGN); + } + } + +exit(EXIT_SUCCESS); + +return 0; /* haha */ +}