nissy-fmc

A Rubik's cube FMC assistant
git clone https://git.tronto.net/nissy-fmc
Download | Log | Files | Refs | README | LICENSE

commit 8fb4670e3d76387b8afb3c8ac81ed09741bf6a15
parent 7c7cf8a8689dcbbbca5e3604a464d2526db31a2b
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Fri, 14 Apr 2023 18:54:58 +0200

Removed some files from old version

Diffstat:
DINSTALL | 81-------------------------------------------------------------------------------
MMakefile | 47++---------------------------------------------
MREADME.md | 98+------------------------------------------------------------------------------
DTODO.md | 142-------------------------------------------------------------------------------
Dmain.c | 0
Dold/maybe-useful-coord.c | 181-------------------------------------------------------------------------------
Dold/maybe-useful-steps.c | 1111-------------------------------------------------------------------------------
Dwww/download/index.html | 212-------------------------------------------------------------------------------
Dwww/examples/index.html | 49-------------------------------------------------
Dwww/favicon.png | 0
Dwww/index.html | 93-------------------------------------------------------------------------------
Dwww/screenshot.png | 0
Dwww/style-2.css | 105-------------------------------------------------------------------------------
13 files changed, 3 insertions(+), 2116 deletions(-)

diff --git a/INSTALL b/INSTALL @@ -1,81 +0,0 @@ -# Website - -Nissy is available at https://nissy.tronto.net - -# Requirements - -A full installation of nissy requires about 3Gb of space, of which -2.3Gb are occupied by the huge pruning table for fast optimal solving, -and running it requires the same amount of RAM. One can choose to never -use this function and not to install the relative pruning table. There -is an alternative (slower) optimal solving function that uses about -500Mb of RAM. When generating the pruning tables automatically (see -the section Tables below), at least 5.3Gb or RAM are required. - -# Installation - -## On Windows - -Try downloading and executing in a terminal the file nissy.exe, then -follow the instructions in the Tables section below for installing the -pruning tables. If nissy.exe does not work, you can try following the -UNIX instructions in WSL (Windows Subsystem for Linux) or in a similar -environment. - -## On a UNIX system: - -Download the source archive (.tar.gz). Extract it with your favorite -archive program, for example with - - tar -xvzf nissy-VERSION.tar.gz - -Open a terminal in the directory just extracted. If you wish, edit the -Makefile to match your local configuration (this is usually not necessary, -but you may want to change the PREFIX variable to change the installation -path) and run - - make - -followed by - - make install - -Then follow the instructions below to install the pruning tables. - -## Tables - -Once you have installed nissy, run - - nissy gen - -to generate all the tables that Nissy will ever need. Running this -command requires around 5.3Gb of RAM, and it can take some time (about -40 minutes on my fairly old but decent laptop, with 8 CPU threads). - -Some unnecessary technical detail: by default this command is going to -use at most 64 threads. If you want you can choose to use more threads -(if your CPU is very powerful) or fewer threads (if you for example -want to run this command in the background while you do other stuff) -with the -t option, for example nissy gen -t 1. - -Alternatively, you can download all the tables (1.7Gb) and copy them -into the correct folder (see manual page, ENVIRONMENT section). On UNIX -operating systems this folder is either .nissy/tables in the user's -home directory or $XDG_DATA_HOME/nissy/tables if the XDG variable -is configured. On Windows it is the same directory as the nissy.exe -executable file. - -You can downloads all the tables from the following link: - - https://nissy.tronto.net/nissy-tables-2.0.2.zip - -# Upgrading - -If you already have nissy installed and you want to upgrade to a more -recent version, you can simply repeat the installation process: -* On Windows: simply replace nissy.exe with the new file with the same name. -* On UNIX systems: download the new version of the source code, extract it - in a new folder and run make and make install again. - -Between each version new table files might have been added, or old ones -may be not used anymore. Nissy will deal with this automatically. diff --git a/Makefile b/Makefile @@ -1,9 +1,8 @@ # See LICENSE file for copyright and license details. -VERSION = post-2.0.2 +VERSION = pre-3.0 PREFIX = /usr/local -MANPREFIX = ${PREFIX}/share/man CPPFLAGS = -DVERSION=\"${VERSION}\" CFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \ @@ -14,55 +13,13 @@ DBGFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \ CC = cc - all: nissy nissy: clean ${CC} ${CFLAGS} -o nissy src/*.c -nissy.exe: - x86_64-w64-mingw32-gcc ${CFLAGS} -static -o nissy.exe src/*.c - debug: ${CC} ${DBGFLAGS} -o nissy src/*.c -clean: - rm -rf nissy nissy*.exe nissy*.tar.gz doc/nissy.html doc/nissy.pdf - -dist: clean nissy.exe - mkdir -p nissy-${VERSION} - cp -R LICENSE Makefile INSTALL doc src nissy-${VERSION} - groff -Tpdf -mandoc doc/nissy.1 > doc/nissy.pdf - groff -Thtml -mandoc doc/nissy.1 > doc/nissy.html - cp doc/nissy.pdf nissy-${VERSION}/doc/nissy.pdf - cp doc/nissy.html nissy-${VERSION}/doc/nissy.html - tar -cf nissy-${VERSION}.tar nissy-${VERSION} - gzip nissy-${VERSION}.tar - rm -rf nissy-${VERSION} - mv nissy.exe nissy-${VERSION}.exe - -upload: dist - rsync -v --rsync-path=openrsync nissy-${VERSION}.exe \ - tronto.net:/var/www/htdocs/nissy.tronto.net/ - rsync -v --rsync-path=openrsync nissy-${VERSION}.tar.gz \ - tronto.net:/var/www/htdocs/nissy.tronto.net/ - -website: - rsync -rv --rsync-path=openrsync \ - www/ tronto.net:/var/www/htdocs/nissy.tronto.net - -install: nissy - mkdir -p ${DESTDIR}${PREFIX}/bin - cp -f nissy ${DESTDIR}${PREFIX}/bin/nissy - chmod 755 ${DESTDIR}${PREFIX}/bin/nissy - mkdir -p ${DESTDIR}${MANPREFIX}/man1 - sed "s/VERSION/${VERSION}/g" < doc/nissy.1 \ - > ${DESTDIR}${MANPREFIX}/man1/nissy.1 - chmod 644 ${DESTDIR}${MANPREFIX}/man1/nissy.1 - -uninstall: - rm -rf ${DESTDIR}${PREFIX}/bin/nissy ${DESTDIR}${MANPREFIX}/man1/nissy.1 - for s in ${SCRIPTS}; do rm -rf ${DESTDIR}${PREFIX}/bin/$$s; done - -.PHONY: all debug clean dist install uninstall upload +.PHONY: all debug diff --git a/README.md b/README.md @@ -1,97 +1 @@ -# Nissy - -A Rubik's cube solver and FMC assistant. -For optimal HTM solving Nissy uses techniques from Herbert Kociemba's -[Cube Explorer](http://kociemba.org/cube.htm) and Tomas Rokicki's -[nxopt](https://github.com/rokicki/cube20src/blob/master/nxopt.md). -With 4 cores at 2.5GHz and using about 3Gb of RAM, Nissy can find an -optimal solution in about a minute on average. - -Nissy can also solve many different substeps of Thistlethwaite's algorithm -(DR/HTR), and can use NISS (Normal-Inverse Scramble Switch). -It can be useful to analyze your DR solves (and more, once I implement more features). - -You can get Nissy from [nissy.tronto.net](https://nissy.tronto.net). -The download links and installation instructions can be found on the -[download page](https://nissy.tronto.net/download). - -## Structure of the code - -You can find all the source code in the `src` folder. -I strived to keep it legible but I did not write many comments (barely any at all). -I'll try to explain here the main parts of the program. - -### Cube, moves and transformations - -There are many ways to represent a cube. In Nissy I use two: - -* An array representation `CubeArray`: 3 arrays representing the permutation -of corners, edges and centers and 2 arrays for the orientation of corners and edges. -* An 11-integers representation `Cube`: 3 integers for edge orientation (with respect -to the three axes), 3 for corner orientation, and so on. Edge permutation is a bit -complicated because encoding 12 factorial as a single number is too large for some -practical reasons, so I use 3 integers for that. - -Moves are easy to apply on the array form, but they are slow. So `moves.c` -contains the instructions to create all the transition tables necessary -to get the next position for the cube with just 11 lookup operations -(one for each of the 11 integers in the second representation). -These transition tables are saved in the `mtables` file in the -`tables` folder in binary format. - -The 11 integers are obviously redundant, but keeping all of them makes it easy -to apply transformations. A transformation is a rotation of the whole cube, possibly -combined with a mirror operation. Applying a transformation to a cube (say obtained -by applying a scramble to the solved cube) means applying the transformation to a -solved cube, then the scramble and then the inverse of the transformation -(i.e. conjugating by it). - -### Coordinates and pruning tables - -A *coordinate* consists of a function that takes a cube (in the 11-integer -representation) and return an (unsigned, 64-bit) integer. They are used -to "linearize" a cube and build pruning tables, which speed up significantly the -solving process. To be able to access the pruning table quickly, the function -needs to be very fast (e.g. it should not convert between the two representations -of the cube if not necessary). - -Some coordinates make use of symmetries to reduce the size of the resulting -pruning table. Unfortunately this complicates the code a lot, but it is a huge -advantage: it reduces by a factor of about 16 the pruning table size. - -Pruning tables are related to a specific step, a moveset and a coordinate. They -contain one value from 0 to 15 (4 bits) for each possible value for the coordinate, -which is less or equal than the minimum number of moves required to solve the -given step with the given moveset for a cube which has the given coordinate. For example, -say the coordinate `neo` gives the number of non-oriented edges (say with respect to -F/B). Then the possible values for the coordinate are 0,2,4,...,12. An associated -pruning table to solving EO with HTM moveset and this coordinate would have values 0 -(for `neo=0`), 3 (for `neo=2`), 1 (for `neo=4`)... - -The values for most pruning tables are memorized modulo 16, so they only occupy -4 bits per entry, and values larger than 15 are saved as 15. This is good enough -for most applications. -Some large tables are memorized in compact form using only 2 bits, similarly -to what [nxopt](https://github.com/rokicki/cube20src/blob/master/nxopt.md) does: -a base value `b` is picked and a value of `n` is saved as `MIN(3,MAX(0,n-b))`. -When a value of `v=1,2,3` is read it is simply returned as `v+b`, while if -`0` is a successive lookup to a fallback table is performed. The base value `b` -is picked to maximize the sum frequency of the values `1,2,3`. - -In order to generate the pruning tables, it is necessary to be able to move -a transform a coordinate; it is possible to do so without passing through a -complete cube representations, in a way similar to what Cube Explorer does. -This used to be different before version 2.1 (June 2022). - -More documentation on this and on the different types of coordinates (base -vs composed) is work in progress. - -### Solving - -Solving is implemented as a generic function that takes both a step and -a (scrambled) cube as input, as well as some extra parameters that say e.g. -how many solution one wants. A step consists, among other things, of -an estimator function that, given a cube, gives a lower bound for the number -of moves needed to complete the step. Many of these estimators simply -look up the corresponding values in the appropriate pruning table. - +# Work in progress diff --git a/TODO.md b/TODO.md @@ -1,142 +0,0 @@ -# TODO list - -This is a list of things that I would like to add or change at some point. -It's more of a personal reminder than anything else. - -## For version 2.1 -### Slow: it is slower than the old nissy 2.0.2 :( -* nxopt's trick (switching to reduce branching) actually saves about 50%! -* Another factor is estimating *while* moving (i.e. do not move all - coordinates if the first one already gives a high value!) -* simplify solve, remove everything that is used only by optimal solvers -* Good compromise: each stepalt offers one of two alternatives: either solve - by simply using pruning tables and moving coordinates, or using a custom - estimator and moving a cube (or fast_cube) and computing coordinates - in the estimator -* is there really no way to use inverse branching trick with current system? -* new file optimal.c with the old solve logic; try first with the simple - cube implementation and the new indexers, if it is still slow change - to fast_cube (intermediate nissy v2.0.2 implementation) -### Changes to Step and Solve -* remove cube from dfsarg? (i still need to save the scramble somewhere, - but I really only use it in dfs_niss) -* coord.c: all old coordinates (WIP...) -* steps.c: checkers (use coordinates), all stepalt and steps (WIP...) -* commands gen and freemem -* commands.c: twophase, ...? -* Coordinate should have a moveset field? No, at worst there are some garbage - values in mtable, but no risk for errors -### Rotate, not transform, before solving -* solve should re-orient first if needed and not just give up if centers are off -### Documentation -* Document how coordinates and pruning tables work now -* Write an examples.md file -* More screenshots! -### Tables management -* Check files in tables directory automatically remove old / extraneous files -* Add checksum to check that tables are generated / downloaded correctly -### Conditional compiling -* Option to avoid large tables at compile time -* option to avoid multithreading (write a simpler solve for t=1, and also - check if found enough solutions before checking pruning values) -### Technical -* generic option parser -* testing? Maybe just hardcode some examples generated with old nissy -### Commands -* Easy: add option -I (inverse) and -L (linear, like inverse + normal) - to do only linear NISS - -## Commands - -### Commands that are available in nissy 1.0, but not in this version (yet): -* drcorners (solve corners after dr) -* search and improve non-optimal subsequences -* save and edit algs as "variables" - (or just use a "logging system" to keep info about previously run commands, -including e.g. solutions that were not shown because -c) - -### More steps for `solve` -* QTM optimal solving -* 5-side solve (for robots) -* Block-building steps (cross, roux blocks, ...) -* Other common steps (LSE, ...) -* Larger table for drudfin (include epe)? About 1Gb uncompressed, - 500Mb compressed (fallback to noE), 250 compressed + parity trick - (is it doable?) - -### Improvements to currently implemented commands -* solve multidfs: do multithread by step, not by alternative (this way - if there are multiple alternatives it can make use of more threads) -* solve should try up to a small bound without loading the large pruning table - (maybe this is not necessary if loading the table is fast enough) -* silent batch mode without >>> - -### New features -* EO analysis (and also DR and HTR analysis): group similar EOs together - and such (suggested by Jay) -* configurability: add an `alias` command, run config file at startup -* command notation to list available moves -* make multi-step solve much more general and create command -* input directly cube status instead of moves - (graphical: maybe there is a cubing.js function; command line: ???) - -## Distribution -* webapp (cgi) - -## Technical stuff - -### Testing -* write some proper tests, move test_coord to the testing module(s) - -### Memory management -* free pruning table after solve is done? if I do this I need to deafault to a - small table for < 8 moves solutions or smth -* improve multi-threading when solving multiple scrambles -* nissy -M maxmem option for running with at most maxmem memory; if exceeded - when loading a pruning table, return failure (or make every solve command - use tiny tables instead?); if maxmem is very 600Mb or - less do not use invtables (the performance loss is minimal anyway). If the - limit is really tiny, do not use mtables or ttables (but this would be - very slow and probably nobody will ever use it) -* Check if memory is enough for loading pruning tables; if not, abort -* For optimal solver: choose largest that fits in memory between nxopt and light - -### Structural changes -* client/server architecture: run a server process in the background so that - multiple client processess can send it queries and get results; this would - open up the door for a web-based version or graphical clients - -### Cleanup -* sort again functions alphabetically in their files -* change some function and variable names to make everything consistent -* more stuff to load at start (or when suitable command is called) rather - than when called directly, to avoid nasty problems with threading -* parse command args: one function per arg type, then each command has - a list of options that it accepts (as a string) - -### Style -* do not declare all variables at the beginning of a function -* remove var names from prototypes -* various stuff from style(9) - -### Random -Collect random info like this somewhere: - -Table pt_nxopt31_HTM -Base value: 9 -0 1 -1 6 -2 29 -3 164 -4 1433 -5 16772 -6 205033 -7 2513871 -8 30329976 -9 342440769 -10 2815191126 -11 6147967200 -12 524918774 -13 3546 -14 0 -15 0 diff --git a/main.c b/main.c diff --git a/old/maybe-useful-coord.c b/old/maybe-useful-coord.c @@ -1,181 +0,0 @@ -int -array_ep_to_epos(int *ep, int *ss) -{ - int epos[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - int eps[4]; - int i, j, is; - - for (i = 0, is = 0; i < 12; i++) { - for (j = 0; j < 4; j++) { - if (ep[i] == ss[j]) { - eps[is++] = j; - epos[i] = 1; - } - } - } - - for (i = 0; i < 4; i++) - swap(&epos[ss[i]], &epos[i+8]); - - return 24 * subset_to_index(epos, 12, 4) + perm_to_index(eps, 4); -} - -void -epos_to_compatible_ep(int epos, int *ep, int *ss) -{ - int i, j, k, other[8]; - bool flag; - - for (i = 0; i < 12; i++) - ep[i] = -1; - - epos_to_partial_ep(epos, ep, ss); - - for (i = 0, j = 0; i < 12; i++) { - flag = false; - for (k = 0; k < 4; k++) - flag = flag || (i == ss[k]); - if (!flag) - other[j++] = i; - } - - for (i = 0, j = 0; i < 12; i++) - if (ep[i] == -1) - ep[i] = other[j++]; -} - -void -epos_to_partial_ep(int epos, int *ep, int *ss) -{ - int i, is, eposs[12], eps[4]; - - index_to_perm(epos % FACTORIAL4, 4, eps); - index_to_subset(epos / FACTORIAL4, 12, 4, eposs); - - for (i = 0; i < 4; i++) - swap(&eposs[ss[i]], &eposs[i+8]); - - for (i = 0, is = 0; i < 12; i++) - if (eposs[i]) - ep[i] = ss[eps[is++]]; -} - -void -fix_eorleoud(CubeArray *arr) -{ - int i; - - for (i = 0; i < 12; i++) { - if ((edge_slice(i) == 0 && edge_slice(arr->ep[i]) != 0) || - (edge_slice(i) != 0 && edge_slice(arr->ep[i]) == 0)) { - arr->eorl[i] = 1 - arr->eofb[i]; - } else { - arr->eorl[i] = arr->eofb[i]; - } - - if ((edge_slice(i) == 2 && edge_slice(arr->ep[i]) != 2) || - (edge_slice(i) != 2 && edge_slice(arr->ep[i]) == 2)) { - arr->eoud[i] = 1 - arr->eofb[i]; - } else { - arr->eoud[i] = arr->eofb[i]; - } - } -} - -void -fix_cofbcorl(CubeArray *arr) -{ - int i; - - for (i = 0; i < 8; i++) { - if (i % 2 == arr->cp[i] % 2) { - arr->cofb[i] = arr->coud[i]; - arr->corl[i] = arr->coud[i]; - } else { - if (arr->cp[i] % 2 == 0) { - arr->cofb[i] = (arr->coud[i]+1)%3; - arr->corl[i] = (arr->coud[i]+2)%3; - } else { - arr->cofb[i] = (arr->coud[i]+2)%3; - arr->corl[i] = (arr->coud[i]+1)%3; - } - } - } -} - -Cube -admissible_ep(Cube cube, PieceFilter f) -{ - CubeArray *arr = new_cubearray(cube, f); - Cube ret; - bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - int i, j; - - for (i = 0; i < 12; i++) - if (arr->ep[i] != -1) - used[arr->ep[i]] = true; - - for (i = 0, j = 0; i < 12; i++) { - for ( ; j < 11 && used[j]; j++); - if (arr->ep[i] == -1) - arr->ep[i] = j++; - } - - ret = arrays_to_cube(arr, pf_ep); - free_cubearray(arr, f); - - return ret; -} - -int -edge_slice(Edge e) { - if (e < 0 || e > 11) - return -1; - - if (e == FR || e == FL || e == BL || e == BR) - return 0; - if (e == UR || e == UL || e == DR || e == DL) - return 1; - - return 2; -} - -int -piece_orientation(Cube cube, int piece, char *orientation) -{ - int arr[12], n, b, x; - - if (!strcmp(orientation, "eofb")) { - x = cube.eofb; - n = 12; - b = 2; - } else if (!strcmp(orientation, "eorl")) { - x = cube.eorl; - n = 12; - b = 2; - } else if (!strcmp(orientation, "eoud")) { - x = cube.eoud; - n = 12; - b = 2; - } else if (!strcmp(orientation, "coud")) { - x = cube.coud; - n = 8; - b = 3; - } else if (!strcmp(orientation, "corl")) { - x = cube.corl; - n = 8; - b = 3; - } else if (!strcmp(orientation, "cofb")) { - x = cube.cofb; - n = 8; - b = 3; - } else { - return -1; - } - - int_to_sum_zero_array(x, b, n, arr); - if (piece < n) - return arr[piece]; - - return -1; -} diff --git a/old/maybe-useful-steps.c b/old/maybe-useful-steps.c @@ -1,1111 +0,0 @@ -#include "steps.h" - -#define UPDATECHECKSTOP(a, b, c) if ((a=(MAX((a),(b))))>(c)) return (a); - -static int estimate_stepalt(StepAlt *a, uint64_t *ind); - -/* Checkers and validators ***************************************************/ - -/* TODO: these should be with Cube *cube (and all need to change) */ -/* Maybe move them to cube.c */ -static bool check_centers(Cube cube); -static bool check_coud_HTM(Cube cube); -static bool check_coud_URF(Cube cube); -static bool check_corners_HTM(Cube cube); -static bool check_corners_URF(Cube cube); -static bool check_cornershtr(Cube cube); -static bool check_eofb(Cube cube); -static bool check_drud(Cube cube); -static bool check_htr(Cube cube); - -static bool always_valid(Alg *alg); -static bool validate_singlecw_ending(Alg *alg); - -/* Messages for when cube is not ready ***************************************/ - -static char check_centers_msg[100] = "cube must be oriented (centers solved)"; -static char check_eo_msg[100] = "EO must be solved on given axis"; -static char check_dr_msg[100] = "DR must be solved on given axis"; -static char check_htr_msg[100] = "HTR must be solved"; -static char check_drany_msg[100] = "DR must be solved on at least one axis"; - -/* Steps *********************************************************************/ - -/* Optimal solvers *******************/ - -Step -optimal_HTM = { - .shortname = "optimal", - .name = "Optimal solve (in HTM)", - - .final = true, - .is_done = is_solved, - .estimate = estimate_nxopt31_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = always_valid, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -Step -optimal_light_HTM = { - .shortname = "light", - .name = "Optimal solve (in HTM), small table (500Mb RAM total)", - - .final = true, - .is_done = is_solved, - .estimate = estimate_light_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = always_valid, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_drud_sym16_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -/* Optimal after EO ******************/ - -Step -eofin_eo = { - .shortname = "eofin", - .name = "Optimal solve after EO without breaking EO (detected)", - - .final = true, - .is_done = is_solved, - .estimate = estimate_nxopt31_HTM, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = always_valid, - .moveset = &moveset_eofb, - - .detect = detect_pretrans_eofb, - - .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -Step -eofbfin_eofb = { - .shortname = "eofbfin", - .name = "Optimal after EO on F/B without breaking EO", - - .final = true, - .is_done = is_solved, - .estimate = estimate_nxopt31_HTM, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = always_valid, - .moveset = &moveset_eofb, - - .pre_trans = uf, - - .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -Step -eorlfin_eorl = { - .shortname = "eorlfin", - .name = "Optimal after EO on R/L without breaking EO", - - .final = true, - .is_done = is_solved, - .estimate = estimate_nxopt31_HTM, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = always_valid, - .moveset = &moveset_eofb, - - .pre_trans = ur, - - .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -Step -eoudfin_eoud = { - .shortname = "eoudfin", - .name = "Optimal after EO on U/D without breaking EO", - - .final = true, - .is_done = is_solved, - .estimate = estimate_nxopt31_HTM, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = always_valid, - .moveset = &moveset_eofb, - - .pre_trans = fd, - - .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -/* EO steps **************************/ -Step -eoany_HTM = { - .shortname = "eo", - .name = "EO on any axis", - - .final = false, - .is_done = check_eofb, - .estimate = estimate_eofb_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .detect = detect_pretrans_void_3axis, - - .tables = {&pd_eofb_HTM}, - .ntables = 1, -}; - -Step -eofb_HTM = { - .shortname = "eofb", - .name = "EO on F/B", - - .final = false, - .is_done = check_eofb, - .estimate = estimate_eofb_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_eofb_HTM}, - .ntables = 1, -}; - -Step -eorl_HTM = { - .shortname = "eorl", - .name = "EO on R/L", - - .final = false, - .is_done = check_eofb, - .estimate = estimate_eofb_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = ur, - - .tables = {&pd_eofb_HTM}, - .ntables = 1, -}; - -Step -eoud_HTM = { - .shortname = "eoud", - .name = "EO on U/D", - - .final = false, - .is_done = check_eofb, - .estimate = estimate_eofb_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = fd, - - .tables = {&pd_eofb_HTM}, - .ntables = 1, -}; - -/* CO steps **************************/ -Step -coany_HTM = { - .shortname = "co", - .name = "CO on any axis", - - .final = false, - .is_done = check_coud_HTM, - .estimate = estimate_coud_HTM, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .detect = detect_pretrans_void_3axis, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -coud_HTM = { - .shortname = "coud", - .name = "CO on U/D", - - .final = false, - .is_done = check_coud_HTM, - .estimate = estimate_coud_HTM, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -corl_HTM = { - .shortname = "corl", - .name = "CO on R/L", - - .final = false, - .is_done = check_coud_HTM, - .estimate = estimate_coud_HTM, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = rf, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -cofb_HTM = { - .shortname = "cofb", - .name = "CO on F/B", - - .final = false, - .is_done = check_coud_HTM, - .estimate = estimate_coud_HTM, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = fd, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -coany_URF = { - .shortname = "co-URF", - .name = "CO any axis (URF moveset)", - - .final = false, - .is_done = check_coud_URF, - .estimate = estimate_coud_URF, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_URF, - - .detect = detect_pretrans_void_3axis, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -coud_URF = { - .shortname = "coud-URF", - .name = "CO on U/D (URF moveset)", - - .final = false, - .is_done = check_coud_URF, - .estimate = estimate_coud_URF, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_URF, - - .pre_trans = uf, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -corl_URF = { - .shortname = "corl-URF", - .name = "CO on R/L (URF moveset)", - - .final = false, - .is_done = check_coud_URF, - .estimate = estimate_coud_URF, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_URF, - - .pre_trans = rf, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -cofb_URF = { - .shortname = "cofb-URF", - .name = "CO on F/B (URF moveset)", - - .final = false, - .is_done = check_coud_URF, - .estimate = estimate_coud_URF, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_URF, - - .pre_trans = fd, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -/* Misc corner steps *****************/ -Step -cornershtr_HTM = { - .shortname = "chtr", - .name = "Solve corners to HTR state", - - .final = false, - .is_done = check_cornershtr, - .estimate = estimate_cornershtr_HTM, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_cornershtr_HTM}, - .ntables = 1, -}; - -Step -cornershtr_URF = { - .shortname = "chtr-URF", - .name = "Solve corners to HTR state (URF moveset)", - - .final = false, - .is_done = check_cornershtr, - .estimate = estimate_cornershtr_URF, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_URF, - - .pre_trans = uf, - - .tables = {&pd_cornershtr_HTM}, - .ntables = 1, -}; - -Step -corners_HTM = { - .shortname = "corners", - .name = "Solve corners", - - .final = true, - .is_done = check_corners_HTM, - .estimate = estimate_corners_HTM, - .ready = NULL, - .is_valid = always_valid, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_corners_HTM}, - .ntables = 1, -}; - -Step -corners_URF = { - .shortname = "corners-URF", - .name = "Solve corners (URF moveset)", - - .final = true, /* TODO: check if this works with reorient */ - .is_done = check_corners_URF, - .estimate = estimate_corners_URF, - .ready = NULL, - .is_valid = always_valid, - .moveset = &moveset_URF, - - .pre_trans = uf, - - .tables = {&pd_corners_HTM}, - .ntables = 1, -}; - -/* DR steps **************************/ -Step -drany_HTM = { - .shortname = "dr", - .name = "DR on any axis", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .detect = detect_pretrans_void_3axis, - - .tables = {&pd_drud_sym16_HTM}, - .ntables = 1, -}; - -Step -drud_HTM = { - .shortname = "drud", - .name = "DR on U/D", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_drud_sym16_HTM}, - .ntables = 1, -}; - -Step -drrl_HTM = { - .shortname = "drrl", - .name = "DR on R/L", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = rf, - - .tables = {&pd_drud_sym16_HTM}, - .ntables = 1, -}; - -Step -drfb_HTM = { - .shortname = "drfb", - .name = "DR on F/B", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = fd, - - .tables = {&pd_drud_sym16_HTM}, - .ntables = 1, -}; - -/* DR from EO */ -Step -dr_eo = { - .shortname = "dr-eo", - .name = "DR without breaking EO (automatically detected)", - - .final = false, - .is_done = check_drud, - .estimate = estimate_dr_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .detect = detect_pretrans_eofb, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -dr_eofb = { - .shortname = "dr-eofb", - .name = "DR on U/D or R/L without breaking EO on F/B", - - .final = false, - .is_done = check_drud, - .estimate = estimate_dr_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = uf, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -dr_eorl = { - .shortname = "dr-eorl", - .name = "DR on U/D or F/B without breaking EO on R/L", - - .final = false, - .is_done = check_drud, - .estimate = estimate_dr_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = ur, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -dr_eoud = { - .shortname = "dr-eoud", - .name = "DR on R/L or F/B without breaking EO on U/D", - - .final = false, - .is_done = check_drud, - .estimate = estimate_dr_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = fd, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drud_eofb = { - .shortname = "drud-eofb", - .name = "DR on U/D without breaking EO on F/B", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = uf, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drrl_eofb = { - .shortname = "drrl-eofb", - .name = "DR on R/L without breaking EO on F/B", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = rf, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drud_eorl = { - .shortname = "drud-eorl", - .name = "DR on U/D without breaking EO on R/L", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = ur, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drfb_eorl = { - .shortname = "drfb-eorl", - .name = "DR on F/B without breaking EO on R/L", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = fr, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drfb_eoud = { - .shortname = "drfb-eoud", - .name = "DR on F/B without breaking EO on U/D", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = fd, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drrl_eoud = { - .shortname = "drrl-eoud", - .name = "DR on R/L without breaking EO on U/D", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = rd, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -/* DR finish steps */ -Step -dranyfin_DR = { - .shortname = "drfin", - .name = "DR finish on any axis without breaking DR", - - .final = true, - .is_done = is_solved, - .estimate = estimate_drudfin_drud, - .ready = check_drud, - .ready_msg = check_drany_msg, - .is_valid = always_valid, - .moveset = &moveset_drud, - - .detect = detect_pretrans_drud, - - .tables = {&pd_drudfin_noE_sym16_drud}, - .ntables = 1, -}; - -Step -drudfin_drud = { - .shortname = "drudfin", - .name = "DR finish on U/D without breaking DR", - - .final = true, - .is_done = is_solved, - .estimate = estimate_drudfin_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = always_valid, - .moveset = &moveset_drud, - - .pre_trans = uf, - - .tables = {&pd_drudfin_noE_sym16_drud}, - .ntables = 1, -}; - -Step -drrlfin_drrl = { - .shortname = "drrlfin", - .name = "DR finish on R/L without breaking DR", - - .final = true, - .is_done = is_solved, - .estimate = estimate_drudfin_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = always_valid, - .moveset = &moveset_drud, - - .pre_trans = rf, - - .tables = {&pd_drudfin_noE_sym16_drud}, - .ntables = 1, -}; - -Step -drfbfin_drfb = { - .shortname = "drfbfin", - .name = "DR finish on F/B without breaking DR", - - .final = true, - .is_done = is_solved, - .estimate = estimate_drudfin_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = always_valid, - .moveset = &moveset_drud, - - .pre_trans = fd, - - .tables = {&pd_drudfin_noE_sym16_drud}, - .ntables = 1, -}; - -/* HTR from DR */ -Step -htr_any = { - .shortname = "htr", - .name = "HTR from DR", - - .final = false, - .is_done = check_htr, - .estimate = estimate_htr_drud, - .ready = check_drud, - .ready_msg = check_drany_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_drud, - - .detect = detect_pretrans_drud, - - .tables = {&pd_htr_drud}, - .ntables = 1, -}; - -Step -htr_drud = { - .shortname = "htr-drud", - .name = "HTR from DR on U/D", - - .final = false, - .is_done = check_htr, - .estimate = estimate_htr_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_drud, - - .pre_trans = uf, - - .tables = {&pd_htr_drud}, - .ntables = 1, -}; - -Step -htr_drrl = { - .shortname = "htr-drrl", - .name = "HTR from DR on R/L", - - .final = false, - .is_done = check_htr, - .estimate = estimate_htr_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_drud, - - .pre_trans = rf, - - .tables = {&pd_htr_drud}, - .ntables = 1, -}; - -Step -htr_drfb = { - .shortname = "htr-drfb", - .name = "HTR from DR on F/B", - - .final = false, - .is_done = check_htr, - .estimate = estimate_htr_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_drud, - - .pre_trans = fd, - - .tables = {&pd_htr_drud}, - .ntables = 1, -}; - -/* HTR finish */ -Step -htrfin_htr = { - .shortname = "htrfin", - .name = "HTR finish without breaking HTR", - - .final = true, - .is_done = is_solved, - .estimate = estimate_htrfin_htr, - .ready = check_htr, - .ready_msg = check_htr_msg, - .is_valid = always_valid, - .moveset = &moveset_htr, - - .pre_trans = uf, - - .tables = {&pd_htrfin_htr}, - .ntables = 1, -}; - -Step *steps[] = { - &optimal_HTM, /* first is default */ - &optimal_light_HTM, - - &eofin_eo, - &eofbfin_eofb, - &eorlfin_eorl, - &eoudfin_eoud, - - &eoany_HTM, - &eofb_HTM, - &eorl_HTM, - &eoud_HTM, - - &coany_HTM, - &coud_HTM, - &corl_HTM, - &cofb_HTM, - - &coany_URF, - &coud_URF, - &corl_URF, - &cofb_URF, - - &drany_HTM, - &drud_HTM, - &drrl_HTM, - &drfb_HTM, - - &dr_eo, - &dr_eofb, - &dr_eorl, - &dr_eoud, - &drud_eofb, - &drrl_eofb, - &drud_eorl, - &drfb_eorl, - &drfb_eoud, - &drrl_eoud, - - &dranyfin_DR, - &drudfin_drud, - &drrlfin_drrl, - &drfbfin_drfb, - - &htr_any, - &htr_drud, - &htr_drrl, - &htr_drfb, - - &htrfin_htr, - - &cornershtr_HTM, - &cornershtr_URF, - &corners_HTM, - &corners_URF, - - NULL -}; - -/* Checkers and validators ***************************************************/ - -static bool -check_centers(Cube cube) -{ - return cube.cpos == 0; -} - -static bool -check_coud_HTM(Cube cube) -{ - return cube.coud == 0; -} - -static bool -check_coud_URF(Cube cube) -{ - Cube c2, c3; - - c2 = apply_move(z, cube); - c3 = apply_move(x, cube); - - return cube.coud == 0 || c2.coud == 0 || c3.coud == 0; -} - -static bool -check_corners_URF(Cube cube) -{ - Cube c; - Trans i; - - for (i = 0; i < NROTATIONS; i++) { - c = apply_alg(rotation_alg(i), cube); - if (c.cp && c.coud) - return true; - } - - return false; -} - -static bool -check_corners_HTM(Cube cube) -{ - return cube.cp == 0 && cube.coud == 0; -} - -static bool -check_cornershtr(Cube cube) -{ - return coord_cornershtr.index(cube) == 0; -} - -static bool -check_eofb(Cube cube) -{ - return cube.eofb == 0; -} - -static bool -check_drud(Cube cube) -{ - return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; -} - -static bool -check_htr(Cube cube) -{ - return check_drud(cube) && coord_htr_drud.index(cube) == 0; -} - -static bool -always_valid(Alg *alg) -{ - return true; -} - -static bool -validate_singlecw_ending(Alg *alg) -{ - int i; - bool nor, inv; - Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; - - for (i = 0; i < alg->len; i++) { - if (alg->inv[i]) { - l2i = l1i; - l1i = alg->move[i]; - } else { - l2 = l1; - l1 = alg->move[i]; - } - } - - nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2)); - inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i)); - - return nor && inv; -} - -/* Public functions **********************************************************/ - -void -compute_ind(StepAlt *a, Cube *cube, uint64_t *ind) -{ - -} - -int -estimate_stepalt(StepAlt *a, uint64_t *ind) -{ - int i, ret, est[a->n_coord]; - - for (i = 0; i < a->n_coord; i++) { - est[i] = ptableval(a->pd[i], ind[i]); - if (est[i] == 0 && a->compact_pd[i]) - est[i] = ptableval(a->fallback_pd, ind[i] / a->fbmod); - } - - for (i = 0; i < a->n_dbtrick; i++) - if (est[a->dbtrick[i][0]] == est[a->dbtrick[i][1]] && - est[a->dbtrick[i][0]] == est[a->dbtrick[i][2]]) - est[a->dbtrick[i][0]] += 1; - - for (i = 0, ret = -1; i < a->n_coord; i++) - ret = max(ret, est[i]); - - return ret; -} - -void -prepare_step(Step *step, SolveOptions *opts) -{ - int i, j; - PDGenData pdg; - StepAlt *a; - - init_moveset(step->moveset); - pdg.moveset = step->moveset; - - for (i = 0; step->alt[i] != NULL; i++) { - a = step->alt[i]; - for (j = 0; j < a->n_coord; j++) { - gen_coord(a->coord[j]); - - pdg.coord = a->coord[j]; - pdg.compact = a->compact[j]; - pdg.pd = NULL; - - a->pd[j] = genptable(&pdg, opts->nthreads); - - if (a->compact_pd[j]) { - gen_coord(a->fallback_coord[j]); - - pdg.coord = a->fallback_coord[j]; - pdg.compact = false; - pdg.pd = NULL; - - a->fallback_pd[j] = - step->genptable(&pdg, opts->nthreads); - } - } - } -} diff --git a/www/download/index.html b/www/download/index.html @@ -1,212 +0,0 @@ -<!doctype html> -<html lang="en"> -<head> - <title> Download | Nissy </title> -<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css"> - <link rel="icon" href="/favicon.png"> - <meta charset="utf-8"> -</head> - -<body> - -<nav class="top"> - <table class="menu"> - <tr> - <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td> - <td class="links"> - <a href="/download/">Download</a> | - <a href="/examples/">Examples</a> - </td> - </tr> - </table> -</nav> - -<hr class="line"> - - -<h1>Get Nissy</h1> - -<table class="dltable"> -<tr> - <td></td> - <td><strong>Source code</strong></td> - <td><strong>Windows executable</strong></td> -</tr> -<tr> - <td><strong>Latest version</strong></td> - <td><a href="/nissy-2.0.2.tar.gz">nissy-2.0.2.tar.gz (67Kb)</a></td> - <td><a href="/nissy-2.0.2.exe">nissy-2.0.2.exe (780Kb)</a></td> -</tr> -</table> - -<p> -In this page you can find download links (see above), -<a href="#Installation">installation instructions</a> and -<a href="#Upgrade">upgrade instructions</a> -for nissy. If instead you wish to clone the -<a href="https://git.tronto.net/nissy/">git repository</a>, -you can use git: -</p> - -<pre> -<code>git clone https://git.tronto.net/nissy</code> -</pre> - -<p> -For a summary of changes and a list of older versions see below. Some versions -(for example 1.0) are not available directly, but can be obtained from -the git repository. -</p> - -<h2 id="Installation">Installation</h2> - -<h3>System requirements</h3> - -<p> -A full installation of nissy requires about 3.1Gb of space, -of which 2.3Gb are occupied by the huge pruning table for fast optimal solving, -and running it requires the same amount of RAM. -One can choose to never use this function and not to install the relative -pruning table. There is an alternative (slower) -optimal solving function that uses about 500Mb of RAM. - -When generating the pruning tables automatically (see the section Tables below), -at least 5.3Gb or RAM are required. -</p> - -<h3>Windows</h3> - -<p> -Try downloading and executing in a terminal the file <code>nissy.exe</code>, -then follow the instructions in the <strong>Tables</strong> section below for -installing the pruning tables. -If <code>nissy.exe</code> does not work, you can try following the UNIX instructions -in WSL (Windows Subsystem for Linux) or in a similar environment. -</p> - -<h3>UNIX (Linux, MacOS, *BSD...)</h3> -<p> -Download the source archive (.tar.gz). Extract it -with your favorite archive program, for example with -</p> -<pre><code>tar -xvzf nissy-VERSION.tar.gz</code></pre> -<p> -Open a terminal in the directory just extracted. -If you wish, edit the <code>Makefile</code> to match your local configuration -(this is usually not necessary, but you may want to change the -<code>PREFIX</code> variable to change the installation path) and run -<pre><code>make</code></pre> -<p> -followed by -</p> -<pre><code>make install</code></pre> -<p> -Then follow the instructions below to install the pruning tables. -</p> - -<h3>Tables</h3> - -<p> -Once you have installed nissy, run -</p> - -<pre><code>nissy gen</code></pre> - -<p> -to generate all the tables that Nissy will ever need. -Running this command requires around 5.3Gb of RAM, and it can take some time -(about 40 minutes on my fairly old but decent laptop, with 8 CPU threads). -</p> - -<p> -Some unnecessary technical detail: by default this command is going to use -at most 64 threads. If you want you can choose to use more threads (if your CPU -is very powerful) or fewer threads (if you for example want to run this command -in the background while you do other stuff) with the <code>-t</code> option, for -example <code>nissy gen -t 1</code>. -</p> - -<p> -Alternatively, you can -<a href="/nissy-tables-2.0.2.zip">download all the tables (1.7Gb)</a> and -copy them into the correct folder (see manual page, <code>ENVIRONMENT</code> -section). On UNIX operating systems this folder is either -<code>.nissy/tables</code> in the user's home directory or -<code>$XDG_DATA_HOME/nissy/tables</code> if the XDG variable is configured. -On Windows it is the same directory as the <code>nissy.exe</code> executable -file. -</p> - -<h2 id="Upgrade">Upgrading</h2> -<p> -If you already have nissy installed and you want to upgrade to a more -recent version, you can simply repeat the installation process: -</p> -<ul> -<li> -On Windows: simply replace nissy.exe with the new file with the same name. -</li> -<li> -On UNIX systems: download the new version of the source code, extract it in -a new folder and run <code>make</code> and <code>make install</code> again. -</li> -</ul> -<p> -Between each version new table files might have been added, or old ones -may be not used anymore. Nissy will deal with this automatically. -</p> - -<h2>Version history</h2> - -<h3>Nissy v2</h3> - -<table class=dltable> -<tr> - <td><strong>Version</strong></td> - <td><strong>Date</strong></td> - <td><strong>Comment</strong></td> -</tr> -<tr> - <td><a href="/nissy-2.0.2.tar.gz">2.0.2</a></td> - <td>2022-06-01</td> - <td>Improved table generation speed</td> -</tr> -<tr> - <td><a href="/nissy-2.0.1.tar.gz">2.0.1</a></td> - <td>2022-02-22</td> - <td>Bugfix release</td> -</tr> -<tr> - <td>2.0</td> - <td>2021-12-29</td> - <td>Rewritten from scratch; much faster optimal solver</td> -</tr> -</table> - -<h3>Nissy v1</h3> - -<p> -Nissy v1 was released in 2020. It was slow, full of bugs and the code -was quite terrible. But in practice it got its job done most of the time. -</p> - - -<hr class="line"> - -<nav class="bottom"> - <table class="footer"> - <tr> - <td class="contact"> - <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a> - </td> - <td class="hosted"> - <a href="mailto:sebastiano@tronto.net"> - sebastiano@tronto.net - </a> - </td> - </tr> - </table> -</nav> - -</body> -</html> diff --git a/www/examples/index.html b/www/examples/index.html @@ -1,49 +0,0 @@ -<!doctype html> -<html lang="en"> -<head> - <title> Examples | Nissy </title> -<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css"> - <link rel="icon" href="/favicon.png"> - <meta charset="utf-8"> -</head> - -<body> - -<nav class="top"> - <table class="menu"> - <tr> - <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td> - <td class="links"> - <a href="/download/">Download</a> | - <a href="/examples/">Examples</a> - </td> - </tr> - </table> -</nav> - -<hr class="line"> - - -<h1>Examples</h1> - -(Coming soon...) - -<hr class="line"> - -<nav class="bottom"> - <table class="footer"> - <tr> - <td class="contact"> - <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a> - </td> - <td class="hosted"> - <a href="mailto:sebastiano@tronto.net"> - sebastiano@tronto.net - </a> - </td> - </tr> - </table> -</nav> - -</body> -</html> diff --git a/www/favicon.png b/www/favicon.png Binary files differ. diff --git a/www/index.html b/www/index.html @@ -1,93 +0,0 @@ -<!doctype html> -<html lang="en"> -<head> - <title> Nissy | Nissy </title> -<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css"> - <link rel="icon" href="/favicon.png"> - <meta charset="utf-8"> -</head> - -<body> - -<nav class="top"> - <table class="menu"> - <tr> - <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td> - <td class="links"> - <a href="/download/">Download</a> | - <a href="/examples/">Examples</a> - </td> - </tr> - </table> -</nav> - -<hr class="line"> - - -<h1>Nissy</h1> - -<p class=subtitle>A Rubik's cube solver and FMC assistant</p> - -<img src="/screenshot.png" alt="A screenshot of nissy running in a terminal emulator"> - -<p> -Nissy is a command-line Rubik's cube solver. It can find optimal solutions -for random positions using techniques from Herbert Kociemba's -<a href="http://kociemba.org/cube.htm">Cube Explorer</a> and -Tomas Rokicki's -<a href="https://github.com/rokici/cube20src/blob/master/nxopt.md">nxopt</a>. -With 4 cores at 2.5GHz and using about 3Gb of RAM, Nissy can find an optimal -solution in about a minute on average. -</p> - -<p> -Nissy aims at being a complete tool -for FMC (Fewest Moves Challenge) practice. It can solve different steps -of Thistlethwaite's algorithm (also know as DR/HTR) and cans use NISS -(Normal-Inverse Scramble Switch). -</p> - -<p> -You should use Nissy if: -</p> -<ul> -<li> -You want to analyze your DR solutions or check for multiple optimal -(or sub-optimal) solutions for EO/DR/HTR or similar steps. -</li> -<li> -You just want a Rubik's cube solver and you like command line interfaces. -</li> -<li> -You want an alternative to Cube Explorer. -</li> -</ul> - -<p> -To get started, head to the <a href="/download/">download</a> page. -</p> - -<p> -You can also see its source code by cloning the git repository -<a href="https://git.tronto.net/nissy/">git.tronto.net/nissy</a> -</p> - -<hr class="line"> - -<nav class="bottom"> - <table class="footer"> - <tr> - <td class="contact"> - <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a> - </td> - <td class="hosted"> - <a href="mailto:sebastiano@tronto.net"> - sebastiano@tronto.net - </a> - </td> - </tr> - </table> -</nav> - -</body> -</html> diff --git a/www/screenshot.png b/www/screenshot.png Binary files differ. diff --git a/www/style-2.css b/www/style-2.css @@ -1,105 +0,0 @@ -.menu { - width: 100%; -} - -.links { - text-align: right; - font-weight: bold; -} - -.logo img { - width: 50px; - height: 50px; -} - -.footer { - font-style: italic; - width: 100%; -} - -.hosted { - text-align: right; -} - -body { - margin: auto 8px 20px 8px; -} - -img { - display: block; - margin-left: auto; - margin-right: auto; - max-width: 100%; -} - -code { - background-color: #eeeeee; - padding: 2px; -} - -pre code { - padding: 0px; -} - -pre { - background-color: #eeeeee; - border: 2px solid; - padding: 6px; -} - -#blob { - background: #ffffff; - border: none; -} - -a { - color: #0f2899; - text-decoration: none; -} - -.links a { - font-weight: bold; - color: black; -} - -.hosted a, -.contact a { - font-weight: bold; -} - -a:hover { - text-decoration: underline; -} - -html { - margin: 1em auto; - max-width: 42em; -} - -h1 { - text-align: center; -} - -td h1 { - text-align: left; - font-size: 1.5em; -} - -table { - width: 100%; -} - -.url td { - font-family: monospace; -} - -.dltable th, .dltable td { - border: 1px solid black; - padding: 3px; -} - -.subtitle { - text-align: center; - font-weight: bold; - font-size: 1.1em; -}