diff options
| author | Sebastiano Tronto <sebastiano@tronto.net> | 2023-05-01 12:48:55 +0200 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano@tronto.net> | 2023-05-01 12:48:55 +0200 |
| commit | 6f4313bc1ed5be794146e6ca2fd73f48c7906061 (patch) | |
| tree | a79c8be8613e8b4256d609477f98f440bfd7168c | |
| parent | 1a5bfe9b08707b0aef748d7921a419ba4a046fba (diff) | |
| download | nissy-classic-6f4313bc1ed5be794146e6ca2fd73f48c7906061.tar.gz nissy-classic-6f4313bc1ed5be794146e6ca2fd73f48c7906061.zip | |
Reverted to 2.0.3
Diffstat (limited to '')
68 files changed, 5547 insertions, 6611 deletions
| @@ -2,4 +2,3 @@ doc/*.html | |||
| 2 | doc/*.pdf | 2 | doc/*.pdf |
| 3 | nissy | 3 | nissy |
| 4 | nissy-* | 4 | nissy-* |
| 5 | test | ||
| @@ -4,78 +4,57 @@ Nissy is available at https://nissy.tronto.net | |||
| 4 | 4 | ||
| 5 | # Requirements | 5 | # Requirements |
| 6 | 6 | ||
| 7 | A full installation of nissy requires about 3Gb of space, of which | 7 | A full installation of nissy requires about 3Gb of space, |
| 8 | 2.3Gb are occupied by the huge pruning table for fast optimal solving, | 8 | of which 2.3Gb are occupied by the huge pruning table for fast optimal solving, |
| 9 | and running it requires the same amount of RAM. One can choose to never | 9 | and running it requires the same amount of RAM. |
| 10 | use this function and not to install the relative pruning table. There | 10 | One can choose to never use this function and not to install the relative |
| 11 | is an alternative (slower) optimal solving function that uses about | 11 | pruning table. There is an alternative (slower) |
| 12 | 500Mb of RAM. When generating the pruning tables automatically (see | 12 | optimal solving function that uses about 500Mb of RAM. |
| 13 | the section Tables below), at least 5.3Gb or RAM are required. | ||
| 14 | 13 | ||
| 15 | # Installation | 14 | # Installation |
| 16 | 15 | ||
| 17 | ## On Windows | 16 | ## On Windows |
| 18 | 17 | ||
| 19 | Try downloading and executing in a terminal the file nissy.exe, then | 18 | Try downloading and executing in a terminal the file nissy.exe, then |
| 20 | follow the instructions in the Tables section below for installing the | 19 | follow the instructions in the Tables section below for |
| 21 | pruning tables. If nissy.exe does not work, you can try following the | 20 | installing the pruning tables. |
| 22 | UNIX instructions in WSL (Windows Subsystem for Linux) or in a similar | 21 | If nissy.exe does not work, you can try following the UNIX instructions |
| 23 | environment. | 22 | in WSL (Windows Subsystem for Linux) or in a similar environment. |
| 24 | 23 | ||
| 25 | ## On a UNIX system: | 24 | Sorry for the inconvenience, I don't have a Windows machine to test this on. |
| 26 | |||
| 27 | Download the source archive (.tar.gz). Extract it with your favorite | ||
| 28 | archive program, for example with | ||
| 29 | |||
| 30 | tar -xvzf nissy-VERSION.tar.gz | ||
| 31 | |||
| 32 | Open a terminal in the directory just extracted. If you wish, edit the | ||
| 33 | Makefile to match your local configuration (this is usually not necessary, | ||
| 34 | but you may want to change the PREFIX variable to change the installation | ||
| 35 | path) and run | ||
| 36 | |||
| 37 | make | ||
| 38 | |||
| 39 | followed by | ||
| 40 | 25 | ||
| 41 | make install | 26 | ## On a UNIX system: |
| 42 | 27 | ||
| 43 | Then follow the instructions below to install the pruning tables. | 28 | Edit the Makefile to match your local configuration (usually not necessary, but you |
| 29 | may want to change the PREFIX variable) and run make, followed by make install. | ||
| 30 | Follow the instructions below to install the pruning tables. | ||
| 44 | 31 | ||
| 45 | ## Tables | 32 | ## Tables |
| 33 | Nissy needs to generate certain large tables to work. These tables are by default | ||
| 34 | generated the first time they are needed (e.g the first time you ask to solve a | ||
| 35 | certain step) and then saved to a file. Whenever these tables are needed again, | ||
| 36 | nissy simply loads the corresponding file from the hard disk. | ||
| 46 | 37 | ||
| 47 | Once you have installed nissy, run | 38 | The very large table for optimal solving can take some time to generate |
| 39 | (about 1.5 hours on my fairly old but decent laptop, using 8 CPU threads). | ||
| 40 | In order to generate it you need at least 5Gb of RAM. | ||
| 41 | All other tables are much faster. | ||
| 48 | 42 | ||
| 49 | nissy gen | 43 | You can ask nissy to generate all the tables it will ever need with the gen |
| 44 | command. It is recommended to use more than one thread, if your CPU has them. | ||
| 45 | For example, you can run: | ||
| 50 | 46 | ||
| 51 | to generate all the tables that Nissy will ever need. Running this | 47 | nissy gen -t 8 |
| 52 | command requires around 5.3Gb of RAM, and it can take some time (about | ||
| 53 | 40 minutes on my fairly old but decent laptop, with 8 CPU threads). | ||
| 54 | 48 | ||
| 55 | Some unnecessary technical detail: by default this command is going to | 49 | to generate all tables using 8 threads. |
| 56 | use at most 64 threads. If you want you can choose to use more threads | ||
| 57 | (if your CPU is very powerful) or fewer threads (if you for example | ||
| 58 | want to run this command in the background while you do other stuff) | ||
| 59 | with the -t option, for example nissy gen -t 1. | ||
| 60 | 50 | ||
| 61 | Alternatively, you can download all the tables (1.7Gb) and copy them | 51 | Alternatively, you can simply download all the tables and copy them into the |
| 62 | into the correct folder (see manual page, ENVIRONMENT section). On UNIX | 52 | correct folder (see manual page, ENVIRONMENT section). On UNIX operating |
| 63 | operating systems this folder is either .nissy/tables in the user's | 53 | systems this folder is either .nissy/tables in the user's home directory or |
| 64 | home directory or $XDG_DATA_HOME/nissy/tables if the XDG variable | 54 | $XDG_DATA_HOME/nissy/tables if the XDG variable is configured. On Windows |
| 65 | is configured. On Windows it is the same directory as the nissy.exe | 55 | it is the same directory as the nissy.exe executable file. |
| 66 | executable file. | ||
| 67 | 56 | ||
| 68 | You can downloads all the tables from the following link: | 57 | You can downloads all the tables from the following link: |
| 69 | 58 | https://nissy.tronto.net/nissy-tables-2.0.zip | |
| 70 | https://nissy.tronto.net/nissy-tables-2.0.2.zip | 59 | The version 2.0 at the end of the file name is only indicative. |
| 71 | 60 | Later versions will use the same tables, unless otherwise specified. | |
| 72 | # Upgrading | ||
| 73 | |||
| 74 | If you already have nissy installed and you want to upgrade to a more | ||
| 75 | recent version, you can simply repeat the installation process: | ||
| 76 | * On Windows: simply replace nissy.exe with the new file with the same name. | ||
| 77 | * On UNIX systems: download the new version of the source code, extract it | ||
| 78 | in a new folder and run make and make install again. | ||
| 79 | |||
| 80 | Between each version new table files might have been added, or old ones | ||
| 81 | may be not used anymore. Nissy will deal with this automatically. | ||
| @@ -1,18 +1,19 @@ | |||
| 1 | # See LICENSE file for copyright and license details. | 1 | # See LICENSE file for copyright and license details. |
| 2 | 2 | ||
| 3 | VERSION = post-2.0.2 | 3 | VERSION = 2.0.3 |
| 4 | 4 | ||
| 5 | PREFIX = /usr/local | 5 | PREFIX = /usr/local |
| 6 | MANPREFIX = ${PREFIX}/share/man | 6 | MANPREFIX = ${PREFIX}/share/man |
| 7 | 7 | ||
| 8 | CPPFLAGS = -DVERSION=\"${VERSION}\" | 8 | CPPFLAGS = -DVERSION=\"${VERSION}\" |
| 9 | CFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \ | 9 | CFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \ |
| 10 | -Wno-unused-parameter -O3 ${CPPFLAGS} | 10 | -Wno-unused-parameter -O3 ${CPPFLAGS} |
| 11 | DBGFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \ | 11 | DBGFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \ |
| 12 | -Wno-unused-parameter -g ${CPPFLAGS} | 12 | -Wno-unused-parameter -g ${CPPFLAGS} |
| 13 | 13 | ||
| 14 | CC = cc | 14 | CC = cc |
| 15 | 15 | ||
| 16 | |||
| 16 | all: nissy | 17 | all: nissy |
| 17 | 18 | ||
| 18 | nissy: clean | 19 | nissy: clean |
| @@ -24,11 +25,8 @@ nissy.exe: | |||
| 24 | debug: | 25 | debug: |
| 25 | ${CC} ${DBGFLAGS} -o nissy src/*.c | 26 | ${CC} ${DBGFLAGS} -o nissy src/*.c |
| 26 | 27 | ||
| 27 | test: | ||
| 28 | ${CC} ${DBGFLAGS} -DTEST -o test src/*.c tests/*.c | ||
| 29 | |||
| 30 | clean: | 28 | clean: |
| 31 | rm -rf nissy nissy*.exe nissy*.tar.gz doc/nissy.html doc/nissy.pdf | 29 | rm -rf nissy nissy*.exe nissy*.tar.gz |
| 32 | 30 | ||
| 33 | dist: clean nissy.exe | 31 | dist: clean nissy.exe |
| 34 | mkdir -p nissy-${VERSION} | 32 | mkdir -p nissy-${VERSION} |
| @@ -65,4 +63,5 @@ uninstall: | |||
| 65 | rm -rf ${DESTDIR}${PREFIX}/bin/nissy ${DESTDIR}${MANPREFIX}/man1/nissy.1 | 63 | rm -rf ${DESTDIR}${PREFIX}/bin/nissy ${DESTDIR}${MANPREFIX}/man1/nissy.1 |
| 66 | for s in ${SCRIPTS}; do rm -rf ${DESTDIR}${PREFIX}/bin/$$s; done | 64 | for s in ${SCRIPTS}; do rm -rf ${DESTDIR}${PREFIX}/bin/$$s; done |
| 67 | 65 | ||
| 68 | .PHONY: all debug test clean dist install uninstall upload | 66 | .PHONY: all debug clean dist install uninstall upload |
| 67 | |||
diff --git a/TODO/2.1.md b/TODO/2.1.md deleted file mode 100644 index 7448094..0000000 --- a/TODO/2.1.md +++ /dev/null | |||
| @@ -1,51 +0,0 @@ | |||
| 1 | # TODO-list for version 2.1 (or is it 3.0 at this point?) | ||
| 2 | |||
| 3 | ## Rework solver | ||
| 4 | |||
| 5 | ### 1. Implement minimum viable | ||
| 6 | |||
| 7 | * Implement nxopt31 with fst_cube. Remember that the function | ||
| 8 | move_check_solved() should do one axis at the time, so that we don't move | ||
| 9 | everything before checking. | ||
| 10 | * test? | ||
| 11 | |||
| 12 | ### 2. Rework achitecture and file dependencies | ||
| 13 | |||
| 14 | * solve.h depends only on moves(alg?) (dependency on step and trans is removed). | ||
| 15 | * Other modules have changed dependencies, might as well rework all. | ||
| 16 | * Make files smaller, do not include definition in .h, separate | ||
| 17 | data from abstract operations. | ||
| 18 | * remove cubetypes.h | ||
| 19 | * Create a module for multi-step (maybe wait?) | ||
| 20 | * Possible changes: in step solver, copy cube only if niss; add cleanup function | ||
| 21 | in solver (called by solve()) to free cube and perhaps pruning tables. | ||
| 22 | * see various TODO's in files | ||
| 23 | |||
| 24 | ### 4. More threading options | ||
| 25 | |||
| 26 | * Lazy multithread: threads are as independent as possible and only | ||
| 27 | merged at the end. Ideal when all solutions of a certain length are requested. | ||
| 28 | * (Done) Eager multithread: current implementation, branches communicate the | ||
| 29 | number and list of solutions to stop as soon as possible. Good when only one | ||
| 30 | solution of a certain depth is required. | ||
| 31 | |||
| 32 | ## Simplify steps | ||
| 33 | |||
| 34 | * Remove one type of rotation. | ||
| 35 | * Change steps to choicestep and stepalt to step (or was this already done?). | ||
| 36 | |||
| 37 | ## Add missing coordinates and steps | ||
| 38 | |||
| 39 | * Check the old file for a list. Many are missing. | ||
| 40 | * Checkers in steps.c should use coordinates. | ||
| 41 | |||
| 42 | ## Missing and new commands | ||
| 43 | |||
| 44 | * gen | ||
| 45 | * freemem | ||
| 46 | * twophase | ||
| 47 | |||
| 48 | ## Easy improvements | ||
| 49 | |||
| 50 | * Solve should re-orient the cube if centers are off | ||
| 51 | * Solve: add options for -I (inverse only) and -L (linear = normal + inverse). | ||
diff --git a/TODO/build-options.md b/TODO/build-options.md deleted file mode 100644 index 83b8a34..0000000 --- a/TODO/build-options.md +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | # Build options for memory and multithreading | ||
| 2 | |||
| 3 | ## Investigate | ||
| 4 | |||
| 5 | * Check exactly how much memory is needed for everything. | ||
| 6 | * Take note of which parts use threading (solving, genptable, other?). | ||
| 7 | |||
| 8 | ## Prepare code | ||
| 9 | |||
| 10 | * Use define / ifdef or similar to compile and build tables only for the | ||
| 11 | parts to be used. | ||
| 12 | * If threads = 1, use a much simpler version of the solve method. Remember | ||
| 13 | that checking if enough solutions have been found is the first thing to | ||
| 14 | do in singlethread (no locking). | ||
| 15 | * Do not include pthread if threads = 1. | ||
| 16 | * Only one optimal solver should be compiled. | ||
| 17 | * Some simple steps may also need alternatives with smaller tables | ||
| 18 | (e.g. for staying sub 1Gb). For example dr and drfin. | ||
| 19 | * If necessary, work out alternatives to "twophase" for low-resource versions. | ||
| 20 | |||
| 21 | ## Makefile | ||
| 22 | |||
| 23 | * Figure out how to change these options via makefile. For example: one | ||
| 24 | variable for the maximum allowed ram and one for the number of threads. | ||
| 25 | * (Optional) use a configure script? | ||
| 26 | * (Optional) interactive installation script? | ||
| 27 | |||
| 28 | ## Automate | ||
| 29 | |||
| 30 | * Scout for resources during installation and choose best configuration | ||
| 31 | automatically. | ||
| 32 | * How to do this in Linux / POSIX? | ||
| 33 | * How to do this in Windows? | ||
diff --git a/TODO/documentation.md b/TODO/documentation.md deleted file mode 100644 index 050a854..0000000 --- a/TODO/documentation.md +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | # Documentation | ||
| 2 | |||
| 3 | ## Big documentation file on nissy's internals | ||
| 4 | |||
| 5 | * Coordinates | ||
| 6 | * Symcoordinates | ||
| 7 | * Pruning tables | ||
| 8 | * Coordinate solving | ||
| 9 | * fst cube | ||
| 10 | * Optimized solver | ||
| 11 | * Multithreading | ||
| 12 | * Commands etc... | ||
| 13 | * Code architecture | ||
| 14 | |||
| 15 | ## examples.md | ||
| 16 | |||
| 17 | * Example file for nissy's website and documentation folder | ||
| 18 | * With screenshots! | ||
| 19 | |||
| 20 | ## Random info | ||
| 21 | |||
| 22 | Where to collect random information like this table? | ||
| 23 | |||
| 24 | Table pt_nxopt31_HTM | ||
| 25 | Base value: 9 | ||
| 26 | 0 1 | ||
| 27 | 1 6 | ||
| 28 | 2 29 | ||
| 29 | 3 164 | ||
| 30 | 4 1433 | ||
| 31 | 5 16772 | ||
| 32 | 6 205033 | ||
| 33 | 7 2513871 | ||
| 34 | 8 30329976 | ||
| 35 | 9 342440769 | ||
| 36 | 10 2815191126 | ||
| 37 | 11 6147967200 | ||
| 38 | 12 524918774 | ||
| 39 | 13 3546 | ||
| 40 | 14 0 | ||
| 41 | 15 0 | ||
diff --git a/TODO/easy.md b/TODO/easy.md deleted file mode 100644 index 7d780e2..0000000 --- a/TODO/easy.md +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | # Easy things to improve or add | ||
| 2 | |||
| 3 | ## Improvements | ||
| 4 | |||
| 5 | * Silent batch mode without >>> | ||
| 6 | * Solutions should be shown sorted: by length first, then by normal moves | ||
| 7 | (no niss) first, then it depends on the step (e.g. EO by axis). | ||
| 8 | |||
| 9 | ## Old commands and steps | ||
| 10 | |||
| 11 | * drcorners (solve corners after DR) | ||
| 12 | * Search and improve suboptimal subsequences | ||
| 13 | |||
| 14 | ## New commands | ||
| 15 | |||
| 16 | * notation: show valid moves | ||
diff --git a/TODO/installation.md b/TODO/installation.md deleted file mode 100644 index 7f632c2..0000000 --- a/TODO/installation.md +++ /dev/null | |||
| @@ -1,14 +0,0 @@ | |||
| 1 | # Simplify and improve installation | ||
| 2 | |||
| 3 | ## Tables | ||
| 4 | |||
| 5 | * Make install should generate tables, or add a "make tables" target to | ||
| 6 | generate tables. | ||
| 7 | * Make tables should also check for existing files and remove old ones | ||
| 8 | (maybe more for nissy's command than for makefile). | ||
| 9 | |||
| 10 | ## Correctness | ||
| 11 | |||
| 12 | * Add checksum for all generated files. | ||
| 13 | * Hard-code results? Check for compatibility problems between different OSes | ||
| 14 | and filesystems - but there should not be any, since we use stdint.h. | ||
diff --git a/TODO/new-feature-ideas.md b/TODO/new-feature-ideas.md deleted file mode 100644 index 067d440..0000000 --- a/TODO/new-feature-ideas.md +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | # Possible new features and improvements | ||
| 2 | |||
| 3 | This file contains non-refined ideas. Once an idea gets refined, it will | ||
| 4 | get its own file and more details. | ||
| 5 | |||
| 6 | ## Steps | ||
| 7 | |||
| 8 | * QTM solver | ||
| 9 | * 5-side solver (for robots) | ||
| 10 | * Other steps (cross, blocks, LSE...) | ||
| 11 | |||
| 12 | ## UX features | ||
| 13 | |||
| 14 | * Save algs as variables and edit them (like in old nissy) | ||
| 15 | * Use a logging system for previously run commands, info, results... | ||
| 16 | (e.g. when solving with -c solutions are not shown, they can be logged here) | ||
| 17 | * Configurability: add an "alias" command, run config file at startup | ||
| 18 | * Input cube state directly instead of moves (ugly from command line / file) | ||
| 19 | |||
| 20 | ## Improvements | ||
| 21 | |||
| 22 | * Optimal solver: when asking only for one solution, scan for upper bound in | ||
| 23 | parallel using a non-optimal (but fast) solver (e.g. twophase). | ||
| 24 | * Optimal solver: up to a small bound, try with a small pruning table. | ||
| 25 | * Optimal solver: start at different depths in parallel | ||
| 26 | * Multi-step solver: make more general | ||
| 27 | |||
| 28 | ## New features | ||
| 29 | |||
| 30 | * Allow user to specify moveset manually (see issue \#5 on github) | ||
| 31 | * EO analysis (and also DR and HTR analysis): group similar EOs (Jay) | ||
| 32 | * HTR "maze" analysis? | ||
diff --git a/TODO/parser.md b/TODO/parser.md deleted file mode 100644 index 134f0d7..0000000 --- a/TODO/parser.md +++ /dev/null | |||
| @@ -1,13 +0,0 @@ | |||
| 1 | # Improve command parser | ||
| 2 | |||
| 3 | First, expand this TODO file to be more precise. | ||
| 4 | |||
| 5 | ## Refactor | ||
| 6 | |||
| 7 | * The syntax of a command's options should be described by data, not by a | ||
| 8 | parser function. | ||
| 9 | * A single parser function can then parse options for all commands. | ||
| 10 | |||
| 11 | ## Usability | ||
| 12 | |||
| 13 | * Better error messages! | ||
diff --git a/TODO/refactoring.md b/TODO/refactoring.md deleted file mode 100644 index eedbd20..0000000 --- a/TODO/refactoring.md +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | # Refactoring | ||
| 2 | |||
| 3 | ## Init functions | ||
| 4 | |||
| 5 | * All .h files should have a single init function. | ||
| 6 | * This function should initialize everything that this module needs, including | ||
| 7 | calling the init functions of the modules it depends on. | ||
| 8 | * To avoid multiple initialization of the same module, each should have a | ||
| 9 | static bool initialized variable. | ||
| 10 | * Everything that a module needs should be initialized by init(), avoid | ||
| 11 | initializing stuff when solving. Exception: pruning tables, move tables. | ||
| 12 | * Most functions should generate some tables and save them to disk. | ||
| 13 | * Init functions should have a consistent structure (e.g. the way they check | ||
| 14 | if the tables are already generated should be the same). | ||
| 15 | |||
| 16 | ## Cube types | ||
| 17 | |||
| 18 | * Get rid of cubetype.h, split type definitionss into the other modules. | ||
| 19 | * Every type definition should be in the most fundamental module that needs it. | ||
| 20 | |||
| 21 | ## Code style | ||
| 22 | |||
| 23 | * Stop declaring all variables at the beginning of a function. | ||
| 24 | * Remove variable names from prototypes. | ||
| 25 | * Sort function implementations alphabetically, ignore static vs non static. | ||
| 26 | * Rename functions and variable to have a consistent naming scheme. | ||
| 27 | * Functions that copy data: swap src and dest, follow memcpy standard. | ||
| 28 | * Read style(9) and decide what to implement. | ||
diff --git a/TODO/testing.md b/TODO/testing.md deleted file mode 100644 index 1deb93a..0000000 --- a/TODO/testing.md +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | # Testing | ||
| 2 | |||
| 3 | ## Write tests | ||
| 4 | |||
| 5 | * Write tests for each module. Some of might require refactoring (this is | ||
| 6 | a good thing!) | ||
diff --git a/TODO/webapp.md b/TODO/webapp.md deleted file mode 100644 index 4f8eddf..0000000 --- a/TODO/webapp.md +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | # Towards a nissy webapp | ||
| 2 | |||
| 3 | ## Architecture | ||
| 4 | |||
| 5 | * Split in client / server. | ||
| 6 | * Server can load and keep in memory all the tables, client(s) send messages to | ||
| 7 | the server to run commands. | ||
| 8 | * Use UNIX sockets only first, maybe later try WinSock. | ||
| 9 | |||
| 10 | ## Simple webapp | ||
| 11 | |||
| 12 | * Investigate how to use fastcgi, try simple program first. | ||
| 13 | * Decide what limits to put in terms of resources and write a "filter" script | ||
| 14 | to block big requests (maybe use a timeout). | ||
| 15 | |||
| 16 | ## Advanced webapp | ||
| 17 | |||
| 18 | * Use cubing.js for nice graphics. | ||
| 19 | * Port it to a graphical desktop version too. | ||
diff --git a/old/maybe-useful-coord.c b/old/maybe-useful-coord.c deleted file mode 100644 index 9ab2971..0000000 --- a/old/maybe-useful-coord.c +++ /dev/null | |||
| @@ -1,181 +0,0 @@ | |||
| 1 | int | ||
| 2 | array_ep_to_epos(int *ep, int *ss) | ||
| 3 | { | ||
| 4 | int epos[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 5 | int eps[4]; | ||
| 6 | int i, j, is; | ||
| 7 | |||
| 8 | for (i = 0, is = 0; i < 12; i++) { | ||
| 9 | for (j = 0; j < 4; j++) { | ||
| 10 | if (ep[i] == ss[j]) { | ||
| 11 | eps[is++] = j; | ||
| 12 | epos[i] = 1; | ||
| 13 | } | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | for (i = 0; i < 4; i++) | ||
| 18 | swap(&epos[ss[i]], &epos[i+8]); | ||
| 19 | |||
| 20 | return 24 * subset_to_index(epos, 12, 4) + perm_to_index(eps, 4); | ||
| 21 | } | ||
| 22 | |||
| 23 | void | ||
| 24 | epos_to_compatible_ep(int epos, int *ep, int *ss) | ||
| 25 | { | ||
| 26 | int i, j, k, other[8]; | ||
| 27 | bool flag; | ||
| 28 | |||
| 29 | for (i = 0; i < 12; i++) | ||
| 30 | ep[i] = -1; | ||
| 31 | |||
| 32 | epos_to_partial_ep(epos, ep, ss); | ||
| 33 | |||
| 34 | for (i = 0, j = 0; i < 12; i++) { | ||
| 35 | flag = false; | ||
| 36 | for (k = 0; k < 4; k++) | ||
| 37 | flag = flag || (i == ss[k]); | ||
| 38 | if (!flag) | ||
| 39 | other[j++] = i; | ||
| 40 | } | ||
| 41 | |||
| 42 | for (i = 0, j = 0; i < 12; i++) | ||
| 43 | if (ep[i] == -1) | ||
| 44 | ep[i] = other[j++]; | ||
| 45 | } | ||
| 46 | |||
| 47 | void | ||
| 48 | epos_to_partial_ep(int epos, int *ep, int *ss) | ||
| 49 | { | ||
| 50 | int i, is, eposs[12], eps[4]; | ||
| 51 | |||
| 52 | index_to_perm(epos % FACTORIAL4, 4, eps); | ||
| 53 | index_to_subset(epos / FACTORIAL4, 12, 4, eposs); | ||
| 54 | |||
| 55 | for (i = 0; i < 4; i++) | ||
| 56 | swap(&eposs[ss[i]], &eposs[i+8]); | ||
| 57 | |||
| 58 | for (i = 0, is = 0; i < 12; i++) | ||
| 59 | if (eposs[i]) | ||
| 60 | ep[i] = ss[eps[is++]]; | ||
| 61 | } | ||
| 62 | |||
| 63 | void | ||
| 64 | fix_eorleoud(CubeArray *arr) | ||
| 65 | { | ||
| 66 | int i; | ||
| 67 | |||
| 68 | for (i = 0; i < 12; i++) { | ||
| 69 | if ((edge_slice(i) == 0 && edge_slice(arr->ep[i]) != 0) || | ||
| 70 | (edge_slice(i) != 0 && edge_slice(arr->ep[i]) == 0)) { | ||
| 71 | arr->eorl[i] = 1 - arr->eofb[i]; | ||
| 72 | } else { | ||
| 73 | arr->eorl[i] = arr->eofb[i]; | ||
| 74 | } | ||
| 75 | |||
| 76 | if ((edge_slice(i) == 2 && edge_slice(arr->ep[i]) != 2) || | ||
| 77 | (edge_slice(i) != 2 && edge_slice(arr->ep[i]) == 2)) { | ||
| 78 | arr->eoud[i] = 1 - arr->eofb[i]; | ||
| 79 | } else { | ||
| 80 | arr->eoud[i] = arr->eofb[i]; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | void | ||
| 86 | fix_cofbcorl(CubeArray *arr) | ||
| 87 | { | ||
| 88 | int i; | ||
| 89 | |||
| 90 | for (i = 0; i < 8; i++) { | ||
| 91 | if (i % 2 == arr->cp[i] % 2) { | ||
| 92 | arr->cofb[i] = arr->coud[i]; | ||
| 93 | arr->corl[i] = arr->coud[i]; | ||
| 94 | } else { | ||
| 95 | if (arr->cp[i] % 2 == 0) { | ||
| 96 | arr->cofb[i] = (arr->coud[i]+1)%3; | ||
| 97 | arr->corl[i] = (arr->coud[i]+2)%3; | ||
| 98 | } else { | ||
| 99 | arr->cofb[i] = (arr->coud[i]+2)%3; | ||
| 100 | arr->corl[i] = (arr->coud[i]+1)%3; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | Cube | ||
| 107 | admissible_ep(Cube cube, PieceFilter f) | ||
| 108 | { | ||
| 109 | CubeArray *arr = new_cubearray(cube, f); | ||
| 110 | Cube ret; | ||
| 111 | bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 112 | int i, j; | ||
| 113 | |||
| 114 | for (i = 0; i < 12; i++) | ||
| 115 | if (arr->ep[i] != -1) | ||
| 116 | used[arr->ep[i]] = true; | ||
| 117 | |||
| 118 | for (i = 0, j = 0; i < 12; i++) { | ||
| 119 | for ( ; j < 11 && used[j]; j++); | ||
| 120 | if (arr->ep[i] == -1) | ||
| 121 | arr->ep[i] = j++; | ||
| 122 | } | ||
| 123 | |||
| 124 | ret = arrays_to_cube(arr, pf_ep); | ||
| 125 | free_cubearray(arr, f); | ||
| 126 | |||
| 127 | return ret; | ||
| 128 | } | ||
| 129 | |||
| 130 | int | ||
| 131 | edge_slice(Edge e) { | ||
| 132 | if (e < 0 || e > 11) | ||
| 133 | return -1; | ||
| 134 | |||
| 135 | if (e == FR || e == FL || e == BL || e == BR) | ||
| 136 | return 0; | ||
| 137 | if (e == UR || e == UL || e == DR || e == DL) | ||
| 138 | return 1; | ||
| 139 | |||
| 140 | return 2; | ||
| 141 | } | ||
| 142 | |||
| 143 | int | ||
| 144 | piece_orientation(Cube cube, int piece, char *orientation) | ||
| 145 | { | ||
| 146 | int arr[12], n, b, x; | ||
| 147 | |||
| 148 | if (!strcmp(orientation, "eofb")) { | ||
| 149 | x = cube.eofb; | ||
| 150 | n = 12; | ||
| 151 | b = 2; | ||
| 152 | } else if (!strcmp(orientation, "eorl")) { | ||
| 153 | x = cube.eorl; | ||
| 154 | n = 12; | ||
| 155 | b = 2; | ||
| 156 | } else if (!strcmp(orientation, "eoud")) { | ||
| 157 | x = cube.eoud; | ||
| 158 | n = 12; | ||
| 159 | b = 2; | ||
| 160 | } else if (!strcmp(orientation, "coud")) { | ||
| 161 | x = cube.coud; | ||
| 162 | n = 8; | ||
| 163 | b = 3; | ||
| 164 | } else if (!strcmp(orientation, "corl")) { | ||
| 165 | x = cube.corl; | ||
| 166 | n = 8; | ||
| 167 | b = 3; | ||
| 168 | } else if (!strcmp(orientation, "cofb")) { | ||
| 169 | x = cube.cofb; | ||
| 170 | n = 8; | ||
| 171 | b = 3; | ||
| 172 | } else { | ||
| 173 | return -1; | ||
| 174 | } | ||
| 175 | |||
| 176 | int_to_sum_zero_array(x, b, n, arr); | ||
| 177 | if (piece < n) | ||
| 178 | return arr[piece]; | ||
| 179 | |||
| 180 | return -1; | ||
| 181 | } | ||
diff --git a/old/maybe-useful-steps.c b/old/maybe-useful-steps.c deleted file mode 100644 index 2a20dd9..0000000 --- a/old/maybe-useful-steps.c +++ /dev/null | |||
| @@ -1,1111 +0,0 @@ | |||
| 1 | #include "steps.h" | ||
| 2 | |||
| 3 | #define UPDATECHECKSTOP(a, b, c) if ((a=(MAX((a),(b))))>(c)) return (a); | ||
| 4 | |||
| 5 | static int estimate_stepalt(StepAlt *a, uint64_t *ind); | ||
| 6 | |||
| 7 | /* Checkers and validators ***************************************************/ | ||
| 8 | |||
| 9 | /* TODO: these should be with Cube *cube (and all need to change) */ | ||
| 10 | /* Maybe move them to cube.c */ | ||
| 11 | static bool check_centers(Cube cube); | ||
| 12 | static bool check_coud_HTM(Cube cube); | ||
| 13 | static bool check_coud_URF(Cube cube); | ||
| 14 | static bool check_corners_HTM(Cube cube); | ||
| 15 | static bool check_corners_URF(Cube cube); | ||
| 16 | static bool check_cornershtr(Cube cube); | ||
| 17 | static bool check_eofb(Cube cube); | ||
| 18 | static bool check_drud(Cube cube); | ||
| 19 | static bool check_htr(Cube cube); | ||
| 20 | |||
| 21 | static bool always_valid(Alg *alg); | ||
| 22 | static bool validate_singlecw_ending(Alg *alg); | ||
| 23 | |||
| 24 | /* Messages for when cube is not ready ***************************************/ | ||
| 25 | |||
| 26 | static char check_centers_msg[100] = "cube must be oriented (centers solved)"; | ||
| 27 | static char check_eo_msg[100] = "EO must be solved on given axis"; | ||
| 28 | static char check_dr_msg[100] = "DR must be solved on given axis"; | ||
| 29 | static char check_htr_msg[100] = "HTR must be solved"; | ||
| 30 | static char check_drany_msg[100] = "DR must be solved on at least one axis"; | ||
| 31 | |||
| 32 | /* Steps *********************************************************************/ | ||
| 33 | |||
| 34 | /* Optimal solvers *******************/ | ||
| 35 | |||
| 36 | Step | ||
| 37 | optimal_HTM = { | ||
| 38 | .shortname = "optimal", | ||
| 39 | .name = "Optimal solve (in HTM)", | ||
| 40 | |||
| 41 | .final = true, | ||
| 42 | .is_done = is_solved, | ||
| 43 | .estimate = estimate_nxopt31_HTM, | ||
| 44 | .ready = check_centers, | ||
| 45 | .ready_msg = check_centers_msg, | ||
| 46 | .is_valid = always_valid, | ||
| 47 | .moveset = &moveset_HTM, | ||
| 48 | |||
| 49 | .pre_trans = uf, | ||
| 50 | |||
| 51 | .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, | ||
| 52 | .ntables = 2, | ||
| 53 | }; | ||
| 54 | |||
| 55 | Step | ||
| 56 | optimal_light_HTM = { | ||
| 57 | .shortname = "light", | ||
| 58 | .name = "Optimal solve (in HTM), small table (500Mb RAM total)", | ||
| 59 | |||
| 60 | .final = true, | ||
| 61 | .is_done = is_solved, | ||
| 62 | .estimate = estimate_light_HTM, | ||
| 63 | .ready = check_centers, | ||
| 64 | .ready_msg = check_centers_msg, | ||
| 65 | .is_valid = always_valid, | ||
| 66 | .moveset = &moveset_HTM, | ||
| 67 | |||
| 68 | .pre_trans = uf, | ||
| 69 | |||
| 70 | .tables = {&pd_drud_sym16_HTM, &pd_corners_HTM}, | ||
| 71 | .ntables = 2, | ||
| 72 | }; | ||
| 73 | |||
| 74 | /* Optimal after EO ******************/ | ||
| 75 | |||
| 76 | Step | ||
| 77 | eofin_eo = { | ||
| 78 | .shortname = "eofin", | ||
| 79 | .name = "Optimal solve after EO without breaking EO (detected)", | ||
| 80 | |||
| 81 | .final = true, | ||
| 82 | .is_done = is_solved, | ||
| 83 | .estimate = estimate_nxopt31_HTM, | ||
| 84 | .ready = check_eofb, | ||
| 85 | .ready_msg = check_eo_msg, | ||
| 86 | .is_valid = always_valid, | ||
| 87 | .moveset = &moveset_eofb, | ||
| 88 | |||
| 89 | .detect = detect_pretrans_eofb, | ||
| 90 | |||
| 91 | .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, | ||
| 92 | .ntables = 2, | ||
| 93 | }; | ||
| 94 | |||
| 95 | Step | ||
| 96 | eofbfin_eofb = { | ||
| 97 | .shortname = "eofbfin", | ||
| 98 | .name = "Optimal after EO on F/B without breaking EO", | ||
| 99 | |||
| 100 | .final = true, | ||
| 101 | .is_done = is_solved, | ||
| 102 | .estimate = estimate_nxopt31_HTM, | ||
| 103 | .ready = check_eofb, | ||
| 104 | .ready_msg = check_eo_msg, | ||
| 105 | .is_valid = always_valid, | ||
| 106 | .moveset = &moveset_eofb, | ||
| 107 | |||
| 108 | .pre_trans = uf, | ||
| 109 | |||
| 110 | .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, | ||
| 111 | .ntables = 2, | ||
| 112 | }; | ||
| 113 | |||
| 114 | Step | ||
| 115 | eorlfin_eorl = { | ||
| 116 | .shortname = "eorlfin", | ||
| 117 | .name = "Optimal after EO on R/L without breaking EO", | ||
| 118 | |||
| 119 | .final = true, | ||
| 120 | .is_done = is_solved, | ||
| 121 | .estimate = estimate_nxopt31_HTM, | ||
| 122 | .ready = check_eofb, | ||
| 123 | .ready_msg = check_eo_msg, | ||
| 124 | .is_valid = always_valid, | ||
| 125 | .moveset = &moveset_eofb, | ||
| 126 | |||
| 127 | .pre_trans = ur, | ||
| 128 | |||
| 129 | .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, | ||
| 130 | .ntables = 2, | ||
| 131 | }; | ||
| 132 | |||
| 133 | Step | ||
| 134 | eoudfin_eoud = { | ||
| 135 | .shortname = "eoudfin", | ||
| 136 | .name = "Optimal after EO on U/D without breaking EO", | ||
| 137 | |||
| 138 | .final = true, | ||
| 139 | .is_done = is_solved, | ||
| 140 | .estimate = estimate_nxopt31_HTM, | ||
| 141 | .ready = check_eofb, | ||
| 142 | .ready_msg = check_eo_msg, | ||
| 143 | .is_valid = always_valid, | ||
| 144 | .moveset = &moveset_eofb, | ||
| 145 | |||
| 146 | .pre_trans = fd, | ||
| 147 | |||
| 148 | .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, | ||
| 149 | .ntables = 2, | ||
| 150 | }; | ||
| 151 | |||
| 152 | /* EO steps **************************/ | ||
| 153 | Step | ||
| 154 | eoany_HTM = { | ||
| 155 | .shortname = "eo", | ||
| 156 | .name = "EO on any axis", | ||
| 157 | |||
| 158 | .final = false, | ||
| 159 | .is_done = check_eofb, | ||
| 160 | .estimate = estimate_eofb_HTM, | ||
| 161 | .ready = check_centers, | ||
| 162 | .ready_msg = check_centers_msg, | ||
| 163 | .is_valid = validate_singlecw_ending, | ||
| 164 | .moveset = &moveset_HTM, | ||
| 165 | |||
| 166 | .detect = detect_pretrans_void_3axis, | ||
| 167 | |||
| 168 | .tables = {&pd_eofb_HTM}, | ||
| 169 | .ntables = 1, | ||
| 170 | }; | ||
| 171 | |||
| 172 | Step | ||
| 173 | eofb_HTM = { | ||
| 174 | .shortname = "eofb", | ||
| 175 | .name = "EO on F/B", | ||
| 176 | |||
| 177 | .final = false, | ||
| 178 | .is_done = check_eofb, | ||
| 179 | .estimate = estimate_eofb_HTM, | ||
| 180 | .ready = check_centers, | ||
| 181 | .ready_msg = check_centers_msg, | ||
| 182 | .is_valid = validate_singlecw_ending, | ||
| 183 | .moveset = &moveset_HTM, | ||
| 184 | |||
| 185 | .pre_trans = uf, | ||
| 186 | |||
| 187 | .tables = {&pd_eofb_HTM}, | ||
| 188 | .ntables = 1, | ||
| 189 | }; | ||
| 190 | |||
| 191 | Step | ||
| 192 | eorl_HTM = { | ||
| 193 | .shortname = "eorl", | ||
| 194 | .name = "EO on R/L", | ||
| 195 | |||
| 196 | .final = false, | ||
| 197 | .is_done = check_eofb, | ||
| 198 | .estimate = estimate_eofb_HTM, | ||
| 199 | .ready = check_centers, | ||
| 200 | .ready_msg = check_centers_msg, | ||
| 201 | .is_valid = validate_singlecw_ending, | ||
| 202 | .moveset = &moveset_HTM, | ||
| 203 | |||
| 204 | .pre_trans = ur, | ||
| 205 | |||
| 206 | .tables = {&pd_eofb_HTM}, | ||
| 207 | .ntables = 1, | ||
| 208 | }; | ||
| 209 | |||
| 210 | Step | ||
| 211 | eoud_HTM = { | ||
| 212 | .shortname = "eoud", | ||
| 213 | .name = "EO on U/D", | ||
| 214 | |||
| 215 | .final = false, | ||
| 216 | .is_done = check_eofb, | ||
| 217 | .estimate = estimate_eofb_HTM, | ||
| 218 | .ready = check_centers, | ||
| 219 | .ready_msg = check_centers_msg, | ||
| 220 | .is_valid = validate_singlecw_ending, | ||
| 221 | .moveset = &moveset_HTM, | ||
| 222 | |||
| 223 | .pre_trans = fd, | ||
| 224 | |||
| 225 | .tables = {&pd_eofb_HTM}, | ||
| 226 | .ntables = 1, | ||
| 227 | }; | ||
| 228 | |||
| 229 | /* CO steps **************************/ | ||
| 230 | Step | ||
| 231 | coany_HTM = { | ||
| 232 | .shortname = "co", | ||
| 233 | .name = "CO on any axis", | ||
| 234 | |||
| 235 | .final = false, | ||
| 236 | .is_done = check_coud_HTM, | ||
| 237 | .estimate = estimate_coud_HTM, | ||
| 238 | .ready = NULL, | ||
| 239 | .is_valid = validate_singlecw_ending, | ||
| 240 | .moveset = &moveset_HTM, | ||
| 241 | |||
| 242 | .detect = detect_pretrans_void_3axis, | ||
| 243 | |||
| 244 | .tables = {&pd_coud_HTM}, | ||
| 245 | .ntables = 1, | ||
| 246 | }; | ||
| 247 | |||
| 248 | Step | ||
| 249 | coud_HTM = { | ||
| 250 | .shortname = "coud", | ||
| 251 | .name = "CO on U/D", | ||
| 252 | |||
| 253 | .final = false, | ||
| 254 | .is_done = check_coud_HTM, | ||
| 255 | .estimate = estimate_coud_HTM, | ||
| 256 | .ready = NULL, | ||
| 257 | .is_valid = validate_singlecw_ending, | ||
| 258 | .moveset = &moveset_HTM, | ||
| 259 | |||
| 260 | .pre_trans = uf, | ||
| 261 | |||
| 262 | .tables = {&pd_coud_HTM}, | ||
| 263 | .ntables = 1, | ||
| 264 | }; | ||
| 265 | |||
| 266 | Step | ||
| 267 | corl_HTM = { | ||
| 268 | .shortname = "corl", | ||
| 269 | .name = "CO on R/L", | ||
| 270 | |||
| 271 | .final = false, | ||
| 272 | .is_done = check_coud_HTM, | ||
| 273 | .estimate = estimate_coud_HTM, | ||
| 274 | .ready = NULL, | ||
| 275 | .is_valid = validate_singlecw_ending, | ||
| 276 | .moveset = &moveset_HTM, | ||
| 277 | |||
| 278 | .pre_trans = rf, | ||
| 279 | |||
| 280 | .tables = {&pd_coud_HTM}, | ||
| 281 | .ntables = 1, | ||
| 282 | }; | ||
| 283 | |||
| 284 | Step | ||
| 285 | cofb_HTM = { | ||
| 286 | .shortname = "cofb", | ||
| 287 | .name = "CO on F/B", | ||
| 288 | |||
| 289 | .final = false, | ||
| 290 | .is_done = check_coud_HTM, | ||
| 291 | .estimate = estimate_coud_HTM, | ||
| 292 | .ready = NULL, | ||
| 293 | .is_valid = validate_singlecw_ending, | ||
| 294 | .moveset = &moveset_HTM, | ||
| 295 | |||
| 296 | .pre_trans = fd, | ||
| 297 | |||
| 298 | .tables = {&pd_coud_HTM}, | ||
| 299 | .ntables = 1, | ||
| 300 | }; | ||
| 301 | |||
| 302 | Step | ||
| 303 | coany_URF = { | ||
| 304 | .shortname = "co-URF", | ||
| 305 | .name = "CO any axis (URF moveset)", | ||
| 306 | |||
| 307 | .final = false, | ||
| 308 | .is_done = check_coud_URF, | ||
| 309 | .estimate = estimate_coud_URF, | ||
| 310 | .ready = NULL, | ||
| 311 | .is_valid = validate_singlecw_ending, | ||
| 312 | .moveset = &moveset_URF, | ||
| 313 | |||
| 314 | .detect = detect_pretrans_void_3axis, | ||
| 315 | |||
| 316 | .tables = {&pd_coud_HTM}, | ||
| 317 | .ntables = 1, | ||
| 318 | }; | ||
| 319 | |||
| 320 | Step | ||
| 321 | coud_URF = { | ||
| 322 | .shortname = "coud-URF", | ||
| 323 | .name = "CO on U/D (URF moveset)", | ||
| 324 | |||
| 325 | .final = false, | ||
| 326 | .is_done = check_coud_URF, | ||
| 327 | .estimate = estimate_coud_URF, | ||
| 328 | .ready = NULL, | ||
| 329 | .is_valid = validate_singlecw_ending, | ||
| 330 | .moveset = &moveset_URF, | ||
| 331 | |||
| 332 | .pre_trans = uf, | ||
| 333 | |||
| 334 | .tables = {&pd_coud_HTM}, | ||
| 335 | .ntables = 1, | ||
| 336 | }; | ||
| 337 | |||
| 338 | Step | ||
| 339 | corl_URF = { | ||
| 340 | .shortname = "corl-URF", | ||
| 341 | .name = "CO on R/L (URF moveset)", | ||
| 342 | |||
| 343 | .final = false, | ||
| 344 | .is_done = check_coud_URF, | ||
| 345 | .estimate = estimate_coud_URF, | ||
| 346 | .ready = NULL, | ||
| 347 | .is_valid = validate_singlecw_ending, | ||
| 348 | .moveset = &moveset_URF, | ||
| 349 | |||
| 350 | .pre_trans = rf, | ||
| 351 | |||
| 352 | .tables = {&pd_coud_HTM}, | ||
| 353 | .ntables = 1, | ||
| 354 | }; | ||
| 355 | |||
| 356 | Step | ||
| 357 | cofb_URF = { | ||
| 358 | .shortname = "cofb-URF", | ||
| 359 | .name = "CO on F/B (URF moveset)", | ||
| 360 | |||
| 361 | .final = false, | ||
| 362 | .is_done = check_coud_URF, | ||
| 363 | .estimate = estimate_coud_URF, | ||
| 364 | .ready = NULL, | ||
| 365 | .is_valid = validate_singlecw_ending, | ||
| 366 | .moveset = &moveset_URF, | ||
| 367 | |||
| 368 | .pre_trans = fd, | ||
| 369 | |||
| 370 | .tables = {&pd_coud_HTM}, | ||
| 371 | .ntables = 1, | ||
| 372 | }; | ||
| 373 | |||
| 374 | /* Misc corner steps *****************/ | ||
| 375 | Step | ||
| 376 | cornershtr_HTM = { | ||
| 377 | .shortname = "chtr", | ||
| 378 | .name = "Solve corners to HTR state", | ||
| 379 | |||
| 380 | .final = false, | ||
| 381 | .is_done = check_cornershtr, | ||
| 382 | .estimate = estimate_cornershtr_HTM, | ||
| 383 | .ready = NULL, | ||
| 384 | .is_valid = validate_singlecw_ending, | ||
| 385 | .moveset = &moveset_HTM, | ||
| 386 | |||
| 387 | .pre_trans = uf, | ||
| 388 | |||
| 389 | .tables = {&pd_cornershtr_HTM}, | ||
| 390 | .ntables = 1, | ||
| 391 | }; | ||
| 392 | |||
| 393 | Step | ||
| 394 | cornershtr_URF = { | ||
| 395 | .shortname = "chtr-URF", | ||
| 396 | .name = "Solve corners to HTR state (URF moveset)", | ||
| 397 | |||
| 398 | .final = false, | ||
| 399 | .is_done = check_cornershtr, | ||
| 400 | .estimate = estimate_cornershtr_URF, | ||
| 401 | .ready = NULL, | ||
| 402 | .is_valid = validate_singlecw_ending, | ||
| 403 | .moveset = &moveset_URF, | ||
| 404 | |||
| 405 | .pre_trans = uf, | ||
| 406 | |||
| 407 | .tables = {&pd_cornershtr_HTM}, | ||
| 408 | .ntables = 1, | ||
| 409 | }; | ||
| 410 | |||
| 411 | Step | ||
| 412 | corners_HTM = { | ||
| 413 | .shortname = "corners", | ||
| 414 | .name = "Solve corners", | ||
| 415 | |||
| 416 | .final = true, | ||
| 417 | .is_done = check_corners_HTM, | ||
| 418 | .estimate = estimate_corners_HTM, | ||
| 419 | .ready = NULL, | ||
| 420 | .is_valid = always_valid, | ||
| 421 | .moveset = &moveset_HTM, | ||
| 422 | |||
| 423 | .pre_trans = uf, | ||
| 424 | |||
| 425 | .tables = {&pd_corners_HTM}, | ||
| 426 | .ntables = 1, | ||
| 427 | }; | ||
| 428 | |||
| 429 | Step | ||
| 430 | corners_URF = { | ||
| 431 | .shortname = "corners-URF", | ||
| 432 | .name = "Solve corners (URF moveset)", | ||
| 433 | |||
| 434 | .final = true, /* TODO: check if this works with reorient */ | ||
| 435 | .is_done = check_corners_URF, | ||
| 436 | .estimate = estimate_corners_URF, | ||
| 437 | .ready = NULL, | ||
| 438 | .is_valid = always_valid, | ||
| 439 | .moveset = &moveset_URF, | ||
| 440 | |||
| 441 | .pre_trans = uf, | ||
| 442 | |||
| 443 | .tables = {&pd_corners_HTM}, | ||
| 444 | .ntables = 1, | ||
| 445 | }; | ||
| 446 | |||
| 447 | /* DR steps **************************/ | ||
| 448 | Step | ||
| 449 | drany_HTM = { | ||
| 450 | .shortname = "dr", | ||
| 451 | .name = "DR on any axis", | ||
| 452 | |||
| 453 | .final = false, | ||
| 454 | .is_done = check_drud, | ||
| 455 | .estimate = estimate_drud_HTM, | ||
| 456 | .ready = check_centers, | ||
| 457 | .ready_msg = check_centers_msg, | ||
| 458 | .is_valid = validate_singlecw_ending, | ||
| 459 | .moveset = &moveset_HTM, | ||
| 460 | |||
| 461 | .detect = detect_pretrans_void_3axis, | ||
| 462 | |||
| 463 | .tables = {&pd_drud_sym16_HTM}, | ||
| 464 | .ntables = 1, | ||
| 465 | }; | ||
| 466 | |||
| 467 | Step | ||
| 468 | drud_HTM = { | ||
| 469 | .shortname = "drud", | ||
| 470 | .name = "DR on U/D", | ||
| 471 | |||
| 472 | .final = false, | ||
| 473 | .is_done = check_drud, | ||
| 474 | .estimate = estimate_drud_HTM, | ||
| 475 | .ready = check_centers, | ||
| 476 | .ready_msg = check_centers_msg, | ||
| 477 | .is_valid = validate_singlecw_ending, | ||
| 478 | .moveset = &moveset_HTM, | ||
| 479 | |||
| 480 | .pre_trans = uf, | ||
| 481 | |||
| 482 | .tables = {&pd_drud_sym16_HTM}, | ||
| 483 | .ntables = 1, | ||
| 484 | }; | ||
| 485 | |||
| 486 | Step | ||
| 487 | drrl_HTM = { | ||
| 488 | .shortname = "drrl", | ||
| 489 | .name = "DR on R/L", | ||
| 490 | |||
| 491 | .final = false, | ||
| 492 | .is_done = check_drud, | ||
| 493 | .estimate = estimate_drud_HTM, | ||
| 494 | .ready = check_centers, | ||
| 495 | .ready_msg = check_centers_msg, | ||
| 496 | .is_valid = validate_singlecw_ending, | ||
| 497 | .moveset = &moveset_HTM, | ||
| 498 | |||
| 499 | .pre_trans = rf, | ||
| 500 | |||
| 501 | .tables = {&pd_drud_sym16_HTM}, | ||
| 502 | .ntables = 1, | ||
| 503 | }; | ||
| 504 | |||
| 505 | Step | ||
| 506 | drfb_HTM = { | ||
| 507 | .shortname = "drfb", | ||
| 508 | .name = "DR on F/B", | ||
| 509 | |||
| 510 | .final = false, | ||
| 511 | .is_done = check_drud, | ||
| 512 | .estimate = estimate_drud_HTM, | ||
| 513 | .ready = check_centers, | ||
| 514 | .ready_msg = check_centers_msg, | ||
| 515 | .is_valid = validate_singlecw_ending, | ||
| 516 | .moveset = &moveset_HTM, | ||
| 517 | |||
| 518 | .pre_trans = fd, | ||
| 519 | |||
| 520 | .tables = {&pd_drud_sym16_HTM}, | ||
| 521 | .ntables = 1, | ||
| 522 | }; | ||
| 523 | |||
| 524 | /* DR from EO */ | ||
| 525 | Step | ||
| 526 | dr_eo = { | ||
| 527 | .shortname = "dr-eo", | ||
| 528 | .name = "DR without breaking EO (automatically detected)", | ||
| 529 | |||
| 530 | .final = false, | ||
| 531 | .is_done = check_drud, | ||
| 532 | .estimate = estimate_dr_eofb, | ||
| 533 | .ready = check_eofb, | ||
| 534 | .ready_msg = check_eo_msg, | ||
| 535 | .is_valid = validate_singlecw_ending, | ||
| 536 | .moveset = &moveset_eofb, | ||
| 537 | |||
| 538 | .detect = detect_pretrans_eofb, | ||
| 539 | |||
| 540 | .tables = {&pd_drud_eofb}, | ||
| 541 | .ntables = 1, | ||
| 542 | }; | ||
| 543 | |||
| 544 | Step | ||
| 545 | dr_eofb = { | ||
| 546 | .shortname = "dr-eofb", | ||
| 547 | .name = "DR on U/D or R/L without breaking EO on F/B", | ||
| 548 | |||
| 549 | .final = false, | ||
| 550 | .is_done = check_drud, | ||
| 551 | .estimate = estimate_dr_eofb, | ||
| 552 | .ready = check_eofb, | ||
| 553 | .ready_msg = check_eo_msg, | ||
| 554 | .is_valid = validate_singlecw_ending, | ||
| 555 | .moveset = &moveset_eofb, | ||
| 556 | |||
| 557 | .pre_trans = uf, | ||
| 558 | |||
| 559 | .tables = {&pd_drud_eofb}, | ||
| 560 | .ntables = 1, | ||
| 561 | }; | ||
| 562 | |||
| 563 | Step | ||
| 564 | dr_eorl = { | ||
| 565 | .shortname = "dr-eorl", | ||
| 566 | .name = "DR on U/D or F/B without breaking EO on R/L", | ||
| 567 | |||
| 568 | .final = false, | ||
| 569 | .is_done = check_drud, | ||
| 570 | .estimate = estimate_dr_eofb, | ||
| 571 | .ready = check_eofb, | ||
| 572 | .ready_msg = check_eo_msg, | ||
| 573 | .is_valid = validate_singlecw_ending, | ||
| 574 | .moveset = &moveset_eofb, | ||
| 575 | |||
| 576 | .pre_trans = ur, | ||
| 577 | |||
| 578 | .tables = {&pd_drud_eofb}, | ||
| 579 | .ntables = 1, | ||
| 580 | }; | ||
| 581 | |||
| 582 | Step | ||
| 583 | dr_eoud = { | ||
| 584 | .shortname = "dr-eoud", | ||
| 585 | .name = "DR on R/L or F/B without breaking EO on U/D", | ||
| 586 | |||
| 587 | .final = false, | ||
| 588 | .is_done = check_drud, | ||
| 589 | .estimate = estimate_dr_eofb, | ||
| 590 | .ready = check_eofb, | ||
| 591 | .ready_msg = check_eo_msg, | ||
| 592 | .is_valid = validate_singlecw_ending, | ||
| 593 | .moveset = &moveset_eofb, | ||
| 594 | |||
| 595 | .pre_trans = fd, | ||
| 596 | |||
| 597 | .tables = {&pd_drud_eofb}, | ||
| 598 | .ntables = 1, | ||
| 599 | }; | ||
| 600 | |||
| 601 | Step | ||
| 602 | drud_eofb = { | ||
| 603 | .shortname = "drud-eofb", | ||
| 604 | .name = "DR on U/D without breaking EO on F/B", | ||
| 605 | |||
| 606 | .final = false, | ||
| 607 | .is_done = check_drud, | ||
| 608 | .estimate = estimate_drud_eofb, | ||
| 609 | .ready = check_eofb, | ||
| 610 | .ready_msg = check_eo_msg, | ||
| 611 | .is_valid = validate_singlecw_ending, | ||
| 612 | .moveset = &moveset_eofb, | ||
| 613 | |||
| 614 | .pre_trans = uf, | ||
| 615 | |||
| 616 | .tables = {&pd_drud_eofb}, | ||
| 617 | .ntables = 1, | ||
| 618 | }; | ||
| 619 | |||
| 620 | Step | ||
| 621 | drrl_eofb = { | ||
| 622 | .shortname = "drrl-eofb", | ||
| 623 | .name = "DR on R/L without breaking EO on F/B", | ||
| 624 | |||
| 625 | .final = false, | ||
| 626 | .is_done = check_drud, | ||
| 627 | .estimate = estimate_drud_eofb, | ||
| 628 | .ready = check_eofb, | ||
| 629 | .ready_msg = check_eo_msg, | ||
| 630 | .is_valid = validate_singlecw_ending, | ||
| 631 | .moveset = &moveset_eofb, | ||
| 632 | |||
| 633 | .pre_trans = rf, | ||
| 634 | |||
| 635 | .tables = {&pd_drud_eofb}, | ||
| 636 | .ntables = 1, | ||
| 637 | }; | ||
| 638 | |||
| 639 | Step | ||
| 640 | drud_eorl = { | ||
| 641 | .shortname = "drud-eorl", | ||
| 642 | .name = "DR on U/D without breaking EO on R/L", | ||
| 643 | |||
| 644 | .final = false, | ||
| 645 | .is_done = check_drud, | ||
| 646 | .estimate = estimate_drud_eofb, | ||
| 647 | .ready = check_eofb, | ||
| 648 | .ready_msg = check_eo_msg, | ||
| 649 | .is_valid = validate_singlecw_ending, | ||
| 650 | .moveset = &moveset_eofb, | ||
| 651 | |||
| 652 | .pre_trans = ur, | ||
| 653 | |||
| 654 | .tables = {&pd_drud_eofb}, | ||
| 655 | .ntables = 1, | ||
| 656 | }; | ||
| 657 | |||
| 658 | Step | ||
| 659 | drfb_eorl = { | ||
| 660 | .shortname = "drfb-eorl", | ||
| 661 | .name = "DR on F/B without breaking EO on R/L", | ||
| 662 | |||
| 663 | .final = false, | ||
| 664 | .is_done = check_drud, | ||
| 665 | .estimate = estimate_drud_eofb, | ||
| 666 | .ready = check_eofb, | ||
| 667 | .ready_msg = check_eo_msg, | ||
| 668 | .is_valid = validate_singlecw_ending, | ||
| 669 | .moveset = &moveset_eofb, | ||
| 670 | |||
| 671 | .pre_trans = fr, | ||
| 672 | |||
| 673 | .tables = {&pd_drud_eofb}, | ||
| 674 | .ntables = 1, | ||
| 675 | }; | ||
| 676 | |||
| 677 | Step | ||
| 678 | drfb_eoud = { | ||
| 679 | .shortname = "drfb-eoud", | ||
| 680 | .name = "DR on F/B without breaking EO on U/D", | ||
| 681 | |||
| 682 | .final = false, | ||
| 683 | .is_done = check_drud, | ||
| 684 | .estimate = estimate_drud_eofb, | ||
| 685 | .ready = check_eofb, | ||
| 686 | .ready_msg = check_eo_msg, | ||
| 687 | .is_valid = validate_singlecw_ending, | ||
| 688 | .moveset = &moveset_eofb, | ||
| 689 | |||
| 690 | .pre_trans = fd, | ||
| 691 | |||
| 692 | .tables = {&pd_drud_eofb}, | ||
| 693 | .ntables = 1, | ||
| 694 | }; | ||
| 695 | |||
| 696 | Step | ||
| 697 | drrl_eoud = { | ||
| 698 | .shortname = "drrl-eoud", | ||
| 699 | .name = "DR on R/L without breaking EO on U/D", | ||
| 700 | |||
| 701 | .final = false, | ||
| 702 | .is_done = check_drud, | ||
| 703 | .estimate = estimate_drud_eofb, | ||
| 704 | .ready = check_eofb, | ||
| 705 | .ready_msg = check_eo_msg, | ||
| 706 | .is_valid = validate_singlecw_ending, | ||
| 707 | .moveset = &moveset_eofb, | ||
| 708 | |||
| 709 | .pre_trans = rd, | ||
| 710 | |||
| 711 | .tables = {&pd_drud_eofb}, | ||
| 712 | .ntables = 1, | ||
| 713 | }; | ||
| 714 | |||
| 715 | /* DR finish steps */ | ||
| 716 | Step | ||
| 717 | dranyfin_DR = { | ||
| 718 | .shortname = "drfin", | ||
| 719 | .name = "DR finish on any axis without breaking DR", | ||
| 720 | |||
| 721 | .final = true, | ||
| 722 | .is_done = is_solved, | ||
| 723 | .estimate = estimate_drudfin_drud, | ||
| 724 | .ready = check_drud, | ||
| 725 | .ready_msg = check_drany_msg, | ||
| 726 | .is_valid = always_valid, | ||
| 727 | .moveset = &moveset_drud, | ||
| 728 | |||
| 729 | .detect = detect_pretrans_drud, | ||
| 730 | |||
| 731 | .tables = {&pd_drudfin_noE_sym16_drud}, | ||
| 732 | .ntables = 1, | ||
| 733 | }; | ||
| 734 | |||
| 735 | Step | ||
| 736 | drudfin_drud = { | ||
| 737 | .shortname = "drudfin", | ||
| 738 | .name = "DR finish on U/D without breaking DR", | ||
| 739 | |||
| 740 | .final = true, | ||
| 741 | .is_done = is_solved, | ||
| 742 | .estimate = estimate_drudfin_drud, | ||
| 743 | .ready = check_drud, | ||
| 744 | .ready_msg = check_dr_msg, | ||
| 745 | .is_valid = always_valid, | ||
| 746 | .moveset = &moveset_drud, | ||
| 747 | |||
| 748 | .pre_trans = uf, | ||
| 749 | |||
| 750 | .tables = {&pd_drudfin_noE_sym16_drud}, | ||
| 751 | .ntables = 1, | ||
| 752 | }; | ||
| 753 | |||
| 754 | Step | ||
| 755 | drrlfin_drrl = { | ||
| 756 | .shortname = "drrlfin", | ||
| 757 | .name = "DR finish on R/L without breaking DR", | ||
| 758 | |||
| 759 | .final = true, | ||
| 760 | .is_done = is_solved, | ||
| 761 | .estimate = estimate_drudfin_drud, | ||
| 762 | .ready = check_drud, | ||
| 763 | .ready_msg = check_dr_msg, | ||
| 764 | .is_valid = always_valid, | ||
| 765 | .moveset = &moveset_drud, | ||
| 766 | |||
| 767 | .pre_trans = rf, | ||
| 768 | |||
| 769 | .tables = {&pd_drudfin_noE_sym16_drud}, | ||
| 770 | .ntables = 1, | ||
| 771 | }; | ||
| 772 | |||
| 773 | Step | ||
| 774 | drfbfin_drfb = { | ||
| 775 | .shortname = "drfbfin", | ||
| 776 | .name = "DR finish on F/B without breaking DR", | ||
| 777 | |||
| 778 | .final = true, | ||
| 779 | .is_done = is_solved, | ||
| 780 | .estimate = estimate_drudfin_drud, | ||
| 781 | .ready = check_drud, | ||
| 782 | .ready_msg = check_dr_msg, | ||
| 783 | .is_valid = always_valid, | ||
| 784 | .moveset = &moveset_drud, | ||
| 785 | |||
| 786 | .pre_trans = fd, | ||
| 787 | |||
| 788 | .tables = {&pd_drudfin_noE_sym16_drud}, | ||
| 789 | .ntables = 1, | ||
| 790 | }; | ||
| 791 | |||
| 792 | /* HTR from DR */ | ||
| 793 | Step | ||
| 794 | htr_any = { | ||
| 795 | .shortname = "htr", | ||
| 796 | .name = "HTR from DR", | ||
| 797 | |||
| 798 | .final = false, | ||
| 799 | .is_done = check_htr, | ||
| 800 | .estimate = estimate_htr_drud, | ||
| 801 | .ready = check_drud, | ||
| 802 | .ready_msg = check_drany_msg, | ||
| 803 | .is_valid = validate_singlecw_ending, | ||
| 804 | .moveset = &moveset_drud, | ||
| 805 | |||
| 806 | .detect = detect_pretrans_drud, | ||
| 807 | |||
| 808 | .tables = {&pd_htr_drud}, | ||
| 809 | .ntables = 1, | ||
| 810 | }; | ||
| 811 | |||
| 812 | Step | ||
| 813 | htr_drud = { | ||
| 814 | .shortname = "htr-drud", | ||
| 815 | .name = "HTR from DR on U/D", | ||
| 816 | |||
| 817 | .final = false, | ||
| 818 | .is_done = check_htr, | ||
| 819 | .estimate = estimate_htr_drud, | ||
| 820 | .ready = check_drud, | ||
| 821 | .ready_msg = check_dr_msg, | ||
| 822 | .is_valid = validate_singlecw_ending, | ||
| 823 | .moveset = &moveset_drud, | ||
| 824 | |||
| 825 | .pre_trans = uf, | ||
| 826 | |||
| 827 | .tables = {&pd_htr_drud}, | ||
| 828 | .ntables = 1, | ||
| 829 | }; | ||
| 830 | |||
| 831 | Step | ||
| 832 | htr_drrl = { | ||
| 833 | .shortname = "htr-drrl", | ||
| 834 | .name = "HTR from DR on R/L", | ||
| 835 | |||
| 836 | .final = false, | ||
| 837 | .is_done = check_htr, | ||
| 838 | .estimate = estimate_htr_drud, | ||
| 839 | .ready = check_drud, | ||
| 840 | .ready_msg = check_dr_msg, | ||
| 841 | .is_valid = validate_singlecw_ending, | ||
| 842 | .moveset = &moveset_drud, | ||
| 843 | |||
| 844 | .pre_trans = rf, | ||
| 845 | |||
| 846 | .tables = {&pd_htr_drud}, | ||
| 847 | .ntables = 1, | ||
| 848 | }; | ||
| 849 | |||
| 850 | Step | ||
| 851 | htr_drfb = { | ||
| 852 | .shortname = "htr-drfb", | ||
| 853 | .name = "HTR from DR on F/B", | ||
| 854 | |||
| 855 | .final = false, | ||
| 856 | .is_done = check_htr, | ||
| 857 | .estimate = estimate_htr_drud, | ||
| 858 | .ready = check_drud, | ||
| 859 | .ready_msg = check_dr_msg, | ||
| 860 | .is_valid = validate_singlecw_ending, | ||
| 861 | .moveset = &moveset_drud, | ||
| 862 | |||
| 863 | .pre_trans = fd, | ||
| 864 | |||
| 865 | .tables = {&pd_htr_drud}, | ||
| 866 | .ntables = 1, | ||
| 867 | }; | ||
| 868 | |||
| 869 | /* HTR finish */ | ||
| 870 | Step | ||
| 871 | htrfin_htr = { | ||
| 872 | .shortname = "htrfin", | ||
| 873 | .name = "HTR finish without breaking HTR", | ||
| 874 | |||
| 875 | .final = true, | ||
| 876 | .is_done = is_solved, | ||
| 877 | .estimate = estimate_htrfin_htr, | ||
| 878 | .ready = check_htr, | ||
| 879 | .ready_msg = check_htr_msg, | ||
| 880 | .is_valid = always_valid, | ||
| 881 | .moveset = &moveset_htr, | ||
| 882 | |||
| 883 | .pre_trans = uf, | ||
| 884 | |||
| 885 | .tables = {&pd_htrfin_htr}, | ||
| 886 | .ntables = 1, | ||
| 887 | }; | ||
| 888 | |||
| 889 | Step *steps[] = { | ||
| 890 | &optimal_HTM, /* first is default */ | ||
| 891 | &optimal_light_HTM, | ||
| 892 | |||
| 893 | &eofin_eo, | ||
| 894 | &eofbfin_eofb, | ||
| 895 | &eorlfin_eorl, | ||
| 896 | &eoudfin_eoud, | ||
| 897 | |||
| 898 | &eoany_HTM, | ||
| 899 | &eofb_HTM, | ||
| 900 | &eorl_HTM, | ||
| 901 | &eoud_HTM, | ||
| 902 | |||
| 903 | &coany_HTM, | ||
| 904 | &coud_HTM, | ||
| 905 | &corl_HTM, | ||
| 906 | &cofb_HTM, | ||
| 907 | |||
| 908 | &coany_URF, | ||
| 909 | &coud_URF, | ||
| 910 | &corl_URF, | ||
| 911 | &cofb_URF, | ||
| 912 | |||
| 913 | &drany_HTM, | ||
| 914 | &drud_HTM, | ||
| 915 | &drrl_HTM, | ||
| 916 | &drfb_HTM, | ||
| 917 | |||
| 918 | &dr_eo, | ||
| 919 | &dr_eofb, | ||
| 920 | &dr_eorl, | ||
| 921 | &dr_eoud, | ||
| 922 | &drud_eofb, | ||
| 923 | &drrl_eofb, | ||
| 924 | &drud_eorl, | ||
| 925 | &drfb_eorl, | ||
| 926 | &drfb_eoud, | ||
| 927 | &drrl_eoud, | ||
| 928 | |||
| 929 | &dranyfin_DR, | ||
| 930 | &drudfin_drud, | ||
| 931 | &drrlfin_drrl, | ||
| 932 | &drfbfin_drfb, | ||
| 933 | |||
| 934 | &htr_any, | ||
| 935 | &htr_drud, | ||
| 936 | &htr_drrl, | ||
| 937 | &htr_drfb, | ||
| 938 | |||
| 939 | &htrfin_htr, | ||
| 940 | |||
| 941 | &cornershtr_HTM, | ||
| 942 | &cornershtr_URF, | ||
| 943 | &corners_HTM, | ||
| 944 | &corners_URF, | ||
| 945 | |||
| 946 | NULL | ||
| 947 | }; | ||
| 948 | |||
| 949 | /* Checkers and validators ***************************************************/ | ||
| 950 | |||
| 951 | static bool | ||
| 952 | check_centers(Cube cube) | ||
| 953 | { | ||
| 954 | return cube.cpos == 0; | ||
| 955 | } | ||
| 956 | |||
| 957 | static bool | ||
| 958 | check_coud_HTM(Cube cube) | ||
| 959 | { | ||
| 960 | return cube.coud == 0; | ||
| 961 | } | ||
| 962 | |||
| 963 | static bool | ||
| 964 | check_coud_URF(Cube cube) | ||
| 965 | { | ||
| 966 | Cube c2, c3; | ||
| 967 | |||
| 968 | c2 = apply_move(z, cube); | ||
| 969 | c3 = apply_move(x, cube); | ||
| 970 | |||
| 971 | return cube.coud == 0 || c2.coud == 0 || c3.coud == 0; | ||
| 972 | } | ||
| 973 | |||
| 974 | static bool | ||
| 975 | check_corners_URF(Cube cube) | ||
| 976 | { | ||
| 977 | Cube c; | ||
| 978 | Trans i; | ||
| 979 | |||
| 980 | for (i = 0; i < NROTATIONS; i++) { | ||
| 981 | c = apply_alg(rotation_alg(i), cube); | ||
| 982 | if (c.cp && c.coud) | ||
| 983 | return true; | ||
| 984 | } | ||
| 985 | |||
| 986 | return false; | ||
| 987 | } | ||
| 988 | |||
| 989 | static bool | ||
| 990 | check_corners_HTM(Cube cube) | ||
| 991 | { | ||
| 992 | return cube.cp == 0 && cube.coud == 0; | ||
| 993 | } | ||
| 994 | |||
| 995 | static bool | ||
| 996 | check_cornershtr(Cube cube) | ||
| 997 | { | ||
| 998 | return coord_cornershtr.index(cube) == 0; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | static bool | ||
| 1002 | check_eofb(Cube cube) | ||
| 1003 | { | ||
| 1004 | return cube.eofb == 0; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | static bool | ||
| 1008 | check_drud(Cube cube) | ||
| 1009 | { | ||
| 1010 | return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | static bool | ||
| 1014 | check_htr(Cube cube) | ||
| 1015 | { | ||
| 1016 | return check_drud(cube) && coord_htr_drud.index(cube) == 0; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | static bool | ||
| 1020 | always_valid(Alg *alg) | ||
| 1021 | { | ||
| 1022 | return true; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | static bool | ||
| 1026 | validate_singlecw_ending(Alg *alg) | ||
| 1027 | { | ||
| 1028 | int i; | ||
| 1029 | bool nor, inv; | ||
| 1030 | Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; | ||
| 1031 | |||
| 1032 | for (i = 0; i < alg->len; i++) { | ||
| 1033 | if (alg->inv[i]) { | ||
| 1034 | l2i = l1i; | ||
| 1035 | l1i = alg->move[i]; | ||
| 1036 | } else { | ||
| 1037 | l2 = l1; | ||
| 1038 | l1 = alg->move[i]; | ||
| 1039 | } | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2)); | ||
| 1043 | inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i)); | ||
| 1044 | |||
| 1045 | return nor && inv; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | /* Public functions **********************************************************/ | ||
| 1049 | |||
| 1050 | void | ||
| 1051 | compute_ind(StepAlt *a, Cube *cube, uint64_t *ind) | ||
| 1052 | { | ||
| 1053 | |||
| 1054 | } | ||
| 1055 | |||
| 1056 | int | ||
| 1057 | estimate_stepalt(StepAlt *a, uint64_t *ind) | ||
| 1058 | { | ||
| 1059 | int i, ret, est[a->n_coord]; | ||
| 1060 | |||
| 1061 | for (i = 0; i < a->n_coord; i++) { | ||
| 1062 | est[i] = ptableval(a->pd[i], ind[i]); | ||
| 1063 | if (est[i] == 0 && a->compact_pd[i]) | ||
| 1064 | est[i] = ptableval(a->fallback_pd, ind[i] / a->fbmod); | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | for (i = 0; i < a->n_dbtrick; i++) | ||
| 1068 | if (est[a->dbtrick[i][0]] == est[a->dbtrick[i][1]] && | ||
| 1069 | est[a->dbtrick[i][0]] == est[a->dbtrick[i][2]]) | ||
| 1070 | est[a->dbtrick[i][0]] += 1; | ||
| 1071 | |||
| 1072 | for (i = 0, ret = -1; i < a->n_coord; i++) | ||
| 1073 | ret = max(ret, est[i]); | ||
| 1074 | |||
| 1075 | return ret; | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | void | ||
| 1079 | prepare_step(Step *step, SolveOptions *opts) | ||
| 1080 | { | ||
| 1081 | int i, j; | ||
| 1082 | PDGenData pdg; | ||
| 1083 | StepAlt *a; | ||
| 1084 | |||
| 1085 | init_moveset(step->moveset); | ||
| 1086 | pdg.moveset = step->moveset; | ||
| 1087 | |||
| 1088 | for (i = 0; step->alt[i] != NULL; i++) { | ||
| 1089 | a = step->alt[i]; | ||
| 1090 | for (j = 0; j < a->n_coord; j++) { | ||
| 1091 | gen_coord(a->coord[j]); | ||
| 1092 | |||
| 1093 | pdg.coord = a->coord[j]; | ||
| 1094 | pdg.compact = a->compact[j]; | ||
| 1095 | pdg.pd = NULL; | ||
| 1096 | |||
| 1097 | a->pd[j] = genptable(&pdg, opts->nthreads); | ||
| 1098 | |||
| 1099 | if (a->compact_pd[j]) { | ||
| 1100 | gen_coord(a->fallback_coord[j]); | ||
| 1101 | |||
| 1102 | pdg.coord = a->fallback_coord[j]; | ||
| 1103 | pdg.compact = false; | ||
| 1104 | pdg.pd = NULL; | ||
| 1105 | |||
| 1106 | a->fallback_pd[j] = | ||
| 1107 | step->genptable(&pdg, opts->nthreads); | ||
| 1108 | } | ||
| 1109 | } | ||
| 1110 | } | ||
| 1111 | } | ||
diff --git a/old/solve_old.c b/old/solve_old.c deleted file mode 100644 index 8662c9e..0000000 --- a/old/solve_old.c +++ /dev/null | |||
| @@ -1,447 +0,0 @@ | |||
| 1 | #define SOLVE_C | ||
| 2 | |||
| 3 | #include "solve.h" | ||
| 4 | |||
| 5 | /* Local functions ***********************************************************/ | ||
| 6 | |||
| 7 | static void copy_dfsarg(DfsArg *src, DfsArg *dst); | ||
| 8 | static void dfs(DfsArg *arg); | ||
| 9 | static void dfs_add_sol(DfsArg *arg); | ||
| 10 | static void dfs_niss(DfsArg *arg); | ||
| 11 | static bool dfs_move_checkstop(DfsArg *arg); | ||
| 12 | static void * instance_thread(void *arg); | ||
| 13 | static void multidfs(DfsArg *arg); | ||
| 14 | static bool niss_makes_sense(DfsArg *arg); | ||
| 15 | static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols); | ||
| 16 | |||
| 17 | /* Local functions ***********************************************************/ | ||
| 18 | |||
| 19 | static void | ||
| 20 | copy_dfsarg(DfsArg *src, DfsArg *dst) | ||
| 21 | { | ||
| 22 | int i; | ||
| 23 | |||
| 24 | dst->cube = src->cube; | ||
| 25 | dst->t = src->t; | ||
| 26 | dst->s = src->s; | ||
| 27 | dst->opts = src->opts; | ||
| 28 | dst->d = src->d; | ||
| 29 | dst->bound = src->bound; /* In theory not needed */ | ||
| 30 | dst->niss = src->niss; | ||
| 31 | dst->sols = src->sols; | ||
| 32 | dst->sols_mutex = src->sols_mutex; | ||
| 33 | dst->current_alg = src->current_alg; | ||
| 34 | |||
| 35 | for (i = 0; i < src->s->n_coord; i++) { | ||
| 36 | dst->ind[i].val = src->ind[i].val; | ||
| 37 | dst->ind[i].t = src->ind[i].t; | ||
| 38 | } | ||
| 39 | |||
| 40 | src->s->copy_extra(src, dst); | ||
| 41 | } | ||
| 42 | |||
| 43 | static void | ||
| 44 | dfs(DfsArg *arg) | ||
| 45 | { | ||
| 46 | int i; | ||
| 47 | Move m, l0, l1; | ||
| 48 | DfsArg newarg; | ||
| 49 | |||
| 50 | if (dfs_move_checkstop(arg)) | ||
| 51 | return; | ||
| 52 | |||
| 53 | if (arg->bound == 0) { | ||
| 54 | if (arg->current_alg->len == arg->d) | ||
| 55 | dfs_add_sol(arg); | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | |||
| 59 | for (i = 0; arg->s->moveset->sorted_moves[i] != NULLMOVE; i++) { | ||
| 60 | m = arg->s->moveset->sorted_moves[i]; | ||
| 61 | if (arg->s->moveset->can_append(arg->current_alg, m, arg->niss) | ||
| 62 | && compare_last(arg->current_alg, m, arg->niss) >= 0) { | ||
| 63 | copy_dfsarg(arg, &newarg); | ||
| 64 | append_move(arg->current_alg, m, newarg.niss); | ||
| 65 | dfs(&newarg); | ||
| 66 | remove_last_move(arg->current_alg); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | if (niss_makes_sense(arg)) | ||
| 71 | dfs_niss(arg); | ||
| 72 | } | ||
| 73 | |||
| 74 | static void | ||
| 75 | dfs_add_sol(DfsArg *arg) | ||
| 76 | { | ||
| 77 | bool valid, accepted, nisscanc; | ||
| 78 | |||
| 79 | valid = arg->s->is_valid==NULL || arg->s->is_valid(arg->current_alg); | ||
| 80 | accepted = valid || arg->opts->all; | ||
| 81 | nisscanc = arg->s->final && | ||
| 82 | arg->s->moveset->cancel_niss(arg->current_alg); | ||
| 83 | |||
| 84 | if (accepted && !nisscanc) { | ||
| 85 | pthread_mutex_lock(arg->sols_mutex); | ||
| 86 | |||
| 87 | if (arg->sols->len < arg->opts->max_solutions) { | ||
| 88 | append_alg(arg->sols, arg->current_alg); | ||
| 89 | transform_alg( | ||
| 90 | inverse_trans(arg->t), arg->sols->last->alg); | ||
| 91 | if (arg->opts->verbose) | ||
| 92 | print_alg(arg->sols->last->alg, false); | ||
| 93 | } | ||
| 94 | |||
| 95 | pthread_mutex_unlock(arg->sols_mutex); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | static void | ||
| 100 | dfs_niss(DfsArg *arg) | ||
| 101 | { | ||
| 102 | DfsArg newarg; | ||
| 103 | Alg *inv; | ||
| 104 | Cube *c; | ||
| 105 | |||
| 106 | copy_dfsarg(arg, &newarg); | ||
| 107 | |||
| 108 | /* Invert current alg and scramble */ | ||
| 109 | newarg.cube = malloc(sizeof(Cube)); | ||
| 110 | inv = inverse_alg(arg->current_alg); | ||
| 111 | c = malloc(sizeof(Cube)); | ||
| 112 | make_solved(newarg.cube); | ||
| 113 | apply_alg(inv, newarg.cube); | ||
| 114 | copy_cube(arg->cube, c); | ||
| 115 | invert_cube(c); | ||
| 116 | compose(c, newarg.cube); | ||
| 117 | |||
| 118 | /* New indexes */ | ||
| 119 | compute_ind(newarg.s, newarg.cube, newarg.ind); | ||
| 120 | |||
| 121 | newarg.niss = !(arg->niss); | ||
| 122 | |||
| 123 | dfs(&newarg); | ||
| 124 | |||
| 125 | free_alg(inv); | ||
| 126 | free(c); | ||
| 127 | free(newarg.cube); | ||
| 128 | } | ||
| 129 | |||
| 130 | static bool | ||
| 131 | dfs_move_checkstop(DfsArg *arg) | ||
| 132 | { | ||
| 133 | int i, goal, nsols; | ||
| 134 | Move mm; | ||
| 135 | Trans tt = uf; /* Avoid uninitialized warning */ | ||
| 136 | |||
| 137 | /* Moving and computing bound */ | ||
| 138 | arg->bound = 0; | ||
| 139 | goal = arg->d - arg->current_alg->len; | ||
| 140 | for (i = 0; i < arg->s->n_coord; i++) { | ||
| 141 | if (arg->last[0] != NULLMOVE) { | ||
| 142 | mm = transform_move(arg->ind[i].t, arg->last[0]); | ||
| 143 | arg->ind[i].val = move_coord(arg->s->coord[i], | ||
| 144 | mm, arg->ind[i].val, &tt); | ||
| 145 | arg->ind[i].t = transform_trans(tt, arg->ind[i].t); | ||
| 146 | } | ||
| 147 | |||
| 148 | arg->bound = | ||
| 149 | MAX(arg->bound, ptableval(arg->s->pd[i], arg->ind[i].val)); | ||
| 150 | if (arg->opts->can_niss && !arg->niss) | ||
| 151 | arg->bound = MIN(1, arg->bound); | ||
| 152 | |||
| 153 | if (arg->bound > goal) | ||
| 154 | return true; | ||
| 155 | } | ||
| 156 | |||
| 157 | pthread_mutex_lock(arg->sols_mutex); | ||
| 158 | nsols = arg->sols->len; | ||
| 159 | pthread_mutex_unlock(arg->sols_mutex); | ||
| 160 | |||
| 161 | return nsols >= arg->opts->max_solutions; | ||
| 162 | } | ||
| 163 | |||
| 164 | static void * | ||
| 165 | instance_thread(void *arg) | ||
| 166 | { | ||
| 167 | bool b, inv; | ||
| 168 | Cube c; | ||
| 169 | Move m; | ||
| 170 | ThreadDataSolve *td; | ||
| 171 | AlgListNode *node; | ||
| 172 | DfsArg darg; | ||
| 173 | |||
| 174 | td = (ThreadDataSolve *)arg; | ||
| 175 | |||
| 176 | while (1) { | ||
| 177 | b = false; | ||
| 178 | |||
| 179 | pthread_mutex_lock(td->start_mutex); | ||
| 180 | if ((node = *(td->node)) == NULL) | ||
| 181 | b = true; | ||
| 182 | else | ||
| 183 | *(td->node) = (*(td->node))->next; | ||
| 184 | pthread_mutex_unlock(td->start_mutex); | ||
| 185 | |||
| 186 | if (b) | ||
| 187 | break; | ||
| 188 | |||
| 189 | inv = node->alg->inv[0]; | ||
| 190 | m = node->alg->move[0]; | ||
| 191 | |||
| 192 | copy_cube(td->arg.cube, &c); | ||
| 193 | if (inv) | ||
| 194 | invert_cube(&c); | ||
| 195 | |||
| 196 | copy_dfsarg(&td->arg, &darg); | ||
| 197 | compute_ind(td->arg.s, &c, darg.ind); | ||
| 198 | darg.cube = &c; | ||
| 199 | |||
| 200 | darg.niss = inv; | ||
| 201 | darg.current_alg = new_alg(""); | ||
| 202 | append_move(darg.current_alg, m, inv); | ||
| 203 | |||
| 204 | dfs(&darg); | ||
| 205 | |||
| 206 | free_alg(darg.current_alg); | ||
| 207 | } | ||
| 208 | |||
| 209 | return NULL; | ||
| 210 | } | ||
| 211 | |||
| 212 | static void | ||
| 213 | multidfs(DfsArg *arg) | ||
| 214 | { | ||
| 215 | int i; | ||
| 216 | Cube local_cube; | ||
| 217 | Alg *alg; | ||
| 218 | AlgList *start; | ||
| 219 | AlgListNode **node; | ||
| 220 | pthread_t t[arg->opts->nthreads]; | ||
| 221 | ThreadDataSolve td[arg->opts->nthreads]; | ||
| 222 | pthread_mutex_t *start_mutex, *sols_mutex; | ||
| 223 | |||
| 224 | node = malloc(sizeof(AlgListNode *)); | ||
| 225 | start_mutex = malloc(sizeof(pthread_mutex_t)); | ||
| 226 | sols_mutex = malloc(sizeof(pthread_mutex_t)); | ||
| 227 | |||
| 228 | start = new_alglist(); | ||
| 229 | pthread_mutex_init(start_mutex, NULL); | ||
| 230 | pthread_mutex_init(sols_mutex, NULL); | ||
| 231 | |||
| 232 | for (i = 0; arg->s->moveset->sorted_moves[i] != NULLMOVE; i++) { | ||
| 233 | alg = new_alg(""); | ||
| 234 | append_move(alg, arg->s->moveset->sorted_moves[i], false); | ||
| 235 | append_alg(start, alg); | ||
| 236 | if (arg->opts->can_niss && !arg->s->final) { | ||
| 237 | alg->inv[0] = true; | ||
| 238 | append_alg(start, alg); | ||
| 239 | } | ||
| 240 | free_alg(alg); | ||
| 241 | } | ||
| 242 | *node = start->first; | ||
| 243 | |||
| 244 | copy_cube(arg->cube, &local_cube); | ||
| 245 | |||
| 246 | for (i = 0; i < arg->opts->nthreads; i++) { | ||
| 247 | copy_dfsarg(arg, &(td[i].arg)); | ||
| 248 | td[i].arg.cube = &local_cube; | ||
| 249 | td[i].arg.sols_mutex = sols_mutex; | ||
| 250 | |||
| 251 | td[i].thid = i; | ||
| 252 | td[i].start = start; | ||
| 253 | td[i].node = node; | ||
| 254 | td[i].start_mutex = start_mutex; | ||
| 255 | |||
| 256 | pthread_create(&t[i], NULL, instance_thread, &td[i]); | ||
| 257 | } | ||
| 258 | |||
| 259 | for (i = 0; i < arg->opts->nthreads; i++) | ||
| 260 | pthread_join(t[i], NULL); | ||
| 261 | |||
| 262 | free_alglist(start); | ||
| 263 | free(node); | ||
| 264 | free(start_mutex); | ||
| 265 | free(sols_mutex); | ||
| 266 | } | ||
| 267 | |||
| 268 | static bool | ||
| 269 | niss_makes_sense(DfsArg *arg) | ||
| 270 | { | ||
| 271 | Move m, mm; | ||
| 272 | uint64_t u; | ||
| 273 | int i; | ||
| 274 | |||
| 275 | if (arg->s->final || arg->niss || !arg->opts->can_niss) | ||
| 276 | return false; | ||
| 277 | |||
| 278 | if (arg->current_alg->len_normal == 0) | ||
| 279 | return true; | ||
| 280 | |||
| 281 | m = inverse_move(arg->last[0]); | ||
| 282 | for (i = 0; i < arg->s->n_coord; i++) { | ||
| 283 | mm = transform_move(arg->ind[i].t, m); | ||
| 284 | u = move_coord(arg->s->coord[i], mm, 0, NULL); | ||
| 285 | if (ptableval(arg->s->pd[i], u) > 0) | ||
| 286 | return true; | ||
| 287 | } | ||
| 288 | |||
| 289 | return false; | ||
| 290 | } | ||
| 291 | |||
| 292 | static bool | ||
| 293 | solvestop(int d, int op, SolveOptions *opts, AlgList *sols) | ||
| 294 | { | ||
| 295 | bool opt_done, max_moves_exceeded, max_sols_exceeded; | ||
| 296 | |||
| 297 | opt_done = opts->optimal != -1 && op != -1 && d > opts->optimal + op; | ||
| 298 | max_moves_exceeded = d > opts->max_moves; | ||
| 299 | max_sols_exceeded = sols->len >= opts->max_solutions; | ||
| 300 | |||
| 301 | return opt_done || max_moves_exceeded || max_sols_exceeded; | ||
| 302 | } | ||
| 303 | |||
| 304 | /* Public functions **********************************************************/ | ||
| 305 | |||
| 306 | AlgList * | ||
| 307 | solve(Cube *cube, ChoiceStep *cs, SolveOptions *opts) | ||
| 308 | { | ||
| 309 | int i, j, d, op, est; | ||
| 310 | bool ready[99], one_ready, zerosol; | ||
| 311 | Movable ind[99][10]; | ||
| 312 | AlgList *s; | ||
| 313 | Cube *c[99]; | ||
| 314 | DfsArg arg[99]; | ||
| 315 | |||
| 316 | prepare_cs(cs, opts); | ||
| 317 | s = new_alglist(); | ||
| 318 | |||
| 319 | for (i = 0, one_ready = false; cs->step[i] != NULL; i++) { | ||
| 320 | c[i] = malloc(sizeof(Cube)); | ||
| 321 | copy_cube(cube, c[i]); | ||
| 322 | apply_trans(cs->t[i], c[i]); | ||
| 323 | |||
| 324 | arg[i].cube = c[i]; | ||
| 325 | arg[i].t = cs->t[i]; | ||
| 326 | arg[i].s = cs->step[i]; | ||
| 327 | arg[i].opts = opts; | ||
| 328 | arg[i].sols = s; | ||
| 329 | |||
| 330 | if ((ready[i] = cs->step[i]->ready(c[i]))) { | ||
| 331 | one_ready = true; | ||
| 332 | /* Only for local use for 0 moves solutions */ | ||
| 333 | compute_ind(cs->step[i], c[i], ind[i]); | ||
| 334 | } | ||
| 335 | } | ||
| 336 | if (!one_ready) { | ||
| 337 | fprintf(stderr, "Cube not ready for solving step: "); | ||
| 338 | fprintf(stderr, "%s\n", cs->ready_msg); | ||
| 339 | return s; | ||
| 340 | } | ||
| 341 | |||
| 342 | /* If the empty moves sequence is a solution for one of the | ||
| 343 | * alternatives, all longer solutions will be discarded, so we may | ||
| 344 | * just set its ready[] value to false. If the solution is accepted | ||
| 345 | * we append it and start searching from d = 1. */ | ||
| 346 | for (i = 0, zerosol = false; cs->step[i] != NULL; i++) { | ||
| 347 | if (ready[i]) { | ||
| 348 | est = 0; | ||
| 349 | for (j = 0; j < cs->step[i]->n_coord; j++) | ||
| 350 | est = MAX(est, ptableval(cs->step[i]->pd[j], | ||
| 351 | ind[i][j].val)); | ||
| 352 | if (est == 0) { | ||
| 353 | ready[i] = false; | ||
| 354 | zerosol = true; | ||
| 355 | } | ||
| 356 | } | ||
| 357 | } | ||
| 358 | if (zerosol && opts->min_moves == 0) { | ||
| 359 | append_alg(s, new_alg("")); | ||
| 360 | opts->min_moves = 1; | ||
| 361 | if (opts->verbose) | ||
| 362 | printf("Step is already solved" | ||
| 363 | "(empty alg is a solution)\n"); | ||
| 364 | } | ||
| 365 | |||
| 366 | for (d = opts->min_moves, op = -1; !solvestop(d, op, opts, s); d++) { | ||
| 367 | if (opts->verbose) | ||
| 368 | fprintf(stderr, "Searching depth %d\n", d); | ||
| 369 | |||
| 370 | for (i=0; cs->step[i]!=NULL && !solvestop(d,op,opts,s); i++) { | ||
| 371 | if (!ready[i]) | ||
| 372 | continue; | ||
| 373 | |||
| 374 | arg[i].d = d; | ||
| 375 | multidfs(&arg[i]); | ||
| 376 | |||
| 377 | if (s->len > 0 && op == -1) | ||
| 378 | op = d; | ||
| 379 | } | ||
| 380 | } | ||
| 381 | |||
| 382 | for (i = 0; cs->step[i] != NULL; i++) | ||
| 383 | free(c[i]); | ||
| 384 | |||
| 385 | return s; | ||
| 386 | } | ||
| 387 | |||
| 388 | /* TODO: make more general! */ | ||
| 389 | Alg * | ||
| 390 | solve_2phase(Cube *cube, int nthreads) | ||
| 391 | { | ||
| 392 | int bestlen, newb; | ||
| 393 | Alg *bestalg, *ret; | ||
| 394 | AlgList *sols1, *sols2; | ||
| 395 | AlgListNode *i; | ||
| 396 | Cube c; | ||
| 397 | SolveOptions opts1, opts2; | ||
| 398 | |||
| 399 | opts1.min_moves = 0; | ||
| 400 | opts1.max_moves = 13; | ||
| 401 | opts1.max_solutions = 20; | ||
| 402 | opts1.nthreads = nthreads; | ||
| 403 | opts1.optimal = 3; | ||
| 404 | opts1.can_niss = false; | ||
| 405 | opts1.verbose = false; | ||
| 406 | opts1.all = true; | ||
| 407 | |||
| 408 | opts2.min_moves = 0; | ||
| 409 | opts2.max_moves = 19; | ||
| 410 | opts2.max_solutions = 1; | ||
| 411 | opts2.nthreads = nthreads; | ||
| 412 | opts2.can_niss = false; | ||
| 413 | opts2.verbose = false; | ||
| 414 | |||
| 415 | /* We skip step1 if it is solved on U/D */ | ||
| 416 | if (check_drud(cube)) { | ||
| 417 | sols1 = new_alglist(); | ||
| 418 | append_alg(sols1, new_alg("")); | ||
| 419 | } else { | ||
| 420 | sols1 = solve(cube, &drud_HTM, &opts1); | ||
| 421 | } | ||
| 422 | bestalg = new_alg(""); | ||
| 423 | bestlen = 999; | ||
| 424 | for (i = sols1->first; i != NULL; i = i->next) { | ||
| 425 | copy_cube(cube, &c); | ||
| 426 | apply_alg(i->alg, &c); | ||
| 427 | sols2 = solve(&c, &dranyfin_DR, &opts2); | ||
| 428 | |||
| 429 | if (sols2->len > 0) { | ||
| 430 | newb = i->alg->len + sols2->first->alg->len; | ||
| 431 | if (newb < bestlen) { | ||
| 432 | bestlen = newb; | ||
| 433 | copy_alg(i->alg, bestalg); | ||
| 434 | compose_alg(bestalg, sols2->first->alg); | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | free_alglist(sols2); | ||
| 439 | } | ||
| 440 | |||
| 441 | free_alglist(sols1); | ||
| 442 | |||
| 443 | ret = cleanup(bestalg); | ||
| 444 | free_alg(bestalg); | ||
| 445 | |||
| 446 | return ret; | ||
| 447 | } | ||
diff --git a/old/solve_old.h b/old/solve_old.h deleted file mode 100644 index 010389e..0000000 --- a/old/solve_old.h +++ /dev/null | |||
| @@ -1,9 +0,0 @@ | |||
| 1 | #ifndef SOLVE_H | ||
| 2 | #define SOLVE_H | ||
| 3 | |||
| 4 | #include "movesets.h" | ||
| 5 | |||
| 6 | AlgList * solve(Cube *cube, ChoiceStep *cs, SolveOptions *opts); | ||
| 7 | Alg * solve_2phase(Cube *cube, int nthreads); | ||
| 8 | |||
| 9 | #endif | ||
| @@ -1,11 +1,112 @@ | |||
| 1 | #define ALG_C | ||
| 2 | |||
| 3 | #include "alg.h" | 1 | #include "alg.h" |
| 4 | 2 | ||
| 3 | /* Local functions ***********************************************************/ | ||
| 4 | |||
| 5 | static bool allowed_HTM(Move m); | ||
| 6 | static bool allowed_URF(Move m); | ||
| 7 | static bool allowed_eofb(Move m); | ||
| 8 | static bool allowed_drud(Move m); | ||
| 9 | static bool allowed_htr(Move m); | ||
| 10 | static bool allowed_next_HTM(Move l2, Move l1, Move m); | ||
| 5 | static int axis(Move m); | 11 | static int axis(Move m); |
| 12 | |||
| 6 | static void free_alglistnode(AlgListNode *aln); | 13 | static void free_alglistnode(AlgListNode *aln); |
| 7 | static void realloc_alg(Alg *alg, int n); | 14 | static void realloc_alg(Alg *alg, int n); |
| 8 | 15 | ||
| 16 | /* Movesets ******************************************************************/ | ||
| 17 | |||
| 18 | Moveset | ||
| 19 | moveset_HTM = { | ||
| 20 | .allowed = allowed_HTM, | ||
| 21 | .allowed_next = allowed_next_HTM, | ||
| 22 | }; | ||
| 23 | |||
| 24 | Moveset | ||
| 25 | moveset_URF = { | ||
| 26 | .allowed = allowed_URF, | ||
| 27 | .allowed_next = allowed_next_HTM, | ||
| 28 | }; | ||
| 29 | |||
| 30 | Moveset | ||
| 31 | moveset_eofb = { | ||
| 32 | .allowed = allowed_eofb, | ||
| 33 | .allowed_next = allowed_next_HTM, | ||
| 34 | }; | ||
| 35 | |||
| 36 | Moveset | ||
| 37 | moveset_drud = { | ||
| 38 | .allowed = allowed_drud, | ||
| 39 | .allowed_next = allowed_next_HTM, | ||
| 40 | }; | ||
| 41 | |||
| 42 | Moveset | ||
| 43 | moveset_htr = { | ||
| 44 | .allowed = allowed_htr, | ||
| 45 | .allowed_next = allowed_next_HTM, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static int nmoveset = 5; | ||
| 49 | static Moveset * all_ms[] = { | ||
| 50 | &moveset_HTM, | ||
| 51 | &moveset_URF, | ||
| 52 | &moveset_eofb, | ||
| 53 | &moveset_drud, | ||
| 54 | &moveset_htr, | ||
| 55 | }; | ||
| 56 | |||
| 57 | /* Functions *****************************************************************/ | ||
| 58 | |||
| 59 | static bool | ||
| 60 | allowed_HTM(Move m) | ||
| 61 | { | ||
| 62 | return m >= U && m <= B3; | ||
| 63 | } | ||
| 64 | |||
| 65 | static bool | ||
| 66 | allowed_URF(Move m) | ||
| 67 | { | ||
| 68 | Move b = base_move(m); | ||
| 69 | |||
| 70 | return b == U || b == R || b == F; | ||
| 71 | } | ||
| 72 | |||
| 73 | static bool | ||
| 74 | allowed_eofb(Move m) | ||
| 75 | { | ||
| 76 | Move b = base_move(m); | ||
| 77 | |||
| 78 | return b == U || b == D || b == R || b == L || | ||
| 79 | ((b == F || b == B) && m == b+1); | ||
| 80 | } | ||
| 81 | |||
| 82 | static bool | ||
| 83 | allowed_drud(Move m) | ||
| 84 | { | ||
| 85 | Move b = base_move(m); | ||
| 86 | |||
| 87 | return b == U || b == D || | ||
| 88 | ((b == R || b == L || b == F || b == B) && m == b + 1); | ||
| 89 | } | ||
| 90 | |||
| 91 | static bool | ||
| 92 | allowed_htr(Move m) | ||
| 93 | { | ||
| 94 | Move b = base_move(m); | ||
| 95 | |||
| 96 | return moveset_HTM.allowed(m) && m == b + 1; | ||
| 97 | } | ||
| 98 | |||
| 99 | static bool | ||
| 100 | allowed_next_HTM(Move l2, Move l1, Move m) | ||
| 101 | { | ||
| 102 | bool p, q; | ||
| 103 | |||
| 104 | p = l1 != NULLMOVE && base_move(l1) == base_move(m); | ||
| 105 | q = l2 != NULLMOVE && base_move(l2) == base_move(m); | ||
| 106 | |||
| 107 | return !(p || (commute(l1, l2) && q)); | ||
| 108 | } | ||
| 109 | |||
| 9 | void | 110 | void |
| 10 | append_alg(AlgList *l, Alg *alg) | 111 | append_alg(AlgList *l, Alg *alg) |
| 11 | { | 112 | { |
| @@ -33,42 +134,30 @@ append_move(Alg *alg, Move m, bool inverse) | |||
| 33 | alg->move[alg->len] = m; | 134 | alg->move[alg->len] = m; |
| 34 | alg->inv [alg->len] = inverse; | 135 | alg->inv [alg->len] = inverse; |
| 35 | alg->len++; | 136 | alg->len++; |
| 36 | |||
| 37 | if (inverse) | ||
| 38 | alg->move_inverse[alg->len_inverse++] = m; | ||
| 39 | else | ||
| 40 | alg->move_normal[alg->len_normal++] = m; | ||
| 41 | } | 137 | } |
| 42 | 138 | ||
| 43 | static int | 139 | static int |
| 44 | axis(Move m) | 140 | axis(Move m) |
| 45 | { | 141 | { |
| 46 | static int aux[] = { | 142 | if (m == NULLMOVE) |
| 47 | [NULLMOVE] = 0, | 143 | return 0; |
| 48 | 144 | ||
| 49 | [U] = 1, [U2] = 1, [U3] = 1, | 145 | if (m >= U && m <= B3) |
| 50 | [D] = 1, [D2] = 1, [D3] = 1, | 146 | return (m-1)/6 + 1; |
| 51 | [Uw] = 1, [Uw2] = 1, [Uw3] = 1, | 147 | |
| 52 | [Dw] = 1, [Dw2] = 1, [Dw3] = 1, | 148 | if (m >= Uw && m <= Bw3) |
| 53 | [E] = 1, [E2] = 1, [E3] = 1, | 149 | return (m-1)/6 - 2; |
| 54 | [y] = 1, [y2] = 1, [y3] = 1, | ||
| 55 | 150 | ||
| 56 | [R] = 2, [R2] = 2, [R3] = 2, | 151 | if (base_move(m) == E || base_move(m) == y) |
| 57 | [L] = 2, [L2] = 2, [L3] = 2, | 152 | return 1; |
| 58 | [Rw] = 2, [Rw2] = 2, [Rw3] = 2, | ||
| 59 | [Lw] = 2, [Lw2] = 2, [Lw3] = 2, | ||
| 60 | [M] = 2, [M2] = 2, [M3] = 2, | ||
| 61 | [x] = 2, [x2] = 2, [x3] = 2, | ||
| 62 | 153 | ||
| 63 | [F] = 3, [F2] = 3, [F3] = 3, | 154 | if (base_move(m) == M || base_move(m) == x) |
| 64 | [B] = 3, [B2] = 3, [B3] = 3, | 155 | return 2; |
| 65 | [Fw] = 3, [Fw2] = 3, [Fw3] = 3, | 156 | |
| 66 | [Bw] = 3, [Bw2] = 3, [Bw3] = 3, | 157 | if (base_move(m) == S || base_move(m) == z) |
| 67 | [S] = 3, [S2] = 3, [S3] = 3, | 158 | return 3; |
| 68 | [z] = 3, [z2] = 3, [z3] = 3, | ||
| 69 | }; | ||
| 70 | 159 | ||
| 71 | return aux[m]; | 160 | return -1; |
| 72 | } | 161 | } |
| 73 | 162 | ||
| 74 | Move | 163 | Move |
| @@ -86,32 +175,6 @@ commute(Move m1, Move m2) | |||
| 86 | return axis(m1) == axis(m2); | 175 | return axis(m1) == axis(m2); |
| 87 | } | 176 | } |
| 88 | 177 | ||
| 89 | int | ||
| 90 | compare(Move m1, Move m2) | ||
| 91 | { | ||
| 92 | if (!commute(m1, m2)) | ||
| 93 | return 0; | ||
| 94 | |||
| 95 | return m1 < m2 ? 1 : -1; | ||
| 96 | } | ||
| 97 | |||
| 98 | int | ||
| 99 | compare_last(Alg *alg, Move m, bool inverse) | ||
| 100 | { | ||
| 101 | Move last; | ||
| 102 | int n; | ||
| 103 | |||
| 104 | if (inverse) { | ||
| 105 | n = alg->len_inverse; | ||
| 106 | last = n > 0 ? alg->move_inverse[n-1] : NULLMOVE; | ||
| 107 | } else { | ||
| 108 | n = alg->len_normal; | ||
| 109 | last = n > 0 ? alg->move_normal[n-1] : NULLMOVE; | ||
| 110 | } | ||
| 111 | |||
| 112 | return compare(last, m); | ||
| 113 | } | ||
| 114 | |||
| 115 | void | 178 | void |
| 116 | compose_alg(Alg *alg1, Alg *alg2) | 179 | compose_alg(Alg *alg1, Alg *alg2) |
| 117 | { | 180 | { |
| @@ -124,7 +187,7 @@ compose_alg(Alg *alg1, Alg *alg2) | |||
| 124 | void | 187 | void |
| 125 | copy_alg(Alg *src, Alg *dst) | 188 | copy_alg(Alg *src, Alg *dst) |
| 126 | { | 189 | { |
| 127 | dst->len = dst->len_normal = dst->len_inverse = 0; | 190 | dst->len = 0; /* Overwrites */ |
| 128 | compose_alg(dst, src); | 191 | compose_alg(dst, src); |
| 129 | } | 192 | } |
| 130 | 193 | ||
| @@ -156,6 +219,16 @@ free_alglistnode(AlgListNode *aln) | |||
| 156 | free(aln); | 219 | free(aln); |
| 157 | } | 220 | } |
| 158 | 221 | ||
| 222 | void | ||
| 223 | inplace(Alg * (*f)(Alg *), Alg *alg) | ||
| 224 | { | ||
| 225 | Alg *aux; | ||
| 226 | |||
| 227 | aux = f(alg); | ||
| 228 | copy_alg(aux, alg); | ||
| 229 | free(aux); | ||
| 230 | } | ||
| 231 | |||
| 159 | Alg * | 232 | Alg * |
| 160 | inverse_alg(Alg *alg) | 233 | inverse_alg(Alg *alg) |
| 161 | { | 234 | { |
| @@ -211,14 +284,10 @@ new_alg(char *str) | |||
| 211 | Move j, m; | 284 | Move j, m; |
| 212 | 285 | ||
| 213 | alg = malloc(sizeof(Alg)); | 286 | alg = malloc(sizeof(Alg)); |
| 214 | alg->allocated = 30; | 287 | alg->move = malloc(30 * sizeof(Move)); |
| 215 | alg->move = malloc(alg->allocated * sizeof(Move)); | 288 | alg->inv = malloc(30 * sizeof(bool)); |
| 216 | alg->inv = malloc(alg->allocated * sizeof(bool)); | 289 | alg->allocated = 30; |
| 217 | alg->move_normal = malloc(alg->allocated * sizeof(Move)); | 290 | alg->len = 0; |
| 218 | alg->move_inverse = malloc(alg->allocated * sizeof(Move)); | ||
| 219 | alg->len = 0; | ||
| 220 | alg->len_normal = 0; | ||
| 221 | alg->len_inverse = 0; | ||
| 222 | 291 | ||
| 223 | niss = false; | 292 | niss = false; |
| 224 | for (i = 0; str[i]; i++) { | 293 | for (i = 0; str[i]; i++) { |
| @@ -227,13 +296,13 @@ new_alg(char *str) | |||
| 227 | 296 | ||
| 228 | if (str[i] == '(' && niss) { | 297 | if (str[i] == '(' && niss) { |
| 229 | fprintf(stderr, "Error reading moves: nested ( )\n"); | 298 | fprintf(stderr, "Error reading moves: nested ( )\n"); |
| 230 | alg->len = alg->len_normal = alg->len_inverse = 0; | 299 | alg->len = 0; |
| 231 | return alg; | 300 | return alg; |
| 232 | } | 301 | } |
| 233 | 302 | ||
| 234 | if (str[i] == ')' && !niss) { | 303 | if (str[i] == ')' && !niss) { |
| 235 | fprintf(stderr, "Error reading moves: unmatched )\n"); | 304 | fprintf(stderr, "Error reading moves: unmatched )\n"); |
| 236 | alg->len = alg->len_normal = alg->len_inverse = 0; | 305 | alg->len = 0; |
| 237 | return alg; | 306 | return alg; |
| 238 | } | 307 | } |
| 239 | 308 | ||
| @@ -300,7 +369,7 @@ new_alg(char *str) | |||
| 300 | 369 | ||
| 301 | if (niss) { | 370 | if (niss) { |
| 302 | fprintf(stderr, "Error reading moves: unmatched (\n"); | 371 | fprintf(stderr, "Error reading moves: unmatched (\n"); |
| 303 | alg->len = alg->len_normal = alg->len_inverse = 0; | 372 | alg->len = 0; |
| 304 | } | 373 | } |
| 305 | 374 | ||
| 306 | return alg; | 375 | return alg; |
| @@ -385,25 +454,12 @@ realloc_alg(Alg *alg, int n) | |||
| 385 | fprintf(stderr, "something might go wrong.\n"); | 454 | fprintf(stderr, "something might go wrong.\n"); |
| 386 | } | 455 | } |
| 387 | 456 | ||
| 388 | alg->move = realloc(alg->move, n * sizeof(int)); | 457 | alg->move = realloc(alg->move, n * sizeof(int)); |
| 389 | alg->inv = realloc(alg->inv, n * sizeof(int)); | 458 | alg->inv = realloc(alg->inv, n * sizeof(int)); |
| 390 | alg->move_normal = realloc(alg->move_normal, n * sizeof(int)); | ||
| 391 | alg->move_inverse = realloc(alg->move_inverse, n * sizeof(int)); | ||
| 392 | alg->allocated = n; | 459 | alg->allocated = n; |
| 393 | } | 460 | } |
| 394 | 461 | ||
| 395 | void | 462 | void |
| 396 | remove_last_move(Alg *a) | ||
| 397 | { | ||
| 398 | a->len--; | ||
| 399 | |||
| 400 | if (a->inv[a->len]) | ||
| 401 | a->len_inverse--; | ||
| 402 | else | ||
| 403 | a->len_normal--; | ||
| 404 | } | ||
| 405 | |||
| 406 | void | ||
| 407 | swapmove(Move *m1, Move *m2) | 463 | swapmove(Move *m1, Move *m2) |
| 408 | { | 464 | { |
| 409 | Move aux; | 465 | Move aux; |
| @@ -413,34 +469,6 @@ swapmove(Move *m1, Move *m2) | |||
| 413 | *m2 = aux; | 469 | *m2 = aux; |
| 414 | } | 470 | } |
| 415 | 471 | ||
| 416 | char * | ||
| 417 | trans_string(Trans t) | ||
| 418 | { | ||
| 419 | static char trans_string_aux[NTRANS][20] = { | ||
| 420 | [uf] = "uf", [ur] = "ur", [ub] = "ub", [ul] = "ul", | ||
| 421 | [df] = "df", [dr] = "dr", [db] = "db", [dl] = "dl", | ||
| 422 | [rf] = "rf", [rd] = "rd", [rb] = "rb", [ru] = "ru", | ||
| 423 | [lf] = "lf", [ld] = "ld", [lb] = "lb", [lu] = "lu", | ||
| 424 | [fu] = "fu", [fr] = "fr", [fd] = "fd", [fl] = "fl", | ||
| 425 | [bu] = "bu", [br] = "br", [bd] = "bd", [bl] = "bl", | ||
| 426 | |||
| 427 | [uf_mirror] = "uf*", [ur_mirror] = "ur*", | ||
| 428 | [ub_mirror] = "ub*", [ul_mirror] = "ul*", | ||
| 429 | [df_mirror] = "df*", [dr_mirror] = "dr*", | ||
| 430 | [db_mirror] = "db*", [dl_mirror] = "dl*", | ||
| 431 | [rf_mirror] = "rf*", [rd_mirror] = "rd*", | ||
| 432 | [rb_mirror] = "rb*", [ru_mirror] = "ru*", | ||
| 433 | [lf_mirror] = "lf*", [ld_mirror] = "ld*", | ||
| 434 | [lb_mirror] = "lb*", [lu_mirror] = "lu*", | ||
| 435 | [fu_mirror] = "fu*", [fr_mirror] = "fr*", | ||
| 436 | [fd_mirror] = "fd*", [fl_mirror] = "fl*", | ||
| 437 | [bu_mirror] = "bu*", [br_mirror] = "br*", | ||
| 438 | [bd_mirror] = "bd*", [bl_mirror] = "bl*", | ||
| 439 | }; | ||
| 440 | |||
| 441 | return trans_string_aux[t]; | ||
| 442 | } | ||
| 443 | |||
| 444 | Alg * | 472 | Alg * |
| 445 | unniss(Alg *alg) | 473 | unniss(Alg *alg) |
| 446 | { | 474 | { |
| @@ -449,11 +477,48 @@ unniss(Alg *alg) | |||
| 449 | 477 | ||
| 450 | ret = new_alg(""); | 478 | ret = new_alg(""); |
| 451 | 479 | ||
| 452 | for (i = 0; i < alg->len_normal; i++) | 480 | for (i = 0; i < alg->len; i++) |
| 453 | append_move(ret, alg->move_normal[i], false); | 481 | if (!alg->inv[i]) |
| 482 | append_move(ret, alg->move[i], false); | ||
| 483 | |||
| 484 | for (i = alg->len-1; i >= 0; i--) | ||
| 485 | if (alg->inv[i]) | ||
| 486 | append_move(ret, inverse_move(alg->move[i]), false); | ||
| 487 | |||
| 488 | return ret; | ||
| 489 | } | ||
| 454 | 490 | ||
| 455 | for (i = 0; i < alg->len_inverse; i++) | 491 | void |
| 456 | append_move(ret, inverse_move(alg->move_inverse[i]), false); | 492 | init_moveset(Moveset *ms) |
| 493 | { | ||
| 494 | int j; | ||
| 495 | uint64_t l, one; | ||
| 496 | Move m, l2, l1; | ||
| 457 | 497 | ||
| 458 | return ret; | 498 | one = 1; |
| 499 | |||
| 500 | for (j = 0, m = U; m < NMOVES; m++) | ||
| 501 | if (ms->allowed(m)) | ||
| 502 | ms->sorted_moves[j++] = m; | ||
| 503 | ms->sorted_moves[j] = NULLMOVE; | ||
| 504 | |||
| 505 | for (l1 = 0; l1 < NMOVES; l1++) { | ||
| 506 | for (l2 = 0; l2 < NMOVES; l2++) { | ||
| 507 | ms->mask[l2][l1] = 0; | ||
| 508 | for (l=0; ms->sorted_moves[l]!=NULLMOVE; l++) { | ||
| 509 | m = ms->sorted_moves[l]; | ||
| 510 | if (ms->allowed_next(l2, l1, m)) | ||
| 511 | ms->mask[l2][l1] |= (one<<m); | ||
| 512 | } | ||
| 513 | } | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | void | ||
| 518 | init_all_movesets() | ||
| 519 | { | ||
| 520 | int i; | ||
| 521 | |||
| 522 | for (i = 0; i < nmoveset; i++) | ||
| 523 | init_moveset(all_ms[i]); | ||
| 459 | } | 524 | } |
| @@ -8,28 +8,36 @@ | |||
| 8 | #include "cubetypes.h" | 8 | #include "cubetypes.h" |
| 9 | #include "utils.h" | 9 | #include "utils.h" |
| 10 | 10 | ||
| 11 | extern Moveset moveset_HTM; | ||
| 12 | extern Moveset moveset_URF; | ||
| 13 | extern Moveset moveset_eofb; | ||
| 14 | extern Moveset moveset_drud; | ||
| 15 | extern Moveset moveset_htr; | ||
| 16 | |||
| 11 | void append_alg(AlgList *l, Alg *alg); | 17 | void append_alg(AlgList *l, Alg *alg); |
| 12 | void append_move(Alg *alg, Move m, bool inverse); | 18 | void append_move(Alg *alg, Move m, bool inverse); |
| 13 | Move base_move(Move m); | 19 | Move base_move(Move m); |
| 14 | int compare(Move m1, Move m2); /* Return 1 (m1<m2), 0 or -1 (m1>m2) */ | ||
| 15 | int compare_last(Alg *alg, Move m, bool inverse); | ||
| 16 | void compose_alg(Alg *alg1, Alg *alg2); | 20 | void compose_alg(Alg *alg1, Alg *alg2); |
| 17 | bool commute(Move m1, Move m2); | 21 | bool commute(Move m1, Move m2); |
| 18 | void copy_alg(Alg *src, Alg *dst); | 22 | void copy_alg(Alg *src, Alg *dst); |
| 19 | void free_alg(Alg *alg); | 23 | void free_alg(Alg *alg); |
| 20 | void free_alglist(AlgList *l); | 24 | void free_alglist(AlgList *l); |
| 25 | void inplace(Alg * (*f)(Alg *), Alg *alg); | ||
| 21 | Alg * inverse_alg(Alg *alg); | 26 | Alg * inverse_alg(Alg *alg); |
| 22 | Move inverse_move(Move m); | 27 | Move inverse_move(Move m); |
| 23 | char * move_string(Move m); | 28 | char * move_string(Move m); |
| 29 | void movelist_to_position(Move *ml, int *pos); | ||
| 30 | void moveset_to_list(Moveset ms, Move *lst); | ||
| 24 | Alg * new_alg(char *str); | 31 | Alg * new_alg(char *str); |
| 25 | AlgList * new_alglist(); | 32 | AlgList * new_alglist(); |
| 26 | Alg * on_inverse(Alg *alg); | 33 | Alg * on_inverse(Alg *alg); |
| 27 | void print_alg(Alg *alg, bool l); | 34 | void print_alg(Alg *alg, bool l); |
| 28 | void print_alglist(AlgList *al, bool l); | 35 | void print_alglist(AlgList *al, bool l); |
| 29 | void remove_last_move(Alg *alg); | ||
| 30 | void swapmove(Move *m1, Move *m2); | 36 | void swapmove(Move *m1, Move *m2); |
| 31 | char * trans_string(Trans t); /* Here because similar to move_string, move? */ | ||
| 32 | Alg * unniss(Alg *alg); | 37 | Alg * unniss(Alg *alg); |
| 33 | 38 | ||
| 39 | void init_moveset(Moveset *ms); | ||
| 40 | void init_all_movesets(); | ||
| 41 | |||
| 34 | #endif | 42 | #endif |
| 35 | 43 | ||
diff --git a/src/commands.c b/src/commands.c index a9e8fc9..4d3ad50 100644 --- a/src/commands.c +++ b/src/commands.c | |||
| @@ -1,11 +1,187 @@ | |||
| 1 | #define COMMANDS_C | ||
| 2 | |||
| 3 | #include "commands.h" | 1 | #include "commands.h" |
| 4 | 2 | ||
| 5 | static bool read_cs(CommandArgs *args, char *str); | 3 | /* Arg parsing functions *****************************************************/ |
| 4 | |||
| 5 | CommandArgs * gen_parse_args(int c, char **v); | ||
| 6 | CommandArgs * help_parse_args(int c, char **v); | ||
| 7 | CommandArgs * parse_only_scramble(int c, char **v); | ||
| 8 | CommandArgs * parse_no_arg(int c, char **v); | ||
| 9 | CommandArgs * solve_parse_args(int c, char **v); | ||
| 10 | CommandArgs * scramble_parse_args(int c, char **v); | ||
| 11 | |||
| 12 | /* Exec functions ************************************************************/ | ||
| 13 | |||
| 14 | static void gen_exec(CommandArgs *args); | ||
| 15 | static void cleanup_exec(CommandArgs *args); | ||
| 16 | static void invert_exec(CommandArgs *args); | ||
| 17 | static void solve_exec(CommandArgs *args); | ||
| 18 | static void scramble_exec(CommandArgs *args); | ||
| 19 | static void steps_exec(CommandArgs *args); | ||
| 20 | static void commands_exec(CommandArgs *args); | ||
| 21 | static void freemem_exec(CommandArgs *args); | ||
| 22 | static void print_exec(CommandArgs *args); | ||
| 23 | static void twophase_exec(CommandArgs *args); | ||
| 24 | static void help_exec(CommandArgs *args); | ||
| 25 | static void quit_exec(CommandArgs *args); | ||
| 26 | static void unniss_exec(CommandArgs *args); | ||
| 27 | static void version_exec(CommandArgs *args); | ||
| 28 | |||
| 29 | /* Local functions ***********************************************************/ | ||
| 30 | |||
| 31 | static bool read_step(CommandArgs *args, char *str); | ||
| 6 | static bool read_scrtype(CommandArgs *args, char *str); | 32 | static bool read_scrtype(CommandArgs *args, char *str); |
| 7 | static bool read_scramble(int c, char **v, CommandArgs *args); | 33 | static bool read_scramble(int c, char **v, CommandArgs *args); |
| 8 | 34 | ||
| 35 | /* Commands ******************************************************************/ | ||
| 36 | |||
| 37 | Command | ||
| 38 | solve_cmd = { | ||
| 39 | .name = "solve", | ||
| 40 | .usage = "solve STEP [OPTIONS] SCRAMBLE", | ||
| 41 | .description = "Solve a step; see command steps for a list of steps", | ||
| 42 | .parse_args = solve_parse_args, | ||
| 43 | .exec = solve_exec | ||
| 44 | }; | ||
| 45 | |||
| 46 | Command | ||
| 47 | scramble_cmd = { | ||
| 48 | .name = "scramble", | ||
| 49 | .usage = "scramble [TYPE] [-n N]", | ||
| 50 | .description = "Get a random-position scramble", | ||
| 51 | .parse_args = scramble_parse_args, | ||
| 52 | .exec = scramble_exec, | ||
| 53 | }; | ||
| 54 | |||
| 55 | Command | ||
| 56 | gen_cmd = { | ||
| 57 | .name = "gen", | ||
| 58 | .usage = "gen [-t N]", | ||
| 59 | .description = "Generate all tables [using N threads]", | ||
| 60 | .parse_args = gen_parse_args, | ||
| 61 | .exec = gen_exec | ||
| 62 | }; | ||
| 63 | |||
| 64 | Command | ||
| 65 | invert_cmd = { | ||
| 66 | .name = "invert", | ||
| 67 | .usage = "invert SCRAMBLE]", | ||
| 68 | .description = "Invert a scramble", | ||
| 69 | .parse_args = parse_only_scramble, | ||
| 70 | .exec = invert_exec, | ||
| 71 | }; | ||
| 72 | |||
| 73 | Command | ||
| 74 | steps_cmd = { | ||
| 75 | .name = "steps", | ||
| 76 | .usage = "steps", | ||
| 77 | .description = "List available steps", | ||
| 78 | .parse_args = parse_no_arg, | ||
| 79 | .exec = steps_exec | ||
| 80 | }; | ||
| 81 | |||
| 82 | Command | ||
| 83 | commands_cmd = { | ||
| 84 | .name = "commands", | ||
| 85 | .usage = "commands", | ||
| 86 | .description = "List available commands", | ||
| 87 | .parse_args = parse_no_arg, | ||
| 88 | .exec = commands_exec | ||
| 89 | }; | ||
| 90 | |||
| 91 | Command | ||
| 92 | freemem_cmd = { | ||
| 93 | .name = "freemem", | ||
| 94 | .usage = "freemem", | ||
| 95 | .description = "free large tables from RAM", | ||
| 96 | .parse_args = parse_no_arg, | ||
| 97 | .exec = freemem_exec, | ||
| 98 | }; | ||
| 99 | |||
| 100 | Command | ||
| 101 | print_cmd = { | ||
| 102 | .name = "print", | ||
| 103 | .usage = "print SCRAMBLE", | ||
| 104 | .description = "Print written description of the cube", | ||
| 105 | .parse_args = parse_only_scramble, | ||
| 106 | .exec = print_exec, | ||
| 107 | }; | ||
| 108 | |||
| 109 | Command | ||
| 110 | help_cmd = { | ||
| 111 | .name = "help", | ||
| 112 | .usage = "help [COMMAND]", | ||
| 113 | .description = "Display nissy manual page or help on specific command", | ||
| 114 | .parse_args = help_parse_args, | ||
| 115 | .exec = help_exec, | ||
| 116 | }; | ||
| 117 | |||
| 118 | Command | ||
| 119 | twophase_cmd = { | ||
| 120 | .name = "twophase", | ||
| 121 | .usage = "twophase", | ||
| 122 | .description = "Find a solution quickly using a 2-phase method", | ||
| 123 | .parse_args = parse_only_scramble, | ||
| 124 | .exec = twophase_exec, | ||
| 125 | }; | ||
| 126 | |||
| 127 | Command | ||
| 128 | quit_cmd = { | ||
| 129 | .name = "quit", | ||
| 130 | .usage = "quit", | ||
| 131 | .description = "Quit nissy", | ||
| 132 | .parse_args = parse_no_arg, | ||
| 133 | .exec = quit_exec, | ||
| 134 | }; | ||
| 135 | |||
| 136 | Command | ||
| 137 | cleanup_cmd = { | ||
| 138 | .name = "cleanup", | ||
| 139 | .usage = "cleanup SCRAMBLE", | ||
| 140 | .description = "Rewrite a scramble using only standard moves (HTM)", | ||
| 141 | .parse_args = parse_only_scramble, | ||
| 142 | .exec = cleanup_exec, | ||
| 143 | }; | ||
| 144 | |||
| 145 | Command | ||
| 146 | unniss_cmd = { | ||
| 147 | .name = "unniss", | ||
| 148 | .usage = "unniss SCRAMBLE", | ||
| 149 | .description = "Rewrite a scramble without NISS", | ||
| 150 | .parse_args = parse_only_scramble, | ||
| 151 | .exec = unniss_exec, | ||
| 152 | }; | ||
| 153 | |||
| 154 | Command | ||
| 155 | version_cmd = { | ||
| 156 | .name = "version", | ||
| 157 | .usage = "version", | ||
| 158 | .description = "print nissy version", | ||
| 159 | .parse_args = parse_no_arg, | ||
| 160 | .exec = version_exec, | ||
| 161 | }; | ||
| 162 | |||
| 163 | Command *commands[] = { | ||
| 164 | &commands_cmd, | ||
| 165 | &freemem_cmd, | ||
| 166 | &gen_cmd, | ||
| 167 | &help_cmd, | ||
| 168 | &invert_cmd, | ||
| 169 | &print_cmd, | ||
| 170 | &quit_cmd, | ||
| 171 | &solve_cmd, | ||
| 172 | &scramble_cmd, | ||
| 173 | &steps_cmd, | ||
| 174 | &twophase_cmd, | ||
| 175 | &cleanup_cmd, | ||
| 176 | &unniss_cmd, | ||
| 177 | &version_cmd, | ||
| 178 | NULL | ||
| 179 | }; | ||
| 180 | |||
| 181 | /* Other constants ***********************************************************/ | ||
| 182 | |||
| 183 | char *scrtypes[20] = { "eo", "corners", "edges", "fmc", "dr", "htr", NULL }; | ||
| 184 | |||
| 9 | /* Arg parsing functions implementation **************************************/ | 185 | /* Arg parsing functions implementation **************************************/ |
| 10 | 186 | ||
| 11 | CommandArgs * | 187 | CommandArgs * |
| @@ -95,7 +271,7 @@ solve_parse_args(int c, char **v) | |||
| 95 | a->opts->print_number = false; | 271 | a->opts->print_number = false; |
| 96 | } else if (!strcmp(v[i], "-c")) { | 272 | } else if (!strcmp(v[i], "-c")) { |
| 97 | a->opts->count_only = true; | 273 | a->opts->count_only = true; |
| 98 | } else if (!read_cs(a, v[i])) { | 274 | } else if (!read_step(a, v[i])) { |
| 99 | break; | 275 | break; |
| 100 | } | 276 | } |
| 101 | } | 277 | } |
| @@ -210,26 +386,17 @@ parse_no_arg(int c, char **v) | |||
| 210 | 386 | ||
| 211 | /* Exec functions implementation *********************************************/ | 387 | /* Exec functions implementation *********************************************/ |
| 212 | 388 | ||
| 213 | void | 389 | static void |
| 214 | solve_exec(CommandArgs *args) | 390 | solve_exec(CommandArgs *args) |
| 215 | { | 391 | { |
| 216 | Cube c; | 392 | Cube c; |
| 217 | AlgList *sols; | 393 | AlgList *sols; |
| 218 | Solver *solver[99]; | ||
| 219 | Threader *threader; | ||
| 220 | 394 | ||
| 221 | make_solved(&c); | 395 | init_all_movesets(); |
| 222 | apply_alg(args->scramble, &c); | 396 | init_symcoord(); |
| 223 | /* TODO: adjust */ | ||
| 224 | /* threader = &threader_single;*/ | ||
| 225 | threader = &threader_eager; | ||
| 226 | 397 | ||
| 227 | /* TODO: adjust */ | 398 | c = apply_alg(args->scramble, (Cube){0}); |
| 228 | int i; | 399 | sols = solve(c, args->step, args->opts); |
| 229 | for (i = 0; args->cs->step[i] != NULL; i++) | ||
| 230 | solver[i] = new_stepsolver_lazy(args->cs->step[i]); | ||
| 231 | solver[i] = NULL; | ||
| 232 | sols = solve(&c, args->opts, solver, threader); | ||
| 233 | 400 | ||
| 234 | if (args->opts->count_only) | 401 | if (args->opts->count_only) |
| 235 | printf("%d\n", sols->len); | 402 | printf("%d\n", sols->len); |
| @@ -239,67 +406,85 @@ solve_exec(CommandArgs *args) | |||
| 239 | free_alglist(sols); | 406 | free_alglist(sols); |
| 240 | } | 407 | } |
| 241 | 408 | ||
| 242 | void | 409 | static void |
| 243 | scramble_exec(CommandArgs *args) | 410 | scramble_exec(CommandArgs *args) |
| 244 | { | 411 | { |
| 245 | Cube cube; | 412 | Cube cube; |
| 413 | CubeArray *arr; | ||
| 246 | Alg *scr, *ruf, *aux; | 414 | Alg *scr, *ruf, *aux; |
| 247 | int i, j, eo, ep, co, cp; | 415 | int i, j, eo, ep, co, cp, a[12]; |
| 416 | int eparr[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 }; | ||
| 248 | uint64_t ui, uj, uk; | 417 | uint64_t ui, uj, uk; |
| 249 | 418 | ||
| 419 | init_all_movesets(); | ||
| 420 | init_symcoord(); | ||
| 421 | |||
| 250 | srand(time(NULL)); | 422 | srand(time(NULL)); |
| 251 | 423 | ||
| 252 | for (i = 0; i < args->n; i++) { | 424 | for (i = 0; i < args->n; i++) { |
| 253 | 425 | ||
| 254 | if (!strcmp(args->scrtype, "dr")) { | 426 | if (!strcmp(args->scrtype, "dr")) { |
| 255 | ui = rand() % FACTORIAL8; | 427 | /* Warning: cube is inconsistent because of side CO * |
| 256 | uj = rand() % FACTORIAL8; | 428 | * and EO on U/D. But solve_2phase only solves drfin * |
| 257 | uk = rand() % FACTORIAL4; | 429 | * in this case, so it should be ok. * |
| 430 | * TODO: check this properly * | ||
| 431 | * Moreover we again need to fix parity after * | ||
| 432 | * generating epose manually */ | ||
| 433 | do { | ||
| 434 | ui = rand() % FACTORIAL8; | ||
| 435 | uj = rand() % FACTORIAL8; | ||
| 436 | uk = rand() % FACTORIAL4; | ||
| 437 | |||
| 438 | index_to_perm(ui, 8, eparr); | ||
| 439 | arr = malloc(sizeof(CubeArray)); | ||
| 440 | arr->ep = eparr; | ||
| 441 | cube = arrays_to_cube(arr, pf_ep); | ||
| 442 | free(arr); | ||
| 258 | 443 | ||
| 259 | make_solved(&cube); | 444 | cube.cp = uj; |
| 260 | index_to_perm(ui, 8, cube.cp); | 445 | cube.epose = uk; |
| 261 | index_to_perm(uj, 8, cube.ep); | 446 | } while (!is_admissible(cube)); |
| 262 | index_to_perm(uk, 4, cube.ep + 8); | ||
| 263 | for (j = 8; j < 12; j++) | ||
| 264 | cube.ep[j] += 8; | ||
| 265 | } else if (!strcmp(args->scrtype, "htr")) { | 447 | } else if (!strcmp(args->scrtype, "htr")) { |
| 266 | make_solved(&cube); | 448 | /* antindex_htrfin() returns a consistent * |
| 267 | /* TODO */ | 449 | * cube, except possibly for parity */ |
| 450 | do { | ||
| 451 | ui = rand() % (24*24/6); | ||
| 452 | cube = (Cube){0}; | ||
| 453 | cube.cp = cornershtrfin_ant[ui]; | ||
| 454 | cube.epose = rand() % 24; | ||
| 455 | cube.eposs = rand() % 24; | ||
| 456 | cube.eposm = rand() % 24; | ||
| 457 | } while (!is_admissible(cube)); | ||
| 268 | } else { | 458 | } else { |
| 269 | ep = rand() % FACTORIAL12; | ||
| 270 | cp = rand() % FACTORIAL8; | ||
| 271 | eo = rand() % POW2TO11; | 459 | eo = rand() % POW2TO11; |
| 460 | ep = rand() % FACTORIAL12; | ||
| 272 | co = rand() % POW3TO7; | 461 | co = rand() % POW3TO7; |
| 462 | cp = rand() % FACTORIAL8; | ||
| 273 | 463 | ||
| 274 | if (!strcmp(args->scrtype, "eo")) { | 464 | if (!strcmp(args->scrtype, "eo")) { |
| 275 | eo = 0; | 465 | eo = 0; |
| 276 | } else if (!strcmp(args->scrtype, "corners")) { | 466 | } else if (!strcmp(args->scrtype, "corners")) { |
| 277 | eo = 0; | 467 | eo = 0; |
| 278 | ep = 0; | 468 | ep = 0; |
| 469 | index_to_perm(cp, 8, a); | ||
| 470 | if (perm_sign(a, 8) == 1) { | ||
| 471 | swap(&a[0], &a[1]); | ||
| 472 | cp = perm_to_index(a, 8); | ||
| 473 | } | ||
| 279 | } else if (!strcmp(args->scrtype, "edges")) { | 474 | } else if (!strcmp(args->scrtype, "edges")) { |
| 280 | co = 0; | 475 | co = 0; |
| 281 | cp = 0; | 476 | cp = 0; |
| 477 | index_to_perm(ep, 12, a); | ||
| 478 | if (perm_sign(a, 12) == 1) { | ||
| 479 | swap(&a[0], &a[1]); | ||
| 480 | ep = perm_to_index(a, 12); | ||
| 481 | } | ||
| 282 | } | 482 | } |
| 283 | 483 | cube = fourval_to_cube(eo, ep, co, cp); | |
| 284 | make_solved(&cube); | ||
| 285 | index_to_perm(ep, 12, cube.ep); | ||
| 286 | index_to_perm(cp, 8, cube.cp); | ||
| 287 | int_to_sum_zero_array(eo, 2, 12, cube.eo); | ||
| 288 | int_to_sum_zero_array(co, 3, 8, cube.co); | ||
| 289 | } | ||
| 290 | |||
| 291 | if (!is_admissible(&cube)) { | ||
| 292 | if (!strcmp(args->scrtype, "corners")) | ||
| 293 | swap(&cube.cp[UFR], &cube.cp[UFL]); | ||
| 294 | else | ||
| 295 | swap(&cube.ep[UF], &cube.ep[UB]); | ||
| 296 | } | 484 | } |
| 297 | 485 | ||
| 298 | /* TODO: can be optimized for htr and dr using htrfin, drfin */ | 486 | /* TODO: can be optimized for htr and dr using htrfin, drfin */ |
| 299 | /* | 487 | scr = solve_2phase(cube, 1); |
| 300 | TODO: solve_2phase was removed | ||
| 301 | scr = solve_2phase(&cube, 1); | ||
| 302 | */ | ||
| 303 | 488 | ||
| 304 | if (!strcmp(args->scrtype, "fmc")) { | 489 | if (!strcmp(args->scrtype, "fmc")) { |
| 305 | aux = new_alg(""); | 490 | aux = new_alg(""); |
| @@ -328,22 +513,23 @@ scramble_exec(CommandArgs *args) | |||
| 328 | } | 513 | } |
| 329 | } | 514 | } |
| 330 | 515 | ||
| 331 | void | 516 | static void |
| 332 | gen_exec(CommandArgs *args) | 517 | gen_exec(CommandArgs *args) |
| 333 | { | 518 | { |
| 334 | /* TODO: | ||
| 335 | int i; | 519 | int i; |
| 336 | 520 | ||
| 337 | fprintf(stderr, "Generating coordinates...\n"); | 521 | fprintf(stderr, "Generating coordinates...\n"); |
| 522 | init_all_movesets(); | ||
| 523 | init_symcoord(); | ||
| 524 | |||
| 338 | fprintf(stderr, "Generating pruning tables...\n"); | 525 | fprintf(stderr, "Generating pruning tables...\n"); |
| 339 | for (i = 0; all_pd[i] != NULL; i++) | 526 | for (i = 0; all_pd[i] != NULL; i++) |
| 340 | genptable(all_pd[i], args->opts->nthreads); | 527 | genptable(all_pd[i], args->opts->nthreads); |
| 341 | */ | ||
| 342 | 528 | ||
| 343 | fprintf(stderr, "Done!\n"); | 529 | fprintf(stderr, "Done!\n"); |
| 344 | } | 530 | } |
| 345 | 531 | ||
| 346 | void | 532 | static void |
| 347 | invert_exec(CommandArgs *args) | 533 | invert_exec(CommandArgs *args) |
| 348 | { | 534 | { |
| 349 | Alg *inv; | 535 | Alg *inv; |
| @@ -354,16 +540,16 @@ invert_exec(CommandArgs *args) | |||
| 354 | free_alg(inv); | 540 | free_alg(inv); |
| 355 | } | 541 | } |
| 356 | 542 | ||
| 357 | void | 543 | static void |
| 358 | steps_exec(CommandArgs *args) | 544 | steps_exec(CommandArgs *args) |
| 359 | { | 545 | { |
| 360 | int i; | 546 | int i; |
| 361 | 547 | ||
| 362 | for (i = 0; csteps[i] != NULL; i++) | 548 | for (i = 0; steps[i] != NULL; i++) |
| 363 | printf("%-15s %s\n", csteps[i]->shortname, csteps[i]->name); | 549 | printf("%-15s %s\n", steps[i]->shortname, steps[i]->name); |
| 364 | } | 550 | } |
| 365 | 551 | ||
| 366 | void | 552 | static void |
| 367 | commands_exec(CommandArgs *args) | 553 | commands_exec(CommandArgs *args) |
| 368 | { | 554 | { |
| 369 | int i; | 555 | int i; |
| @@ -373,10 +559,9 @@ commands_exec(CommandArgs *args) | |||
| 373 | 559 | ||
| 374 | } | 560 | } |
| 375 | 561 | ||
| 376 | void | 562 | static void |
| 377 | freemem_exec(CommandArgs *args) | 563 | freemem_exec(CommandArgs *args) |
| 378 | { | 564 | { |
| 379 | /* TODO: | ||
| 380 | int i; | 565 | int i; |
| 381 | 566 | ||
| 382 | for (i = 0; all_pd[i] != NULL; i++) | 567 | for (i = 0; all_pd[i] != NULL; i++) |
| @@ -384,36 +569,35 @@ freemem_exec(CommandArgs *args) | |||
| 384 | 569 | ||
| 385 | for (i = 0; all_sd[i] != NULL; i++) | 570 | for (i = 0; all_sd[i] != NULL; i++) |
| 386 | free_sd(all_sd[i]); | 571 | free_sd(all_sd[i]); |
| 387 | */ | 572 | |
| 573 | /* TODO: invtables are also large, but for now they are * | ||
| 574 | * statically allocated. Consider releasing those too. */ | ||
| 388 | } | 575 | } |
| 389 | 576 | ||
| 390 | void | 577 | static void |
| 391 | print_exec(CommandArgs *args) | 578 | print_exec(CommandArgs *args) |
| 392 | { | 579 | { |
| 393 | Cube c; | 580 | init_moves(); |
| 394 | 581 | print_cube(apply_alg(args->scramble, (Cube){0})); | |
| 395 | make_solved(&c); | ||
| 396 | apply_alg(args->scramble, &c); | ||
| 397 | print_cube(&c); | ||
| 398 | } | 582 | } |
| 399 | 583 | ||
| 400 | /* | 584 | static void |
| 401 | void | ||
| 402 | twophase_exec(CommandArgs *args) | 585 | twophase_exec(CommandArgs *args) |
| 403 | { | 586 | { |
| 404 | Cube c; | 587 | Cube c; |
| 405 | Alg *sol; | 588 | Alg *sol; |
| 406 | 589 | ||
| 407 | make_solved(&c); | 590 | init_all_movesets(); |
| 408 | apply_alg(args->scramble, &c); | 591 | init_symcoord(); |
| 409 | sol = solve_2phase(&c, 1); | 592 | |
| 593 | c = apply_alg(args->scramble, (Cube){0}); | ||
| 594 | sol = solve_2phase(c, 1); | ||
| 410 | 595 | ||
| 411 | print_alg(sol, false); | 596 | print_alg(sol, false); |
| 412 | free_alg(sol); | 597 | free_alg(sol); |
| 413 | } | 598 | } |
| 414 | */ | ||
| 415 | 599 | ||
| 416 | void | 600 | static void |
| 417 | help_exec(CommandArgs *args) | 601 | help_exec(CommandArgs *args) |
| 418 | { | 602 | { |
| 419 | if (args->command == NULL) { | 603 | if (args->command == NULL) { |
| @@ -427,7 +611,7 @@ help_exec(CommandArgs *args) | |||
| 427 | " system (such as Linux or MacOS) or in pdf and html" | 611 | " system (such as Linux or MacOS) or in pdf and html" |
| 428 | " format in the docs folder.\n" | 612 | " format in the docs folder.\n" |
| 429 | "Nissy is available for free at " | 613 | "Nissy is available for free at " |
| 430 | "https://nissy.tronto.net\n" | 614 | "https://github.com/sebastianotronto/nissy\n" |
| 431 | ); | 615 | ); |
| 432 | } else { | 616 | } else { |
| 433 | printf("Command %s: %s\nusage: %s\n", args->command->name, | 617 | printf("Command %s: %s\nusage: %s\n", args->command->name, |
| @@ -435,24 +619,26 @@ help_exec(CommandArgs *args) | |||
| 435 | } | 619 | } |
| 436 | } | 620 | } |
| 437 | 621 | ||
| 438 | void | 622 | static void |
| 439 | quit_exec(CommandArgs *args) | 623 | quit_exec(CommandArgs *args) |
| 440 | { | 624 | { |
| 441 | exit(0); | 625 | exit(0); |
| 442 | } | 626 | } |
| 443 | 627 | ||
| 444 | void | 628 | static void |
| 445 | cleanup_exec(CommandArgs *args) | 629 | cleanup_exec(CommandArgs *args) |
| 446 | { | 630 | { |
| 447 | Alg *alg; | 631 | Alg *alg; |
| 448 | 632 | ||
| 633 | init_moves(); | ||
| 634 | |||
| 449 | alg = cleanup(args->scramble); | 635 | alg = cleanup(args->scramble); |
| 450 | print_alg(alg, false); | 636 | print_alg(alg, false); |
| 451 | 637 | ||
| 452 | free_alg(alg); | 638 | free_alg(alg); |
| 453 | } | 639 | } |
| 454 | 640 | ||
| 455 | void | 641 | static void |
| 456 | unniss_exec(CommandArgs *args) | 642 | unniss_exec(CommandArgs *args) |
| 457 | { | 643 | { |
| 458 | Alg *aux; | 644 | Alg *aux; |
| @@ -462,7 +648,7 @@ unniss_exec(CommandArgs *args) | |||
| 462 | free(aux); | 648 | free(aux); |
| 463 | } | 649 | } |
| 464 | 650 | ||
| 465 | void | 651 | static void |
| 466 | version_exec(CommandArgs *args) | 652 | version_exec(CommandArgs *args) |
| 467 | { | 653 | { |
| 468 | printf(VERSION"\n"); | 654 | printf(VERSION"\n"); |
| @@ -505,8 +691,6 @@ static bool | |||
| 505 | read_scrtype(CommandArgs *args, char *str) | 691 | read_scrtype(CommandArgs *args, char *str) |
| 506 | { | 692 | { |
| 507 | int i; | 693 | int i; |
| 508 | static char *scrtypes[20] = | ||
| 509 | { "eo", "corners", "edges", "fmc", "dr", "htr", NULL }; | ||
| 510 | 694 | ||
| 511 | for (i = 0; scrtypes[i] != NULL; i++) { | 695 | for (i = 0; scrtypes[i] != NULL; i++) { |
| 512 | if (!strcmp(scrtypes[i], str)) { | 696 | if (!strcmp(scrtypes[i], str)) { |
| @@ -519,13 +703,13 @@ read_scrtype(CommandArgs *args, char *str) | |||
| 519 | } | 703 | } |
| 520 | 704 | ||
| 521 | static bool | 705 | static bool |
| 522 | read_cs(CommandArgs *args, char *str) | 706 | read_step(CommandArgs *args, char *str) |
| 523 | { | 707 | { |
| 524 | int i; | 708 | int i; |
| 525 | 709 | ||
| 526 | for (i = 0; csteps[i] != NULL; i++) { | 710 | for (i = 0; steps[i] != NULL; i++) { |
| 527 | if (!strcmp(csteps[i]->shortname, str)) { | 711 | if (!strcmp(steps[i]->shortname, str)) { |
| 528 | args->cs = csteps[i]; | 712 | args->step = steps[i]; |
| 529 | return true; | 713 | return true; |
| 530 | } | 714 | } |
| 531 | } | 715 | } |
| @@ -562,7 +746,7 @@ new_args() | |||
| 562 | args->opts = malloc(sizeof(SolveOptions)); | 746 | args->opts = malloc(sizeof(SolveOptions)); |
| 563 | 747 | ||
| 564 | /* step and command are static */ | 748 | /* step and command are static */ |
| 565 | args->cs = csteps[0]; /* default: first step in list */ | 749 | args->step = steps[0]; /* default: first step in list */ |
| 566 | args->command = NULL; | 750 | args->command = NULL; |
| 567 | 751 | ||
| 568 | return args; | 752 | return args; |
diff --git a/src/commands.h b/src/commands.h index 65708e0..b7a4c36 100644 --- a/src/commands.h +++ b/src/commands.h | |||
| @@ -5,207 +5,10 @@ | |||
| 5 | 5 | ||
| 6 | #include "solve.h" | 6 | #include "solve.h" |
| 7 | #include "steps.h" | 7 | #include "steps.h" |
| 8 | #include "solver_step.h" | ||
| 9 | #include "threader_single.h" | ||
| 10 | #include "threader_eager.h" | ||
| 11 | 8 | ||
| 12 | void free_args(CommandArgs *args); | 9 | void free_args(CommandArgs *args); |
| 13 | CommandArgs * new_args(); | 10 | CommandArgs * new_args(); |
| 14 | 11 | ||
| 15 | /* Arg parsing functions *****************************************************/ | 12 | extern Command * commands[]; |
| 16 | |||
| 17 | CommandArgs * gen_parse_args(int c, char **v); | ||
| 18 | CommandArgs * help_parse_args(int c, char **v); | ||
| 19 | CommandArgs * parse_only_scramble(int c, char **v); | ||
| 20 | CommandArgs * parse_no_arg(int c, char **v); | ||
| 21 | CommandArgs * solve_parse_args(int c, char **v); | ||
| 22 | CommandArgs * scramble_parse_args(int c, char **v); | ||
| 23 | |||
| 24 | /* Exec functions ************************************************************/ | ||
| 25 | |||
| 26 | void gen_exec(CommandArgs *args); | ||
| 27 | void cleanup_exec(CommandArgs *args); | ||
| 28 | void invert_exec(CommandArgs *args); | ||
| 29 | void solve_exec(CommandArgs *args); | ||
| 30 | void scramble_exec(CommandArgs *args); | ||
| 31 | void steps_exec(CommandArgs *args); | ||
| 32 | void commands_exec(CommandArgs *args); | ||
| 33 | void freemem_exec(CommandArgs *args); | ||
| 34 | void print_exec(CommandArgs *args); | ||
| 35 | /*void twophase_exec(CommandArgs *args);*/ | ||
| 36 | void help_exec(CommandArgs *args); | ||
| 37 | void quit_exec(CommandArgs *args); | ||
| 38 | void unniss_exec(CommandArgs *args); | ||
| 39 | void version_exec(CommandArgs *args); | ||
| 40 | |||
| 41 | /* Commands ******************************************************************/ | ||
| 42 | |||
| 43 | #ifndef COMMANDS_C | ||
| 44 | |||
| 45 | extern Command cleanup_cmd; | ||
| 46 | extern Command commands_cmd; | ||
| 47 | extern Command freemem_cmd; | ||
| 48 | extern Command gen_cmd; | ||
| 49 | extern Command help_cmd; | ||
| 50 | extern Command invert_cmd; | ||
| 51 | extern Command print_cmd; | ||
| 52 | extern Command quit_cmd; | ||
| 53 | extern Command scramble_cmd; | ||
| 54 | extern Command solve_cmd; | ||
| 55 | extern Command steps_cmd; | ||
| 56 | extern Command unniss_cmd; | ||
| 57 | extern Command version_cmd; | ||
| 58 | |||
| 59 | extern Command *commands[]; | ||
| 60 | |||
| 61 | #else | ||
| 62 | |||
| 63 | Command | ||
| 64 | solve_cmd = { | ||
| 65 | .name = "solve", | ||
| 66 | .usage = "solve STEP [OPTIONS] SCRAMBLE", | ||
| 67 | .description = "Solve a step; see command steps for a list of steps", | ||
| 68 | .parse_args = solve_parse_args, | ||
| 69 | .exec = solve_exec | ||
| 70 | }; | ||
| 71 | |||
| 72 | Command | ||
| 73 | scramble_cmd = { | ||
| 74 | .name = "scramble", | ||
| 75 | .usage = "scramble [TYPE] [-n N]", | ||
| 76 | .description = "Get a random-position scramble", | ||
| 77 | .parse_args = scramble_parse_args, | ||
| 78 | .exec = scramble_exec, | ||
| 79 | }; | ||
| 80 | |||
| 81 | Command | ||
| 82 | gen_cmd = { | ||
| 83 | .name = "gen", | ||
| 84 | .usage = "gen [-t N]", | ||
| 85 | .description = "Generate all tables [using N threads]", | ||
| 86 | .parse_args = gen_parse_args, | ||
| 87 | .exec = gen_exec | ||
| 88 | }; | ||
| 89 | |||
| 90 | Command | ||
| 91 | invert_cmd = { | ||
| 92 | .name = "invert", | ||
| 93 | .usage = "invert SCRAMBLE]", | ||
| 94 | .description = "Invert a scramble", | ||
| 95 | .parse_args = parse_only_scramble, | ||
| 96 | .exec = invert_exec, | ||
| 97 | }; | ||
| 98 | |||
| 99 | Command | ||
| 100 | steps_cmd = { | ||
| 101 | .name = "steps", | ||
| 102 | .usage = "steps", | ||
| 103 | .description = "List available steps", | ||
| 104 | .parse_args = parse_no_arg, | ||
| 105 | .exec = steps_exec | ||
| 106 | }; | ||
| 107 | |||
| 108 | Command | ||
| 109 | commands_cmd = { | ||
| 110 | .name = "commands", | ||
| 111 | .usage = "commands", | ||
| 112 | .description = "List available commands", | ||
| 113 | .parse_args = parse_no_arg, | ||
| 114 | .exec = commands_exec | ||
| 115 | }; | ||
| 116 | |||
| 117 | Command | ||
| 118 | freemem_cmd = { | ||
| 119 | .name = "freemem", | ||
| 120 | .usage = "freemem", | ||
| 121 | .description = "free large tables from RAM", | ||
| 122 | .parse_args = parse_no_arg, | ||
| 123 | .exec = freemem_exec, | ||
| 124 | }; | ||
| 125 | |||
| 126 | Command | ||
| 127 | print_cmd = { | ||
| 128 | .name = "print", | ||
| 129 | .usage = "print SCRAMBLE", | ||
| 130 | .description = "Print written description of the cube", | ||
| 131 | .parse_args = parse_only_scramble, | ||
| 132 | .exec = print_exec, | ||
| 133 | }; | ||
| 134 | |||
| 135 | Command | ||
| 136 | help_cmd = { | ||
| 137 | .name = "help", | ||
| 138 | .usage = "help [COMMAND]", | ||
| 139 | .description = "Display nissy manual page or help on specific command", | ||
| 140 | .parse_args = help_parse_args, | ||
| 141 | .exec = help_exec, | ||
| 142 | }; | ||
| 143 | |||
| 144 | /* | ||
| 145 | Command | ||
| 146 | twophase_cmd = { | ||
| 147 | .name = "twophase", | ||
| 148 | .usage = "twophase", | ||
| 149 | .description = "Find a solution quickly using a 2-phase method", | ||
| 150 | .parse_args = parse_only_scramble, | ||
| 151 | .exec = twophase_exec, | ||
| 152 | }; | ||
| 153 | */ | ||
| 154 | |||
| 155 | Command | ||
| 156 | quit_cmd = { | ||
| 157 | .name = "quit", | ||
| 158 | .usage = "quit", | ||
| 159 | .description = "Quit nissy", | ||
| 160 | .parse_args = parse_no_arg, | ||
| 161 | .exec = quit_exec, | ||
| 162 | }; | ||
| 163 | |||
| 164 | Command | ||
| 165 | cleanup_cmd = { | ||
| 166 | .name = "cleanup", | ||
| 167 | .usage = "cleanup SCRAMBLE", | ||
| 168 | .description = "Rewrite a scramble using only standard moves (HTM)", | ||
| 169 | .parse_args = parse_only_scramble, | ||
| 170 | .exec = cleanup_exec, | ||
| 171 | }; | ||
| 172 | |||
| 173 | Command | ||
| 174 | unniss_cmd = { | ||
| 175 | .name = "unniss", | ||
| 176 | .usage = "unniss SCRAMBLE", | ||
| 177 | .description = "Rewrite a scramble without NISS", | ||
| 178 | .parse_args = parse_only_scramble, | ||
| 179 | .exec = unniss_exec, | ||
| 180 | }; | ||
| 181 | |||
| 182 | Command | ||
| 183 | version_cmd = { | ||
| 184 | .name = "version", | ||
| 185 | .usage = "version", | ||
| 186 | .description = "print nissy version", | ||
| 187 | .parse_args = parse_no_arg, | ||
| 188 | .exec = version_exec, | ||
| 189 | }; | ||
| 190 | |||
| 191 | Command *commands[] = { | ||
| 192 | &commands_cmd, | ||
| 193 | &freemem_cmd, | ||
| 194 | &gen_cmd, | ||
| 195 | &help_cmd, | ||
| 196 | &invert_cmd, | ||
| 197 | &print_cmd, | ||
| 198 | &quit_cmd, | ||
| 199 | &solve_cmd, | ||
| 200 | &scramble_cmd, | ||
| 201 | &steps_cmd, | ||
| 202 | /* &twophase_cmd,*/ | ||
| 203 | &cleanup_cmd, | ||
| 204 | &unniss_cmd, | ||
| 205 | &version_cmd, | ||
| 206 | NULL | ||
| 207 | }; | ||
| 208 | |||
| 209 | #endif | ||
| 210 | 13 | ||
| 211 | #endif | 14 | #endif |
diff --git a/src/coord.c b/src/coord.c index 673434f..a9df9fd 100644 --- a/src/coord.c +++ b/src/coord.c | |||
| @@ -1,654 +1,611 @@ | |||
| 1 | #define COORD_C | ||
| 2 | |||
| 3 | #include "coord.h" | 1 | #include "coord.h" |
| 4 | 2 | ||
| 5 | static void gen_coord_comp(Coordinate *coord); | 3 | static uint64_t index_eofb(Cube cube); |
| 6 | static void gen_coord_sym(Coordinate *coord); | 4 | static uint64_t index_eofbepos(Cube cube); |
| 7 | static bool read_coord_mtable(Coordinate *coord); | 5 | static uint64_t index_epud(Cube cube); |
| 8 | static bool read_coord_sd(Coordinate *coord); | 6 | static uint64_t index_coud(Cube cube); |
| 9 | static bool read_coord_ttable(Coordinate *coord); | 7 | static uint64_t index_corners(Cube cube); |
| 10 | static bool write_coord_mtable(Coordinate *coord); | 8 | static uint64_t index_cp(Cube cube); |
| 11 | static bool write_coord_sd(Coordinate *coord); | 9 | static uint64_t index_cphtr(Cube cube); |
| 12 | static bool write_coord_ttable(Coordinate *coord); | 10 | static uint64_t index_cornershtr(Cube cube); |
| 11 | static uint64_t index_cornershtrfin(Cube cube); | ||
| 12 | static uint64_t index_drud(Cube cube); | ||
| 13 | static uint64_t index_drud_eofb(Cube cube); | ||
| 14 | static uint64_t index_htr_drud(Cube cube); | ||
| 15 | static uint64_t index_htrfin(Cube cube); | ||
| 16 | static uint64_t index_cpud_separate(Cube cube); | ||
| 13 | 17 | ||
| 14 | /* Indexers ******************************************************************/ | 18 | static uint64_t move_eofb(Move m, uint64_t ind); |
| 19 | static uint64_t move_eofbepos(Move m, uint64_t ind); | ||
| 20 | static uint64_t move_epud(Move m, uint64_t ind); | ||
| 21 | static uint64_t move_coud(Move m, uint64_t ind); | ||
| 22 | static uint64_t move_corners(Move m, uint64_t ind); | ||
| 23 | static uint64_t move_cp(Move m, uint64_t ind); | ||
| 24 | static uint64_t move_cphtr(Move m, uint64_t ind); | ||
| 25 | static uint64_t move_cornershtr(Move m, uint64_t ind); | ||
| 26 | static uint64_t move_cornershtrfin(Move m, uint64_t ind); | ||
| 27 | static uint64_t move_drud(Move m, uint64_t ind); | ||
| 28 | static uint64_t move_drud_eofb(Move m, uint64_t ind); | ||
| 29 | static uint64_t move_htr_drud(Move m, uint64_t ind); | ||
| 30 | static uint64_t move_htrfin(Move m, uint64_t ind); | ||
| 31 | static uint64_t move_cpud_separate(Move m, uint64_t ind); | ||
| 15 | 32 | ||
| 16 | uint64_t | 33 | static void init_cphtr_cosets(); |
| 17 | index_eofb(Cube *cube) | 34 | static void init_cphtr_left_cosets_bfs(int i, int c); |
| 18 | { | 35 | static void init_cphtr_right_cosets_color(int i, int c); |
| 19 | return (uint64_t)digit_array_to_int(cube->eo, 11, 2); | 36 | static void init_cpud_separate(); |
| 20 | } | 37 | static void init_cornershtrfin(); |
| 38 | static void init_htr_eposs(); | ||
| 21 | 39 | ||
| 22 | uint64_t | ||
| 23 | index_coud(Cube *cube) | ||
| 24 | { | ||
| 25 | return (uint64_t)digit_array_to_int(cube->co, 7, 3); | ||
| 26 | } | ||
| 27 | 40 | ||
| 28 | uint64_t | 41 | /* All sorts of useful costants and tables **********************************/ |
| 29 | index_cp(Cube *cube) | ||
| 30 | { | ||
| 31 | return (uint64_t)perm_to_index(cube->cp, 8); | ||
| 32 | } | ||
| 33 | 42 | ||
| 34 | uint64_t | 43 | static int cphtr_left_cosets[FACTORIAL8]; |
| 35 | index_cpudsep(Cube *cube) | 44 | static int cphtr_right_cosets[FACTORIAL8]; |
| 36 | { | 45 | static int cphtr_right_rep[BINOM8ON4*6]; |
| 37 | int i, c[8]; | 46 | int cpud_separate_ind[FACTORIAL8]; |
| 47 | int cpud_separate_ant[BINOM8ON4]; | ||
| 48 | static int cornershtrfin_ind[FACTORIAL8]; | ||
| 49 | int cornershtrfin_ant[24*24/6]; | ||
| 50 | static int htr_eposs_ind[BINOM12ON4]; | ||
| 51 | static int htr_eposs_ant[BINOM8ON4]; | ||
| 38 | 52 | ||
| 39 | for (i = 0; i < 8; i++) | 53 | /* Coordinates and their implementation **************************************/ |
| 40 | c[i] = cube->cp[i] < 4 ? 0 : 1; | ||
| 41 | 54 | ||
| 42 | return (uint64_t)subset_to_index(c, 8, 4); | 55 | Coordinate |
| 43 | } | 56 | coord_eofb = { |
| 57 | .index = index_eofb, | ||
| 58 | .max = POW2TO11, | ||
| 59 | .move = move_eofb, | ||
| 60 | }; | ||
| 44 | 61 | ||
| 45 | uint64_t | 62 | Coordinate |
| 46 | index_epe(Cube *cube) | 63 | coord_eofbepos = { |
| 47 | { | 64 | .index = index_eofbepos, |
| 48 | int i, e[4]; | 65 | .max = POW2TO11 * BINOM12ON4, |
| 66 | .move = move_eofbepos, | ||
| 67 | }; | ||
| 49 | 68 | ||
| 50 | for (i = 0; i < 4; i++) | 69 | Coordinate |
| 51 | e[i] = cube->ep[i+8] - 8; | 70 | coord_coud = { |
| 71 | .index = index_coud, | ||
| 72 | .max = POW3TO7, | ||
| 73 | .move = move_coud, | ||
| 74 | }; | ||
| 52 | 75 | ||
| 53 | return (uint64_t)perm_to_index(e, 4); | 76 | Coordinate |
| 54 | } | 77 | coord_corners = { |
| 78 | .index = index_corners, | ||
| 79 | .max = POW3TO7 * FACTORIAL8, | ||
| 80 | .move = move_corners, | ||
| 81 | }; | ||
| 55 | 82 | ||
| 56 | uint64_t | 83 | Coordinate |
| 57 | index_epud(Cube *cube) | 84 | coord_cp = { |
| 58 | { | 85 | .index = index_cp, |
| 59 | return (uint64_t)perm_to_index(cube->ep, 8); | 86 | .max = FACTORIAL8, |
| 60 | } | 87 | .move = move_cp, |
| 88 | }; | ||
| 61 | 89 | ||
| 62 | uint64_t | 90 | Coordinate |
| 63 | index_epos(Cube *cube) | 91 | coord_cphtr = { |
| 64 | { | 92 | .index = index_cphtr, |
| 65 | int i, a[12]; | 93 | .max = BINOM8ON4 * 6, |
| 94 | .move = move_cphtr, | ||
| 95 | }; | ||
| 66 | 96 | ||
| 67 | for (i = 0; i < 12; i++) | 97 | Coordinate |
| 68 | a[i] = (cube->ep[i] < 8) ? 0 : 1; | 98 | coord_cornershtr = { |
| 99 | .index = index_cornershtr, | ||
| 100 | .max = POW3TO7 * BINOM8ON4 * 6, | ||
| 101 | .move = move_cornershtr, | ||
| 102 | }; | ||
| 69 | 103 | ||
| 70 | return (uint64_t)subset_to_index(a, 12, 4); | 104 | Coordinate |
| 71 | } | 105 | coord_cornershtrfin = { |
| 106 | .index = index_cornershtrfin, | ||
| 107 | .max = 24*24/6, | ||
| 108 | .move = move_cornershtrfin, | ||
| 109 | }; | ||
| 72 | 110 | ||
| 73 | uint64_t | 111 | Coordinate |
| 74 | index_eposepe(Cube *cube) | 112 | coord_epud = { |
| 75 | { | 113 | .index = index_epud, |
| 76 | int i, j, e[4]; | 114 | .max = FACTORIAL8, |
| 77 | uint64_t epos, epe; | 115 | .move = move_epud, |
| 116 | }; | ||
| 78 | 117 | ||
| 79 | epos = (uint64_t)index_epos(cube); | 118 | Coordinate |
| 80 | for (i = 0, j = 0; i < 12; i++) | 119 | coord_drud = { |
| 81 | if (cube->ep[i] >= 8) | 120 | .index = index_drud, |
| 82 | e[j++] = cube->ep[i] - 8; | 121 | .max = POW2TO11 * POW3TO7 * BINOM12ON4, |
| 83 | epe = (uint64_t)perm_to_index(e, 4); | 122 | .move = move_drud, |
| 123 | }; | ||
| 84 | 124 | ||
| 85 | return epos * FACTORIAL4 + epe; | 125 | Coordinate |
| 86 | } | 126 | coord_htr_drud = { |
| 127 | .index = index_htr_drud, | ||
| 128 | .max = BINOM8ON4 * 6 * BINOM8ON4, | ||
| 129 | .move = move_htr_drud, | ||
| 130 | }; | ||
| 87 | 131 | ||
| 88 | /* Inverse indexers **********************************************************/ | 132 | Coordinate |
| 133 | coord_htrfin = { | ||
| 134 | .index = index_htrfin, | ||
| 135 | .max = 24 * 24 * 24 *24 * 24 / 6, /* should be /12 but it's ok */ | ||
| 136 | .move = move_htrfin, | ||
| 137 | }; | ||
| 89 | 138 | ||
| 90 | void | 139 | Coordinate |
| 91 | invindex_eofb(uint64_t ind, Cube *cube) | 140 | coord_drud_eofb = { |
| 92 | { | 141 | .index = index_drud_eofb, |
| 93 | int_to_sum_zero_array(ind, 2, 12, cube->eo); | 142 | .max = POW3TO7 * BINOM12ON4, |
| 94 | } | 143 | .move = move_drud_eofb, |
| 144 | }; | ||
| 95 | 145 | ||
| 96 | void | 146 | Coordinate |
| 97 | invindex_coud(uint64_t ind, Cube *cube) | 147 | coord_cpud_separate = { |
| 148 | .index = index_cpud_separate, | ||
| 149 | .max = BINOM8ON4, | ||
| 150 | .move = move_cpud_separate, | ||
| 151 | }; | ||
| 152 | |||
| 153 | /* Indexers ******************************************************************/ | ||
| 154 | |||
| 155 | static uint64_t | ||
| 156 | index_eofb(Cube cube) | ||
| 98 | { | 157 | { |
| 99 | int_to_sum_zero_array(ind, 3, 8, cube->co); | 158 | return cube.eofb; |
| 100 | } | 159 | } |
| 101 | 160 | ||
| 102 | void | 161 | static uint64_t |
| 103 | invindex_cp(uint64_t ind, Cube *cube) | 162 | index_eofbepos(Cube cube) |
| 104 | { | 163 | { |
| 105 | index_to_perm(ind, 8, cube->cp); | 164 | return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; |
| 106 | } | 165 | } |
| 107 | 166 | ||
| 108 | void | 167 | static uint64_t |
| 109 | invindex_cpudsep(uint64_t ind, Cube *cube) | 168 | index_epud(Cube cube) |
| 110 | { | 169 | { |
| 111 | int i, j, k, c[8]; | 170 | uint64_t ret; |
| 171 | CubeArray *arr = new_cubearray(cube, pf_ep); | ||
| 112 | 172 | ||
| 113 | index_to_subset(ind, 8, 4, c); | 173 | ret = perm_to_index(arr->ep, 8); |
| 114 | for (i = 0, j = 0, k = 4; i < 8; i++) | 174 | free_cubearray(arr, pf_ep); |
| 115 | cube->cp[i] = c[i] == 0 ? j++ : k++; | 175 | |
| 176 | return ret; | ||
| 116 | } | 177 | } |
| 117 | 178 | ||
| 179 | static uint64_t | ||
| 180 | index_coud(Cube cube) | ||
| 181 | { | ||
| 182 | return cube.coud; | ||
| 183 | } | ||
| 118 | 184 | ||
| 119 | void | 185 | static uint64_t |
| 120 | invindex_epe(uint64_t ind, Cube *cube) | 186 | index_corners(Cube cube) |
| 121 | { | 187 | { |
| 122 | int i; | 188 | return cube.coud * FACTORIAL8 + cube.cp; |
| 189 | } | ||
| 123 | 190 | ||
| 124 | index_to_perm(ind, 4, &cube->ep[8]); | 191 | static uint64_t |
| 125 | for (i = 0; i < 4; i++) | 192 | index_cp(Cube cube) |
| 126 | cube->ep[i+8] += 8; | 193 | { |
| 194 | return cube.cp; | ||
| 127 | } | 195 | } |
| 128 | 196 | ||
| 129 | void | 197 | static uint64_t |
| 130 | invindex_epud(uint64_t ind, Cube *cube) | 198 | index_cphtr(Cube cube) |
| 131 | { | 199 | { |
| 132 | index_to_perm(ind, 8, cube->ep); | 200 | return cphtr_right_cosets[cube.cp]; |
| 133 | } | 201 | } |
| 134 | 202 | ||
| 135 | void | 203 | static uint64_t |
| 136 | invindex_epos(uint64_t ind, Cube *cube) | 204 | index_cornershtr(Cube cube) |
| 137 | { | 205 | { |
| 138 | int i, j, k; | 206 | return cube.coud * BINOM8ON4 * 6 + index_cphtr(cube); |
| 207 | } | ||
| 139 | 208 | ||
| 140 | index_to_subset(ind, 12, 4, cube->ep); | 209 | static uint64_t |
| 141 | for (i = 0, j = 0, k = 8; i < 12; i++) | 210 | index_cornershtrfin(Cube cube) |
| 142 | if (cube->ep[i] == 0) | 211 | { |
| 143 | cube->ep[i] = j++; | 212 | return cornershtrfin_ind[cube.cp]; |
| 144 | else | ||
| 145 | cube->ep[i] = k++; | ||
| 146 | } | 213 | } |
| 147 | 214 | ||
| 148 | void | 215 | static uint64_t |
| 149 | invindex_eposepe(uint64_t ind, Cube *cube) | 216 | index_drud(Cube cube) |
| 150 | { | 217 | { |
| 151 | int i, j, k, e[4]; | 218 | uint64_t a, b, c; |
| 152 | uint64_t epos, epe; | ||
| 153 | 219 | ||
| 154 | epos = ind / FACTORIAL4; | 220 | a = cube.eofb; |
| 155 | epe = ind % FACTORIAL4; | 221 | b = cube.coud; |
| 222 | c = cube.epose / FACTORIAL4; | ||
| 156 | 223 | ||
| 157 | index_to_subset(epos, 12, 4, cube->ep); | 224 | b *= POW2TO11; |
| 158 | index_to_perm(epe, 4, e); | 225 | c *= POW2TO11 * POW3TO7; |
| 159 | 226 | ||
| 160 | for (i = 0, j = 0, k = 0; i < 12; i++) | 227 | return a + b + c; |
| 161 | if (cube->ep[i] == 0) | ||
| 162 | cube->ep[i] = j++; | ||
| 163 | else | ||
| 164 | cube->ep[i] = e[k++] + 8; | ||
| 165 | } | 228 | } |
| 166 | 229 | ||
| 167 | /* Other local functions *****************************************************/ | 230 | static uint64_t |
| 168 | 231 | index_drud_eofb(Cube cube) | |
| 169 | uint64_t | ||
| 170 | indexers_getmax(Indexer **is) | ||
| 171 | { | 232 | { |
| 172 | int i; | 233 | return index_drud(cube) / POW2TO11; |
| 173 | uint64_t max = 1; | ||
| 174 | |||
| 175 | for (i = 0; is[i] != NULL; i++) | ||
| 176 | max *= is[i]->n; | ||
| 177 | |||
| 178 | return max; | ||
| 179 | } | 234 | } |
| 180 | 235 | ||
| 181 | uint64_t | 236 | static uint64_t |
| 182 | indexers_getind(Indexer **is, Cube *c) | 237 | index_htr_drud(Cube cube) |
| 183 | { | 238 | { |
| 184 | int i; | 239 | uint64_t a, b; |
| 185 | uint64_t max = 0; | ||
| 186 | 240 | ||
| 187 | for (i = 0; is[i] != NULL; i++) { | 241 | a = index_cphtr(cube); |
| 188 | max *= is[i]->n; | 242 | b = htr_eposs_ind[cube.eposs/24]; |
| 189 | max += is[i]->index(c); | ||
| 190 | } | ||
| 191 | 243 | ||
| 192 | return max; | 244 | return a * BINOM8ON4 + b; |
| 193 | } | 245 | } |
| 194 | 246 | ||
| 195 | void | 247 | static uint64_t |
| 196 | indexers_makecube(Indexer **is, uint64_t ind, Cube *c) | 248 | index_htrfin(Cube cube) |
| 197 | { | 249 | { |
| 198 | /* Warning: anti-indexers are applied in the same order as indexers. */ | 250 | uint64_t epe, eps, epm, cp, ep; |
| 199 | /* We assume order does not matter, but it would make more sense to */ | ||
| 200 | /* apply them in reverse. */ | ||
| 201 | 251 | ||
| 202 | int i; | 252 | epe = cube.epose % 24; |
| 203 | uint64_t m; | 253 | eps = cube.eposs % 24; |
| 254 | epm = cube.eposm % 24; | ||
| 255 | ep = (epe * 24 + eps) *24 + epm; | ||
| 256 | cp = index_cornershtrfin(cube); | ||
| 204 | 257 | ||
| 205 | make_solved(c); | 258 | return cp * 24 * 24 * 24 + ep; |
| 206 | m = indexers_getmax(is); | ||
| 207 | for (i = 0; is[i] != NULL; i++) { | ||
| 208 | m /= is[i]->n; | ||
| 209 | is[i]->to_cube(ind / m, c); | ||
| 210 | ind %= m; | ||
| 211 | } | ||
| 212 | } | 259 | } |
| 213 | 260 | ||
| 214 | static void | 261 | static uint64_t |
| 215 | gen_coord_comp(Coordinate *coord) | 262 | index_cpud_separate(Cube cube) |
| 216 | { | 263 | { |
| 217 | uint64_t ui; | 264 | return cpud_separate_ind[cube.cp]; |
| 218 | Cube c, mvd; | 265 | } |
| 219 | Move m; | ||
| 220 | Trans t; | ||
| 221 | |||
| 222 | coord->max = indexers_getmax(coord->i); | ||
| 223 | |||
| 224 | for (m = 0; m < NMOVES; m++) | ||
| 225 | coord->mtable[m] = malloc(coord->max * sizeof(uint64_t)); | ||
| 226 | 266 | ||
| 227 | for (t = 0; t < NTRANS; t++) | 267 | /* Coordinate movers *********************************************************/ |
| 228 | coord->ttable[t] = malloc(coord->max * sizeof(uint64_t)); | ||
| 229 | 268 | ||
| 230 | if (!read_coord_mtable(coord)) { | 269 | static uint64_t |
| 231 | fprintf(stderr, "%s: generating mtable\n", coord->name); | 270 | move_eofb(Move m, uint64_t ind) |
| 271 | { | ||
| 272 | return eofb_mtable[m][ind]; | ||
| 273 | } | ||
| 232 | 274 | ||
| 233 | for (ui = 0; ui < coord->max; ui++) { | 275 | static uint64_t |
| 234 | indexers_makecube(coord->i, ui, &c); | 276 | move_eofbepos(Move m, uint64_t ind) |
| 235 | for (m = 0; m < NMOVES; m++) { | 277 | { |
| 236 | copy_cube(&c, &mvd); | 278 | uint64_t a, b; |
| 237 | apply_move(m, &mvd); | ||
| 238 | coord->mtable[m][ui] = | ||
| 239 | indexers_getind(coord->i, &mvd); | ||
| 240 | } | ||
| 241 | } | ||
| 242 | if (!write_coord_mtable(coord)) | ||
| 243 | fprintf(stderr, "%s: error writing mtable\n", | ||
| 244 | coord->name); | ||
| 245 | |||
| 246 | fprintf(stderr, "%s: mtable generated\n", coord->name); | ||
| 247 | } | ||
| 248 | 279 | ||
| 249 | if (!read_coord_ttable(coord)) { | 280 | a = epose_mtable[m][(ind / POW2TO11)*24]; |
| 250 | fprintf(stderr, "%s: generating ttable\n", coord->name); | 281 | b = eofb_mtable[m][ind % POW2TO11]; |
| 251 | 282 | ||
| 252 | for (ui = 0; ui < coord->max; ui++) { | 283 | return (a/24) * POW2TO11 + b; |
| 253 | indexers_makecube(coord->i, ui, &c); | ||
| 254 | for (t = 0; t < NTRANS; t++) { | ||
| 255 | copy_cube(&c, &mvd); | ||
| 256 | apply_trans(t, &mvd); | ||
| 257 | coord->ttable[t][ui] = | ||
| 258 | indexers_getind(coord->i, &mvd); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | if (!write_coord_ttable(coord)) | ||
| 262 | fprintf(stderr, "%s: error writing ttable\n", | ||
| 263 | coord->name); | ||
| 264 | } | ||
| 265 | } | 284 | } |
| 266 | 285 | ||
| 267 | static void | 286 | static uint64_t |
| 268 | gen_coord_sym(Coordinate *coord) | 287 | move_epud(Move m, uint64_t ind) |
| 269 | { | 288 | { |
| 270 | uint64_t i, in, ui, uj, uu, M, nr; | 289 | /* TODO: save to file? */ |
| 290 | static bool initialized = false; | ||
| 291 | static int a[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 }; | ||
| 292 | static int shortlist[NMOVES] = { | ||
| 293 | [U] = 0, [U2] = 1, [U3] = 2, [D] = 3, [D2] = 4, [D3] = 5, | ||
| 294 | [R2] = 6, [L2] = 7, [F2] = 8, [B2] = 9 | ||
| 295 | }; | ||
| 296 | static uint64_t aux[10][FACTORIAL8]; | ||
| 297 | uint64_t ui; | ||
| 271 | int j; | 298 | int j; |
| 272 | Move m; | 299 | Move mj; |
| 273 | Trans t; | 300 | Cube c; |
| 274 | 301 | CubeArray *arr, *auxarr; | |
| 275 | M = coord->base[0]->max; | ||
| 276 | coord->selfsim = malloc(M * sizeof(uint64_t)); | ||
| 277 | coord->symclass = malloc(M * sizeof(uint64_t)); | ||
| 278 | coord->symrep = malloc(M * sizeof(uint64_t)); | ||
| 279 | coord->transtorep = malloc(M * sizeof(Trans)); | ||
| 280 | |||
| 281 | if (!read_coord_sd(coord)) { | ||
| 282 | fprintf(stderr, "%s: generating syms\n", coord->name); | ||
| 283 | |||
| 284 | for (i = 0; i < M; i++) | ||
| 285 | coord->symclass[i] = M+1; | ||
| 286 | 302 | ||
| 287 | for (i = 0, nr = 0; i < M; i++) { | 303 | if (!moveset_drud.allowed(m)) { |
| 288 | if (coord->symclass[i] != M+1) | 304 | fprintf(stderr, "Move not allowed for epud\n" |
| 289 | continue; | 305 | "This is a bug, please report\n"); |
| 306 | return coord_epud.max; | ||
| 307 | } | ||
| 290 | 308 | ||
| 291 | coord->symrep[nr] = i; | 309 | if (!initialized) { |
| 292 | coord->transtorep[i] = uf; | 310 | auxarr = malloc(sizeof(CubeArray)); |
| 293 | coord->selfsim[nr] = (uint64_t)0; | 311 | auxarr->ep = a; |
| 294 | for (j = 0; j < coord->tgrp->n; j++) { | 312 | for (ui = 0; ui < coord_epud.max; ui++) { |
| 295 | t = coord->tgrp->t[j]; | 313 | index_to_perm(ui, 8, a); |
| 296 | in = trans_coord(coord->base[0], t, i); | 314 | c = arrays_to_cube(auxarr, pf_ep); |
| 297 | coord->symclass[in] = nr; | 315 | for (j = 0; moveset_drud.sorted_moves[j] != NULLMOVE; |
| 298 | if (in == i) | 316 | j++) { |
| 299 | coord->selfsim[nr] |= ((uint64_t)1<<t); | 317 | mj = moveset_drud.sorted_moves[j]; |
| 300 | else | 318 | arr = new_cubearray(apply_move(mj, c), pf_ep); |
| 301 | coord->transtorep[in] = | 319 | aux[shortlist[mj]][ui] = |
| 302 | inverse_trans(t); | 320 | perm_to_index(arr->ep, 8); |
| 321 | free_cubearray(arr, pf_ep); | ||
| 303 | } | 322 | } |
| 304 | nr++; | ||
| 305 | } | 323 | } |
| 324 | free(auxarr); | ||
| 306 | 325 | ||
| 307 | coord->max = nr; | 326 | initialized = true; |
| 308 | |||
| 309 | fprintf(stderr, "%s: found %" PRIu64 " classes\n", | ||
| 310 | coord->name, nr); | ||
| 311 | if (!write_coord_sd(coord)) | ||
| 312 | fprintf(stderr, "%s: error writing symdata\n", | ||
| 313 | coord->name); | ||
| 314 | } | ||
| 315 | |||
| 316 | coord->symrep = realloc(coord->symrep, coord->max*sizeof(uint64_t)); | ||
| 317 | coord->selfsim = realloc(coord->selfsim, coord->max*sizeof(uint64_t)); | ||
| 318 | |||
| 319 | for (m = 0; m < NMOVES; m++) { | ||
| 320 | coord->mtable[m] = malloc(coord->max*sizeof(uint64_t)); | ||
| 321 | coord->ttrep_move[m] = malloc(coord->max*sizeof(Trans)); | ||
| 322 | } | 327 | } |
| 323 | 328 | ||
| 324 | if (!read_coord_mtable(coord)) { | 329 | return aux[shortlist[m]][ind]; |
| 325 | for (ui = 0; ui < coord->max; ui++) { | ||
| 326 | uu = coord->symrep[ui]; | ||
| 327 | for (m = 0; m < NMOVES; m++) { | ||
| 328 | uj = move_coord(coord->base[0], m, uu, NULL); | ||
| 329 | coord->mtable[m][ui] = coord->symclass[uj]; | ||
| 330 | coord->ttrep_move[m][ui] = | ||
| 331 | coord->transtorep[uj]; | ||
| 332 | } | ||
| 333 | } | ||
| 334 | if (!write_coord_mtable(coord)) | ||
| 335 | fprintf(stderr, "%s: error writing mtable\n", | ||
| 336 | coord->name); | ||
| 337 | } | ||
| 338 | } | 330 | } |
| 339 | 331 | ||
| 340 | static bool | 332 | static uint64_t |
| 341 | read_coord_mtable(Coordinate *coord) | 333 | move_coud(Move m, uint64_t ind) |
| 342 | { | 334 | { |
| 343 | FILE *f; | 335 | return coud_mtable[m][ind]; |
| 344 | char fname[strlen(tabledir)+256]; | 336 | } |
| 345 | Move m; | ||
| 346 | uint64_t M; | ||
| 347 | bool r; | ||
| 348 | |||
| 349 | strcpy(fname, tabledir); | ||
| 350 | strcat(fname, "/mt_"); | ||
| 351 | strcat(fname, coord->name); | ||
| 352 | |||
| 353 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 354 | return false; | ||
| 355 | 337 | ||
| 356 | M = coord->max; | 338 | static uint64_t |
| 357 | r = true; | 339 | move_corners(Move m, uint64_t ind) |
| 358 | for (m = 0; m < NMOVES; m++) | 340 | { |
| 359 | r = r && fread(coord->mtable[m], sizeof(uint64_t), M, f) == M; | 341 | uint64_t a, b; |
| 360 | 342 | ||
| 361 | if (coord->type == SYM_COORD) | 343 | a = coud_mtable[m][ind / FACTORIAL8]; |
| 362 | for (m = 0; m < NMOVES; m++) | 344 | b = cp_mtable[m][ind % FACTORIAL8]; |
| 363 | r = r && fread(coord->ttrep_move[m], | ||
| 364 | sizeof(Trans), M, f) == M; | ||
| 365 | 345 | ||
| 366 | fclose(f); | 346 | return a * FACTORIAL8 + b; |
| 367 | return r; | ||
| 368 | } | 347 | } |
| 369 | 348 | ||
| 370 | static bool | 349 | static uint64_t |
| 371 | read_coord_sd(Coordinate *coord) | 350 | move_cp(Move m, uint64_t ind) |
| 372 | { | 351 | { |
| 373 | FILE *f; | 352 | return cp_mtable[m][ind]; |
| 374 | char fname[strlen(tabledir)+256]; | 353 | } |
| 375 | uint64_t M, N; | ||
| 376 | bool r; | ||
| 377 | 354 | ||
| 378 | strcpy(fname, tabledir); | 355 | static uint64_t |
| 379 | strcat(fname, "/sd_"); | 356 | move_cphtr(Move m, uint64_t ind) |
| 380 | strcat(fname, coord->name); | 357 | { |
| 358 | static bool initialized = false; | ||
| 359 | static uint64_t aux[NMOVES][BINOM8ON4*6]; | ||
| 360 | uint64_t ui; | ||
| 361 | Move j; | ||
| 381 | 362 | ||
| 382 | if ((f = fopen(fname, "rb")) == NULL) | 363 | if (!initialized) { |
| 383 | return false; | 364 | for (ui = 0; ui < BINOM8ON4*6; ui++) |
| 365 | for (j = U; j < NMOVES; j++) | ||
| 366 | aux[j][ui] = cphtr_right_cosets[ | ||
| 367 | cp_mtable[j][cphtr_right_rep[ui]]]; | ||
| 384 | 368 | ||
| 385 | r = true; | 369 | initialized = true; |
| 386 | r = r && fread(&coord->max, sizeof(uint64_t), 1, f) == 1; | 370 | } |
| 387 | M = coord->max; | ||
| 388 | N = coord->base[0]->max; | ||
| 389 | r = r && fread(coord->symrep, sizeof(uint64_t), M, f) == M; | ||
| 390 | r = r && fread(coord->selfsim, sizeof(uint64_t), M, f) == M; | ||
| 391 | r = r && fread(coord->symclass, sizeof(uint64_t), N, f) == N; | ||
| 392 | r = r && fread(coord->transtorep, sizeof(Trans), N, f) == N; | ||
| 393 | 371 | ||
| 394 | fclose(f); | 372 | return aux[m][ind]; |
| 395 | return r; | ||
| 396 | } | 373 | } |
| 397 | 374 | ||
| 398 | static bool | 375 | static uint64_t |
| 399 | read_coord_ttable(Coordinate *coord) | 376 | move_cornershtr(Move m, uint64_t ind) |
| 400 | { | 377 | { |
| 401 | FILE *f; | 378 | uint64_t a, b; |
| 402 | char fname[strlen(tabledir)+256]; | ||
| 403 | Trans t; | ||
| 404 | uint64_t M; | ||
| 405 | bool r; | ||
| 406 | |||
| 407 | strcpy(fname, tabledir); | ||
| 408 | strcat(fname, "/tt_"); | ||
| 409 | strcat(fname, coord->name); | ||
| 410 | |||
| 411 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 412 | return false; | ||
| 413 | 379 | ||
| 414 | M = coord->max; | 380 | a = coud_mtable[m][ind/(BINOM8ON4 * 6)]; |
| 415 | r = true; | 381 | b = move_cphtr(m, ind % (BINOM8ON4 * 6)); |
| 416 | for (t = 0; t < NTRANS; t++) | ||
| 417 | r = r && fread(coord->ttable[t], sizeof(uint64_t), M, f) == M; | ||
| 418 | 382 | ||
| 419 | fclose(f); | 383 | return a * BINOM8ON4 * 6 + b; |
| 420 | return r; | ||
| 421 | } | 384 | } |
| 422 | 385 | ||
| 423 | static bool | 386 | static uint64_t |
| 424 | write_coord_mtable(Coordinate *coord) | 387 | move_cornershtrfin(Move m, uint64_t ind) |
| 425 | { | 388 | { |
| 426 | FILE *f; | 389 | int a; |
| 427 | char fname[strlen(tabledir)+256]; | ||
| 428 | Move m; | ||
| 429 | uint64_t M; | ||
| 430 | bool r; | ||
| 431 | 390 | ||
| 432 | strcpy(fname, tabledir); | 391 | a = cp_mtable[m][cornershtrfin_ant[ind]]; |
| 433 | strcat(fname, "/mt_"); | ||
| 434 | strcat(fname, coord->name); | ||
| 435 | 392 | ||
| 436 | if ((f = fopen(fname, "wb")) == NULL) | 393 | return cornershtrfin_ind[a]; |
| 437 | return false; | 394 | } |
| 438 | 395 | ||
| 439 | M = coord->max; | 396 | static uint64_t |
| 440 | r = true; | 397 | move_drud(Move m, uint64_t ind) |
| 441 | for (m = 0; m < NMOVES; m++) | 398 | { |
| 442 | r = r && fwrite(coord->mtable[m], sizeof(uint64_t), M, f) == M; | 399 | uint64_t a, b, c; |
| 443 | 400 | ||
| 444 | if (coord->type == SYM_COORD) | 401 | a = eofb_mtable[m][ind % POW2TO11]; |
| 445 | for (m = 0; m < NMOVES; m++) | 402 | b = coud_mtable[m][(ind / POW2TO11) % POW3TO7]; |
| 446 | r = r && fwrite(coord->ttrep_move[m], | 403 | c = epose_mtable[m][ind / (POW2TO11 * POW3TO7)]; |
| 447 | sizeof(Trans), M, f) == M; | ||
| 448 | 404 | ||
| 449 | fclose(f); | 405 | return a + (b + c * POW3TO7) * POW2TO11; |
| 450 | return r; | ||
| 451 | } | 406 | } |
| 452 | 407 | ||
| 453 | static bool | 408 | static uint64_t |
| 454 | write_coord_sd(Coordinate *coord) | 409 | move_drud_eofb(Move m, uint64_t ind) |
| 455 | { | 410 | { |
| 456 | FILE *f; | 411 | uint64_t a, b; |
| 457 | char fname[strlen(tabledir)+256]; | ||
| 458 | uint64_t M, N; | ||
| 459 | bool r; | ||
| 460 | |||
| 461 | strcpy(fname, tabledir); | ||
| 462 | strcat(fname, "/sd_"); | ||
| 463 | strcat(fname, coord->name); | ||
| 464 | 412 | ||
| 465 | if ((f = fopen(fname, "wb")) == NULL) | 413 | a = coud_mtable[m][ind % POW3TO7]; |
| 466 | return false; | 414 | b = epose_mtable[m][(ind / POW3TO7) * 24] / 24; |
| 467 | 415 | ||
| 468 | r = true; | 416 | return a + b * POW3TO7; |
| 469 | M = coord->max; | ||
| 470 | N = coord->base[0]->max; | ||
| 471 | r = r && fwrite(&coord->max, sizeof(uint64_t), 1, f) == 1; | ||
| 472 | r = r && fwrite(coord->symrep, sizeof(uint64_t), M, f) == M; | ||
| 473 | r = r && fwrite(coord->selfsim, sizeof(uint64_t), M, f) == M; | ||
| 474 | r = r && fwrite(coord->symclass, sizeof(uint64_t), N, f) == N; | ||
| 475 | r = r && fwrite(coord->transtorep, sizeof(Trans), N, f) == N; | ||
| 476 | |||
| 477 | fclose(f); | ||
| 478 | return r; | ||
| 479 | } | 417 | } |
| 480 | 418 | ||
| 481 | static bool | 419 | static uint64_t |
| 482 | write_coord_ttable(Coordinate *coord) | 420 | move_htr_drud(Move m, uint64_t ind) |
| 483 | { | 421 | { |
| 484 | FILE *f; | 422 | uint64_t a, b; |
| 485 | char fname[strlen(tabledir)+256]; | ||
| 486 | Trans t; | ||
| 487 | uint64_t M; | ||
| 488 | bool r; | ||
| 489 | 423 | ||
| 490 | strcpy(fname, tabledir); | 424 | a = move_cphtr(m, ind/BINOM8ON4); |
| 491 | strcat(fname, "/tt_"); | 425 | b = eposs_mtable[m][htr_eposs_ant[ind%BINOM8ON4]]; |
| 492 | strcat(fname, coord->name); | ||
| 493 | 426 | ||
| 494 | if ((f = fopen(fname, "wb")) == NULL) | 427 | return a*BINOM8ON4 + htr_eposs_ind[b/24]; |
| 495 | return false; | 428 | } |
| 496 | 429 | ||
| 497 | M = coord->max; | 430 | static uint64_t |
| 498 | r = true; | 431 | move_htrfin(Move m, uint64_t ind) |
| 499 | for (t = 0; t < NTRANS; t++) | 432 | { |
| 500 | r = r && fwrite(coord->ttable[t], sizeof(uint64_t), M, f) == M; | 433 | uint64_t a, b, bm, bs, be; |
| 501 | 434 | ||
| 502 | fclose(f); | 435 | a = move_cornershtrfin(m, ind / (24*24*24)); |
| 503 | return r; | 436 | bm = eposm_mtable[m][ind%24] % 24; |
| 504 | } | 437 | bs = eposs_mtable[m][(ind/24)%24] % 24; |
| 438 | be = epose_mtable[m][(ind/(24*24))%24] % 24; | ||
| 439 | b = (be * 24 + bs) * 24 + bm; | ||
| 505 | 440 | ||
| 506 | /* Public functions **********************************************************/ | 441 | return a * (24*24*24) + b; |
| 442 | } | ||
| 507 | 443 | ||
| 508 | void | 444 | static uint64_t |
| 509 | gen_coord(Coordinate *coord) | 445 | move_cpud_separate(Move m, uint64_t ind) |
| 510 | { | 446 | { |
| 511 | int i; | 447 | return cpud_separate_ind[cp_mtable[m][cpud_separate_ant[ind]]]; |
| 448 | } | ||
| 512 | 449 | ||
| 513 | if (coord == NULL || coord->generated) | 450 | /* Init functions implementation *********************************************/ |
| 514 | return; | ||
| 515 | 451 | ||
| 516 | for (i = 0; i < 2; i++) | 452 | /* |
| 517 | gen_coord(coord->base[i]); | 453 | * There is certainly a better way to do this, but for now I just use |
| 454 | * a "graph coloring" algorithm to compute the left cosets, and I compose | ||
| 455 | * with every possible cp to get the right cosets (it is possible that I am | ||
| 456 | * mixing up left and right). | ||
| 457 | * | ||
| 458 | * For doing it better "Mathematically", we need 3 things: | ||
| 459 | * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other | ||
| 460 | * This is easy and it is done in the commented function cphtr_cp(). | ||
| 461 | * - Check that there is no ep/cp parity | ||
| 462 | * - Check that we are not in the "3c" case; this is the part I don't | ||
| 463 | * know how to do. | ||
| 464 | */ | ||
| 465 | static void | ||
| 466 | init_cphtr_cosets() | ||
| 467 | { | ||
| 468 | unsigned int i; | ||
| 469 | int c = 0, d = 0; | ||
| 518 | 470 | ||
| 519 | switch (coord->type) { | 471 | for (i = 0; i < FACTORIAL8; i++) { |
| 520 | case COMP_COORD: | 472 | cphtr_left_cosets[i] = -1; |
| 521 | if (coord->i[0] == NULL) | 473 | cphtr_right_cosets[i] = -1; |
| 522 | goto error_gc; | ||
| 523 | gen_coord_comp(coord); | ||
| 524 | break; | ||
| 525 | case SYM_COORD: | ||
| 526 | if (coord->base[0] == NULL || coord->tgrp == NULL) | ||
| 527 | goto error_gc; | ||
| 528 | gen_coord_sym(coord); | ||
| 529 | break; | ||
| 530 | case SYMCOMP_COORD: | ||
| 531 | if (coord->base[0] == NULL || coord->base[1] == NULL) | ||
| 532 | goto error_gc; | ||
| 533 | coord->max = coord->base[0]->max * coord->base[1]->max; | ||
| 534 | break; | ||
| 535 | default: | ||
| 536 | break; | ||
| 537 | } | 474 | } |
| 538 | 475 | ||
| 539 | coord->generated = true; | 476 | /* First we compute left cosets with a bfs */ |
| 540 | return; | 477 | for (i = 0; i < FACTORIAL8; i++) |
| 478 | if (cphtr_left_cosets[i] == -1) | ||
| 479 | init_cphtr_left_cosets_bfs(i, c++); | ||
| 541 | 480 | ||
| 542 | error_gc: | 481 | /* Then we compute right cosets using compose() */ |
| 543 | fprintf(stderr, "Error generating coordinates.\n" | 482 | for (i = 0; i < FACTORIAL8; i++) |
| 544 | "This is a bug, pleae report.\n"); | 483 | if (cphtr_right_cosets[i] == -1) |
| 545 | exit(1); | 484 | init_cphtr_right_cosets_color(i, d++); |
| 546 | } | 485 | } |
| 547 | 486 | ||
| 548 | uint64_t | 487 | static void |
| 549 | index_coord(Coordinate *coord, Cube *cube, Trans *offtrans) | 488 | init_cphtr_left_cosets_bfs(int i, int c) |
| 550 | { | 489 | { |
| 551 | uint64_t c[2], cnosym; | 490 | int j, jj, next[FACTORIAL8], next2[FACTORIAL8], n, n2; |
| 552 | Trans ttr; | ||
| 553 | |||
| 554 | switch (coord->type) { | ||
| 555 | case COMP_COORD: | ||
| 556 | if (offtrans != NULL) | ||
| 557 | *offtrans = uf; | ||
| 558 | 491 | ||
| 559 | return indexers_getind(coord->i, cube); | 492 | Move k; |
| 560 | case SYM_COORD: | ||
| 561 | cnosym = index_coord(coord->base[0], cube, NULL); | ||
| 562 | ttr = coord->transtorep[cnosym]; | ||
| 563 | 493 | ||
| 564 | if (offtrans != NULL) | 494 | n = 1; |
| 565 | *offtrans = ttr; | 495 | next[0] = i; |
| 496 | cphtr_left_cosets[i] = c; | ||
| 566 | 497 | ||
| 567 | return coord->symclass[cnosym]; | 498 | while (n != 0) { |
| 568 | case SYMCOMP_COORD: | 499 | for (j = 0, n2 = 0; j < n; j++) { |
| 569 | c[0] = index_coord(coord->base[0], cube, NULL); | 500 | for (k = U2; k < B3; k++) { |
| 570 | cnosym = index_coord(coord->base[0]->base[0], cube, NULL); | 501 | if (!moveset_htr.allowed(k)) |
| 571 | ttr = coord->base[0]->transtorep[cnosym]; | 502 | continue; |
| 572 | c[1] = index_coord(coord->base[1], cube, NULL); | 503 | jj = apply_move(k, (Cube){ .cp = next[j] }).cp; |
| 573 | c[1] = trans_coord(coord->base[1], ttr, c[1]); | ||
| 574 | 504 | ||
| 575 | if (offtrans != NULL) | 505 | if (cphtr_left_cosets[jj] == -1) { |
| 576 | *offtrans = ttr; | 506 | cphtr_left_cosets[jj] = c; |
| 507 | next2[n2++] = jj; | ||
| 508 | } | ||
| 509 | } | ||
| 510 | } | ||
| 577 | 511 | ||
| 578 | return c[0] * coord->base[1]->max + c[1]; | 512 | for (j = 0; j < n2; j++) |
| 579 | default: | 513 | next[j] = next2[j]; |
| 580 | break; | 514 | n = n2; |
| 581 | } | 515 | } |
| 582 | |||
| 583 | return coord->max; /* Only reached in case of error */ | ||
| 584 | } | 516 | } |
| 585 | 517 | ||
| 586 | uint64_t | 518 | static void |
| 587 | move_coord(Coordinate *coord, Move m, uint64_t ind, Trans *offtrans) | 519 | init_cphtr_right_cosets_color(int i, int d) |
| 588 | { | 520 | { |
| 589 | uint64_t i[2], M; | 521 | int cp; |
| 590 | Trans ttr; | 522 | unsigned int j; |
| 591 | 523 | ||
| 592 | /* Some safety checks should be done here, but for performance * | 524 | cphtr_right_rep[d] = i; |
| 593 | * reasons we'd rather do them before calling this function. * | 525 | for (j = 0; j < FACTORIAL8; j++) { |
| 594 | * We should check if coord is generated. */ | 526 | if (cphtr_left_cosets[j] == 0) { |
| 595 | 527 | cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp; | |
| 596 | switch (coord->type) { | 528 | cphtr_right_cosets[cp] = d; |
| 597 | case COMP_COORD: | 529 | } |
| 598 | if (offtrans != NULL) | 530 | } |
| 599 | *offtrans = uf; | 531 | } |
| 600 | 532 | ||
| 601 | return coord->mtable[m][ind]; | 533 | static void |
| 602 | case SYM_COORD: | 534 | init_cpud_separate() |
| 603 | ttr = coord->ttrep_move[m][ind]; | 535 | { |
| 536 | unsigned int ui; | ||
| 537 | int i, co[8]; | ||
| 604 | 538 | ||
| 605 | if (offtrans != NULL) | 539 | for (ui = 0; ui < FACTORIAL8; ui++) { |
| 606 | *offtrans = ttr; | 540 | for (i = 0; i < 8; i++) |
| 541 | co[i] = what_corner_at((Cube){.cp=ui},i)>UBR ? 1 : 0; | ||
| 542 | cpud_separate_ind[ui] = subset_to_index(co, 8, 4); | ||
| 543 | cpud_separate_ant[cpud_separate_ind[ui]] = ui; | ||
| 544 | } | ||
| 545 | } | ||
| 607 | 546 | ||
| 608 | return coord->mtable[m][ind]; | 547 | static void |
| 609 | case SYMCOMP_COORD: | 548 | init_cornershtrfin() |
| 610 | M = coord->base[1]->max; | 549 | { |
| 611 | i[0] = ind / M; | 550 | unsigned int i, j; |
| 612 | i[1] = ind % M; | 551 | int n, c; |
| 613 | ttr = coord->base[0]->ttrep_move[m][i[0]]; | 552 | Move m; |
| 614 | i[0] = coord->base[0]->mtable[m][i[0]]; | ||
| 615 | i[1] = coord->base[1]->mtable[m][i[1]]; | ||
| 616 | i[1] = coord->base[1]->ttable[ttr][i[1]]; | ||
| 617 | 553 | ||
| 618 | if (offtrans != NULL) | 554 | for (i = 0; i < FACTORIAL8; i++) |
| 619 | *offtrans = ttr; | 555 | cornershtrfin_ind[i] = -1; |
| 556 | cornershtrfin_ind[0] = 0; | ||
| 620 | 557 | ||
| 621 | return i[0] * M + i[1]; | 558 | /* 10-pass, I think 5 is enough, but just in case */ |
| 622 | default: | 559 | n = 1; |
| 623 | break; | 560 | for (i = 0; i < 10; i++) { |
| 561 | for (j = 0; j < FACTORIAL8; j++) { | ||
| 562 | if (cornershtrfin_ind[j] == -1) | ||
| 563 | continue; | ||
| 564 | for (m = U; m < NMOVES; m++) { | ||
| 565 | if (moveset_htr.allowed(m)) { | ||
| 566 | c = cp_mtable[m][j]; | ||
| 567 | if (cornershtrfin_ind[c] == -1) { | ||
| 568 | cornershtrfin_ind[c] = n; | ||
| 569 | cornershtrfin_ant[n] = c; | ||
| 570 | n++; | ||
| 571 | } | ||
| 572 | } | ||
| 573 | } | ||
| 574 | } | ||
| 624 | } | 575 | } |
| 625 | |||
| 626 | return coord->max; /* Only reached in case of error */ | ||
| 627 | } | 576 | } |
| 628 | 577 | ||
| 629 | uint64_t | 578 | void |
| 630 | trans_coord(Coordinate *coord, Trans t, uint64_t ind) | 579 | init_htr_eposs() |
| 631 | { | 580 | { |
| 632 | uint64_t i[2], M; | 581 | int ep[12], ep2[12]; |
| 582 | int eps_solved[4] = {UL, UR, DL, DR}; | ||
| 583 | unsigned int i, j; | ||
| 633 | 584 | ||
| 634 | /* Some safety checks should be done here, but for performance * | 585 | for (i = 0; i < BINOM12ON4; i++) { |
| 635 | * reasons we'd rather do them before calling this function. * | 586 | for (j = 0; j < 12; j++) |
| 636 | * We should check if coord is generated. */ | 587 | ep[j] = ep2[j] = 0; |
| 637 | 588 | epos_to_partial_ep(i*24, ep, eps_solved); | |
| 638 | switch (coord->type) { | 589 | for (j = 0; j < 8; j++) |
| 639 | case COMP_COORD: | 590 | ep2[j/2 + 4*(j%2)] = ep[j] ? 1 : 0; |
| 640 | return coord->ttable[t][ind]; | 591 | htr_eposs_ind[i] = subset_to_index(ep2, 8, 4); |
| 641 | case SYM_COORD: | 592 | htr_eposs_ant[htr_eposs_ind[i]] = i*24; |
| 642 | return ind; | ||
| 643 | case SYMCOMP_COORD: | ||
| 644 | M = coord->base[1]->max; | ||
| 645 | i[0] = ind / M; /* Always fixed */ | ||
| 646 | i[1] = ind % M; | ||
| 647 | i[1] = coord->base[1]->ttable[t][i[1]]; | ||
| 648 | return i[0] * M + i[1]; | ||
| 649 | default: | ||
| 650 | break; | ||
| 651 | } | 593 | } |
| 594 | } | ||
| 595 | |||
| 596 | void | ||
| 597 | init_coord() | ||
| 598 | { | ||
| 599 | static bool initialized = false; | ||
| 600 | if (initialized) | ||
| 601 | return; | ||
| 602 | initialized = true; | ||
| 652 | 603 | ||
| 653 | return coord->max; /* Only reached in case of error */ | 604 | init_trans(); |
| 605 | |||
| 606 | init_cphtr_cosets(); | ||
| 607 | init_cornershtrfin(); | ||
| 608 | init_htr_eposs(); | ||
| 609 | init_cpud_separate(); | ||
| 654 | } | 610 | } |
| 611 | |||
diff --git a/src/coord.h b/src/coord.h index 4cd7e47..61398a4 100644 --- a/src/coord.h +++ b/src/coord.h | |||
| @@ -3,257 +3,26 @@ | |||
| 3 | 3 | ||
| 4 | #include "trans.h" | 4 | #include "trans.h" |
| 5 | 5 | ||
| 6 | void gen_coord(Coordinate *coord); | 6 | extern Coordinate coord_eofb; |
| 7 | uint64_t index_coord(Coordinate *coord, Cube *cube, | 7 | extern Coordinate coord_eofbepos; |
| 8 | Trans *offtrans); | 8 | extern Coordinate coord_coud; |
| 9 | uint64_t indexers_getind(Indexer **is, Cube *c); | 9 | extern Coordinate coord_cp; |
| 10 | void indexers_makecube(Indexer **is, uint64_t ind, Cube *c); | 10 | extern Coordinate coord_cphtr; |
| 11 | uint64_t move_coord(Coordinate *coord, Move m, | 11 | extern Coordinate coord_corners; |
| 12 | uint64_t ind, Trans *offtrans); | 12 | extern Coordinate coord_cornershtr; |
| 13 | uint64_t trans_coord(Coordinate *coord, Trans t, uint64_t ind); | 13 | extern Coordinate coord_cornershtrfin; |
| 14 | extern Coordinate coord_epud; | ||
| 15 | extern Coordinate coord_drud; | ||
| 16 | extern Coordinate coord_drud_eofb; | ||
| 17 | extern Coordinate coord_htr_drud; | ||
| 18 | extern Coordinate coord_htrfin; | ||
| 19 | extern Coordinate coord_cpud_separate; | ||
| 14 | 20 | ||
| 15 | /* Base coordinates and their index functions ********************************/ | 21 | extern int cpud_separate_ant[BINOM8ON4]; |
| 22 | extern int cpud_separate_ind[FACTORIAL8]; | ||
| 23 | extern int cornershtrfin_ant[24*24/6]; | ||
| 16 | 24 | ||
| 17 | #ifndef COORD_C | 25 | void init_coord(); |
| 18 | |||
| 19 | extern Coordinate coord_eofb; | ||
| 20 | extern Coordinate coord_coud; | ||
| 21 | extern Coordinate coord_cp; | ||
| 22 | extern Coordinate coord_cpudsep; | ||
| 23 | extern Coordinate coord_epos; | ||
| 24 | extern Coordinate coord_epe; | ||
| 25 | extern Coordinate coord_eposepe; | ||
| 26 | extern Coordinate coord_epud; | ||
| 27 | extern Coordinate coord_eofbepos; | ||
| 28 | extern Coordinate coord_coud_cpudsep; | ||
| 29 | extern Coordinate coord_eofbepos_sym16; | ||
| 30 | extern Coordinate coord_cp_sym16; | ||
| 31 | extern Coordinate coord_corners_sym16; | ||
| 32 | extern Coordinate coord_drud_sym16; | ||
| 33 | extern Coordinate coord_drudfin_noE_sym16; | ||
| 34 | extern Coordinate coord_nxopt31; | ||
| 35 | |||
| 36 | extern Coordinate *all_coordinates[]; | ||
| 37 | |||
| 38 | #else | ||
| 39 | |||
| 40 | /* Indexers ******************************************************************/ | ||
| 41 | |||
| 42 | uint64_t index_eofb(Cube *cube); | ||
| 43 | void invindex_eofb(uint64_t ind, Cube *ret); | ||
| 44 | Indexer | ||
| 45 | i_eofb = { | ||
| 46 | .n = POW2TO11, | ||
| 47 | .index = index_eofb, | ||
| 48 | .to_cube = invindex_eofb, | ||
| 49 | }; | ||
| 50 | |||
| 51 | uint64_t index_coud(Cube *cube); | ||
| 52 | void invindex_coud(uint64_t ind, Cube *ret); | ||
| 53 | Indexer | ||
| 54 | i_coud = { | ||
| 55 | .n = POW3TO7, | ||
| 56 | .index = index_coud, | ||
| 57 | .to_cube = invindex_coud, | ||
| 58 | }; | ||
| 59 | |||
| 60 | uint64_t index_cp(Cube *cube); | ||
| 61 | void invindex_cp(uint64_t ind, Cube *ret); | ||
| 62 | Indexer | ||
| 63 | i_cp = { | ||
| 64 | .n = FACTORIAL8, | ||
| 65 | .index = index_cp, | ||
| 66 | .to_cube = invindex_cp, | ||
| 67 | }; | ||
| 68 | |||
| 69 | uint64_t index_cpudsep(Cube *cube); | ||
| 70 | void invindex_cpudsep(uint64_t ind, Cube *ret); | ||
| 71 | Indexer | ||
| 72 | i_cpudsep = { | ||
| 73 | .n = BINOM8ON4, | ||
| 74 | .index = index_cpudsep, | ||
| 75 | .to_cube = invindex_cpudsep, | ||
| 76 | }; | ||
| 77 | |||
| 78 | uint64_t index_epos(Cube *cube); | ||
| 79 | void invindex_epos(uint64_t ind, Cube *ret); | ||
| 80 | Indexer | ||
| 81 | i_epos = { | ||
| 82 | .n = BINOM12ON4, | ||
| 83 | .index = index_epos, | ||
| 84 | .to_cube = invindex_epos, | ||
| 85 | }; | ||
| 86 | |||
| 87 | uint64_t index_epe(Cube *cube); | ||
| 88 | void invindex_epe(uint64_t ind, Cube *ret); | ||
| 89 | Indexer | ||
| 90 | i_epe = { | ||
| 91 | .n = FACTORIAL4, | ||
| 92 | .index = index_epe, | ||
| 93 | .to_cube = invindex_epe, | ||
| 94 | }; | ||
| 95 | |||
| 96 | uint64_t index_eposepe(Cube *cube); | ||
| 97 | void invindex_eposepe(uint64_t ind, Cube *ret); | ||
| 98 | Indexer | ||
| 99 | i_eposepe = { | ||
| 100 | .n = BINOM12ON4 * FACTORIAL4, | ||
| 101 | .index = index_eposepe, | ||
| 102 | .to_cube = invindex_eposepe, | ||
| 103 | }; | ||
| 104 | |||
| 105 | uint64_t index_epud(Cube *cube); | ||
| 106 | void invindex_epud(uint64_t ind, Cube *ret); | ||
| 107 | Indexer | ||
| 108 | i_epud = { | ||
| 109 | .n = FACTORIAL8, | ||
| 110 | .index = index_epud, | ||
| 111 | .to_cube = invindex_epud, | ||
| 112 | }; | ||
| 113 | |||
| 114 | /* Composite coordinates *****************************************************/ | ||
| 115 | |||
| 116 | Coordinate | ||
| 117 | coord_eofb = { | ||
| 118 | .name = "eofb", | ||
| 119 | .type = COMP_COORD, | ||
| 120 | .i = {&i_eofb, NULL}, | ||
| 121 | }; | ||
| 122 | |||
| 123 | Coordinate | ||
| 124 | coord_coud = { | ||
| 125 | .name = "coud", | ||
| 126 | .type = COMP_COORD, | ||
| 127 | .i = {&i_coud, NULL}, | ||
| 128 | }; | ||
| 129 | |||
| 130 | Coordinate | ||
| 131 | coord_cp = { | ||
| 132 | .name = "cp", | ||
| 133 | .type = COMP_COORD, | ||
| 134 | .i = {&i_cp, NULL}, | ||
| 135 | }; | ||
| 136 | |||
| 137 | Coordinate | ||
| 138 | coord_cpudsep = { | ||
| 139 | .name = "cpudsep", | ||
| 140 | .type = COMP_COORD, | ||
| 141 | .i = {&i_cpudsep, NULL}, | ||
| 142 | }; | ||
| 143 | |||
| 144 | Coordinate | ||
| 145 | coord_epos = { | ||
| 146 | .name = "epos", | ||
| 147 | .type = COMP_COORD, | ||
| 148 | .i = {&i_epos, NULL}, | ||
| 149 | }; | ||
| 150 | |||
| 151 | Coordinate | ||
| 152 | coord_epe = { | ||
| 153 | .name = "epe", | ||
| 154 | .type = COMP_COORD, | ||
| 155 | .i = {&i_epe, NULL}, | ||
| 156 | }; | ||
| 157 | |||
| 158 | Coordinate | ||
| 159 | coord_eposepe = { /* Has to be done by hand, hard compose epos + epe */ | ||
| 160 | .name = "eposepe", | ||
| 161 | .type = COMP_COORD, | ||
| 162 | .i = {&i_eposepe, NULL}, | ||
| 163 | }; | ||
| 164 | |||
| 165 | Coordinate | ||
| 166 | coord_epud = { | ||
| 167 | .name = "epud", | ||
| 168 | .type = COMP_COORD, | ||
| 169 | .i = {&i_epud, NULL}, | ||
| 170 | }; | ||
| 171 | |||
| 172 | Coordinate | ||
| 173 | coord_eofbepos = { | ||
| 174 | .name = "eofbepos", | ||
| 175 | .type = COMP_COORD, | ||
| 176 | .i = {&i_epos, &i_eofb, NULL}, | ||
| 177 | }; | ||
| 178 | |||
| 179 | Coordinate | ||
| 180 | coord_coud_cpudsep = { | ||
| 181 | .name = "coud_cpudsep", | ||
| 182 | .type = COMP_COORD, | ||
| 183 | .i = {&i_coud, &i_cpudsep, NULL}, | ||
| 184 | }; | ||
| 185 | |||
| 186 | /* Symcoordinates ************************************************************/ | ||
| 187 | |||
| 188 | Coordinate | ||
| 189 | coord_eofbepos_sym16 = { | ||
| 190 | .name = "eofbepos_sym16", | ||
| 191 | .type = SYM_COORD, | ||
| 192 | .base = {&coord_eofbepos, NULL}, | ||
| 193 | .tgrp = &tgrp_udfix, | ||
| 194 | }; | ||
| 195 | |||
| 196 | Coordinate | ||
| 197 | coord_cp_sym16 = { | ||
| 198 | .name = "cp_sym16", | ||
| 199 | .type = SYM_COORD, | ||
| 200 | .base = {&coord_cp, NULL}, | ||
| 201 | .tgrp = &tgrp_udfix, | ||
| 202 | }; | ||
| 203 | |||
| 204 | /* "Symcomp" coordinates *****************************************************/ | ||
| 205 | |||
| 206 | Coordinate | ||
| 207 | coord_corners_sym16 = { | ||
| 208 | .name = "corners_sym16", | ||
| 209 | .type = SYMCOMP_COORD, | ||
| 210 | .base = {&coord_cp_sym16, &coord_coud}, | ||
| 211 | }; | ||
| 212 | |||
| 213 | Coordinate | ||
| 214 | coord_drud_sym16 = { | ||
| 215 | .name = "drud_sym16", | ||
| 216 | .type = SYMCOMP_COORD, | ||
| 217 | .base = {&coord_eofbepos_sym16, &coord_coud}, | ||
| 218 | }; | ||
| 219 | |||
| 220 | Coordinate | ||
| 221 | coord_drudfin_noE_sym16 = { | ||
| 222 | .name = "drudfin_noE_sym16", | ||
| 223 | .type = SYMCOMP_COORD, | ||
| 224 | .base = {&coord_cp_sym16, &coord_epud}, | ||
| 225 | }; | ||
| 226 | |||
| 227 | Coordinate | ||
| 228 | coord_nxopt31 = { | ||
| 229 | .name = "nxopt31", | ||
| 230 | .type = SYMCOMP_COORD, | ||
| 231 | .base = {&coord_eofbepos_sym16, &coord_coud_cpudsep}, | ||
| 232 | }; | ||
| 233 | |||
| 234 | /* All coordinates ***********************************************************/ | ||
| 235 | |||
| 236 | Coordinate *all_coordinates[] = { | ||
| 237 | &coord_eofb, | ||
| 238 | &coord_coud, | ||
| 239 | &coord_cp, | ||
| 240 | &coord_cpudsep, | ||
| 241 | &coord_epos, | ||
| 242 | &coord_epe, | ||
| 243 | &coord_eposepe, | ||
| 244 | &coord_epud, | ||
| 245 | &coord_eofbepos, | ||
| 246 | &coord_coud_cpudsep, | ||
| 247 | &coord_eofbepos_sym16, | ||
| 248 | &coord_cp_sym16, | ||
| 249 | &coord_corners_sym16, | ||
| 250 | &coord_drud_sym16, | ||
| 251 | &coord_drudfin_noE_sym16, | ||
| 252 | &coord_nxopt31, | ||
| 253 | NULL | ||
| 254 | }; | ||
| 255 | |||
| 256 | #endif | ||
| 257 | 26 | ||
| 258 | #endif | 27 | #endif |
| 259 | 28 | ||
| @@ -1,205 +1,531 @@ | |||
| 1 | #define CUBE_C | ||
| 2 | |||
| 3 | #include "cube.h" | 1 | #include "cube.h" |
| 4 | 2 | ||
| 5 | static int where_is_piece(int piece, int *arr, int n); | 3 | /* Local functions ***********************************************************/ |
| 6 | 4 | ||
| 7 | void | 5 | static void init_inverse(); |
| 8 | compose_centers(Cube *c2, Cube *c1) | 6 | static bool read_invtables_file(); |
| 7 | static bool write_invtables_file(); | ||
| 8 | |||
| 9 | /* Tables ********************************************************************/ | ||
| 10 | |||
| 11 | static uint16_t eo_invtable_e[POW2TO11][BINOM12ON4*FACTORIAL4]; | ||
| 12 | static uint16_t eo_invtable_s[POW2TO11][BINOM12ON4*FACTORIAL4]; | ||
| 13 | static uint16_t eo_invtable_m[POW2TO11][BINOM12ON4*FACTORIAL4]; | ||
| 14 | static uint16_t co_invtable[POW3TO7][FACTORIAL8]; | ||
| 15 | static uint16_t cp_invtable[FACTORIAL8]; | ||
| 16 | static uint16_t cpos_invtable[FACTORIAL6]; | ||
| 17 | |||
| 18 | /* Functions implementation **************************************************/ | ||
| 19 | |||
| 20 | int | ||
| 21 | array_ep_to_epos(int *ep, int *ss) | ||
| 9 | { | 22 | { |
| 10 | apply_permutation(c2->xp, c1->xp, 6); | 23 | int epos[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 24 | int eps[4]; | ||
| 25 | int i, j, is; | ||
| 26 | |||
| 27 | for (i = 0, is = 0; i < 12; i++) { | ||
| 28 | for (j = 0; j < 4; j++) { | ||
| 29 | if (ep[i] == ss[j]) { | ||
| 30 | eps[is++] = j; | ||
| 31 | epos[i] = 1; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | for (i = 0; i < 4; i++) | ||
| 37 | swap(&epos[ss[i]], &epos[i+8]); | ||
| 38 | |||
| 39 | return 24 * subset_to_index(epos, 12, 4) + perm_to_index(eps, 4); | ||
| 11 | } | 40 | } |
| 12 | 41 | ||
| 13 | void | 42 | Cube |
| 14 | compose_corners(Cube *c2, Cube *c1) | 43 | arrays_to_cube(CubeArray *arr, PieceFilter f) |
| 15 | { | 44 | { |
| 16 | apply_permutation(c2->cp, c1->cp, 8); | 45 | Cube ret = {0}; |
| 17 | apply_permutation(c2->cp, c1->co, 8); | 46 | |
| 18 | sum_arrays_mod(c2->co, c1->co, 8, 3); | 47 | static int epe_solved[4] = {FR, FL, BL, BR}; |
| 48 | static int eps_solved[4] = {UL, UR, DL, DR}; | ||
| 49 | static int epm_solved[4] = {UF, UB, DF, DB}; | ||
| 50 | |||
| 51 | if (f.epose) | ||
| 52 | ret.epose = array_ep_to_epos(arr->ep, epe_solved); | ||
| 53 | if (f.eposs) | ||
| 54 | ret.eposs = array_ep_to_epos(arr->ep, eps_solved); | ||
| 55 | if (f.eposm) | ||
| 56 | ret.eposm = array_ep_to_epos(arr->ep, epm_solved); | ||
| 57 | if (f.eofb) | ||
| 58 | ret.eofb = digit_array_to_int(arr->eofb, 11, 2); | ||
| 59 | if (f.eorl) | ||
| 60 | ret.eorl = digit_array_to_int(arr->eorl, 11, 2); | ||
| 61 | if (f.eoud) | ||
| 62 | ret.eoud = digit_array_to_int(arr->eoud, 11, 2); | ||
| 63 | if (f.cp) | ||
| 64 | ret.cp = perm_to_index(arr->cp, 8); | ||
| 65 | if (f.coud) | ||
| 66 | ret.coud = digit_array_to_int(arr->coud, 7, 3); | ||
| 67 | if (f.corl) | ||
| 68 | ret.corl = digit_array_to_int(arr->corl, 7, 3); | ||
| 69 | if (f.cofb) | ||
| 70 | ret.cofb = digit_array_to_int(arr->cofb, 7, 3); | ||
| 71 | if (f.cpos) | ||
| 72 | ret.cpos = perm_to_index(arr->cpos, 6); | ||
| 73 | |||
| 74 | return ret; | ||
| 19 | } | 75 | } |
| 20 | 76 | ||
| 21 | void | 77 | Cube |
| 22 | compose_edges(Cube *c2, Cube *c1) | 78 | compose_filtered(Cube c2, Cube c1, PieceFilter f) |
| 23 | { | 79 | { |
| 24 | apply_permutation(c2->ep, c1->ep, 12); | 80 | CubeArray *arr = new_cubearray(c2, f); |
| 25 | apply_permutation(c2->ep, c1->eo, 12); | 81 | Cube ret; |
| 26 | sum_arrays_mod(c2->eo, c1->eo, 12, 2); | 82 | |
| 83 | ret = move_via_arrays(arr, c1, f); | ||
| 84 | free_cubearray(arr, f); | ||
| 85 | |||
| 86 | return ret; | ||
| 27 | } | 87 | } |
| 28 | 88 | ||
| 29 | void | 89 | void |
| 30 | compose(Cube *c2, Cube *c1) | 90 | cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) |
| 31 | { | 91 | { |
| 32 | compose_centers(c2, c1); | 92 | int i; |
| 33 | compose_corners(c2, c1); | 93 | |
| 34 | compose_edges(c2, c1); | 94 | static int epe_solved[4] = {FR, FL, BL, BR}; |
| 95 | static int eps_solved[4] = {UL, UR, DL, DR}; | ||
| 96 | static int epm_solved[4] = {UF, UB, DF, DB}; | ||
| 97 | |||
| 98 | if (f.epose || f.eposs || f.eposm) | ||
| 99 | for (i = 0; i < 12; i++) | ||
| 100 | arr->ep[i] = -1; | ||
| 101 | |||
| 102 | if (f.epose) | ||
| 103 | epos_to_partial_ep(cube.epose, arr->ep, epe_solved); | ||
| 104 | if (f.eposs) | ||
| 105 | epos_to_partial_ep(cube.eposs, arr->ep, eps_solved); | ||
| 106 | if (f.eposm) | ||
| 107 | epos_to_partial_ep(cube.eposm, arr->ep, epm_solved); | ||
| 108 | if (f.eofb) | ||
| 109 | int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb); | ||
| 110 | if (f.eorl) | ||
| 111 | int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl); | ||
| 112 | if (f.eoud) | ||
| 113 | int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud); | ||
| 114 | if (f.cp) | ||
| 115 | index_to_perm(cube.cp, 8, arr->cp); | ||
| 116 | if (f.coud) | ||
| 117 | int_to_sum_zero_array(cube.coud, 3, 8, arr->coud); | ||
| 118 | if (f.corl) | ||
| 119 | int_to_sum_zero_array(cube.corl, 3, 8, arr->corl); | ||
| 120 | if (f.cofb) | ||
| 121 | int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb); | ||
| 122 | if (f.cpos) | ||
| 123 | index_to_perm(cube.cpos, 6, arr->cpos); | ||
| 35 | } | 124 | } |
| 36 | 125 | ||
| 37 | void | 126 | void |
| 38 | copy_cube_centers(Cube *src, Cube *dst) | 127 | epos_to_compatible_ep(int epos, int *ep, int *ss) |
| 39 | { | 128 | { |
| 40 | memcpy(dst->xp, src->xp, 6 * sizeof(int)); | 129 | int i, j, k, other[8]; |
| 130 | bool flag; | ||
| 131 | |||
| 132 | for (i = 0; i < 12; i++) | ||
| 133 | ep[i] = -1; | ||
| 134 | |||
| 135 | epos_to_partial_ep(epos, ep, ss); | ||
| 136 | |||
| 137 | for (i = 0, j = 0; i < 12; i++) { | ||
| 138 | flag = false; | ||
| 139 | for (k = 0; k < 4; k++) | ||
| 140 | flag = flag || (i == ss[k]); | ||
| 141 | if (!flag) | ||
| 142 | other[j++] = i; | ||
| 143 | } | ||
| 144 | |||
| 145 | for (i = 0, j = 0; i < 12; i++) | ||
| 146 | if (ep[i] == -1) | ||
| 147 | ep[i] = other[j++]; | ||
| 41 | } | 148 | } |
| 42 | 149 | ||
| 43 | void | 150 | void |
| 44 | copy_cube_corners(Cube *src, Cube *dst) | 151 | epos_to_partial_ep(int epos, int *ep, int *ss) |
| 45 | { | 152 | { |
| 46 | memcpy(dst->cp, src->cp, 8 * sizeof(int)); | 153 | int i, is, eposs[12], eps[4]; |
| 47 | memcpy(dst->co, src->co, 8 * sizeof(int)); | 154 | |
| 155 | index_to_perm(epos % FACTORIAL4, 4, eps); | ||
| 156 | index_to_subset(epos / FACTORIAL4, 12, 4, eposs); | ||
| 157 | |||
| 158 | for (i = 0; i < 4; i++) | ||
| 159 | swap(&eposs[ss[i]], &eposs[i+8]); | ||
| 160 | |||
| 161 | for (i = 0, is = 0; i < 12; i++) | ||
| 162 | if (eposs[i]) | ||
| 163 | ep[i] = ss[eps[is++]]; | ||
| 48 | } | 164 | } |
| 49 | 165 | ||
| 50 | void | 166 | void |
| 51 | copy_cube_edges(Cube *src, Cube *dst) | 167 | fix_eorleoud(CubeArray *arr) |
| 52 | { | 168 | { |
| 53 | memcpy(dst->ep, src->ep, 12 * sizeof(int)); | 169 | int i; |
| 54 | memcpy(dst->eo, src->eo, 12 * sizeof(int)); | 170 | |
| 171 | for (i = 0; i < 12; i++) { | ||
| 172 | if ((edge_slice(i) == 0 && edge_slice(arr->ep[i]) != 0) || | ||
| 173 | (edge_slice(i) != 0 && edge_slice(arr->ep[i]) == 0)) { | ||
| 174 | arr->eorl[i] = 1 - arr->eofb[i]; | ||
| 175 | } else { | ||
| 176 | arr->eorl[i] = arr->eofb[i]; | ||
| 177 | } | ||
| 178 | |||
| 179 | if ((edge_slice(i) == 2 && edge_slice(arr->ep[i]) != 2) || | ||
| 180 | (edge_slice(i) != 2 && edge_slice(arr->ep[i]) == 2)) { | ||
| 181 | arr->eoud[i] = 1 - arr->eofb[i]; | ||
| 182 | } else { | ||
| 183 | arr->eoud[i] = arr->eofb[i]; | ||
| 184 | } | ||
| 185 | } | ||
| 55 | } | 186 | } |
| 56 | 187 | ||
| 57 | void | 188 | void |
| 58 | copy_cube(Cube *src, Cube *dst) | 189 | fix_cofbcorl(CubeArray *arr) |
| 59 | { | 190 | { |
| 60 | copy_cube_centers(src, dst); | 191 | int i; |
| 61 | copy_cube_corners(src, dst); | 192 | |
| 62 | copy_cube_edges(src, dst); | 193 | for (i = 0; i < 8; i++) { |
| 194 | if (i % 2 == arr->cp[i] % 2) { | ||
| 195 | arr->cofb[i] = arr->coud[i]; | ||
| 196 | arr->corl[i] = arr->coud[i]; | ||
| 197 | } else { | ||
| 198 | if (arr->cp[i] % 2 == 0) { | ||
| 199 | arr->cofb[i] = (arr->coud[i]+1)%3; | ||
| 200 | arr->corl[i] = (arr->coud[i]+2)%3; | ||
| 201 | } else { | ||
| 202 | arr->cofb[i] = (arr->coud[i]+2)%3; | ||
| 203 | arr->corl[i] = (arr->coud[i]+1)%3; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | } | ||
| 63 | } | 207 | } |
| 64 | 208 | ||
| 65 | bool | 209 | Cube |
| 66 | equal(Cube *c1, Cube *c2) | 210 | fourval_to_cube(int eofb, int ep, int coud, int cp) |
| 67 | { | 211 | { |
| 68 | int i; | 212 | CubeArray *arr; |
| 69 | 213 | ||
| 70 | for (i = 0; i < 12; i++) | 214 | arr = new_cubearray((Cube){0}, pf_all); |
| 71 | if (c1->ep[i] != c2->ep[i] || c1->eo[i] != c2->eo[i]) | ||
| 72 | return false; | ||
| 73 | 215 | ||
| 74 | for (i = 0; i < 8; i++) | 216 | index_to_perm(ep, 12, arr->ep); |
| 75 | if (c1->cp[i] != c2->cp[i] || c1->co[i] != c2->co[i]) | 217 | index_to_perm(cp, 8, arr->cp); |
| 76 | return false; | 218 | int_to_sum_zero_array(eofb, 2, 12, arr->eofb); |
| 219 | int_to_sum_zero_array(coud, 3, 8, arr->coud); | ||
| 77 | 220 | ||
| 78 | for (i = 0; i < 6; i++) | 221 | /* fix parity */ |
| 79 | if (c1->xp[i] != c2->xp[i]) | 222 | if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) |
| 80 | return false; | 223 | swap(&(arr->ep[0]), &(arr->ep[1])); |
| 81 | 224 | ||
| 82 | return true; | 225 | fix_eorleoud(arr); |
| 226 | fix_cofbcorl(arr); | ||
| 227 | |||
| 228 | return arrays_to_cube(arr, pf_all); | ||
| 83 | } | 229 | } |
| 84 | 230 | ||
| 85 | void | 231 | void |
| 86 | invert_cube_centers(Cube *cube) | 232 | free_cubearray(CubeArray *arr, PieceFilter f) |
| 87 | { | 233 | { |
| 88 | int i; | 234 | if (f.epose || f.eposs || f.eposm) |
| 89 | Cube aux; | 235 | free(arr->ep); |
| 90 | 236 | if (f.eofb) | |
| 91 | copy_cube_centers(cube, &aux); | 237 | free(arr->eofb); |
| 238 | if (f.eorl) | ||
| 239 | free(arr->eorl); | ||
| 240 | if (f.eoud) | ||
| 241 | free(arr->eoud); | ||
| 242 | if (f.cp) | ||
| 243 | free(arr->cp); | ||
| 244 | if (f.coud) | ||
| 245 | free(arr->coud); | ||
| 246 | if (f.corl) | ||
| 247 | free(arr->corl); | ||
| 248 | if (f.cofb) | ||
| 249 | free(arr->cofb); | ||
| 250 | if (f.cpos) | ||
| 251 | free(arr->cpos); | ||
| 92 | 252 | ||
| 93 | for (i = 0; i < 6; i++) | 253 | free(arr); |
| 94 | cube->xp[aux.xp[i]] = i; | ||
| 95 | } | 254 | } |
| 96 | 255 | ||
| 97 | void | 256 | Cube |
| 98 | invert_cube_corners(Cube *cube) | 257 | move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) |
| 99 | { | 258 | { |
| 100 | int i; | 259 | CubeArray *arrc = new_cubearray(c, f); |
| 101 | Cube aux; | 260 | Cube ret; |
| 102 | 261 | ||
| 103 | copy_cube_corners(cube, &aux); | 262 | if (f.epose || f.eposs || f.eposm) |
| 263 | apply_permutation(arr->ep, arrc->ep, 12); | ||
| 104 | 264 | ||
| 105 | for (i = 0; i < 8; i++) { | 265 | if (f.eofb) { |
| 106 | cube->cp[aux.cp[i]] = i; | 266 | apply_permutation(arr->ep, arrc->eofb, 12); |
| 107 | cube->co[aux.cp[i]] = (3 - aux.co[i]) % 3; | 267 | sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2); |
| 108 | } | 268 | } |
| 269 | |||
| 270 | if (f.eorl) { | ||
| 271 | apply_permutation(arr->ep, arrc->eorl, 12); | ||
| 272 | sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2); | ||
| 273 | } | ||
| 274 | |||
| 275 | if (f.eoud) { | ||
| 276 | apply_permutation(arr->ep, arrc->eoud, 12); | ||
| 277 | sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2); | ||
| 278 | } | ||
| 279 | |||
| 280 | if (f.cp) | ||
| 281 | apply_permutation(arr->cp, arrc->cp, 8); | ||
| 282 | |||
| 283 | if (f.coud) { | ||
| 284 | apply_permutation(arr->cp, arrc->coud, 8); | ||
| 285 | sum_arrays_mod(arr->coud, arrc->coud, 8, 3); | ||
| 286 | } | ||
| 287 | |||
| 288 | if (f.corl) { | ||
| 289 | apply_permutation(arr->cp, arrc->corl, 8); | ||
| 290 | sum_arrays_mod(arr->corl, arrc->corl, 8, 3); | ||
| 291 | } | ||
| 292 | |||
| 293 | if (f.cofb) { | ||
| 294 | apply_permutation(arr->cp, arrc->cofb, 8); | ||
| 295 | sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3); | ||
| 296 | } | ||
| 297 | |||
| 298 | if (f.cpos) | ||
| 299 | apply_permutation(arr->cpos, arrc->cpos, 6); | ||
| 300 | |||
| 301 | ret = arrays_to_cube(arrc, f); | ||
| 302 | free_cubearray(arrc, f); | ||
| 303 | |||
| 304 | return ret; | ||
| 109 | } | 305 | } |
| 110 | 306 | ||
| 111 | void | 307 | CubeArray * |
| 112 | invert_cube_edges(Cube *cube) | 308 | new_cubearray(Cube cube, PieceFilter f) |
| 113 | { | 309 | { |
| 114 | int i; | 310 | CubeArray *arr = malloc(sizeof(CubeArray)); |
| 115 | Cube aux; | ||
| 116 | 311 | ||
| 117 | copy_cube_edges(cube, &aux); | 312 | if (f.epose || f.eposs || f.eposm) |
| 313 | arr->ep = malloc(12 * sizeof(int)); | ||
| 314 | if (f.eofb) | ||
| 315 | arr->eofb = malloc(12 * sizeof(int)); | ||
| 316 | if (f.eorl) | ||
| 317 | arr->eorl = malloc(12 * sizeof(int)); | ||
| 318 | if (f.eoud) | ||
| 319 | arr->eoud = malloc(12 * sizeof(int)); | ||
| 320 | if (f.cp) | ||
| 321 | arr->cp = malloc(8 * sizeof(int)); | ||
| 322 | if (f.coud) | ||
| 323 | arr->coud = malloc(8 * sizeof(int)); | ||
| 324 | if (f.corl) | ||
| 325 | arr->corl = malloc(8 * sizeof(int)); | ||
| 326 | if (f.cofb) | ||
| 327 | arr->cofb = malloc(8 * sizeof(int)); | ||
| 328 | if (f.cpos) | ||
| 329 | arr->cpos = malloc(6 * sizeof(int)); | ||
| 118 | 330 | ||
| 119 | for (i = 0; i < 12; i++) { | 331 | cube_to_arrays(cube, arr, f); |
| 120 | cube->ep[aux.ep[i]] = i; | 332 | |
| 121 | cube->eo[aux.ep[i]] = aux.eo[i]; | 333 | return arr; |
| 334 | } | ||
| 335 | |||
| 336 | Cube | ||
| 337 | admissible_ep(Cube cube, PieceFilter f) | ||
| 338 | { | ||
| 339 | CubeArray *arr = new_cubearray(cube, f); | ||
| 340 | Cube ret; | ||
| 341 | bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 342 | int i, j; | ||
| 343 | |||
| 344 | for (i = 0; i < 12; i++) | ||
| 345 | if (arr->ep[i] != -1) | ||
| 346 | used[arr->ep[i]] = true; | ||
| 347 | |||
| 348 | for (i = 0, j = 0; i < 12; i++) { | ||
| 349 | for ( ; j < 11 && used[j]; j++); | ||
| 350 | if (arr->ep[i] == -1) | ||
| 351 | arr->ep[i] = j++; | ||
| 122 | } | 352 | } |
| 353 | |||
| 354 | ret = arrays_to_cube(arr, pf_ep); | ||
| 355 | free_cubearray(arr, f); | ||
| 356 | |||
| 357 | return ret; | ||
| 123 | } | 358 | } |
| 124 | 359 | ||
| 125 | void | 360 | Cube |
| 126 | invert_cube(Cube *cube) | 361 | compose(Cube c2, Cube c1) |
| 127 | { | 362 | { |
| 128 | invert_cube_centers(cube); | 363 | return compose_filtered(c2, c1, pf_all); |
| 129 | invert_cube_corners(cube); | 364 | } |
| 130 | invert_cube_edges(cube); | 365 | |
| 366 | int | ||
| 367 | edge_slice(Edge e) { | ||
| 368 | if (e < 0 || e > 11) | ||
| 369 | return -1; | ||
| 370 | |||
| 371 | if (e == FR || e == FL || e == BL || e == BR) | ||
| 372 | return 0; | ||
| 373 | if (e == UR || e == UL || e == DR || e == DL) | ||
| 374 | return 1; | ||
| 375 | |||
| 376 | return 2; | ||
| 131 | } | 377 | } |
| 132 | 378 | ||
| 133 | bool | 379 | bool |
| 134 | is_admissible(Cube *c) { | 380 | equal(Cube c1, Cube c2) |
| 135 | bool perm; | 381 | { |
| 136 | int sign, i; | 382 | return c1.eofb == c2.eofb && |
| 137 | int sum_e, sum_c; | 383 | c1.epose == c2.epose && |
| 384 | c1.eposs == c2.eposs && | ||
| 385 | c1.eposm == c2.eposm && | ||
| 386 | c1.coud == c2.coud && | ||
| 387 | c1.cp == c2.cp && | ||
| 388 | c1.cpos == c2.cpos; | ||
| 389 | } | ||
| 390 | |||
| 391 | Cube | ||
| 392 | inverse_cube(Cube cube) | ||
| 393 | { | ||
| 394 | CubeArray inv; | ||
| 395 | Cube ret; | ||
| 396 | int i, ep[12]; | ||
| 138 | 397 | ||
| 139 | perm = is_perm(c->ep, 12) && is_perm(c->cp, 8) && is_perm(c->xp, 6); | 398 | for (i = 0; i < 12; i++) |
| 399 | ep[i] = where_is_edge(cube, i); | ||
| 400 | inv = (CubeArray){.ep = ep}; | ||
| 401 | ret = arrays_to_cube(&inv, pf_ep); | ||
| 140 | 402 | ||
| 141 | sign = perm_sign(c->ep,12) + perm_sign(c->cp,8) + perm_sign(c->xp,6); | 403 | ret.eofb = ((int)eo_invtable_e[cube.eofb][cube.epose]) | |
| 404 | ((int)eo_invtable_m[cube.eofb][cube.eposm]) | | ||
| 405 | ((int)eo_invtable_s[cube.eofb][cube.eposs]); | ||
| 406 | ret.eorl = ((int)eo_invtable_e[cube.eorl][cube.epose]) | | ||
| 407 | ((int)eo_invtable_m[cube.eorl][cube.eposm]) | | ||
| 408 | ((int)eo_invtable_s[cube.eorl][cube.eposs]); | ||
| 409 | ret.eoud = ((int)eo_invtable_e[cube.eoud][cube.epose]) | | ||
| 410 | ((int)eo_invtable_m[cube.eoud][cube.eposm]) | | ||
| 411 | ((int)eo_invtable_s[cube.eoud][cube.eposs]); | ||
| 412 | ret.cp = cp_invtable[cube.cp]; | ||
| 413 | ret.cpos = cpos_invtable[cube.cpos]; | ||
| 414 | ret.coud = co_invtable[cube.coud][cube.cp]; | ||
| 415 | ret.corl = co_invtable[cube.corl][cube.cp]; | ||
| 416 | ret.cofb = co_invtable[cube.cofb][cube.cp]; | ||
| 142 | 417 | ||
| 143 | for (i = 0, sum_e = 0; i < 12; i++) | 418 | return ret; |
| 144 | if (c->eo[i] > 1) | 419 | } |
| 145 | return false; | ||
| 146 | else | ||
| 147 | sum_e += c->eo[i]; | ||
| 148 | 420 | ||
| 149 | for (i = 0, sum_c = 0; i < 8; i++) | 421 | bool |
| 150 | if (c->co[i] > 2) | 422 | is_admissible(Cube cube) { |
| 151 | return false; | 423 | |
| 152 | else | 424 | /* TODO: this should check consistency of different orientations */ |
| 153 | sum_c += c->co[i]; | 425 | /* check also that centers are opposite and admissible */ |
| 154 | 426 | ||
| 155 | return (perm && sign % 2 == 0 && sum_e % 2 == 0 && sum_c % 2 == 0); | 427 | CubeArray *a = new_cubearray(cube, pf_all); |
| 428 | int parity; | ||
| 429 | bool perm; | ||
| 430 | |||
| 431 | perm = is_perm(a->ep, 12) && | ||
| 432 | is_perm(a->cp, 8) && | ||
| 433 | is_perm(a->cpos, 6); | ||
| 434 | parity = perm_sign(a->ep, 12) + | ||
| 435 | perm_sign(a->cp, 8) + | ||
| 436 | perm_sign(a->cpos, 6); | ||
| 437 | |||
| 438 | free_cubearray(a, pf_all); | ||
| 439 | |||
| 440 | return perm && parity % 2 == 0; | ||
| 156 | } | 441 | } |
| 157 | 442 | ||
| 158 | bool | 443 | bool |
| 159 | is_solved(Cube *cube) | 444 | is_solved(Cube cube) |
| 160 | { | 445 | { |
| 161 | Cube solved_cube; | 446 | return equal(cube, (Cube){0}); |
| 162 | make_solved(&solved_cube); | ||
| 163 | |||
| 164 | return equal(cube, &solved_cube); | ||
| 165 | } | 447 | } |
| 166 | 448 | ||
| 167 | void | 449 | bool |
| 168 | make_solved_centers(Cube *cube) | 450 | is_block_solved(Cube cube, Block block) |
| 169 | { | 451 | { |
| 170 | static int sorted[6] = {0, 1, 2, 3, 4, 5}; | 452 | int i; |
| 453 | |||
| 454 | for (i = 0; i < 12; i++) | ||
| 455 | if (block.edge[i] && !is_solved_edge(cube, i)) | ||
| 456 | return false; | ||
| 457 | for (i = 0; i < 8; i++) | ||
| 458 | if (block.corner[i] && !is_solved_corner(cube, i)) | ||
| 459 | return false; | ||
| 460 | for (i = 0; i < 6; i++) | ||
| 461 | if (block.center[i] && !is_solved_center(cube, i)) | ||
| 462 | return false; | ||
| 171 | 463 | ||
| 172 | memcpy(cube->xp, sorted, 6 * sizeof(int)); | 464 | return true; |
| 173 | } | 465 | } |
| 174 | 466 | ||
| 175 | void | 467 | bool |
| 176 | make_solved_corners(Cube *cube) | 468 | is_solved_center(Cube cube, Center c) |
| 177 | { | 469 | { |
| 178 | static int sorted[8] = {0, 1, 2, 3, 4, 5, 6, 7}; | 470 | return what_center_at(cube, c) == c; |
| 179 | |||
| 180 | memcpy(cube->cp, sorted, 8 * sizeof(int)); | ||
| 181 | memset(cube->co, 0, 8 * sizeof(int)); | ||
| 182 | } | 471 | } |
| 183 | 472 | ||
| 184 | void | 473 | bool |
| 185 | make_solved_edges(Cube *cube) | 474 | is_solved_corner(Cube cube, Corner c) |
| 186 | { | 475 | { |
| 187 | static int sorted[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; | 476 | return what_corner_at(cube, c) == c && |
| 477 | what_orientation_corner(cube.coud, c); | ||
| 478 | } | ||
| 188 | 479 | ||
| 189 | memcpy(cube->ep, sorted, 12 * sizeof(int)); | 480 | bool |
| 190 | memset(cube->eo, 0, 12 * sizeof(int)); | 481 | is_solved_edge(Cube cube, Edge e) |
| 482 | { | ||
| 483 | return what_edge_at(cube, e) == e && | ||
| 484 | what_orientation_edge(cube.eofb, e); | ||
| 191 | } | 485 | } |
| 192 | 486 | ||
| 193 | void | 487 | int |
| 194 | make_solved(Cube *cube) | 488 | piece_orientation(Cube cube, int piece, char *orientation) |
| 195 | { | 489 | { |
| 196 | make_solved_centers(cube); | 490 | int arr[12], n, b, x; |
| 197 | make_solved_corners(cube); | 491 | |
| 198 | make_solved_edges(cube); | 492 | if (!strcmp(orientation, "eofb")) { |
| 493 | x = cube.eofb; | ||
| 494 | n = 12; | ||
| 495 | b = 2; | ||
| 496 | } else if (!strcmp(orientation, "eorl")) { | ||
| 497 | x = cube.eorl; | ||
| 498 | n = 12; | ||
| 499 | b = 2; | ||
| 500 | } else if (!strcmp(orientation, "eoud")) { | ||
| 501 | x = cube.eoud; | ||
| 502 | n = 12; | ||
| 503 | b = 2; | ||
| 504 | } else if (!strcmp(orientation, "coud")) { | ||
| 505 | x = cube.coud; | ||
| 506 | n = 8; | ||
| 507 | b = 3; | ||
| 508 | } else if (!strcmp(orientation, "corl")) { | ||
| 509 | x = cube.corl; | ||
| 510 | n = 8; | ||
| 511 | b = 3; | ||
| 512 | } else if (!strcmp(orientation, "cofb")) { | ||
| 513 | x = cube.cofb; | ||
| 514 | n = 8; | ||
| 515 | b = 3; | ||
| 516 | } else { | ||
| 517 | return -1; | ||
| 518 | } | ||
| 519 | |||
| 520 | int_to_sum_zero_array(x, b, n, arr); | ||
| 521 | if (piece < n) | ||
| 522 | return arr[piece]; | ||
| 523 | |||
| 524 | return -1; | ||
| 199 | } | 525 | } |
| 200 | 526 | ||
| 201 | void | 527 | void |
| 202 | print_cube(Cube *cube) | 528 | print_cube(Cube cube) |
| 203 | { | 529 | { |
| 204 | static char edge_string[12][7] = { | 530 | static char edge_string[12][7] = { |
| 205 | [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR", | 531 | [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR", |
| @@ -219,52 +545,388 @@ print_cube(Cube *cube) | |||
| 219 | }; | 545 | }; |
| 220 | 546 | ||
| 221 | for (int i = 0; i < 12; i++) | 547 | for (int i = 0; i < 12; i++) |
| 222 | printf(" %s ", edge_string[cube->ep[i]]); | 548 | printf(" %s ", edge_string[what_edge_at(cube, i)]); |
| 223 | printf("\n"); | 549 | printf("\n"); |
| 224 | 550 | ||
| 225 | for (int i = 0; i < 12; i++) | 551 | for (int i = 0; i < 12; i++) |
| 226 | printf(" %" PRIu8 " ", cube->eo[i]); | 552 | printf(" %d ", what_orientation_edge(cube.eofb, i)); |
| 227 | printf("\n"); | 553 | printf("\n"); |
| 228 | 554 | ||
| 229 | for (int i = 0; i < 8; i++) | 555 | for (int i = 0; i < 8; i++) |
| 230 | printf("%s ", corner_string[cube->cp[i]]); | 556 | printf("%s ", corner_string[what_corner_at(cube, i)]); |
| 231 | printf("\n"); | 557 | printf("\n"); |
| 232 | 558 | ||
| 233 | for (int i = 0; i < 8; i++) | 559 | for (int i = 0; i < 8; i++) |
| 234 | printf(" %" PRIu8 " ", cube->co[i]); | 560 | printf(" %d ", what_orientation_corner(cube.coud, i)); |
| 235 | printf("\n"); | 561 | printf("\n"); |
| 236 | 562 | ||
| 237 | for (int i = 0; i < 6; i++) | 563 | for (int i = 0; i < 6; i++) |
| 238 | printf(" %s ", center_string[cube->xp[i]]); | 564 | printf(" %s ", center_string[what_center_at(cube, i)]); |
| 239 | printf("\n"); | 565 | printf("\n"); |
| 240 | } | 566 | } |
| 241 | 567 | ||
| 242 | int | 568 | Center |
| 243 | where_is_center(Center x, Cube *c) | 569 | what_center_at(Cube cube, Center c) |
| 570 | { | ||
| 571 | static bool initialized = false; | ||
| 572 | static Center aux[FACTORIAL6][6]; | ||
| 573 | static int i; | ||
| 574 | static unsigned int ui; | ||
| 575 | static CubeArray *arr; | ||
| 576 | |||
| 577 | if (!initialized) { | ||
| 578 | for (ui = 0; ui < FACTORIAL6; ui++) { | ||
| 579 | arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); | ||
| 580 | for (i = 0; i < 6; i++) | ||
| 581 | aux[ui][i] = arr->cpos[i]; | ||
| 582 | free_cubearray(arr, pf_cpos); | ||
| 583 | } | ||
| 584 | |||
| 585 | initialized = true; | ||
| 586 | } | ||
| 587 | |||
| 588 | return aux[cube.cpos][c]; | ||
| 589 | } | ||
| 590 | |||
| 591 | Corner | ||
| 592 | what_corner_at(Cube cube, Corner c) | ||
| 593 | { | ||
| 594 | int i; | ||
| 595 | unsigned int ui; | ||
| 596 | CubeArray *arr; | ||
| 597 | |||
| 598 | static bool initialized = false; | ||
| 599 | static Corner aux[FACTORIAL8][8]; | ||
| 600 | |||
| 601 | if (!initialized) { | ||
| 602 | for (ui = 0; ui < FACTORIAL8; ui++) { | ||
| 603 | arr = new_cubearray((Cube){.cp = ui}, pf_cp); | ||
| 604 | for (i = 0; i < 8; i++) | ||
| 605 | aux[ui][i] = arr->cp[i]; | ||
| 606 | free_cubearray(arr, pf_cp); | ||
| 607 | } | ||
| 608 | |||
| 609 | initialized = true; | ||
| 610 | } | ||
| 611 | |||
| 612 | return aux[cube.cp][c]; | ||
| 613 | } | ||
| 614 | |||
| 615 | Edge | ||
| 616 | what_edge_at(Cube cube, Edge e) | ||
| 244 | { | 617 | { |
| 245 | return where_is_piece(x, c->xp, 6); | 618 | Edge ret; |
| 619 | CubeArray *arr = new_cubearray(cube, pf_ep); | ||
| 620 | |||
| 621 | ret = arr->ep[e]; | ||
| 622 | |||
| 623 | free_cubearray(arr, pf_ep); | ||
| 624 | return ret; | ||
| 246 | } | 625 | } |
| 247 | 626 | ||
| 248 | int | 627 | int |
| 249 | where_is_corner(Corner k, Cube *c) | 628 | what_orientation_corner(int co, Corner c) |
| 250 | { | 629 | { |
| 251 | return where_is_piece(k, c->cp, 8); | 630 | static bool initialized = false; |
| 631 | static int auxlast[POW3TO7]; | ||
| 632 | static int auxarr[8]; | ||
| 633 | static unsigned int ui; | ||
| 634 | |||
| 635 | if (!initialized) { | ||
| 636 | for (ui = 0; ui < POW3TO7; ui++) { | ||
| 637 | int_to_sum_zero_array(ui, 3, 8, auxarr); | ||
| 638 | auxlast[ui] = auxarr[7]; | ||
| 639 | } | ||
| 640 | |||
| 641 | initialized = true; | ||
| 642 | } | ||
| 643 | |||
| 644 | if (c < 7) | ||
| 645 | return (co / powint(3, c)) % 3; | ||
| 646 | else | ||
| 647 | return auxlast[co]; | ||
| 252 | } | 648 | } |
| 253 | 649 | ||
| 254 | int | 650 | int |
| 255 | where_is_edge(Edge e, Cube *c) | 651 | what_orientation_edge(int eo, Edge e) |
| 652 | { | ||
| 653 | static bool initialized = false; | ||
| 654 | static int auxlast[POW2TO11]; | ||
| 655 | static int auxarr[12]; | ||
| 656 | static unsigned int ui; | ||
| 657 | |||
| 658 | if (!initialized) { | ||
| 659 | for (ui = 0; ui < POW2TO11; ui++) { | ||
| 660 | int_to_sum_zero_array(ui, 2, 12, auxarr); | ||
| 661 | auxlast[ui] = auxarr[11]; | ||
| 662 | } | ||
| 663 | |||
| 664 | initialized = true; | ||
| 665 | } | ||
| 666 | |||
| 667 | if (e < 11) | ||
| 668 | return (eo & (1 << e)) ? 1 : 0; | ||
| 669 | else | ||
| 670 | return auxlast[eo]; | ||
| 671 | } | ||
| 672 | |||
| 673 | Center | ||
| 674 | where_is_center(Cube cube, Center c) | ||
| 256 | { | 675 | { |
| 257 | return where_is_piece(e, c->ep, 12); | 676 | static bool initialized = false; |
| 677 | static Center aux[FACTORIAL6][6]; | ||
| 678 | static int i; | ||
| 679 | static unsigned int ui; | ||
| 680 | static CubeArray *arr; | ||
| 681 | |||
| 682 | if (!initialized) { | ||
| 683 | for (ui = 0; ui < FACTORIAL6; ui++) { | ||
| 684 | arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); | ||
| 685 | for (i = 0; i < 6; i++) | ||
| 686 | aux[ui][arr->cpos[i]] = i; | ||
| 687 | free_cubearray(arr, pf_cpos); | ||
| 688 | } | ||
| 689 | |||
| 690 | initialized = true; | ||
| 691 | } | ||
| 692 | |||
| 693 | return aux[cube.cpos][c]; | ||
| 258 | } | 694 | } |
| 259 | 695 | ||
| 260 | static int | 696 | Corner |
| 261 | where_is_piece(int piece, int *arr, int n) | 697 | where_is_corner(Cube cube, Corner c) |
| 262 | { | 698 | { |
| 263 | int i; | 699 | static bool initialized = false; |
| 700 | static Corner aux[FACTORIAL8][8]; | ||
| 701 | static int i; | ||
| 702 | static unsigned int ui; | ||
| 703 | static CubeArray *arr; | ||
| 264 | 704 | ||
| 265 | for (i = 0; i < n; i++) | 705 | if (!initialized) { |
| 266 | if (arr[i] == piece) | 706 | for (ui = 0; ui < FACTORIAL8; ui++) { |
| 267 | return i; | 707 | arr = new_cubearray((Cube){.cp = ui}, pf_cp); |
| 708 | for (i = 0; i < 8; i++) | ||
| 709 | aux[ui][arr->cp[i]] = i; | ||
| 710 | free_cubearray(arr, pf_cp); | ||
| 711 | } | ||
| 268 | 712 | ||
| 269 | return -1; | 713 | initialized = true; |
| 714 | } | ||
| 715 | return aux[cube.cp][c]; | ||
| 716 | } | ||
| 717 | |||
| 718 | Edge | ||
| 719 | where_is_edge(Cube c, Edge e) | ||
| 720 | { | ||
| 721 | int r0, r1, r2; | ||
| 722 | |||
| 723 | static bool initialized = false; | ||
| 724 | static int aux[3][BINOM12ON4*FACTORIAL4][12]; | ||
| 725 | static int i, j; | ||
| 726 | static unsigned int ui; | ||
| 727 | static CubeArray *arr; | ||
| 728 | |||
| 729 | if (!initialized) { | ||
| 730 | for (ui = 0; ui < BINOM12ON4*FACTORIAL4; ui++) { | ||
| 731 | for (i = 0; i < 3; i++) | ||
| 732 | for (j = 0; j < 12; j++) | ||
| 733 | aux[i][ui][j] = -1; | ||
| 734 | |||
| 735 | arr = new_cubearray((Cube){.epose = ui}, pf_e); | ||
| 736 | for (i = 0; i < 12; i++) | ||
| 737 | if (edge_slice(arr->ep[i]) == 0) | ||
| 738 | aux[0][ui][arr->ep[i]] = i; | ||
| 739 | free_cubearray(arr, pf_e); | ||
| 740 | |||
| 741 | arr = new_cubearray((Cube){.eposs = ui}, pf_s); | ||
| 742 | for (i = 0; i < 12; i++) | ||
| 743 | if (edge_slice(arr->ep[i]) == 1) | ||
| 744 | aux[1][ui][arr->ep[i]] = i; | ||
| 745 | free_cubearray(arr, pf_s); | ||
| 746 | |||
| 747 | arr = new_cubearray((Cube){.eposm = ui}, pf_m); | ||
| 748 | for (i = 0; i < 12; i++) | ||
| 749 | if (edge_slice(arr->ep[i]) == 2) | ||
| 750 | aux[2][ui][arr->ep[i]] = i; | ||
| 751 | free_cubearray(arr, pf_m); | ||
| 752 | } | ||
| 753 | |||
| 754 | initialized = true; | ||
| 755 | } | ||
| 756 | |||
| 757 | r0 = aux[0][c.epose][e]; | ||
| 758 | r1 = aux[1][c.eposs][e]; | ||
| 759 | r2 = aux[2][c.eposm][e]; | ||
| 760 | return MAX(r0, MAX(r1, r2)); | ||
| 761 | } | ||
| 762 | |||
| 763 | static bool | ||
| 764 | read_invtables_file() | ||
| 765 | { | ||
| 766 | init_env(); | ||
| 767 | |||
| 768 | FILE *f; | ||
| 769 | char fname[strlen(tabledir)+20]; | ||
| 770 | int b; | ||
| 771 | unsigned int ui, meeo, meco, mecp, mecpos; | ||
| 772 | bool r; | ||
| 773 | |||
| 774 | strcpy(fname, tabledir); | ||
| 775 | strcat(fname, "/invtables"); | ||
| 776 | |||
| 777 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 778 | return false; | ||
| 779 | |||
| 780 | b = sizeof(uint16_t); | ||
| 781 | r = true; | ||
| 782 | meeo = BINOM12ON4*FACTORIAL4; | ||
| 783 | meco = FACTORIAL8; | ||
| 784 | mecp = FACTORIAL8; | ||
| 785 | mecpos = FACTORIAL6; | ||
| 786 | |||
| 787 | for (ui = 0; ui < POW2TO11; ui++) { | ||
| 788 | r = r && fread(eo_invtable_e[ui], b, meeo, f) == meeo; | ||
| 789 | r = r && fread(eo_invtable_m[ui], b, meeo, f) == meeo; | ||
| 790 | r = r && fread(eo_invtable_s[ui], b, meeo, f) == meeo; | ||
| 791 | } | ||
| 792 | |||
| 793 | for (ui = 0; ui < POW3TO7; ui++) { | ||
| 794 | r = r && fread(co_invtable[ui], b, meco, f) == meco; | ||
| 795 | } | ||
| 796 | |||
| 797 | r = r && fread(cp_invtable, b, mecp, f) == mecp; | ||
| 798 | r = r && fread(cpos_invtable, b, mecpos, f) == mecpos; | ||
| 799 | |||
| 800 | fclose(f); | ||
| 801 | return r; | ||
| 802 | } | ||
| 803 | |||
| 804 | static bool | ||
| 805 | write_invtables_file() | ||
| 806 | { | ||
| 807 | init_env(); | ||
| 808 | |||
| 809 | FILE *f; | ||
| 810 | char fname[strlen(tabledir)+20]; | ||
| 811 | unsigned int ui, meeo, meco, mecp, mecpos; | ||
| 812 | int b; | ||
| 813 | bool r; | ||
| 814 | |||
| 815 | strcpy(fname, tabledir); | ||
| 816 | strcat(fname, "/invtables"); | ||
| 817 | |||
| 818 | if ((f = fopen(fname, "wb")) == NULL) | ||
| 819 | return false; | ||
| 820 | |||
| 821 | b = sizeof(uint16_t); | ||
| 822 | r = true; | ||
| 823 | meeo = BINOM12ON4*FACTORIAL4; | ||
| 824 | meco = FACTORIAL8; | ||
| 825 | mecp = FACTORIAL8; | ||
| 826 | mecpos = FACTORIAL6; | ||
| 827 | |||
| 828 | for (ui = 0; ui < POW2TO11; ui++) { | ||
| 829 | r = r && fwrite(eo_invtable_e[ui], b, meeo, f) == meeo; | ||
| 830 | r = r && fwrite(eo_invtable_m[ui], b, meeo, f) == meeo; | ||
| 831 | r = r && fwrite(eo_invtable_s[ui], b, meeo, f) == meeo; | ||
| 832 | } | ||
| 833 | |||
| 834 | for (ui = 0; ui < POW3TO7; ui++) { | ||
| 835 | r = r && fwrite(co_invtable[ui], b, meco, f) == meco; | ||
| 836 | } | ||
| 837 | |||
| 838 | r = r && fwrite(cp_invtable, b, mecp, f) == mecp; | ||
| 839 | r = r && fwrite(cpos_invtable, b, mecpos, f) == mecpos; | ||
| 840 | |||
| 841 | fclose(f); | ||
| 842 | return r; | ||
| 843 | } | ||
| 844 | |||
| 845 | void | ||
| 846 | init_inverse() | ||
| 847 | { | ||
| 848 | static bool initialized = false; | ||
| 849 | if (initialized) | ||
| 850 | return; | ||
| 851 | initialized = true; | ||
| 852 | |||
| 853 | if (read_invtables_file()) | ||
| 854 | return; | ||
| 855 | |||
| 856 | fprintf(stderr, "Cannot load invtables, generating it\n"); | ||
| 857 | |||
| 858 | CubeArray *aux, *inv; | ||
| 859 | Cube c; | ||
| 860 | int i, j, eoaux[12], eoinv[12]; | ||
| 861 | unsigned int ui, uj; | ||
| 862 | |||
| 863 | aux = new_cubearray((Cube){0}, pf_all); | ||
| 864 | inv = new_cubearray((Cube){0}, pf_all); | ||
| 865 | |||
| 866 | for (ui = 0; ui < POW2TO11; ui++) { | ||
| 867 | int_to_sum_zero_array(ui, 2, 12, eoaux); | ||
| 868 | for (uj = 0; uj < BINOM12ON4*FACTORIAL4; uj++) { | ||
| 869 | for (j = 0; j < 12; j++) | ||
| 870 | eoinv[j] = 0; | ||
| 871 | c = (Cube){.epose = uj, .eposm = 0, .eposs = 0}; | ||
| 872 | eoinv[FR] = eoaux[where_is_edge(c, FR)]; | ||
| 873 | eoinv[FL] = eoaux[where_is_edge(c, FL)]; | ||
| 874 | eoinv[BL] = eoaux[where_is_edge(c, BL)]; | ||
| 875 | eoinv[BR] = eoaux[where_is_edge(c, BR)]; | ||
| 876 | eo_invtable_e[ui][uj] = digit_array_to_int(eoinv,11,2); | ||
| 877 | |||
| 878 | for (j = 0; j < 12; j++) | ||
| 879 | eoinv[j] = 0; | ||
| 880 | c = (Cube){.epose = 0, .eposm = uj, .eposs = 0}; | ||
| 881 | eoinv[UF] = eoaux[where_is_edge(c, UF)]; | ||
| 882 | eoinv[UB] = eoaux[where_is_edge(c, UB)]; | ||
| 883 | eoinv[DF] = eoaux[where_is_edge(c, DF)]; | ||
| 884 | eoinv[DB] = eoaux[where_is_edge(c, DB)]; | ||
| 885 | eo_invtable_m[ui][uj] = digit_array_to_int(eoinv,11,2); | ||
| 886 | |||
| 887 | for (j = 0; j < 12; j++) | ||
| 888 | eoinv[j] = 0; | ||
| 889 | c = (Cube){.epose = 0, .eposm = 0, .eposs = uj}; | ||
| 890 | eoinv[UL] = eoaux[where_is_edge(c, UL)]; | ||
| 891 | eoinv[UR] = eoaux[where_is_edge(c, UR)]; | ||
| 892 | eoinv[DL] = eoaux[where_is_edge(c, DL)]; | ||
| 893 | eoinv[DR] = eoaux[where_is_edge(c, DR)]; | ||
| 894 | eo_invtable_s[ui][uj] = digit_array_to_int(eoinv,11,2); | ||
| 895 | } | ||
| 896 | } | ||
| 897 | |||
| 898 | for (ui = 0; ui < FACTORIAL8; ui++) { | ||
| 899 | cube_to_arrays((Cube){.cp = ui}, aux, pf_cp); | ||
| 900 | for (i = 0; i < 8; i++) | ||
| 901 | inv->cp[aux->cp[i]] = i; | ||
| 902 | cp_invtable[ui] = (uint16_t)arrays_to_cube(inv, pf_cp).cp; | ||
| 903 | |||
| 904 | for (uj = 0; uj < POW3TO7; uj++) { | ||
| 905 | cube_to_arrays((Cube){.coud = uj}, aux, pf_coud); | ||
| 906 | for (i = 0; i < 8; i++) | ||
| 907 | inv->coud[aux->cp[i]] = (3-aux->coud[i])%3; | ||
| 908 | co_invtable[uj][ui] = | ||
| 909 | (uint16_t)arrays_to_cube(inv, pf_coud).coud; | ||
| 910 | } | ||
| 911 | } | ||
| 912 | |||
| 913 | for (ui = 0; ui < FACTORIAL6; ui++) { | ||
| 914 | cube_to_arrays((Cube){.cpos = ui}, aux, pf_cpos); | ||
| 915 | for (i = 0; i < 6; i++) | ||
| 916 | inv->cpos[aux->cpos[i]] = i; | ||
| 917 | cpos_invtable[ui] = | ||
| 918 | (uint16_t)arrays_to_cube(inv, pf_cpos).cpos; | ||
| 919 | } | ||
| 920 | |||
| 921 | free_cubearray(aux, pf_all); | ||
| 922 | free_cubearray(inv, pf_all); | ||
| 923 | |||
| 924 | if (!write_invtables_file()) | ||
| 925 | fprintf(stderr, "Error writing invtables\n"); | ||
| 926 | } | ||
| 927 | |||
| 928 | void | ||
| 929 | init_cube() | ||
| 930 | { | ||
| 931 | init_inverse(); | ||
| 270 | } | 932 | } |
| @@ -3,33 +3,44 @@ | |||
| 3 | 3 | ||
| 4 | #include <stdio.h> | 4 | #include <stdio.h> |
| 5 | 5 | ||
| 6 | #include "cubetypes.h" | ||
| 7 | #include "env.h" | 6 | #include "env.h" |
| 7 | #include "pf.h" | ||
| 8 | #include "utils.h" | 8 | #include "utils.h" |
| 9 | 9 | ||
| 10 | void compose(Cube *c2, Cube *c1); /* Use c2 as an alg on c1 */ | 10 | Cube admissible_ep(Cube cube, PieceFilter f); |
| 11 | void compose_centers(Cube *c2, Cube *c1); | 11 | int array_ep_to_epos(int *ep, int *eps_solved); |
| 12 | void compose_corners(Cube *c2, Cube *c1); | 12 | Cube arrays_to_cube(CubeArray *arr, PieceFilter f); |
| 13 | void compose_edges(Cube *c2, Cube *c1); | 13 | Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ |
| 14 | void copy_cube(Cube *src, Cube *dst); | 14 | Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); |
| 15 | void copy_cube_centers(Cube *src, Cube *dst); | 15 | void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); |
| 16 | void copy_cube_corners(Cube *src, Cube *dst); | 16 | int edge_slice(Edge e); /* E=0, S=1, M=2 */ |
| 17 | void copy_cube_edges(Cube *src, Cube *dst); | 17 | bool equal(Cube c1, Cube c2); |
| 18 | bool equal(Cube *c1, Cube *c2); | 18 | Cube inverse_cube(Cube cube); |
| 19 | void invert_cube(Cube *cube); | 19 | bool is_admissible(Cube cube); |
| 20 | void invert_cube_centers(Cube *cube); | 20 | bool is_solved(Cube cube); |
| 21 | void invert_cube_corners(Cube *cube); | 21 | bool is_block_solved(Cube cube, Block); |
| 22 | void invert_cube_edges(Cube *cube); | 22 | bool is_solved_center(Cube cube, Center c); |
| 23 | bool is_admissible(Cube *cube); | 23 | bool is_solved_corner(Cube cube, Corner c); |
| 24 | bool is_solved(Cube *cube); | 24 | bool is_solved_edge(Cube cube, Edge e); |
| 25 | void make_solved(Cube *cube); | 25 | void epos_to_partial_ep(int epos, int *ep, int *ss); |
| 26 | void make_solved_centers(Cube *cube); | 26 | void epos_to_compatible_ep(int epos, int *ep, int *ss); |
| 27 | void make_solved_corners(Cube *cube); | 27 | void fix_eorleoud(CubeArray *arr); |
| 28 | void make_solved_edges(Cube *cube); | 28 | void fix_cofbcorl(CubeArray *arr); |
| 29 | void print_cube(Cube *cube); | 29 | Cube fourval_to_cube(int eofb, int ep, int coud, int cp); |
| 30 | int where_is_center(Center x, Cube *c); | 30 | void free_cubearray(CubeArray *arr, PieceFilter f); |
| 31 | int where_is_corner(Corner k, Cube *c); | 31 | Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); |
| 32 | int where_is_edge(Edge e, Cube *c); | 32 | CubeArray * new_cubearray(Cube cube, PieceFilter f); |
| 33 | void print_cube(Cube cube); | ||
| 34 | Center what_center_at(Cube cube, Center c); | ||
| 35 | Corner what_corner_at(Cube cube, Corner c); | ||
| 36 | Edge what_edge_at(Cube cube, Edge e); | ||
| 37 | int what_orientation_corner(int co, Corner c); | ||
| 38 | int what_orientation_edge(int eo, Edge e); | ||
| 39 | Center where_is_center(Cube cube, Center c); | ||
| 40 | Corner where_is_corner(Cube cube, Corner c); | ||
| 41 | Edge where_is_edge(Cube cube, Edge e); | ||
| 42 | |||
| 43 | void init_cube(); | ||
| 33 | 44 | ||
| 34 | #endif | 45 | #endif |
| 35 | 46 | ||
diff --git a/src/cubetypes.h b/src/cubetypes.h index 3752019..ad9c627 100644 --- a/src/cubetypes.h +++ b/src/cubetypes.h | |||
| @@ -10,8 +10,6 @@ | |||
| 10 | #define NROTATIONS 24 | 10 | #define NROTATIONS 24 |
| 11 | #define entry_group_t uint8_t /* For pruning tables */ | 11 | #define entry_group_t uint8_t /* For pruning tables */ |
| 12 | 12 | ||
| 13 | #define MAX_N_COORD 6 | ||
| 14 | |||
| 15 | /* Enums *********************************************************************/ | 13 | /* Enums *********************************************************************/ |
| 16 | 14 | ||
| 17 | typedef enum | 15 | typedef enum |
| @@ -30,12 +28,6 @@ corner | |||
| 30 | } Corner; | 28 | } Corner; |
| 31 | 29 | ||
| 32 | typedef enum | 30 | typedef enum |
| 33 | coordtype | ||
| 34 | { | ||
| 35 | COMP_COORD, SYM_COORD, SYMCOMP_COORD | ||
| 36 | } CoordType; | ||
| 37 | |||
| 38 | typedef enum | ||
| 39 | edge | 31 | edge |
| 40 | { | 32 | { |
| 41 | UF, UL, UB, UR, | 33 | UF, UL, UB, UR, |
| @@ -84,32 +76,33 @@ trans | |||
| 84 | typedef struct alg Alg; | 76 | typedef struct alg Alg; |
| 85 | typedef struct alglist AlgList; | 77 | typedef struct alglist AlgList; |
| 86 | typedef struct alglistnode AlgListNode; | 78 | typedef struct alglistnode AlgListNode; |
| 87 | typedef struct choicestep ChoiceStep; | 79 | typedef struct block Block; |
| 88 | typedef struct command Command; | 80 | typedef struct command Command; |
| 89 | typedef struct commandargs CommandArgs; | 81 | typedef struct commandargs CommandArgs; |
| 90 | typedef struct coordinate Coordinate; | 82 | typedef struct coordinate Coordinate; |
| 91 | typedef struct cube Cube; | 83 | typedef struct cube Cube; |
| 92 | /*typedef struct dfsarg DfsArg;*/ | 84 | typedef struct cubearray CubeArray; |
| 93 | typedef struct fstcube FstCube; | 85 | typedef struct dfsarg DfsArg; |
| 94 | typedef struct indexer Indexer; | 86 | typedef struct estimatedata EstimateData; |
| 95 | typedef struct movable Movable; | ||
| 96 | typedef struct moveset Moveset; | 87 | typedef struct moveset Moveset; |
| 88 | typedef struct piecefilter PieceFilter; | ||
| 97 | typedef struct prunedata PruneData; | 89 | typedef struct prunedata PruneData; |
| 98 | typedef struct solveoptions SolveOptions; | 90 | typedef struct solveoptions SolveOptions; |
| 99 | typedef struct step Step; | 91 | typedef struct step Step; |
| 100 | typedef struct symdata SymData; | 92 | typedef struct symdata SymData; |
| 101 | typedef struct threaddatasolve ThreadDataSolve; | 93 | typedef struct threaddatasolve ThreadDataSolve; |
| 102 | typedef struct threaddatagenpt ThreadDataGenpt; | 94 | typedef struct threaddatagenpt ThreadDataGenpt; |
| 103 | typedef struct transgroup TransGroup; | ||
| 104 | 95 | ||
| 105 | typedef bool (*Checker) (Cube *); | 96 | typedef Cube (*AntiIndexer) (uint64_t); |
| 106 | typedef bool (*CubeTester) (Cube *, Alg *); | 97 | typedef bool (*Checker) (Cube); |
| 107 | /*typedef bool (*DfsMover) (DfsArg *);*/ | 98 | typedef uint64_t (*CoordMover) (Move, uint64_t); |
| 108 | typedef void (*DfsExtraCopier) (void *, void *); | 99 | typedef uint64_t (*CoordTransformer) (Trans, uint64_t); |
| 109 | typedef Alg * (*Validator) (Alg *); | 100 | typedef int (*Estimator) (DfsArg *); |
| 101 | typedef bool (*Validator) (Alg *); | ||
| 110 | typedef void (*Exec) (CommandArgs *); | 102 | typedef void (*Exec) (CommandArgs *); |
| 103 | typedef uint64_t (*Indexer) (Cube); | ||
| 111 | typedef CommandArgs * (*ArgParser) (int, char **); | 104 | typedef CommandArgs * (*ArgParser) (int, char **); |
| 112 | typedef bool (*Tester) (void); | 105 | typedef int (*TransDetector) (Cube, Trans *); |
| 113 | typedef int (*TransFinder) (uint64_t, Trans *); | 106 | typedef int (*TransFinder) (uint64_t, Trans *); |
| 114 | 107 | ||
| 115 | 108 | ||
| @@ -122,10 +115,6 @@ alg | |||
| 122 | bool * inv; | 115 | bool * inv; |
| 123 | int len; | 116 | int len; |
| 124 | int allocated; | 117 | int allocated; |
| 125 | Move * move_normal; | ||
| 126 | int len_normal; | ||
| 127 | Move * move_inverse; | ||
| 128 | int len_inverse; | ||
| 129 | }; | 118 | }; |
| 130 | 119 | ||
| 131 | struct | 120 | struct |
| @@ -144,13 +133,11 @@ alglistnode | |||
| 144 | }; | 133 | }; |
| 145 | 134 | ||
| 146 | struct | 135 | struct |
| 147 | choicestep | 136 | block |
| 148 | { | 137 | { |
| 149 | char * shortname; | 138 | bool edge[12]; |
| 150 | char * name; | 139 | bool corner[8]; |
| 151 | Step * step[99]; | 140 | bool center[6]; |
| 152 | Trans t[99]; | ||
| 153 | char * ready_msg; | ||
| 154 | }; | 141 | }; |
| 155 | 142 | ||
| 156 | struct | 143 | struct |
| @@ -169,7 +156,7 @@ commandargs | |||
| 169 | bool success; | 156 | bool success; |
| 170 | Alg * scramble; | 157 | Alg * scramble; |
| 171 | SolveOptions * opts; | 158 | SolveOptions * opts; |
| 172 | ChoiceStep * cs; | 159 | Step * step; |
| 173 | Command * command; /* For help */ | 160 | Command * command; /* For help */ |
| 174 | int n; | 161 | int n; |
| 175 | char scrtype[20]; | 162 | char scrtype[20]; |
| @@ -180,119 +167,119 @@ commandargs | |||
| 180 | struct | 167 | struct |
| 181 | coordinate | 168 | coordinate |
| 182 | { | 169 | { |
| 183 | char * name; | 170 | Indexer index; |
| 184 | CoordType type; | ||
| 185 | bool generated; | ||
| 186 | Indexer * i[99]; | ||
| 187 | uint64_t max; | 171 | uint64_t max; |
| 188 | uint64_t * mtable[NMOVES]; | 172 | CoordMover move; |
| 189 | uint64_t * ttable[NTRANS]; | 173 | CoordTransformer transform; |
| 190 | TransGroup * tgrp; | 174 | SymData * sd; |
| 191 | Coordinate * base[2]; | 175 | TransFinder tfind; /* TODO: should be easy to remove */ |
| 192 | uint64_t * symclass; | 176 | Coordinate * base; /* TODO: part of refactor */ |
| 193 | uint64_t * symrep; | ||
| 194 | Trans * transtorep; | ||
| 195 | Trans * ttrep_move[NMOVES]; | ||
| 196 | uint64_t * selfsim; | ||
| 197 | }; | 177 | }; |
| 198 | 178 | ||
| 199 | struct | 179 | struct |
| 200 | cube | 180 | cube |
| 201 | { | 181 | { |
| 202 | int ep[12]; | 182 | int epose; |
| 203 | int eo[12]; | 183 | int eposs; |
| 204 | int cp[8]; | 184 | int eposm; |
| 205 | int co[8]; | 185 | int eofb; |
| 206 | int xp[6]; | 186 | int eorl; |
| 187 | int eoud; | ||
| 188 | int cp; | ||
| 189 | int coud; | ||
| 190 | int cofb; | ||
| 191 | int corl; | ||
| 192 | int cpos; | ||
| 207 | }; | 193 | }; |
| 208 | 194 | ||
| 209 | /* | ||
| 210 | struct | 195 | struct |
| 211 | movable | 196 | cubearray |
| 212 | { | 197 | { |
| 213 | uint64_t val; | 198 | int * ep; |
| 214 | Trans t; | 199 | int * eofb; |
| 200 | int * eorl; | ||
| 201 | int * eoud; | ||
| 202 | int * cp; | ||
| 203 | int * coud; | ||
| 204 | int * corl; | ||
| 205 | int * cofb; | ||
| 206 | int * cpos; | ||
| 215 | }; | 207 | }; |
| 216 | */ | ||
| 217 | 208 | ||
| 218 | /* | ||
| 219 | struct | 209 | struct |
| 220 | dfsarg | 210 | dfsarg |
| 221 | { | 211 | { |
| 222 | Cube * cube; | 212 | Step * step; |
| 223 | Movable ind[MAX_N_COORD]; | ||
| 224 | Trans t; | ||
| 225 | Step * s; | ||
| 226 | SolveOptions * opts; | 213 | SolveOptions * opts; |
| 214 | Trans t; | ||
| 215 | Cube cube; | ||
| 216 | Cube inverse; | ||
| 227 | int d; | 217 | int d; |
| 228 | int bound; | 218 | uint64_t badmoves; |
| 219 | uint64_t badmovesinv; | ||
| 229 | bool niss; | 220 | bool niss; |
| 221 | Move last1; | ||
| 222 | Move last2; | ||
| 223 | Move last1inv; | ||
| 224 | Move last2inv; | ||
| 225 | EstimateData * ed; | ||
| 230 | AlgList * sols; | 226 | AlgList * sols; |
| 231 | pthread_mutex_t * sols_mutex; | 227 | pthread_mutex_t * sols_mutex; |
| 232 | Alg * current_alg; | 228 | Alg * current_alg; |
| 233 | void * extra; | ||
| 234 | }; | 229 | }; |
| 235 | */ | ||
| 236 | 230 | ||
| 237 | /* | ||
| 238 | struct | 231 | struct |
| 239 | dfsarg | 232 | estimatedata |
| 240 | { | 233 | { |
| 241 | void * cube_data; | 234 | int corners; |
| 242 | SolveOptions * opts; | 235 | int normal_ud; |
| 243 | int d; | 236 | int normal_fb; |
| 244 | int bound; | 237 | int normal_rl; |
| 245 | bool niss; | 238 | int inverse_ud; |
| 246 | AlgList * sols; | 239 | int inverse_fb; |
| 247 | Alg * current_alg; | 240 | int inverse_rl; |
| 248 | Solver * solver; | 241 | int oldret; |
| 249 | Threader * threader; | ||
| 250 | }; | 242 | }; |
| 251 | */ | ||
| 252 | 243 | ||
| 253 | struct | 244 | struct |
| 254 | fstcube | 245 | moveset |
| 255 | { | 246 | { |
| 256 | uint16_t uf_eofb; | 247 | bool (*allowed)(Move); |
| 257 | uint16_t uf_eposepe; | 248 | bool (*allowed_next)(Move, Move, Move); |
| 258 | uint16_t uf_coud; | 249 | Move sorted_moves[NMOVES+1]; |
| 259 | uint16_t uf_cp; | 250 | uint64_t mask[NMOVES][NMOVES]; |
| 260 | uint16_t fr_eofb; | ||
| 261 | uint16_t fr_eposepe; | ||
| 262 | uint16_t fr_coud; | ||
| 263 | uint16_t rd_eofb; | ||
| 264 | uint16_t rd_eposepe; | ||
| 265 | uint16_t rd_coud; | ||
| 266 | }; | 251 | }; |
| 267 | 252 | ||
| 268 | struct | 253 | struct |
| 269 | indexer | 254 | piecefilter |
| 270 | { | 255 | { |
| 271 | int n; | 256 | bool epose; |
| 272 | uint64_t (*index)(Cube *); | 257 | bool eposs; |
| 273 | void (*to_cube)(uint64_t, Cube *); | 258 | bool eposm; |
| 274 | }; | 259 | bool eofb; |
| 275 | 260 | bool eorl; | |
| 276 | struct | 261 | bool eoud; |
| 277 | moveset | 262 | bool cp; |
| 278 | { | 263 | bool coud; |
| 279 | char * name; | 264 | bool cofb; |
| 280 | bool (*allowed)(Move); | 265 | bool corl; |
| 281 | bool (*can_append)(Alg *, Move, bool); | 266 | bool cpos; |
| 282 | bool (*cancel_niss)(Alg *); | ||
| 283 | Move sorted_moves[NMOVES+1]; | ||
| 284 | }; | 267 | }; |
| 285 | 268 | ||
| 286 | struct | 269 | struct |
| 287 | prunedata | 270 | prunedata |
| 288 | { | 271 | { |
| 272 | char * filename; | ||
| 289 | entry_group_t * ptable; | 273 | entry_group_t * ptable; |
| 274 | bool generated; | ||
| 290 | uint64_t n; | 275 | uint64_t n; |
| 291 | Coordinate * coord; | 276 | Coordinate * coord; |
| 292 | Moveset * moveset; | 277 | Moveset * moveset; |
| 293 | uint64_t count[16]; | ||
| 294 | bool compact; | 278 | bool compact; |
| 295 | int base; | 279 | int base; |
| 280 | uint64_t count[16]; | ||
| 281 | PruneData * fallback; | ||
| 282 | uint64_t fbmod; | ||
| 296 | }; | 283 | }; |
| 297 | 284 | ||
| 298 | struct | 285 | struct |
| @@ -313,30 +300,52 @@ solveoptions | |||
| 313 | struct | 300 | struct |
| 314 | step | 301 | step |
| 315 | { | 302 | { |
| 316 | Checker ready; | 303 | char * shortname; |
| 304 | char * name; | ||
| 317 | bool final; | 305 | bool final; |
| 318 | Moveset * moveset; | 306 | Checker is_done; |
| 319 | int n_coord; | 307 | Estimator estimate; |
| 320 | Coordinate * coord[MAX_N_COORD]; | 308 | Checker ready; |
| 321 | Trans coord_trans[MAX_N_COORD]; | 309 | char * ready_msg; |
| 322 | PruneData * pd[MAX_N_COORD]; | ||
| 323 | bool pd_compact[MAX_N_COORD]; | ||
| 324 | Validator is_valid; | 310 | Validator is_valid; |
| 325 | /*DfsMover custom_move_checkstop;*/ | 311 | Moveset * moveset; |
| 326 | DfsExtraCopier copy_extra; | 312 | Trans pre_trans; |
| 313 | TransDetector detect; | ||
| 314 | int ntables; | ||
| 315 | PruneData * tables[10]; | ||
| 316 | }; | ||
| 317 | |||
| 318 | struct | ||
| 319 | symdata | ||
| 320 | { | ||
| 321 | char * filename; | ||
| 322 | bool generated; | ||
| 323 | Coordinate * coord; | ||
| 324 | Coordinate * sym_coord; | ||
| 325 | int ntrans; | ||
| 326 | Trans * trans; | ||
| 327 | uint64_t * class; | ||
| 328 | uint64_t * unsym; | ||
| 329 | Trans * transtorep; | ||
| 330 | uint64_t * selfsim; | ||
| 331 | CoordTransformer transform; /* TODO: remove, use that of base coord */ | ||
| 327 | }; | 332 | }; |
| 328 | 333 | ||
| 329 | /* | ||
| 330 | struct | 334 | struct |
| 331 | threaddatasolve | 335 | threaddatasolve |
| 332 | { | 336 | { |
| 333 | DfsArg arg; | ||
| 334 | int thid; | 337 | int thid; |
| 338 | Trans t; | ||
| 339 | Cube cube; | ||
| 340 | Step * step; | ||
| 341 | int depth; | ||
| 342 | SolveOptions * opts; | ||
| 335 | AlgList * start; | 343 | AlgList * start; |
| 336 | AlgListNode ** node; | 344 | AlgListNode ** node; |
| 345 | AlgList * sols; | ||
| 337 | pthread_mutex_t * start_mutex; | 346 | pthread_mutex_t * start_mutex; |
| 347 | pthread_mutex_t * sols_mutex; | ||
| 338 | }; | 348 | }; |
| 339 | */ | ||
| 340 | 349 | ||
| 341 | struct | 350 | struct |
| 342 | threaddatagenpt | 351 | threaddatagenpt |
| @@ -350,11 +359,4 @@ threaddatagenpt | |||
| 350 | pthread_mutex_t * upmutex; | 359 | pthread_mutex_t * upmutex; |
| 351 | }; | 360 | }; |
| 352 | 361 | ||
| 353 | struct | ||
| 354 | transgroup | ||
| 355 | { | ||
| 356 | int n; | ||
| 357 | Trans t[NTRANS]; | ||
| 358 | }; | ||
| 359 | |||
| 360 | #endif | 362 | #endif |
| @@ -1,5 +1,3 @@ | |||
| 1 | #define ENV_C | ||
| 2 | |||
| 3 | #include "env.h" | 1 | #include "env.h" |
| 4 | 2 | ||
| 5 | bool initialized_env = false; | 3 | bool initialized_env = false; |
| @@ -8,8 +8,8 @@ | |||
| 8 | #include <unistd.h> | 8 | #include <unistd.h> |
| 9 | #include <sys/stat.h> | 9 | #include <sys/stat.h> |
| 10 | 10 | ||
| 11 | void init_env(); | ||
| 12 | |||
| 13 | extern char *tabledir; | 11 | extern char *tabledir; |
| 14 | 12 | ||
| 13 | void init_env(); | ||
| 14 | |||
| 15 | #endif | 15 | #endif |
diff --git a/src/fst.c b/src/fst.c deleted file mode 100644 index b51e2d4..0000000 --- a/src/fst.c +++ /dev/null | |||
| @@ -1,401 +0,0 @@ | |||
| 1 | #define FST_C | ||
| 2 | |||
| 3 | #include "fst.h" | ||
| 4 | |||
| 5 | static FstCube ep_to_fst_epos(int *ep); | ||
| 6 | static void init_fst_corner_invtables(); | ||
| 7 | static void init_fst_eo_invtables(); | ||
| 8 | static void init_fst_eo_update(uint64_t, uint64_t, int, Cube *); | ||
| 9 | static void init_fst_where_is_edge(); | ||
| 10 | static bool read_fst_tables_file(); | ||
| 11 | static bool write_fst_tables_file(); | ||
| 12 | |||
| 13 | static int edge_slice[12] = {[FR] = 0, [FL] = 0, [BL] = 0, [BR] = 0, | ||
| 14 | [UL] = 1, [UR] = 1, [DR] = 1, [DL] = 1, | ||
| 15 | [UF] = 2, [UB] = 2, [DF] = 2, [DB] = 2}; | ||
| 16 | |||
| 17 | static uint16_t inv_coud[FACTORIAL8][POW3TO7]; | ||
| 18 | static uint16_t inv_cp[FACTORIAL8]; | ||
| 19 | static uint16_t uf_cp_to_fr_cp[FACTORIAL8]; | ||
| 20 | static uint16_t uf_cp_to_rd_cp[FACTORIAL8]; | ||
| 21 | static uint16_t eo_invtable[3][POW2TO11][BINOM12ON4*FACTORIAL4]; | ||
| 22 | static uint16_t fst_where_is_edge_arr[3][12][BINOM12ON4*FACTORIAL4]; | ||
| 23 | |||
| 24 | FstCube | ||
| 25 | cube_to_fst(Cube *cube) | ||
| 26 | { | ||
| 27 | Cube c; | ||
| 28 | FstCube ret; | ||
| 29 | |||
| 30 | copy_cube(cube, &c); | ||
| 31 | ret.uf_eofb = coord_eofb.i[0]->index(&c); | ||
| 32 | ret.uf_eposepe = coord_eposepe.i[0]->index(&c); | ||
| 33 | ret.uf_coud = coord_coud.i[0]->index(&c); | ||
| 34 | ret.uf_cp = coord_cp.i[0]->index(&c); | ||
| 35 | copy_cube(cube, &c); | ||
| 36 | apply_trans(fr, &c); | ||
| 37 | ret.fr_eofb = coord_eofb.i[0]->index(&c); | ||
| 38 | ret.fr_eposepe = coord_eposepe.i[0]->index(&c); | ||
| 39 | ret.fr_coud = coord_coud.i[0]->index(&c); | ||
| 40 | copy_cube(cube, &c); | ||
| 41 | apply_trans(rd, &c); | ||
| 42 | ret.rd_eofb = coord_eofb.i[0]->index(&c); | ||
| 43 | ret.rd_eposepe = coord_eposepe.i[0]->index(&c); | ||
| 44 | ret.rd_coud = coord_coud.i[0]->index(&c); | ||
| 45 | |||
| 46 | return ret; | ||
| 47 | } | ||
| 48 | |||
| 49 | static FstCube | ||
| 50 | ep_to_fst_epos(int *ep) | ||
| 51 | { | ||
| 52 | static int eind[12] = { | ||
| 53 | [FR] = 0, [FL] = 1, [BL] = 2, [BR] = 3, | ||
| 54 | [UR] = 0, [DR] = 1, [DL] = 2, [UL] = 3, | ||
| 55 | [DB] = 0, [DF] = 1, [UF] = 2, [UB] = 3 | ||
| 56 | }; | ||
| 57 | static int eptrans_fr[12] = { | ||
| 58 | [FR] = UF, [DF] = UL, [FL] = UB, [UF] = UR, | ||
| 59 | [BR] = DF, [DB] = DL, [BL] = DB, [UB] = DR, | ||
| 60 | [UR] = FR, [DR] = FL, [DL] = BL, [UL] = BR | ||
| 61 | }; | ||
| 62 | static int eptrans_rd[12] = { | ||
| 63 | [DR] = UF, [FR] = UL, [UR] = UB, [BR] = UR, | ||
| 64 | [DL] = DF, [FL] = DL, [UL] = DB, [BL] = DR, | ||
| 65 | [DB] = FR, [DF] = FL, [UF] = BL, [UB] = BR | ||
| 66 | }; | ||
| 67 | |||
| 68 | FstCube ret; | ||
| 69 | int i, ce, cs, cm; | ||
| 70 | int epe[4], eps[4], epm[4], epose[12], eposs[12], eposm[12]; | ||
| 71 | |||
| 72 | memset(epose, 0, 12*sizeof(int)); | ||
| 73 | memset(eposs, 0, 12*sizeof(int)); | ||
| 74 | memset(eposm, 0, 12*sizeof(int)); | ||
| 75 | |||
| 76 | for (i = 0, ce = 0; i < 12; i++) { | ||
| 77 | switch (edge_slice[ep[i]]) { | ||
| 78 | case 0: | ||
| 79 | epose[i] = 1; | ||
| 80 | epe[ce++] = eind[ep[i]]; | ||
| 81 | break; | ||
| 82 | case 1: | ||
| 83 | eposs[eptrans_fr[i]] = eind[ep[i]] + 1; | ||
| 84 | break; | ||
| 85 | default: | ||
| 86 | eposm[eptrans_rd[i]] = eind[ep[i]] + 1; | ||
| 87 | break; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | for (i = 0, cs = 0, cm = 0; i < 12; i++) { | ||
| 92 | if (eposs[i]) { | ||
| 93 | eps[cs++] = eposs[i] - 1; | ||
| 94 | eposs[i] = 1; | ||
| 95 | } | ||
| 96 | if (eposm[i]) { | ||
| 97 | epm[cm++] = eposm[i] - 1; | ||
| 98 | eposm[i] = 1; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | ret.uf_eposepe = subset_to_index(epose, 12, 4) * FACTORIAL4 + | ||
| 103 | perm_to_index(epe, 4); | ||
| 104 | ret.fr_eposepe = subset_to_index(eposs, 12, 4) * FACTORIAL4 + | ||
| 105 | perm_to_index(eps, 4); | ||
| 106 | ret.rd_eposepe = subset_to_index(eposm, 12, 4) * FACTORIAL4 + | ||
| 107 | perm_to_index(epm, 4); | ||
| 108 | |||
| 109 | return ret; | ||
| 110 | } | ||
| 111 | |||
| 112 | FstCube | ||
| 113 | fst_inverse(FstCube fst) | ||
| 114 | { | ||
| 115 | FstCube ret; | ||
| 116 | int ep_inv[12]; | ||
| 117 | |||
| 118 | ep_inv[FR] = fst_where_is_edge_arr[0][FR][fst.uf_eposepe]; | ||
| 119 | ep_inv[FL] = fst_where_is_edge_arr[0][FL][fst.uf_eposepe]; | ||
| 120 | ep_inv[BL] = fst_where_is_edge_arr[0][BL][fst.uf_eposepe]; | ||
| 121 | ep_inv[BR] = fst_where_is_edge_arr[0][BR][fst.uf_eposepe]; | ||
| 122 | |||
| 123 | ep_inv[UR] = fst_where_is_edge_arr[1][UR][fst.fr_eposepe]; | ||
| 124 | ep_inv[UL] = fst_where_is_edge_arr[1][UL][fst.fr_eposepe]; | ||
| 125 | ep_inv[DR] = fst_where_is_edge_arr[1][DR][fst.fr_eposepe]; | ||
| 126 | ep_inv[DL] = fst_where_is_edge_arr[1][DL][fst.fr_eposepe]; | ||
| 127 | |||
| 128 | ep_inv[UF] = fst_where_is_edge_arr[2][UF][fst.rd_eposepe]; | ||
| 129 | ep_inv[UB] = fst_where_is_edge_arr[2][UB][fst.rd_eposepe]; | ||
| 130 | ep_inv[DF] = fst_where_is_edge_arr[2][DF][fst.rd_eposepe]; | ||
| 131 | ep_inv[DB] = fst_where_is_edge_arr[2][DB][fst.rd_eposepe]; | ||
| 132 | |||
| 133 | ret = ep_to_fst_epos(ep_inv); | ||
| 134 | |||
| 135 | ret.uf_eofb = ((uint16_t)eo_invtable[0][fst.uf_eofb][fst.uf_eposepe]) | | ||
| 136 | ((uint16_t)eo_invtable[1][fst.uf_eofb][fst.fr_eposepe]) | | ||
| 137 | ((uint16_t)eo_invtable[2][fst.uf_eofb][fst.rd_eposepe]); | ||
| 138 | ret.fr_eofb = ((uint16_t)eo_invtable[0][fst.fr_eofb][fst.uf_eposepe]) | | ||
| 139 | ((uint16_t)eo_invtable[1][fst.fr_eofb][fst.fr_eposepe]) | | ||
| 140 | ((uint16_t)eo_invtable[2][fst.fr_eofb][fst.rd_eposepe]); | ||
| 141 | ret.rd_eofb = ((uint16_t)eo_invtable[0][fst.rd_eofb][fst.uf_eposepe]) | | ||
| 142 | ((uint16_t)eo_invtable[1][fst.rd_eofb][fst.fr_eposepe]) | | ||
| 143 | ((uint16_t)eo_invtable[2][fst.rd_eofb][fst.rd_eposepe]); | ||
| 144 | |||
| 145 | ret.uf_cp = inv_cp[fst.uf_cp]; | ||
| 146 | |||
| 147 | ret.uf_coud = inv_coud[fst.uf_cp][fst.uf_coud]; | ||
| 148 | ret.fr_coud = inv_coud[uf_cp_to_fr_cp[fst.uf_cp]][fst.fr_coud]; | ||
| 149 | ret.rd_coud = inv_coud[uf_cp_to_rd_cp[fst.uf_cp]][fst.rd_coud]; | ||
| 150 | |||
| 151 | return ret; | ||
| 152 | } | ||
| 153 | |||
| 154 | FstCube | ||
| 155 | fst_move(Move m, FstCube fst) | ||
| 156 | { | ||
| 157 | FstCube ret; | ||
| 158 | Move m_fr, m_rd; | ||
| 159 | |||
| 160 | m_fr = transform_move(fr, m); | ||
| 161 | m_rd = transform_move(rd, m); | ||
| 162 | |||
| 163 | ret.uf_eofb = coord_eofb.mtable[m][fst.uf_eofb]; | ||
| 164 | ret.uf_eposepe = coord_eposepe.mtable[m][fst.uf_eposepe]; | ||
| 165 | ret.uf_coud = coord_coud.mtable[m][fst.uf_coud]; | ||
| 166 | ret.uf_cp = coord_cp.mtable[m][fst.uf_cp]; | ||
| 167 | |||
| 168 | ret.fr_eofb = coord_eofb.mtable[m_fr][fst.fr_eofb]; | ||
| 169 | ret.fr_eposepe = coord_eposepe.mtable[m_fr][fst.fr_eposepe]; | ||
| 170 | ret.fr_coud = coord_coud.mtable[m_fr][fst.fr_coud]; | ||
| 171 | |||
| 172 | ret.rd_eofb = coord_eofb.mtable[m_rd][fst.rd_eofb]; | ||
| 173 | ret.rd_eposepe = coord_eposepe.mtable[m_rd][fst.rd_eposepe]; | ||
| 174 | ret.rd_coud = coord_coud.mtable[m_rd][fst.rd_coud]; | ||
| 175 | |||
| 176 | return ret; | ||
| 177 | } | ||
| 178 | |||
| 179 | void | ||
| 180 | fst_to_cube(FstCube fst, Cube *cube) | ||
| 181 | { | ||
| 182 | Cube e, s, m; | ||
| 183 | int i; | ||
| 184 | |||
| 185 | coord_eposepe.i[0]->to_cube(fst.uf_eposepe, &e); | ||
| 186 | coord_eposepe.i[0]->to_cube(fst.fr_eposepe, &s); | ||
| 187 | apply_trans(inverse_trans(fr), &s); | ||
| 188 | coord_eposepe.i[0]->to_cube(fst.rd_eposepe, &m); | ||
| 189 | apply_trans(inverse_trans(rd), &m); | ||
| 190 | |||
| 191 | for (i = 0; i < 12; i++) { | ||
| 192 | if (edge_slice[e.ep[i]] == 0) | ||
| 193 | cube->ep[i] = e.ep[i]; | ||
| 194 | if (edge_slice[s.ep[i]] == 1) | ||
| 195 | cube->ep[i] = s.ep[i]; | ||
| 196 | if (edge_slice[m.ep[i]] == 2) | ||
| 197 | cube->ep[i] = m.ep[i]; | ||
| 198 | } | ||
| 199 | |||
| 200 | coord_eofb.i[0]->to_cube((uint64_t)fst.uf_eofb, cube); | ||
| 201 | coord_coud.i[0]->to_cube((uint64_t)fst.uf_coud, cube); | ||
| 202 | coord_cp.i[0]->to_cube((uint64_t)fst.uf_cp, cube); | ||
| 203 | |||
| 204 | for (i = 0; i < 6; i++) | ||
| 205 | cube->xp[i] = i; | ||
| 206 | } | ||
| 207 | |||
| 208 | void | ||
| 209 | init_fst() | ||
| 210 | { | ||
| 211 | init_trans(); | ||
| 212 | gen_coord(&coord_eofb); | ||
| 213 | gen_coord(&coord_eposepe); | ||
| 214 | gen_coord(&coord_coud); | ||
| 215 | gen_coord(&coord_cp); | ||
| 216 | |||
| 217 | if (!read_fst_tables_file()) { | ||
| 218 | fprintf(stderr, | ||
| 219 | "Could not load fst_tables, generating them\n"); | ||
| 220 | init_fst_corner_invtables(); | ||
| 221 | init_fst_eo_invtables(); | ||
| 222 | init_fst_where_is_edge(); | ||
| 223 | if (!write_fst_tables_file()) | ||
| 224 | fprintf(stderr, "fst_tables could not be written\b"); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | static void | ||
| 229 | init_fst_corner_invtables() | ||
| 230 | { | ||
| 231 | Cube c, d; | ||
| 232 | uint64_t cp, coud; | ||
| 233 | |||
| 234 | for (cp = 0; cp < FACTORIAL8; cp++) { | ||
| 235 | make_solved_corners(&c); | ||
| 236 | coord_cp.i[0]->to_cube(cp, &c); | ||
| 237 | |||
| 238 | copy_cube_corners(&c, &d); | ||
| 239 | invert_cube_corners(&d); | ||
| 240 | inv_cp[cp] = coord_cp.i[0]->index(&d); | ||
| 241 | |||
| 242 | for (coud = 0; coud < POW3TO7; coud++) { | ||
| 243 | copy_cube_corners(&c, &d); | ||
| 244 | coord_coud.i[0]->to_cube(coud, &d); | ||
| 245 | invert_cube_corners(&d); | ||
| 246 | inv_coud[cp][coud] = coord_coud.i[0]->index(&d); | ||
| 247 | } | ||
| 248 | |||
| 249 | copy_cube_corners(&c, &d); | ||
| 250 | apply_trans(fr, &d); | ||
| 251 | uf_cp_to_fr_cp[cp] = coord_cp.i[0]->index(&d); | ||
| 252 | |||
| 253 | copy_cube_corners(&c, &d); | ||
| 254 | apply_trans(rd, &d); | ||
| 255 | uf_cp_to_rd_cp[cp] = coord_cp.i[0]->index(&d); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | static void | ||
| 260 | init_fst_eo_invtables() | ||
| 261 | { | ||
| 262 | uint64_t ep, eo; | ||
| 263 | Cube c, d; | ||
| 264 | |||
| 265 | for (ep = 0; ep < BINOM12ON4 * FACTORIAL4; ep++) { | ||
| 266 | make_solved(&c); | ||
| 267 | coord_eposepe.i[0]->to_cube(ep, &c); | ||
| 268 | for (eo = 0; eo < POW2TO11; eo++) { | ||
| 269 | copy_cube_edges(&c, &d); | ||
| 270 | coord_eofb.i[0]->to_cube(eo, &d); | ||
| 271 | init_fst_eo_update(eo, ep, 0, &d); | ||
| 272 | |||
| 273 | apply_trans(inverse_trans(fr), &d); | ||
| 274 | coord_eofb.i[0]->to_cube(eo, &d); | ||
| 275 | init_fst_eo_update(eo, ep, 1, &d); | ||
| 276 | |||
| 277 | copy_cube_edges(&c, &d); | ||
| 278 | apply_trans(inverse_trans(rd), &d); | ||
| 279 | coord_eofb.i[0]->to_cube(eo, &d); | ||
| 280 | init_fst_eo_update(eo, ep, 2, &d); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | static void | ||
| 286 | init_fst_eo_update(uint64_t eo, uint64_t ep, int s, Cube *d) | ||
| 287 | { | ||
| 288 | int i; | ||
| 289 | |||
| 290 | for (i = 0; i < 12; i++) { | ||
| 291 | if (edge_slice[d->ep[i]] == s && d->eo[i] && d->ep[i] != 11) | ||
| 292 | eo_invtable[s][eo][ep] |= | ||
| 293 | ((uint16_t)1) << ((uint16_t)d->ep[i]); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | static void | ||
| 298 | init_fst_where_is_edge() | ||
| 299 | { | ||
| 300 | Cube c, d; | ||
| 301 | uint64_t e; | ||
| 302 | |||
| 303 | make_solved(&c); | ||
| 304 | for (e = 0; e < BINOM12ON4 * FACTORIAL4; e++) { | ||
| 305 | coord_eposepe.i[0]->to_cube(e, &c); | ||
| 306 | |||
| 307 | copy_cube_edges(&c, &d); | ||
| 308 | fst_where_is_edge_arr[0][FR][e] = where_is_edge(FR, &d); | ||
| 309 | fst_where_is_edge_arr[0][FL][e] = where_is_edge(FL, &d); | ||
| 310 | fst_where_is_edge_arr[0][BL][e] = where_is_edge(BL, &d); | ||
| 311 | fst_where_is_edge_arr[0][BR][e] = where_is_edge(BR, &d); | ||
| 312 | |||
| 313 | copy_cube_edges(&c, &d); | ||
| 314 | apply_trans(inverse_trans(fr), &d); | ||
| 315 | fst_where_is_edge_arr[1][UL][e] = where_is_edge(UL, &d); | ||
| 316 | fst_where_is_edge_arr[1][UR][e] = where_is_edge(UR, &d); | ||
| 317 | fst_where_is_edge_arr[1][DL][e] = where_is_edge(DL, &d); | ||
| 318 | fst_where_is_edge_arr[1][DR][e] = where_is_edge(DR, &d); | ||
| 319 | |||
| 320 | copy_cube_edges(&c, &d); | ||
| 321 | apply_trans(inverse_trans(rd), &d); | ||
| 322 | fst_where_is_edge_arr[2][UF][e] = where_is_edge(UF, &d); | ||
| 323 | fst_where_is_edge_arr[2][UB][e] = where_is_edge(UB, &d); | ||
| 324 | fst_where_is_edge_arr[2][DF][e] = where_is_edge(DF, &d); | ||
| 325 | fst_where_is_edge_arr[2][DB][e] = where_is_edge(DB, &d); | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | static bool | ||
| 330 | read_fst_tables_file() | ||
| 331 | { | ||
| 332 | init_env(); | ||
| 333 | |||
| 334 | FILE *f; | ||
| 335 | char fname[strlen(tabledir)+256]; | ||
| 336 | uint64_t i, j, r, total; | ||
| 337 | |||
| 338 | strcpy(fname, tabledir); | ||
| 339 | strcat(fname, "/fst_tables"); | ||
| 340 | |||
| 341 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 342 | return false; | ||
| 343 | |||
| 344 | r = 0; | ||
| 345 | total = FACTORIAL8*(POW3TO7+3) + 3*BINOM12ON4*FACTORIAL4*(12+POW2TO11); | ||
| 346 | |||
| 347 | for (i = 0; i < FACTORIAL8; i++) | ||
| 348 | r += fread(inv_coud[i], sizeof(uint16_t), POW3TO7, f); | ||
| 349 | r += fread(inv_cp, sizeof(uint16_t), FACTORIAL8, f); | ||
| 350 | r += fread(uf_cp_to_fr_cp, sizeof(uint16_t), FACTORIAL8, f); | ||
| 351 | r += fread(uf_cp_to_rd_cp, sizeof(uint16_t), FACTORIAL8, f); | ||
| 352 | for (i = 0; i < 3; i++) | ||
| 353 | for (j = 0; j < POW2TO11; j++) | ||
| 354 | r += fread(eo_invtable[i][j], | ||
| 355 | sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f); | ||
| 356 | for (i = 0; i < 3; i++) | ||
| 357 | for (j = 0; j < 12; j++) | ||
| 358 | r += fread(fst_where_is_edge_arr[i][j], | ||
| 359 | sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f); | ||
| 360 | |||
| 361 | fclose(f); | ||
| 362 | |||
| 363 | return r == total; | ||
| 364 | } | ||
| 365 | |||
| 366 | static bool | ||
| 367 | write_fst_tables_file() | ||
| 368 | { | ||
| 369 | init_env(); | ||
| 370 | |||
| 371 | FILE *f; | ||
| 372 | char fname[strlen(tabledir)+256]; | ||
| 373 | uint64_t i, j, w, total; | ||
| 374 | |||
| 375 | strcpy(fname, tabledir); | ||
| 376 | strcat(fname, "/fst_tables"); | ||
| 377 | |||
| 378 | if ((f = fopen(fname, "wb")) == NULL) | ||
| 379 | return false; | ||
| 380 | |||
| 381 | w = 0; | ||
| 382 | total = FACTORIAL8*(POW3TO7+3) + 3*BINOM12ON4*FACTORIAL4*(12+POW2TO11); | ||
| 383 | |||
| 384 | for (i = 0; i < FACTORIAL8; i++) | ||
| 385 | w += fwrite(inv_coud[i], sizeof(uint16_t), POW3TO7, f); | ||
| 386 | w += fwrite(inv_cp, sizeof(uint16_t), FACTORIAL8, f); | ||
| 387 | w += fwrite(uf_cp_to_fr_cp, sizeof(uint16_t), FACTORIAL8, f); | ||
| 388 | w += fwrite(uf_cp_to_rd_cp, sizeof(uint16_t), FACTORIAL8, f); | ||
| 389 | for (i = 0; i < 3; i++) | ||
| 390 | for (j = 0; j < POW2TO11; j++) | ||
| 391 | w += fwrite(eo_invtable[i][j], | ||
| 392 | sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f); | ||
| 393 | for (i = 0; i < 3; i++) | ||
| 394 | for (j = 0; j < 12; j++) | ||
| 395 | w += fwrite(fst_where_is_edge_arr[i][j], | ||
| 396 | sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f); | ||
| 397 | |||
| 398 | fclose(f); | ||
| 399 | |||
| 400 | return w == total; | ||
| 401 | } | ||
diff --git a/src/fst.h b/src/fst.h deleted file mode 100644 index c3b226c..0000000 --- a/src/fst.h +++ /dev/null | |||
| @@ -1,13 +0,0 @@ | |||
| 1 | #ifndef FST_H | ||
| 2 | #define FST_H | ||
| 3 | |||
| 4 | #include "coord.h" | ||
| 5 | |||
| 6 | FstCube cube_to_fst(Cube *cube); | ||
| 7 | FstCube fst_inverse(FstCube fst); | ||
| 8 | FstCube fst_move(Move m, FstCube fst); | ||
| 9 | void fst_to_cube(FstCube fst, Cube *cube); | ||
| 10 | void init_fst(); | ||
| 11 | |||
| 12 | #endif | ||
| 13 | |||
diff --git a/src/moves.c b/src/moves.c index a9dfdc0..02880ca 100644 --- a/src/moves.c +++ b/src/moves.c | |||
| @@ -1,18 +1,79 @@ | |||
| 1 | #define MOVES_C | ||
| 2 | |||
| 3 | #include "moves.h" | 1 | #include "moves.h" |
| 4 | 2 | ||
| 5 | /* Local functions ***********************************************************/ | 3 | /* Local functions ***********************************************************/ |
| 6 | 4 | ||
| 5 | static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); | ||
| 7 | static void cleanup_aux(Alg *alg, Alg *ret, bool inv); | 6 | static void cleanup_aux(Alg *alg, Alg *ret, bool inv); |
| 7 | static bool read_mtables_file(); | ||
| 8 | static bool write_mtables_file(); | ||
| 8 | 9 | ||
| 9 | /* Tables and other data *****************************************************/ | 10 | /* Tables and other data *****************************************************/ |
| 10 | 11 | ||
| 11 | /* Moves are represented as cubes and applied using compose(). Every move is * | 12 | /* Every move is translated to a an <U, x, y> alg before filling the |
| 12 | * translated to a an <U, x, y> alg before filling the transition tables. * | 13 | transition tables, see init_moves() */ |
| 13 | * See init_moves(). */ | 14 | |
| 15 | static int edge_cycle[NMOVES][12] = | ||
| 16 | { | ||
| 17 | [U] = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR }, | ||
| 18 | [x] = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR }, | ||
| 19 | [y] = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL } | ||
| 20 | }; | ||
| 21 | |||
| 22 | static int corner_cycle[NMOVES][8] = | ||
| 23 | { | ||
| 24 | [U] = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR }, | ||
| 25 | [x] = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR }, | ||
| 26 | [y] = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL } | ||
| 27 | }; | ||
| 28 | |||
| 29 | static int center_cycle[NMOVES][6] = | ||
| 30 | { | ||
| 31 | [x] = { F_center, B_center, R_center, L_center, D_center, U_center }, | ||
| 32 | [y] = { U_center, D_center, B_center, F_center, R_center, L_center } | ||
| 33 | }; | ||
| 34 | |||
| 35 | static int eofb_flipped[NMOVES][12] = { | ||
| 36 | [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, | ||
| 37 | [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } | ||
| 38 | }; | ||
| 39 | |||
| 40 | static int eorl_flipped[NMOVES][12] = { | ||
| 41 | [x] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, | ||
| 42 | [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } | ||
| 43 | }; | ||
| 44 | |||
| 45 | static int eoud_flipped[NMOVES][12] = { | ||
| 46 | [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 }, | ||
| 47 | [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, | ||
| 48 | [y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } | ||
| 49 | }; | ||
| 50 | |||
| 51 | static int coud_flipped[NMOVES][8] = { | ||
| 52 | [x] = { | ||
| 53 | [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2, | ||
| 54 | [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2 | ||
| 55 | } | ||
| 56 | }; | ||
| 57 | |||
| 58 | static int corl_flipped[NMOVES][8] = { | ||
| 59 | [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 }, | ||
| 60 | [y] = { | ||
| 61 | [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2, | ||
| 62 | [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1 | ||
| 63 | } | ||
| 64 | }; | ||
| 14 | 65 | ||
| 15 | static Cube move_array[NMOVES]; | 66 | static int cofb_flipped[NMOVES][8] = { |
| 67 | [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 }, | ||
| 68 | [x] = { | ||
| 69 | [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2, | ||
| 70 | [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1 | ||
| 71 | }, | ||
| 72 | [y] = { | ||
| 73 | [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1, | ||
| 74 | [DFR] = 1, [DBR] = 2, [DBL] = 1, [DFL] = 2 | ||
| 75 | } | ||
| 76 | }; | ||
| 16 | 77 | ||
| 17 | static char equiv_alg_string[100][NMOVES] = { | 78 | static char equiv_alg_string[100][NMOVES] = { |
| 18 | [NULLMOVE] = "", | 79 | [NULLMOVE] = "", |
| @@ -76,52 +137,89 @@ static char equiv_alg_string[100][NMOVES] = { | |||
| 76 | [z3] = " y x yyy " | 137 | [z3] = " y x yyy " |
| 77 | }; | 138 | }; |
| 78 | 139 | ||
| 140 | /* Transition tables, to be loaded up at the beginning */ | ||
| 141 | int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; | ||
| 142 | int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; | ||
| 143 | int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; | ||
| 144 | int eofb_mtable[NMOVES][POW2TO11]; | ||
| 145 | int eorl_mtable[NMOVES][POW2TO11]; | ||
| 146 | int eoud_mtable[NMOVES][POW2TO11]; | ||
| 147 | int cp_mtable[NMOVES][FACTORIAL8]; | ||
| 148 | int coud_mtable[NMOVES][POW3TO7]; | ||
| 149 | int cofb_mtable[NMOVES][POW3TO7]; | ||
| 150 | int corl_mtable[NMOVES][POW3TO7]; | ||
| 151 | int cpos_mtable[NMOVES][FACTORIAL6]; | ||
| 152 | |||
| 153 | |||
| 154 | /* Local functions implementation ********************************************/ | ||
| 155 | |||
| 156 | static Cube | ||
| 157 | apply_move_cubearray(Move m, Cube cube, PieceFilter f) | ||
| 158 | { | ||
| 159 | /*init_moves();*/ | ||
| 160 | |||
| 161 | CubeArray m_arr = { | ||
| 162 | edge_cycle[m], | ||
| 163 | eofb_flipped[m], | ||
| 164 | eorl_flipped[m], | ||
| 165 | eoud_flipped[m], | ||
| 166 | corner_cycle[m], | ||
| 167 | coud_flipped[m], | ||
| 168 | corl_flipped[m], | ||
| 169 | cofb_flipped[m], | ||
| 170 | center_cycle[m] | ||
| 171 | }; | ||
| 172 | |||
| 173 | return move_via_arrays(&m_arr, cube, f); | ||
| 174 | } | ||
| 79 | 175 | ||
| 80 | /* Public functions **********************************************************/ | 176 | /* Public functions **********************************************************/ |
| 81 | 177 | ||
| 82 | void | 178 | Cube |
| 83 | apply_alg(Alg *alg, Cube *cube) | 179 | apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) |
| 84 | { | 180 | { |
| 85 | Cube aux; | 181 | Cube ret = {0}; |
| 86 | int i; | 182 | int i; |
| 87 | 183 | ||
| 88 | copy_cube(cube, &aux); | ||
| 89 | make_solved(cube); | ||
| 90 | |||
| 91 | for (i = 0; i < alg->len; i++) | 184 | for (i = 0; i < alg->len; i++) |
| 92 | if (alg->inv[i]) | 185 | if (alg->inv[i]) |
| 93 | apply_move(alg->move[i], cube); | 186 | ret = a ? apply_move(alg->move[i], ret) : |
| 187 | apply_move_cubearray(alg->move[i], ret, f); | ||
| 94 | 188 | ||
| 95 | invert_cube(cube); | 189 | ret = compose_filtered(c, inverse_cube(ret), f); |
| 96 | compose(&aux, cube); | ||
| 97 | 190 | ||
| 98 | for (i = 0; i < alg->len; i++) | 191 | for (i = 0; i < alg->len; i++) |
| 99 | if (!alg->inv[i]) | 192 | if (!alg->inv[i]) |
| 100 | apply_move(alg->move[i], cube); | 193 | ret = a ? apply_move(alg->move[i], ret) : |
| 101 | } | 194 | apply_move_cubearray(alg->move[i], ret, f); |
| 102 | 195 | ||
| 103 | void | 196 | return ret; |
| 104 | apply_move(Move m, Cube *cube) | ||
| 105 | { | ||
| 106 | compose(&move_array[m], cube); | ||
| 107 | } | 197 | } |
| 108 | 198 | ||
| 109 | void | 199 | Cube |
| 110 | apply_move_centers(Move m, Cube *cube) | 200 | apply_alg(Alg *alg, Cube cube) |
| 111 | { | 201 | { |
| 112 | compose_centers(&move_array[m], cube); | 202 | return apply_alg_generic(alg, cube, pf_all, true); |
| 113 | } | 203 | } |
| 114 | 204 | ||
| 115 | void | 205 | Cube |
| 116 | apply_move_corners(Move m, Cube *cube) | 206 | apply_move(Move m, Cube cube) |
| 117 | { | 207 | { |
| 118 | compose_corners(&move_array[m], cube); | 208 | /*init_moves();*/ |
| 119 | } | ||
| 120 | 209 | ||
| 121 | void | 210 | return (Cube) { |
| 122 | apply_move_edges(Move m, Cube *cube) | 211 | .epose = epose_mtable[m][cube.epose], |
| 123 | { | 212 | .eposs = eposs_mtable[m][cube.eposs], |
| 124 | compose_edges(&move_array[m], cube); | 213 | .eposm = eposm_mtable[m][cube.eposm], |
| 214 | .eofb = eofb_mtable[m][cube.eofb], | ||
| 215 | .eorl = eorl_mtable[m][cube.eorl], | ||
| 216 | .eoud = eoud_mtable[m][cube.eoud], | ||
| 217 | .coud = coud_mtable[m][cube.coud], | ||
| 218 | .cofb = cofb_mtable[m][cube.cofb], | ||
| 219 | .corl = corl_mtable[m][cube.corl], | ||
| 220 | .cp = cp_mtable[m][cube.cp], | ||
| 221 | .cpos = cpos_mtable[m][cube.cpos] | ||
| 222 | }; | ||
| 125 | } | 223 | } |
| 126 | 224 | ||
| 127 | Alg * | 225 | Alg * |
| @@ -181,27 +279,31 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv) | |||
| 181 | { | 279 | { |
| 182 | int i, j; | 280 | int i, j; |
| 183 | Cube c, d; | 281 | Cube c, d; |
| 184 | Move m; | 282 | Move m, mm; |
| 185 | Alg *equiv_alg; | 283 | Alg *equiv_alg; |
| 186 | 284 | ||
| 187 | make_solved(&c); | 285 | c = (Cube){0}; |
| 188 | for (i = 0; i < alg->len; i++) { | 286 | for (i = 0; i < alg->len; i++) { |
| 189 | if (alg->inv[i] != inv) | 287 | if (alg->inv[i] != inv) |
| 190 | continue; | 288 | continue; |
| 191 | 289 | ||
| 192 | equiv_alg = new_alg(equiv_alg_string[alg->move[i]]); | 290 | equiv_alg = new_alg(equiv_alg_string[alg->move[i]]); |
| 193 | 291 | ||
| 194 | for (j = 0; j < equiv_alg->len; j++) | 292 | for (j = 0; j < equiv_alg->len; j++) { |
| 195 | if (equiv_alg->move[j] == U) | 293 | m = equiv_alg->move[j]; |
| 196 | append_move(ret, 3 * c.xp[U_center] + 1, inv); | 294 | if (m == U) { |
| 197 | else | 295 | mm = 3*what_center_at(c, U_center) + 1; |
| 198 | apply_move(equiv_alg->move[j], &c); | 296 | append_move(ret, mm, inv); |
| 297 | } else { | ||
| 298 | c = apply_move(m, c); | ||
| 299 | } | ||
| 300 | } | ||
| 199 | 301 | ||
| 200 | free_alg(equiv_alg); | 302 | free_alg(equiv_alg); |
| 201 | } | 303 | } |
| 202 | 304 | ||
| 203 | m = NULLMOVE; | 305 | m = NULLMOVE; |
| 204 | switch (c.xp[F_center]) { | 306 | switch (what_center_at(c, F_center)) { |
| 205 | case U_center: | 307 | case U_center: |
| 206 | m = x3; | 308 | m = x3; |
| 207 | break; | 309 | break; |
| @@ -215,7 +317,7 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv) | |||
| 215 | m = y3; | 317 | m = y3; |
| 216 | break; | 318 | break; |
| 217 | case B_center: | 319 | case B_center: |
| 218 | if (c.xp[U_center] == U_center) | 320 | if (what_center_at(c, U_center) == U_center) |
| 219 | m = y2; | 321 | m = y2; |
| 220 | else | 322 | else |
| 221 | m = x2; | 323 | m = x2; |
| @@ -223,24 +325,120 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv) | |||
| 223 | default: | 325 | default: |
| 224 | break; | 326 | break; |
| 225 | } | 327 | } |
| 226 | 328 | d = apply_move(m, (Cube){0}); | |
| 227 | make_solved(&d); | ||
| 228 | apply_move(m, &d); | ||
| 229 | if (m != NULLMOVE) | 329 | if (m != NULLMOVE) |
| 230 | append_move(ret, m, inv); | 330 | append_move(ret, m, inv); |
| 231 | 331 | ||
| 232 | m = NULLMOVE; | 332 | m = NULLMOVE; |
| 233 | if (c.xp[U_center] == d.xp[D_center]) { | 333 | if (what_center_at(c, U_center) == what_center_at(d, D_center)) { |
| 234 | m = z2; | 334 | m = z2; |
| 235 | } else if (c.xp[U_center] == d.xp[R_center]) { | 335 | } else if (what_center_at(c, U_center) == what_center_at(d, R_center)) { |
| 236 | m = z3; | 336 | m = z3; |
| 237 | } else if (c.xp[U_center] == d.xp[L_center]) { | 337 | } else if (what_center_at(c, U_center) == what_center_at(d, L_center)) { |
| 238 | m = z; | 338 | m = z; |
| 239 | } | 339 | } |
| 240 | if (m != NULLMOVE) | 340 | if (m != NULLMOVE) |
| 241 | append_move(ret, m, inv); | 341 | append_move(ret, m, inv); |
| 242 | } | 342 | } |
| 243 | 343 | ||
| 344 | static bool | ||
| 345 | read_mtables_file() | ||
| 346 | { | ||
| 347 | init_env(); | ||
| 348 | |||
| 349 | FILE *f; | ||
| 350 | char fname[strlen(tabledir)+20]; | ||
| 351 | int m, b = sizeof(int); | ||
| 352 | bool r = true; | ||
| 353 | |||
| 354 | /* Table sizes, used for reading and writing files */ | ||
| 355 | uint64_t me[11] = { | ||
| 356 | [0] = FACTORIAL12/FACTORIAL8, | ||
| 357 | [1] = FACTORIAL12/FACTORIAL8, | ||
| 358 | [2] = FACTORIAL12/FACTORIAL8, | ||
| 359 | [3] = POW2TO11, | ||
| 360 | [4] = POW2TO11, | ||
| 361 | [5] = POW2TO11, | ||
| 362 | [6] = FACTORIAL8, | ||
| 363 | [7] = POW3TO7, | ||
| 364 | [8] = POW3TO7, | ||
| 365 | [9] = POW3TO7, | ||
| 366 | [10] = FACTORIAL6 | ||
| 367 | }; | ||
| 368 | |||
| 369 | strcpy(fname, tabledir); | ||
| 370 | strcat(fname, "/mtables"); | ||
| 371 | |||
| 372 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 373 | return false; | ||
| 374 | |||
| 375 | for (m = 0; m < NMOVES; m++) { | ||
| 376 | r = r && fread(epose_mtable[m], b, me[0], f) == me[0]; | ||
| 377 | r = r && fread(eposs_mtable[m], b, me[1], f) == me[1]; | ||
| 378 | r = r && fread(eposm_mtable[m], b, me[2], f) == me[2]; | ||
| 379 | r = r && fread(eofb_mtable[m], b, me[3], f) == me[3]; | ||
| 380 | r = r && fread(eorl_mtable[m], b, me[4], f) == me[4]; | ||
| 381 | r = r && fread(eoud_mtable[m], b, me[5], f) == me[5]; | ||
| 382 | r = r && fread(cp_mtable[m], b, me[6], f) == me[6]; | ||
| 383 | r = r && fread(coud_mtable[m], b, me[7], f) == me[7]; | ||
| 384 | r = r && fread(corl_mtable[m], b, me[8], f) == me[8]; | ||
| 385 | r = r && fread(cofb_mtable[m], b, me[9], f) == me[9]; | ||
| 386 | r = r && fread(cpos_mtable[m], b, me[10], f) == me[10]; | ||
| 387 | } | ||
| 388 | |||
| 389 | fclose(f); | ||
| 390 | return r; | ||
| 391 | } | ||
| 392 | |||
| 393 | static bool | ||
| 394 | write_mtables_file() | ||
| 395 | { | ||
| 396 | init_env(); | ||
| 397 | |||
| 398 | FILE *f; | ||
| 399 | char fname[strlen(tabledir)+20]; | ||
| 400 | int m, b = sizeof(int); | ||
| 401 | bool r = true; | ||
| 402 | |||
| 403 | /* Table sizes, used for reading and writing files */ | ||
| 404 | uint64_t me[11] = { | ||
| 405 | [0] = FACTORIAL12/FACTORIAL8, | ||
| 406 | [1] = FACTORIAL12/FACTORIAL8, | ||
| 407 | [2] = FACTORIAL12/FACTORIAL8, | ||
| 408 | [3] = POW2TO11, | ||
| 409 | [4] = POW2TO11, | ||
| 410 | [5] = POW2TO11, | ||
| 411 | [6] = FACTORIAL8, | ||
| 412 | [7] = POW3TO7, | ||
| 413 | [8] = POW3TO7, | ||
| 414 | [9] = POW3TO7, | ||
| 415 | [10] = FACTORIAL6 | ||
| 416 | }; | ||
| 417 | |||
| 418 | strcpy(fname, tabledir); | ||
| 419 | strcat(fname, "/mtables"); | ||
| 420 | |||
| 421 | if ((f = fopen(fname, "wb")) == NULL) | ||
| 422 | return false; | ||
| 423 | |||
| 424 | for (m = 0; m < NMOVES; m++) { | ||
| 425 | r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0]; | ||
| 426 | r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1]; | ||
| 427 | r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2]; | ||
| 428 | r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3]; | ||
| 429 | r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4]; | ||
| 430 | r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5]; | ||
| 431 | r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6]; | ||
| 432 | r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7]; | ||
| 433 | r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8]; | ||
| 434 | r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9]; | ||
| 435 | r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10]; | ||
| 436 | } | ||
| 437 | |||
| 438 | fclose(f); | ||
| 439 | return r; | ||
| 440 | } | ||
| 441 | |||
| 244 | void | 442 | void |
| 245 | init_moves() { | 443 | init_moves() { |
| 246 | static bool initialized = false; | 444 | static bool initialized = false; |
| @@ -248,54 +446,101 @@ init_moves() { | |||
| 248 | return; | 446 | return; |
| 249 | initialized = true; | 447 | initialized = true; |
| 250 | 448 | ||
| 449 | Cube c; | ||
| 450 | CubeArray arrs; | ||
| 451 | int i; | ||
| 452 | unsigned int ui; | ||
| 251 | Move m; | 453 | Move m; |
| 252 | Alg *equiv_alg[NMOVES]; | 454 | Alg *equiv_alg[NMOVES]; |
| 253 | 455 | ||
| 254 | static const Cube mcu = { | 456 | init_cube(); |
| 255 | .ep = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR }, | 457 | |
| 256 | .cp = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR }, | 458 | for (i = 0; i < NMOVES; i++) |
| 257 | }; | 459 | equiv_alg[i] = new_alg(equiv_alg_string[i]); |
| 258 | static const Cube mcx = { | ||
| 259 | .ep = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR }, | ||
| 260 | .eo = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, | ||
| 261 | .cp = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR }, | ||
| 262 | .co = { [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2, | ||
| 263 | [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2 }, | ||
| 264 | .xp = { F_center, B_center, R_center, | ||
| 265 | L_center, D_center, U_center }, | ||
| 266 | }; | ||
| 267 | static const Cube mcy = { | ||
| 268 | .ep = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL }, | ||
| 269 | .eo = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }, | ||
| 270 | .cp = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL }, | ||
| 271 | .xp = { U_center, D_center, B_center, | ||
| 272 | F_center, R_center, L_center }, | ||
| 273 | }; | ||
| 274 | 460 | ||
| 275 | move_array[U] = mcu; | 461 | /* Generate all move cycles and flips; I do this regardless */ |
| 276 | move_array[x] = mcx; | 462 | for (i = 0; i < NMOVES; i++) { |
| 277 | move_array[y] = mcy; | 463 | if (i == U || i == x || i == y) |
| 464 | continue; | ||
| 465 | |||
| 466 | c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false); | ||
| 467 | |||
| 468 | arrs = (CubeArray) { | ||
| 469 | edge_cycle[i], | ||
| 470 | eofb_flipped[i], | ||
| 471 | eorl_flipped[i], | ||
| 472 | eoud_flipped[i], | ||
| 473 | corner_cycle[i], | ||
| 474 | coud_flipped[i], | ||
| 475 | corl_flipped[i], | ||
| 476 | cofb_flipped[i], | ||
| 477 | center_cycle[i] | ||
| 478 | }; | ||
| 479 | cube_to_arrays(c, &arrs, pf_all); | ||
| 480 | } | ||
| 481 | |||
| 482 | if (read_mtables_file()) | ||
| 483 | return; | ||
| 278 | 484 | ||
| 279 | for (m = 0; m < NMOVES; m++) | 485 | fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); |
| 280 | equiv_alg[m] = new_alg(equiv_alg_string[m]); | ||
| 281 | 486 | ||
| 487 | /* Initialize transition tables */ | ||
| 282 | for (m = 0; m < NMOVES; m++) { | 488 | for (m = 0; m < NMOVES; m++) { |
| 283 | switch (m) { | 489 | for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { |
| 284 | case NULLMOVE: | 490 | c = (Cube){ .epose = ui }; |
| 285 | make_solved(&move_array[m]); | 491 | c = apply_move_cubearray(m, c, pf_e); |
| 286 | break; | 492 | epose_mtable[m][ui] = c.epose; |
| 287 | case U: | 493 | |
| 288 | case x: | 494 | c = (Cube){ .eposs = ui }; |
| 289 | case y: | 495 | c = apply_move_cubearray(m, c, pf_s); |
| 290 | break; | 496 | eposs_mtable[m][ui] = c.eposs; |
| 291 | default: | 497 | |
| 292 | make_solved(&move_array[m]); | 498 | c = (Cube){ .eposm = ui }; |
| 293 | apply_alg(equiv_alg[m], &move_array[m]); | 499 | c = apply_move_cubearray(m, c, pf_m); |
| 294 | break; | 500 | eposm_mtable[m][ui] = c.eposm; |
| 501 | } | ||
| 502 | for (ui = 0; ui < POW2TO11; ui++ ) { | ||
| 503 | c = (Cube){ .eofb = ui }; | ||
| 504 | c = apply_move_cubearray(m, c, pf_eo); | ||
| 505 | eofb_mtable[m][ui] = c.eofb; | ||
| 506 | |||
| 507 | c = (Cube){ .eorl = ui }; | ||
| 508 | c = apply_move_cubearray(m, c, pf_eo); | ||
| 509 | eorl_mtable[m][ui] = c.eorl; | ||
| 510 | |||
| 511 | c = (Cube){ .eoud = ui }; | ||
| 512 | c = apply_move_cubearray(m, c, pf_eo); | ||
| 513 | eoud_mtable[m][ui] = c.eoud; | ||
| 514 | } | ||
| 515 | for (ui = 0; ui < POW3TO7; ui++) { | ||
| 516 | c = (Cube){ .coud = ui }; | ||
| 517 | c = apply_move_cubearray(m, c, pf_co); | ||
| 518 | coud_mtable[m][ui] = c.coud; | ||
| 519 | |||
| 520 | c = (Cube){ .corl = ui }; | ||
| 521 | c = apply_move_cubearray(m, c, pf_co); | ||
| 522 | corl_mtable[m][ui] = c.corl; | ||
| 523 | |||
| 524 | c = (Cube){ .cofb = ui }; | ||
| 525 | c = apply_move_cubearray(m, c, pf_co); | ||
| 526 | cofb_mtable[m][ui] = c.cofb; | ||
| 527 | } | ||
| 528 | for (ui = 0; ui < FACTORIAL8; ui++) { | ||
| 529 | c = (Cube){ .cp = ui }; | ||
| 530 | c = apply_move_cubearray(m, c, pf_cp); | ||
| 531 | cp_mtable[m][ui] = c.cp; | ||
| 532 | } | ||
| 533 | for (ui = 0; ui < FACTORIAL6; ui++) { | ||
| 534 | c = (Cube){ .cpos = ui }; | ||
| 535 | c = apply_move_cubearray(m, c, pf_cpos); | ||
| 536 | cpos_mtable[m][ui] = c.cpos; | ||
| 295 | } | 537 | } |
| 296 | } | 538 | } |
| 297 | 539 | ||
| 298 | for (m = 0; m < NMOVES; m++) | 540 | if (!write_mtables_file()) |
| 299 | free_alg(equiv_alg[m]); | 541 | fprintf(stderr, "Error writing mtables\n"); |
| 542 | |||
| 543 | for (i = 0; i < NMOVES; i++) | ||
| 544 | free_alg(equiv_alg[i]); | ||
| 300 | } | 545 | } |
| 301 | 546 | ||
diff --git a/src/moves.h b/src/moves.h index 4e8be7f..14ae087 100644 --- a/src/moves.h +++ b/src/moves.h | |||
| @@ -5,11 +5,24 @@ | |||
| 5 | #include "cube.h" | 5 | #include "cube.h" |
| 6 | #include "env.h" | 6 | #include "env.h" |
| 7 | 7 | ||
| 8 | void apply_alg(Alg *alg, Cube *cube); | 8 | /* |
| 9 | void apply_move(Move m, Cube *cube); | 9 | * Tables are exposed to allow for faster moves in some cases. |
| 10 | void apply_move_centers(Move m, Cube *cube); | 10 | */ |
| 11 | void apply_move_corners(Move m, Cube *cube); | 11 | extern int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; |
| 12 | void apply_move_edges(Move m, Cube *cube); | 12 | extern int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; |
| 13 | extern int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; | ||
| 14 | extern int eofb_mtable[NMOVES][POW2TO11]; | ||
| 15 | extern int eorl_mtable[NMOVES][POW2TO11]; | ||
| 16 | extern int eoud_mtable[NMOVES][POW2TO11]; | ||
| 17 | extern int cp_mtable[NMOVES][FACTORIAL8]; | ||
| 18 | extern int coud_mtable[NMOVES][POW3TO7]; | ||
| 19 | extern int cofb_mtable[NMOVES][POW3TO7]; | ||
| 20 | extern int corl_mtable[NMOVES][POW3TO7]; | ||
| 21 | extern int cpos_mtable[NMOVES][FACTORIAL6]; | ||
| 22 | |||
| 23 | Cube apply_alg(Alg *alg, Cube cube); | ||
| 24 | Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); | ||
| 25 | Cube apply_move(Move m, Cube cube); | ||
| 13 | Alg * cleanup(Alg *alg); | 26 | Alg * cleanup(Alg *alg); |
| 14 | 27 | ||
| 15 | void init_moves(); | 28 | void init_moves(); |
diff --git a/src/movesets.c b/src/movesets.c deleted file mode 100644 index d8f5bc1..0000000 --- a/src/movesets.c +++ /dev/null | |||
| @@ -1,194 +0,0 @@ | |||
| 1 | #define MOVESETS_C | ||
| 2 | |||
| 3 | #include "movesets.h" | ||
| 4 | |||
| 5 | static bool allowed_HTM(Move m); | ||
| 6 | static bool allowed_URF(Move m); | ||
| 7 | static bool allowed_eofb(Move m); | ||
| 8 | static bool allowed_drud(Move m); | ||
| 9 | static bool allowed_htr(Move m); | ||
| 10 | static bool can_append_HTM(Move l2, Move l1, Move m); | ||
| 11 | static bool can_append_HTM_cached(Alg *alg, Move m, bool inverse); | ||
| 12 | static bool cancel_niss_HTM_cached(Alg *alg); | ||
| 13 | static void init_can_append_HTM(); | ||
| 14 | |||
| 15 | Moveset | ||
| 16 | moveset_HTM = { | ||
| 17 | .name = "HTM", | ||
| 18 | .allowed = allowed_HTM, | ||
| 19 | .can_append = can_append_HTM_cached, | ||
| 20 | .cancel_niss = cancel_niss_HTM_cached, | ||
| 21 | }; | ||
| 22 | |||
| 23 | Moveset | ||
| 24 | moveset_URF = { | ||
| 25 | .name = "URF", | ||
| 26 | .allowed = allowed_URF, | ||
| 27 | .can_append = can_append_HTM_cached, | ||
| 28 | .cancel_niss = cancel_niss_HTM_cached, | ||
| 29 | }; | ||
| 30 | |||
| 31 | Moveset | ||
| 32 | moveset_eofb = { | ||
| 33 | .name = "eofb", | ||
| 34 | .allowed = allowed_eofb, | ||
| 35 | .can_append = can_append_HTM_cached, | ||
| 36 | .cancel_niss = cancel_niss_HTM_cached, | ||
| 37 | }; | ||
| 38 | |||
| 39 | Moveset | ||
| 40 | moveset_drud = { | ||
| 41 | .name = "drud", | ||
| 42 | .allowed = allowed_drud, | ||
| 43 | .can_append = can_append_HTM_cached, | ||
| 44 | .cancel_niss = cancel_niss_HTM_cached, | ||
| 45 | }; | ||
| 46 | |||
| 47 | Moveset | ||
| 48 | moveset_htr = { | ||
| 49 | .name = "htr", | ||
| 50 | .allowed = allowed_htr, | ||
| 51 | .can_append = can_append_HTM_cached, | ||
| 52 | .cancel_niss = cancel_niss_HTM_cached, | ||
| 53 | }; | ||
| 54 | |||
| 55 | Moveset * | ||
| 56 | all_movesets[] = { | ||
| 57 | &moveset_HTM, | ||
| 58 | &moveset_URF, | ||
| 59 | &moveset_eofb, | ||
| 60 | &moveset_drud, | ||
| 61 | &moveset_htr, | ||
| 62 | NULL | ||
| 63 | }; | ||
| 64 | |||
| 65 | static uint64_t can_append_HTM_mask[NMOVES][NMOVES]; | ||
| 66 | |||
| 67 | static bool | ||
| 68 | allowed_HTM(Move m) | ||
| 69 | { | ||
| 70 | return m >= U && m <= B3; | ||
| 71 | } | ||
| 72 | |||
| 73 | static bool | ||
| 74 | allowed_URF(Move m) | ||
| 75 | { | ||
| 76 | Move b = base_move(m); | ||
| 77 | |||
| 78 | return b == U || b == R || b == F; | ||
| 79 | } | ||
| 80 | |||
| 81 | static bool | ||
| 82 | allowed_eofb(Move m) | ||
| 83 | { | ||
| 84 | Move b = base_move(m); | ||
| 85 | |||
| 86 | return b == U || b == D || b == R || b == L || | ||
| 87 | ((b == F || b == B) && m == b+1); | ||
| 88 | } | ||
| 89 | |||
| 90 | static bool | ||
| 91 | allowed_drud(Move m) | ||
| 92 | { | ||
| 93 | Move b = base_move(m); | ||
| 94 | |||
| 95 | return b == U || b == D || | ||
| 96 | ((b == R || b == L || b == F || b == B) && m == b + 1); | ||
| 97 | } | ||
| 98 | |||
| 99 | static bool | ||
| 100 | allowed_htr(Move m) | ||
| 101 | { | ||
| 102 | Move b = base_move(m); | ||
| 103 | |||
| 104 | return moveset_HTM.allowed(m) && m == b + 1; | ||
| 105 | } | ||
| 106 | |||
| 107 | static bool | ||
| 108 | can_append_HTM(Move l2, Move l1, Move m) | ||
| 109 | { | ||
| 110 | bool cancel, cancel_last, cancel_swap; | ||
| 111 | |||
| 112 | cancel_last = l1 != NULLMOVE && base_move(l1) == base_move(m); | ||
| 113 | cancel_swap = l2 != NULLMOVE && base_move(l2) == base_move(m); | ||
| 114 | cancel = cancel_last || (commute(l1, l2) && cancel_swap); | ||
| 115 | |||
| 116 | return !cancel; | ||
| 117 | } | ||
| 118 | |||
| 119 | static bool | ||
| 120 | can_append_HTM_cached(Alg *alg, Move m, bool inverse) | ||
| 121 | { | ||
| 122 | Move *moves, l1, l2; | ||
| 123 | uint64_t mbit; | ||
| 124 | int n; | ||
| 125 | |||
| 126 | if (inverse) { | ||
| 127 | moves = alg->move_inverse; | ||
| 128 | n = alg->len_inverse; | ||
| 129 | } else { | ||
| 130 | moves = alg->move_normal; | ||
| 131 | n = alg->len_normal; | ||
| 132 | } | ||
| 133 | |||
| 134 | l1 = n > 0 ? moves[n-1] : NULLMOVE; | ||
| 135 | l2 = n > 1 ? moves[n-2] : NULLMOVE; | ||
| 136 | |||
| 137 | mbit = ((uint64_t)1) << m; | ||
| 138 | |||
| 139 | return can_append_HTM_mask[l2][l1] & mbit; | ||
| 140 | } | ||
| 141 | |||
| 142 | static bool | ||
| 143 | cancel_niss_HTM_cached(Alg *alg) | ||
| 144 | { | ||
| 145 | Move i1, i2; | ||
| 146 | int n; | ||
| 147 | bool can_first, can_swap; | ||
| 148 | |||
| 149 | n = alg->len_inverse; | ||
| 150 | i1 = n > 0 ? alg->move_inverse[n-1] : NULLMOVE; | ||
| 151 | i2 = n > 1 ? alg->move_inverse[n-2] : NULLMOVE; | ||
| 152 | |||
| 153 | can_first = can_append_HTM_cached(alg, inverse_move(i1), false); | ||
| 154 | can_swap = can_append_HTM_cached(alg, inverse_move(i2), false); | ||
| 155 | |||
| 156 | return can_first && (!commute(i1, i2) || can_swap); | ||
| 157 | } | ||
| 158 | |||
| 159 | static void | ||
| 160 | init_can_append_HTM() | ||
| 161 | { | ||
| 162 | Move l2, l1, m; | ||
| 163 | |||
| 164 | for (l1 = 0; l1 < NMOVES; l1++) | ||
| 165 | for (l2 = 0; l2 < NMOVES; l2++) | ||
| 166 | for (m = 0; m < NMOVES; m++) | ||
| 167 | if (can_append_HTM(l2, l1, m)) | ||
| 168 | can_append_HTM_mask[l2][l1] | ||
| 169 | |= (((uint64_t)1) << m); | ||
| 170 | } | ||
| 171 | |||
| 172 | void | ||
| 173 | init_moveset(Moveset *ms) | ||
| 174 | { | ||
| 175 | int j; | ||
| 176 | Move m; | ||
| 177 | |||
| 178 | for (j = 0, m = U; m < NMOVES; m++) | ||
| 179 | if (ms->allowed(m)) | ||
| 180 | ms->sorted_moves[j++] = m; | ||
| 181 | ms->sorted_moves[j] = NULLMOVE; | ||
| 182 | |||
| 183 | /* TODO: should be here? maybe just init all movesets together anyway... */ | ||
| 184 | init_can_append_HTM(); | ||
| 185 | } | ||
| 186 | |||
| 187 | void | ||
| 188 | init_movesets() | ||
| 189 | { | ||
| 190 | int i; | ||
| 191 | |||
| 192 | for (i = 0; all_movesets[i] != NULL; i++) | ||
| 193 | init_moveset(all_movesets[i]); | ||
| 194 | } | ||
diff --git a/src/movesets.h b/src/movesets.h deleted file mode 100644 index a02d171..0000000 --- a/src/movesets.h +++ /dev/null | |||
| @@ -1,15 +0,0 @@ | |||
| 1 | #ifndef MOVESETS_H | ||
| 2 | #define MOVESETS_H | ||
| 3 | |||
| 4 | #include "alg.h" | ||
| 5 | |||
| 6 | void init_moveset(Moveset *); | ||
| 7 | void init_movesets(); | ||
| 8 | |||
| 9 | extern Moveset moveset_HTM; | ||
| 10 | extern Moveset moveset_URF; | ||
| 11 | extern Moveset moveset_eofb; | ||
| 12 | extern Moveset moveset_drud; | ||
| 13 | extern Moveset moveset_htr; | ||
| 14 | |||
| 15 | #endif | ||
diff --git a/src/pf.c b/src/pf.c new file mode 100644 index 0000000..7d86e4e --- /dev/null +++ b/src/pf.c | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | #include "pf.h" | ||
| 2 | |||
| 3 | PieceFilter | ||
| 4 | pf_all = { | ||
| 5 | .epose = true, | ||
| 6 | .eposs = true, | ||
| 7 | .eposm = true, | ||
| 8 | .eofb = true, | ||
| 9 | .eorl = true, | ||
| 10 | .eoud = true, | ||
| 11 | .cp = true, | ||
| 12 | .cofb = true, | ||
| 13 | .corl = true, | ||
| 14 | .coud = true, | ||
| 15 | .cpos = true | ||
| 16 | }; | ||
| 17 | |||
| 18 | PieceFilter | ||
| 19 | pf_4val = { | ||
| 20 | .epose = true, | ||
| 21 | .eposs = true, | ||
| 22 | .eposm = true, | ||
| 23 | .eofb = true, | ||
| 24 | .coud = true, | ||
| 25 | .cp = true | ||
| 26 | }; | ||
| 27 | |||
| 28 | PieceFilter | ||
| 29 | pf_epcp = { | ||
| 30 | .epose = true, | ||
| 31 | .eposs = true, | ||
| 32 | .eposm = true, | ||
| 33 | .cp = true | ||
| 34 | }; | ||
| 35 | |||
| 36 | PieceFilter | ||
| 37 | pf_cpos = { | ||
| 38 | .cpos = true | ||
| 39 | }; | ||
| 40 | |||
| 41 | PieceFilter | ||
| 42 | pf_cp = { | ||
| 43 | .cp = true | ||
| 44 | }; | ||
| 45 | |||
| 46 | PieceFilter | ||
| 47 | pf_ep = { | ||
| 48 | .epose = true, | ||
| 49 | .eposs = true, | ||
| 50 | .eposm = true | ||
| 51 | }; | ||
| 52 | |||
| 53 | PieceFilter | ||
| 54 | pf_e = { | ||
| 55 | .epose = true | ||
| 56 | }; | ||
| 57 | |||
| 58 | PieceFilter | ||
| 59 | pf_s = { | ||
| 60 | .eposs = true | ||
| 61 | }; | ||
| 62 | |||
| 63 | PieceFilter | ||
| 64 | pf_m = { | ||
| 65 | .eposm = true | ||
| 66 | }; | ||
| 67 | |||
| 68 | PieceFilter | ||
| 69 | pf_eo = { | ||
| 70 | .eofb = true, | ||
| 71 | .eorl = true, | ||
| 72 | .eoud = true | ||
| 73 | }; | ||
| 74 | |||
| 75 | PieceFilter | ||
| 76 | pf_co = { | ||
| 77 | .cofb = true, | ||
| 78 | .corl = true, | ||
| 79 | .coud = true | ||
| 80 | }; | ||
| 81 | |||
| 82 | PieceFilter | ||
| 83 | pf_coud = { | ||
| 84 | .coud = true | ||
| 85 | }; | ||
| 86 | |||
| 87 | PieceFilter | ||
| 88 | pf_edges = { | ||
| 89 | .epose = true, | ||
| 90 | .eposs = true, | ||
| 91 | .eposm = true, | ||
| 92 | .eofb = true, | ||
| 93 | .eorl = true, | ||
| 94 | .eoud = true | ||
| 95 | }; | ||
diff --git a/src/pf.h b/src/pf.h new file mode 100644 index 0000000..0b552dc --- /dev/null +++ b/src/pf.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #ifndef PF_H | ||
| 2 | #define PF_H | ||
| 3 | |||
| 4 | #include "cubetypes.h" | ||
| 5 | |||
| 6 | extern PieceFilter pf_all; | ||
| 7 | extern PieceFilter pf_4val; | ||
| 8 | extern PieceFilter pf_epcp; | ||
| 9 | extern PieceFilter pf_cpos; | ||
| 10 | extern PieceFilter pf_cp; | ||
| 11 | extern PieceFilter pf_ep; | ||
| 12 | extern PieceFilter pf_e; | ||
| 13 | extern PieceFilter pf_s; | ||
| 14 | extern PieceFilter pf_m; | ||
| 15 | extern PieceFilter pf_eo; | ||
| 16 | extern PieceFilter pf_co; | ||
| 17 | extern PieceFilter pf_coud; | ||
| 18 | extern PieceFilter pf_edges; | ||
| 19 | |||
| 20 | #endif | ||
diff --git a/src/pruning.c b/src/pruning.c index 3cc9152..1dba949 100644 --- a/src/pruning.c +++ b/src/pruning.c | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | #define PRUNING_C | ||
| 2 | |||
| 3 | #include "pruning.h" | 1 | #include "pruning.h" |
| 4 | 2 | ||
| 5 | #define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) | 3 | #define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) |
| @@ -7,14 +5,106 @@ | |||
| 7 | 5 | ||
| 8 | static int findchunk(PruneData *pd, int nchunks, uint64_t i); | 6 | static int findchunk(PruneData *pd, int nchunks, uint64_t i); |
| 9 | static void genptable_bfs(PruneData *pd, int d, int nt, int nc); | 7 | static void genptable_bfs(PruneData *pd, int d, int nt, int nc); |
| 8 | static void genptable_compress(PruneData *pd); | ||
| 10 | static void genptable_fixnasty(PruneData *pd, int d, int nthreads); | 9 | static void genptable_fixnasty(PruneData *pd, int d, int nthreads); |
| 10 | static void genptable_setbase(PruneData *pd); | ||
| 11 | static void * instance_bfs(void *arg); | 11 | static void * instance_bfs(void *arg); |
| 12 | static void * instance_fixnasty(void *arg); | 12 | static void * instance_fixnasty(void *arg); |
| 13 | static void ptable_update(PruneData *pd, uint64_t ind, int m); | 13 | static void ptable_update(PruneData *pd, Cube cube, int m); |
| 14 | static void ptable_update_index(PruneData *pd, uint64_t ind, int m); | ||
| 15 | static int ptableval_index(PruneData *pd, uint64_t ind); | ||
| 14 | static bool read_ptable_file(PruneData *pd); | 16 | static bool read_ptable_file(PruneData *pd); |
| 15 | static bool write_ptable_file(PruneData *pd); | 17 | static bool write_ptable_file(PruneData *pd); |
| 16 | 18 | ||
| 17 | PruneData *active_pd[256]; | 19 | PruneData |
| 20 | pd_eofb_HTM = { | ||
| 21 | .filename = "pt_eofb_HTM", | ||
| 22 | .coord = &coord_eofb, | ||
| 23 | .moveset = &moveset_HTM, | ||
| 24 | }; | ||
| 25 | |||
| 26 | PruneData | ||
| 27 | pd_coud_HTM = { | ||
| 28 | .filename = "pt_coud_HTM", | ||
| 29 | .coord = &coord_coud, | ||
| 30 | .moveset = &moveset_HTM, | ||
| 31 | }; | ||
| 32 | |||
| 33 | PruneData | ||
| 34 | pd_cornershtr_HTM = { | ||
| 35 | .filename = "pt_cornershtr_HTM", | ||
| 36 | .coord = &coord_cornershtr, | ||
| 37 | .moveset = &moveset_HTM, | ||
| 38 | }; | ||
| 39 | |||
| 40 | PruneData | ||
| 41 | pd_corners_HTM = { | ||
| 42 | .filename = "pt_corners_HTM", | ||
| 43 | .coord = &coord_corners, | ||
| 44 | .moveset = &moveset_HTM, | ||
| 45 | }; | ||
| 46 | |||
| 47 | PruneData | ||
| 48 | pd_drud_sym16_HTM = { | ||
| 49 | .filename = "pt_drud_sym16_HTM", | ||
| 50 | .coord = &coord_drud_sym16, | ||
| 51 | .moveset = &moveset_HTM, | ||
| 52 | }; | ||
| 53 | |||
| 54 | PruneData | ||
| 55 | pd_drud_eofb = { | ||
| 56 | .filename = "pt_drud_eofb", | ||
| 57 | .coord = &coord_drud_eofb, | ||
| 58 | .moveset = &moveset_eofb, | ||
| 59 | }; | ||
| 60 | |||
| 61 | PruneData | ||
| 62 | pd_drudfin_noE_sym16_drud = { | ||
| 63 | .filename = "pt_drudfin_noE_sym16_drud", | ||
| 64 | .coord = &coord_drudfin_noE_sym16, | ||
| 65 | .moveset = &moveset_drud, | ||
| 66 | }; | ||
| 67 | |||
| 68 | PruneData | ||
| 69 | pd_htr_drud = { | ||
| 70 | .filename = "pt_htr_drud", | ||
| 71 | .coord = &coord_htr_drud, | ||
| 72 | .moveset = &moveset_drud, | ||
| 73 | }; | ||
| 74 | |||
| 75 | PruneData | ||
| 76 | pd_htrfin_htr = { | ||
| 77 | .filename = "pt_htrfin_htr", | ||
| 78 | .coord = &coord_htrfin, | ||
| 79 | .moveset = &moveset_htr, | ||
| 80 | }; | ||
| 81 | |||
| 82 | PruneData | ||
| 83 | pd_nxopt31_HTM = { | ||
| 84 | .filename = "pt_nxopt31_HTM", | ||
| 85 | .coord = &coord_nxopt31, | ||
| 86 | .moveset = &moveset_HTM, | ||
| 87 | |||
| 88 | .compact = true, | ||
| 89 | .fallback = &pd_drud_sym16_HTM, | ||
| 90 | .fbmod = BINOM8ON4, | ||
| 91 | }; | ||
| 92 | |||
| 93 | PruneData * all_pd[] = { | ||
| 94 | &pd_eofb_HTM, | ||
| 95 | &pd_coud_HTM, | ||
| 96 | &pd_cornershtr_HTM, | ||
| 97 | &pd_corners_HTM, | ||
| 98 | &pd_drud_sym16_HTM, | ||
| 99 | &pd_drud_eofb, | ||
| 100 | &pd_drudfin_noE_sym16_drud, | ||
| 101 | &pd_htr_drud, | ||
| 102 | &pd_htrfin_htr, | ||
| 103 | &pd_nxopt31_HTM, | ||
| 104 | NULL | ||
| 105 | }; | ||
| 106 | |||
| 107 | /* Functions *****************************************************************/ | ||
| 18 | 108 | ||
| 19 | int | 109 | int |
| 20 | findchunk(PruneData *pd, int nchunks, uint64_t i) | 110 | findchunk(PruneData *pd, int nchunks, uint64_t i) |
| @@ -27,47 +117,59 @@ findchunk(PruneData *pd, int nchunks, uint64_t i) | |||
| 27 | return MIN(nchunks-1, (int)(i / chunksize)); | 117 | return MIN(nchunks-1, (int)(i / chunksize)); |
| 28 | } | 118 | } |
| 29 | 119 | ||
| 30 | PruneData * | 120 | void |
| 31 | genptable(PruneData *pd, int nthreads) | 121 | free_pd(PruneData *pd) |
| 32 | { | 122 | { |
| 33 | int d, nchunks, i, maxv; | 123 | if (pd->generated) |
| 34 | uint64_t oldn; | 124 | free(pd->ptable); |
| 35 | 125 | ||
| 36 | for (i = 0; active_pd[i] != NULL; i++) { | 126 | pd->generated = false; |
| 37 | if (active_pd[i]->coord == pd->coord && | 127 | } |
| 38 | active_pd[i]->moveset == pd->moveset && | 128 | |
| 39 | active_pd[i]->compact == pd->compact) | 129 | void |
| 40 | return active_pd[i]; | 130 | genptable(PruneData *pd, int nthreads) |
| 41 | } | 131 | { |
| 132 | bool compact; | ||
| 133 | int d, nchunks; | ||
| 134 | uint64_t oldn, sz; | ||
| 42 | 135 | ||
| 43 | init_moveset(pd->moveset); | 136 | if (pd->generated) |
| 44 | gen_coord(pd->coord); | 137 | return; |
| 45 | 138 | ||
| 46 | pd->ptable = malloc(ptablesize(pd) * sizeof(entry_group_t)); | 139 | /* TODO: check if memory is enough, otherwise maybe exit gracefully? */ |
| 140 | sz = ptablesize(pd) * (pd->compact ? 2 : 1); | ||
| 141 | pd->ptable = malloc(sz * sizeof(entry_group_t)); | ||
| 47 | 142 | ||
| 48 | if (read_ptable_file(pd)) | 143 | if (read_ptable_file(pd)) { |
| 49 | goto genptable_done; | 144 | pd->generated = true; |
| 145 | return; | ||
| 146 | } | ||
| 50 | 147 | ||
| 51 | if (nthreads < 4) { | 148 | if (nthreads < 4) { |
| 52 | fprintf(stderr, | 149 | fprintf(stderr, |
| 53 | "--- Warning ---\n" | 150 | "--- Warning ---\n" |
| 54 | "You are using only %d threads to generate the pruning" | 151 | "You are using only %d threads to generate the pruning" |
| 55 | "tables. This can take a while.\n" | 152 | "tables. This can take a while." |
| 56 | "Unless you did this intentionally, you should re-run" | 153 | "Unless you did this intentionally, you should re-run" |
| 57 | "this command with `-t 4' or more.\n" | 154 | "this command with `-t 4' or more.\n" |
| 58 | "---------------\n\n", nthreads | 155 | "---------------\n\n", nthreads |
| 59 | ); | 156 | ); |
| 60 | } | 157 | } |
| 61 | 158 | ||
| 159 | |||
| 160 | /* For the first steps we proceed the same way for compact and not */ | ||
| 161 | compact = pd->compact; | ||
| 162 | pd->compact = false; | ||
| 163 | pd->generated = true; | ||
| 164 | |||
| 62 | nchunks = MIN(ptablesize(pd), 100000); | 165 | nchunks = MIN(ptablesize(pd), 100000); |
| 63 | fprintf(stderr, "Generating pt_%s_%s with %d threads\n", | 166 | fprintf(stderr, "Cannot load %s, generating it with %d threads\n", |
| 64 | pd->coord->name, pd->moveset->name, nthreads); | 167 | pd->filename, nthreads); |
| 168 | |||
| 65 | 169 | ||
| 66 | memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t)); | 170 | memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t)); |
| 67 | for (i = 0; i < 16; i++) | ||
| 68 | pd->count[i] = 0; | ||
| 69 | 171 | ||
| 70 | ptable_update(pd, 0, 0); | 172 | ptable_update(pd, (Cube){0}, 0); |
| 71 | pd->n = 1; | 173 | pd->n = 1; |
| 72 | oldn = 0; | 174 | oldn = 0; |
| 73 | genptable_fixnasty(pd, 0, nthreads); | 175 | genptable_fixnasty(pd, 0, nthreads); |
| @@ -76,9 +178,7 @@ genptable(PruneData *pd, int nthreads) | |||
| 76 | 0, pd->n - oldn, pd->n, pd->coord->max); | 178 | 0, pd->n - oldn, pd->n, pd->coord->max); |
| 77 | oldn = pd->n; | 179 | oldn = pd->n; |
| 78 | pd->count[0] = pd->n; | 180 | pd->count[0] = pd->n; |
| 79 | 181 | for (d = 0; d < 15 && pd->n < pd->coord->max; d++) { | |
| 80 | maxv = pd->compact ? MIN(15, pd->base + 4) : 15; | ||
| 81 | for (d = 0; d < maxv && pd->n < pd->coord->max; d++) { | ||
| 82 | genptable_bfs(pd, d, nthreads, nchunks); | 182 | genptable_bfs(pd, d, nthreads, nchunks); |
| 83 | genptable_fixnasty(pd, d+1, nthreads); | 183 | genptable_fixnasty(pd, d+1, nthreads); |
| 84 | fprintf(stderr, "Depth %d done, generated %" | 184 | fprintf(stderr, "Depth %d done, generated %" |
| @@ -87,17 +187,14 @@ genptable(PruneData *pd, int nthreads) | |||
| 87 | pd->count[d+1] = pd->n - oldn; | 187 | pd->count[d+1] = pd->n - oldn; |
| 88 | oldn = pd->n; | 188 | oldn = pd->n; |
| 89 | } | 189 | } |
| 90 | if (pd->compact) | ||
| 91 | fprintf(stderr, "Compact table, values above " | ||
| 92 | "%d are inaccurate.\n", maxv-1); | ||
| 93 | fprintf(stderr, "Pruning table generated!\n"); | 190 | fprintf(stderr, "Pruning table generated!\n"); |
| 94 | 191 | ||
| 192 | genptable_setbase(pd); | ||
| 193 | if (compact) | ||
| 194 | genptable_compress(pd); | ||
| 195 | |||
| 95 | if (!write_ptable_file(pd)) | 196 | if (!write_ptable_file(pd)) |
| 96 | fprintf(stderr, "Error writing ptable file\n"); | 197 | fprintf(stderr, "Error writing ptable file\n"); |
| 97 | |||
| 98 | genptable_done: | ||
| 99 | for (i = 0; active_pd[i] != NULL; i++); | ||
| 100 | return active_pd[i] = pd; | ||
| 101 | } | 198 | } |
| 102 | 199 | ||
| 103 | static void | 200 | static void |
| @@ -135,6 +232,31 @@ genptable_bfs(PruneData *pd, int d, int nthreads, int nchunks) | |||
| 135 | } | 232 | } |
| 136 | 233 | ||
| 137 | static void | 234 | static void |
| 235 | genptable_compress(PruneData *pd) | ||
| 236 | { | ||
| 237 | int val; | ||
| 238 | uint64_t i, j; | ||
| 239 | entry_group_t mask, v; | ||
| 240 | |||
| 241 | fprintf(stderr, "Compressing table to 2 bits per entry\n"); | ||
| 242 | |||
| 243 | for (i = 0; i < pd->coord->max; i += ENTRIES_PER_GROUP_COMPACT) { | ||
| 244 | mask = (entry_group_t)0; | ||
| 245 | for (j = 0; j < ENTRIES_PER_GROUP_COMPACT; j++) { | ||
| 246 | if (i+j >= pd->coord->max) | ||
| 247 | break; | ||
| 248 | val = ptableval_index(pd, i+j) - pd->base; | ||
| 249 | v = (entry_group_t)MIN(3, MAX(0, val)); | ||
| 250 | mask |= v << (2*j); | ||
| 251 | } | ||
| 252 | pd->ptable[i/ENTRIES_PER_GROUP_COMPACT] = mask; | ||
| 253 | } | ||
| 254 | |||
| 255 | pd->compact = true; | ||
| 256 | pd->ptable = realloc(pd->ptable, sizeof(entry_group_t)*ptablesize(pd)); | ||
| 257 | } | ||
| 258 | |||
| 259 | static void | ||
| 138 | genptable_fixnasty(PruneData *pd, int d, int nthreads) | 260 | genptable_fixnasty(PruneData *pd, int d, int nthreads) |
| 139 | { | 261 | { |
| 140 | int i; | 262 | int i; |
| @@ -142,7 +264,7 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads) | |||
| 142 | ThreadDataGenpt td[nthreads]; | 264 | ThreadDataGenpt td[nthreads]; |
| 143 | pthread_mutex_t *upmtx; | 265 | pthread_mutex_t *upmtx; |
| 144 | 266 | ||
| 145 | if (pd->coord->type != SYMCOMP_COORD) | 267 | if (pd->coord->tfind == NULL) |
| 146 | return; | 268 | return; |
| 147 | 269 | ||
| 148 | upmtx = malloc(sizeof(pthread_mutex_t)); | 270 | upmtx = malloc(sizeof(pthread_mutex_t)); |
| @@ -162,12 +284,28 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads) | |||
| 162 | free(upmtx); | 284 | free(upmtx); |
| 163 | } | 285 | } |
| 164 | 286 | ||
| 287 | static void | ||
| 288 | genptable_setbase(PruneData *pd) | ||
| 289 | { | ||
| 290 | int i; | ||
| 291 | uint64_t sum, newsum; | ||
| 292 | |||
| 293 | pd->base = 0; | ||
| 294 | sum = pd->count[0] + pd->count[1] + pd->count[2]; | ||
| 295 | for (i = 3; i < 16; i++) { | ||
| 296 | newsum = sum + pd->count[i] - pd->count[i-3]; | ||
| 297 | if (newsum > sum) | ||
| 298 | pd->base = i-3; | ||
| 299 | sum = newsum; | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 165 | static void * | 303 | static void * |
| 166 | instance_bfs(void *arg) | 304 | instance_bfs(void *arg) |
| 167 | { | 305 | { |
| 168 | ThreadDataGenpt *td; | 306 | ThreadDataGenpt *td; |
| 169 | uint64_t i, ii, blocksize, rmin, rmax, updated; | 307 | uint64_t i, ii, blocksize, rmin, rmax, updated; |
| 170 | int j, pval, ichunk, oldc, newc; | 308 | int j, pval, ichunk; |
| 171 | Move *ms; | 309 | Move *ms; |
| 172 | 310 | ||
| 173 | td = (ThreadDataGenpt *)arg; | 311 | td = (ThreadDataGenpt *)arg; |
| @@ -178,43 +316,25 @@ instance_bfs(void *arg) | |||
| 178 | td->pd->coord->max : | 316 | td->pd->coord->max : |
| 179 | ((uint64_t)td->thid + 1) * blocksize; | 317 | ((uint64_t)td->thid + 1) * blocksize; |
| 180 | 318 | ||
| 181 | if (td->pd->compact) { | ||
| 182 | if (td->d <= td->pd->base) { | ||
| 183 | oldc = 1; | ||
| 184 | newc = 1; | ||
| 185 | } else { | ||
| 186 | oldc = td->d - td->pd->base; | ||
| 187 | newc = td->d - td->pd->base; | ||
| 188 | } | ||
| 189 | } else { | ||
| 190 | oldc = td->d; | ||
| 191 | newc = td->d + 1; | ||
| 192 | } | ||
| 193 | |||
| 194 | updated = 0; | 319 | updated = 0; |
| 195 | for (i = rmin; i < rmax; i++) { | 320 | for (i = rmin; i < rmax; i++) { |
| 196 | ichunk = findchunk(td->pd, td->nchunks, i); | 321 | ichunk = findchunk(td->pd, td->nchunks, i); |
| 197 | pthread_mutex_lock(td->mutex[ichunk]); | 322 | pthread_mutex_lock(td->mutex[ichunk]); |
| 198 | pval = ptableval(td->pd, i); | 323 | pval = ptableval_index(td->pd, i); |
| 199 | pthread_mutex_unlock(td->mutex[ichunk]); | 324 | pthread_mutex_unlock(td->mutex[ichunk]); |
| 200 | if (pval == oldc) { | 325 | if (pval == td->d) { |
| 201 | for (j = 0; ms[j] != NULLMOVE; j++) { | 326 | for (j = 0; ms[j] != NULLMOVE; j++) { |
| 202 | ii = move_coord(td->pd->coord, ms[j], i, NULL); | 327 | ii = td->pd->coord->move(ms[j], i); |
| 203 | ichunk = findchunk(td->pd, td->nchunks, ii); | 328 | ichunk = findchunk(td->pd, td->nchunks, ii); |
| 204 | pthread_mutex_lock(td->mutex[ichunk]); | 329 | pthread_mutex_lock(td->mutex[ichunk]); |
| 205 | pval = ptableval(td->pd, ii); | 330 | pval = ptableval_index(td->pd, ii); |
| 206 | if (pval > newc) { | 331 | if (pval > td->d+1) { |
| 207 | ptable_update(td->pd, ii, newc); | 332 | ptable_update_index(td->pd, |
| 333 | ii, td->d+1); | ||
| 208 | updated++; | 334 | updated++; |
| 209 | } | 335 | } |
| 210 | pthread_mutex_unlock(td->mutex[ichunk]); | 336 | pthread_mutex_unlock(td->mutex[ichunk]); |
| 211 | } | 337 | } |
| 212 | if (td->pd->compact && td->d <= td->pd->base) { | ||
| 213 | ichunk = findchunk(td->pd, td->nchunks, i); | ||
| 214 | pthread_mutex_lock(td->mutex[ichunk]); | ||
| 215 | ptable_update(td->pd, i, 0); | ||
| 216 | pthread_mutex_unlock(td->mutex[ichunk]); | ||
| 217 | } | ||
| 218 | } | 338 | } |
| 219 | } | 339 | } |
| 220 | 340 | ||
| @@ -229,40 +349,30 @@ static void * | |||
| 229 | instance_fixnasty(void *arg) | 349 | instance_fixnasty(void *arg) |
| 230 | { | 350 | { |
| 231 | ThreadDataGenpt *td; | 351 | ThreadDataGenpt *td; |
| 232 | uint64_t i, ii, blocksize, rmin, rmax, updated, ss, M; | 352 | uint64_t i, ii, nb, blocksize, rmin, rmax, updated; |
| 233 | int j, oldc; | 353 | int j, n; |
| 234 | Trans t; | 354 | Trans t, aux[NTRANS]; |
| 235 | 355 | ||
| 236 | td = (ThreadDataGenpt *)arg; | 356 | td = (ThreadDataGenpt *)arg; |
| 237 | 357 | nb = td->pd->coord->max / td->pd->coord->base->max; | |
| 238 | /* We know type = SYMCOMP_COORD */ | 358 | blocksize = (td->pd->coord->base->max / td->nthreads) * nb; |
| 239 | M = td->pd->coord->base[1]->max; | ||
| 240 | blocksize = (td->pd->coord->base[0]->max / td->nthreads) * M; | ||
| 241 | rmin = ((uint64_t)td->thid) * blocksize; | 359 | rmin = ((uint64_t)td->thid) * blocksize; |
| 242 | rmax = td->thid == td->nthreads - 1 ? | 360 | rmax = td->thid == td->nthreads - 1 ? |
| 243 | td->pd->coord->max : | 361 | td->pd->coord->max : |
| 244 | ((uint64_t)td->thid + 1) * blocksize; | 362 | ((uint64_t)td->thid + 1) * blocksize; |
| 245 | 363 | ||
| 246 | if (td->pd->compact) { | ||
| 247 | if (td->d <= td->pd->base) | ||
| 248 | oldc = 1; | ||
| 249 | else | ||
| 250 | oldc = td->d - td->pd->base; | ||
| 251 | } else { | ||
| 252 | oldc = td->d; | ||
| 253 | } | ||
| 254 | |||
| 255 | updated = 0; | 364 | updated = 0; |
| 256 | for (i = rmin; i < rmax; i++) { | 365 | for (i = rmin; i < rmax; i++) { |
| 257 | if (ptableval(td->pd, i) == oldc) { | 366 | if (ptableval_index(td->pd, i) == td->d) { |
| 258 | ss = td->pd->coord->base[0]->selfsim[i/M]; | 367 | if ((n = td->pd->coord->tfind(i, aux)) == 1) |
| 259 | for (j = 0; j < td->pd->coord->base[0]->tgrp->n; j++) { | 368 | continue; |
| 260 | t = td->pd->coord->base[0]->tgrp->t[j]; | 369 | |
| 261 | if (t == uf || !(ss & ((uint64_t)1<<t))) | 370 | for (j = 0; j < n; j++) { |
| 371 | if ((t = aux[j]) == uf) | ||
| 262 | continue; | 372 | continue; |
| 263 | ii = trans_coord(td->pd->coord, t, i); | 373 | ii = td->pd->coord->transform(t, i); |
| 264 | if (ptableval(td->pd, ii) > oldc) { | 374 | if (ptableval_index(td->pd, ii) > td->d) { |
| 265 | ptable_update(td->pd, ii, oldc); | 375 | ptable_update_index(td->pd, ii, td->d); |
| 266 | updated++; | 376 | updated++; |
| 267 | } | 377 | } |
| 268 | } | 378 | } |
| @@ -281,13 +391,11 @@ print_ptable(PruneData *pd) | |||
| 281 | { | 391 | { |
| 282 | uint64_t i; | 392 | uint64_t i; |
| 283 | 393 | ||
| 284 | printf("Table %s_%s\n", pd->coord->name, pd->moveset->name); | 394 | if (!pd->generated) |
| 285 | 395 | genptable(pd, 1); /* TODO: set default nthreads somewhere */ | |
| 286 | if (pd->compact) { | 396 | |
| 287 | printf("Compract table with base value: %d\n", pd->base); | 397 | printf("Table %s\n", pd->filename); |
| 288 | printf("Values above %d are inaccurate.\n", pd->base + 3); | 398 | printf("Base value: %d\n", pd->base); |
| 289 | } | ||
| 290 | |||
| 291 | for (i = 0; i < 16; i++) | 399 | for (i = 0; i < 16; i++) |
| 292 | printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]); | 400 | printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]); |
| 293 | } | 401 | } |
| @@ -303,31 +411,48 @@ ptablesize(PruneData *pd) | |||
| 303 | } | 411 | } |
| 304 | 412 | ||
| 305 | static void | 413 | static void |
| 306 | ptable_update(PruneData *pd, uint64_t ind, int n) | 414 | ptable_update(PruneData *pd, Cube cube, int n) |
| 307 | { | 415 | { |
| 308 | int sh; | 416 | ptable_update_index(pd, pd->coord->index(cube), n); |
| 309 | entry_group_t f, mask; | 417 | } |
| 310 | uint64_t i, e, b; | ||
| 311 | 418 | ||
| 312 | e = pd->compact ? ENTRIES_PER_GROUP_COMPACT : ENTRIES_PER_GROUP; | 419 | static void |
| 313 | b = pd->compact ? 2 : 4; | 420 | ptable_update_index(PruneData *pd, uint64_t ind, int n) |
| 314 | f = pd->compact ? 3 : 15; | 421 | { |
| 422 | int sh; | ||
| 423 | entry_group_t mask; | ||
| 424 | uint64_t i; | ||
| 315 | 425 | ||
| 316 | sh = b * (ind % e); | 426 | sh = 4 * (ind % ENTRIES_PER_GROUP); |
| 317 | mask = f << sh; | 427 | mask = ((entry_group_t)15) << sh; |
| 318 | i = ind / e; | 428 | i = ind/ENTRIES_PER_GROUP; |
| 319 | 429 | ||
| 320 | pd->ptable[i] &= ~mask; | 430 | pd->ptable[i] &= ~mask; |
| 321 | pd->ptable[i] |= (((entry_group_t)n) & f) << sh; | 431 | pd->ptable[i] |= (((entry_group_t)n)&15) << sh; |
| 322 | } | 432 | } |
| 323 | 433 | ||
| 324 | int | 434 | int |
| 325 | ptableval(PruneData *pd, uint64_t ind) | 435 | ptableval(PruneData *pd, Cube cube) |
| 326 | { | 436 | { |
| 327 | int sh; | 437 | return ptableval_index(pd, pd->coord->index(cube)); |
| 328 | uint64_t e; | 438 | } |
| 439 | |||
| 440 | static int | ||
| 441 | ptableval_index(PruneData *pd, uint64_t ind) | ||
| 442 | { | ||
| 443 | int sh, ret; | ||
| 444 | entry_group_t mask; | ||
| 445 | uint64_t i, e; | ||
| 329 | entry_group_t m; | 446 | entry_group_t m; |
| 330 | 447 | ||
| 448 | if (!pd->generated) { | ||
| 449 | fprintf(stderr, "Warning: request pruning table value" | ||
| 450 | " for uninitialized table %s.\n It's fine, but it" | ||
| 451 | " should not happen. Please report bug.\n", | ||
| 452 | pd->filename); | ||
| 453 | genptable(pd, 1); /* TODO: set default or remove this case */ | ||
| 454 | } | ||
| 455 | |||
| 331 | if (pd->compact) { | 456 | if (pd->compact) { |
| 332 | e = ENTRIES_PER_GROUP_COMPACT; | 457 | e = ENTRIES_PER_GROUP_COMPACT; |
| 333 | m = 3; | 458 | m = 3; |
| @@ -338,7 +463,19 @@ ptableval(PruneData *pd, uint64_t ind) | |||
| 338 | sh = (ind % e) * 4; | 463 | sh = (ind % e) * 4; |
| 339 | } | 464 | } |
| 340 | 465 | ||
| 341 | return (pd->ptable[ind/e] & (m << sh)) >> sh; | 466 | mask = m << sh; |
| 467 | i = ind/e; | ||
| 468 | |||
| 469 | ret = (pd->ptable[i] & mask) >> sh; | ||
| 470 | |||
| 471 | if (pd->compact) { | ||
| 472 | if (ret) | ||
| 473 | ret += pd->base; | ||
| 474 | else | ||
| 475 | ret = ptableval_index(pd->fallback, ind / pd->fbmod); | ||
| 476 | } | ||
| 477 | |||
| 478 | return ret; | ||
| 342 | } | 479 | } |
| 343 | 480 | ||
| 344 | static bool | 481 | static bool |
| @@ -347,15 +484,13 @@ read_ptable_file(PruneData *pd) | |||
| 347 | init_env(); | 484 | init_env(); |
| 348 | 485 | ||
| 349 | FILE *f; | 486 | FILE *f; |
| 350 | char fname[strlen(tabledir)+256]; | 487 | char fname[strlen(tabledir)+100]; |
| 351 | int i; | 488 | int i; |
| 352 | uint64_t r; | 489 | uint64_t r; |
| 353 | 490 | ||
| 354 | strcpy(fname, tabledir); | 491 | strcpy(fname, tabledir); |
| 355 | strcat(fname, "/pt_"); | 492 | strcat(fname, "/"); |
| 356 | strcat(fname, pd->coord->name); | 493 | strcat(fname, pd->filename); |
| 357 | strcat(fname, "_"); | ||
| 358 | strcat(fname, pd->moveset->name); | ||
| 359 | 494 | ||
| 360 | if ((f = fopen(fname, "rb")) == NULL) | 495 | if ((f = fopen(fname, "rb")) == NULL) |
| 361 | return false; | 496 | return false; |
| @@ -376,15 +511,13 @@ write_ptable_file(PruneData *pd) | |||
| 376 | init_env(); | 511 | init_env(); |
| 377 | 512 | ||
| 378 | FILE *f; | 513 | FILE *f; |
| 379 | char fname[strlen(tabledir)+256]; | 514 | char fname[strlen(tabledir)+100]; |
| 380 | int i; | 515 | int i; |
| 381 | uint64_t w; | 516 | uint64_t w; |
| 382 | 517 | ||
| 383 | strcpy(fname, tabledir); | 518 | strcpy(fname, tabledir); |
| 384 | strcat(fname, "/pt_"); | 519 | strcat(fname, "/"); |
| 385 | strcat(fname, pd->coord->name); | 520 | strcat(fname, pd->filename); |
| 386 | strcat(fname, "_"); | ||
| 387 | strcat(fname, pd->moveset->name); | ||
| 388 | 521 | ||
| 389 | if ((f = fopen(fname, "wb")) == NULL) | 522 | if ((f = fopen(fname, "wb")) == NULL) |
| 390 | return false; | 523 | return false; |
diff --git a/src/pruning.h b/src/pruning.h index 93ae863..6bdbee1 100644 --- a/src/pruning.h +++ b/src/pruning.h | |||
| @@ -1,16 +1,26 @@ | |||
| 1 | #ifndef PRUNING_H | 1 | #ifndef PRUNING_H |
| 2 | #define PRUNING_H | 2 | #define PRUNING_H |
| 3 | 3 | ||
| 4 | #include "coord.h" | 4 | #include "symcoord.h" |
| 5 | #include "movesets.h" | 5 | |
| 6 | extern PruneData pd_eofb_HTM; | ||
| 7 | extern PruneData pd_coud_HTM; | ||
| 8 | extern PruneData pd_corners_HTM; | ||
| 9 | extern PruneData pd_cornershtr_HTM; | ||
| 10 | extern PruneData pd_drud_sym16_HTM; | ||
| 11 | extern PruneData pd_drud_eofb; | ||
| 12 | extern PruneData pd_drudfin_noE_sym16_drud; | ||
| 13 | extern PruneData pd_htr_drud; | ||
| 14 | extern PruneData pd_htrfin_htr; | ||
| 15 | extern PruneData pd_nxopt31_HTM; | ||
| 16 | |||
| 17 | extern PruneData * all_pd[]; | ||
| 6 | 18 | ||
| 7 | void free_pd(PruneData *pd); | 19 | void free_pd(PruneData *pd); |
| 8 | PruneData * genptable(PruneData *data, int nthreads); | 20 | void genptable(PruneData *pd, int nthreads); |
| 9 | void print_ptable(PruneData *pd); | 21 | void print_ptable(PruneData *pd); |
| 10 | uint64_t ptablesize(PruneData *pd); | 22 | uint64_t ptablesize(PruneData *pd); |
| 11 | int ptableval(PruneData *pd, uint64_t ind); | 23 | int ptableval(PruneData *pd, Cube cube); |
| 12 | |||
| 13 | extern PruneData *active_pd[256]; | ||
| 14 | 24 | ||
| 15 | #endif | 25 | #endif |
| 16 | 26 | ||
diff --git a/src/shell.c b/src/shell.c index 4faa0a8..0001e0d 100644 --- a/src/shell.c +++ b/src/shell.c | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | #define SHELL_C | ||
| 2 | |||
| 3 | #include "shell.h" | 1 | #include "shell.h" |
| 4 | 2 | ||
| 5 | static void cleanwhitespaces(char *line); | 3 | static void cleanwhitespaces(char *line); |
| @@ -9,9 +7,7 @@ bool | |||
| 9 | checkfiles() | 7 | checkfiles() |
| 10 | { | 8 | { |
| 11 | /* TODO: add more checks (other files, use checksum...) */ | 9 | /* TODO: add more checks (other files, use checksum...) */ |
| 12 | /* How to check for pruning tables with new method? */ | 10 | FILE *f; |
| 13 | /* Solution: use list of steps */ | ||
| 14 | /* | ||
| 15 | char fname[strlen(tabledir)+100]; | 11 | char fname[strlen(tabledir)+100]; |
| 16 | int i; | 12 | int i; |
| 17 | 13 | ||
| @@ -24,7 +20,6 @@ checkfiles() | |||
| 24 | else | 20 | else |
| 25 | fclose(f); | 21 | fclose(f); |
| 26 | } | 22 | } |
| 27 | */ | ||
| 28 | 23 | ||
| 29 | return true; | 24 | return true; |
| 30 | } | 25 | } |
| @@ -142,14 +137,12 @@ launch(bool batchmode) | |||
| 142 | free(shell_argv); | 137 | free(shell_argv); |
| 143 | } | 138 | } |
| 144 | 139 | ||
| 145 | #ifndef TEST | ||
| 146 | int | 140 | int |
| 147 | main(int argc, char *argv[]) | 141 | main(int argc, char *argv[]) |
| 148 | { | 142 | { |
| 149 | char *closing_cmd[1] = { "freemem" }; | 143 | char *closing_cmd[1] = { "freemem" }; |
| 150 | 144 | ||
| 151 | init_env(); | 145 | init_env(); |
| 152 | init_trans(); | ||
| 153 | 146 | ||
| 154 | if (!checkfiles()) { | 147 | if (!checkfiles()) { |
| 155 | fprintf(stderr, | 148 | fprintf(stderr, |
| @@ -174,4 +167,3 @@ main(int argc, char *argv[]) | |||
| 174 | 167 | ||
| 175 | return 0; | 168 | return 0; |
| 176 | } | 169 | } |
| 177 | #endif | ||
diff --git a/src/solve.c b/src/solve.c index 2d0c94d..d4c0f18 100644 --- a/src/solve.c +++ b/src/solve.c | |||
| @@ -1,122 +1,500 @@ | |||
| 1 | #define SOLVE_C | ||
| 2 | |||
| 3 | #include "solve.h" | 1 | #include "solve.h" |
| 4 | 2 | ||
| 5 | void | 3 | /* Local functions ***********************************************************/ |
| 6 | dfs(DfsArg *arg, Solver *solver, Threader *threader) | 4 | |
| 5 | static bool allowed_next(Move move, DfsArg *arg); | ||
| 6 | static bool cancel_niss(DfsArg *arg); | ||
| 7 | static void copy_dfsarg(DfsArg *src, DfsArg *dst); | ||
| 8 | static void dfs(DfsArg *arg); | ||
| 9 | static void dfs_branch(DfsArg *arg); | ||
| 10 | static bool dfs_check_solved(DfsArg *arg); | ||
| 11 | static bool dfs_switch(DfsArg *arg); | ||
| 12 | static void dfs_niss(DfsArg *arg); | ||
| 13 | static bool dfs_stop(DfsArg *arg); | ||
| 14 | static void * instance_thread(void *arg); | ||
| 15 | static void invert_branch(DfsArg *arg); | ||
| 16 | static void multidfs(Cube c, Trans t, Step *s, SolveOptions *opts, | ||
| 17 | AlgList *sols, int d); | ||
| 18 | static bool niss_makes_sense(DfsArg *arg); | ||
| 19 | static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols); | ||
| 20 | |||
| 21 | /* Local functions ***********************************************************/ | ||
| 22 | |||
| 23 | static bool | ||
| 24 | allowed_next(Move m, DfsArg *arg) | ||
| 25 | { | ||
| 26 | bool bad, allowed, order; | ||
| 27 | uint64_t mbit; | ||
| 28 | |||
| 29 | mbit = ((uint64_t)1) << m; | ||
| 30 | bad = mbit & arg->badmoves; | ||
| 31 | allowed = mbit & arg->step->moveset->mask[arg->last2][arg->last1]; | ||
| 32 | order = !commute(arg->last1, m) || arg->last1 < m; | ||
| 33 | |||
| 34 | return allowed && !bad && order; | ||
| 35 | } | ||
| 36 | |||
| 37 | static bool | ||
| 38 | cancel_niss(DfsArg *arg) | ||
| 39 | { | ||
| 40 | Moveset *ms; | ||
| 41 | Move i1, i2; | ||
| 42 | bool p, p1, p2, q, q1, q2; | ||
| 43 | |||
| 44 | if (arg->last1inv == NULLMOVE) | ||
| 45 | return false; | ||
| 46 | |||
| 47 | ms = arg->step->moveset; | ||
| 48 | i1 = inverse_move(arg->last1inv); | ||
| 49 | i2 = inverse_move(arg->last2inv); | ||
| 50 | |||
| 51 | p1 = !ms->allowed_next(arg->last2, arg->last1, i1); | ||
| 52 | p2 = !ms->allowed_next(arg->last2, i1, arg->last1); | ||
| 53 | p = p1 || (commute(i1, arg->last1) && p2); | ||
| 54 | |||
| 55 | q1 = !ms->allowed_next(arg->last2, arg->last1, i2); | ||
| 56 | q2 = !ms->allowed_next(arg->last2, i2, arg->last1); | ||
| 57 | q = q1 || (commute(i2, arg->last1) && q2); | ||
| 58 | |||
| 59 | return p || (commute(i1, i2) && q); | ||
| 60 | } | ||
| 61 | |||
| 62 | static void | ||
| 63 | copy_dfsarg(DfsArg *src, DfsArg *dst) | ||
| 64 | { | ||
| 65 | dst->step = src->step; | ||
| 66 | dst->opts = src->opts; | ||
| 67 | dst->t = src->t; | ||
| 68 | dst->cube = src->cube; | ||
| 69 | dst->inverse = src->inverse; | ||
| 70 | dst->d = src->d; | ||
| 71 | dst->badmoves = src->badmoves; | ||
| 72 | dst->badmovesinv = src->badmovesinv; | ||
| 73 | dst->niss = src->niss; | ||
| 74 | dst->last1 = src->last1; | ||
| 75 | dst->last2 = src->last2; | ||
| 76 | dst->last1inv = src->last1inv; | ||
| 77 | dst->last2inv = src->last2inv; | ||
| 78 | dst->sols = src->sols; | ||
| 79 | dst->sols_mutex = src->sols_mutex; | ||
| 80 | dst->current_alg = src->current_alg; | ||
| 81 | |||
| 82 | copy_estimatedata(src->ed, dst->ed); | ||
| 83 | } | ||
| 84 | |||
| 85 | static void | ||
| 86 | dfs(DfsArg *arg) | ||
| 87 | { | ||
| 88 | bool sw = false; | ||
| 89 | |||
| 90 | if (dfs_stop(arg)) | ||
| 91 | return; | ||
| 92 | |||
| 93 | if (dfs_check_solved(arg)) | ||
| 94 | return; | ||
| 95 | |||
| 96 | if (arg->step->final && (sw = dfs_switch(arg))) | ||
| 97 | invert_branch(arg); | ||
| 98 | dfs_branch(arg); | ||
| 99 | |||
| 100 | if (arg->opts->can_niss && !arg->niss && niss_makes_sense(arg)) | ||
| 101 | dfs_niss(arg); | ||
| 102 | |||
| 103 | if (sw) | ||
| 104 | invert_branch(arg); | ||
| 105 | } | ||
| 106 | |||
| 107 | static void | ||
| 108 | dfs_branch(DfsArg *arg) | ||
| 7 | { | 109 | { |
| 8 | int i; | 110 | int i; |
| 9 | DfsArg newarg; | ||
| 10 | Alg *sol; | ||
| 11 | Move m; | 111 | Move m; |
| 112 | DfsArg *newarg; | ||
| 12 | 113 | ||
| 13 | if (arg->current_alg->len > arg->d) | 114 | newarg = malloc(sizeof(DfsArg)); |
| 14 | return; | 115 | newarg->ed = malloc(sizeof(EstimateData)); |
| 15 | 116 | ||
| 16 | if (solver->is_solved(solver->param, arg->cubedata)) { | 117 | for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) { |
| 17 | /* TODO: the "all" option should be re-implemented as setting | 118 | m = arg->step->moveset->sorted_moves[i]; |
| 18 | validate to null */ | 119 | if (allowed_next(m, arg)) { |
| 120 | copy_dfsarg(arg, newarg); | ||
| 121 | newarg->last2 = arg->last1; | ||
| 122 | newarg->last1 = m; | ||
| 123 | newarg->cube = apply_move(m, arg->cube); | ||
| 124 | append_move(arg->current_alg, m, newarg->niss); | ||
| 19 | 125 | ||
| 20 | /* TODO: we also have to check if cancel with NISS; | 126 | dfs(newarg); |
| 21 | we can't because we have no access to the s->final field | ||
| 22 | this should be done by the step's validator? */ | ||
| 23 | sol = solver->validate_solution(solver->param,arg->current_alg); | ||
| 24 | bool accepted = sol != NULL; | ||
| 25 | bool too_short = arg->current_alg->len != arg->d; | ||
| 26 | 127 | ||
| 27 | if (accepted && !too_short) { | 128 | arg->current_alg->len--; |
| 28 | /* TODO: arg->t got lost in refactoring */ | ||
| 29 | /* transform_alg(inverse_trans(arg->t), sol);*/ | ||
| 30 | if (arg->opts->verbose) | ||
| 31 | print_alg(sol, false); | ||
| 32 | threader->append_sol(sol, arg->threaddata); | ||
| 33 | } | 129 | } |
| 34 | return; | ||
| 35 | } | 130 | } |
| 36 | 131 | ||
| 37 | if (arg->current_alg->len == arg->d) | 132 | free(newarg->ed); |
| 38 | return; | 133 | free(newarg); |
| 134 | } | ||
| 135 | |||
| 136 | static bool | ||
| 137 | dfs_check_solved(DfsArg *arg) | ||
| 138 | { | ||
| 139 | if (!arg->step->is_done(arg->cube)) | ||
| 140 | return false; | ||
| 141 | |||
| 142 | if (arg->current_alg->len == arg->d) { | ||
| 143 | if ((arg->step->is_valid(arg->current_alg) || arg->opts->all) | ||
| 144 | && (!arg->step->final || !cancel_niss(arg))) { | ||
| 145 | |||
| 146 | pthread_mutex_lock(arg->sols_mutex); | ||
| 147 | |||
| 148 | if (arg->sols->len < arg->opts->max_solutions) { | ||
| 149 | append_alg(arg->sols, arg->current_alg); | ||
| 150 | |||
| 151 | transform_alg( | ||
| 152 | inverse_trans(arg->t), | ||
| 153 | arg->sols->last->alg | ||
| 154 | ); | ||
| 155 | if (arg->step->final) | ||
| 156 | inplace(unniss, arg->sols->last->alg); | ||
| 157 | |||
| 158 | if (arg->opts->verbose) | ||
| 159 | print_alg(arg->sols->last->alg, false); | ||
| 160 | } | ||
| 161 | |||
| 162 | pthread_mutex_unlock(arg->sols_mutex); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | return true; | ||
| 167 | } | ||
| 168 | |||
| 169 | static void | ||
| 170 | dfs_niss(DfsArg *arg) | ||
| 171 | { | ||
| 172 | DfsArg *newarg; | ||
| 173 | |||
| 174 | newarg = malloc(sizeof(DfsArg)); | ||
| 175 | newarg->ed = malloc(sizeof(EstimateData)); | ||
| 176 | |||
| 177 | copy_dfsarg(arg, newarg); | ||
| 178 | swapmove(&(newarg->last1), &(newarg->last1inv)); | ||
| 179 | swapmove(&(newarg->last2), &(newarg->last2inv)); | ||
| 180 | newarg->niss = !(arg->niss); | ||
| 181 | newarg->cube = inverse_cube(arg->cube); | ||
| 182 | |||
| 183 | dfs(newarg); | ||
| 184 | |||
| 185 | free(newarg->ed); | ||
| 186 | free(newarg); | ||
| 187 | } | ||
| 188 | |||
| 189 | static bool | ||
| 190 | dfs_stop(DfsArg *arg) | ||
| 191 | { | ||
| 192 | int lowerbound; | ||
| 193 | bool b; | ||
| 194 | |||
| 195 | lowerbound = arg->step->estimate(arg); | ||
| 196 | if (arg->opts->can_niss && !arg->niss) | ||
| 197 | lowerbound = MIN(1, lowerbound); | ||
| 198 | |||
| 199 | if (arg->current_alg->len + lowerbound > arg->d) { | ||
| 200 | b = true; | ||
| 201 | } else { | ||
| 202 | pthread_mutex_lock(arg->sols_mutex); | ||
| 203 | b = arg->sols->len >= arg->opts->max_solutions; | ||
| 204 | pthread_mutex_unlock(arg->sols_mutex); | ||
| 205 | } | ||
| 206 | |||
| 207 | return b; | ||
| 208 | } | ||
| 209 | |||
| 210 | static bool | ||
| 211 | dfs_switch(DfsArg *arg) | ||
| 212 | { | ||
| 213 | int i, bn, bi; | ||
| 214 | |||
| 215 | bn = 0; | ||
| 216 | for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) | ||
| 217 | if (allowed_next(arg->step->moveset->sorted_moves[i], arg)) | ||
| 218 | bn++; | ||
| 219 | |||
| 220 | swapmove(&(arg->last1), &(arg->last1inv)); | ||
| 221 | swapmove(&(arg->last2), &(arg->last2inv)); | ||
| 222 | swapu64(&(arg->badmoves), &(arg->badmovesinv)); | ||
| 223 | |||
| 224 | bi = 0; | ||
| 225 | for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) | ||
| 226 | if (allowed_next(arg->step->moveset->sorted_moves[i], arg)) | ||
| 227 | bi++; | ||
| 228 | |||
| 229 | swapmove(&(arg->last1), &(arg->last1inv)); | ||
| 230 | swapmove(&(arg->last2), &(arg->last2inv)); | ||
| 231 | swapu64(&(arg->badmoves), &(arg->badmovesinv)); | ||
| 232 | |||
| 233 | return bi < bn; | ||
| 234 | } | ||
| 235 | |||
| 236 | static void * | ||
| 237 | instance_thread(void *arg) | ||
| 238 | { | ||
| 239 | bool b; | ||
| 240 | Cube c; | ||
| 241 | ThreadDataSolve *td; | ||
| 242 | AlgListNode *node; | ||
| 243 | DfsArg darg; | ||
| 244 | |||
| 245 | td = (ThreadDataSolve *)arg; | ||
| 246 | |||
| 247 | while (1) { | ||
| 248 | b = false; | ||
| 249 | |||
| 250 | pthread_mutex_lock(td->start_mutex); | ||
| 251 | if ((node = *(td->node)) == NULL) | ||
| 252 | b = true; | ||
| 253 | else | ||
| 254 | *(td->node) = (*(td->node))->next; | ||
| 255 | pthread_mutex_unlock(td->start_mutex); | ||
| 256 | |||
| 257 | if (b) | ||
| 258 | break; | ||
| 259 | |||
| 260 | c = node->alg->inv[0] ? | ||
| 261 | apply_move(node->alg->move[0], inverse_cube(td->cube)) : | ||
| 262 | apply_move(node->alg->move[0], td->cube); | ||
| 263 | |||
| 264 | darg.step = td->step; | ||
| 265 | darg.opts = td->opts; | ||
| 266 | darg.t = td->t; | ||
| 267 | darg.cube = c; | ||
| 268 | darg.d = td->depth; | ||
| 269 | darg.niss = node->alg->inv[0]; | ||
| 270 | darg.last1 = node->alg->move[0]; | ||
| 271 | darg.last2 = NULLMOVE; | ||
| 272 | darg.last1inv = NULLMOVE; | ||
| 273 | darg.last2inv = NULLMOVE; | ||
| 274 | darg.sols = td->sols; | ||
| 275 | darg.sols_mutex = td->sols_mutex; | ||
| 276 | darg.current_alg = new_alg(""); | ||
| 277 | append_move(darg.current_alg, node->alg->move[0], | ||
| 278 | node->alg->inv[0]); | ||
| 279 | darg.ed = malloc(sizeof(EstimateData)); | ||
| 280 | reset_estimatedata(darg.ed); | ||
| 281 | darg.badmoves = 0; | ||
| 282 | darg.badmovesinv = 0; | ||
| 283 | |||
| 284 | dfs(&darg); | ||
| 285 | |||
| 286 | free_alg(darg.current_alg); | ||
| 287 | free(darg.ed); | ||
| 288 | } | ||
| 289 | |||
| 290 | return NULL; | ||
| 291 | } | ||
| 292 | |||
| 293 | static void | ||
| 294 | invert_branch(DfsArg *arg) | ||
| 295 | { | ||
| 296 | Cube aux; | ||
| 297 | |||
| 298 | aux = arg->cube; | ||
| 299 | arg->cube = is_solved(arg->inverse) ? | ||
| 300 | inverse_cube(arg->cube) : arg->inverse; | ||
| 301 | arg->inverse = aux; | ||
| 302 | |||
| 303 | swapu64(&(arg->badmoves), &(arg->badmovesinv)); | ||
| 304 | arg->niss = !(arg->niss); | ||
| 305 | swapmove(&(arg->last1), &(arg->last1inv)); | ||
| 306 | swapmove(&(arg->last2), &(arg->last2inv)); | ||
| 307 | invert_estimatedata(arg->ed); | ||
| 308 | } | ||
| 309 | |||
| 310 | static void | ||
| 311 | multidfs(Cube c, Trans tr, Step *s, SolveOptions *opts, AlgList *sols, int d) | ||
| 312 | { | ||
| 313 | int i; | ||
| 314 | Alg *alg; | ||
| 315 | AlgList *start; | ||
| 316 | AlgListNode **node; | ||
| 317 | pthread_t t[opts->nthreads]; | ||
| 318 | ThreadDataSolve td[opts->nthreads]; | ||
| 319 | pthread_mutex_t *start_mutex, *sols_mutex; | ||
| 39 | 320 | ||
| 40 | /* TODO: do not alloc */ | 321 | node = malloc(sizeof(AlgListNode *)); |
| 41 | newarg.cubedata = solver->alloc_cubedata(solver->param); | 322 | start_mutex = malloc(sizeof(pthread_mutex_t)); |
| 42 | for (i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) { | 323 | sols_mutex = malloc(sizeof(pthread_mutex_t)); |
| 43 | m = solver->moveset->sorted_moves[i]; | ||
| 44 | if (solver->moveset->can_append(arg->current_alg, m, arg->niss) | ||
| 45 | && compare_last(arg->current_alg, m, arg->niss) >= 0) { | ||
| 46 | append_move(arg->current_alg, m, arg->niss); | ||
| 47 | 324 | ||
| 48 | solver->copy_cubedata( | 325 | start = new_alglist(); |
| 49 | solver->param, arg->cubedata, newarg.cubedata); | 326 | pthread_mutex_init(start_mutex, NULL); |
| 50 | newarg.threaddata = arg->threaddata; | 327 | pthread_mutex_init(sols_mutex, NULL); |
| 51 | newarg.opts = arg->opts; | ||
| 52 | newarg.d = arg->d; | ||
| 53 | newarg.niss = arg->niss; | ||
| 54 | newarg.current_alg = arg->current_alg; | ||
| 55 | if (!solver->move_check_stop( | ||
| 56 | solver->param, &newarg, threader)) | ||
| 57 | dfs(&newarg, solver, threader); | ||
| 58 | 328 | ||
| 59 | remove_last_move(arg->current_alg); | 329 | for (i = 0; s->moveset->sorted_moves[i] != NULLMOVE; i++) { |
| 330 | alg = new_alg(""); | ||
| 331 | append_move(alg, s->moveset->sorted_moves[i], false); | ||
| 332 | append_alg(start, alg); | ||
| 333 | if (opts->can_niss) { | ||
| 334 | alg->inv[0] = true; | ||
| 335 | append_alg(start, alg); | ||
| 60 | } | 336 | } |
| 337 | free_alg(alg); | ||
| 61 | } | 338 | } |
| 62 | solver->free_cubedata(solver->param, newarg.cubedata); | 339 | *node = start->first; |
| 63 | 340 | ||
| 64 | if (arg->opts->can_niss && !arg->niss && | 341 | for (i = 0; i < opts->nthreads; i++) { |
| 65 | solver->niss_makes_sense( | 342 | td[i].thid = i; |
| 66 | solver->param, arg->cubedata, arg->current_alg)) { | 343 | td[i].t = tr; |
| 67 | solver->invert_cube(solver->param, arg->cubedata); | 344 | td[i].cube = c; |
| 68 | arg->niss = true; | 345 | td[i].step = s; |
| 69 | dfs(arg, solver, threader); | 346 | td[i].depth = d; |
| 347 | td[i].opts = opts; | ||
| 348 | td[i].start = start; | ||
| 349 | td[i].node = node; | ||
| 350 | td[i].sols = sols; | ||
| 351 | td[i].start_mutex = start_mutex; | ||
| 352 | td[i].sols_mutex = sols_mutex; | ||
| 353 | pthread_create(&t[i], NULL, instance_thread, &td[i]); | ||
| 70 | } | 354 | } |
| 355 | |||
| 356 | for (i = 0; i < opts->nthreads; i++) | ||
| 357 | pthread_join(t[i], NULL); | ||
| 358 | |||
| 359 | free_alglist(start); | ||
| 360 | free(node); | ||
| 361 | free(start_mutex); | ||
| 362 | free(sols_mutex); | ||
| 363 | } | ||
| 364 | |||
| 365 | static bool | ||
| 366 | niss_makes_sense(DfsArg *arg) | ||
| 367 | { | ||
| 368 | Cube testcube; | ||
| 369 | |||
| 370 | testcube = apply_move(inverse_move(arg->last1), (Cube){0}); | ||
| 371 | return arg->current_alg->len == 0 || !arg->step->is_done(testcube); | ||
| 71 | } | 372 | } |
| 72 | 373 | ||
| 374 | static bool | ||
| 375 | solvestop(int d, int op, SolveOptions *opts, AlgList *sols) | ||
| 376 | { | ||
| 377 | bool opt_done, max_moves_exceeded, max_sols_exceeded; | ||
| 378 | |||
| 379 | opt_done = opts->optimal != -1 && op != -1 && d > opts->optimal + op; | ||
| 380 | max_moves_exceeded = d > opts->max_moves; | ||
| 381 | max_sols_exceeded = sols->len >= opts->max_solutions; | ||
| 382 | |||
| 383 | return opt_done || max_moves_exceeded || max_sols_exceeded; | ||
| 384 | } | ||
| 385 | |||
| 386 | /* Public functions **********************************************************/ | ||
| 387 | |||
| 73 | AlgList * | 388 | AlgList * |
| 74 | solve(Cube *cube, SolveOptions *opts, Solver **solver, Threader *threader) | 389 | solve(Cube cube, Step *step, SolveOptions *opts) |
| 75 | { | 390 | { |
| 76 | int i, d, optimal; | 391 | bool ready; |
| 77 | bool ready[MAX_SOLVERS], stop, one_ready; | 392 | int i, d, op, nt; |
| 78 | DfsArg arg[MAX_SOLVERS]; | ||
| 79 | AlgList *sols; | 393 | AlgList *sols; |
| 394 | Cube c; | ||
| 395 | Trans tt[NTRANS]; | ||
| 396 | |||
| 397 | prepare_step(step, opts); | ||
| 80 | 398 | ||
| 81 | one_ready = false; | 399 | if (step->detect != NULL) { |
| 82 | for (i = 0; solver[i] != NULL; i++) { | 400 | nt = step->detect(cube, tt); |
| 83 | arg[i].cubedata = | 401 | } else { |
| 84 | solver[i]->prepare_cube(solver[i]->param, cube); | 402 | tt[0] = step->pre_trans; |
| 85 | arg[i].opts = opts; | 403 | ready = step->ready == NULL || |
| 86 | ready[i] = arg[i].cubedata != NULL; | 404 | step->ready(apply_trans(tt[0], cube)); |
| 87 | one_ready = one_ready || ready[i]; | 405 | nt = ready ? 1 : 0; |
| 88 | } | 406 | } |
| 89 | 407 | ||
| 90 | sols = new_alglist(); | 408 | sols = new_alglist(); |
| 91 | if (!one_ready) { | 409 | |
| 92 | fprintf(stderr, "Cube not ready for solving\n"); | 410 | if (nt == 0) { |
| 411 | fprintf(stderr, "Cube not ready for solving step: "); | ||
| 412 | fprintf(stderr, "%s\n", step->ready_msg); | ||
| 93 | return sols; | 413 | return sols; |
| 94 | } | 414 | } |
| 95 | 415 | ||
| 96 | optimal = opts->max_moves; | 416 | if (opts->min_moves == 0) { |
| 97 | stop = false; | 417 | for (i = 0; i < nt; i++) { |
| 98 | for (d = opts->min_moves; d <= opts->max_moves && !stop; d++) { | 418 | c = apply_trans(tt[i], cube); |
| 419 | if (step->is_done(c)) { | ||
| 420 | append_alg(sols, new_alg("")); | ||
| 421 | return sols; | ||
| 422 | } | ||
| 423 | } | ||
| 424 | } | ||
| 425 | |||
| 426 | op = -1; | ||
| 427 | for (d = opts->min_moves; !solvestop(d, op, opts, sols); d++) { | ||
| 99 | if (opts->verbose) | 428 | if (opts->verbose) |
| 100 | fprintf(stderr, "Searching depth %d\n", d); | 429 | fprintf(stderr, "Searching depth %d\n", d); |
| 101 | 430 | ||
| 102 | for (i = 0; solver[i] != NULL && !stop; i++) { | 431 | for (i = 0; i < nt && !solvestop(d, op, opts, sols); i++) { |
| 103 | if (!ready[i]) | 432 | c = apply_trans(tt[i], cube); |
| 104 | continue; | 433 | multidfs(c, tt[i], step, opts, sols, d); |
| 434 | if (sols->len > 0 && op == -1) | ||
| 435 | op = d; | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | return sols; | ||
| 440 | } | ||
| 441 | |||
| 442 | /* TODO: make more general! */ | ||
| 443 | Alg * | ||
| 444 | solve_2phase(Cube cube, int nthreads) | ||
| 445 | { | ||
| 446 | int bestlen, newb; | ||
| 447 | Alg *bestalg, *ret; | ||
| 448 | AlgList *sols1, *sols2; | ||
| 449 | AlgListNode *i; | ||
| 450 | Cube c; | ||
| 451 | SolveOptions opts1, opts2; | ||
| 105 | 452 | ||
| 106 | arg[i].d = d; | 453 | opts1.min_moves = 0; |
| 107 | threader->dispatch(&arg[i], sols, solver[i], threader); | 454 | opts1.max_moves = 13; |
| 455 | opts1.max_solutions = 20; | ||
| 456 | opts1.nthreads = nthreads; | ||
| 457 | opts1.optimal = 3; | ||
| 458 | opts1.can_niss = false; | ||
| 459 | opts1.verbose = false; | ||
| 460 | opts1.all = true; | ||
| 108 | 461 | ||
| 109 | if (sols->len > 0) | 462 | opts2.min_moves = 0; |
| 110 | optimal = MIN(optimal, d); | 463 | opts2.max_moves = 19; |
| 464 | opts2.max_solutions = 1; | ||
| 465 | opts2.nthreads = nthreads; | ||
| 466 | opts2.can_niss = false; | ||
| 467 | opts2.verbose = false; | ||
| 111 | 468 | ||
| 112 | stop = sols->len >= opts->max_solutions; | 469 | /* We skip step1 if it is solved on any axis */ |
| 470 | if (drany_HTM.is_done(cube)) { | ||
| 471 | sols1 = new_alglist(); | ||
| 472 | append_alg(sols1, new_alg("")); | ||
| 473 | } else { | ||
| 474 | sols1 = solve(cube, &drany_HTM, &opts1); | ||
| 475 | } | ||
| 476 | bestalg = new_alg(""); | ||
| 477 | bestlen = 999; | ||
| 478 | for (i = sols1->first; i != NULL; i = i->next) { | ||
| 479 | c = apply_alg(i->alg, cube); | ||
| 480 | sols2 = solve(c, &dranyfin_DR, &opts2); | ||
| 481 | |||
| 482 | if (sols2->len > 0) { | ||
| 483 | newb = i->alg->len + sols2->first->alg->len; | ||
| 484 | if (newb < bestlen) { | ||
| 485 | bestlen = newb; | ||
| 486 | copy_alg(i->alg, bestalg); | ||
| 487 | compose_alg(bestalg, sols2->first->alg); | ||
| 488 | } | ||
| 113 | } | 489 | } |
| 114 | stop = stop || | 490 | |
| 115 | (opts->optimal != -1 && d >= opts->optimal + optimal); | 491 | free_alglist(sols2); |
| 116 | } | 492 | } |
| 117 | 493 | ||
| 118 | /* TODO: some cleanup (free cubedata) */ | 494 | free_alglist(sols1); |
| 119 | /* TODO: actually, preparation should be done somewhere else */ | ||
| 120 | 495 | ||
| 121 | return sols; | 496 | ret = cleanup(bestalg); |
| 497 | free_alg(bestalg); | ||
| 498 | |||
| 499 | return ret; | ||
| 122 | } | 500 | } |
diff --git a/src/solve.h b/src/solve.h index 8182887..6ce6609 100644 --- a/src/solve.h +++ b/src/solve.h | |||
| @@ -2,53 +2,10 @@ | |||
| 2 | #define SOLVE_H | 2 | #define SOLVE_H |
| 3 | 3 | ||
| 4 | #include "moves.h" | 4 | #include "moves.h" |
| 5 | #include "steps.h" | ||
| 6 | #include "trans.h" | ||
| 5 | 7 | ||
| 6 | #define MAX_SOLVERS 99 | 8 | AlgList * solve(Cube cube, Step *step, SolveOptions *opts); |
| 7 | 9 | Alg * solve_2phase(Cube cube, int nthreads); | |
| 8 | typedef struct dfsarg DfsArg; | ||
| 9 | typedef struct threader Threader; | ||
| 10 | typedef struct solver Solver; | ||
| 11 | |||
| 12 | /* TODO: add solver and threader in DfsData, remove from dispatch args and similar */ | ||
| 13 | |||
| 14 | struct dfsarg { | ||
| 15 | void * cubedata; | ||
| 16 | void * threaddata; | ||
| 17 | SolveOptions * opts; | ||
| 18 | int d; | ||
| 19 | bool niss; | ||
| 20 | Alg * current_alg; | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct threader { | ||
| 24 | void (*append_sol)(Alg *, void *); | ||
| 25 | void (*dispatch)(DfsArg *, AlgList *, Solver *, Threader *); | ||
| 26 | int (*get_nsol)(void *); | ||
| 27 | /* TODO: threader should have param, like solver? */ | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct solver { | ||
| 31 | Moveset * moveset; | ||
| 32 | bool (*move_check_stop)(void *, DfsArg *, Threader *); | ||
| 33 | Alg * (*validate_solution)(void *, Alg *); | ||
| 34 | bool (*niss_makes_sense)(void *, void *, Alg *); | ||
| 35 | /* TODO: move param to somewhere where it makes more sense */ | ||
| 36 | void * param; | ||
| 37 | /* TODO: the following should be part of a generic cube description */ | ||
| 38 | /* TODO: remove alloc? */ | ||
| 39 | /* TODO: revisit apply_move, maybe apply_alg? or both? */ | ||
| 40 | void * (*alloc_cubedata)(void *); | ||
| 41 | void (*copy_cubedata)(void *, void *, void *); | ||
| 42 | void (*free_cubedata)(void *, void *); | ||
| 43 | void (*invert_cube)(void *, void *); | ||
| 44 | bool (*is_solved)(void *, void *); | ||
| 45 | void (*apply_move)(void *, void *, Move); | ||
| 46 | /* TODO: remove dependence on Cube, preparation should be done before */ | ||
| 47 | void * (*prepare_cube)(void *, Cube *); | ||
| 48 | }; | ||
| 49 | |||
| 50 | void dfs(DfsArg *, Solver *, Threader *); | ||
| 51 | /* TODO: remove dependence on Cube, preparation should be done before */ | ||
| 52 | AlgList * solve(Cube *, SolveOptions *, Solver **, Threader *); | ||
| 53 | 10 | ||
| 54 | #endif | 11 | #endif |
diff --git a/src/solver_step.c b/src/solver_step.c deleted file mode 100644 index 52fa347..0000000 --- a/src/solver_step.c +++ /dev/null | |||
| @@ -1,306 +0,0 @@ | |||
| 1 | #include "solver_step.h" | ||
| 2 | |||
| 3 | typedef struct { | ||
| 4 | Cube * cube; | ||
| 5 | uint64_t * val; | ||
| 6 | Trans * t; | ||
| 7 | } CubeData; | ||
| 8 | |||
| 9 | static void apply_move_cubedata(void *, void *, Move); | ||
| 10 | static void init_indexes(Step *, CubeData *); | ||
| 11 | static void * prepare_cube(void *, Cube *); | ||
| 12 | static bool move_check_stop_eager(void *, DfsArg *, Threader *); | ||
| 13 | static bool move_check_stop_lazy(void *, DfsArg *, Threader *); | ||
| 14 | static bool move_check_stop_nonsol(void *, DfsArg *, Threader *); | ||
| 15 | static bool is_solved_step(void *, void *); | ||
| 16 | static Alg * validate_solution(void *, Alg *); | ||
| 17 | static void * alloc_cubedata(void *); | ||
| 18 | static void copy_cubedata(void *, void *, void *); | ||
| 19 | static void free_cubedata(void *, void *); | ||
| 20 | static void invert_cubedata(void *, void *); | ||
| 21 | static bool niss_makes_sense(void *, void *, Alg *); | ||
| 22 | static Solver * new_stepsolver_nocheckstop(Step *step); | ||
| 23 | |||
| 24 | static void | ||
| 25 | apply_move_cubedata(void *param, void *cubedata, Move m) | ||
| 26 | { | ||
| 27 | Step *s = (Step *)param; | ||
| 28 | CubeData *data = (CubeData *)cubedata; | ||
| 29 | |||
| 30 | Trans tt; | ||
| 31 | for (int i = 0; i < s->n_coord; i++) { | ||
| 32 | Move mm = transform_move(data->t[i], m); | ||
| 33 | data->val[i] = move_coord(s->coord[i], mm, data->val[i], &tt); | ||
| 34 | data->t[i] = transform_trans(tt, data->t[i]); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | static void | ||
| 39 | init_indexes(Step *step, CubeData *data) | ||
| 40 | { | ||
| 41 | int i; | ||
| 42 | Cube moved; | ||
| 43 | Trans t, tt; | ||
| 44 | |||
| 45 | for (i = 0; i < step->n_coord; i++) { | ||
| 46 | t = step->coord_trans[i]; | ||
| 47 | copy_cube(data->cube, &moved); | ||
| 48 | apply_trans(t, &moved); | ||
| 49 | data->val[i] = index_coord(step->coord[i], &moved, &tt); | ||
| 50 | data->t[i] = transform_trans(tt, t); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | static void * | ||
| 55 | prepare_cube(void *param, Cube *cube) | ||
| 56 | { | ||
| 57 | int i; | ||
| 58 | Step *s; | ||
| 59 | CubeData *data; | ||
| 60 | |||
| 61 | s = (Step *)param; | ||
| 62 | |||
| 63 | for (i = 0; i < s->n_coord; i++) { | ||
| 64 | s->pd[i] = malloc(sizeof(PruneData)); | ||
| 65 | s->pd[i]->moveset = s->moveset; | ||
| 66 | /* TODO: check if moveset initialization works fine, | ||
| 67 | e.g. if there is a variable to save the initialized status | ||
| 68 | or if it gets initialized multiple times */ | ||
| 69 | init_moveset(s->moveset); | ||
| 70 | s->pd[i]->coord = s->coord[i]; | ||
| 71 | gen_coord(s->coord[i]); | ||
| 72 | s->pd[i]->compact = s->pd_compact[i]; | ||
| 73 | s->pd[i] = genptable(s->pd[i], 4); /* TODO: threads */ | ||
| 74 | } | ||
| 75 | |||
| 76 | data = alloc_cubedata(param); | ||
| 77 | data->cube = malloc(sizeof(Cube)); | ||
| 78 | copy_cube(cube, data->cube); | ||
| 79 | init_indexes(s, data); | ||
| 80 | |||
| 81 | return data; | ||
| 82 | } | ||
| 83 | |||
| 84 | static bool | ||
| 85 | move_check_stop_eager(void *param, DfsArg *arg, Threader *threader) | ||
| 86 | { | ||
| 87 | int nsol; | ||
| 88 | |||
| 89 | if (move_check_stop_nonsol(param, arg, threader)) | ||
| 90 | return true; | ||
| 91 | |||
| 92 | nsol = threader->get_nsol(arg->threaddata); | ||
| 93 | return nsol >= arg->opts->max_solutions; | ||
| 94 | } | ||
| 95 | |||
| 96 | static bool | ||
| 97 | move_check_stop_lazy(void *param, DfsArg *arg, Threader *threader) | ||
| 98 | { | ||
| 99 | int nsol; | ||
| 100 | |||
| 101 | nsol = threader->get_nsol(arg->threaddata); | ||
| 102 | if (nsol >= arg->opts->max_solutions) | ||
| 103 | return true; | ||
| 104 | |||
| 105 | return move_check_stop_nonsol(param, arg, threader); | ||
| 106 | } | ||
| 107 | |||
| 108 | /* TODO: split in 2 (nissable / non-nissable) and only move cube | ||
| 109 | when nissable */ | ||
| 110 | static bool | ||
| 111 | move_check_stop_nonsol(void *param, DfsArg *arg, Threader *threader) | ||
| 112 | { | ||
| 113 | int i, goal, bound; | ||
| 114 | Move mm, lastmove; | ||
| 115 | Trans tt = uf; | ||
| 116 | CubeData *data; | ||
| 117 | Step *s; | ||
| 118 | |||
| 119 | s = (Step *)param; | ||
| 120 | data = (CubeData *)arg->cubedata; | ||
| 121 | |||
| 122 | |||
| 123 | bound = 0; | ||
| 124 | goal = arg->d - arg->current_alg->len; | ||
| 125 | /* TODO: check if len is 0 */ | ||
| 126 | lastmove = arg->current_alg->move[arg->current_alg->len-1]; | ||
| 127 | for (i = 0; i < s->n_coord; i++) { | ||
| 128 | mm = transform_move(data->t[i], lastmove); | ||
| 129 | data->val[i] = move_coord(s->coord[i], mm, data->val[i], &tt); | ||
| 130 | data->t[i] = transform_trans(tt, data->t[i]); | ||
| 131 | |||
| 132 | bound = MAX(bound, ptableval(s->pd[i], data->val[i])); | ||
| 133 | if (arg->opts->can_niss && !arg->niss) | ||
| 134 | bound = MIN(1, bound); | ||
| 135 | |||
| 136 | if (bound > goal) { | ||
| 137 | return true; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | if (arg->opts->can_niss && !arg->niss) | ||
| 141 | apply_move(lastmove, data->cube); | ||
| 142 | |||
| 143 | return false; | ||
| 144 | } | ||
| 145 | |||
| 146 | static bool | ||
| 147 | is_solved_step(void *param, void *cubedata) | ||
| 148 | { | ||
| 149 | int i; | ||
| 150 | Step *s; | ||
| 151 | CubeData *data; | ||
| 152 | |||
| 153 | s = (Step *)param; | ||
| 154 | data = (CubeData *)cubedata; | ||
| 155 | |||
| 156 | for (i = 0; i < s->n_coord; i++) | ||
| 157 | if (data->val[i] != 0) | ||
| 158 | return false; | ||
| 159 | |||
| 160 | return true; | ||
| 161 | } | ||
| 162 | |||
| 163 | static Alg * | ||
| 164 | validate_solution(void *param, Alg *alg) | ||
| 165 | { | ||
| 166 | return ((Step *)param)->is_valid(alg); | ||
| 167 | } | ||
| 168 | |||
| 169 | static void * | ||
| 170 | alloc_cubedata(void *param) | ||
| 171 | { | ||
| 172 | Step *s; | ||
| 173 | CubeData *data; | ||
| 174 | |||
| 175 | s = (Step *)param; | ||
| 176 | |||
| 177 | data = malloc(sizeof(CubeData)); | ||
| 178 | /* We do not need to allocate a cube */ | ||
| 179 | data->val = malloc(s->n_coord * sizeof(uint64_t)); | ||
| 180 | data->t = malloc(s->n_coord * sizeof(Trans)); | ||
| 181 | |||
| 182 | return data; | ||
| 183 | } | ||
| 184 | |||
| 185 | static void | ||
| 186 | copy_cubedata(void *param, void *src, void *dst) | ||
| 187 | { | ||
| 188 | int i; | ||
| 189 | Step *s; | ||
| 190 | CubeData *newdata, *olddata; | ||
| 191 | |||
| 192 | s = (Step *)param; | ||
| 193 | olddata = (CubeData *)src; | ||
| 194 | newdata = (CubeData *)dst; | ||
| 195 | |||
| 196 | /* TODO: do not copy if not nissable */ | ||
| 197 | newdata->cube = malloc(sizeof(Cube)); | ||
| 198 | copy_cube(olddata->cube, newdata->cube); | ||
| 199 | for (i = 0; i < s->n_coord; i++) { | ||
| 200 | newdata->val[i] = olddata->val[i]; | ||
| 201 | newdata->t[i] = olddata->t[i]; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | static void | ||
| 206 | free_cubedata(void *param, void *cubedata) | ||
| 207 | { | ||
| 208 | CubeData *data; | ||
| 209 | |||
| 210 | data = (CubeData *)cubedata; | ||
| 211 | |||
| 212 | free(data->t); | ||
| 213 | free(data->val); | ||
| 214 | free(data->cube); | ||
| 215 | free(data); | ||
| 216 | } | ||
| 217 | |||
| 218 | static void | ||
| 219 | invert_cubedata(void *param, void *cubedata) | ||
| 220 | { | ||
| 221 | Step *s; | ||
| 222 | CubeData *data; | ||
| 223 | |||
| 224 | s = (Step *)param; | ||
| 225 | data = (CubeData *)cubedata; | ||
| 226 | |||
| 227 | invert_cube(data->cube); | ||
| 228 | init_indexes(s, data); | ||
| 229 | } | ||
| 230 | |||
| 231 | static bool | ||
| 232 | niss_makes_sense(void *param, void *cubedata, Alg *alg) | ||
| 233 | { | ||
| 234 | Step *s; | ||
| 235 | CubeData *data; | ||
| 236 | |||
| 237 | s = (Step *)param; | ||
| 238 | data = (CubeData *)cubedata; | ||
| 239 | |||
| 240 | if (s->final) | ||
| 241 | return false; | ||
| 242 | |||
| 243 | if (alg->len_normal == 0) | ||
| 244 | return true; | ||
| 245 | |||
| 246 | Move m = inverse_move(alg->move_normal[alg->len_normal-1]); | ||
| 247 | for (int i = 0; i < s->n_coord; i++) { | ||
| 248 | Move mm = transform_move(data->t[i], m); | ||
| 249 | uint64_t u = move_coord(s->coord[i], mm, 0, NULL); | ||
| 250 | if (ptableval(s->pd[i], u) > 0) | ||
| 251 | return true; | ||
| 252 | } | ||
| 253 | |||
| 254 | return false; | ||
| 255 | } | ||
| 256 | |||
| 257 | static Solver * | ||
| 258 | new_stepsolver_nocheckstop(Step *step) | ||
| 259 | { | ||
| 260 | Solver *solver; | ||
| 261 | |||
| 262 | solver = malloc(sizeof(Solver)); | ||
| 263 | |||
| 264 | solver->moveset = step->moveset; | ||
| 265 | solver->param = step; | ||
| 266 | |||
| 267 | solver->apply_move = apply_move_cubedata; | ||
| 268 | solver->prepare_cube = prepare_cube; | ||
| 269 | solver->is_solved = is_solved_step; | ||
| 270 | solver->validate_solution = validate_solution; | ||
| 271 | solver->alloc_cubedata = alloc_cubedata; | ||
| 272 | solver->copy_cubedata = copy_cubedata; | ||
| 273 | solver->free_cubedata = free_cubedata; | ||
| 274 | solver->invert_cube = invert_cubedata; | ||
| 275 | solver->niss_makes_sense = niss_makes_sense; | ||
| 276 | |||
| 277 | return solver; | ||
| 278 | } | ||
| 279 | |||
| 280 | Solver * | ||
| 281 | new_stepsolver_eager(Step *step) | ||
| 282 | { | ||
| 283 | Solver *solver; | ||
| 284 | |||
| 285 | solver = new_stepsolver_nocheckstop(step); | ||
| 286 | solver->move_check_stop = move_check_stop_eager; | ||
| 287 | |||
| 288 | return solver; | ||
| 289 | } | ||
| 290 | |||
| 291 | Solver * | ||
| 292 | new_stepsolver_lazy(Step *step) | ||
| 293 | { | ||
| 294 | Solver *solver; | ||
| 295 | |||
| 296 | solver = new_stepsolver_nocheckstop(step); | ||
| 297 | solver->move_check_stop = move_check_stop_lazy; | ||
| 298 | |||
| 299 | return solver; | ||
| 300 | } | ||
| 301 | |||
| 302 | void | ||
| 303 | free_stepsolver(Solver *solver) | ||
| 304 | { | ||
| 305 | free(solver); | ||
| 306 | } | ||
diff --git a/src/solver_step.h b/src/solver_step.h deleted file mode 100644 index f68d077..0000000 --- a/src/solver_step.h +++ /dev/null | |||
| @@ -1,12 +0,0 @@ | |||
| 1 | #ifndef SOLVER_STEP_H | ||
| 2 | #define SOLVER_STEP_H | ||
| 3 | |||
| 4 | #include "cube.h" | ||
| 5 | #include "solve.h" | ||
| 6 | #include "steps.h" | ||
| 7 | |||
| 8 | Solver *new_stepsolver_eager(Step *); | ||
| 9 | Solver *new_stepsolver_lazy(Step *); | ||
| 10 | void free_stepsolver(Solver *); | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/src/steps.c b/src/steps.c index cdba763..3189811 100644 --- a/src/steps.c +++ b/src/steps.c | |||
| @@ -1,117 +1,1376 @@ | |||
| 1 | #define STEPS_C | ||
| 2 | |||
| 3 | #include "steps.h" | 1 | #include "steps.h" |
| 4 | 2 | ||
| 5 | /* TODO: change all checkers to use coordinates! */ | 3 | #define UPDATECHECKSTOP(a, b, c) if ((a=(MAX((a),(b))))>(c)) return (a); |
| 4 | |||
| 5 | /* Checkers, estimators and validators ***************************************/ | ||
| 6 | |||
| 7 | static bool check_centers(Cube cube); | ||
| 8 | static bool check_coud_HTM(Cube cube); | ||
| 9 | static bool check_coud_URF(Cube cube); | ||
| 10 | static bool check_corners_HTM(Cube cube); | ||
| 11 | static bool check_corners_URF(Cube cube); | ||
| 12 | static bool check_cornershtr(Cube cube); | ||
| 13 | static bool check_eofb(Cube cube); | ||
| 14 | static bool check_drud(Cube cube); | ||
| 15 | static bool check_htr(Cube cube); | ||
| 16 | |||
| 17 | static int estimate_eofb_HTM(DfsArg *arg); | ||
| 18 | static int estimate_coud_HTM(DfsArg *arg); | ||
| 19 | static int estimate_coud_URF(DfsArg *arg); | ||
| 20 | static int estimate_corners_HTM(DfsArg *arg); | ||
| 21 | static int estimate_cornershtr_HTM(DfsArg *arg); | ||
| 22 | static int estimate_corners_URF(DfsArg *arg); | ||
| 23 | static int estimate_cornershtr_URF(DfsArg *arg); | ||
| 24 | static int estimate_drud_HTM(DfsArg *arg); | ||
| 25 | static int estimate_drud_eofb(DfsArg *arg); | ||
| 26 | static int estimate_dr_eofb(DfsArg *arg); | ||
| 27 | static int estimate_drudfin_drud(DfsArg *arg); | ||
| 28 | static int estimate_htr_drud(DfsArg *arg); | ||
| 29 | static int estimate_htrfin_htr(DfsArg *arg); | ||
| 30 | static int estimate_nxopt31_HTM(DfsArg *arg); | ||
| 31 | static int estimate_light_HTM(DfsArg *arg); | ||
| 32 | |||
| 33 | static int estimate_nxoptlike(DfsArg *arg, PruneData *pd); | ||
| 34 | |||
| 35 | static bool always_valid(Alg *alg); | ||
| 36 | static bool validate_singlecw_ending(Alg *alg); | ||
| 37 | |||
| 38 | /* Pre-transformation detectors **********************************************/ | ||
| 39 | |||
| 40 | static int detect_pretrans_eofb(Cube cube, Trans *ret); | ||
| 41 | static int detect_pretrans_drud(Cube cube, Trans *ret); | ||
| 42 | static int detect_pretrans_void_3axis(Cube cube, Trans *ret); | ||
| 43 | |||
| 44 | /* Messages for when cube is not ready ***************************************/ | ||
| 45 | |||
| 46 | static char check_centers_msg[100] = "cube must be oriented (centers solved)"; | ||
| 47 | static char check_eo_msg[100] = "EO must be solved on given axis"; | ||
| 48 | static char check_dr_msg[100] = "DR must be solved on given axis"; | ||
| 49 | static char check_htr_msg[100] = "HTR must be solved"; | ||
| 50 | static char check_drany_msg[100] = "DR must be solved on at least one axis"; | ||
| 51 | |||
| 52 | /* Steps *********************************************************************/ | ||
| 53 | |||
| 54 | /* Optimal solvers *******************/ | ||
| 55 | |||
| 56 | Step | ||
| 57 | optimal_HTM = { | ||
| 58 | .shortname = "optimal", | ||
| 59 | .name = "Optimal solve (in HTM)", | ||
| 60 | |||
| 61 | .final = true, | ||
| 62 | .is_done = is_solved, | ||
| 63 | .estimate = estimate_nxopt31_HTM, | ||
| 64 | .ready = check_centers, | ||
| 65 | .ready_msg = check_centers_msg, | ||
| 66 | .is_valid = always_valid, | ||
| 67 | .moveset = &moveset_HTM, | ||
| 68 | |||
| 69 | .pre_trans = uf, | ||
| 70 | |||
| 71 | .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, | ||
| 72 | .ntables = 2, | ||
| 73 | }; | ||
| 74 | |||
| 75 | Step | ||
| 76 | optimal_light_HTM = { | ||
| 77 | .shortname = "light", | ||
| 78 | .name = "Optimal solve (in HTM), small table (500Mb RAM total)", | ||
| 79 | |||
| 80 | .final = true, | ||
| 81 | .is_done = is_solved, | ||
| 82 | .estimate = estimate_light_HTM, | ||
| 83 | .ready = check_centers, | ||
| 84 | .ready_msg = check_centers_msg, | ||
| 85 | .is_valid = always_valid, | ||
| 86 | .moveset = &moveset_HTM, | ||
| 87 | |||
| 88 | .pre_trans = uf, | ||
| 89 | |||
| 90 | .tables = {&pd_drud_sym16_HTM, &pd_corners_HTM}, | ||
| 91 | .ntables = 2, | ||
| 92 | }; | ||
| 93 | |||
| 94 | /* Optimal after EO ******************/ | ||
| 95 | |||
| 96 | Step | ||
| 97 | eofin_eo = { | ||
| 98 | .shortname = "eofin", | ||
| 99 | .name = "Optimal solve after EO without breaking EO (detected)", | ||
| 100 | |||
| 101 | .final = true, | ||
| 102 | .is_done = is_solved, | ||
| 103 | .estimate = estimate_nxopt31_HTM, | ||
| 104 | .ready = check_eofb, | ||
| 105 | .ready_msg = check_eo_msg, | ||
| 106 | .is_valid = always_valid, | ||
| 107 | .moveset = &moveset_eofb, | ||
| 108 | |||
| 109 | .detect = detect_pretrans_eofb, | ||
| 110 | |||
| 111 | .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, | ||
| 112 | .ntables = 2, | ||
| 113 | }; | ||
| 114 | |||
| 115 | Step | ||
| 116 | eofbfin_eofb = { | ||
| 117 | .shortname = "eofbfin", | ||
| 118 | .name = "Optimal after EO on F/B without breaking EO", | ||
| 119 | |||
| 120 | .final = true, | ||
| 121 | .is_done = is_solved, | ||
| 122 | .estimate = estimate_nxopt31_HTM, | ||
| 123 | .ready = check_eofb, | ||
| 124 | .ready_msg = check_eo_msg, | ||
| 125 | .is_valid = always_valid, | ||
| 126 | .moveset = &moveset_eofb, | ||
| 127 | |||
| 128 | .pre_trans = uf, | ||
| 129 | |||
| 130 | .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, | ||
| 131 | .ntables = 2, | ||
| 132 | }; | ||
| 133 | |||
| 134 | Step | ||
| 135 | eorlfin_eorl = { | ||
| 136 | .shortname = "eorlfin", | ||
| 137 | .name = "Optimal after EO on R/L without breaking EO", | ||
| 138 | |||
| 139 | .final = true, | ||
| 140 | .is_done = is_solved, | ||
| 141 | .estimate = estimate_nxopt31_HTM, | ||
| 142 | .ready = check_eofb, | ||
| 143 | .ready_msg = check_eo_msg, | ||
| 144 | .is_valid = always_valid, | ||
| 145 | .moveset = &moveset_eofb, | ||
| 146 | |||
| 147 | .pre_trans = ur, | ||
| 148 | |||
| 149 | .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, | ||
| 150 | .ntables = 2, | ||
| 151 | }; | ||
| 152 | |||
| 153 | Step | ||
| 154 | eoudfin_eoud = { | ||
| 155 | .shortname = "eoudfin", | ||
| 156 | .name = "Optimal after EO on U/D without breaking EO", | ||
| 157 | |||
| 158 | .final = true, | ||
| 159 | .is_done = is_solved, | ||
| 160 | .estimate = estimate_nxopt31_HTM, | ||
| 161 | .ready = check_eofb, | ||
| 162 | .ready_msg = check_eo_msg, | ||
| 163 | .is_valid = always_valid, | ||
| 164 | .moveset = &moveset_eofb, | ||
| 165 | |||
| 166 | .pre_trans = fd, | ||
| 167 | |||
| 168 | .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, | ||
| 169 | .ntables = 2, | ||
| 170 | }; | ||
| 171 | |||
| 172 | /* EO steps **************************/ | ||
| 173 | Step | ||
| 174 | eoany_HTM = { | ||
| 175 | .shortname = "eo", | ||
| 176 | .name = "EO on any axis", | ||
| 177 | |||
| 178 | .final = false, | ||
| 179 | .is_done = check_eofb, | ||
| 180 | .estimate = estimate_eofb_HTM, | ||
| 181 | .ready = check_centers, | ||
| 182 | .ready_msg = check_centers_msg, | ||
| 183 | .is_valid = validate_singlecw_ending, | ||
| 184 | .moveset = &moveset_HTM, | ||
| 185 | |||
| 186 | .detect = detect_pretrans_void_3axis, | ||
| 187 | |||
| 188 | .tables = {&pd_eofb_HTM}, | ||
| 189 | .ntables = 1, | ||
| 190 | }; | ||
| 191 | |||
| 192 | Step | ||
| 193 | eofb_HTM = { | ||
| 194 | .shortname = "eofb", | ||
| 195 | .name = "EO on F/B", | ||
| 196 | |||
| 197 | .final = false, | ||
| 198 | .is_done = check_eofb, | ||
| 199 | .estimate = estimate_eofb_HTM, | ||
| 200 | .ready = check_centers, | ||
| 201 | .ready_msg = check_centers_msg, | ||
| 202 | .is_valid = validate_singlecw_ending, | ||
| 203 | .moveset = &moveset_HTM, | ||
| 204 | |||
| 205 | .pre_trans = uf, | ||
| 206 | |||
| 207 | .tables = {&pd_eofb_HTM}, | ||
| 208 | .ntables = 1, | ||
| 209 | }; | ||
| 210 | |||
| 211 | Step | ||
| 212 | eorl_HTM = { | ||
| 213 | .shortname = "eorl", | ||
| 214 | .name = "EO on R/L", | ||
| 215 | |||
| 216 | .final = false, | ||
| 217 | .is_done = check_eofb, | ||
| 218 | .estimate = estimate_eofb_HTM, | ||
| 219 | .ready = check_centers, | ||
| 220 | .ready_msg = check_centers_msg, | ||
| 221 | .is_valid = validate_singlecw_ending, | ||
| 222 | .moveset = &moveset_HTM, | ||
| 223 | |||
| 224 | .pre_trans = ur, | ||
| 225 | |||
| 226 | .tables = {&pd_eofb_HTM}, | ||
| 227 | .ntables = 1, | ||
| 228 | }; | ||
| 229 | |||
| 230 | Step | ||
| 231 | eoud_HTM = { | ||
| 232 | .shortname = "eoud", | ||
| 233 | .name = "EO on U/D", | ||
| 234 | |||
| 235 | .final = false, | ||
| 236 | .is_done = check_eofb, | ||
| 237 | .estimate = estimate_eofb_HTM, | ||
| 238 | .ready = check_centers, | ||
| 239 | .ready_msg = check_centers_msg, | ||
| 240 | .is_valid = validate_singlecw_ending, | ||
| 241 | .moveset = &moveset_HTM, | ||
| 242 | |||
| 243 | .pre_trans = fd, | ||
| 244 | |||
| 245 | .tables = {&pd_eofb_HTM}, | ||
| 246 | .ntables = 1, | ||
| 247 | }; | ||
| 248 | |||
| 249 | /* CO steps **************************/ | ||
| 250 | Step | ||
| 251 | coany_HTM = { | ||
| 252 | .shortname = "co", | ||
| 253 | .name = "CO on any axis", | ||
| 254 | |||
| 255 | .final = false, | ||
| 256 | .is_done = check_coud_HTM, | ||
| 257 | .estimate = estimate_coud_HTM, | ||
| 258 | .ready = NULL, | ||
| 259 | .is_valid = validate_singlecw_ending, | ||
| 260 | .moveset = &moveset_HTM, | ||
| 261 | |||
| 262 | .detect = detect_pretrans_void_3axis, | ||
| 263 | |||
| 264 | .tables = {&pd_coud_HTM}, | ||
| 265 | .ntables = 1, | ||
| 266 | }; | ||
| 267 | |||
| 268 | Step | ||
| 269 | coud_HTM = { | ||
| 270 | .shortname = "coud", | ||
| 271 | .name = "CO on U/D", | ||
| 272 | |||
| 273 | .final = false, | ||
| 274 | .is_done = check_coud_HTM, | ||
| 275 | .estimate = estimate_coud_HTM, | ||
| 276 | .ready = NULL, | ||
| 277 | .is_valid = validate_singlecw_ending, | ||
| 278 | .moveset = &moveset_HTM, | ||
| 279 | |||
| 280 | .pre_trans = uf, | ||
| 281 | |||
| 282 | .tables = {&pd_coud_HTM}, | ||
| 283 | .ntables = 1, | ||
| 284 | }; | ||
| 285 | |||
| 286 | Step | ||
| 287 | corl_HTM = { | ||
| 288 | .shortname = "corl", | ||
| 289 | .name = "CO on R/L", | ||
| 290 | |||
| 291 | .final = false, | ||
| 292 | .is_done = check_coud_HTM, | ||
| 293 | .estimate = estimate_coud_HTM, | ||
| 294 | .ready = NULL, | ||
| 295 | .is_valid = validate_singlecw_ending, | ||
| 296 | .moveset = &moveset_HTM, | ||
| 297 | |||
| 298 | .pre_trans = rf, | ||
| 299 | |||
| 300 | .tables = {&pd_coud_HTM}, | ||
| 301 | .ntables = 1, | ||
| 302 | }; | ||
| 303 | |||
| 304 | Step | ||
| 305 | cofb_HTM = { | ||
| 306 | .shortname = "cofb", | ||
| 307 | .name = "CO on F/B", | ||
| 308 | |||
| 309 | .final = false, | ||
| 310 | .is_done = check_coud_HTM, | ||
| 311 | .estimate = estimate_coud_HTM, | ||
| 312 | .ready = NULL, | ||
| 313 | .is_valid = validate_singlecw_ending, | ||
| 314 | .moveset = &moveset_HTM, | ||
| 315 | |||
| 316 | .pre_trans = fd, | ||
| 317 | |||
| 318 | .tables = {&pd_coud_HTM}, | ||
| 319 | .ntables = 1, | ||
| 320 | }; | ||
| 321 | |||
| 322 | Step | ||
| 323 | coany_URF = { | ||
| 324 | .shortname = "co-URF", | ||
| 325 | .name = "CO any axis (URF moveset)", | ||
| 326 | |||
| 327 | .final = false, | ||
| 328 | .is_done = check_coud_URF, | ||
| 329 | .estimate = estimate_coud_URF, | ||
| 330 | .ready = NULL, | ||
| 331 | .is_valid = validate_singlecw_ending, | ||
| 332 | .moveset = &moveset_URF, | ||
| 333 | |||
| 334 | .detect = detect_pretrans_void_3axis, | ||
| 335 | |||
| 336 | .tables = {&pd_coud_HTM}, | ||
| 337 | .ntables = 1, | ||
| 338 | }; | ||
| 339 | |||
| 340 | Step | ||
| 341 | coud_URF = { | ||
| 342 | .shortname = "coud-URF", | ||
| 343 | .name = "CO on U/D (URF moveset)", | ||
| 344 | |||
| 345 | .final = false, | ||
| 346 | .is_done = check_coud_URF, | ||
| 347 | .estimate = estimate_coud_URF, | ||
| 348 | .ready = NULL, | ||
| 349 | .is_valid = validate_singlecw_ending, | ||
| 350 | .moveset = &moveset_URF, | ||
| 351 | |||
| 352 | .pre_trans = uf, | ||
| 353 | |||
| 354 | .tables = {&pd_coud_HTM}, | ||
| 355 | .ntables = 1, | ||
| 356 | }; | ||
| 357 | |||
| 358 | Step | ||
| 359 | corl_URF = { | ||
| 360 | .shortname = "corl-URF", | ||
| 361 | .name = "CO on R/L (URF moveset)", | ||
| 362 | |||
| 363 | .final = false, | ||
| 364 | .is_done = check_coud_URF, | ||
| 365 | .estimate = estimate_coud_URF, | ||
| 366 | .ready = NULL, | ||
| 367 | .is_valid = validate_singlecw_ending, | ||
| 368 | .moveset = &moveset_URF, | ||
| 369 | |||
| 370 | .pre_trans = rf, | ||
| 371 | |||
| 372 | .tables = {&pd_coud_HTM}, | ||
| 373 | .ntables = 1, | ||
| 374 | }; | ||
| 375 | |||
| 376 | Step | ||
| 377 | cofb_URF = { | ||
| 378 | .shortname = "cofb-URF", | ||
| 379 | .name = "CO on F/B (URF moveset)", | ||
| 380 | |||
| 381 | .final = false, | ||
| 382 | .is_done = check_coud_URF, | ||
| 383 | .estimate = estimate_coud_URF, | ||
| 384 | .ready = NULL, | ||
| 385 | .is_valid = validate_singlecw_ending, | ||
| 386 | .moveset = &moveset_URF, | ||
| 387 | |||
| 388 | .pre_trans = fd, | ||
| 389 | |||
| 390 | .tables = {&pd_coud_HTM}, | ||
| 391 | .ntables = 1, | ||
| 392 | }; | ||
| 393 | |||
| 394 | /* Misc corner steps *****************/ | ||
| 395 | Step | ||
| 396 | cornershtr_HTM = { | ||
| 397 | .shortname = "chtr", | ||
| 398 | .name = "Solve corners to HTR state", | ||
| 399 | |||
| 400 | .final = false, | ||
| 401 | .is_done = check_cornershtr, | ||
| 402 | .estimate = estimate_cornershtr_HTM, | ||
| 403 | .ready = NULL, | ||
| 404 | .is_valid = validate_singlecw_ending, | ||
| 405 | .moveset = &moveset_HTM, | ||
| 406 | |||
| 407 | .pre_trans = uf, | ||
| 408 | |||
| 409 | .tables = {&pd_cornershtr_HTM}, | ||
| 410 | .ntables = 1, | ||
| 411 | }; | ||
| 412 | |||
| 413 | Step | ||
| 414 | cornershtr_URF = { | ||
| 415 | .shortname = "chtr-URF", | ||
| 416 | .name = "Solve corners to HTR state (URF moveset)", | ||
| 417 | |||
| 418 | .final = false, | ||
| 419 | .is_done = check_cornershtr, | ||
| 420 | .estimate = estimate_cornershtr_URF, | ||
| 421 | .ready = NULL, | ||
| 422 | .is_valid = validate_singlecw_ending, | ||
| 423 | .moveset = &moveset_URF, | ||
| 424 | |||
| 425 | .pre_trans = uf, | ||
| 426 | |||
| 427 | .tables = {&pd_cornershtr_HTM}, | ||
| 428 | .ntables = 1, | ||
| 429 | }; | ||
| 430 | |||
| 431 | Step | ||
| 432 | corners_HTM = { | ||
| 433 | .shortname = "corners", | ||
| 434 | .name = "Solve corners", | ||
| 435 | |||
| 436 | .final = true, | ||
| 437 | .is_done = check_corners_HTM, | ||
| 438 | .estimate = estimate_corners_HTM, | ||
| 439 | .ready = NULL, | ||
| 440 | .is_valid = always_valid, | ||
| 441 | .moveset = &moveset_HTM, | ||
| 442 | |||
| 443 | .pre_trans = uf, | ||
| 444 | |||
| 445 | .tables = {&pd_corners_HTM}, | ||
| 446 | .ntables = 1, | ||
| 447 | }; | ||
| 448 | |||
| 449 | Step | ||
| 450 | corners_URF = { | ||
| 451 | .shortname = "corners-URF", | ||
| 452 | .name = "Solve corners (URF moveset)", | ||
| 453 | |||
| 454 | .final = true, /* TODO: check if this works with reorient */ | ||
| 455 | .is_done = check_corners_URF, | ||
| 456 | .estimate = estimate_corners_URF, | ||
| 457 | .ready = NULL, | ||
| 458 | .is_valid = always_valid, | ||
| 459 | .moveset = &moveset_URF, | ||
| 460 | |||
| 461 | .pre_trans = uf, | ||
| 462 | |||
| 463 | .tables = {&pd_corners_HTM}, | ||
| 464 | .ntables = 1, | ||
| 465 | }; | ||
| 466 | |||
| 467 | /* DR steps **************************/ | ||
| 468 | Step | ||
| 469 | drany_HTM = { | ||
| 470 | .shortname = "dr", | ||
| 471 | .name = "DR on any axis", | ||
| 472 | |||
| 473 | .final = false, | ||
| 474 | .is_done = check_drud, | ||
| 475 | .estimate = estimate_drud_HTM, | ||
| 476 | .ready = check_centers, | ||
| 477 | .ready_msg = check_centers_msg, | ||
| 478 | .is_valid = validate_singlecw_ending, | ||
| 479 | .moveset = &moveset_HTM, | ||
| 480 | |||
| 481 | .detect = detect_pretrans_void_3axis, | ||
| 482 | |||
| 483 | .tables = {&pd_drud_sym16_HTM}, | ||
| 484 | .ntables = 1, | ||
| 485 | }; | ||
| 486 | |||
| 487 | Step | ||
| 488 | drud_HTM = { | ||
| 489 | .shortname = "drud", | ||
| 490 | .name = "DR on U/D", | ||
| 491 | |||
| 492 | .final = false, | ||
| 493 | .is_done = check_drud, | ||
| 494 | .estimate = estimate_drud_HTM, | ||
| 495 | .ready = check_centers, | ||
| 496 | .ready_msg = check_centers_msg, | ||
| 497 | .is_valid = validate_singlecw_ending, | ||
| 498 | .moveset = &moveset_HTM, | ||
| 499 | |||
| 500 | .pre_trans = uf, | ||
| 501 | |||
| 502 | .tables = {&pd_drud_sym16_HTM}, | ||
| 503 | .ntables = 1, | ||
| 504 | }; | ||
| 505 | |||
| 506 | Step | ||
| 507 | drrl_HTM = { | ||
| 508 | .shortname = "drrl", | ||
| 509 | .name = "DR on R/L", | ||
| 510 | |||
| 511 | .final = false, | ||
| 512 | .is_done = check_drud, | ||
| 513 | .estimate = estimate_drud_HTM, | ||
| 514 | .ready = check_centers, | ||
| 515 | .ready_msg = check_centers_msg, | ||
| 516 | .is_valid = validate_singlecw_ending, | ||
| 517 | .moveset = &moveset_HTM, | ||
| 518 | |||
| 519 | .pre_trans = rf, | ||
| 520 | |||
| 521 | .tables = {&pd_drud_sym16_HTM}, | ||
| 522 | .ntables = 1, | ||
| 523 | }; | ||
| 524 | |||
| 525 | Step | ||
| 526 | drfb_HTM = { | ||
| 527 | .shortname = "drfb", | ||
| 528 | .name = "DR on F/B", | ||
| 529 | |||
| 530 | .final = false, | ||
| 531 | .is_done = check_drud, | ||
| 532 | .estimate = estimate_drud_HTM, | ||
| 533 | .ready = check_centers, | ||
| 534 | .ready_msg = check_centers_msg, | ||
| 535 | .is_valid = validate_singlecw_ending, | ||
| 536 | .moveset = &moveset_HTM, | ||
| 537 | |||
| 538 | .pre_trans = fd, | ||
| 539 | |||
| 540 | .tables = {&pd_drud_sym16_HTM}, | ||
| 541 | .ntables = 1, | ||
| 542 | }; | ||
| 543 | |||
| 544 | /* DR from EO */ | ||
| 545 | Step | ||
| 546 | dr_eo = { | ||
| 547 | .shortname = "dr-eo", | ||
| 548 | .name = "DR without breaking EO (automatically detected)", | ||
| 549 | |||
| 550 | .final = false, | ||
| 551 | .is_done = check_drud, | ||
| 552 | .estimate = estimate_dr_eofb, | ||
| 553 | .ready = check_eofb, | ||
| 554 | .ready_msg = check_eo_msg, | ||
| 555 | .is_valid = validate_singlecw_ending, | ||
| 556 | .moveset = &moveset_eofb, | ||
| 557 | |||
| 558 | .detect = detect_pretrans_eofb, | ||
| 559 | |||
| 560 | .tables = {&pd_drud_eofb}, | ||
| 561 | .ntables = 1, | ||
| 562 | }; | ||
| 563 | |||
| 564 | Step | ||
| 565 | dr_eofb = { | ||
| 566 | .shortname = "dr-eofb", | ||
| 567 | .name = "DR on U/D or R/L without breaking EO on F/B", | ||
| 568 | |||
| 569 | .final = false, | ||
| 570 | .is_done = check_drud, | ||
| 571 | .estimate = estimate_dr_eofb, | ||
| 572 | .ready = check_eofb, | ||
| 573 | .ready_msg = check_eo_msg, | ||
| 574 | .is_valid = validate_singlecw_ending, | ||
| 575 | .moveset = &moveset_eofb, | ||
| 576 | |||
| 577 | .pre_trans = uf, | ||
| 578 | |||
| 579 | .tables = {&pd_drud_eofb}, | ||
| 580 | .ntables = 1, | ||
| 581 | }; | ||
| 582 | |||
| 583 | Step | ||
| 584 | dr_eorl = { | ||
| 585 | .shortname = "dr-eorl", | ||
| 586 | .name = "DR on U/D or F/B without breaking EO on R/L", | ||
| 587 | |||
| 588 | .final = false, | ||
| 589 | .is_done = check_drud, | ||
| 590 | .estimate = estimate_dr_eofb, | ||
| 591 | .ready = check_eofb, | ||
| 592 | .ready_msg = check_eo_msg, | ||
| 593 | .is_valid = validate_singlecw_ending, | ||
| 594 | .moveset = &moveset_eofb, | ||
| 595 | |||
| 596 | .pre_trans = ur, | ||
| 597 | |||
| 598 | .tables = {&pd_drud_eofb}, | ||
| 599 | .ntables = 1, | ||
| 600 | }; | ||
| 601 | |||
| 602 | Step | ||
| 603 | dr_eoud = { | ||
| 604 | .shortname = "dr-eoud", | ||
| 605 | .name = "DR on R/L or F/B without breaking EO on U/D", | ||
| 606 | |||
| 607 | .final = false, | ||
| 608 | .is_done = check_drud, | ||
| 609 | .estimate = estimate_dr_eofb, | ||
| 610 | .ready = check_eofb, | ||
| 611 | .ready_msg = check_eo_msg, | ||
| 612 | .is_valid = validate_singlecw_ending, | ||
| 613 | .moveset = &moveset_eofb, | ||
| 614 | |||
| 615 | .pre_trans = fd, | ||
| 616 | |||
| 617 | .tables = {&pd_drud_eofb}, | ||
| 618 | .ntables = 1, | ||
| 619 | }; | ||
| 620 | |||
| 621 | Step | ||
| 622 | drud_eofb = { | ||
| 623 | .shortname = "drud-eofb", | ||
| 624 | .name = "DR on U/D without breaking EO on F/B", | ||
| 625 | |||
| 626 | .final = false, | ||
| 627 | .is_done = check_drud, | ||
| 628 | .estimate = estimate_drud_eofb, | ||
| 629 | .ready = check_eofb, | ||
| 630 | .ready_msg = check_eo_msg, | ||
| 631 | .is_valid = validate_singlecw_ending, | ||
| 632 | .moveset = &moveset_eofb, | ||
| 633 | |||
| 634 | .pre_trans = uf, | ||
| 635 | |||
| 636 | .tables = {&pd_drud_eofb}, | ||
| 637 | .ntables = 1, | ||
| 638 | }; | ||
| 639 | |||
| 640 | Step | ||
| 641 | drrl_eofb = { | ||
| 642 | .shortname = "drrl-eofb", | ||
| 643 | .name = "DR on R/L without breaking EO on F/B", | ||
| 644 | |||
| 645 | .final = false, | ||
| 646 | .is_done = check_drud, | ||
| 647 | .estimate = estimate_drud_eofb, | ||
| 648 | .ready = check_eofb, | ||
| 649 | .ready_msg = check_eo_msg, | ||
| 650 | .is_valid = validate_singlecw_ending, | ||
| 651 | .moveset = &moveset_eofb, | ||
| 652 | |||
| 653 | .pre_trans = rf, | ||
| 654 | |||
| 655 | .tables = {&pd_drud_eofb}, | ||
| 656 | .ntables = 1, | ||
| 657 | }; | ||
| 658 | |||
| 659 | Step | ||
| 660 | drud_eorl = { | ||
| 661 | .shortname = "drud-eorl", | ||
| 662 | .name = "DR on U/D without breaking EO on R/L", | ||
| 663 | |||
| 664 | .final = false, | ||
| 665 | .is_done = check_drud, | ||
| 666 | .estimate = estimate_drud_eofb, | ||
| 667 | .ready = check_eofb, | ||
| 668 | .ready_msg = check_eo_msg, | ||
| 669 | .is_valid = validate_singlecw_ending, | ||
| 670 | .moveset = &moveset_eofb, | ||
| 671 | |||
| 672 | .pre_trans = ur, | ||
| 673 | |||
| 674 | .tables = {&pd_drud_eofb}, | ||
| 675 | .ntables = 1, | ||
| 676 | }; | ||
| 677 | |||
| 678 | Step | ||
| 679 | drfb_eorl = { | ||
| 680 | .shortname = "drfb-eorl", | ||
| 681 | .name = "DR on F/B without breaking EO on R/L", | ||
| 682 | |||
| 683 | .final = false, | ||
| 684 | .is_done = check_drud, | ||
| 685 | .estimate = estimate_drud_eofb, | ||
| 686 | .ready = check_eofb, | ||
| 687 | .ready_msg = check_eo_msg, | ||
| 688 | .is_valid = validate_singlecw_ending, | ||
| 689 | .moveset = &moveset_eofb, | ||
| 690 | |||
| 691 | .pre_trans = fr, | ||
| 692 | |||
| 693 | .tables = {&pd_drud_eofb}, | ||
| 694 | .ntables = 1, | ||
| 695 | }; | ||
| 696 | |||
| 697 | Step | ||
| 698 | drfb_eoud = { | ||
| 699 | .shortname = "drfb-eoud", | ||
| 700 | .name = "DR on F/B without breaking EO on U/D", | ||
| 701 | |||
| 702 | .final = false, | ||
| 703 | .is_done = check_drud, | ||
| 704 | .estimate = estimate_drud_eofb, | ||
| 705 | .ready = check_eofb, | ||
| 706 | .ready_msg = check_eo_msg, | ||
| 707 | .is_valid = validate_singlecw_ending, | ||
| 708 | .moveset = &moveset_eofb, | ||
| 709 | |||
| 710 | .pre_trans = fd, | ||
| 711 | |||
| 712 | .tables = {&pd_drud_eofb}, | ||
| 713 | .ntables = 1, | ||
| 714 | }; | ||
| 715 | |||
| 716 | Step | ||
| 717 | drrl_eoud = { | ||
| 718 | .shortname = "drrl-eoud", | ||
| 719 | .name = "DR on R/L without breaking EO on U/D", | ||
| 720 | |||
| 721 | .final = false, | ||
| 722 | .is_done = check_drud, | ||
| 723 | .estimate = estimate_drud_eofb, | ||
| 724 | .ready = check_eofb, | ||
| 725 | .ready_msg = check_eo_msg, | ||
| 726 | .is_valid = validate_singlecw_ending, | ||
| 727 | .moveset = &moveset_eofb, | ||
| 728 | |||
| 729 | .pre_trans = rd, | ||
| 730 | |||
| 731 | .tables = {&pd_drud_eofb}, | ||
| 732 | .ntables = 1, | ||
| 733 | }; | ||
| 734 | |||
| 735 | /* DR finish steps */ | ||
| 736 | Step | ||
| 737 | dranyfin_DR = { | ||
| 738 | .shortname = "drfin", | ||
| 739 | .name = "DR finish on any axis without breaking DR", | ||
| 740 | |||
| 741 | .final = true, | ||
| 742 | .is_done = is_solved, | ||
| 743 | .estimate = estimate_drudfin_drud, | ||
| 744 | .ready = check_drud, | ||
| 745 | .ready_msg = check_drany_msg, | ||
| 746 | .is_valid = always_valid, | ||
| 747 | .moveset = &moveset_drud, | ||
| 748 | |||
| 749 | .detect = detect_pretrans_drud, | ||
| 750 | |||
| 751 | .tables = {&pd_drudfin_noE_sym16_drud}, | ||
| 752 | .ntables = 1, | ||
| 753 | }; | ||
| 754 | |||
| 755 | Step | ||
| 756 | drudfin_drud = { | ||
| 757 | .shortname = "drudfin", | ||
| 758 | .name = "DR finish on U/D without breaking DR", | ||
| 759 | |||
| 760 | .final = true, | ||
| 761 | .is_done = is_solved, | ||
| 762 | .estimate = estimate_drudfin_drud, | ||
| 763 | .ready = check_drud, | ||
| 764 | .ready_msg = check_dr_msg, | ||
| 765 | .is_valid = always_valid, | ||
| 766 | .moveset = &moveset_drud, | ||
| 767 | |||
| 768 | .pre_trans = uf, | ||
| 769 | |||
| 770 | .tables = {&pd_drudfin_noE_sym16_drud}, | ||
| 771 | .ntables = 1, | ||
| 772 | }; | ||
| 773 | |||
| 774 | Step | ||
| 775 | drrlfin_drrl = { | ||
| 776 | .shortname = "drrlfin", | ||
| 777 | .name = "DR finish on R/L without breaking DR", | ||
| 778 | |||
| 779 | .final = true, | ||
| 780 | .is_done = is_solved, | ||
| 781 | .estimate = estimate_drudfin_drud, | ||
| 782 | .ready = check_drud, | ||
| 783 | .ready_msg = check_dr_msg, | ||
| 784 | .is_valid = always_valid, | ||
| 785 | .moveset = &moveset_drud, | ||
| 786 | |||
| 787 | .pre_trans = rf, | ||
| 788 | |||
| 789 | .tables = {&pd_drudfin_noE_sym16_drud}, | ||
| 790 | .ntables = 1, | ||
| 791 | }; | ||
| 792 | |||
| 793 | Step | ||
| 794 | drfbfin_drfb = { | ||
| 795 | .shortname = "drfbfin", | ||
| 796 | .name = "DR finish on F/B without breaking DR", | ||
| 797 | |||
| 798 | .final = true, | ||
| 799 | .is_done = is_solved, | ||
| 800 | .estimate = estimate_drudfin_drud, | ||
| 801 | .ready = check_drud, | ||
| 802 | .ready_msg = check_dr_msg, | ||
| 803 | .is_valid = always_valid, | ||
| 804 | .moveset = &moveset_drud, | ||
| 805 | |||
| 806 | .pre_trans = fd, | ||
| 807 | |||
| 808 | .tables = {&pd_drudfin_noE_sym16_drud}, | ||
| 809 | .ntables = 1, | ||
| 810 | }; | ||
| 811 | |||
| 812 | /* HTR from DR */ | ||
| 813 | Step | ||
| 814 | htr_any = { | ||
| 815 | .shortname = "htr", | ||
| 816 | .name = "HTR from DR", | ||
| 817 | |||
| 818 | .final = false, | ||
| 819 | .is_done = check_htr, | ||
| 820 | .estimate = estimate_htr_drud, | ||
| 821 | .ready = check_drud, | ||
| 822 | .ready_msg = check_drany_msg, | ||
| 823 | .is_valid = validate_singlecw_ending, | ||
| 824 | .moveset = &moveset_drud, | ||
| 825 | |||
| 826 | .detect = detect_pretrans_drud, | ||
| 827 | |||
| 828 | .tables = {&pd_htr_drud}, | ||
| 829 | .ntables = 1, | ||
| 830 | }; | ||
| 831 | |||
| 832 | Step | ||
| 833 | htr_drud = { | ||
| 834 | .shortname = "htr-drud", | ||
| 835 | .name = "HTR from DR on U/D", | ||
| 6 | 836 | ||
| 7 | bool | 837 | .final = false, |
| 8 | check_centers(Cube *cube) | 838 | .is_done = check_htr, |
| 839 | .estimate = estimate_htr_drud, | ||
| 840 | .ready = check_drud, | ||
| 841 | .ready_msg = check_dr_msg, | ||
| 842 | .is_valid = validate_singlecw_ending, | ||
| 843 | .moveset = &moveset_drud, | ||
| 844 | |||
| 845 | .pre_trans = uf, | ||
| 846 | |||
| 847 | .tables = {&pd_htr_drud}, | ||
| 848 | .ntables = 1, | ||
| 849 | }; | ||
| 850 | |||
| 851 | Step | ||
| 852 | htr_drrl = { | ||
| 853 | .shortname = "htr-drrl", | ||
| 854 | .name = "HTR from DR on R/L", | ||
| 855 | |||
| 856 | .final = false, | ||
| 857 | .is_done = check_htr, | ||
| 858 | .estimate = estimate_htr_drud, | ||
| 859 | .ready = check_drud, | ||
| 860 | .ready_msg = check_dr_msg, | ||
| 861 | .is_valid = validate_singlecw_ending, | ||
| 862 | .moveset = &moveset_drud, | ||
| 863 | |||
| 864 | .pre_trans = rf, | ||
| 865 | |||
| 866 | .tables = {&pd_htr_drud}, | ||
| 867 | .ntables = 1, | ||
| 868 | }; | ||
| 869 | |||
| 870 | Step | ||
| 871 | htr_drfb = { | ||
| 872 | .shortname = "htr-drfb", | ||
| 873 | .name = "HTR from DR on F/B", | ||
| 874 | |||
| 875 | .final = false, | ||
| 876 | .is_done = check_htr, | ||
| 877 | .estimate = estimate_htr_drud, | ||
| 878 | .ready = check_drud, | ||
| 879 | .ready_msg = check_dr_msg, | ||
| 880 | .is_valid = validate_singlecw_ending, | ||
| 881 | .moveset = &moveset_drud, | ||
| 882 | |||
| 883 | .pre_trans = fd, | ||
| 884 | |||
| 885 | .tables = {&pd_htr_drud}, | ||
| 886 | .ntables = 1, | ||
| 887 | }; | ||
| 888 | |||
| 889 | /* HTR finish */ | ||
| 890 | Step | ||
| 891 | htrfin_htr = { | ||
| 892 | .shortname = "htrfin", | ||
| 893 | .name = "HTR finish without breaking HTR", | ||
| 894 | |||
| 895 | .final = true, | ||
| 896 | .is_done = is_solved, | ||
| 897 | .estimate = estimate_htrfin_htr, | ||
| 898 | .ready = check_htr, | ||
| 899 | .ready_msg = check_htr_msg, | ||
| 900 | .is_valid = always_valid, | ||
| 901 | .moveset = &moveset_htr, | ||
| 902 | |||
| 903 | .pre_trans = uf, | ||
| 904 | |||
| 905 | .tables = {&pd_htrfin_htr}, | ||
| 906 | .ntables = 1, | ||
| 907 | }; | ||
| 908 | |||
| 909 | Step *steps[] = { | ||
| 910 | &optimal_HTM, /* first is default */ | ||
| 911 | &optimal_light_HTM, | ||
| 912 | |||
| 913 | &eofin_eo, | ||
| 914 | &eofbfin_eofb, | ||
| 915 | &eorlfin_eorl, | ||
| 916 | &eoudfin_eoud, | ||
| 917 | |||
| 918 | &eoany_HTM, | ||
| 919 | &eofb_HTM, | ||
| 920 | &eorl_HTM, | ||
| 921 | &eoud_HTM, | ||
| 922 | |||
| 923 | &coany_HTM, | ||
| 924 | &coud_HTM, | ||
| 925 | &corl_HTM, | ||
| 926 | &cofb_HTM, | ||
| 927 | |||
| 928 | &coany_URF, | ||
| 929 | &coud_URF, | ||
| 930 | &corl_URF, | ||
| 931 | &cofb_URF, | ||
| 932 | |||
| 933 | &drany_HTM, | ||
| 934 | &drud_HTM, | ||
| 935 | &drrl_HTM, | ||
| 936 | &drfb_HTM, | ||
| 937 | |||
| 938 | &dr_eo, | ||
| 939 | &dr_eofb, | ||
| 940 | &dr_eorl, | ||
| 941 | &dr_eoud, | ||
| 942 | &drud_eofb, | ||
| 943 | &drrl_eofb, | ||
| 944 | &drud_eorl, | ||
| 945 | &drfb_eorl, | ||
| 946 | &drfb_eoud, | ||
| 947 | &drrl_eoud, | ||
| 948 | |||
| 949 | &dranyfin_DR, | ||
| 950 | &drudfin_drud, | ||
| 951 | &drrlfin_drrl, | ||
| 952 | &drfbfin_drfb, | ||
| 953 | |||
| 954 | &htr_any, | ||
| 955 | &htr_drud, | ||
| 956 | &htr_drrl, | ||
| 957 | &htr_drfb, | ||
| 958 | |||
| 959 | &htrfin_htr, | ||
| 960 | |||
| 961 | &cornershtr_HTM, | ||
| 962 | &cornershtr_URF, | ||
| 963 | &corners_HTM, | ||
| 964 | &corners_URF, | ||
| 965 | |||
| 966 | NULL | ||
| 967 | }; | ||
| 968 | |||
| 969 | /* Checkers, estimators and validators ***************************************/ | ||
| 970 | |||
| 971 | static bool | ||
| 972 | check_centers(Cube cube) | ||
| 9 | { | 973 | { |
| 10 | int i; | 974 | return cube.cpos == 0; |
| 975 | } | ||
| 11 | 976 | ||
| 12 | for (i = 0; i < 6; i++) | 977 | static bool |
| 13 | if (cube->xp[i] != i) | 978 | check_coud_HTM(Cube cube) |
| 14 | return false; | 979 | { |
| 980 | return cube.coud == 0; | ||
| 981 | } | ||
| 15 | 982 | ||
| 16 | return true; | 983 | static bool |
| 984 | check_coud_URF(Cube cube) | ||
| 985 | { | ||
| 986 | Cube c2, c3; | ||
| 987 | |||
| 988 | c2 = apply_move(z, cube); | ||
| 989 | c3 = apply_move(x, cube); | ||
| 990 | |||
| 991 | return cube.coud == 0 || c2.coud == 0 || c3.coud == 0; | ||
| 17 | } | 992 | } |
| 18 | 993 | ||
| 19 | bool | 994 | static bool |
| 20 | check_coud_HTM(Cube *cube) | 995 | check_corners_URF(Cube cube) |
| 21 | { | 996 | { |
| 22 | int i; | 997 | Cube c; |
| 998 | Trans i; | ||
| 23 | 999 | ||
| 24 | for (i = 0; i < 8; i++) | 1000 | for (i = 0; i < NROTATIONS; i++) { |
| 25 | if (cube->co[i] != 0) | 1001 | c = apply_alg(rotation_alg(i), cube); |
| 26 | return false; | 1002 | if (c.cp && c.coud) |
| 1003 | return true; | ||
| 1004 | } | ||
| 27 | 1005 | ||
| 28 | return true; | 1006 | return false; |
| 29 | } | 1007 | } |
| 30 | 1008 | ||
| 31 | bool | 1009 | static bool |
| 32 | check_coud_URF(Cube *cube) | 1010 | check_corners_HTM(Cube cube) |
| 33 | { | 1011 | { |
| 34 | Cube c2, c3; | 1012 | return cube.cp == 0 && cube.coud == 0; |
| 1013 | } | ||
| 35 | 1014 | ||
| 36 | copy_cube(cube, &c2); | 1015 | static bool |
| 37 | copy_cube(cube, &c3); | 1016 | check_cornershtr(Cube cube) |
| 1017 | { | ||
| 1018 | return coord_cornershtr.index(cube) == 0; | ||
| 1019 | } | ||
| 38 | 1020 | ||
| 39 | apply_move(z, &c2); | 1021 | static bool |
| 40 | apply_move(x, &c3); | 1022 | check_eofb(Cube cube) |
| 1023 | { | ||
| 1024 | return cube.eofb == 0; | ||
| 1025 | } | ||
| 41 | 1026 | ||
| 42 | return check_coud_HTM(cube) || | 1027 | static bool |
| 43 | check_coud_HTM(&c2) || | 1028 | check_drud(Cube cube) |
| 44 | check_coud_HTM(&c3); | 1029 | { |
| 1030 | return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; | ||
| 45 | } | 1031 | } |
| 46 | 1032 | ||
| 47 | bool | 1033 | static bool |
| 48 | check_cp_HTM(Cube *cube) | 1034 | check_htr(Cube cube) |
| 49 | { | 1035 | { |
| 50 | int i; | 1036 | return check_drud(cube) && coord_htr_drud.index(cube) == 0; |
| 1037 | } | ||
| 1038 | |||
| 1039 | static int | ||
| 1040 | estimate_eofb_HTM(DfsArg *arg) | ||
| 1041 | { | ||
| 1042 | return ptableval(&pd_eofb_HTM, arg->cube); | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | static int | ||
| 1046 | estimate_coud_HTM(DfsArg *arg) | ||
| 1047 | { | ||
| 1048 | return ptableval(&pd_coud_HTM, arg->cube); | ||
| 1049 | } | ||
| 51 | 1050 | ||
| 52 | for (i = 0; i < 8; i++) | 1051 | static int |
| 53 | if (cube->cp[i] != i) | 1052 | estimate_coud_URF(DfsArg *arg) |
| 54 | return false; | 1053 | { |
| 1054 | /* TODO: I can improve this by checking first the orientation of | ||
| 1055 | * the corner in DBL and use that as a reference */ | ||
| 55 | 1056 | ||
| 56 | return true; | 1057 | Cube c; |
| 1058 | |||
| 1059 | c = arg->cube; | ||
| 1060 | |||
| 1061 | int ud = estimate_coud_HTM(arg); | ||
| 1062 | arg->cube = apply_move(z, c); | ||
| 1063 | int rl = estimate_coud_HTM(arg); | ||
| 1064 | arg->cube = apply_move(x, c); | ||
| 1065 | int fb = estimate_coud_HTM(arg); | ||
| 1066 | |||
| 1067 | arg->cube = c; | ||
| 1068 | |||
| 1069 | return MIN(ud, MIN(rl, fb)); | ||
| 57 | } | 1070 | } |
| 58 | 1071 | ||
| 59 | bool | 1072 | static int |
| 60 | check_corners_HTM(Cube *cube) | 1073 | estimate_corners_HTM(DfsArg *arg) |
| 61 | { | 1074 | { |
| 62 | return check_coud_HTM(cube) && check_cp_HTM(cube); | 1075 | return ptableval(&pd_corners_HTM, arg->cube); |
| 63 | } | 1076 | } |
| 64 | 1077 | ||
| 65 | bool | 1078 | static int |
| 66 | check_corners_URF(Cube *cube) | 1079 | estimate_cornershtr_HTM(DfsArg *arg) |
| 67 | { | 1080 | { |
| 1081 | return ptableval(&pd_cornershtr_HTM, arg->cube); | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | static int | ||
| 1085 | estimate_cornershtr_URF(DfsArg *arg) | ||
| 1086 | { | ||
| 1087 | /* TODO: I can improve this by checking first the corner in DBL | ||
| 1088 | * and use that as a reference */ | ||
| 1089 | |||
| 1090 | int ret; | ||
| 68 | Cube c; | 1091 | Cube c; |
| 69 | Trans i; | 1092 | Trans i; |
| 70 | 1093 | ||
| 1094 | c = arg->cube; | ||
| 1095 | ret = 15; | ||
| 1096 | |||
| 71 | for (i = 0; i < NROTATIONS; i++) { | 1097 | for (i = 0; i < NROTATIONS; i++) { |
| 72 | copy_cube(cube, &c); | 1098 | arg->cube = apply_alg(rotation_alg(i), c); |
| 73 | apply_alg(rotation_alg(i), &c); | 1099 | ret = MIN(ret, estimate_cornershtr_HTM(arg)); |
| 74 | if (check_corners_HTM(&c)) | ||
| 75 | return true; | ||
| 76 | } | 1100 | } |
| 77 | 1101 | ||
| 78 | return false; | 1102 | arg->cube = c; |
| 1103 | |||
| 1104 | return ret; | ||
| 79 | } | 1105 | } |
| 80 | 1106 | ||
| 81 | bool | 1107 | static int |
| 82 | check_cornershtr(Cube *cube) | 1108 | estimate_corners_URF(DfsArg *arg) |
| 83 | { | 1109 | { |
| 84 | /* TODO (use coord) */ | 1110 | /* TODO: I can improve this by checking first the corner in DBL |
| 85 | return true; | 1111 | * and use that as a reference */ |
| 1112 | |||
| 1113 | int ret; | ||
| 1114 | Cube c; | ||
| 1115 | Trans i; | ||
| 1116 | |||
| 1117 | c = arg->cube; | ||
| 1118 | ret = 15; | ||
| 1119 | |||
| 1120 | for (i = 0; i < NROTATIONS; i++) { | ||
| 1121 | arg->cube = apply_alg(rotation_alg(i), c); | ||
| 1122 | ret = MIN(ret, estimate_corners_HTM(arg)); | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | arg->cube = c; | ||
| 1126 | |||
| 1127 | return ret; | ||
| 86 | } | 1128 | } |
| 87 | 1129 | ||
| 88 | bool | 1130 | static int |
| 89 | check_eofb(Cube *cube) | 1131 | estimate_drud_HTM(DfsArg *arg) |
| 90 | { | 1132 | { |
| 91 | /* TODO (use coord) */ | 1133 | return ptableval(&pd_drud_sym16_HTM, arg->cube); |
| 92 | return true; | ||
| 93 | } | 1134 | } |
| 94 | 1135 | ||
| 95 | bool | 1136 | static int |
| 96 | check_drud(Cube *cube) | 1137 | estimate_drud_eofb(DfsArg *arg) |
| 97 | { | 1138 | { |
| 98 | /* TODO (use coord) */ | 1139 | return ptableval(&pd_drud_eofb, arg->cube); |
| 99 | return true; | ||
| 100 | } | 1140 | } |
| 101 | 1141 | ||
| 102 | bool | 1142 | static int |
| 103 | check_htr(Cube *cube) | 1143 | estimate_dr_eofb(DfsArg *arg) |
| 1144 | { | ||
| 1145 | int r1, r2; | ||
| 1146 | |||
| 1147 | r1 = ptableval(&pd_drud_eofb, arg->cube); | ||
| 1148 | r2 = ptableval(&pd_drud_eofb, apply_trans(rf, arg->cube)); | ||
| 1149 | |||
| 1150 | return MIN(r1, r2); | ||
| 1151 | } | ||
| 1152 | |||
| 1153 | static int | ||
| 1154 | estimate_drudfin_drud(DfsArg *arg) | ||
| 1155 | { | ||
| 1156 | int val = ptableval(&pd_drudfin_noE_sym16_drud, arg->cube); | ||
| 1157 | |||
| 1158 | if (val != 0) | ||
| 1159 | return val; | ||
| 1160 | |||
| 1161 | return arg->cube.epose % 24 == 0 ? 0 : 1; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | static int | ||
| 1165 | estimate_htr_drud(DfsArg *arg) | ||
| 1166 | { | ||
| 1167 | return ptableval(&pd_htr_drud, arg->cube); | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | static int | ||
| 1171 | estimate_htrfin_htr(DfsArg *arg) | ||
| 1172 | { | ||
| 1173 | return ptableval(&pd_htrfin_htr, arg->cube); | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | static int | ||
| 1177 | estimate_nxopt31_HTM(DfsArg *arg) | ||
| 1178 | { | ||
| 1179 | return estimate_nxoptlike(arg, &pd_nxopt31_HTM); | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | /* TODO: also use generic procedure for this */ | ||
| 1183 | static int | ||
| 1184 | estimate_light_HTM(DfsArg *arg) | ||
| 1185 | { | ||
| 1186 | int target, ret; | ||
| 1187 | Cube aux; | ||
| 1188 | |||
| 1189 | static const uint64_t udmask = (1<<U) | (1<<U2) | (1<<U3) | | ||
| 1190 | (1<<D) | (1<<D2) | (1<<D3); | ||
| 1191 | static const uint64_t rlmask = (1<<R) | (1<<R2) | (1<<R3) | | ||
| 1192 | (1<<L) | (1<<L2) | (1<<L3); | ||
| 1193 | static const uint64_t fbmask = (1<<F) | (1<<F2) | (1<<F3) | | ||
| 1194 | (1<<B) | (1<<B2) | (1<<B3); | ||
| 1195 | static const uint64_t htmask = (1<<U2) | (1<<D2) | | ||
| 1196 | (1<<R2) | (1<<L2) | | ||
| 1197 | (1<<F2) | (1<<B2); | ||
| 1198 | |||
| 1199 | ret = -1; | ||
| 1200 | target = arg->d - arg->current_alg->len; | ||
| 1201 | arg->inverse = (Cube){0}; | ||
| 1202 | arg->badmovesinv = 0; | ||
| 1203 | arg->badmoves = 0; | ||
| 1204 | |||
| 1205 | /* Corners */ | ||
| 1206 | arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube); | ||
| 1207 | UPDATECHECKSTOP(ret, arg->ed->corners, target); | ||
| 1208 | |||
| 1209 | /* Normal probing */ | ||
| 1210 | arg->ed->normal_ud = ptableval(&pd_drud_sym16_HTM, arg->cube); | ||
| 1211 | UPDATECHECKSTOP(ret, arg->ed->normal_ud, target); | ||
| 1212 | aux = apply_trans(fd, arg->cube); | ||
| 1213 | arg->ed->normal_fb = ptableval(&pd_drud_sym16_HTM, aux); | ||
| 1214 | UPDATECHECKSTOP(ret, arg->ed->normal_fb, target); | ||
| 1215 | aux = apply_trans(rf, arg->cube); | ||
| 1216 | arg->ed->normal_rl = ptableval(&pd_drud_sym16_HTM, aux); | ||
| 1217 | UPDATECHECKSTOP(ret, arg->ed->normal_rl, target); | ||
| 1218 | |||
| 1219 | /* If ret == 0, it's solved (corners + triple slice solved) */ | ||
| 1220 | if (ret == 0) | ||
| 1221 | return is_solved(arg->cube) ? 0 : 1; | ||
| 1222 | |||
| 1223 | /* Michel de Bondt's trick*/ | ||
| 1224 | if (arg->ed->normal_ud == arg->ed->normal_fb && | ||
| 1225 | arg->ed->normal_fb == arg->ed->normal_rl) { | ||
| 1226 | UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target); | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | /* Inverse probing */ | ||
| 1230 | if (!((1<<arg->last1) & htmask)) { | ||
| 1231 | aux = arg->inverse = inverse_cube(arg->cube); | ||
| 1232 | if (!((1<<arg->last1) & udmask) || (arg->ed->inverse_ud==-1)) { | ||
| 1233 | arg->ed->inverse_ud = | ||
| 1234 | ptableval(&pd_drud_sym16_HTM, aux); | ||
| 1235 | } | ||
| 1236 | UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target); | ||
| 1237 | if (!((1<<arg->last1) & fbmask) || (arg->ed->inverse_fb==-1)) { | ||
| 1238 | aux = apply_trans(fd, arg->inverse); | ||
| 1239 | arg->ed->inverse_fb = | ||
| 1240 | ptableval(&pd_drud_sym16_HTM, aux); | ||
| 1241 | } | ||
| 1242 | UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target); | ||
| 1243 | if (!((1<<arg->last1) & rlmask) || (arg->ed->inverse_rl==-1)) { | ||
| 1244 | aux = apply_trans(rf, arg->inverse); | ||
| 1245 | arg->ed->inverse_rl = | ||
| 1246 | ptableval(&pd_drud_sym16_HTM, aux); | ||
| 1247 | } | ||
| 1248 | UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target); | ||
| 1249 | } else { | ||
| 1250 | UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target); | ||
| 1251 | UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target); | ||
| 1252 | UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target); | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | /* Michel de Bondt's trick*/ | ||
| 1256 | if (arg->ed->inverse_ud == arg->ed->inverse_fb && | ||
| 1257 | arg->ed->inverse_fb == arg->ed->inverse_rl) { | ||
| 1258 | UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target); | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | /* nxopt trick + half turn trick */ | ||
| 1262 | if (arg->ed->normal_ud == target) | ||
| 1263 | arg->badmovesinv |= udmask | htmask; | ||
| 1264 | if (arg->ed->normal_fb == target) | ||
| 1265 | arg->badmovesinv |= fbmask | htmask; | ||
| 1266 | if (arg->ed->normal_rl == target) | ||
| 1267 | arg->badmovesinv |= rlmask | htmask; | ||
| 1268 | |||
| 1269 | if (arg->ed->inverse_ud == target) | ||
| 1270 | arg->badmoves |= udmask | htmask; | ||
| 1271 | if (arg->ed->inverse_fb == target) | ||
| 1272 | arg->badmoves |= fbmask | htmask; | ||
| 1273 | if (arg->ed->inverse_rl == target) | ||
| 1274 | arg->badmoves |= rlmask | htmask; | ||
| 1275 | |||
| 1276 | return arg->ed->oldret = ret; | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | static int | ||
| 1280 | estimate_nxoptlike(DfsArg *arg, PruneData *pd) | ||
| 1281 | { | ||
| 1282 | int target, ret; | ||
| 1283 | Cube aux; | ||
| 1284 | |||
| 1285 | static const uint64_t udmask = (1<<U) | (1<<U2) | (1<<U3) | | ||
| 1286 | (1<<D) | (1<<D2) | (1<<D3); | ||
| 1287 | static const uint64_t rlmask = (1<<R) | (1<<R2) | (1<<R3) | | ||
| 1288 | (1<<L) | (1<<L2) | (1<<L3); | ||
| 1289 | static const uint64_t fbmask = (1<<F) | (1<<F2) | (1<<F3) | | ||
| 1290 | (1<<B) | (1<<B2) | (1<<B3); | ||
| 1291 | |||
| 1292 | ret = -1; | ||
| 1293 | target = arg->d - arg->current_alg->len; | ||
| 1294 | arg->inverse = (Cube){0}; | ||
| 1295 | arg->badmovesinv = 0; | ||
| 1296 | arg->badmoves = 0; | ||
| 1297 | |||
| 1298 | /* Corners */ | ||
| 1299 | arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube); | ||
| 1300 | UPDATECHECKSTOP(ret, arg->ed->corners, target); | ||
| 1301 | |||
| 1302 | /* Normal probing */ | ||
| 1303 | arg->ed->normal_ud = ptableval(pd, arg->cube); | ||
| 1304 | UPDATECHECKSTOP(ret, arg->ed->normal_ud, target); | ||
| 1305 | aux = apply_trans(fd, arg->cube); | ||
| 1306 | arg->ed->normal_fb = ptableval(pd, aux); | ||
| 1307 | UPDATECHECKSTOP(ret, arg->ed->normal_fb, target); | ||
| 1308 | aux = apply_trans(rf, arg->cube); | ||
| 1309 | arg->ed->normal_rl = ptableval(pd, aux); | ||
| 1310 | UPDATECHECKSTOP(ret, arg->ed->normal_rl, target); | ||
| 1311 | |||
| 1312 | if (ret == 0) | ||
| 1313 | return arg->step->is_done(arg->cube) ? 0 : 1; | ||
| 1314 | |||
| 1315 | /* Michel de Bondt's trick*/ | ||
| 1316 | if (arg->ed->normal_ud == arg->ed->normal_fb && | ||
| 1317 | arg->ed->normal_fb == arg->ed->normal_rl) { | ||
| 1318 | UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target); | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | /* Inverse probing */ | ||
| 1322 | aux = arg->inverse = inverse_cube(arg->cube); | ||
| 1323 | if (!((1<<arg->last1) & udmask) || (arg->ed->inverse_ud == -1)) { | ||
| 1324 | arg->ed->inverse_ud = ptableval(pd, aux); | ||
| 1325 | } | ||
| 1326 | UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target); | ||
| 1327 | if (!((1<<arg->last1) & fbmask) || (arg->ed->inverse_fb == -1)) { | ||
| 1328 | aux = apply_trans(fd, arg->inverse); | ||
| 1329 | arg->ed->inverse_fb = ptableval(pd, aux); | ||
| 1330 | } | ||
| 1331 | UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target); | ||
| 1332 | if (!((1<<arg->last1) & rlmask) || (arg->ed->inverse_rl == -1)) { | ||
| 1333 | aux = apply_trans(rf, arg->inverse); | ||
| 1334 | arg->ed->inverse_rl = ptableval(pd, aux); | ||
| 1335 | } | ||
| 1336 | UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target); | ||
| 1337 | |||
| 1338 | /* Michel de Bondt's trick*/ | ||
| 1339 | if (arg->ed->inverse_ud == arg->ed->inverse_fb && | ||
| 1340 | arg->ed->inverse_fb == arg->ed->inverse_rl) { | ||
| 1341 | UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target); | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | /* nxopt trick */ | ||
| 1345 | if (arg->ed->normal_ud == target) | ||
| 1346 | arg->badmovesinv |= udmask; | ||
| 1347 | if (arg->ed->normal_fb == target) | ||
| 1348 | arg->badmovesinv |= fbmask; | ||
| 1349 | if (arg->ed->normal_rl == target) | ||
| 1350 | arg->badmovesinv |= rlmask; | ||
| 1351 | |||
| 1352 | if (arg->ed->inverse_ud == target) | ||
| 1353 | arg->badmoves |= udmask; | ||
| 1354 | if (arg->ed->inverse_fb == target) | ||
| 1355 | arg->badmoves |= fbmask; | ||
| 1356 | if (arg->ed->inverse_rl == target) | ||
| 1357 | arg->badmoves |= rlmask; | ||
| 1358 | |||
| 1359 | return arg->ed->oldret = ret; | ||
| 1360 | } | ||
| 1361 | |||
| 1362 | |||
| 1363 | static bool | ||
| 1364 | always_valid(Alg *alg) | ||
| 104 | { | 1365 | { |
| 105 | /* TODO (check_drud(cube) and coord_htr_drud == 0) */ | ||
| 106 | return true; | 1366 | return true; |
| 107 | } | 1367 | } |
| 108 | 1368 | ||
| 109 | Alg * | 1369 | static bool |
| 110 | validate_singlecw_ending(Alg *alg) | 1370 | validate_singlecw_ending(Alg *alg) |
| 111 | { | 1371 | { |
| 112 | int i; | 1372 | int i; |
| 113 | bool nor, inv; | 1373 | bool nor, inv; |
| 114 | Alg *ret; | ||
| 115 | Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; | 1374 | Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; |
| 116 | 1375 | ||
| 117 | for (i = 0; i < alg->len; i++) { | 1376 | for (i = 0; i < alg->len; i++) { |
| @@ -127,51 +1386,96 @@ validate_singlecw_ending(Alg *alg) | |||
| 127 | nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2)); | 1386 | nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2)); |
| 128 | inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i)); | 1387 | inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i)); |
| 129 | 1388 | ||
| 130 | if (nor && inv) { | 1389 | return nor && inv; |
| 131 | ret = new_alg(""); | 1390 | } |
| 132 | copy_alg(alg, ret); | ||
| 133 | } else { | ||
| 134 | ret = NULL; | ||
| 135 | } | ||
| 136 | 1391 | ||
| 137 | return ret; | 1392 | /* Pre-transformation detectors **********************************************/ |
| 1393 | |||
| 1394 | static int | ||
| 1395 | detect_pretrans_eofb(Cube cube, Trans *ret) | ||
| 1396 | { | ||
| 1397 | int i, n; | ||
| 1398 | static Trans tt[3] = {uf, ur, fd}; | ||
| 1399 | |||
| 1400 | for (i = 0, n = 0; i < 3; i++) | ||
| 1401 | if (check_eofb(apply_trans(tt[i], cube))) | ||
| 1402 | ret[n++] = tt[i]; | ||
| 1403 | |||
| 1404 | return n; | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | static int | ||
| 1408 | detect_pretrans_drud(Cube cube, Trans *ret) | ||
| 1409 | { | ||
| 1410 | int i, n; | ||
| 1411 | static Trans tt[3] = {uf, fr, rd}; | ||
| 1412 | |||
| 1413 | for (i = 0, n = 0; i < 3; i++) | ||
| 1414 | if (check_drud(apply_trans(tt[i], cube))) | ||
| 1415 | ret[n++] = tt[i]; | ||
| 1416 | |||
| 1417 | return n; | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | static int | ||
| 1421 | detect_pretrans_void_3axis(Cube cube, Trans *ret) | ||
| 1422 | { | ||
| 1423 | ret[0] = uf; | ||
| 1424 | ret[1] = fr; | ||
| 1425 | ret[2] = rd; | ||
| 1426 | |||
| 1427 | return 3; | ||
| 138 | } | 1428 | } |
| 139 | 1429 | ||
| 140 | /* Public functions **********************************************************/ | 1430 | /* Public functions **********************************************************/ |
| 141 | 1431 | ||
| 142 | /* | ||
| 143 | void | 1432 | void |
| 144 | compute_ind(Step *s, Cube *cube, Movable *ind) | 1433 | copy_estimatedata(EstimateData *src, EstimateData *dst) |
| 145 | { | 1434 | { |
| 146 | int i; | 1435 | dst->corners = src->corners; |
| 147 | Cube mvd; | 1436 | dst->normal_ud = src->normal_ud; |
| 148 | Trans t, tt; | 1437 | dst->normal_fb = src->normal_fb; |
| 1438 | dst->normal_rl = src->normal_rl; | ||
| 1439 | dst->inverse_ud = src->inverse_ud; | ||
| 1440 | dst->inverse_fb = src->inverse_fb; | ||
| 1441 | dst->inverse_rl = src->inverse_rl; | ||
| 1442 | dst->oldret = src->oldret; | ||
| 1443 | } | ||
| 149 | 1444 | ||
| 150 | for (i = 0; i < s->n_coord; i++) { | 1445 | void |
| 151 | t = s->coord_trans[i]; | 1446 | invert_estimatedata(EstimateData *ed) |
| 152 | copy_cube(cube, &mvd); | 1447 | { |
| 153 | apply_trans(t, &mvd); | 1448 | swap(&(ed->normal_ud), &(ed->inverse_ud)); |
| 1449 | swap(&(ed->normal_fb), &(ed->inverse_fb)); | ||
| 1450 | swap(&(ed->normal_rl), &(ed->inverse_rl)); | ||
| 1451 | } | ||
| 154 | 1452 | ||
| 155 | ind[i].val = index_coord(s->coord[i], &mvd, &tt); | 1453 | void |
| 156 | ind[i].t = transform_trans(tt, t); | 1454 | reset_estimatedata(EstimateData *ed) |
| 157 | } | 1455 | { |
| 1456 | ed->corners = -1; | ||
| 1457 | ed->normal_ud = -1; | ||
| 1458 | ed->normal_fb = -1; | ||
| 1459 | ed->normal_rl = -1; | ||
| 1460 | ed->inverse_ud = -1; | ||
| 1461 | ed->inverse_fb = -1; | ||
| 1462 | ed->inverse_rl = -1; | ||
| 1463 | ed->oldret = -1; | ||
| 158 | } | 1464 | } |
| 159 | */ | ||
| 160 | 1465 | ||
| 161 | void | 1466 | void |
| 162 | prepare_cs(ChoiceStep *cs, SolveOptions *opts) | 1467 | prepare_step(Step *step, SolveOptions *opts) |
| 163 | { | 1468 | { |
| 164 | int i, j; | 1469 | int i; |
| 165 | Step *s; | ||
| 166 | 1470 | ||
| 167 | for (i = 0; cs->step[i] != NULL; i++) { | 1471 | if (step->final && opts->can_niss) { |
| 168 | s = cs->step[i]; | 1472 | opts->can_niss = false; |
| 169 | for (j = 0; j < s->n_coord; j++) { | 1473 | fprintf(stderr, "Step is final, NISS not used (-n ignored)\n"); |
| 170 | s->pd[j] = malloc(sizeof(PruneData)); | 1474 | } |
| 171 | s->pd[j]->moveset = s->moveset; | 1475 | |
| 172 | s->pd[j]->coord = s->coord[j]; | 1476 | for (i = 0; i < step->ntables; i++) { |
| 173 | s->pd[j]->compact = s->pd_compact[j]; | 1477 | genptable(step->tables[i], opts->nthreads); |
| 174 | s->pd[j] = genptable(s->pd[j], opts->nthreads); | 1478 | if (step->tables[i]->compact) |
| 175 | } | 1479 | genptable(step->tables[i]->fallback, opts->nthreads); |
| 176 | } | 1480 | } |
| 177 | } | 1481 | } |
diff --git a/src/steps.h b/src/steps.h index 206f8b4..da5c041 100644 --- a/src/steps.h +++ b/src/steps.h | |||
| @@ -2,243 +2,16 @@ | |||
| 2 | #define STEPS_H | 2 | #define STEPS_H |
| 3 | 3 | ||
| 4 | #include "pruning.h" | 4 | #include "pruning.h" |
| 5 | #include "movesets.h" | ||
| 6 | 5 | ||
| 7 | bool check_centers(Cube *cube); | 6 | extern Step * steps[]; |
| 8 | bool check_coud_HTM(Cube *cube); | ||
| 9 | bool check_coud_URF(Cube *cube); | ||
| 10 | bool check_cp_HTM(Cube *cube); | ||
| 11 | bool check_corners_HTM(Cube *cube); | ||
| 12 | bool check_corners_URF(Cube *cube); | ||
| 13 | bool check_cornershtr(Cube *cube); | ||
| 14 | bool check_eofb(Cube *cube); | ||
| 15 | bool check_drud(Cube *cube); | ||
| 16 | bool check_htr(Cube *cube); | ||
| 17 | /*void compute_ind(Step *a, Cube *cube, Movable *ind);*/ | ||
| 18 | void prepare_cs(ChoiceStep *cs, SolveOptions *opts); | ||
| 19 | bool always_valid(Alg *alg); | ||
| 20 | Alg * validate_singlecw_ending(Alg *alg); | ||
| 21 | 7 | ||
| 22 | #ifndef STEPS_C | 8 | /* Two steps used directly by two-phase solver */ |
| 9 | extern Step drany_HTM; | ||
| 10 | extern Step dranyfin_DR; | ||
| 23 | 11 | ||
| 24 | extern char check_centers_msg[100]; | 12 | void copy_estimatedata(EstimateData *s, EstimateData *d); |
| 25 | extern char check_eo_msg[100]; | 13 | void invert_estimatedata(EstimateData *ed); |
| 26 | extern char check_dr_msg[100]; | 14 | void reset_estimatedata(EstimateData *ed); |
| 27 | extern char check_htr_msg[100]; | 15 | void prepare_step(Step *step, SolveOptions *opts); |
| 28 | extern char check_drany_msg[100]; | ||
| 29 | |||
| 30 | extern Step step_eofb_HTM; | ||
| 31 | extern Step step_drud_HTM; | ||
| 32 | extern Step step_drfin_drud; | ||
| 33 | |||
| 34 | extern ChoiceStep optimal_HTM; | ||
| 35 | extern ChoiceStep eoany_HTM; | ||
| 36 | extern ChoiceStep eofb_HTM; | ||
| 37 | extern ChoiceStep eorl_HTM; | ||
| 38 | extern ChoiceStep eoud_HTM; | ||
| 39 | extern ChoiceStep drany_HTM; | ||
| 40 | extern ChoiceStep drud_HTM; | ||
| 41 | extern ChoiceStep drrl_HTM; | ||
| 42 | extern ChoiceStep drfb_HTM; | ||
| 43 | extern ChoiceStep dranyfin_DR; | ||
| 44 | extern ChoiceStep drudfin_drud; | ||
| 45 | extern ChoiceStep drrlfin_drrl; | ||
| 46 | extern ChoiceStep drfbfin_drfb; | ||
| 47 | |||
| 48 | extern ChoiceStep *csteps[]; | ||
| 49 | |||
| 50 | #else | ||
| 51 | |||
| 52 | char check_centers_msg[100] = "cube must be oriented (centers solved)"; | ||
| 53 | char check_eo_msg[100] = "EO must be solved on given axis"; | ||
| 54 | char check_dr_msg[100] = "DR must be solved on given axis"; | ||
| 55 | char check_htr_msg[100] = "HTR must be solved"; | ||
| 56 | char check_drany_msg[100] = "DR must be solved on at least one axis"; | ||
| 57 | |||
| 58 | /* Optimal after EO ******************/ | ||
| 59 | /* TODO: eofin_eo (generic), eofbfin_eofb, eorlfin_eorl, eoudfin_eoud */ | ||
| 60 | |||
| 61 | /* EO steps **************************/ | ||
| 62 | /* TODO: eoany_HTM (generic), eofb_HTM, eorl_HTM, eoud_HTM */ | ||
| 63 | |||
| 64 | Step | ||
| 65 | step_eofb_HTM = { | ||
| 66 | .ready = check_centers, | ||
| 67 | .final = false, | ||
| 68 | .moveset = &moveset_HTM, | ||
| 69 | .n_coord = 1, | ||
| 70 | .coord = {&coord_eofb}, | ||
| 71 | .coord_trans = {uf}, | ||
| 72 | .is_valid = validate_singlecw_ending, | ||
| 73 | }; | ||
| 74 | ChoiceStep | ||
| 75 | eoany_HTM = { | ||
| 76 | .shortname = "eo", | ||
| 77 | .name = "EO on any axis", | ||
| 78 | .step = {&step_eofb_HTM, &step_eofb_HTM, &step_eofb_HTM, NULL}, | ||
| 79 | .t = {uf, ur, fd}, | ||
| 80 | .ready_msg = check_centers_msg, | ||
| 81 | }; | ||
| 82 | ChoiceStep | ||
| 83 | eofb_HTM = { | ||
| 84 | .shortname = "eofb", | ||
| 85 | .name = "EO on F/B", | ||
| 86 | .step = {&step_eofb_HTM, NULL}, | ||
| 87 | .t = {uf}, | ||
| 88 | .ready_msg = check_centers_msg, | ||
| 89 | }; | ||
| 90 | ChoiceStep | ||
| 91 | eorl_HTM = { | ||
| 92 | .shortname = "eorl", | ||
| 93 | .name = "EO on R/L", | ||
| 94 | .step = {&step_eofb_HTM, NULL}, | ||
| 95 | .t = {ur}, | ||
| 96 | .ready_msg = check_centers_msg, | ||
| 97 | }; | ||
| 98 | ChoiceStep | ||
| 99 | eoud_HTM = { | ||
| 100 | .shortname = "eoud", | ||
| 101 | .name = "EO on U/D", | ||
| 102 | .step = {&step_eofb_HTM, NULL}, | ||
| 103 | .t = {fd}, | ||
| 104 | .ready_msg = check_centers_msg, | ||
| 105 | }; | ||
| 106 | |||
| 107 | /* CO steps **************************/ | ||
| 108 | /* TODO: coany_HTM (generic), cofb_HTM, corl_HTM, coud_HTM */ | ||
| 109 | /* TODO: coany_URF (generic), cofb_URF, corl_URF, coud_URF */ | ||
| 110 | |||
| 111 | /* Misc corner steps *****************/ | ||
| 112 | /* TODO: cornershtr_HTM, cornershtr_URF, corners_HTM, corners_URF */ | ||
| 113 | /* TODO (new): corners_drud */ | ||
| 114 | |||
| 115 | /* DR steps **************************/ | ||
| 116 | /* TODO: dr_eo (generic) */ | ||
| 117 | /* TODO: dr_eofb (generic), dr_eorl (generic), dr_eoud (generic) */ | ||
| 118 | /* TODO: drud_eofb, drrl_eofb, drud_eorl, drfb_eorl, drrl_eoud, drfb_eoud */ | ||
| 119 | |||
| 120 | Step | ||
| 121 | step_drud_HTM = { | ||
| 122 | .ready = check_centers, | ||
| 123 | .final = false, | ||
| 124 | .moveset = &moveset_HTM, | ||
| 125 | .n_coord = 1, | ||
| 126 | .coord = {&coord_drud_sym16}, | ||
| 127 | .coord_trans = {uf}, | ||
| 128 | .is_valid = validate_singlecw_ending, | ||
| 129 | }; | ||
| 130 | ChoiceStep | ||
| 131 | drany_HTM = { | ||
| 132 | .shortname = "dr", | ||
| 133 | .name = "DR on any axis", | ||
| 134 | .step = {&step_drud_HTM, &step_drud_HTM, &step_drud_HTM, NULL}, | ||
| 135 | .t = {uf, rf, fd}, | ||
| 136 | .ready_msg = check_centers_msg, | ||
| 137 | }; | ||
| 138 | ChoiceStep | ||
| 139 | drud_HTM = { | ||
| 140 | .shortname = "drud", | ||
| 141 | .name = "DR on U/D", | ||
| 142 | .step = {&step_drud_HTM, NULL}, | ||
| 143 | .t = {uf}, | ||
| 144 | .ready_msg = check_centers_msg, | ||
| 145 | }; | ||
| 146 | ChoiceStep | ||
| 147 | drrl_HTM = { | ||
| 148 | .shortname = "drrl", | ||
| 149 | .name = "DR on R/L", | ||
| 150 | .step = {&step_drud_HTM, NULL}, | ||
| 151 | .t = {rf}, | ||
| 152 | .ready_msg = check_centers_msg, | ||
| 153 | }; | ||
| 154 | ChoiceStep | ||
| 155 | drfb_HTM = { | ||
| 156 | .shortname = "drfb", | ||
| 157 | .name = "DR on F/B", | ||
| 158 | .step = {&step_drud_HTM, NULL}, | ||
| 159 | .t = {fd}, | ||
| 160 | .ready_msg = check_centers_msg, | ||
| 161 | }; | ||
| 162 | |||
| 163 | /* DR finish steps */ | ||
| 164 | Step | ||
| 165 | step_drfin_drud = { | ||
| 166 | .ready = check_drud, | ||
| 167 | .final = true, | ||
| 168 | .moveset = &moveset_drud, | ||
| 169 | .n_coord = 1, | ||
| 170 | .coord = {&coord_drudfin_noE_sym16}, /* TODO: maybe no noE */ | ||
| 171 | .coord_trans = {uf}, | ||
| 172 | .is_valid = NULL, | ||
| 173 | }; | ||
| 174 | ChoiceStep | ||
| 175 | dranyfin_DR = { | ||
| 176 | .shortname = "drfin", | ||
| 177 | .name = "DR finish on any axis without breaking DR", | ||
| 178 | .step = {&step_drfin_drud, &step_drfin_drud, | ||
| 179 | &step_drfin_drud, NULL}, | ||
| 180 | .t = {uf, rf, fd}, | ||
| 181 | .ready_msg = check_dr_msg, | ||
| 182 | }; | ||
| 183 | ChoiceStep | ||
| 184 | drudfin_drud = { | ||
| 185 | .shortname = "drudfin", | ||
| 186 | .name = "DR finis on U/D without breaking DR", | ||
| 187 | .step = {&step_drfin_drud, NULL}, | ||
| 188 | .t = {uf}, | ||
| 189 | .ready_msg = check_dr_msg, | ||
| 190 | }; | ||
| 191 | ChoiceStep | ||
| 192 | drrlfin_drrl = { | ||
| 193 | .shortname = "drrlfin", | ||
| 194 | .name = "DR finish on R/L without breaking DR", | ||
| 195 | .step = {&step_drfin_drud, NULL}, | ||
| 196 | .t = {rf}, | ||
| 197 | .ready_msg = check_dr_msg, | ||
| 198 | }; | ||
| 199 | ChoiceStep | ||
| 200 | drfbfin_drfb = { | ||
| 201 | .shortname = "drfbfin", | ||
| 202 | .name = "DR finish on F/B without breaking DR", | ||
| 203 | .step = {&step_drfin_drud, NULL}, | ||
| 204 | .t = {fd}, | ||
| 205 | .ready_msg = check_dr_msg, | ||
| 206 | }; | ||
| 207 | |||
| 208 | /* HTR from DR */ | ||
| 209 | /* TODO: htr_any (generic), htr_drud, htr_drrl, htr_drfb */ | ||
| 210 | |||
| 211 | /* HTR finish */ | ||
| 212 | /* TODO: htrfin_htr */ | ||
| 213 | |||
| 214 | ChoiceStep *csteps[] = { | ||
| 215 | /* TODO: re-implement optimal | ||
| 216 | &optimal_HTM, | ||
| 217 | */ | ||
| 218 | |||
| 219 | &eoany_HTM, &eofb_HTM, &eorl_HTM, &eoud_HTM, | ||
| 220 | &drany_HTM, &drud_HTM, &drrl_HTM, &drfb_HTM, | ||
| 221 | &dranyfin_DR, &drudfin_drud, &drrlfin_drrl, &drfbfin_drfb, | ||
| 222 | |||
| 223 | NULL | ||
| 224 | /* TODO: | ||
| 225 | &optimal_light_HTM, | ||
| 226 | |||
| 227 | &eofin_eo, &eofbfin_eofb, &eorlfin_eorl, &eoudfin_eoud, | ||
| 228 | &coany_HTM, &coud_HTM, &corl_HTM, &cofb_HTM, | ||
| 229 | &coany_URF, &coud_URF, &corl_URF, &cofb_URF, | ||
| 230 | &dr_eo, &dr_eofb, &dr_eorl, &dr_eoud, | ||
| 231 | &drud_eofb, &drrl_eofb, | ||
| 232 | &drud_eorl, &drfb_eorl, | ||
| 233 | &drfb_eoud, &drrl_eoud, | ||
| 234 | &htr_any, &htr_drud, &htr_drrl, &htr_drfb, | ||
| 235 | &htrfin_htr, | ||
| 236 | &cornershtr_HTM, &cornershtr_URF, &corners_HTM, &corners_URF, | ||
| 237 | NULL | ||
| 238 | */ | ||
| 239 | |||
| 240 | }; | ||
| 241 | |||
| 242 | #endif | ||
| 243 | 16 | ||
| 244 | #endif | 17 | #endif |
diff --git a/src/symcoord.c b/src/symcoord.c new file mode 100644 index 0000000..20d7c28 --- /dev/null +++ b/src/symcoord.c | |||
| @@ -0,0 +1,687 @@ | |||
| 1 | #include "symcoord.h" | ||
| 2 | |||
| 3 | /* These constants have been computed generating the respective SymData */ | ||
| 4 | #define CLASSES_CP_16 2768 | ||
| 5 | #define CLASSES_EOFBEPOS_16 64430 | ||
| 6 | |||
| 7 | static uint64_t index_cp_sym16(Cube cube); | ||
| 8 | static uint64_t index_eofbepos_sym16(Cube cube); | ||
| 9 | static uint64_t index_drud_sym16(Cube cube); | ||
| 10 | static uint64_t index_drudfin_noE_sym16(Cube cube); | ||
| 11 | static uint64_t index_nxopt31(Cube cube); | ||
| 12 | |||
| 13 | static uint64_t move_cp_sym16(Move m, uint64_t ind); | ||
| 14 | static uint64_t move_eofbepos_sym16(Move m, uint64_t ind); | ||
| 15 | static uint64_t move_drud_sym16(Move m, uint64_t ind); | ||
| 16 | static uint64_t move_drudfin_noE_sym16(Move m, uint64_t ind); | ||
| 17 | static uint64_t move_nxopt31(Move m, uint64_t ind); | ||
| 18 | |||
| 19 | static int tfind_from_mask(uint64_t mask, Trans *ret); | ||
| 20 | static int tfind_drud_sym16(uint64_t ind, Trans *ret); | ||
| 21 | static int tfind_drudfin_noE_sym16(uint64_t ind, Trans *ret); | ||
| 22 | static int tfind_nxopt31(uint64_t ind, Trans *ret); | ||
| 23 | |||
| 24 | static uint64_t transform_cp(Trans t, uint64_t ind); | ||
| 25 | static uint64_t transform_eofbepos(Trans t, uint64_t ind); | ||
| 26 | static uint64_t transform_drud_sym16(Trans t, uint64_t ind); | ||
| 27 | static uint64_t transform_drudfin_noE_sym16(Trans t, uint64_t ind); | ||
| 28 | static uint64_t transform_nxopt31(Trans t, uint64_t ind); | ||
| 29 | |||
| 30 | static void gensym(SymData *sd); | ||
| 31 | static void init_symc_moves(); | ||
| 32 | static void init_symc_trans(); | ||
| 33 | static bool read_symdata_file(SymData *sd); | ||
| 34 | static bool read_symc_moves_file(); | ||
| 35 | static bool read_symc_trans_file(); | ||
| 36 | static bool write_symdata_file(SymData *sd); | ||
| 37 | static bool write_symc_moves_file(); | ||
| 38 | static bool write_symc_trans_file(); | ||
| 39 | |||
| 40 | /* Some tables ***************************************************************/ | ||
| 41 | |||
| 42 | static uint64_t move_cp_16[NMOVES][CLASSES_CP_16]; | ||
| 43 | static uint64_t move_eofbepos_16[NMOVES][CLASSES_EOFBEPOS_16]; | ||
| 44 | |||
| 45 | static int trans_eofbepos[NTRANS][POW2TO11*BINOM12ON4]; | ||
| 46 | static int trans_epud[NTRANS][FACTORIAL8]; | ||
| 47 | static int trans_cpud_separate[NTRANS][BINOM8ON4]; | ||
| 48 | |||
| 49 | static Trans ttrep_move_cp_16[NMOVES][CLASSES_CP_16]; | ||
| 50 | static Trans ttrep_move_eofbepos_16[NMOVES][CLASSES_EOFBEPOS_16]; | ||
| 51 | |||
| 52 | |||
| 53 | /* Transformation groups and symmetry data ***********************************/ | ||
| 54 | |||
| 55 | static Trans | ||
| 56 | trans_group_udfix[16] = { | ||
| 57 | uf, ur, ub, ul, | ||
| 58 | df, dr, db, dl, | ||
| 59 | uf_mirror, ur_mirror, ub_mirror, ul_mirror, | ||
| 60 | df_mirror, dr_mirror, db_mirror, dl_mirror, | ||
| 61 | }; | ||
| 62 | |||
| 63 | static SymData | ||
| 64 | sd_cp_16 = { | ||
| 65 | .filename = "sd_cp_16_new", | ||
| 66 | .coord = &coord_cp, | ||
| 67 | .sym_coord = &coord_cp_sym16, | ||
| 68 | .ntrans = 16, | ||
| 69 | .trans = trans_group_udfix, | ||
| 70 | .transform = transform_cp, | ||
| 71 | }; | ||
| 72 | |||
| 73 | static SymData | ||
| 74 | sd_eofbepos_16 = { | ||
| 75 | .filename = "sd_eofbepos_16_new", | ||
| 76 | .coord = &coord_eofbepos, | ||
| 77 | .sym_coord = &coord_eofbepos_sym16, | ||
| 78 | .ntrans = 16, | ||
| 79 | .trans = trans_group_udfix, | ||
| 80 | .transform = transform_eofbepos, | ||
| 81 | }; | ||
| 82 | |||
| 83 | SymData * all_sd[] = { | ||
| 84 | &sd_cp_16, | ||
| 85 | &sd_eofbepos_16, | ||
| 86 | NULL | ||
| 87 | }; | ||
| 88 | |||
| 89 | |||
| 90 | /* Coordinates and their implementation **************************************/ | ||
| 91 | |||
| 92 | Coordinate | ||
| 93 | coord_eofbepos_sym16 = { | ||
| 94 | .index = index_eofbepos_sym16, | ||
| 95 | .move = move_eofbepos_sym16, | ||
| 96 | }; | ||
| 97 | |||
| 98 | Coordinate | ||
| 99 | coord_cp_sym16 = { | ||
| 100 | .index = index_cp_sym16, | ||
| 101 | .move = move_cp_sym16, | ||
| 102 | }; | ||
| 103 | |||
| 104 | Coordinate | ||
| 105 | coord_drud_sym16 = { | ||
| 106 | .index = index_drud_sym16, | ||
| 107 | .move = move_drud_sym16, | ||
| 108 | .max = POW3TO7 * CLASSES_EOFBEPOS_16, | ||
| 109 | .base = &coord_eofbepos_sym16, | ||
| 110 | .transform = transform_drud_sym16, | ||
| 111 | .tfind = tfind_drud_sym16, | ||
| 112 | }; | ||
| 113 | |||
| 114 | Coordinate | ||
| 115 | coord_drudfin_noE_sym16 = { | ||
| 116 | .index = index_drudfin_noE_sym16, | ||
| 117 | .move = move_drudfin_noE_sym16, | ||
| 118 | .max = FACTORIAL8 * CLASSES_CP_16, | ||
| 119 | .base = &coord_cp_sym16, | ||
| 120 | .transform = transform_drudfin_noE_sym16, | ||
| 121 | .tfind = tfind_drudfin_noE_sym16, | ||
| 122 | }; | ||
| 123 | |||
| 124 | Coordinate | ||
| 125 | coord_nxopt31 = { | ||
| 126 | .index = index_nxopt31, | ||
| 127 | .move = move_nxopt31, | ||
| 128 | .max = POW3TO7 * BINOM8ON4 * CLASSES_EOFBEPOS_16, | ||
| 129 | .base = &coord_eofbepos_sym16, | ||
| 130 | .transform = transform_nxopt31, | ||
| 131 | .tfind = tfind_nxopt31, | ||
| 132 | }; | ||
| 133 | |||
| 134 | /* Functions *****************************************************************/ | ||
| 135 | |||
| 136 | static uint64_t | ||
| 137 | index_cp_sym16(Cube cube) | ||
| 138 | { | ||
| 139 | return sd_cp_16.class[coord_cp.index(cube)]; | ||
| 140 | } | ||
| 141 | |||
| 142 | static uint64_t | ||
| 143 | index_drud_sym16(Cube cube) | ||
| 144 | { | ||
| 145 | Trans t; | ||
| 146 | |||
| 147 | t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)]; | ||
| 148 | |||
| 149 | return index_eofbepos_sym16(cube) * POW3TO7 + co_ttable[t][cube.coud]; | ||
| 150 | } | ||
| 151 | |||
| 152 | static uint64_t | ||
| 153 | index_drudfin_noE_sym16(Cube cube) | ||
| 154 | { | ||
| 155 | Trans t; | ||
| 156 | Cube c; | ||
| 157 | |||
| 158 | t = sd_cp_16.transtorep[coord_cp.index(cube)]; | ||
| 159 | c = apply_trans(t, cube); | ||
| 160 | |||
| 161 | /* TODO: add transform to coord_epud to make this faster */ | ||
| 162 | return index_cp_sym16(c) * FACTORIAL8 + coord_epud.index(c); | ||
| 163 | } | ||
| 164 | |||
| 165 | static uint64_t | ||
| 166 | index_eofbepos_sym16(Cube cube) | ||
| 167 | { | ||
| 168 | return sd_eofbepos_16.class[coord_eofbepos.index(cube)]; | ||
| 169 | } | ||
| 170 | |||
| 171 | static uint64_t | ||
| 172 | index_nxopt31(Cube cube) | ||
| 173 | { | ||
| 174 | Trans t; | ||
| 175 | uint64_t a; | ||
| 176 | int coud, cp; | ||
| 177 | |||
| 178 | t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)]; | ||
| 179 | coud = co_ttable[t][cube.coud]; | ||
| 180 | cp = cp_ttable[t][cube.cp]; | ||
| 181 | a = (index_eofbepos_sym16(cube)*POW3TO7) + coud; | ||
| 182 | |||
| 183 | return a * BINOM8ON4 + coord_cpud_separate.index((Cube){.cp = cp}); | ||
| 184 | } | ||
| 185 | |||
| 186 | static uint64_t | ||
| 187 | move_cp_sym16(Move m, uint64_t ind) | ||
| 188 | { | ||
| 189 | return move_cp_16[m][ind]; | ||
| 190 | } | ||
| 191 | |||
| 192 | static uint64_t | ||
| 193 | move_eofbepos_sym16(Move m, uint64_t ind) | ||
| 194 | { | ||
| 195 | return move_eofbepos_16[m][ind]; | ||
| 196 | } | ||
| 197 | |||
| 198 | static uint64_t | ||
| 199 | move_drud_sym16(Move m, uint64_t ind) | ||
| 200 | { | ||
| 201 | uint64_t coud, eofbepos; | ||
| 202 | Trans ttr; | ||
| 203 | |||
| 204 | eofbepos = move_eofbepos_16[m][ind / POW3TO7]; | ||
| 205 | ttr = ttrep_move_eofbepos_16[m][ind / POW3TO7]; | ||
| 206 | coud = coud_mtable[m][ind % POW3TO7]; | ||
| 207 | coud = co_ttable[ttr][coud]; /* Source is always coud */ | ||
| 208 | |||
| 209 | return eofbepos * POW3TO7 + coud; | ||
| 210 | } | ||
| 211 | |||
| 212 | static uint64_t | ||
| 213 | move_drudfin_noE_sym16(Move m, uint64_t ind) | ||
| 214 | { | ||
| 215 | uint64_t cp, epud; | ||
| 216 | Trans ttr; | ||
| 217 | |||
| 218 | cp = move_cp_16[m][ind / FACTORIAL8]; | ||
| 219 | ttr = ttrep_move_cp_16[m][ind / FACTORIAL8]; | ||
| 220 | epud = coord_epud.move(m, ind % FACTORIAL8); | ||
| 221 | epud = trans_epud[ttr][epud]; | ||
| 222 | |||
| 223 | return cp * FACTORIAL8 + epud; | ||
| 224 | } | ||
| 225 | |||
| 226 | static uint64_t | ||
| 227 | move_nxopt31(Move m, uint64_t ind) | ||
| 228 | { | ||
| 229 | uint64_t eofbepos, cpsep, coud; | ||
| 230 | Trans ttr; | ||
| 231 | |||
| 232 | eofbepos = ind / (POW3TO7 * BINOM8ON4); | ||
| 233 | coud = (ind / BINOM8ON4) % POW3TO7; | ||
| 234 | cpsep = ind % BINOM8ON4; | ||
| 235 | |||
| 236 | ttr = ttrep_move_eofbepos_16[m][eofbepos]; | ||
| 237 | eofbepos = move_eofbepos_16[m][eofbepos]; | ||
| 238 | coud = coud_mtable[m][coud]; | ||
| 239 | coud = co_ttable[ttr][coud]; /* Source is always coud */ | ||
| 240 | cpsep = coord_cpud_separate.move(m, cpsep); | ||
| 241 | cpsep = trans_cpud_separate[ttr][cpsep]; | ||
| 242 | |||
| 243 | return (eofbepos * POW3TO7 + coud) * BINOM8ON4 + cpsep; | ||
| 244 | } | ||
| 245 | |||
| 246 | static uint64_t | ||
| 247 | transform_cp(Trans t, uint64_t ind) | ||
| 248 | { | ||
| 249 | return cp_ttable[t][ind]; | ||
| 250 | } | ||
| 251 | |||
| 252 | static uint64_t | ||
| 253 | transform_eofbepos(Trans t, uint64_t ind) | ||
| 254 | { | ||
| 255 | return trans_eofbepos[t][ind]; | ||
| 256 | } | ||
| 257 | |||
| 258 | static uint64_t | ||
| 259 | transform_drud_sym16(Trans t, uint64_t ind) | ||
| 260 | { | ||
| 261 | uint64_t coud, eofbepos; | ||
| 262 | |||
| 263 | eofbepos = ind / POW3TO7; /* Assum trans fixes eofbepos */ | ||
| 264 | coud = co_ttable[t][ind % POW3TO7]; /* Source is always coud */ | ||
| 265 | |||
| 266 | return eofbepos * POW3TO7 + coud; | ||
| 267 | } | ||
| 268 | |||
| 269 | static uint64_t | ||
| 270 | transform_drudfin_noE_sym16(Trans t, uint64_t ind) | ||
| 271 | { | ||
| 272 | uint64_t cp, epud; | ||
| 273 | |||
| 274 | cp = ind / FACTORIAL8; /* Assume trans fixes cp */ | ||
| 275 | epud = trans_epud[t][ind % FACTORIAL8]; | ||
| 276 | |||
| 277 | return cp * FACTORIAL8 + epud; | ||
| 278 | } | ||
| 279 | |||
| 280 | static uint64_t | ||
| 281 | transform_nxopt31(Trans t, uint64_t ind) | ||
| 282 | { | ||
| 283 | uint64_t eofbepos, cpsep, coud; | ||
| 284 | |||
| 285 | eofbepos = ind / (POW3TO7 * BINOM8ON4); | ||
| 286 | coud = (ind / BINOM8ON4) % POW3TO7; | ||
| 287 | cpsep = ind % BINOM8ON4; | ||
| 288 | |||
| 289 | coud = co_ttable[t][coud]; /* Source is always coud */ | ||
| 290 | cpsep = trans_cpud_separate[t][cpsep]; | ||
| 291 | |||
| 292 | return (eofbepos * POW3TO7 + coud) * BINOM8ON4 + cpsep; | ||
| 293 | } | ||
| 294 | |||
| 295 | static int | ||
| 296 | tfind_from_mask(uint64_t mask, Trans *ret) | ||
| 297 | { | ||
| 298 | Trans t; | ||
| 299 | int i = 0; | ||
| 300 | |||
| 301 | for (t = uf; t < NTRANS; t++) | ||
| 302 | if (((uint64_t)1 << t) & mask) | ||
| 303 | ret[i++] = t; | ||
| 304 | |||
| 305 | return i; | ||
| 306 | } | ||
| 307 | |||
| 308 | static int | ||
| 309 | tfind_drud_sym16(uint64_t ind, Trans *ret) | ||
| 310 | { | ||
| 311 | uint64_t mask = sd_eofbepos_16.selfsim[ind / POW3TO7]; | ||
| 312 | |||
| 313 | return tfind_from_mask(mask, ret); | ||
| 314 | } | ||
| 315 | |||
| 316 | static int | ||
| 317 | tfind_drudfin_noE_sym16(uint64_t ind, Trans *ret) | ||
| 318 | { | ||
| 319 | uint64_t mask = sd_cp_16.selfsim[ind / FACTORIAL8]; | ||
| 320 | |||
| 321 | return tfind_from_mask(mask, ret); | ||
| 322 | } | ||
| 323 | |||
| 324 | static int | ||
| 325 | tfind_nxopt31(uint64_t ind, Trans *ret) | ||
| 326 | { | ||
| 327 | uint64_t mask = sd_eofbepos_16.selfsim[ind / (POW3TO7 * BINOM8ON4)]; | ||
| 328 | |||
| 329 | return tfind_from_mask(mask, ret); | ||
| 330 | } | ||
| 331 | |||
| 332 | /* Other functions ***********************************************************/ | ||
| 333 | |||
| 334 | void | ||
| 335 | free_sd(SymData *sd) | ||
| 336 | { | ||
| 337 | if (sd->generated) { | ||
| 338 | free(sd->class); | ||
| 339 | free(sd->unsym); | ||
| 340 | free(sd->transtorep); | ||
| 341 | } | ||
| 342 | |||
| 343 | sd->generated = false; | ||
| 344 | } | ||
| 345 | |||
| 346 | static void | ||
| 347 | gensym(SymData *sd) | ||
| 348 | { | ||
| 349 | uint64_t i, in, nreps = 0; | ||
| 350 | Trans t; | ||
| 351 | int j; | ||
| 352 | |||
| 353 | if (sd->generated) | ||
| 354 | return; | ||
| 355 | |||
| 356 | sd->class = malloc(sd->coord->max * sizeof(uint64_t)); | ||
| 357 | sd->unsym = malloc(sd->coord->max * sizeof(uint64_t)); | ||
| 358 | sd->transtorep = malloc(sd->coord->max * sizeof(Trans)); | ||
| 359 | sd->selfsim = malloc(sd->coord->max * sizeof(uint64_t)); | ||
| 360 | |||
| 361 | if (read_symdata_file(sd)) { | ||
| 362 | sd->generated = true; | ||
| 363 | return; | ||
| 364 | } | ||
| 365 | |||
| 366 | fprintf(stderr, "Cannot load %s, generating it\n", sd->filename); | ||
| 367 | |||
| 368 | for (i = 0; i < sd->coord->max; i++) | ||
| 369 | sd->class[i] = sd->coord->max + 1; | ||
| 370 | |||
| 371 | for (i = 0; i < sd->coord->max; i++) { | ||
| 372 | if (sd->class[i] == sd->coord->max + 1) { | ||
| 373 | sd->unsym[nreps] = i; | ||
| 374 | sd->transtorep[i] = uf; | ||
| 375 | sd->selfsim[nreps] = (uint64_t)0; | ||
| 376 | for (j = 0; j < sd->ntrans; j++) { | ||
| 377 | t = sd->trans[j]; | ||
| 378 | in = sd->transform(t, i); | ||
| 379 | sd->class[in] = nreps; | ||
| 380 | if (in == i) | ||
| 381 | sd->selfsim[nreps] |= | ||
| 382 | ((uint64_t)1 << t); | ||
| 383 | else | ||
| 384 | sd->transtorep[in] = inverse_trans(t); | ||
| 385 | } | ||
| 386 | nreps++; | ||
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 390 | sd->sym_coord->max = nreps; | ||
| 391 | sd->unsym = realloc(sd->unsym, nreps * sizeof(uint64_t)); | ||
| 392 | sd->selfsim = realloc(sd->selfsim, nreps * sizeof(uint64_t)); | ||
| 393 | sd->generated = true; | ||
| 394 | |||
| 395 | fprintf(stderr, "Found %" PRIu64 " classes\n", nreps); | ||
| 396 | |||
| 397 | if (!write_symdata_file(sd)) | ||
| 398 | fprintf(stderr, "Error writing SymData file\n"); | ||
| 399 | |||
| 400 | return; | ||
| 401 | } | ||
| 402 | |||
| 403 | static bool | ||
| 404 | read_symdata_file(SymData *sd) | ||
| 405 | { | ||
| 406 | init_env(); | ||
| 407 | |||
| 408 | FILE *f; | ||
| 409 | char fname[strlen(tabledir)+100]; | ||
| 410 | uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max; | ||
| 411 | bool r = true; | ||
| 412 | |||
| 413 | strcpy(fname, tabledir); | ||
| 414 | strcat(fname, "/"); | ||
| 415 | strcat(fname, sd->filename); | ||
| 416 | |||
| 417 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 418 | return false; | ||
| 419 | |||
| 420 | r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1; | ||
| 421 | r = r && fread(sd->unsym, sizeof(uint64_t), *sn, f) == *sn; | ||
| 422 | r = r && fread(sd->selfsim, sizeof(uint64_t), *sn, f) == *sn; | ||
| 423 | r = r && fread(sd->class, sizeof(uint64_t), n, f) == n; | ||
| 424 | r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n; | ||
| 425 | |||
| 426 | fclose(f); | ||
| 427 | return r; | ||
| 428 | } | ||
| 429 | |||
| 430 | static bool | ||
| 431 | read_symc_moves_file() | ||
| 432 | { | ||
| 433 | init_env(); | ||
| 434 | |||
| 435 | Move m; | ||
| 436 | bool r = true; | ||
| 437 | FILE *f; | ||
| 438 | char fname[strlen(tabledir)+100]; | ||
| 439 | |||
| 440 | strcpy(fname, tabledir); | ||
| 441 | strcat(fname, "/symc_moves"); | ||
| 442 | |||
| 443 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 444 | return false; | ||
| 445 | |||
| 446 | for (m = 0; m < NMOVES; m++) { | ||
| 447 | r = r && fread(move_cp_16[m], sizeof(uint64_t), | ||
| 448 | CLASSES_CP_16, f) == CLASSES_CP_16; | ||
| 449 | r = r && fread(move_eofbepos_16[m], sizeof(uint64_t), | ||
| 450 | CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; | ||
| 451 | |||
| 452 | r = r && fread(ttrep_move_cp_16[m], sizeof(Trans), | ||
| 453 | CLASSES_CP_16, f) == CLASSES_CP_16; | ||
| 454 | r = r && fread(ttrep_move_eofbepos_16[m], sizeof(Trans), | ||
| 455 | CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; | ||
| 456 | } | ||
| 457 | |||
| 458 | fclose(f); | ||
| 459 | return r; | ||
| 460 | } | ||
| 461 | |||
| 462 | static bool | ||
| 463 | read_symc_trans_file() | ||
| 464 | { | ||
| 465 | init_env(); | ||
| 466 | |||
| 467 | Trans t; | ||
| 468 | bool r = true; | ||
| 469 | FILE *f; | ||
| 470 | char fname[strlen(tabledir)+100]; | ||
| 471 | |||
| 472 | strcpy(fname, tabledir); | ||
| 473 | strcat(fname, "/symc_trans"); | ||
| 474 | |||
| 475 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 476 | return false; | ||
| 477 | |||
| 478 | for (t = 0; t < NTRANS; t++) { | ||
| 479 | r = r && fread(trans_eofbepos[t], sizeof(int), | ||
| 480 | POW2TO11*BINOM12ON4, f) == POW2TO11*BINOM12ON4; | ||
| 481 | r = r && fread(trans_epud[t], sizeof(int), | ||
| 482 | FACTORIAL8, f) == FACTORIAL8; | ||
| 483 | r = r && fread(trans_cpud_separate[t], sizeof(int), | ||
| 484 | BINOM8ON4, f) == BINOM8ON4; | ||
| 485 | } | ||
| 486 | |||
| 487 | fclose(f); | ||
| 488 | return r; | ||
| 489 | } | ||
| 490 | |||
| 491 | static bool | ||
| 492 | write_symdata_file(SymData *sd) | ||
| 493 | { | ||
| 494 | init_env(); | ||
| 495 | |||
| 496 | FILE *f; | ||
| 497 | char fname[strlen(tabledir)+100]; | ||
| 498 | uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max; | ||
| 499 | bool r = true; | ||
| 500 | |||
| 501 | strcpy(fname, tabledir); | ||
| 502 | strcat(fname, "/"); | ||
| 503 | strcat(fname, sd->filename); | ||
| 504 | |||
| 505 | if ((f = fopen(fname, "wb")) == NULL) | ||
| 506 | return false; | ||
| 507 | |||
| 508 | r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1; | ||
| 509 | r = r && fwrite(sd->unsym, sizeof(uint64_t), *sn, f) == *sn; | ||
| 510 | r = r && fwrite(sd->selfsim, sizeof(uint64_t), *sn, f) == *sn; | ||
| 511 | r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n; | ||
| 512 | r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n; | ||
| 513 | |||
| 514 | fclose(f); | ||
| 515 | return r; | ||
| 516 | } | ||
| 517 | |||
| 518 | static bool | ||
| 519 | write_symc_moves_file() | ||
| 520 | { | ||
| 521 | init_env(); | ||
| 522 | |||
| 523 | Move m; | ||
| 524 | bool r = true; | ||
| 525 | FILE *f; | ||
| 526 | char fname[strlen(tabledir)+100]; | ||
| 527 | |||
| 528 | strcpy(fname, tabledir); | ||
| 529 | strcat(fname, "/symc_moves"); | ||
| 530 | |||
| 531 | if ((f = fopen(fname, "wb")) == NULL) | ||
| 532 | return false; | ||
| 533 | |||
| 534 | for (m = 0; m < NMOVES; m++) { | ||
| 535 | r = r && fwrite(move_cp_16[m], sizeof(uint64_t), | ||
| 536 | CLASSES_CP_16, f) == CLASSES_CP_16; | ||
| 537 | r = r && fwrite(move_eofbepos_16[m], sizeof(uint64_t), | ||
| 538 | CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; | ||
| 539 | |||
| 540 | r = r && fwrite(ttrep_move_cp_16[m], sizeof(Trans), | ||
| 541 | CLASSES_CP_16, f) == CLASSES_CP_16; | ||
| 542 | r = r && fwrite(ttrep_move_eofbepos_16[m], sizeof(Trans), | ||
| 543 | CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; | ||
| 544 | } | ||
| 545 | |||
| 546 | fclose(f); | ||
| 547 | return r; | ||
| 548 | } | ||
| 549 | |||
| 550 | static bool | ||
| 551 | write_symc_trans_file() | ||
| 552 | { | ||
| 553 | init_env(); | ||
| 554 | |||
| 555 | Trans t; | ||
| 556 | bool r = true; | ||
| 557 | FILE *f; | ||
| 558 | char fname[strlen(tabledir)+100]; | ||
| 559 | |||
| 560 | strcpy(fname, tabledir); | ||
| 561 | strcat(fname, "/symc_trans"); | ||
| 562 | |||
| 563 | if ((f = fopen(fname, "wb")) == NULL) | ||
| 564 | return false; | ||
| 565 | |||
| 566 | for (t = 0; t < NTRANS; t++) { | ||
| 567 | r = r && fwrite(trans_eofbepos[t], sizeof(int), | ||
| 568 | POW2TO11*BINOM12ON4, f) == POW2TO11*BINOM12ON4; | ||
| 569 | r = r && fwrite(trans_epud[t], sizeof(int), | ||
| 570 | FACTORIAL8, f) == FACTORIAL8; | ||
| 571 | r = r && fwrite(trans_cpud_separate[t], sizeof(int), | ||
| 572 | BINOM8ON4, f) == BINOM8ON4; | ||
| 573 | } | ||
| 574 | |||
| 575 | fclose(f); | ||
| 576 | return r; | ||
| 577 | } | ||
| 578 | |||
| 579 | static void | ||
| 580 | init_symc_moves() | ||
| 581 | { | ||
| 582 | uint64_t i, ii, coo; | ||
| 583 | Move j; | ||
| 584 | |||
| 585 | if (read_symc_moves_file()) | ||
| 586 | return; | ||
| 587 | |||
| 588 | for (i = 0; i < CLASSES_CP_16; i++) { | ||
| 589 | ii = sd_cp_16.unsym[i]; | ||
| 590 | for (j = 0; j < NMOVES; j++) { | ||
| 591 | coo = sd_cp_16.coord->move(j, ii); | ||
| 592 | move_cp_16[j][i] = sd_cp_16.class[coo]; | ||
| 593 | ttrep_move_cp_16[j][i] = sd_cp_16.transtorep[coo]; | ||
| 594 | } | ||
| 595 | } | ||
| 596 | |||
| 597 | for (i = 0; i < CLASSES_EOFBEPOS_16; i++) { | ||
| 598 | ii = sd_eofbepos_16.unsym[i]; | ||
| 599 | for (j = 0; j < NMOVES; j++) { | ||
| 600 | coo = sd_eofbepos_16.coord->move(j, ii); | ||
| 601 | move_eofbepos_16[j][i] = sd_eofbepos_16.class[coo]; | ||
| 602 | ttrep_move_eofbepos_16[j][i] = | ||
| 603 | sd_eofbepos_16.transtorep[coo]; | ||
| 604 | } | ||
| 605 | } | ||
| 606 | |||
| 607 | if (!write_symc_moves_file()) | ||
| 608 | fprintf(stderr, "Error writing SymMoves file\n"); | ||
| 609 | } | ||
| 610 | |||
| 611 | void | ||
| 612 | init_symc_trans() | ||
| 613 | { | ||
| 614 | uint64_t i; | ||
| 615 | int j, cp; | ||
| 616 | int epe[4] = {FR, FL, BL, BR}; | ||
| 617 | int a[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 }; | ||
| 618 | Cube c; | ||
| 619 | CubeArray *arr, *aux; | ||
| 620 | Trans t; | ||
| 621 | |||
| 622 | if (read_symc_trans_file()) | ||
| 623 | return; | ||
| 624 | |||
| 625 | for (i = 0; i < POW2TO11*BINOM12ON4; i++) { | ||
| 626 | for (j = 0; j < 16; j++) { | ||
| 627 | t = trans_group_udfix[j]; | ||
| 628 | |||
| 629 | arr = new_cubearray((Cube){0}, pf_edges); | ||
| 630 | int_to_sum_zero_array(i % POW2TO11, 2, 12, arr->eofb); | ||
| 631 | epos_to_compatible_ep((i / POW2TO11)*24, arr->ep, epe); | ||
| 632 | fix_eorleoud(arr); | ||
| 633 | c = arrays_to_cube(arr, pf_edges); | ||
| 634 | free_cubearray(arr, pf_edges); | ||
| 635 | |||
| 636 | c = apply_trans(t, c); | ||
| 637 | trans_eofbepos[t][i] = (c.epose/24)*POW2TO11 + c.eofb; | ||
| 638 | } | ||
| 639 | } | ||
| 640 | |||
| 641 | aux = malloc(sizeof(CubeArray)); | ||
| 642 | aux->ep = a; | ||
| 643 | for (i = 0; i < FACTORIAL8; i++) { | ||
| 644 | index_to_perm(i, 8, a); | ||
| 645 | c = arrays_to_cube(aux, pf_ep); | ||
| 646 | for (j = 0; j < 16; j++) { | ||
| 647 | t = trans_group_udfix[j]; | ||
| 648 | arr = new_cubearray(apply_trans(t, c), pf_ep); | ||
| 649 | trans_epud[t][i] = perm_to_index(arr->ep, 8); | ||
| 650 | free_cubearray(arr, pf_ep); | ||
| 651 | } | ||
| 652 | } | ||
| 653 | free(aux); | ||
| 654 | |||
| 655 | for (i = 0; i < BINOM8ON4; i++) { | ||
| 656 | cp = cpud_separate_ant[i]; | ||
| 657 | for (j = 0; j < 16; j++) { | ||
| 658 | t = trans_group_udfix[j]; | ||
| 659 | trans_cpud_separate[t][i] = | ||
| 660 | cpud_separate_ind[cp_ttable[t][cp]]; | ||
| 661 | } | ||
| 662 | } | ||
| 663 | |||
| 664 | if (!write_symc_trans_file()) | ||
| 665 | fprintf(stderr, "Error writing SymTrans file\n"); | ||
| 666 | } | ||
| 667 | |||
| 668 | void | ||
| 669 | init_symcoord() | ||
| 670 | { | ||
| 671 | int i; | ||
| 672 | |||
| 673 | static bool initialized = false; | ||
| 674 | if (initialized) | ||
| 675 | return; | ||
| 676 | initialized = true; | ||
| 677 | |||
| 678 | init_coord(); | ||
| 679 | |||
| 680 | init_symc_trans(); | ||
| 681 | |||
| 682 | for (i = 0; all_sd[i] != NULL; i++) | ||
| 683 | gensym(all_sd[i]); | ||
| 684 | |||
| 685 | init_symc_moves(); | ||
| 686 | } | ||
| 687 | |||
diff --git a/src/symcoord.h b/src/symcoord.h new file mode 100644 index 0000000..0882bff --- /dev/null +++ b/src/symcoord.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #ifndef SYMCOORD_H | ||
| 2 | #define SYMCOORD_H | ||
| 3 | |||
| 4 | #include "coord.h" | ||
| 5 | |||
| 6 | extern Coordinate coord_cp_sym16; | ||
| 7 | extern Coordinate coord_eofbepos_sym16; | ||
| 8 | extern Coordinate coord_drud_sym16; | ||
| 9 | extern Coordinate coord_drudfin_noE_sym16; | ||
| 10 | extern Coordinate coord_nxopt31; | ||
| 11 | |||
| 12 | extern SymData *all_sd[]; | ||
| 13 | |||
| 14 | void free_sd(SymData *sd); | ||
| 15 | void init_symcoord(); | ||
| 16 | |||
| 17 | #endif | ||
diff --git a/src/threader_eager.c b/src/threader_eager.c deleted file mode 100644 index 261b995..0000000 --- a/src/threader_eager.c +++ /dev/null | |||
| @@ -1,163 +0,0 @@ | |||
| 1 | #include <pthread.h> | ||
| 2 | #include "threader_eager.h" | ||
| 3 | |||
| 4 | typedef struct { | ||
| 5 | AlgList * sols; | ||
| 6 | pthread_mutex_t * sols_mutex; | ||
| 7 | } ThreadData; | ||
| 8 | |||
| 9 | typedef struct { | ||
| 10 | DfsArg * arg; | ||
| 11 | Solver * solver; | ||
| 12 | Threader * threader; | ||
| 13 | AlgList * starts; | ||
| 14 | AlgListNode ** node; | ||
| 15 | pthread_mutex_t * start_mutex; | ||
| 16 | } ThreadInitData; | ||
| 17 | |||
| 18 | static void append_sol(Alg *, void *); | ||
| 19 | static void * instance_thread(void *); | ||
| 20 | static void dispatch(DfsArg *, AlgList *, Solver *, Threader *); | ||
| 21 | static AlgList * possible_starts(DfsArg *, Solver *); | ||
| 22 | static int get_nsol(void *); | ||
| 23 | |||
| 24 | Threader threader_eager = { | ||
| 25 | .append_sol = append_sol, | ||
| 26 | .dispatch = dispatch, | ||
| 27 | .get_nsol = get_nsol, | ||
| 28 | }; | ||
| 29 | |||
| 30 | static void | ||
| 31 | append_sol(Alg *alg, void *threaddata) | ||
| 32 | { | ||
| 33 | ThreadData *td = (ThreadData *)threaddata; | ||
| 34 | |||
| 35 | pthread_mutex_lock(td->sols_mutex); | ||
| 36 | append_alg(td->sols, alg); | ||
| 37 | pthread_mutex_unlock(td->sols_mutex); | ||
| 38 | } | ||
| 39 | |||
| 40 | static AlgList * | ||
| 41 | possible_starts(DfsArg *arg, Solver *solver) | ||
| 42 | { | ||
| 43 | AlgList *ret = new_alglist(); | ||
| 44 | |||
| 45 | if (solver->is_solved(solver->param, arg->cubedata)) { | ||
| 46 | if (arg->opts->min_moves == 0 && arg->d == 0) | ||
| 47 | append_sol(new_alg(""), arg->threaddata); | ||
| 48 | return ret; | ||
| 49 | } | ||
| 50 | |||
| 51 | for (int i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) { | ||
| 52 | Move m = solver->moveset->sorted_moves[i]; | ||
| 53 | Alg *alg = new_alg(""); | ||
| 54 | append_move(alg, m, false); | ||
| 55 | append_alg(ret, alg); | ||
| 56 | free_alg(alg); | ||
| 57 | |||
| 58 | /* TODO: check if step not final */ | ||
| 59 | if (arg->opts->can_niss) { | ||
| 60 | alg = new_alg(""); | ||
| 61 | append_move(alg, m, true); | ||
| 62 | append_alg(ret, alg); | ||
| 63 | free_alg(alg); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | return ret; | ||
| 68 | } | ||
| 69 | |||
| 70 | static void * | ||
| 71 | instance_thread(void *arg) | ||
| 72 | { | ||
| 73 | ThreadInitData *tid = (ThreadInitData *)arg; | ||
| 74 | |||
| 75 | while (true) { | ||
| 76 | pthread_mutex_lock(tid->start_mutex); | ||
| 77 | AlgListNode *node = *(tid->node); | ||
| 78 | if (node == NULL) { | ||
| 79 | pthread_mutex_unlock(tid->start_mutex); | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | *(tid->node) = (*(tid->node))->next; | ||
| 83 | pthread_mutex_unlock(tid->start_mutex); | ||
| 84 | |||
| 85 | /* TODO: adjust for longer (arbitrarily long?) starting sequences */ | ||
| 86 | void *data = tid->solver->alloc_cubedata(tid->solver->param); | ||
| 87 | tid->solver->copy_cubedata( | ||
| 88 | tid->solver->param, tid->arg->cubedata, data); | ||
| 89 | bool inv = node->alg->inv[node->alg->len-1]; | ||
| 90 | if (inv) | ||
| 91 | tid->solver->invert_cube( | ||
| 92 | tid->solver->param, data); | ||
| 93 | tid->solver->apply_move( | ||
| 94 | tid->solver->param, data, node->alg->move[0]); | ||
| 95 | |||
| 96 | DfsArg newarg; | ||
| 97 | newarg.cubedata = data; | ||
| 98 | newarg.threaddata = tid->arg->threaddata; | ||
| 99 | newarg.opts = tid->arg->opts; | ||
| 100 | newarg.d = tid->arg->d; | ||
| 101 | newarg.niss = inv; | ||
| 102 | newarg.current_alg = new_alg(""); | ||
| 103 | copy_alg(node->alg, newarg.current_alg); | ||
| 104 | |||
| 105 | dfs(&newarg, tid->solver, tid->threader); | ||
| 106 | |||
| 107 | tid->solver->free_cubedata(tid->solver->param, data); | ||
| 108 | free_alg(newarg.current_alg); | ||
| 109 | } | ||
| 110 | |||
| 111 | return NULL; | ||
| 112 | } | ||
| 113 | |||
| 114 | static void | ||
| 115 | dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader) | ||
| 116 | { | ||
| 117 | int nthreads = arg->opts->nthreads; | ||
| 118 | ThreadInitData tid[nthreads]; | ||
| 119 | pthread_t t[nthreads]; | ||
| 120 | |||
| 121 | pthread_mutex_t *sols_mutex = malloc(sizeof(pthread_mutex_t)); | ||
| 122 | pthread_mutex_init(sols_mutex, NULL); | ||
| 123 | |||
| 124 | arg->threaddata = malloc(sizeof(ThreadData)); | ||
| 125 | ThreadData *td = (ThreadData *)arg->threaddata; | ||
| 126 | td->sols = sols; | ||
| 127 | td->sols_mutex = sols_mutex; | ||
| 128 | |||
| 129 | AlgList *starts = possible_starts(arg, solver); | ||
| 130 | AlgListNode *node = starts->first; | ||
| 131 | pthread_mutex_t *start_mutex = malloc(sizeof(pthread_mutex_t)); | ||
| 132 | pthread_mutex_init(start_mutex, NULL); | ||
| 133 | for (int i = 0; i < nthreads; i++) { | ||
| 134 | tid[i].arg = arg; | ||
| 135 | tid[i].solver = solver; | ||
| 136 | tid[i].threader = threader; | ||
| 137 | tid[i].starts = starts; | ||
| 138 | tid[i].node = &node; | ||
| 139 | tid[i].start_mutex = start_mutex; | ||
| 140 | |||
| 141 | pthread_create(&t[i], NULL, instance_thread, &tid[i]); | ||
| 142 | } | ||
| 143 | |||
| 144 | for (int i = 0; i < nthreads; i++) | ||
| 145 | pthread_join(t[i], NULL); | ||
| 146 | |||
| 147 | free(td); | ||
| 148 | free(sols_mutex); | ||
| 149 | free_alglist(starts); | ||
| 150 | free(start_mutex); | ||
| 151 | } | ||
| 152 | |||
| 153 | static int | ||
| 154 | get_nsol(void *threaddata) | ||
| 155 | { | ||
| 156 | ThreadData *td = (ThreadData *)threaddata; | ||
| 157 | |||
| 158 | pthread_mutex_lock(td->sols_mutex); | ||
| 159 | int n = td->sols->len; | ||
| 160 | pthread_mutex_unlock(td->sols_mutex); | ||
| 161 | |||
| 162 | return n; | ||
| 163 | } | ||
diff --git a/src/threader_eager.h b/src/threader_eager.h deleted file mode 100644 index e39b27f..0000000 --- a/src/threader_eager.h +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | #ifndef THREADER_EAGER_H | ||
| 2 | #define THREADER_EAGER_H | ||
| 3 | |||
| 4 | #include "solve.h" | ||
| 5 | |||
| 6 | extern Threader threader_eager; | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/src/threader_single.c b/src/threader_single.c deleted file mode 100644 index 232835d..0000000 --- a/src/threader_single.c +++ /dev/null | |||
| @@ -1,35 +0,0 @@ | |||
| 1 | #include "threader_single.h" | ||
| 2 | |||
| 3 | static void append_sol(Alg *, void *); | ||
| 4 | static void dispatch(DfsArg *, AlgList *, Solver *, Threader *); | ||
| 5 | static int get_nsol(void *); | ||
| 6 | |||
| 7 | Threader threader_single = { | ||
| 8 | .append_sol = append_sol, | ||
| 9 | .dispatch = dispatch, | ||
| 10 | .get_nsol = get_nsol, | ||
| 11 | }; | ||
| 12 | |||
| 13 | static void | ||
| 14 | append_sol(Alg *alg, void *threaddata) | ||
| 15 | { | ||
| 16 | append_alg((AlgList *)threaddata, alg); | ||
| 17 | } | ||
| 18 | |||
| 19 | static void | ||
| 20 | dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader) | ||
| 21 | { | ||
| 22 | arg->threaddata = sols; | ||
| 23 | arg->niss = false; | ||
| 24 | arg->current_alg = new_alg(""); | ||
| 25 | |||
| 26 | dfs(arg, solver, threader); | ||
| 27 | |||
| 28 | free_alg(arg->current_alg); | ||
| 29 | } | ||
| 30 | |||
| 31 | static int | ||
| 32 | get_nsol(void *threaddata) | ||
| 33 | { | ||
| 34 | return ((AlgList *)threaddata)->len; | ||
| 35 | } | ||
diff --git a/src/threader_single.h b/src/threader_single.h deleted file mode 100644 index 2c0bfab..0000000 --- a/src/threader_single.h +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | #ifndef THREADER_SINGLE_H | ||
| 2 | #define THREADER_SINGLE_H | ||
| 3 | |||
| 4 | #include "solve.h" | ||
| 5 | |||
| 6 | extern Threader threader_single; | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/src/trans.c b/src/trans.c index 898c2be..e267a17 100644 --- a/src/trans.c +++ b/src/trans.c | |||
| @@ -1,23 +1,31 @@ | |||
| 1 | #define TRANS_C | ||
| 2 | |||
| 3 | #include "trans.h" | 1 | #include "trans.h" |
| 4 | 2 | ||
| 5 | /* Local functions ***********************************************************/ | 3 | /* Local functions ***********************************************************/ |
| 6 | 4 | ||
| 5 | static bool read_ttables_file(); | ||
| 6 | static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); | ||
| 7 | static bool write_ttables_file(); | ||
| 8 | |||
| 7 | /* Tables and other data *****************************************************/ | 9 | /* Tables and other data *****************************************************/ |
| 8 | 10 | ||
| 9 | static Cube mirror_cube = { | 11 | static int ep_mirror[12] = { |
| 10 | .ep = { [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL, | 12 | [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL, |
| 11 | [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL, | 13 | [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL, |
| 12 | [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL }, | 14 | [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL |
| 13 | .cp = { [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL, | 15 | }; |
| 14 | [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL }, | 16 | |
| 15 | .xp = { [U_center] = U_center, [D_center] = D_center, | 17 | static int cp_mirror[8] = { |
| 18 | [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL, | ||
| 19 | [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL | ||
| 20 | }; | ||
| 21 | |||
| 22 | static int cpos_mirror[6] = { | ||
| 23 | [U_center] = U_center, [D_center] = D_center, | ||
| 16 | [R_center] = L_center, [L_center] = R_center, | 24 | [R_center] = L_center, [L_center] = R_center, |
| 17 | [F_center] = F_center, [B_center] = B_center } | 25 | [F_center] = F_center, [B_center] = B_center |
| 18 | }; | 26 | }; |
| 19 | 27 | ||
| 20 | static char rotation_alg_string[100][NROTATIONS] = { | 28 | static char rotation_alg_string[100][NROTATIONS] = { |
| 21 | [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3", | 29 | [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3", |
| 22 | [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2", | 30 | [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2", |
| 23 | [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3", | 31 | [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3", |
| @@ -26,39 +34,176 @@ static char rotation_alg_string[100][NROTATIONS] = { | |||
| 26 | [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3", | 34 | [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3", |
| 27 | }; | 35 | }; |
| 28 | 36 | ||
| 29 | Alg *rotation_alg_arr[NROTATIONS]; | 37 | static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */ |
| 30 | Move moves_ttable[NTRANS][NMOVES]; | 38 | static int eposs_source[NTRANS]; |
| 31 | Trans trans_ttable[NTRANS][NTRANS]; | 39 | static int eposm_source[NTRANS]; |
| 32 | Trans trans_itable[NTRANS]; | 40 | static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */ |
| 41 | static int eorl_source[NTRANS]; | ||
| 42 | static int eoud_source[NTRANS]; | ||
| 43 | static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */ | ||
| 44 | static int cofb_source[NTRANS]; | ||
| 45 | static int corl_source[NTRANS]; | ||
| 33 | 46 | ||
| 34 | /* Public functions **********************************************************/ | 47 | int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; |
| 48 | int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; | ||
| 49 | int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; | ||
| 50 | int eo_ttable[NTRANS][POW2TO11]; | ||
| 51 | int cp_ttable[NTRANS][FACTORIAL8]; | ||
| 52 | int co_ttable[NTRANS][POW3TO7]; | ||
| 53 | int cpos_ttable[NTRANS][FACTORIAL6]; | ||
| 54 | Move moves_ttable[NTRANS][NMOVES]; | ||
| 35 | 55 | ||
| 36 | void | 56 | /* Local functions implementation ********************************************/ |
| 37 | apply_trans(Trans t, Cube *cube) | 57 | |
| 58 | static bool | ||
| 59 | read_ttables_file() | ||
| 38 | { | 60 | { |
| 39 | Cube aux; | 61 | init_env(); |
| 40 | Alg *inv; | 62 | |
| 41 | int i; | 63 | FILE *f; |
| 64 | char fname[strlen(tabledir)+20]; | ||
| 65 | int b = sizeof(int); | ||
| 66 | bool r = true; | ||
| 67 | Move m; | ||
| 42 | 68 | ||
| 43 | inv = inverse_alg(rotation_alg(t % NROTATIONS)); | 69 | /* Table sizes, used for reading and writing files */ |
| 44 | copy_cube(cube, &aux); | 70 | uint64_t me[11] = { |
| 45 | make_solved(cube); | 71 | [0] = FACTORIAL12/FACTORIAL8, |
| 72 | [1] = FACTORIAL12/FACTORIAL8, | ||
| 73 | [2] = FACTORIAL12/FACTORIAL8, | ||
| 74 | [3] = POW2TO11, | ||
| 75 | [4] = FACTORIAL8, | ||
| 76 | [5] = POW3TO7, | ||
| 77 | [6] = FACTORIAL6, | ||
| 78 | [7] = NMOVES | ||
| 79 | }; | ||
| 80 | |||
| 81 | strcpy(fname, tabledir); | ||
| 82 | strcat(fname, "/"); | ||
| 83 | strcat(fname, "ttables"); | ||
| 84 | |||
| 85 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 86 | return false; | ||
| 46 | 87 | ||
| 47 | if (t >= NROTATIONS) | 88 | for (m = 0; m < NTRANS; m++) { |
| 48 | compose(&mirror_cube, cube); | 89 | r = r && fread(epose_ttable[m], b, me[0], f) == me[0]; |
| 49 | apply_alg(inv, cube); | 90 | r = r && fread(eposs_ttable[m], b, me[1], f) == me[1]; |
| 50 | compose(&aux, cube); | 91 | r = r && fread(eposm_ttable[m], b, me[2], f) == me[2]; |
| 51 | apply_alg(rotation_alg(t % NROTATIONS), cube); | 92 | r = r && fread(eo_ttable[m], b, me[3], f) == me[3]; |
| 52 | if (t >= NROTATIONS) { | 93 | r = r && fread(cp_ttable[m], b, me[4], f) == me[4]; |
| 53 | compose(&mirror_cube, cube); | 94 | r = r && fread(co_ttable[m], b, me[5], f) == me[5]; |
| 54 | for (i = 0; i < 8; i++) | 95 | r = r && fread(cpos_ttable[m], b, me[6], f) == me[6]; |
| 55 | cube->co[i] = (3 - cube->co[i]) % 3; | 96 | r = r && fread(moves_ttable[m], b, me[7], f) == me[7]; |
| 56 | } | 97 | } |
| 57 | 98 | ||
| 99 | fclose(f); | ||
| 100 | return r; | ||
| 101 | } | ||
| 102 | |||
| 103 | static Cube | ||
| 104 | rotate_via_compose(Trans r, Cube c, PieceFilter f) | ||
| 105 | { | ||
| 106 | static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
| 107 | static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
| 108 | static CubeArray ma = { | ||
| 109 | .ep = ep_mirror, | ||
| 110 | .eofb = zero12, | ||
| 111 | .eorl = zero12, | ||
| 112 | .eoud = zero12, | ||
| 113 | .cp = cp_mirror, | ||
| 114 | .coud = zero8, | ||
| 115 | .corl = zero8, | ||
| 116 | .cofb = zero8, | ||
| 117 | .cpos = cpos_mirror | ||
| 118 | }; | ||
| 119 | |||
| 120 | Alg *inv = inverse_alg(rotation_alg(r)); | ||
| 121 | Cube ret = {0}; | ||
| 122 | |||
| 123 | if (r >= NROTATIONS) | ||
| 124 | ret = move_via_arrays(&ma, ret, f); | ||
| 125 | ret = apply_alg_generic(inv, ret, f, true); | ||
| 126 | |||
| 127 | ret = compose_filtered(c, ret, f); | ||
| 128 | |||
| 129 | ret = apply_alg_generic(rotation_alg(r), ret, f, true); | ||
| 130 | if (r >= NROTATIONS) | ||
| 131 | ret = move_via_arrays(&ma, ret, f); | ||
| 132 | |||
| 58 | free_alg(inv); | 133 | free_alg(inv); |
| 134 | return ret; | ||
| 135 | } | ||
| 136 | |||
| 137 | static bool | ||
| 138 | write_ttables_file() | ||
| 139 | { | ||
| 140 | init_env(); | ||
| 141 | |||
| 142 | FILE *f; | ||
| 143 | char fname[strlen(tabledir)+20]; | ||
| 144 | bool r = true; | ||
| 145 | int b = sizeof(int); | ||
| 146 | Move m; | ||
| 147 | |||
| 148 | /* Table sizes, used for reading and writing files */ | ||
| 149 | uint64_t me[11] = { | ||
| 150 | [0] = FACTORIAL12/FACTORIAL8, | ||
| 151 | [1] = FACTORIAL12/FACTORIAL8, | ||
| 152 | [2] = FACTORIAL12/FACTORIAL8, | ||
| 153 | [3] = POW2TO11, | ||
| 154 | [4] = FACTORIAL8, | ||
| 155 | [5] = POW3TO7, | ||
| 156 | [6] = FACTORIAL6, | ||
| 157 | [7] = NMOVES | ||
| 158 | }; | ||
| 159 | |||
| 160 | strcpy(fname, tabledir); | ||
| 161 | strcat(fname, "/ttables"); | ||
| 162 | |||
| 163 | if ((f = fopen(fname, "wb")) == NULL) | ||
| 164 | return false; | ||
| 165 | |||
| 166 | for (m = 0; m < NTRANS; m++) { | ||
| 167 | r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0]; | ||
| 168 | r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1]; | ||
| 169 | r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2]; | ||
| 170 | r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3]; | ||
| 171 | r = r && fwrite(cp_ttable[m], b, me[4], f) == me[4]; | ||
| 172 | r = r && fwrite(co_ttable[m], b, me[5], f) == me[5]; | ||
| 173 | r = r && fwrite(cpos_ttable[m], b, me[6], f) == me[6]; | ||
| 174 | r = r && fwrite(moves_ttable[m], b, me[7], f) == me[7]; | ||
| 175 | } | ||
| 176 | |||
| 177 | fclose(f); | ||
| 178 | return r; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* Public functions **********************************************************/ | ||
| 182 | |||
| 183 | Cube | ||
| 184 | apply_trans(Trans t, Cube cube) | ||
| 185 | { | ||
| 186 | /*init_trans();*/ | ||
| 187 | |||
| 188 | int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm }; | ||
| 189 | int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb }; | ||
| 190 | int aux_co[3] = { cube.coud, cube.corl, cube.cofb }; | ||
| 191 | |||
| 192 | return (Cube) { | ||
| 193 | .epose = epose_ttable[t][aux_epos[epose_source[t]]], | ||
| 194 | .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]], | ||
| 195 | .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]], | ||
| 196 | .eofb = eo_ttable[t][aux_eo[eofb_source[t]]], | ||
| 197 | .eorl = eo_ttable[t][aux_eo[eorl_source[t]]], | ||
| 198 | .eoud = eo_ttable[t][aux_eo[eoud_source[t]]], | ||
| 199 | .coud = co_ttable[t][aux_co[coud_source[t]]], | ||
| 200 | .corl = co_ttable[t][aux_co[corl_source[t]]], | ||
| 201 | .cofb = co_ttable[t][aux_co[cofb_source[t]]], | ||
| 202 | .cp = cp_ttable[t][cube.cp], | ||
| 203 | .cpos = cpos_ttable[t][cube.cpos] | ||
| 204 | }; | ||
| 59 | } | 205 | } |
| 60 | 206 | ||
| 61 | /* | ||
| 62 | Trans | 207 | Trans |
| 63 | inverse_trans(Trans t) | 208 | inverse_trans(Trans t) |
| 64 | { | 209 | { |
| @@ -86,18 +231,23 @@ inverse_trans(Trans t) | |||
| 86 | 231 | ||
| 87 | return inverse_trans_aux[t]; | 232 | return inverse_trans_aux[t]; |
| 88 | } | 233 | } |
| 89 | */ | ||
| 90 | |||
| 91 | Trans | ||
| 92 | inverse_trans(Trans t) | ||
| 93 | { | ||
| 94 | return trans_itable[t]; | ||
| 95 | } | ||
| 96 | 234 | ||
| 97 | Alg * | 235 | Alg * |
| 98 | rotation_alg(Trans i) | 236 | rotation_alg(Trans t) |
| 99 | { | 237 | { |
| 100 | return rotation_alg_arr[i % NROTATIONS]; | 238 | int i; |
| 239 | |||
| 240 | static Alg *rotation_alg_arr[NROTATIONS]; | ||
| 241 | static bool initialized = false; | ||
| 242 | |||
| 243 | if (!initialized) { | ||
| 244 | for (i = 0; i < NROTATIONS; i++) | ||
| 245 | rotation_alg_arr[i] = new_alg(rotation_alg_string[i]); | ||
| 246 | |||
| 247 | initialized = true; | ||
| 248 | } | ||
| 249 | |||
| 250 | return rotation_alg_arr[t % NROTATIONS]; | ||
| 101 | } | 251 | } |
| 102 | 252 | ||
| 103 | void | 253 | void |
| @@ -105,20 +255,10 @@ transform_alg(Trans t, Alg *alg) | |||
| 105 | { | 255 | { |
| 106 | int i; | 256 | int i; |
| 107 | 257 | ||
| 258 | /*init_trans();*/ | ||
| 259 | |||
| 108 | for (i = 0; i < alg->len; i++) | 260 | for (i = 0; i < alg->len; i++) |
| 109 | alg->move[i] = transform_move(t, alg->move[i]); | 261 | alg->move[i] = moves_ttable[t][alg->move[i]]; |
| 110 | } | ||
| 111 | |||
| 112 | Move | ||
| 113 | transform_move(Trans t, Move m) | ||
| 114 | { | ||
| 115 | return moves_ttable[t][m]; | ||
| 116 | } | ||
| 117 | |||
| 118 | Trans | ||
| 119 | transform_trans(Trans t, Trans m) | ||
| 120 | { | ||
| 121 | return trans_ttable[t][m]; | ||
| 122 | } | 262 | } |
| 123 | 263 | ||
| 124 | void | 264 | void |
| @@ -128,63 +268,106 @@ init_trans() { | |||
| 128 | return; | 268 | return; |
| 129 | initialized = true; | 269 | initialized = true; |
| 130 | 270 | ||
| 131 | int i; | 271 | init_moves(); |
| 132 | Alg *nonsym_alg, *nonsym_inv; | 272 | |
| 133 | Cube aux, cube; | 273 | Cube aux, cube, c[3]; |
| 274 | CubeArray epcp; | ||
| 275 | int i, eparr[12], eoarr[12], cparr[8], coarr[8]; | ||
| 276 | unsigned int ui; | ||
| 134 | Move mi, move; | 277 | Move mi, move; |
| 135 | Trans t, u, v; | 278 | Trans m; |
| 136 | 279 | ||
| 137 | init_moves(); | 280 | /* Compute sources */ |
| 281 | for (i = 0; i < NTRANS; i++) { | ||
| 282 | cube = apply_alg(rotation_alg(i), (Cube){0}); | ||
| 283 | |||
| 284 | epose_source[i] = edge_slice(what_edge_at(cube, FR)); | ||
| 285 | eposs_source[i] = edge_slice(what_edge_at(cube, UR)); | ||
| 286 | eposm_source[i] = edge_slice(what_edge_at(cube, UF)); | ||
| 287 | eofb_source[i] = what_center_at(cube, F_center)/2; | ||
| 288 | eorl_source[i] = what_center_at(cube, R_center)/2; | ||
| 289 | eoud_source[i] = what_center_at(cube, U_center)/2; | ||
| 290 | coud_source[i] = what_center_at(cube, U_center)/2; | ||
| 291 | cofb_source[i] = what_center_at(cube, F_center)/2; | ||
| 292 | corl_source[i] = what_center_at(cube, R_center)/2; | ||
| 293 | } | ||
| 138 | 294 | ||
| 139 | for (i = 0; i < NROTATIONS; i++) | 295 | if (read_ttables_file()) |
| 140 | rotation_alg_arr[i] = new_alg(rotation_alg_string[i]); | 296 | return; |
| 297 | |||
| 298 | fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); | ||
| 141 | 299 | ||
| 142 | for (t = 0; t < NTRANS; t++) { | 300 | /* Initialize tables */ |
| 301 | for (m = 0; m < NTRANS; m++) { | ||
| 302 | epcp = (CubeArray){ .ep = eparr, .cp = cparr }; | ||
| 303 | cube = apply_alg(rotation_alg(m), (Cube){0}); | ||
| 304 | cube_to_arrays(cube, &epcp, pf_epcp); | ||
| 305 | if (m >= NROTATIONS) { | ||
| 306 | apply_permutation(ep_mirror, eparr, 12); | ||
| 307 | apply_permutation(cp_mirror, cparr, 8); | ||
| 308 | } | ||
| 309 | |||
| 310 | for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { | ||
| 311 | c[0] = admissible_ep((Cube){ .epose = ui }, pf_e); | ||
| 312 | c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s); | ||
| 313 | c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m); | ||
| 314 | |||
| 315 | cube = rotate_via_compose(m,c[epose_source[m]],pf_ep); | ||
| 316 | epose_ttable[m][ui] = cube.epose; | ||
| 317 | |||
| 318 | cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep); | ||
| 319 | eposs_ttable[m][ui] = cube.eposs; | ||
| 320 | |||
| 321 | cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep); | ||
| 322 | eposm_ttable[m][ui] = cube.eposm; | ||
| 323 | } | ||
| 324 | for (ui = 0; ui < POW2TO11; ui++ ) { | ||
| 325 | int_to_sum_zero_array(ui, 2, 12, eoarr); | ||
| 326 | apply_permutation(eparr, eoarr, 12); | ||
| 327 | eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2); | ||
| 328 | } | ||
| 329 | for (ui = 0; ui < POW3TO7; ui++) { | ||
| 330 | int_to_sum_zero_array(ui, 3, 8, coarr); | ||
| 331 | apply_permutation(cparr, coarr, 8); | ||
| 332 | co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3); | ||
| 333 | if (m >= NROTATIONS) | ||
| 334 | co_ttable[m][ui] = | ||
| 335 | invert_digits(co_ttable[m][ui], 3, 7); | ||
| 336 | } | ||
| 337 | for (ui = 0; ui < FACTORIAL8; ui++) { | ||
| 338 | cube = (Cube){ .cp = ui }; | ||
| 339 | cube = rotate_via_compose(m, cube, pf_cp); | ||
| 340 | cp_ttable[m][ui] = cube.cp; | ||
| 341 | } | ||
| 342 | for (ui = 0; ui < FACTORIAL6; ui++) { | ||
| 343 | cube = (Cube){ .cpos = ui }; | ||
| 344 | cube = rotate_via_compose(m, cube, pf_cpos); | ||
| 345 | cpos_ttable[m][ui] = cube.cpos; | ||
| 346 | } | ||
| 143 | for (mi = 0; mi < NMOVES; mi++) { | 347 | for (mi = 0; mi < NMOVES; mi++) { |
| 144 | make_solved(&aux); | 348 | /* Old version: |
| 145 | apply_move(mi, &aux); | 349 | * |
| 146 | apply_trans(t, &aux); | 350 | aux = apply_trans(m, apply_move(mi, (Cube){0})); |
| 147 | for (move = 0; move < NMOVES; move++) { | 351 | for (move = 0; move < NMOVES; move++) { |
| 148 | copy_cube(&aux, &cube); | 352 | cube = apply_move(inverse_move(move), aux); |
| 149 | apply_move(inverse_move(move), &cube); | 353 | mirr = apply_trans(uf_mirror, cube); |
| 150 | if (is_solved(&cube)) { | 354 | if (is_solved(cube) || is_solved(mirr)) |
| 151 | moves_ttable[t][mi] = move; | 355 | moves_ttable[m][mi] = move; |
| 152 | break; | ||
| 153 | } | ||
| 154 | } | 356 | } |
| 155 | } | 357 | */ |
| 156 | } | ||
| 157 | 358 | ||
| 158 | nonsym_alg = new_alg("R' U' F"); | 359 | aux = apply_trans(m, apply_move(mi, (Cube){0})); |
| 159 | nonsym_inv = inverse_alg(nonsym_alg); | 360 | for (move = 0; move < NMOVES; move++) { |
| 160 | 361 | cube = apply_move(inverse_move(move), aux); | |
| 161 | for (t = 0; t < NTRANS; t++) { | 362 | if (is_solved(cube)) { |
| 162 | for (u = 0; u < NTRANS; u++) { | 363 | moves_ttable[m][mi] = move; |
| 163 | make_solved(&aux); | ||
| 164 | apply_alg(nonsym_alg, &aux); | ||
| 165 | apply_trans(u, &aux); | ||
| 166 | apply_trans(t, &aux); | ||
| 167 | for (v = 0; v < NTRANS; v++) { | ||
| 168 | copy_cube(&aux, &cube); | ||
| 169 | apply_trans(v, &cube); | ||
| 170 | apply_alg(nonsym_inv, &cube); | ||
| 171 | if (is_solved(&cube)) { | ||
| 172 | /* This is the inverse of the correct | ||
| 173 | value, it will be inverted later */ | ||
| 174 | trans_ttable[t][u] = v; | ||
| 175 | if (v == uf) | ||
| 176 | trans_itable[t] = u; | ||
| 177 | break; | 364 | break; |
| 178 | } | 365 | } |
| 179 | } | 366 | } |
| 180 | } | 367 | } |
| 181 | } | 368 | } |
| 182 | for (t = 0; t < NTRANS; t++) | ||
| 183 | for (u = 0; u < NTRANS; u++) | ||
| 184 | trans_ttable[t][u] = trans_itable[trans_ttable[t][u]]; | ||
| 185 | |||
| 186 | 369 | ||
| 187 | free_alg(nonsym_alg); | 370 | if (!write_ttables_file()) |
| 188 | free_alg(nonsym_inv); | 371 | fprintf(stderr, "Error writing ttables\n"); |
| 189 | } | 372 | } |
| 190 | 373 | ||
diff --git a/src/trans.h b/src/trans.h index 0cc8cef..51df12f 100644 --- a/src/trans.h +++ b/src/trans.h | |||
| @@ -3,30 +3,24 @@ | |||
| 3 | 3 | ||
| 4 | #include "moves.h" | 4 | #include "moves.h" |
| 5 | 5 | ||
| 6 | void apply_trans(Trans t, Cube *cube); | 6 | /* |
| 7 | * Tables are exposed to allow faster partial transformations in some | ||
| 8 | * specific cases (in symcoord) | ||
| 9 | */ | ||
| 10 | extern int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; | ||
| 11 | extern int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; | ||
| 12 | extern int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; | ||
| 13 | extern int eo_ttable[NTRANS][POW2TO11]; | ||
| 14 | extern int cp_ttable[NTRANS][FACTORIAL8]; | ||
| 15 | extern int co_ttable[NTRANS][POW3TO7]; | ||
| 16 | extern int cpos_ttable[NTRANS][FACTORIAL6]; | ||
| 17 | extern Move moves_ttable[NTRANS][NMOVES]; | ||
| 18 | |||
| 19 | Cube apply_trans(Trans t, Cube cube); | ||
| 7 | Trans inverse_trans(Trans t); | 20 | Trans inverse_trans(Trans t); |
| 8 | Alg * rotation_alg(Trans i); | 21 | Alg * rotation_alg(Trans i); |
| 9 | void transform_alg(Trans t, Alg *alg); | 22 | void transform_alg(Trans i, Alg *alg); |
| 10 | Move transform_move(Trans t, Move m); | ||
| 11 | Trans transform_trans(Trans t, Trans m); | ||
| 12 | 23 | ||
| 13 | void init_trans(); | 24 | void init_trans(); |
| 14 | 25 | ||
| 15 | #ifndef TRANS_C | ||
| 16 | |||
| 17 | extern TransGroup tgrp_udfix; | ||
| 18 | |||
| 19 | #else | ||
| 20 | |||
| 21 | TransGroup | ||
| 22 | tgrp_udfix = { | ||
| 23 | .n = 16, | ||
| 24 | .t = { uf, ur, ub, ul, | ||
| 25 | df, dr, db, dl, | ||
| 26 | uf_mirror, ur_mirror, ub_mirror, ul_mirror, | ||
| 27 | df_mirror, dr_mirror, db_mirror, dl_mirror }, | ||
| 28 | }; | ||
| 29 | |||
| 30 | #endif | ||
| 31 | |||
| 32 | #endif | 26 | #endif |
diff --git a/src/utils.c b/src/utils.c index cbf951e..e0d3268 100644 --- a/src/utils.c +++ b/src/utils.c | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | #define UTILS_C | ||
| 2 | |||
| 3 | #include "utils.h" | 1 | #include "utils.h" |
| 4 | 2 | ||
| 5 | void | 3 | void |
| @@ -161,24 +159,24 @@ is_perm(int *a, int n) | |||
| 161 | { | 159 | { |
| 162 | int *aux = malloc(n * sizeof(int)); | 160 | int *aux = malloc(n * sizeof(int)); |
| 163 | int i; | 161 | int i; |
| 164 | bool ret = true; | ||
| 165 | 162 | ||
| 166 | for (i = 0; i < n; i++) | 163 | for (i = 0; i < n; i++) |
| 167 | aux[i] = 0; | 164 | aux[i] = 0; |
| 168 | 165 | ||
| 169 | for (i = 0; i < n; i++) { | 166 | for (i = 0; i < n; i++) { |
| 170 | if (a[i] < 0 || a[i] >= n) | 167 | if (a[i] < 0 || a[i] >= n) |
| 171 | ret = false; | 168 | return false; |
| 172 | else | 169 | else |
| 173 | aux[a[i]] = 1; | 170 | aux[a[i]] = 1; |
| 174 | } | 171 | } |
| 175 | 172 | ||
| 176 | for (i = 0; i < n; i++) | 173 | for (i = 0; i < n; i++) |
| 177 | if (!aux[i]) | 174 | if (!aux[i]) |
| 178 | ret = false; | 175 | return false; |
| 179 | 176 | ||
| 180 | free(aux); | 177 | free(aux); |
| 181 | return ret; | 178 | |
| 179 | return true; | ||
| 182 | } | 180 | } |
| 183 | 181 | ||
| 184 | bool | 182 | bool |
| @@ -197,7 +195,7 @@ perm_sign(int *a, int n) | |||
| 197 | { | 195 | { |
| 198 | int i, j, ret = 0; | 196 | int i, j, ret = 0; |
| 199 | 197 | ||
| 200 | if (!is_perm(a, n)) | 198 | if (!is_perm(a,n)) |
| 201 | return -1; | 199 | return -1; |
| 202 | 200 | ||
| 203 | for (i = 0; i < n; i++) | 201 | for (i = 0; i < n; i++) |
| @@ -213,7 +211,7 @@ perm_to_index(int *a, int n) | |||
| 213 | int i, j, c, ret = 0; | 211 | int i, j, c, ret = 0; |
| 214 | 212 | ||
| 215 | if (!is_perm(a, n)) | 213 | if (!is_perm(a, n)) |
| 216 | return factorial(n); | 214 | return -1; |
| 217 | 215 | ||
| 218 | for (i = 0; i < n; i++) { | 216 | for (i = 0; i < n; i++) { |
| 219 | c = 0; | 217 | c = 0; |
diff --git a/tests/alg_tests.c b/tests/alg_tests.c deleted file mode 100644 index 9ac1595..0000000 --- a/tests/alg_tests.c +++ /dev/null | |||
| @@ -1,266 +0,0 @@ | |||
| 1 | #include "alg_tests.h" | ||
| 2 | |||
| 3 | bool testmethod_append_move(void *); | ||
| 4 | bool testmethod_new_alg(void *); | ||
| 5 | /* | ||
| 6 | bool testmethod_compose_alg(void *); | ||
| 7 | bool testmethod_inverse_alg(void *); | ||
| 8 | bool testmethod_on_inverse(void *); | ||
| 9 | bool testmethod_unniss(void *); | ||
| 10 | */ | ||
| 11 | |||
| 12 | typedef struct { | ||
| 13 | Move *move; | ||
| 14 | bool *inv; | ||
| 15 | int len; | ||
| 16 | Move m; | ||
| 17 | bool inverse; | ||
| 18 | } append_move_t; | ||
| 19 | |||
| 20 | Move m_app1[] = {F, x, D3}; | ||
| 21 | bool i_app1[] = {true, false, false}; | ||
| 22 | append_move_t append_move_case1 = { | ||
| 23 | .move = m_app1, | ||
| 24 | .inv = i_app1, | ||
| 25 | .len = 3, | ||
| 26 | .m = L3, | ||
| 27 | .inverse = false, | ||
| 28 | }; | ||
| 29 | |||
| 30 | Move m_app2[] = {S, U, x2, M2}; | ||
| 31 | bool i_app2[] = {true, false, true, true}; | ||
| 32 | append_move_t append_move_case2 = { | ||
| 33 | .move = m_app2, | ||
| 34 | .inv = i_app2, | ||
| 35 | .len = 4, | ||
| 36 | .m = R, | ||
| 37 | .inverse = true, | ||
| 38 | }; | ||
| 39 | |||
| 40 | Move m_app3[] = {U, U, U, U, U}; | ||
| 41 | bool i_app3[] = {false, false, false, false, false}; | ||
| 42 | append_move_t append_move_case3 = { | ||
| 43 | .move = m_app3, | ||
| 44 | .inv = i_app3, | ||
| 45 | .len = 5, | ||
| 46 | .m = U, | ||
| 47 | .inverse = false, | ||
| 48 | }; | ||
| 49 | |||
| 50 | append_move_t *append_move_cases[] = { | ||
| 51 | &append_move_case1, | ||
| 52 | &append_move_case2, | ||
| 53 | &append_move_case3, | ||
| 54 | }; | ||
| 55 | |||
| 56 | Test test_append_move = { | ||
| 57 | .name = "Appending a move to and alg", | ||
| 58 | .t = testmethod_append_move, | ||
| 59 | .cases = (void **)append_move_cases, | ||
| 60 | }; | ||
| 61 | |||
| 62 | typedef struct { | ||
| 63 | char *str; | ||
| 64 | Move *move; | ||
| 65 | bool *inv; | ||
| 66 | int len; | ||
| 67 | Move *move_normal; | ||
| 68 | int len_normal; | ||
| 69 | Move *move_inverse; | ||
| 70 | int len_inverse; | ||
| 71 | } new_alg_t; | ||
| 72 | |||
| 73 | /* Alg F U B' (L3 D) x M (S) y3 */ | ||
| 74 | Move m_new1[] = {F, U, B3, L3, D, x, M, S, y3}; | ||
| 75 | Move mn_new1[] = {F, U, B3, x, M, y3}; | ||
| 76 | Move mi_new1[] = {L3, D, S}; | ||
| 77 | bool i_new1[] = {false, false, false, true, true, false, false, true, false}; | ||
| 78 | new_alg_t new_alg_case1 = { | ||
| 79 | .str = "F U B' (L3 D) x M (S) y3", | ||
| 80 | .move = m_new1, | ||
| 81 | .inv = i_new1, | ||
| 82 | .len = 9, | ||
| 83 | .move_normal = mn_new1, | ||
| 84 | .len_normal = 6, | ||
| 85 | .move_inverse = mi_new1, | ||
| 86 | .len_inverse = 3, | ||
| 87 | }; | ||
| 88 | new_alg_t *new_alg_cases[] = {&new_alg_case1}; | ||
| 89 | |||
| 90 | Test test_new_alg = { | ||
| 91 | .name = "Initializing an alg from a string", | ||
| 92 | .t = testmethod_new_alg, | ||
| 93 | .cases = (void **)new_alg_cases, | ||
| 94 | }; | ||
| 95 | |||
| 96 | Test *alg_all_tests[] = { | ||
| 97 | &test_append_move, | ||
| 98 | &test_new_alg, | ||
| 99 | /* | ||
| 100 | &test_append_alg, | ||
| 101 | &test_compose_alg, | ||
| 102 | &test_inverse_alg, | ||
| 103 | &test_on_inverse, | ||
| 104 | &test_unniss, | ||
| 105 | */ | ||
| 106 | NULL | ||
| 107 | }; | ||
| 108 | TestSuite alg_suite = { | ||
| 109 | .setup = NULL, | ||
| 110 | .tests = alg_all_tests, | ||
| 111 | .teardown = NULL, | ||
| 112 | }; | ||
| 113 | |||
| 114 | TestSuite *alg_suites[] = { | ||
| 115 | &alg_suite, | ||
| 116 | NULL | ||
| 117 | }; | ||
| 118 | |||
| 119 | bool | ||
| 120 | testmethod_append_move(void *a) | ||
| 121 | { | ||
| 122 | append_move_t *b = (append_move_t *)a; | ||
| 123 | int li, ln; | ||
| 124 | Alg *alg; | ||
| 125 | |||
| 126 | /* Small to test reallocation */ | ||
| 127 | alg = malloc(sizeof(Alg)); | ||
| 128 | alg->allocated = 5; | ||
| 129 | alg->move = malloc(alg->allocated * sizeof(Move)); | ||
| 130 | alg->inv = malloc(alg->allocated * sizeof(bool)); | ||
| 131 | alg->len = b->len; | ||
| 132 | memcpy(alg->move, b->move, alg->len * sizeof(Move)); | ||
| 133 | memcpy(alg->inv, b->inv, alg->len * sizeof(bool)); | ||
| 134 | alg->move_normal = malloc(alg->allocated * sizeof(Move)); | ||
| 135 | alg->move_inverse = malloc(alg->allocated * sizeof(Move)); | ||
| 136 | |||
| 137 | li = ln = 0; | ||
| 138 | for (int i = 0; i < alg->len; i++) { | ||
| 139 | if (alg->inv[i]) | ||
| 140 | alg->move_inverse[li++] = alg->move[i]; | ||
| 141 | else | ||
| 142 | alg->move_normal[ln++] = alg->move[i]; | ||
| 143 | } | ||
| 144 | alg->len_inverse = li; | ||
| 145 | alg->len_normal = ln; | ||
| 146 | |||
| 147 | append_move(alg, b->m, b->inverse); | ||
| 148 | |||
| 149 | if (alg->len != b->len + 1) { | ||
| 150 | printf("Alg has wrong len (%d instead of %d)\n", | ||
| 151 | alg->len, b->len + 1); | ||
| 152 | goto append_move_fail; | ||
| 153 | } | ||
| 154 | if (alg->move[alg->len-1] != b->m) { | ||
| 155 | printf("Wrong last move (%s instead of %s)\n", | ||
| 156 | move_string(alg->move[alg->len-1]), | ||
| 157 | move_string(b->m)); | ||
| 158 | goto append_move_fail; | ||
| 159 | } | ||
| 160 | if (alg->inv[alg->len-1] != b->inverse) { | ||
| 161 | printf("Wrong inverse flag for last move " | ||
| 162 | "(%s instead of %s)\n", | ||
| 163 | b->inverse ? "normal" : "inverse", | ||
| 164 | b->inverse ? "inverse" : "normal"); | ||
| 165 | goto append_move_fail; | ||
| 166 | } | ||
| 167 | if (b->inverse) { | ||
| 168 | if (alg->len_inverse != li + 1 || | ||
| 169 | alg->len_normal != ln) { | ||
| 170 | printf("%d moves on normal (should be %d)" | ||
| 171 | " and %d on inverse (should be %d)\n", | ||
| 172 | alg->len_normal, ln, | ||
| 173 | alg->len_inverse, li + 1); | ||
| 174 | goto append_move_fail; | ||
| 175 | } | ||
| 176 | if (alg->move_inverse[alg->len_inverse-1] != b->m) { | ||
| 177 | printf("Wrong move on inverse (%s instead of %s)\n", | ||
| 178 | move_string(alg->move_inverse[alg->len-1]), | ||
| 179 | move_string(b->m)); | ||
| 180 | goto append_move_fail; | ||
| 181 | } | ||
| 182 | } else { | ||
| 183 | if (alg->len_inverse != li || | ||
| 184 | alg->len_normal != ln + 1) { | ||
| 185 | printf("%d moves on normal (should be %d)" | ||
| 186 | " and %d on inverse (should be %d)\n", | ||
| 187 | alg->len_normal, ln, | ||
| 188 | alg->len_inverse, li + 1); | ||
| 189 | goto append_move_fail; | ||
| 190 | } | ||
| 191 | if (alg->move_normal[alg->len_normal-1] != b->m) { | ||
| 192 | printf("Wrong move on normal (%s instead of %s)\n", | ||
| 193 | move_string(alg->move_normal[alg->len-1]), | ||
| 194 | move_string(b->m)); | ||
| 195 | goto append_move_fail; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | free(alg); | ||
| 200 | return true; | ||
| 201 | |||
| 202 | append_move_fail: | ||
| 203 | free(alg); | ||
| 204 | return false; | ||
| 205 | } | ||
| 206 | |||
| 207 | bool | ||
| 208 | testmethod_new_alg(void *a) | ||
| 209 | { | ||
| 210 | new_alg_t *b = (new_alg_t *)a; | ||
| 211 | Alg *alg = new_alg(b->str); | ||
| 212 | |||
| 213 | if (alg->len != b->len) { | ||
| 214 | printf("Algs have different length (%d instead of %d)\n", | ||
| 215 | alg->len, b->len); | ||
| 216 | goto new_alg_fail; | ||
| 217 | } | ||
| 218 | |||
| 219 | for (int i = 0; i < alg->len; i++) { | ||
| 220 | if (alg->move[i] != b->move[i] || alg->inv[i] != b->inv[i]) { | ||
| 221 | printf("Algs differ on move %d\n", i); | ||
| 222 | printf("Expected: %s\nActual: ", b->str); | ||
| 223 | print_alg(alg, false); | ||
| 224 | goto new_alg_fail; | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | if (alg->len_normal != b->len_normal) { | ||
| 229 | printf("Algs have different number of moves on normal" | ||
| 230 | " (%d instead of %d)\n", | ||
| 231 | alg->len_normal, b->len_normal); | ||
| 232 | goto new_alg_fail; | ||
| 233 | } | ||
| 234 | for (int i = 0; i < alg->len_normal; i++) { | ||
| 235 | if (alg->move_normal[i] != b->move_normal[i]) { | ||
| 236 | printf("Algs have different move %d on normal" | ||
| 237 | " (%s instead of %s)\n", i, | ||
| 238 | move_string(alg->move_normal[i]), | ||
| 239 | move_string(b->move_normal[i])); | ||
| 240 | goto new_alg_fail; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | if (alg->len_inverse != b->len_inverse) { | ||
| 245 | printf("Algs have different number of moves on inverse" | ||
| 246 | " (%d instead of %d)\n", | ||
| 247 | alg->len_inverse, b->len_inverse); | ||
| 248 | goto new_alg_fail; | ||
| 249 | } | ||
| 250 | for (int i = 0; i < alg->len_inverse; i++) { | ||
| 251 | if (alg->move_inverse[i] != b->move_inverse[i]) { | ||
| 252 | printf("Algs have different move %d on inverse:\n" | ||
| 253 | " (%s instead of %s)\n", i, | ||
| 254 | move_string(alg->move_inverse[i]), | ||
| 255 | move_string(b->move_inverse[i])); | ||
| 256 | goto new_alg_fail; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | free(alg); | ||
| 261 | return true; | ||
| 262 | |||
| 263 | new_alg_fail: | ||
| 264 | free(alg); | ||
| 265 | return false; | ||
| 266 | } | ||
diff --git a/tests/alg_tests.h b/tests/alg_tests.h deleted file mode 100644 index a24b51f..0000000 --- a/tests/alg_tests.h +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | #ifndef ALG_TESTS_H | ||
| 2 | #define ALG_TESTS_H | ||
| 3 | |||
| 4 | #include "../src/alg.h" | ||
| 5 | #include "test_common.h" | ||
| 6 | |||
| 7 | extern Test test_append_move; | ||
| 8 | extern Test test_new_alg; | ||
| 9 | /* | ||
| 10 | extern Test remove_last_move; | ||
| 11 | extern Test test_compose_alg; | ||
| 12 | extern Test test_inverse_alg; | ||
| 13 | extern Test test_on_inverse; | ||
| 14 | extern Test test_unniss; | ||
| 15 | */ | ||
| 16 | |||
| 17 | extern TestSuite alg_suite; | ||
| 18 | |||
| 19 | extern TestSuite *alg_suites[]; | ||
| 20 | |||
| 21 | #endif | ||
diff --git a/tests/coord_tests.c b/tests/coord_tests.c deleted file mode 100644 index 8d6b6d3..0000000 --- a/tests/coord_tests.c +++ /dev/null | |||
| @@ -1,50 +0,0 @@ | |||
| 1 | #include "coord_tests.h" | ||
| 2 | |||
| 3 | bool testmethod_indexes_consistent(void *); | ||
| 4 | |||
| 5 | Test test_indexes_consistent = { | ||
| 6 | .name = "Consitency of index and anti-index", | ||
| 7 | .t = testmethod_indexes_consistent, | ||
| 8 | .cases = (void **)all_coordinates, | ||
| 9 | }; | ||
| 10 | Test *coord_pre_init[] = { | ||
| 11 | &test_indexes_consistent, | ||
| 12 | NULL | ||
| 13 | }; | ||
| 14 | TestSuite coord_pre_init_suite = { | ||
| 15 | .setup = NULL, | ||
| 16 | .tests = coord_pre_init, | ||
| 17 | .teardown = NULL, | ||
| 18 | }; | ||
| 19 | |||
| 20 | TestSuite *coord_suites[] = { | ||
| 21 | &coord_pre_init_suite, | ||
| 22 | NULL | ||
| 23 | }; | ||
| 24 | |||
| 25 | bool | ||
| 26 | testmethod_indexes_consistent(void *a) | ||
| 27 | { | ||
| 28 | uint64_t ui, uj; | ||
| 29 | Cube c; | ||
| 30 | Coordinate *coord; | ||
| 31 | |||
| 32 | coord = (Coordinate *)a; | ||
| 33 | |||
| 34 | if (coord->type != COMP_COORD) | ||
| 35 | return true; /* Not applicable */ | ||
| 36 | |||
| 37 | gen_coord(coord); | ||
| 38 | for (ui = 0; ui < coord->max; ui++) { | ||
| 39 | indexers_makecube(coord->i, ui, &c); | ||
| 40 | uj = indexers_getind(coord->i, &c); | ||
| 41 | if (ui != uj) { | ||
| 42 | fprintf(stderr, "Error with coordinate %s: " | ||
| 43 | "%" PRIu64 " != %" PRIu64 "\n", | ||
| 44 | coord->name, uj, ui); | ||
| 45 | return false; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | return true; | ||
| 50 | } | ||
diff --git a/tests/coord_tests.h b/tests/coord_tests.h deleted file mode 100644 index 0cfd145..0000000 --- a/tests/coord_tests.h +++ /dev/null | |||
| @@ -1,13 +0,0 @@ | |||
| 1 | #ifndef COORD_TESTS_H | ||
| 2 | #define COORD_TESTS_H | ||
| 3 | |||
| 4 | #include "../src/coord.h" | ||
| 5 | #include "test_common.h" | ||
| 6 | |||
| 7 | extern Test test_indexes_consistent; | ||
| 8 | |||
| 9 | extern TestSuite coord_pre_init_suite; | ||
| 10 | |||
| 11 | extern TestSuite *coord_suites[]; | ||
| 12 | |||
| 13 | #endif | ||
diff --git a/tests/fst_tests.c b/tests/fst_tests.c deleted file mode 100644 index 1a9bedd..0000000 --- a/tests/fst_tests.c +++ /dev/null | |||
| @@ -1,184 +0,0 @@ | |||
| 1 | #include "fst_tests.h" | ||
| 2 | |||
| 3 | static bool testmethod_fst_is_consistent(void *); | ||
| 4 | static bool testmethod_cube_to_fst_to_cube(void *); | ||
| 5 | static bool testmethod_fst_move(void *); | ||
| 6 | static bool testmethod_fst_inverse(void *); | ||
| 7 | static bool check_equal_and_log(Cube *, Cube *); | ||
| 8 | static void void_to_cube(void *, Cube *); | ||
| 9 | |||
| 10 | char *algs[] = { | ||
| 11 | "", | ||
| 12 | "U", "U2", "U'", "D", "D2", "D'", "R", "R2", "R'", | ||
| 13 | "L", "L2", "L'", "F", "F2", "F'", "B", "B2", "B'", | ||
| 14 | "U2 R2 U2 R2 U2", | ||
| 15 | "U2 F2 R2 B2 U2 D2 F2 L2 B2", | ||
| 16 | "RUR'URU2R'", | ||
| 17 | "L2 D R U2 B2 L", | ||
| 18 | "R'U'F", | ||
| 19 | "F2 U' R2 D' B2 D2 R2 D2 R2 U' F L' U' R B F2 R B' D2", | ||
| 20 | "D L2 F2 R2 D R2 U L2 U' B2 D L' F2 U2 B' L D' U' R' B2 F2", | ||
| 21 | "F' L2 F' D' R F2 L U L' D2 R2 F2 D2 R2 B' L2 B2 U2 F D2 B", | ||
| 22 | NULL, | ||
| 23 | }; | ||
| 24 | |||
| 25 | Test test_fst_is_consistent = { | ||
| 26 | .name = "Consitency of FST (converted from cube)", | ||
| 27 | .t = testmethod_fst_is_consistent, | ||
| 28 | .cases = (void **)algs, | ||
| 29 | }; | ||
| 30 | Test test_cube_to_fst_to_cube = { | ||
| 31 | .name = "Cube to FST to cube", | ||
| 32 | .t = testmethod_cube_to_fst_to_cube, | ||
| 33 | .cases = (void **)algs, | ||
| 34 | }; | ||
| 35 | Test test_fst_move = { | ||
| 36 | .name = "FST move", | ||
| 37 | .t = testmethod_fst_move, | ||
| 38 | .cases = (void **)algs, | ||
| 39 | }; | ||
| 40 | Test test_fst_inverse = { | ||
| 41 | .name = "FST inverse", | ||
| 42 | .t = testmethod_fst_inverse, | ||
| 43 | .cases = (void **)algs, | ||
| 44 | }; | ||
| 45 | |||
| 46 | Test *fst_pre_init[] = { | ||
| 47 | &test_fst_is_consistent, | ||
| 48 | &test_cube_to_fst_to_cube, | ||
| 49 | NULL | ||
| 50 | }; | ||
| 51 | TestSuite fst_pre_init_suite = { | ||
| 52 | .setup = NULL, | ||
| 53 | .tests = fst_pre_init, | ||
| 54 | .teardown = NULL, | ||
| 55 | }; | ||
| 56 | |||
| 57 | Test *fst_post_init[] = { | ||
| 58 | &test_fst_move, | ||
| 59 | &test_fst_inverse, | ||
| 60 | NULL | ||
| 61 | }; | ||
| 62 | TestSuite fst_post_init_suite = { | ||
| 63 | .setup = init_fst, | ||
| 64 | .tests = fst_post_init, | ||
| 65 | .teardown = NULL, | ||
| 66 | }; | ||
| 67 | |||
| 68 | TestSuite *fst_suites[] = { | ||
| 69 | &fst_pre_init_suite, | ||
| 70 | &fst_post_init_suite, | ||
| 71 | NULL | ||
| 72 | }; | ||
| 73 | |||
| 74 | static bool | ||
| 75 | check_equal_and_log(Cube *c, Cube *d) | ||
| 76 | { | ||
| 77 | bool ret = equal(c, d); | ||
| 78 | |||
| 79 | if (!ret) { | ||
| 80 | printf("\n"); | ||
| 81 | printf("These cubes should be equal, but are not:\n\n"); | ||
| 82 | print_cube(c); | ||
| 83 | printf("\n"); | ||
| 84 | print_cube(d); | ||
| 85 | printf("\n"); | ||
| 86 | } | ||
| 87 | |||
| 88 | return ret; | ||
| 89 | } | ||
| 90 | |||
| 91 | static void | ||
| 92 | void_to_cube(void *a, Cube *c) | ||
| 93 | { | ||
| 94 | char *algstr; | ||
| 95 | Alg *alg; | ||
| 96 | |||
| 97 | algstr = (char *)a; | ||
| 98 | alg = new_alg(algstr); | ||
| 99 | make_solved(c); | ||
| 100 | apply_alg(alg, c); | ||
| 101 | free_alg(alg); | ||
| 102 | } | ||
| 103 | |||
| 104 | bool | ||
| 105 | testmethod_fst_is_consistent(void *a) | ||
| 106 | { | ||
| 107 | FstCube fst_uf, fst_fr, fst_rd; | ||
| 108 | Cube c, c_fr, c_rd; | ||
| 109 | bool consistent_fr, consistent_rd, result; | ||
| 110 | |||
| 111 | void_to_cube(a, &c); | ||
| 112 | copy_cube(&c, &c_fr); | ||
| 113 | apply_trans(fr, &c_fr); | ||
| 114 | |||
| 115 | copy_cube(&c, &c_rd); | ||
| 116 | apply_trans(rd, &c_rd); | ||
| 117 | |||
| 118 | fst_uf = cube_to_fst(&c); | ||
| 119 | fst_fr = cube_to_fst(&c_fr); | ||
| 120 | fst_rd = cube_to_fst(&c_rd); | ||
| 121 | |||
| 122 | consistent_fr = fst_uf.fr_eofb == fst_fr.uf_eofb && | ||
| 123 | fst_uf.fr_eposepe == fst_fr.uf_eposepe && | ||
| 124 | fst_uf.fr_coud == fst_fr.uf_coud; | ||
| 125 | |||
| 126 | consistent_rd = fst_uf.rd_eofb == fst_rd.uf_eofb && | ||
| 127 | fst_uf.rd_eposepe == fst_rd.uf_eposepe && | ||
| 128 | fst_uf.rd_coud == fst_rd.uf_coud; | ||
| 129 | |||
| 130 | result = consistent_fr && consistent_rd; | ||
| 131 | |||
| 132 | if (!result) | ||
| 133 | printf("\nFailed with alg %s\n", (char *)a); | ||
| 134 | |||
| 135 | return result; | ||
| 136 | } | ||
| 137 | |||
| 138 | bool | ||
| 139 | testmethod_cube_to_fst_to_cube(void *a) | ||
| 140 | { | ||
| 141 | Cube c, d; | ||
| 142 | FstCube fst; | ||
| 143 | |||
| 144 | void_to_cube(a, &c); | ||
| 145 | fst = cube_to_fst(&c); | ||
| 146 | fst_to_cube(fst, &d); | ||
| 147 | |||
| 148 | return check_equal_and_log(&c, &d);; | ||
| 149 | } | ||
| 150 | |||
| 151 | bool | ||
| 152 | testmethod_fst_move(void *a) | ||
| 153 | { | ||
| 154 | int i; | ||
| 155 | Alg *alg; | ||
| 156 | Cube c, d; | ||
| 157 | FstCube fst; | ||
| 158 | |||
| 159 | void_to_cube(a, &c); | ||
| 160 | alg = new_alg((char *)a); | ||
| 161 | make_solved(&d); | ||
| 162 | fst = cube_to_fst(&d); | ||
| 163 | |||
| 164 | for (i = 0; i < alg->len; i++) | ||
| 165 | fst = fst_move(alg->move[i], fst); | ||
| 166 | |||
| 167 | fst_to_cube(fst, &d); | ||
| 168 | |||
| 169 | free_alg(alg); | ||
| 170 | |||
| 171 | return check_equal_and_log(&c, &d); | ||
| 172 | } | ||
| 173 | |||
| 174 | bool | ||
| 175 | testmethod_fst_inverse(void *a) | ||
| 176 | { | ||
| 177 | Cube c, d; | ||
| 178 | |||
| 179 | void_to_cube(a, &c); | ||
| 180 | fst_to_cube(fst_inverse(cube_to_fst(&c)), &d); | ||
| 181 | invert_cube(&c); | ||
| 182 | |||
| 183 | return check_equal_and_log(&c, &d); | ||
| 184 | } | ||
diff --git a/tests/fst_tests.h b/tests/fst_tests.h deleted file mode 100644 index 68bbf04..0000000 --- a/tests/fst_tests.h +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | #ifndef FST_TESTS_H | ||
| 2 | #define FST_TESTS_H | ||
| 3 | |||
| 4 | #include "../src/fst.h" | ||
| 5 | #include "test_common.h" | ||
| 6 | |||
| 7 | extern char *algs[]; | ||
| 8 | |||
| 9 | extern Test test_fst_is_consistent; | ||
| 10 | extern Test test_cube_to_fst_to_cube; | ||
| 11 | extern Test test_fst_move; | ||
| 12 | extern Test test_fst_inverse; | ||
| 13 | |||
| 14 | extern TestSuite fst_pre_init_suite; | ||
| 15 | extern TestSuite fst_post_init_suite; | ||
| 16 | |||
| 17 | extern TestSuite *fst_suites[]; | ||
| 18 | |||
| 19 | #endif | ||
diff --git a/tests/test.c b/tests/test.c deleted file mode 100644 index 8961de1..0000000 --- a/tests/test.c +++ /dev/null | |||
| @@ -1,85 +0,0 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | |||
| 3 | #include "alg_tests.h" | ||
| 4 | #include "coord_tests.h" | ||
| 5 | #include "fst_tests.h" | ||
| 6 | |||
| 7 | static bool run_test(Test *); | ||
| 8 | static bool run_suite(TestSuite *); | ||
| 9 | |||
| 10 | static bool | ||
| 11 | run_test(Test *test) | ||
| 12 | { | ||
| 13 | int i; | ||
| 14 | |||
| 15 | printf("Running test %s...", test->name); | ||
| 16 | for (i = 0; test->cases[i] != NULL; i++) { | ||
| 17 | if (!test->t(test->cases[i])) { | ||
| 18 | printf("FAILED!\n"); | ||
| 19 | return false; | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | printf("OK\n"); | ||
| 24 | return true; | ||
| 25 | } | ||
| 26 | |||
| 27 | static bool | ||
| 28 | run_suite(TestSuite *suite) | ||
| 29 | { | ||
| 30 | int i; | ||
| 31 | |||
| 32 | if (suite->setup != NULL) | ||
| 33 | suite->setup(); | ||
| 34 | for (i = 0; suite->tests[i] != NULL; i++) | ||
| 35 | if(!run_test(suite->tests[i])) | ||
| 36 | return false; | ||
| 37 | if (suite->teardown != NULL) | ||
| 38 | suite->teardown(); | ||
| 39 | |||
| 40 | return true; | ||
| 41 | } | ||
| 42 | |||
| 43 | static bool | ||
| 44 | module_in_args(char *module, int argc, char *argv[]) | ||
| 45 | { | ||
| 46 | for (int i = 0; i < argc; i++) | ||
| 47 | if (!strcmp(module, argv[i])) | ||
| 48 | return true; | ||
| 49 | return false; | ||
| 50 | } | ||
| 51 | |||
| 52 | int main(int argc, char *argv[]) { | ||
| 53 | /* TODO: init should be in testsuites */ | ||
| 54 | init_env(); | ||
| 55 | init_trans(); | ||
| 56 | /**************************************/ | ||
| 57 | |||
| 58 | TestModule alg = { .name = "alg", .suites = alg_suites }; | ||
| 59 | TestModule fst = { .name = "fst", .suites = fst_suites }; | ||
| 60 | TestModule coord = { .name = "coord", .suites = coord_suites }; | ||
| 61 | TestModule *modules[999] = { | ||
| 62 | &alg, | ||
| 63 | &fst, | ||
| 64 | &coord, | ||
| 65 | NULL | ||
| 66 | }; | ||
| 67 | |||
| 68 | |||
| 69 | bool all = argc == 1 || module_in_args("all", argc, argv); | ||
| 70 | int count = 0; | ||
| 71 | for (int i = 0; modules[i] != NULL; i++) { | ||
| 72 | if (all || module_in_args(modules[i]->name, argc, argv)) { | ||
| 73 | for (int j = 0; modules[i]->suites[j] != NULL; j++) { | ||
| 74 | if (!run_suite(modules[i]->suites[j])) { | ||
| 75 | return 1; | ||
| 76 | } else { | ||
| 77 | count++; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | printf("All tests passed (%d test suites).\n", count); | ||
| 84 | return 0; | ||
| 85 | } | ||
diff --git a/tests/test_common.h b/tests/test_common.h deleted file mode 100644 index 03511ef..0000000 --- a/tests/test_common.h +++ /dev/null | |||
| @@ -1,41 +0,0 @@ | |||
| 1 | #ifndef TEST_COMMON_H | ||
| 2 | #define TEST_COMMON_H | ||
| 3 | |||
| 4 | /* | ||
| 5 | * Common utilities for testing. | ||
| 6 | * A VoidMethod can be used as a setup or teardown method for testing, see | ||
| 7 | * the TestSuite struct. A TestMethod takes a void pointer (usually cast | ||
| 8 | * to some data to be used for testing, but can also be ignored) and returns | ||
| 9 | * a bool: true for pass, false for fail. | ||
| 10 | * A Test consists of a name (string), a TestMethod and an array of void | ||
| 11 | * pointers that describe the test cases. Each element of this array is | ||
| 12 | * passed to the test method sequentially, and the test session stops on | ||
| 13 | * the first failure. | ||
| 14 | * A test suite is just a list of tests with a setup and a teardown method. | ||
| 15 | * The setup method is run once and for all before the first test, and the | ||
| 16 | * teardown is run at the end of the testsuite. | ||
| 17 | * Finally, a TestModule roughly corresponds to a test file. This type is | ||
| 18 | * only used in test.c to collect multiple test modules. | ||
| 19 | */ | ||
| 20 | |||
| 21 | typedef void (*VoidMethod)(void); | ||
| 22 | typedef bool (*TestMethod)(void *); | ||
| 23 | |||
| 24 | typedef struct { | ||
| 25 | char * name; | ||
| 26 | TestMethod t; | ||
| 27 | void ** cases; | ||
| 28 | } Test; | ||
| 29 | |||
| 30 | typedef struct { | ||
| 31 | VoidMethod setup; | ||
| 32 | Test ** tests; | ||
| 33 | VoidMethod teardown; | ||
| 34 | } TestSuite; | ||
| 35 | |||
| 36 | typedef struct { | ||
| 37 | char * name; | ||
| 38 | TestSuite ** suites; | ||
| 39 | } TestModule; | ||
| 40 | |||
| 41 | #endif | ||
diff --git a/www/download/index.html b/www/download/index.html deleted file mode 100644 index 8e4cccd..0000000 --- a/www/download/index.html +++ /dev/null | |||
| @@ -1,217 +0,0 @@ | |||
| 1 | <!doctype html> | ||
| 2 | <html lang="en"> | ||
| 3 | <head> | ||
| 4 | <title> Download | Nissy </title> | ||
| 5 | <meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css"> | ||
| 6 | <link rel="icon" href="/favicon.png"> | ||
| 7 | <meta charset="utf-8"> | ||
| 8 | </head> | ||
| 9 | |||
| 10 | <body> | ||
| 11 | |||
| 12 | <nav class="top"> | ||
| 13 | <table class="menu"> | ||
| 14 | <tr> | ||
| 15 | <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td> | ||
| 16 | <td class="links"> | ||
| 17 | <a href="/download/">Download</a> | | ||
| 18 | <a href="/examples/">Examples</a> | ||
| 19 | </td> | ||
| 20 | </tr> | ||
| 21 | </table> | ||
| 22 | </nav> | ||
| 23 | |||
| 24 | <hr class="line"> | ||
| 25 | |||
| 26 | |||
| 27 | <h1>Get Nissy</h1> | ||
| 28 | |||
| 29 | <table class="dltable"> | ||
| 30 | <tr> | ||
| 31 | <td></td> | ||
| 32 | <td><strong>Source code</strong></td> | ||
| 33 | <td><strong>Windows executable</strong></td> | ||
| 34 | </tr> | ||
| 35 | <tr> | ||
| 36 | <td><strong>Latest version</strong></td> | ||
| 37 | <td><a href="/nissy-2.0.3.tar.gz">nissy-2.0.3.tar.gz (67Kb)</a></td> | ||
| 38 | <td><a href="/nissy-2.0.3.exe">nissy-2.0.3.exe (780Kb)</a></td> | ||
| 39 | </tr> | ||
| 40 | </table> | ||
| 41 | |||
| 42 | <p> | ||
| 43 | In this page you can find download links (see above), | ||
| 44 | <a href="#Installation">installation instructions</a> and | ||
| 45 | <a href="#Upgrade">upgrade instructions</a> | ||
| 46 | for nissy. If instead you wish to clone the | ||
| 47 | <a href="https://git.tronto.net/nissy/">git repository</a>, | ||
| 48 | you can use git: | ||
| 49 | </p> | ||
| 50 | |||
| 51 | <pre> | ||
| 52 | <code>git clone https://git.tronto.net/nissy</code> | ||
| 53 | </pre> | ||
| 54 | |||
| 55 | <p> | ||
| 56 | For a summary of changes and a list of older versions see below. Some versions | ||
| 57 | (for example 1.0) are not available directly, but can be obtained from | ||
| 58 | the git repository. | ||
| 59 | </p> | ||
| 60 | |||
| 61 | <h2 id="Installation">Installation</h2> | ||
| 62 | |||
| 63 | <h3>System requirements</h3> | ||
| 64 | |||
| 65 | <p> | ||
| 66 | A full installation of nissy requires about 3.1Gb of space, | ||
| 67 | of which 2.3Gb are occupied by the huge pruning table for fast optimal solving, | ||
| 68 | and running it requires the same amount of RAM. | ||
| 69 | One can choose to never use this function and not to install the relative | ||
| 70 | pruning table. There is an alternative (slower) | ||
| 71 | optimal solving function that uses about 500Mb of RAM. | ||
| 72 | |||
| 73 | When generating the pruning tables automatically (see the section Tables below), | ||
| 74 | at least 5.3Gb or RAM are required. | ||
| 75 | </p> | ||
| 76 | |||
| 77 | <h3>Windows</h3> | ||
| 78 | |||
| 79 | <p> | ||
| 80 | Try downloading and executing in a terminal the file <code>nissy.exe</code>, | ||
| 81 | then follow the instructions in the <strong>Tables</strong> section below for | ||
| 82 | installing the pruning tables. | ||
| 83 | If <code>nissy.exe</code> does not work, you can try following the UNIX instructions | ||
| 84 | in WSL (Windows Subsystem for Linux) or in a similar environment. | ||
| 85 | </p> | ||
| 86 | |||
| 87 | <h3>UNIX (Linux, MacOS, *BSD...)</h3> | ||
| 88 | <p> | ||
| 89 | Download the source archive (.tar.gz). Extract it | ||
| 90 | with your favorite archive program, for example with | ||
| 91 | </p> | ||
| 92 | <pre><code>tar -xvzf nissy-VERSION.tar.gz</code></pre> | ||
| 93 | <p> | ||
| 94 | Open a terminal in the directory just extracted. | ||
| 95 | If you wish, edit the <code>Makefile</code> to match your local configuration | ||
| 96 | (this is usually not necessary, but you may want to change the | ||
| 97 | <code>PREFIX</code> variable to change the installation path) and run | ||
| 98 | <pre><code>make</code></pre> | ||
| 99 | <p> | ||
| 100 | followed by | ||
| 101 | </p> | ||
| 102 | <pre><code>make install</code></pre> | ||
| 103 | <p> | ||
| 104 | Then follow the instructions below to install the pruning tables. | ||
| 105 | </p> | ||
| 106 | |||
| 107 | <h3>Tables</h3> | ||
| 108 | |||
| 109 | <p> | ||
| 110 | Once you have installed nissy, run | ||
| 111 | </p> | ||
| 112 | |||
| 113 | <pre><code>nissy gen</code></pre> | ||
| 114 | |||
| 115 | <p> | ||
| 116 | to generate all the tables that Nissy will ever need. | ||
| 117 | Running this command requires around 5.3Gb of RAM, and it can take some time | ||
| 118 | (about 40 minutes on my fairly old but decent laptop, with 8 CPU threads). | ||
| 119 | </p> | ||
| 120 | |||
| 121 | <p> | ||
| 122 | Some unnecessary technical detail: by default this command is going to use | ||
| 123 | at most 64 threads. If you want you can choose to use more threads (if your CPU | ||
| 124 | is very powerful) or fewer threads (if you for example want to run this command | ||
| 125 | in the background while you do other stuff) with the <code>-t</code> option, for | ||
| 126 | example <code>nissy gen -t 1</code>. | ||
| 127 | </p> | ||
| 128 | |||
| 129 | <p> | ||
| 130 | Alternatively, you can | ||
| 131 | <a href="/nissy-tables-2.0.2.zip">download all the tables (1.7Gb)</a> and | ||
| 132 | copy them into the correct folder (see manual page, <code>ENVIRONMENT</code> | ||
| 133 | section). On UNIX operating systems this folder is either | ||
| 134 | <code>.nissy/tables</code> in the user's home directory or | ||
| 135 | <code>$XDG_DATA_HOME/nissy/tables</code> if the XDG variable is configured. | ||
| 136 | On Windows it is the same directory as the <code>nissy.exe</code> executable | ||
| 137 | file. | ||
| 138 | </p> | ||
| 139 | |||
| 140 | <h2 id="Upgrade">Upgrading</h2> | ||
| 141 | <p> | ||
| 142 | If you already have nissy installed and you want to upgrade to a more | ||
| 143 | recent version, you can simply repeat the installation process: | ||
| 144 | </p> | ||
| 145 | <ul> | ||
| 146 | <li> | ||
| 147 | On Windows: simply replace nissy.exe with the new file with the same name. | ||
| 148 | </li> | ||
| 149 | <li> | ||
| 150 | On UNIX systems: download the new version of the source code, extract it in | ||
| 151 | a new folder and run <code>make</code> and <code>make install</code> again. | ||
| 152 | </li> | ||
| 153 | </ul> | ||
| 154 | <p> | ||
| 155 | Between each version new table files might have been added, or old ones | ||
| 156 | may be not used anymore. Nissy will deal with this automatically. | ||
| 157 | </p> | ||
| 158 | |||
| 159 | <h2>Version history</h2> | ||
| 160 | |||
| 161 | <h3>Nissy v2</h3> | ||
| 162 | |||
| 163 | <table class=dltable> | ||
| 164 | <tr> | ||
| 165 | <td><strong>Version</strong></td> | ||
| 166 | <td><strong>Date</strong></td> | ||
| 167 | <td><strong>Comment</strong></td> | ||
| 168 | </tr> | ||
| 169 | <tr> | ||
| 170 | <td><a href="/nissy-2.0.3.tar.gz">2.0.3</a></td> | ||
| 171 | <td>2022-09-10</td> | ||
| 172 | <td>Fixed bug in scramble dr</td> | ||
| 173 | </tr> | ||
| 174 | <tr> | ||
| 175 | <td><a href="/nissy-2.0.2.tar.gz">2.0.2</a></td> | ||
| 176 | <td>2022-06-01</td> | ||
| 177 | <td>Improved table generation speed</td> | ||
| 178 | </tr> | ||
| 179 | <tr> | ||
| 180 | <td><a href="/nissy-2.0.1.tar.gz">2.0.1</a></td> | ||
| 181 | <td>2022-02-22</td> | ||
| 182 | <td>Bugfix release</td> | ||
| 183 | </tr> | ||
| 184 | <tr> | ||
| 185 | <td>2.0</td> | ||
| 186 | <td>2021-12-29</td> | ||
| 187 | <td>Rewritten from scratch; much faster optimal solver</td> | ||
| 188 | </tr> | ||
| 189 | </table> | ||
| 190 | |||
| 191 | <h3>Nissy v1</h3> | ||
| 192 | |||
| 193 | <p> | ||
| 194 | Nissy v1 was released in 2020. It was slow, full of bugs and the code | ||
| 195 | was quite terrible. But in practice it got its job done most of the time. | ||
| 196 | </p> | ||
| 197 | |||
| 198 | |||
| 199 | <hr class="line"> | ||
| 200 | |||
| 201 | <nav class="bottom"> | ||
| 202 | <table class="footer"> | ||
| 203 | <tr> | ||
| 204 | <td class="contact"> | ||
| 205 | <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a> | ||
| 206 | </td> | ||
| 207 | <td class="hosted"> | ||
| 208 | <a href="mailto:sebastiano@tronto.net"> | ||
| 209 | sebastiano@tronto.net | ||
| 210 | </a> | ||
| 211 | </td> | ||
| 212 | </tr> | ||
| 213 | </table> | ||
| 214 | </nav> | ||
| 215 | |||
| 216 | </body> | ||
| 217 | </html> | ||
diff --git a/www/examples/index.html b/www/examples/index.html deleted file mode 100644 index 517c251..0000000 --- a/www/examples/index.html +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | <!doctype html> | ||
| 2 | <html lang="en"> | ||
| 3 | <head> | ||
| 4 | <title> Examples | Nissy </title> | ||
| 5 | <meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css"> | ||
| 6 | <link rel="icon" href="/favicon.png"> | ||
| 7 | <meta charset="utf-8"> | ||
| 8 | </head> | ||
| 9 | |||
| 10 | <body> | ||
| 11 | |||
| 12 | <nav class="top"> | ||
| 13 | <table class="menu"> | ||
| 14 | <tr> | ||
| 15 | <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td> | ||
| 16 | <td class="links"> | ||
| 17 | <a href="/download/">Download</a> | | ||
| 18 | <a href="/examples/">Examples</a> | ||
| 19 | </td> | ||
| 20 | </tr> | ||
| 21 | </table> | ||
| 22 | </nav> | ||
| 23 | |||
| 24 | <hr class="line"> | ||
| 25 | |||
| 26 | |||
| 27 | <h1>Examples</h1> | ||
| 28 | |||
| 29 | (Coming soon...) | ||
| 30 | |||
| 31 | <hr class="line"> | ||
| 32 | |||
| 33 | <nav class="bottom"> | ||
| 34 | <table class="footer"> | ||
| 35 | <tr> | ||
| 36 | <td class="contact"> | ||
| 37 | <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a> | ||
| 38 | </td> | ||
| 39 | <td class="hosted"> | ||
| 40 | <a href="mailto:sebastiano@tronto.net"> | ||
| 41 | sebastiano@tronto.net | ||
| 42 | </a> | ||
| 43 | </td> | ||
| 44 | </tr> | ||
| 45 | </table> | ||
| 46 | </nav> | ||
| 47 | |||
| 48 | </body> | ||
| 49 | </html> | ||
diff --git a/www/favicon.png b/www/favicon.png deleted file mode 100644 index 3ec80a1..0000000 --- a/www/favicon.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/www/index.html b/www/index.html deleted file mode 100644 index 500952c..0000000 --- a/www/index.html +++ /dev/null | |||
| @@ -1,93 +0,0 @@ | |||
| 1 | <!doctype html> | ||
| 2 | <html lang="en"> | ||
| 3 | <head> | ||
| 4 | <title> Nissy | Nissy </title> | ||
| 5 | <meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css"> | ||
| 6 | <link rel="icon" href="/favicon.png"> | ||
| 7 | <meta charset="utf-8"> | ||
| 8 | </head> | ||
| 9 | |||
| 10 | <body> | ||
| 11 | |||
| 12 | <nav class="top"> | ||
| 13 | <table class="menu"> | ||
| 14 | <tr> | ||
| 15 | <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td> | ||
| 16 | <td class="links"> | ||
| 17 | <a href="/download/">Download</a> | | ||
| 18 | <a href="/examples/">Examples</a> | ||
| 19 | </td> | ||
| 20 | </tr> | ||
| 21 | </table> | ||
| 22 | </nav> | ||
| 23 | |||
| 24 | <hr class="line"> | ||
| 25 | |||
| 26 | |||
| 27 | <h1>Nissy</h1> | ||
| 28 | |||
| 29 | <p class=subtitle>A Rubik's cube solver and FMC assistant</p> | ||
| 30 | |||
| 31 | <img src="/screenshot.png" alt="A screenshot of nissy running in a terminal emulator"> | ||
| 32 | |||
| 33 | <p> | ||
| 34 | Nissy is a command-line Rubik's cube solver. It can find optimal solutions | ||
| 35 | for random positions using techniques from Herbert Kociemba's | ||
| 36 | <a href="http://kociemba.org/cube.htm">Cube Explorer</a> and | ||
| 37 | Tomas Rokicki's | ||
| 38 | <a href="https://github.com/rokici/cube20src/blob/master/nxopt.md">nxopt</a>. | ||
| 39 | With 4 cores at 2.5GHz and using about 3Gb of RAM, Nissy can find an optimal | ||
| 40 | solution in about a minute on average. | ||
| 41 | </p> | ||
| 42 | |||
| 43 | <p> | ||
| 44 | Nissy aims at being a complete tool | ||
| 45 | for FMC (Fewest Moves Challenge) practice. It can solve different steps | ||
| 46 | of Thistlethwaite's algorithm (also know as DR/HTR) and cans use NISS | ||
| 47 | (Normal-Inverse Scramble Switch). | ||
| 48 | </p> | ||
| 49 | |||
| 50 | <p> | ||
| 51 | You should use Nissy if: | ||
| 52 | </p> | ||
| 53 | <ul> | ||
| 54 | <li> | ||
| 55 | You want to analyze your DR solutions or check for multiple optimal | ||
| 56 | (or sub-optimal) solutions for EO/DR/HTR or similar steps. | ||
| 57 | </li> | ||
| 58 | <li> | ||
| 59 | You just want a Rubik's cube solver and you like command line interfaces. | ||
| 60 | </li> | ||
| 61 | <li> | ||
| 62 | You want an alternative to Cube Explorer. | ||
| 63 | </li> | ||
| 64 | </ul> | ||
| 65 | |||
| 66 | <p> | ||
| 67 | To get started, head to the <a href="/download/">download</a> page. | ||
| 68 | </p> | ||
| 69 | |||
| 70 | <p> | ||
| 71 | You can also see its source code by cloning the git repository | ||
| 72 | <a href="https://git.tronto.net/nissy/">git.tronto.net/nissy</a> | ||
| 73 | </p> | ||
| 74 | |||
| 75 | <hr class="line"> | ||
| 76 | |||
| 77 | <nav class="bottom"> | ||
| 78 | <table class="footer"> | ||
| 79 | <tr> | ||
| 80 | <td class="contact"> | ||
| 81 | <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a> | ||
| 82 | </td> | ||
| 83 | <td class="hosted"> | ||
| 84 | <a href="mailto:sebastiano@tronto.net"> | ||
| 85 | sebastiano@tronto.net | ||
| 86 | </a> | ||
| 87 | </td> | ||
| 88 | </tr> | ||
| 89 | </table> | ||
| 90 | </nav> | ||
| 91 | |||
| 92 | </body> | ||
| 93 | </html> | ||
diff --git a/www/screenshot.png b/www/screenshot.png deleted file mode 100644 index a73f2fd..0000000 --- a/www/screenshot.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/www/style-3.css b/www/style-3.css deleted file mode 100644 index ec70635..0000000 --- a/www/style-3.css +++ /dev/null | |||
| @@ -1,105 +0,0 @@ | |||
| 1 | .menu { | ||
| 2 | width: 100%; | ||
| 3 | } | ||
| 4 | |||
| 5 | .links { | ||
| 6 | text-align: right; | ||
| 7 | font-weight: bold; | ||
| 8 | } | ||
| 9 | |||
| 10 | .logo img { | ||
| 11 | width: 50px; | ||
| 12 | height: 50px; | ||
| 13 | } | ||
| 14 | |||
| 15 | .footer { | ||
| 16 | font-style: italic; | ||
| 17 | width: 100%; | ||
| 18 | } | ||
| 19 | |||
| 20 | .hosted { | ||
| 21 | text-align: right; | ||
| 22 | } | ||
| 23 | |||
| 24 | body { | ||
| 25 | margin: auto 8px 20px 8px; | ||
| 26 | } | ||
| 27 | |||
| 28 | img { | ||
| 29 | display: block; | ||
| 30 | margin-left: auto; | ||
| 31 | margin-right: auto; | ||
| 32 | max-width: 100%; | ||
| 33 | } | ||
| 34 | |||
| 35 | code { | ||
| 36 | background-color: #eeeeee; | ||
| 37 | padding: 2px; | ||
| 38 | } | ||
| 39 | |||
| 40 | pre code { | ||
| 41 | padding: 0px; | ||
| 42 | } | ||
| 43 | |||
| 44 | pre { | ||
| 45 | background-color: #eeeeee; | ||
| 46 | border: 2px solid; | ||
| 47 | padding: 6px; | ||
| 48 | } | ||
| 49 | |||
| 50 | #blob { | ||
| 51 | background: #ffffff; | ||
| 52 | border: none; | ||
| 53 | } | ||
| 54 | |||
| 55 | a { | ||
| 56 | color: #0f2899; | ||
| 57 | text-decoration: none; | ||
| 58 | } | ||
| 59 | |||
| 60 | .links a { | ||
| 61 | font-weight: bold; | ||
| 62 | color: black; | ||
| 63 | } | ||
| 64 | |||
| 65 | .hosted a, | ||
| 66 | .contact a { | ||
| 67 | font-weight: bold; | ||
| 68 | } | ||
| 69 | |||
| 70 | a:hover { | ||
| 71 | text-decoration: underline; | ||
| 72 | } | ||
| 73 | |||
| 74 | html { | ||
| 75 | margin: 1em auto; | ||
| 76 | max-width: 42em; | ||
| 77 | } | ||
| 78 | |||
| 79 | h1 { | ||
| 80 | text-align: center; | ||
| 81 | } | ||
| 82 | |||
| 83 | td h1 { | ||
| 84 | text-align: left; | ||
| 85 | font-size: 1.5em; | ||
| 86 | } | ||
| 87 | |||
| 88 | table { | ||
| 89 | width: 100%; | ||
| 90 | } | ||
| 91 | |||
| 92 | .url td { | ||
| 93 | font-family: monospace; | ||
| 94 | } | ||
| 95 | |||
| 96 | .dltable th, .dltable td { | ||
| 97 | border: 1px solid black; | ||
| 98 | padding: 3px; | ||
| 99 | } | ||
| 100 | |||
| 101 | .subtitle { | ||
| 102 | text-align: center; | ||
| 103 | font-weight: bold; | ||
| 104 | font-size: 1.1em; | ||
| 105 | } | ||
