-
-
Save mhoehle/e5cd120376c68b5e189bb458bb44580f to your computer and use it in GitHub Desktop.
Check that 17 repeats of Lw' Uw' Lw Uw in a 3x3 Rubik's cube take you back to the starting configuration.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // hoehle 2023-06-17: Downloaded as "subgroup.tar.gz" from | |
| // http://www.geometer.org/rubik/index.html | |
| // in order to check that 17 repeats are needed | |
| // for the move sequence described in | |
| // https://twitter.com/Rainmaker1973/status/1669664486855176192?s=20 | |
| // (the sequence is Lw' Uw' Lw Uw) | |
| // or in the notation of the program (line 92): | |
| // char *grouplist[] = {"l*Ru*DL*LU*U", 0}; | |
| // Compile with g++ subgroup.cxx -o subgroup -Wc++11-compat-deprecated-writable-strings | |
| // Copyright 2003 Thomas R. Davis | |
| // | |
| // This file is part of Rubik. | |
| // | |
| // | |
| // Rubik is free software; you can redistribute it and/or modify | |
| // it under the terms of the GNU General Public License as published by | |
| // the Free Software Foundation; either version 2 of the License, or | |
| // (at your option) any later version. | |
| // | |
| // Rubik is distributed in the hope that it will be useful, | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| // GNU General Public License for more details. | |
| // | |
| // You should have received a copy of the GNU General Public License | |
| // along with Rubik; if not, write to the Free Software Foundation, | |
| // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| // cube configuration: | |
| // 0 1 2 | |
| // 3 4 5 | |
| // 6 7 8 | |
| // | |
| // 9 10 11 18 19 20 27 28 29 36 37 38 | |
| // 12 13 14 21 22 23 30 31 32 39 40 41 | |
| // 15 16 17 24 25 26 33 34 35 42 43 44 | |
| // | |
| // 45 46 47 | |
| // 48 49 50 | |
| // 51 52 53 | |
| // Cube faces: | |
| // | |
| // U | |
| // L F R B | |
| // D | |
| // Moves: F, R, ... front, right, ... clockwise | |
| // Moves: f, r, ... front, right, ... counter-clockwise | |
| // >F whole cube clockwise | |
| // *F front slice clockwise | |
| // Fill in array grouplist with the generaters. For example: | |
| // char *grouplist[] = {"FF", ">F", "D", 0}; counts all positions | |
| // you can get to from FF, >F, or D in any order. | |
| // define CORNERS or EDGES to get just corner or edge permutations. | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #define HASHSIZE 65536*2 | |
| #define CHUNKSIZE 20000 | |
| #define MAXGROUP 20000000 | |
| #ifdef CORNERS | |
| #define COUNT 7 | |
| unsigned char cubefaces[7] = {0, 2, 6, 8, 15, 17, 33}; | |
| #endif | |
| #ifdef EDGES | |
| #define COUNT 11 | |
| unsigned char cubefaces[11] = {1, 3, 5, 7, 12, 14, 23, 32, 16, 25, 34}; | |
| #endif | |
| #if !defined(EDGES) && !defined(CORNERS) | |
| #define COUNT 20 | |
| unsigned char cubefaces[20] = {1, 3, 5, 7, 12, 14, 23, 32, 16, 25, 34, | |
| 0, 2, 6, 8, 15, 17, 33, 4, 22}; | |
| #endif | |
| extern void moveface(int); | |
| extern void movecube(int); | |
| //char *grouplist[] = {"UUdd", "LLrr", "FFbb", 0}; | |
| //char *grouplist[] = {"rUUBlFuBDFUdLDDfRbDfubdU", "RF", 0}; | |
| //char *grouplist[] = {"UR", 0}; | |
| //char *grouplist[] = {"RUru", 0}; | |
| //https://twitter.com/Rainmaker1973/status/1669664486855176192?s=20 | |
| //char *grouplist[] = {"*l*u*L*U", 0}; | |
| char *grouplist[] = {"l*Ru*DL*LU*U", 0}; | |
| static int totalpositions = 0; | |
| int maxdepth = 0; | |
| struct hashrec { | |
| char cube[COUNT]; | |
| struct hashrec *next; | |
| int depth; | |
| }; | |
| static struct hashrec *table[HASHSIZE]; | |
| static struct hashrec *group[MAXGROUP]; | |
| static struct hashrec *freelist = 0; | |
| static struct hashrec *curhash = 0; | |
| int currecord = 0; | |
| int moves[6][54]; | |
| int movec[3][54]; | |
| #define moveit(a, b, c, d) moves[j][d]=a;moves[j][c]=d;moves[j][b]=c;moves[j][a]=b; | |
| #define movex(a, b, c, d) movec[j][d]=a;movec[j][c]=d;movec[j][b]=c;movec[j][a]=b; | |
| void hashstats() | |
| { | |
| int i, total; | |
| int len[10000]; | |
| struct hashrec *h; | |
| for (i = 0; i < 10000; i++) len[i] = 0; | |
| for (i = 0; i < HASHSIZE; i++) { | |
| total = 0; | |
| h = table[i]; | |
| while (h) { total++; h = h->next; } | |
| len[total]++; | |
| } | |
| for (i = 0; i < 10000; i++) | |
| if (len[i] > 0) printf("[%d:%d]", i, len[i]); | |
| printf("\n"); | |
| } | |
| static void loadmovearray() | |
| { | |
| int i, j, tmp; | |
| for (i = 0; i < 6; i++) | |
| for (j = 0; j < 54; j++) | |
| moves[i][j] = j; | |
| j = 0; | |
| moveit(0, 2, 8, 6); | |
| moveit(1, 5, 7, 3); | |
| moveit(9, 36, 27, 18); | |
| moveit(10, 37, 28, 19); | |
| moveit(11, 38, 29, 20); | |
| j = 1; | |
| moveit(9, 11, 17, 15); | |
| moveit(10, 14, 16, 12); | |
| moveit(0, 18, 45, 44); | |
| moveit(3, 21, 48, 41); | |
| moveit(6, 24, 51, 38); | |
| j = 2; | |
| moveit(18, 20, 26, 24); | |
| moveit(19, 23, 25, 21); | |
| moveit(6, 27, 47, 17); | |
| moveit(7, 30, 46, 14); | |
| moveit(8, 33, 45, 11); | |
| j = 3; | |
| moveit(27, 29, 35, 33); | |
| moveit(28, 32, 34, 30); | |
| moveit(8, 36, 53, 26); | |
| moveit(5, 39, 50, 23); | |
| moveit(2, 42, 47, 20); | |
| j = 4; | |
| moveit(36, 38, 44, 42); | |
| moveit(37, 41, 43, 39); | |
| moveit(2, 9, 51, 35); | |
| moveit(1, 12, 52, 32); | |
| moveit(0, 15, 53, 29); | |
| j = 5; | |
| moveit(45, 47, 53, 51); | |
| moveit(46, 50, 52, 48); | |
| moveit(24, 33, 42, 15); | |
| moveit(25, 34, 43, 16); | |
| moveit(26, 35, 44, 17); | |
| for (i = 0; i < 3; i++) | |
| for (j = 0; j < 54; j++) | |
| movec[i][j] = j; | |
| j = 0; | |
| movex(0, 2, 8, 6); | |
| movex(1, 5, 7, 3); | |
| movex(45, 51, 53, 47); | |
| movex(46, 48, 52, 50); | |
| movex(9, 36, 27, 18); | |
| movex(10, 37, 28, 19); | |
| movex(11, 38, 29, 20); | |
| movex(12, 39, 30, 21); | |
| movex(13, 40, 31, 22); | |
| movex(14, 41, 32, 23); | |
| movex(15, 42, 33, 24); | |
| movex(16, 43, 34, 25); | |
| movex(17, 44, 35, 26); | |
| j = 1; | |
| movex(9, 11, 17, 15); | |
| movex(10, 14, 16, 12); | |
| movex(27, 33, 35, 29); | |
| movex(28, 30, 34, 32); | |
| movex(0, 18, 45, 44); | |
| movex(3, 21, 48, 41); | |
| movex(6, 24, 51, 38); | |
| movex(1, 19, 46, 43); | |
| movex(4, 22, 49, 40); | |
| movex(7, 25, 52, 37); | |
| movex(2, 20, 47, 42); | |
| movex(5, 23, 50, 39); | |
| movex(8, 26, 53, 36); | |
| j = 2; | |
| movex(18, 20, 26, 24); | |
| movex(19, 23, 25, 21); | |
| movex(36, 42, 44, 38); | |
| movex(37, 39, 43, 41); | |
| movex(6, 27, 47, 17); | |
| movex(7, 30, 46, 14); | |
| movex(8, 33, 45, 11); | |
| movex(3, 28, 50, 16); | |
| movex(4, 31, 49, 13); | |
| movex(5, 34, 48, 10); | |
| movex(0, 29, 53, 15); | |
| movex(1, 32, 52, 12); | |
| movex(2, 35, 51, 9); | |
| } | |
| static void inithash() | |
| { | |
| struct hashrec *tmp; | |
| int i; | |
| while (freelist) { | |
| tmp = freelist; | |
| freelist = freelist->next; | |
| free(tmp); | |
| } | |
| for (i = 0; i < HASHSIZE; i++) | |
| table[i] = 0; | |
| totalpositions = 0; | |
| curhash = 0; | |
| currecord = 0; | |
| maxdepth = 0; | |
| loadmovearray(); | |
| } | |
| int hashpos() | |
| { | |
| int i; | |
| int hash = 0; | |
| #ifdef CORNERS | |
| for (i = 0; i < COUNT; i++) { | |
| hash <<= 3; | |
| hash ^= cubefaces[i]; | |
| } | |
| #else | |
| #ifdef EDGES | |
| for (i = 0; i < COUNT; i++) { | |
| hash <<= 2; | |
| hash ^= cubefaces[i]; | |
| } | |
| #else | |
| for (i = 0; i < COUNT; i++) { | |
| hash <<= 1; | |
| hash ^= cubefaces[i]; | |
| } | |
| #endif | |
| #endif | |
| return hash %(HASHSIZE-1); | |
| } | |
| static int samepos(struct hashrec *h) | |
| { | |
| int i; | |
| for (i = 0; i < COUNT; i++) | |
| if (h->cube[i] != cubefaces[i]) return 0; | |
| return 1; | |
| } | |
| static struct hashrec *newrecord() | |
| { | |
| struct hashrec *newr; | |
| if (currecord == 0) { | |
| curhash = (struct hashrec *)malloc(CHUNKSIZE*sizeof(struct hashrec)); | |
| curhash->next = freelist; | |
| freelist = curhash; | |
| currecord = 1; | |
| } | |
| newr = curhash + currecord++; | |
| if (currecord == CHUNKSIZE) currecord = 0; | |
| //printf("%d\n", newr); | |
| return newr; | |
| } | |
| void printcube() | |
| { | |
| int i; | |
| for (i = 0; i < COUNT; i++) | |
| printf("%2d ", cubefaces[i]); | |
| printf("\n"); | |
| } | |
| int addrec(int depth) | |
| { | |
| int h = hashpos(); | |
| int i; | |
| struct hashrec *hnew, *hrec = table[h]; | |
| //printcube(); | |
| //printf(" %d\n", h); | |
| if (hrec == 0) { | |
| hnew = newrecord(); | |
| for (i = 0; i < COUNT; i++) hnew->cube[i] = cubefaces[i]; | |
| hnew->next = 0; | |
| hnew->depth = depth; | |
| if (depth > maxdepth) maxdepth = depth; | |
| table[h] = hnew; | |
| group[totalpositions] = hnew; | |
| totalpositions++; | |
| return 1; | |
| } | |
| while (hrec) { | |
| if (samepos(hrec)) return 0; | |
| if (hrec->next == 0) { | |
| hnew = newrecord(); | |
| for (i = 0; i < COUNT; i++) hnew->cube[i] = cubefaces[i]; | |
| hnew->next = 0; | |
| hnew->depth = depth; | |
| if (depth > maxdepth) maxdepth = depth; | |
| hrec->next = hnew; | |
| group[totalpositions] = hnew; | |
| totalpositions++; | |
| return 1; | |
| } | |
| hrec = hrec->next; | |
| } | |
| return 0; | |
| } | |
| int grouppos = 0; | |
| int listcount; | |
| void makemove(char *s) | |
| { | |
| while (*s) | |
| switch (*s++) { | |
| case 'u': moveface(0); moveface(0); | |
| case 'U': moveface(0); break; | |
| case 'l': moveface(1); moveface(1); | |
| case 'L': moveface(1); break; | |
| case 'f': moveface(2); moveface(2); | |
| case 'F': moveface(2); break; | |
| case 'r': moveface(3); moveface(3); | |
| case 'R': moveface(3); break; | |
| case 'b': moveface(4); moveface(4); | |
| case 'B': moveface(4); break; | |
| case 'd': moveface(5); moveface(5); | |
| case 'D': moveface(5); break; | |
| case '>': // whole cube move | |
| switch (*s++) { | |
| case 'U': movecube(0); break; | |
| case 'L': movecube(1); break; | |
| case 'F': movecube(2); break; | |
| case 'R': movecube(3); break; | |
| case 'B': movecube(4); break; | |
| case 'D': movecube(5); break; | |
| } | |
| break; | |
| case '*': // slice move | |
| switch (*s++) { | |
| case 'U': | |
| moveface(0); | |
| moveface(0); | |
| moveface(0); | |
| moveface(5); | |
| movecube(0); | |
| break; | |
| case 'L': | |
| moveface(1); | |
| moveface(1); | |
| moveface(1); | |
| moveface(3); | |
| movecube(1); | |
| break; | |
| case 'F': | |
| moveface(2); | |
| moveface(2); | |
| moveface(2); | |
| moveface(4); | |
| movecube(2); | |
| break; | |
| case 'R': | |
| moveface(3); | |
| moveface(3); | |
| moveface(3); | |
| moveface(1); | |
| movecube(3); | |
| break; | |
| case 'B': | |
| moveface(4); | |
| moveface(4); | |
| moveface(4); | |
| moveface(2); | |
| movecube(4); | |
| break; | |
| case 'D': | |
| moveface(5); | |
| moveface(5); | |
| moveface(5); | |
| moveface(0); | |
| movecube(5); | |
| break; | |
| } | |
| break; | |
| } | |
| } | |
| int main() | |
| { | |
| int i, j, depth; | |
| inithash(); | |
| addrec(0); | |
| listcount = 0; | |
| while (grouplist[listcount]) listcount++; | |
| while (grouppos < totalpositions) { | |
| for (i = 0; i < listcount; i++) { | |
| for (j = 0; j < COUNT; j++) cubefaces[j] = group[grouppos]->cube[j]; | |
| depth = group[grouppos]->depth; | |
| //printcube(); | |
| makemove(grouplist[i]); | |
| addrec(depth+1); | |
| if (totalpositions == MAXGROUP) { | |
| printf("\nMore than %d group members\n", totalpositions); | |
| return 0; | |
| } | |
| } | |
| grouppos++; | |
| if (grouppos % 100000 == 0) { | |
| printf("[%d:%d]\n", grouppos, totalpositions); | |
| //hashstats(); | |
| } | |
| } | |
| printf("\ntotal count = %d\nmaxdepth = %d\n", totalpositions, maxdepth); | |
| return 0; | |
| } | |
| void moveface(int j) | |
| { | |
| unsigned char x[COUNT]; | |
| int i; | |
| for (i = 0; i < COUNT; i++) x[i] = moves[j][cubefaces[i]]; | |
| for (i = 0; i < COUNT; i++) cubefaces[i] = x[i]; | |
| } | |
| void movecube(int j) | |
| { | |
| unsigned char x[COUNT]; | |
| int i; | |
| if (j < 3) { | |
| for (i = 0; i < COUNT; i++) x[i] = movec[j][cubefaces[i]]; | |
| for (i = 0; i < COUNT; i++) cubefaces[i] = x[i]; | |
| } else switch (j) { | |
| case 3: | |
| movecube(1); | |
| movecube(1); | |
| movecube(1); | |
| break; | |
| case 4: | |
| movecube(2); | |
| movecube(2); | |
| movecube(2); | |
| break; | |
| case 5: | |
| movecube(0); | |
| movecube(0); | |
| movecube(0); | |
| break; | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment