Просмотр исходного кода

- 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
master
kali 16 лет назад
Родитель
Сommit
e889d5536b
3 измененных файлов: 5092 добавлений и 0 удалений
  1. +640
    -0
      2008-rubik/rubikutils/rubik.c
  2. +136
    -0
      2008-rubik/solver/optimal/README
  3. +4316
    -0
      2008-rubik/solver/optimal/optimal.c

+ 640
- 0
2008-rubik/rubikutils/rubik.c Просмотреть файл

@@ -0,0 +1,640 @@
#include <stdio.h>
#include <stdlib.h>

#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 */
}

+ 136
- 0
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

+ 4316
- 0
2008-rubik/solver/optimal/optimal.c
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


Загрузка…
Отмена
Сохранить