diff options
69 files changed, 38 insertions, 10456 deletions
diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 17008a0..0000000 --- a/.gitignore +++ /dev/null | |||
| @@ -1,5 +0,0 @@ | |||
| 1 | doc/*.html | ||
| 2 | doc/*.pdf | ||
| 3 | nissy | ||
| 4 | nissy-* | ||
| 5 | test | ||
diff --git a/INSTALL b/INSTALL deleted file mode 100644 index ffc461d..0000000 --- a/INSTALL +++ /dev/null | |||
| @@ -1,81 +0,0 @@ | |||
| 1 | # Website | ||
| 2 | |||
| 3 | Nissy is available at https://nissy.tronto.net | ||
| 4 | |||
| 5 | # Requirements | ||
| 6 | |||
| 7 | A full installation of nissy requires about 3Gb of space, of which | ||
| 8 | 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 | ||
| 10 | use this function and not to install the relative pruning table. There | ||
| 11 | is an alternative (slower) optimal solving function that uses about | ||
| 12 | 500Mb of RAM. When generating the pruning tables automatically (see | ||
| 13 | the section Tables below), at least 5.3Gb or RAM are required. | ||
| 14 | |||
| 15 | # Installation | ||
| 16 | |||
| 17 | ## On Windows | ||
| 18 | |||
| 19 | Try downloading and executing in a terminal the file nissy.exe, then | ||
| 20 | follow the instructions in the Tables section below for installing the | ||
| 21 | pruning tables. If nissy.exe does not work, you can try following the | ||
| 22 | UNIX instructions in WSL (Windows Subsystem for Linux) or in a similar | ||
| 23 | environment. | ||
| 24 | |||
| 25 | ## On a UNIX system: | ||
| 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 | |||
| 41 | make install | ||
| 42 | |||
| 43 | Then follow the instructions below to install the pruning tables. | ||
| 44 | |||
| 45 | ## Tables | ||
| 46 | |||
| 47 | Once you have installed nissy, run | ||
| 48 | |||
| 49 | nissy gen | ||
| 50 | |||
| 51 | to generate all the tables that Nissy will ever need. Running this | ||
| 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 | |||
| 55 | Some unnecessary technical detail: by default this command is going to | ||
| 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 | |||
| 61 | Alternatively, you can download all the tables (1.7Gb) and copy them | ||
| 62 | into the correct folder (see manual page, ENVIRONMENT section). On UNIX | ||
| 63 | operating systems this folder is either .nissy/tables in the user's | ||
| 64 | home directory or $XDG_DATA_HOME/nissy/tables if the XDG variable | ||
| 65 | is configured. On Windows it is the same directory as the nissy.exe | ||
| 66 | executable file. | ||
| 67 | |||
| 68 | You can downloads all the tables from the following link: | ||
| 69 | |||
| 70 | https://nissy.tronto.net/nissy-tables-2.0.2.zip | ||
| 71 | |||
| 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. | ||
diff --git a/LICENSE b/LICENSE deleted file mode 100644 index b61b417..0000000 --- a/LICENSE +++ /dev/null | |||
| @@ -1,636 +0,0 @@ | |||
| 1 | The following license applies to every C source code and header file | ||
| 2 | distributed with this LICENSE file. | ||
| 3 | |||
| 4 | Nissy - A Rubik's cube solver and FMC assistant | ||
| 5 | Copyright (C) 2020-2022 Sebastiano Tronto <sebastiano@tronto.net> | ||
| 6 | |||
| 7 | This program is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or | ||
| 10 | (at your option) any later version. | ||
| 11 | |||
| 12 | This program is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | |||
| 18 | GNU GENERAL PUBLIC LICENSE | ||
| 19 | Version 3, 29 June 2007 | ||
| 20 | |||
| 21 | Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> | ||
| 22 | Everyone is permitted to copy and distribute verbatim copies | ||
| 23 | of this license document, but changing it is not allowed. | ||
| 24 | |||
| 25 | Preamble | ||
| 26 | |||
| 27 | The GNU General Public License is a free, copyleft license for | ||
| 28 | software and other kinds of works. | ||
| 29 | |||
| 30 | The licenses for most software and other practical works are designed | ||
| 31 | to take away your freedom to share and change the works. By contrast, | ||
| 32 | the GNU General Public License is intended to guarantee your freedom to | ||
| 33 | share and change all versions of a program--to make sure it remains free | ||
| 34 | software for all its users. We, the Free Software Foundation, use the | ||
| 35 | GNU General Public License for most of our software; it applies also to | ||
| 36 | any other work released this way by its authors. You can apply it to | ||
| 37 | your programs, too. | ||
| 38 | |||
| 39 | When we speak of free software, we are referring to freedom, not | ||
| 40 | price. Our General Public Licenses are designed to make sure that you | ||
| 41 | have the freedom to distribute copies of free software (and charge for | ||
| 42 | them if you wish), that you receive source code or can get it if you | ||
| 43 | want it, that you can change the software or use pieces of it in new | ||
| 44 | free programs, and that you know you can do these things. | ||
| 45 | |||
| 46 | To protect your rights, we need to prevent others from denying you | ||
| 47 | these rights or asking you to surrender the rights. Therefore, you have | ||
| 48 | certain responsibilities if you distribute copies of the software, or if | ||
| 49 | you modify it: responsibilities to respect the freedom of others. | ||
| 50 | |||
| 51 | For example, if you distribute copies of such a program, whether | ||
| 52 | gratis or for a fee, you must pass on to the recipients the same | ||
| 53 | freedoms that you received. You must make sure that they, too, receive | ||
| 54 | or can get the source code. And you must show them these terms so they | ||
| 55 | know their rights. | ||
| 56 | |||
| 57 | Developers that use the GNU GPL protect your rights with two steps: | ||
| 58 | (1) assert copyright on the software, and (2) offer you this License | ||
| 59 | giving you legal permission to copy, distribute and/or modify it. | ||
| 60 | |||
| 61 | For the developers' and authors' protection, the GPL clearly explains | ||
| 62 | that there is no warranty for this free software. For both users' and | ||
| 63 | authors' sake, the GPL requires that modified versions be marked as | ||
| 64 | changed, so that their problems will not be attributed erroneously to | ||
| 65 | authors of previous versions. | ||
| 66 | |||
| 67 | Some devices are designed to deny users access to install or run | ||
| 68 | modified versions of the software inside them, although the manufacturer | ||
| 69 | can do so. This is fundamentally incompatible with the aim of | ||
| 70 | protecting users' freedom to change the software. The systematic | ||
| 71 | pattern of such abuse occurs in the area of products for individuals to | ||
| 72 | use, which is precisely where it is most unacceptable. Therefore, we | ||
| 73 | have designed this version of the GPL to prohibit the practice for those | ||
| 74 | products. If such problems arise substantially in other domains, we | ||
| 75 | stand ready to extend this provision to those domains in future versions | ||
| 76 | of the GPL, as needed to protect the freedom of users. | ||
| 77 | |||
| 78 | Finally, every program is threatened constantly by software patents. | ||
| 79 | States should not allow patents to restrict development and use of | ||
| 80 | software on general-purpose computers, but in those that do, we wish to | ||
| 81 | avoid the special danger that patents applied to a free program could | ||
| 82 | make it effectively proprietary. To prevent this, the GPL assures that | ||
| 83 | patents cannot be used to render the program non-free. | ||
| 84 | |||
| 85 | The precise terms and conditions for copying, distribution and | ||
| 86 | modification follow. | ||
| 87 | |||
| 88 | TERMS AND CONDITIONS | ||
| 89 | |||
| 90 | 0. Definitions. | ||
| 91 | |||
| 92 | "This License" refers to version 3 of the GNU General Public License. | ||
| 93 | |||
| 94 | "Copyright" also means copyright-like laws that apply to other kinds of | ||
| 95 | works, such as semiconductor masks. | ||
| 96 | |||
| 97 | "The Program" refers to any copyrightable work licensed under this | ||
| 98 | License. Each licensee is addressed as "you". "Licensees" and | ||
| 99 | "recipients" may be individuals or organizations. | ||
| 100 | |||
| 101 | To "modify" a work means to copy from or adapt all or part of the work | ||
| 102 | in a fashion requiring copyright permission, other than the making of an | ||
| 103 | exact copy. The resulting work is called a "modified version" of the | ||
| 104 | earlier work or a work "based on" the earlier work. | ||
| 105 | |||
| 106 | A "covered work" means either the unmodified Program or a work based | ||
| 107 | on the Program. | ||
| 108 | |||
| 109 | To "propagate" a work means to do anything with it that, without | ||
| 110 | permission, would make you directly or secondarily liable for | ||
| 111 | infringement under applicable copyright law, except executing it on a | ||
| 112 | computer or modifying a private copy. Propagation includes copying, | ||
| 113 | distribution (with or without modification), making available to the | ||
| 114 | public, and in some countries other activities as well. | ||
| 115 | |||
| 116 | To "convey" a work means any kind of propagation that enables other | ||
| 117 | parties to make or receive copies. Mere interaction with a user through | ||
| 118 | a computer network, with no transfer of a copy, is not conveying. | ||
| 119 | |||
| 120 | An interactive user interface displays "Appropriate Legal Notices" | ||
| 121 | to the extent that it includes a convenient and prominently visible | ||
| 122 | feature that (1) displays an appropriate copyright notice, and (2) | ||
| 123 | tells the user that there is no warranty for the work (except to the | ||
| 124 | extent that warranties are provided), that licensees may convey the | ||
| 125 | work under this License, and how to view a copy of this License. If | ||
| 126 | the interface presents a list of user commands or options, such as a | ||
| 127 | menu, a prominent item in the list meets this criterion. | ||
| 128 | |||
| 129 | 1. Source Code. | ||
| 130 | |||
| 131 | The "source code" for a work means the preferred form of the work | ||
| 132 | for making modifications to it. "Object code" means any non-source | ||
| 133 | form of a work. | ||
| 134 | |||
| 135 | A "Standard Interface" means an interface that either is an official | ||
| 136 | standard defined by a recognized standards body, or, in the case of | ||
| 137 | interfaces specified for a particular programming language, one that | ||
| 138 | is widely used among developers working in that language. | ||
| 139 | |||
| 140 | The "System Libraries" of an executable work include anything, other | ||
| 141 | than the work as a whole, that (a) is included in the normal form of | ||
| 142 | packaging a Major Component, but which is not part of that Major | ||
| 143 | Component, and (b) serves only to enable use of the work with that | ||
| 144 | Major Component, or to implement a Standard Interface for which an | ||
| 145 | implementation is available to the public in source code form. A | ||
| 146 | "Major Component", in this context, means a major essential component | ||
| 147 | (kernel, window system, and so on) of the specific operating system | ||
| 148 | (if any) on which the executable work runs, or a compiler used to | ||
| 149 | produce the work, or an object code interpreter used to run it. | ||
| 150 | |||
| 151 | The "Corresponding Source" for a work in object code form means all | ||
| 152 | the source code needed to generate, install, and (for an executable | ||
| 153 | work) run the object code and to modify the work, including scripts to | ||
| 154 | control those activities. However, it does not include the work's | ||
| 155 | System Libraries, or general-purpose tools or generally available free | ||
| 156 | programs which are used unmodified in performing those activities but | ||
| 157 | which are not part of the work. For example, Corresponding Source | ||
| 158 | includes interface definition files associated with source files for | ||
| 159 | the work, and the source code for shared libraries and dynamically | ||
| 160 | linked subprograms that the work is specifically designed to require, | ||
| 161 | such as by intimate data communication or control flow between those | ||
| 162 | subprograms and other parts of the work. | ||
| 163 | |||
| 164 | The Corresponding Source need not include anything that users | ||
| 165 | can regenerate automatically from other parts of the Corresponding | ||
| 166 | Source. | ||
| 167 | |||
| 168 | The Corresponding Source for a work in source code form is that | ||
| 169 | same work. | ||
| 170 | |||
| 171 | 2. Basic Permissions. | ||
| 172 | |||
| 173 | All rights granted under this License are granted for the term of | ||
| 174 | copyright on the Program, and are irrevocable provided the stated | ||
| 175 | conditions are met. This License explicitly affirms your unlimited | ||
| 176 | permission to run the unmodified Program. The output from running a | ||
| 177 | covered work is covered by this License only if the output, given its | ||
| 178 | content, constitutes a covered work. This License acknowledges your | ||
| 179 | rights of fair use or other equivalent, as provided by copyright law. | ||
| 180 | |||
| 181 | You may make, run and propagate covered works that you do not | ||
| 182 | convey, without conditions so long as your license otherwise remains | ||
| 183 | in force. You may convey covered works to others for the sole purpose | ||
| 184 | of having them make modifications exclusively for you, or provide you | ||
| 185 | with facilities for running those works, provided that you comply with | ||
| 186 | the terms of this License in conveying all material for which you do | ||
| 187 | not control copyright. Those thus making or running the covered works | ||
| 188 | for you must do so exclusively on your behalf, under your direction | ||
| 189 | and control, on terms that prohibit them from making any copies of | ||
| 190 | your copyrighted material outside their relationship with you. | ||
| 191 | |||
| 192 | Conveying under any other circumstances is permitted solely under | ||
| 193 | the conditions stated below. Sublicensing is not allowed; section 10 | ||
| 194 | makes it unnecessary. | ||
| 195 | |||
| 196 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. | ||
| 197 | |||
| 198 | No covered work shall be deemed part of an effective technological | ||
| 199 | measure under any applicable law fulfilling obligations under article | ||
| 200 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or | ||
| 201 | similar laws prohibiting or restricting circumvention of such | ||
| 202 | measures. | ||
| 203 | |||
| 204 | When you convey a covered work, you waive any legal power to forbid | ||
| 205 | circumvention of technological measures to the extent such circumvention | ||
| 206 | is effected by exercising rights under this License with respect to | ||
| 207 | the covered work, and you disclaim any intention to limit operation or | ||
| 208 | modification of the work as a means of enforcing, against the work's | ||
| 209 | users, your or third parties' legal rights to forbid circumvention of | ||
| 210 | technological measures. | ||
| 211 | |||
| 212 | 4. Conveying Verbatim Copies. | ||
| 213 | |||
| 214 | You may convey verbatim copies of the Program's source code as you | ||
| 215 | receive it, in any medium, provided that you conspicuously and | ||
| 216 | appropriately publish on each copy an appropriate copyright notice; | ||
| 217 | keep intact all notices stating that this License and any | ||
| 218 | non-permissive terms added in accord with section 7 apply to the code; | ||
| 219 | keep intact all notices of the absence of any warranty; and give all | ||
| 220 | recipients a copy of this License along with the Program. | ||
| 221 | |||
| 222 | You may charge any price or no price for each copy that you convey, | ||
| 223 | and you may offer support or warranty protection for a fee. | ||
| 224 | |||
| 225 | 5. Conveying Modified Source Versions. | ||
| 226 | |||
| 227 | You may convey a work based on the Program, or the modifications to | ||
| 228 | produce it from the Program, in the form of source code under the | ||
| 229 | terms of section 4, provided that you also meet all of these conditions: | ||
| 230 | |||
| 231 | a) The work must carry prominent notices stating that you modified | ||
| 232 | it, and giving a relevant date. | ||
| 233 | |||
| 234 | b) The work must carry prominent notices stating that it is | ||
| 235 | released under this License and any conditions added under section | ||
| 236 | 7. This requirement modifies the requirement in section 4 to | ||
| 237 | "keep intact all notices". | ||
| 238 | |||
| 239 | c) You must license the entire work, as a whole, under this | ||
| 240 | License to anyone who comes into possession of a copy. This | ||
| 241 | License will therefore apply, along with any applicable section 7 | ||
| 242 | additional terms, to the whole of the work, and all its parts, | ||
| 243 | regardless of how they are packaged. This License gives no | ||
| 244 | permission to license the work in any other way, but it does not | ||
| 245 | invalidate such permission if you have separately received it. | ||
| 246 | |||
| 247 | d) If the work has interactive user interfaces, each must display | ||
| 248 | Appropriate Legal Notices; however, if the Program has interactive | ||
| 249 | interfaces that do not display Appropriate Legal Notices, your | ||
| 250 | work need not make them do so. | ||
| 251 | |||
| 252 | A compilation of a covered work with other separate and independent | ||
| 253 | works, which are not by their nature extensions of the covered work, | ||
| 254 | and which are not combined with it such as to form a larger program, | ||
| 255 | in or on a volume of a storage or distribution medium, is called an | ||
| 256 | "aggregate" if the compilation and its resulting copyright are not | ||
| 257 | used to limit the access or legal rights of the compilation's users | ||
| 258 | beyond what the individual works permit. Inclusion of a covered work | ||
| 259 | in an aggregate does not cause this License to apply to the other | ||
| 260 | parts of the aggregate. | ||
| 261 | |||
| 262 | 6. Conveying Non-Source Forms. | ||
| 263 | |||
| 264 | You may convey a covered work in object code form under the terms | ||
| 265 | of sections 4 and 5, provided that you also convey the | ||
| 266 | machine-readable Corresponding Source under the terms of this License, | ||
| 267 | in one of these ways: | ||
| 268 | |||
| 269 | a) Convey the object code in, or embodied in, a physical product | ||
| 270 | (including a physical distribution medium), accompanied by the | ||
| 271 | Corresponding Source fixed on a durable physical medium | ||
| 272 | customarily used for software interchange. | ||
| 273 | |||
| 274 | b) Convey the object code in, or embodied in, a physical product | ||
| 275 | (including a physical distribution medium), accompanied by a | ||
| 276 | written offer, valid for at least three years and valid for as | ||
| 277 | long as you offer spare parts or customer support for that product | ||
| 278 | model, to give anyone who possesses the object code either (1) a | ||
| 279 | copy of the Corresponding Source for all the software in the | ||
| 280 | product that is covered by this License, on a durable physical | ||
| 281 | medium customarily used for software interchange, for a price no | ||
| 282 | more than your reasonable cost of physically performing this | ||
| 283 | conveying of source, or (2) access to copy the | ||
| 284 | Corresponding Source from a network server at no charge. | ||
| 285 | |||
| 286 | c) Convey individual copies of the object code with a copy of the | ||
| 287 | written offer to provide the Corresponding Source. This | ||
| 288 | alternative is allowed only occasionally and noncommercially, and | ||
| 289 | only if you received the object code with such an offer, in accord | ||
| 290 | with subsection 6b. | ||
| 291 | |||
| 292 | d) Convey the object code by offering access from a designated | ||
| 293 | place (gratis or for a charge), and offer equivalent access to the | ||
| 294 | Corresponding Source in the same way through the same place at no | ||
| 295 | further charge. You need not require recipients to copy the | ||
| 296 | Corresponding Source along with the object code. If the place to | ||
| 297 | copy the object code is a network server, the Corresponding Source | ||
| 298 | may be on a different server (operated by you or a third party) | ||
| 299 | that supports equivalent copying facilities, provided you maintain | ||
| 300 | clear directions next to the object code saying where to find the | ||
| 301 | Corresponding Source. Regardless of what server hosts the | ||
| 302 | Corresponding Source, you remain obligated to ensure that it is | ||
| 303 | available for as long as needed to satisfy these requirements. | ||
| 304 | |||
| 305 | e) Convey the object code using peer-to-peer transmission, provided | ||
| 306 | you inform other peers where the object code and Corresponding | ||
| 307 | Source of the work are being offered to the general public at no | ||
| 308 | charge under subsection 6d. | ||
| 309 | |||
| 310 | A separable portion of the object code, whose source code is excluded | ||
| 311 | from the Corresponding Source as a System Library, need not be | ||
| 312 | included in conveying the object code work. | ||
| 313 | |||
| 314 | A "User Product" is either (1) a "consumer product", which means any | ||
| 315 | tangible personal property which is normally used for personal, family, | ||
| 316 | or household purposes, or (2) anything designed or sold for incorporation | ||
| 317 | into a dwelling. In determining whether a product is a consumer product, | ||
| 318 | doubtful cases shall be resolved in favor of coverage. For a particular | ||
| 319 | product received by a particular user, "normally used" refers to a | ||
| 320 | typical or common use of that class of product, regardless of the status | ||
| 321 | of the particular user or of the way in which the particular user | ||
| 322 | actually uses, or expects or is expected to use, the product. A product | ||
| 323 | is a consumer product regardless of whether the product has substantial | ||
| 324 | commercial, industrial or non-consumer uses, unless such uses represent | ||
| 325 | the only significant mode of use of the product. | ||
| 326 | |||
| 327 | "Installation Information" for a User Product means any methods, | ||
| 328 | procedures, authorization keys, or other information required to install | ||
| 329 | and execute modified versions of a covered work in that User Product from | ||
| 330 | a modified version of its Corresponding Source. The information must | ||
| 331 | suffice to ensure that the continued functioning of the modified object | ||
| 332 | code is in no case prevented or interfered with solely because | ||
| 333 | modification has been made. | ||
| 334 | |||
| 335 | If you convey an object code work under this section in, or with, or | ||
| 336 | specifically for use in, a User Product, and the conveying occurs as | ||
| 337 | part of a transaction in which the right of possession and use of the | ||
| 338 | User Product is transferred to the recipient in perpetuity or for a | ||
| 339 | fixed term (regardless of how the transaction is characterized), the | ||
| 340 | Corresponding Source conveyed under this section must be accompanied | ||
| 341 | by the Installation Information. But this requirement does not apply | ||
| 342 | if neither you nor any third party retains the ability to install | ||
| 343 | modified object code on the User Product (for example, the work has | ||
| 344 | been installed in ROM). | ||
| 345 | |||
| 346 | The requirement to provide Installation Information does not include a | ||
| 347 | requirement to continue to provide support service, warranty, or updates | ||
| 348 | for a work that has been modified or installed by the recipient, or for | ||
| 349 | the User Product in which it has been modified or installed. Access to a | ||
| 350 | network may be denied when the modification itself materially and | ||
| 351 | adversely affects the operation of the network or violates the rules and | ||
| 352 | protocols for communication across the network. | ||
| 353 | |||
| 354 | Corresponding Source conveyed, and Installation Information provided, | ||
| 355 | in accord with this section must be in a format that is publicly | ||
| 356 | documented (and with an implementation available to the public in | ||
| 357 | source code form), and must require no special password or key for | ||
| 358 | unpacking, reading or copying. | ||
| 359 | |||
| 360 | 7. Additional Terms. | ||
| 361 | |||
| 362 | "Additional permissions" are terms that supplement the terms of this | ||
| 363 | License by making exceptions from one or more of its conditions. | ||
| 364 | Additional permissions that are applicable to the entire Program shall | ||
| 365 | be treated as though they were included in this License, to the extent | ||
| 366 | that they are valid under applicable law. If additional permissions | ||
| 367 | apply only to part of the Program, that part may be used separately | ||
| 368 | under those permissions, but the entire Program remains governed by | ||
| 369 | this License without regard to the additional permissions. | ||
| 370 | |||
| 371 | When you convey a copy of a covered work, you may at your option | ||
| 372 | remove any additional permissions from that copy, or from any part of | ||
| 373 | it. (Additional permissions may be written to require their own | ||
| 374 | removal in certain cases when you modify the work.) You may place | ||
| 375 | additional permissions on material, added by you to a covered work, | ||
| 376 | for which you have or can give appropriate copyright permission. | ||
| 377 | |||
| 378 | Notwithstanding any other provision of this License, for material you | ||
| 379 | add to a covered work, you may (if authorized by the copyright holders of | ||
| 380 | that material) supplement the terms of this License with terms: | ||
| 381 | |||
| 382 | a) Disclaiming warranty or limiting liability differently from the | ||
| 383 | terms of sections 15 and 16 of this License; or | ||
| 384 | |||
| 385 | b) Requiring preservation of specified reasonable legal notices or | ||
| 386 | author attributions in that material or in the Appropriate Legal | ||
| 387 | Notices displayed by works containing it; or | ||
| 388 | |||
| 389 | c) Prohibiting misrepresentation of the origin of that material, or | ||
| 390 | requiring that modified versions of such material be marked in | ||
| 391 | reasonable ways as different from the original version; or | ||
| 392 | |||
| 393 | d) Limiting the use for publicity purposes of names of licensors or | ||
| 394 | authors of the material; or | ||
| 395 | |||
| 396 | e) Declining to grant rights under trademark law for use of some | ||
| 397 | trade names, trademarks, or service marks; or | ||
| 398 | |||
| 399 | f) Requiring indemnification of licensors and authors of that | ||
| 400 | material by anyone who conveys the material (or modified versions of | ||
| 401 | it) with contractual assumptions of liability to the recipient, for | ||
| 402 | any liability that these contractual assumptions directly impose on | ||
| 403 | those licensors and authors. | ||
| 404 | |||
| 405 | All other non-permissive additional terms are considered "further | ||
| 406 | restrictions" within the meaning of section 10. If the Program as you | ||
| 407 | received it, or any part of it, contains a notice stating that it is | ||
| 408 | governed by this License along with a term that is a further | ||
| 409 | restriction, you may remove that term. If a license document contains | ||
| 410 | a further restriction but permits relicensing or conveying under this | ||
| 411 | License, you may add to a covered work material governed by the terms | ||
| 412 | of that license document, provided that the further restriction does | ||
| 413 | not survive such relicensing or conveying. | ||
| 414 | |||
| 415 | If you add terms to a covered work in accord with this section, you | ||
| 416 | must place, in the relevant source files, a statement of the | ||
| 417 | additional terms that apply to those files, or a notice indicating | ||
| 418 | where to find the applicable terms. | ||
| 419 | |||
| 420 | Additional terms, permissive or non-permissive, may be stated in the | ||
| 421 | form of a separately written license, or stated as exceptions; | ||
| 422 | the above requirements apply either way. | ||
| 423 | |||
| 424 | 8. Termination. | ||
| 425 | |||
| 426 | You may not propagate or modify a covered work except as expressly | ||
| 427 | provided under this License. Any attempt otherwise to propagate or | ||
| 428 | modify it is void, and will automatically terminate your rights under | ||
| 429 | this License (including any patent licenses granted under the third | ||
| 430 | paragraph of section 11). | ||
| 431 | |||
| 432 | However, if you cease all violation of this License, then your | ||
| 433 | license from a particular copyright holder is reinstated (a) | ||
| 434 | provisionally, unless and until the copyright holder explicitly and | ||
| 435 | finally terminates your license, and (b) permanently, if the copyright | ||
| 436 | holder fails to notify you of the violation by some reasonable means | ||
| 437 | prior to 60 days after the cessation. | ||
| 438 | |||
| 439 | Moreover, your license from a particular copyright holder is | ||
| 440 | reinstated permanently if the copyright holder notifies you of the | ||
| 441 | violation by some reasonable means, this is the first time you have | ||
| 442 | received notice of violation of this License (for any work) from that | ||
| 443 | copyright holder, and you cure the violation prior to 30 days after | ||
| 444 | your receipt of the notice. | ||
| 445 | |||
| 446 | Termination of your rights under this section does not terminate the | ||
| 447 | licenses of parties who have received copies or rights from you under | ||
| 448 | this License. If your rights have been terminated and not permanently | ||
| 449 | reinstated, you do not qualify to receive new licenses for the same | ||
| 450 | material under section 10. | ||
| 451 | |||
| 452 | 9. Acceptance Not Required for Having Copies. | ||
| 453 | |||
| 454 | You are not required to accept this License in order to receive or | ||
| 455 | run a copy of the Program. Ancillary propagation of a covered work | ||
| 456 | occurring solely as a consequence of using peer-to-peer transmission | ||
| 457 | to receive a copy likewise does not require acceptance. However, | ||
| 458 | nothing other than this License grants you permission to propagate or | ||
| 459 | modify any covered work. These actions infringe copyright if you do | ||
| 460 | not accept this License. Therefore, by modifying or propagating a | ||
| 461 | covered work, you indicate your acceptance of this License to do so. | ||
| 462 | |||
| 463 | 10. Automatic Licensing of Downstream Recipients. | ||
| 464 | |||
| 465 | Each time you convey a covered work, the recipient automatically | ||
| 466 | receives a license from the original licensors, to run, modify and | ||
| 467 | propagate that work, subject to this License. You are not responsible | ||
| 468 | for enforcing compliance by third parties with this License. | ||
| 469 | |||
| 470 | An "entity transaction" is a transaction transferring control of an | ||
| 471 | organization, or substantially all assets of one, or subdividing an | ||
| 472 | organization, or merging organizations. If propagation of a covered | ||
| 473 | work results from an entity transaction, each party to that | ||
| 474 | transaction who receives a copy of the work also receives whatever | ||
| 475 | licenses to the work the party's predecessor in interest had or could | ||
| 476 | give under the previous paragraph, plus a right to possession of the | ||
| 477 | Corresponding Source of the work from the predecessor in interest, if | ||
| 478 | the predecessor has it or can get it with reasonable efforts. | ||
| 479 | |||
| 480 | You may not impose any further restrictions on the exercise of the | ||
| 481 | rights granted or affirmed under this License. For example, you may | ||
| 482 | not impose a license fee, royalty, or other charge for exercise of | ||
| 483 | rights granted under this License, and you may not initiate litigation | ||
| 484 | (including a cross-claim or counterclaim in a lawsuit) alleging that | ||
| 485 | any patent claim is infringed by making, using, selling, offering for | ||
| 486 | sale, or importing the Program or any portion of it. | ||
| 487 | |||
| 488 | 11. Patents. | ||
| 489 | |||
| 490 | A "contributor" is a copyright holder who authorizes use under this | ||
| 491 | License of the Program or a work on which the Program is based. The | ||
| 492 | work thus licensed is called the contributor's "contributor version". | ||
| 493 | |||
| 494 | A contributor's "essential patent claims" are all patent claims | ||
| 495 | owned or controlled by the contributor, whether already acquired or | ||
| 496 | hereafter acquired, that would be infringed by some manner, permitted | ||
| 497 | by this License, of making, using, or selling its contributor version, | ||
| 498 | but do not include claims that would be infringed only as a | ||
| 499 | consequence of further modification of the contributor version. For | ||
| 500 | purposes of this definition, "control" includes the right to grant | ||
| 501 | patent sublicenses in a manner consistent with the requirements of | ||
| 502 | this License. | ||
| 503 | |||
| 504 | Each contributor grants you a non-exclusive, worldwide, royalty-free | ||
| 505 | patent license under the contributor's essential patent claims, to | ||
| 506 | make, use, sell, offer for sale, import and otherwise run, modify and | ||
| 507 | propagate the contents of its contributor version. | ||
| 508 | |||
| 509 | In the following three paragraphs, a "patent license" is any express | ||
| 510 | agreement or commitment, however denominated, not to enforce a patent | ||
| 511 | (such as an express permission to practice a patent or covenant not to | ||
| 512 | sue for patent infringement). To "grant" such a patent license to a | ||
| 513 | party means to make such an agreement or commitment not to enforce a | ||
| 514 | patent against the party. | ||
| 515 | |||
| 516 | If you convey a covered work, knowingly relying on a patent license, | ||
| 517 | and the Corresponding Source of the work is not available for anyone | ||
| 518 | to copy, free of charge and under the terms of this License, through a | ||
| 519 | publicly available network server or other readily accessible means, | ||
| 520 | then you must either (1) cause the Corresponding Source to be so | ||
| 521 | available, or (2) arrange to deprive yourself of the benefit of the | ||
| 522 | patent license for this particular work, or (3) arrange, in a manner | ||
| 523 | consistent with the requirements of this License, to extend the patent | ||
| 524 | license to downstream recipients. "Knowingly relying" means you have | ||
| 525 | actual knowledge that, but for the patent license, your conveying the | ||
| 526 | covered work in a country, or your recipient's use of the covered work | ||
| 527 | in a country, would infringe one or more identifiable patents in that | ||
| 528 | country that you have reason to believe are valid. | ||
| 529 | |||
| 530 | If, pursuant to or in connection with a single transaction or | ||
| 531 | arrangement, you convey, or propagate by procuring conveyance of, a | ||
| 532 | covered work, and grant a patent license to some of the parties | ||
| 533 | receiving the covered work authorizing them to use, propagate, modify | ||
| 534 | or convey a specific copy of the covered work, then the patent license | ||
| 535 | you grant is automatically extended to all recipients of the covered | ||
| 536 | work and works based on it. | ||
| 537 | |||
| 538 | A patent license is "discriminatory" if it does not include within | ||
| 539 | the scope of its coverage, prohibits the exercise of, or is | ||
| 540 | conditioned on the non-exercise of one or more of the rights that are | ||
| 541 | specifically granted under this License. You may not convey a covered | ||
| 542 | work if you are a party to an arrangement with a third party that is | ||
| 543 | in the business of distributing software, under which you make payment | ||
| 544 | to the third party based on the extent of your activity of conveying | ||
| 545 | the work, and under which the third party grants, to any of the | ||
| 546 | parties who would receive the covered work from you, a discriminatory | ||
| 547 | patent license (a) in connection with copies of the covered work | ||
| 548 | conveyed by you (or copies made from those copies), or (b) primarily | ||
| 549 | for and in connection with specific products or compilations that | ||
| 550 | contain the covered work, unless you entered into that arrangement, | ||
| 551 | or that patent license was granted, prior to 28 March 2007. | ||
| 552 | |||
| 553 | Nothing in this License shall be construed as excluding or limiting | ||
| 554 | any implied license or other defenses to infringement that may | ||
| 555 | otherwise be available to you under applicable patent law. | ||
| 556 | |||
| 557 | 12. No Surrender of Others' Freedom. | ||
| 558 | |||
| 559 | If conditions are imposed on you (whether by court order, agreement or | ||
| 560 | otherwise) that contradict the conditions of this License, they do not | ||
| 561 | excuse you from the conditions of this License. If you cannot convey a | ||
| 562 | covered work so as to satisfy simultaneously your obligations under this | ||
| 563 | License and any other pertinent obligations, then as a consequence you may | ||
| 564 | not convey it at all. For example, if you agree to terms that obligate you | ||
| 565 | to collect a royalty for further conveying from those to whom you convey | ||
| 566 | the Program, the only way you could satisfy both those terms and this | ||
| 567 | License would be to refrain entirely from conveying the Program. | ||
| 568 | |||
| 569 | 13. Use with the GNU Affero General Public License. | ||
| 570 | |||
| 571 | Notwithstanding any other provision of this License, you have | ||
| 572 | permission to link or combine any covered work with a work licensed | ||
| 573 | under version 3 of the GNU Affero General Public License into a single | ||
| 574 | combined work, and to convey the resulting work. The terms of this | ||
| 575 | License will continue to apply to the part which is the covered work, | ||
| 576 | but the special requirements of the GNU Affero General Public License, | ||
| 577 | section 13, concerning interaction through a network will apply to the | ||
| 578 | combination as such. | ||
| 579 | |||
| 580 | 14. Revised Versions of this License. | ||
| 581 | |||
| 582 | The Free Software Foundation may publish revised and/or new versions of | ||
| 583 | the GNU General Public License from time to time. Such new versions will | ||
| 584 | be similar in spirit to the present version, but may differ in detail to | ||
| 585 | address new problems or concerns. | ||
| 586 | |||
| 587 | Each version is given a distinguishing version number. If the | ||
| 588 | Program specifies that a certain numbered version of the GNU General | ||
| 589 | Public License "or any later version" applies to it, you have the | ||
| 590 | option of following the terms and conditions either of that numbered | ||
| 591 | version or of any later version published by the Free Software | ||
| 592 | Foundation. If the Program does not specify a version number of the | ||
| 593 | GNU General Public License, you may choose any version ever published | ||
| 594 | by the Free Software Foundation. | ||
| 595 | |||
| 596 | If the Program specifies that a proxy can decide which future | ||
| 597 | versions of the GNU General Public License can be used, that proxy's | ||
| 598 | public statement of acceptance of a version permanently authorizes you | ||
| 599 | to choose that version for the Program. | ||
| 600 | |||
| 601 | Later license versions may give you additional or different | ||
| 602 | permissions. However, no additional obligations are imposed on any | ||
| 603 | author or copyright holder as a result of your choosing to follow a | ||
| 604 | later version. | ||
| 605 | |||
| 606 | 15. Disclaimer of Warranty. | ||
| 607 | |||
| 608 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | ||
| 609 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | ||
| 610 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | ||
| 611 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | ||
| 612 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
| 613 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | ||
| 614 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | ||
| 615 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | ||
| 616 | |||
| 617 | 16. Limitation of Liability. | ||
| 618 | |||
| 619 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||
| 620 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | ||
| 621 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | ||
| 622 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | ||
| 623 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | ||
| 624 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | ||
| 625 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | ||
| 626 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | ||
| 627 | SUCH DAMAGES. | ||
| 628 | |||
| 629 | 17. Interpretation of Sections 15 and 16. | ||
| 630 | |||
| 631 | If the disclaimer of warranty and limitation of liability provided | ||
| 632 | above cannot be given local legal effect according to their terms, | ||
| 633 | reviewing courts shall apply local law that most closely approximates | ||
| 634 | an absolute waiver of all civil liability in connection with the | ||
| 635 | Program, unless a warranty or assumption of liability accompanies a | ||
| 636 | copy of the Program in return for a fee. | ||
diff --git a/Makefile b/Makefile deleted file mode 100644 index 71eda6b..0000000 --- a/Makefile +++ /dev/null | |||
| @@ -1,68 +0,0 @@ | |||
| 1 | # See LICENSE file for copyright and license details. | ||
| 2 | |||
| 3 | VERSION = post-2.0.2 | ||
| 4 | |||
| 5 | PREFIX = /usr/local | ||
| 6 | MANPREFIX = ${PREFIX}/share/man | ||
| 7 | |||
| 8 | CPPFLAGS = -DVERSION=\"${VERSION}\" | ||
| 9 | CFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \ | ||
| 10 | -Wno-unused-parameter -O3 ${CPPFLAGS} | ||
| 11 | DBGFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \ | ||
| 12 | -Wno-unused-parameter -g ${CPPFLAGS} | ||
| 13 | |||
| 14 | CC = cc | ||
| 15 | |||
| 16 | all: nissy | ||
| 17 | |||
| 18 | nissy: clean | ||
| 19 | ${CC} ${CFLAGS} -o nissy src/*.c | ||
| 20 | |||
| 21 | nissy.exe: | ||
| 22 | x86_64-w64-mingw32-gcc ${CFLAGS} -static -o nissy.exe src/*.c | ||
| 23 | |||
| 24 | debug: | ||
| 25 | ${CC} ${DBGFLAGS} -o nissy src/*.c | ||
| 26 | |||
| 27 | test: | ||
| 28 | ${CC} ${DBGFLAGS} -DTEST -o test src/*.c tests/*.c | ||
| 29 | |||
| 30 | clean: | ||
| 31 | rm -rf nissy nissy*.exe nissy*.tar.gz doc/nissy.html doc/nissy.pdf | ||
| 32 | |||
| 33 | dist: clean nissy.exe | ||
| 34 | mkdir -p nissy-${VERSION} | ||
| 35 | cp -R LICENSE Makefile INSTALL doc src nissy-${VERSION} | ||
| 36 | groff -Tpdf -mandoc doc/nissy.1 > doc/nissy.pdf | ||
| 37 | groff -Thtml -mandoc doc/nissy.1 > doc/nissy.html | ||
| 38 | cp doc/nissy.pdf nissy-${VERSION}/doc/nissy.pdf | ||
| 39 | cp doc/nissy.html nissy-${VERSION}/doc/nissy.html | ||
| 40 | tar -cf nissy-${VERSION}.tar nissy-${VERSION} | ||
| 41 | gzip nissy-${VERSION}.tar | ||
| 42 | rm -rf nissy-${VERSION} | ||
| 43 | mv nissy.exe nissy-${VERSION}.exe | ||
| 44 | |||
| 45 | upload: dist | ||
| 46 | rsync -v --rsync-path=openrsync nissy-${VERSION}.exe \ | ||
| 47 | tronto.net:/var/www/htdocs/nissy.tronto.net/ | ||
| 48 | rsync -v --rsync-path=openrsync nissy-${VERSION}.tar.gz \ | ||
| 49 | tronto.net:/var/www/htdocs/nissy.tronto.net/ | ||
| 50 | |||
| 51 | website: | ||
| 52 | rsync -rv --rsync-path=openrsync \ | ||
| 53 | www/ tronto.net:/var/www/htdocs/nissy.tronto.net | ||
| 54 | |||
| 55 | install: nissy | ||
| 56 | mkdir -p ${DESTDIR}${PREFIX}/bin | ||
| 57 | cp -f nissy ${DESTDIR}${PREFIX}/bin/nissy | ||
| 58 | chmod 755 ${DESTDIR}${PREFIX}/bin/nissy | ||
| 59 | mkdir -p ${DESTDIR}${MANPREFIX}/man1 | ||
| 60 | sed "s/VERSION/${VERSION}/g" < doc/nissy.1 \ | ||
| 61 | > ${DESTDIR}${MANPREFIX}/man1/nissy.1 | ||
| 62 | chmod 644 ${DESTDIR}${MANPREFIX}/man1/nissy.1 | ||
| 63 | |||
| 64 | uninstall: | ||
| 65 | rm -rf ${DESTDIR}${PREFIX}/bin/nissy ${DESTDIR}${MANPREFIX}/man1/nissy.1 | ||
| 66 | for s in ${SCRIPTS}; do rm -rf ${DESTDIR}${PREFIX}/bin/$$s; done | ||
| 67 | |||
| 68 | .PHONY: all debug test clean dist install uninstall upload | ||
| @@ -1,104 +1,50 @@ | |||
| 1 | # WARNING | 1 | # Where is nissy? |
| 2 | 2 | ||
| 3 | I am currently rewriting some important parts of the code | 3 | In April 2023 I have decided to split nissy in 2 separate projects: an |
| 4 | and the git version is not working. | 4 | optimal solver and an FMC assistant. These two projects are not usable |
| 5 | You can download the last stable version from the | 5 | yet, so in the meantime I will keep a third branch where I update the |
| 6 | [download page](https://nissy.tronto.net/download). | 6 | classic version of nissy with bugfixes and minor improvements. |
| 7 | 7 | ||
| 8 | # Nissy | 8 | You can find these three branches at the following pages (also |
| 9 | on github, links below are to my personal git instance): | ||
| 9 | 10 | ||
| 10 | A Rubik's cube solver and FMC assistant. | 11 | * [nissy-classic](https://git.tronto.net/nissy-classic): The stable |
| 11 | For optimal HTM solving Nissy uses techniques from Herbert Kociemba's | 12 | branch, will receive bugfixes and minor improvements but no big |
| 12 | [Cube Explorer](http://kociemba.org/cube.htm) and Tomas Rokicki's | 13 | change. Will eventually be replaced by the other two versions. |
| 13 | [nxopt](https://github.com/rokicki/cube20src/blob/master/nxopt.md). | 14 | * [nissy-fmc](https://git.tronto.net/nissy-fmc): This will focus on |
| 14 | With 4 cores at 2.5GHz and using about 3Gb of RAM, Nissy can find an | 15 | features useful for practicing FMC, for example finding EOs and |
| 15 | optimal solution in about a minute on average. | 16 | DRs (if you do not know what this means, there is a good chance |
| 17 | you don't care). I plan to make a graphical interface for it and | ||
| 18 | make it more usable. It will not be able to find an optimal | ||
| 19 | solution. *Not working at the moment.* | ||
| 20 | * [nissy-nx](https://git.tronto.net/nissy-nx): An optimal solver. | ||
| 21 | For now this is just my playground for implementing complex | ||
| 22 | optimizations, following the ideas of Tomas's Rokicki's | ||
| 23 | [nxopt](https://github.com/rokicki/cube20src/blob/master/nxopt.md). | ||
| 24 | Eventually it will become faster than nissy-classic at optimal | ||
| 25 | solving, but without all other features. *Not working at the moment.* | ||
| 16 | 26 | ||
| 17 | Nissy can also solve many different substeps of Thistlethwaite's algorithm | 27 | # I am a user of nissy, what should I do? |
| 18 | (DR/HTR), and can use NISS (Normal-Inverse Scramble Switch). | ||
| 19 | It can be useful to analyze your DR solves (and more, once I implement more features). | ||
| 20 | 28 | ||
| 21 | You can get Nissy from [nissy.tronto.net](https://nissy.tronto.net). | 29 | If you are happy with using nissy as it is, you can keep using it. |
| 22 | The download links and installation instructions can be found on the | ||
| 23 | [download page](https://nissy.tronto.net/download). | ||
| 24 | 30 | ||
| 25 | ## Structure of the code | 31 | When nissy-fmc and nissy-classic are ready, you can chek them out too. |
| 26 | 32 | ||
| 27 | You can find all the source code in the `src` folder. | 33 | # But I liked that nissy can do both optimal solving! Why did you split it? |
| 28 | I strived to keep it legible but I did not write many comments (barely any at all). | ||
| 29 | I'll try to explain here the main parts of the program. | ||
| 30 | 34 | ||
| 31 | ### Cube, moves and transformations | 35 | Then I encourage you to keep using nissy-classic :-) |
| 32 | 36 | ||
| 33 | There are many ways to represent a cube. In Nissy I use two: | 37 | See |
| 38 | [my blog post](https://sebastiano.tronto.net/blog/2023-04-10-the-big-rewrite/) | ||
| 39 | for some reasons behind this change. | ||
| 34 | 40 | ||
| 35 | * An array representation `CubeArray`: 3 arrays representing the permutation | 41 | # I just want to look at the code, where should I go? |
| 36 | of corners, edges and centers and 2 arrays for the orientation of corners and edges. | ||
| 37 | * An 11-integers representation `Cube`: 3 integers for edge orientation (with respect | ||
| 38 | to the three axes), 3 for corner orientation, and so on. Edge permutation is a bit | ||
| 39 | complicated because encoding 12 factorial as a single number is too large for some | ||
| 40 | practical reasons, so I use 3 integers for that. | ||
| 41 | 42 | ||
| 42 | Moves are easy to apply on the array form, but they are slow. So `moves.c` | 43 | If you want to check out the git repository of the version you are |
| 43 | contains the instructions to create all the transition tables necessary | 44 | running, you probably want nissy-classic. The newer nissy-fmc will |
| 44 | to get the next position for the cube with just 11 lookup operations | 45 | eventually be nicer and easier to read, containing more or less |
| 45 | (one for each of the 11 integers in the second representation). | 46 | the same functionality (except for optimal solving). |
| 46 | These transition tables are saved in the `mtables` file in the | ||
| 47 | `tables` folder in binary format. | ||
| 48 | |||
| 49 | The 11 integers are obviously redundant, but keeping all of them makes it easy | ||
| 50 | to apply transformations. A transformation is a rotation of the whole cube, possibly | ||
| 51 | combined with a mirror operation. Applying a transformation to a cube (say obtained | ||
| 52 | by applying a scramble to the solved cube) means applying the transformation to a | ||
| 53 | solved cube, then the scramble and then the inverse of the transformation | ||
| 54 | (i.e. conjugating by it). | ||
| 55 | |||
| 56 | ### Coordinates and pruning tables | ||
| 57 | |||
| 58 | A *coordinate* consists of a function that takes a cube (in the 11-integer | ||
| 59 | representation) and return an (unsigned, 64-bit) integer. They are used | ||
| 60 | to "linearize" a cube and build pruning tables, which speed up significantly the | ||
| 61 | solving process. To be able to access the pruning table quickly, the function | ||
| 62 | needs to be very fast (e.g. it should not convert between the two representations | ||
| 63 | of the cube if not necessary). | ||
| 64 | |||
| 65 | Some coordinates make use of symmetries to reduce the size of the resulting | ||
| 66 | pruning table. Unfortunately this complicates the code a lot, but it is a huge | ||
| 67 | advantage: it reduces by a factor of about 16 the pruning table size. | ||
| 68 | |||
| 69 | Pruning tables are related to a specific step, a moveset and a coordinate. They | ||
| 70 | contain one value from 0 to 15 (4 bits) for each possible value for the coordinate, | ||
| 71 | which is less or equal than the minimum number of moves required to solve the | ||
| 72 | given step with the given moveset for a cube which has the given coordinate. For example, | ||
| 73 | say the coordinate `neo` gives the number of non-oriented edges (say with respect to | ||
| 74 | F/B). Then the possible values for the coordinate are 0,2,4,...,12. An associated | ||
| 75 | pruning table to solving EO with HTM moveset and this coordinate would have values 0 | ||
| 76 | (for `neo=0`), 3 (for `neo=2`), 1 (for `neo=4`)... | ||
| 77 | |||
| 78 | The values for most pruning tables are memorized modulo 16, so they only occupy | ||
| 79 | 4 bits per entry, and values larger than 15 are saved as 15. This is good enough | ||
| 80 | for most applications. | ||
| 81 | Some large tables are memorized in compact form using only 2 bits, similarly | ||
| 82 | to what [nxopt](https://github.com/rokicki/cube20src/blob/master/nxopt.md) does: | ||
| 83 | a base value `b` is picked and a value of `n` is saved as `MIN(3,MAX(0,n-b))`. | ||
| 84 | When a value of `v=1,2,3` is read it is simply returned as `v+b`, while if | ||
| 85 | `0` is a successive lookup to a fallback table is performed. The base value `b` | ||
| 86 | is picked to maximize the sum frequency of the values `1,2,3`. | ||
| 87 | |||
| 88 | In order to generate the pruning tables, it is necessary to be able to move | ||
| 89 | a transform a coordinate; it is possible to do so without passing through a | ||
| 90 | complete cube representations, in a way similar to what Cube Explorer does. | ||
| 91 | This used to be different before version 2.1 (June 2022). | ||
| 92 | |||
| 93 | More documentation on this and on the different types of coordinates (base | ||
| 94 | vs composed) is work in progress. | ||
| 95 | |||
| 96 | ### Solving | ||
| 97 | |||
| 98 | Solving is implemented as a generic function that takes both a step and | ||
| 99 | a (scrambled) cube as input, as well as some extra parameters that say e.g. | ||
| 100 | how many solution one wants. A step consists, among other things, of | ||
| 101 | an estimator function that, given a cube, gives a lower bound for the number | ||
| 102 | of moves needed to complete the step. Many of these estimators simply | ||
| 103 | look up the corresponding values in the appropriate pruning table. | ||
| 104 | 47 | ||
| 48 | If you want to follow my progress on an advanced optimal Rubik's | ||
| 49 | cube solver, you can check out nissy-nx - just remember that it | ||
| 50 | does not work yet! | ||
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/doc/nissy.1 b/doc/nissy.1 deleted file mode 100644 index 138d6ae..0000000 --- a/doc/nissy.1 +++ /dev/null | |||
| @@ -1,271 +0,0 @@ | |||
| 1 | .Dd November 2021 | ||
| 2 | .Dt NISSY 1 | ||
| 3 | .Os | ||
| 4 | .Sh NAME | ||
| 5 | .Nm nissy | ||
| 6 | .Nd a Rubik's cube solver and FMC assistant | ||
| 7 | . | ||
| 8 | .Sh SYNOPSIS | ||
| 9 | .Nm | ||
| 10 | .Op Fl b | ||
| 11 | .Nm | ||
| 12 | .Ar command | ||
| 13 | .Op options... | ||
| 14 | . | ||
| 15 | .Sh DESCRIPTION | ||
| 16 | .Nm | ||
| 17 | is a Rubik's Cube solver. | ||
| 18 | It uses techniques from Herbert Kociemba's Cube Explorer and | ||
| 19 | Tomas Rokicki's nxopt. With 4 cores at 2.5GHz and using about 3Gb | ||
| 20 | of RAM, Nissy can find the optimal solution for a random Rubik's cube position | ||
| 21 | in about a minute on average. | ||
| 22 | Nissy can also solve different substeps of the Thistlethwaite's algorithm and more. | ||
| 23 | .Pp | ||
| 24 | When run without any argument an interactive shell is launched, otherwise | ||
| 25 | the provided | ||
| 26 | .Ar command | ||
| 27 | is executed and nissy terminates. If the option | ||
| 28 | .Fl b | ||
| 29 | is given, every argument after it is ignored and the shell is launched without | ||
| 30 | any prompt or welcome message. This can be used to run nissy in batch mode, | ||
| 31 | for example writing a list of commands in a | ||
| 32 | .Ar file | ||
| 33 | (one per line) and running | ||
| 34 | .Ar nissy -b < file | ||
| 35 | .Pp | ||
| 36 | The commands that can be run in the interactive shell are the same that can | ||
| 37 | be run non-interactively and are provided below. | ||
| 38 | . | ||
| 39 | .Sh COMMANDS | ||
| 40 | The available | ||
| 41 | .Ar commands | ||
| 42 | are the following: | ||
| 43 | . | ||
| 44 | .Bl -tag -width Ds | ||
| 45 | . | ||
| 46 | .It Nm cleanup Ar scramble | ||
| 47 | Rewrites the given scramble using only the 18 base (HTM) moves and at most two | ||
| 48 | rotations at the end. If | ||
| 49 | Ar scramble | ||
| 50 | uses NISS, all moves done on normal scramble are written first, followed by | ||
| 51 | all moves done on inverse. | ||
| 52 | . | ||
| 53 | .It Nm commands | ||
| 54 | List all available commands. | ||
| 55 | . | ||
| 56 | .It Nm freemem | ||
| 57 | Release some large tables from memory. You can use this command in case | ||
| 58 | you want to keep nissy open without using too much RAM. | ||
| 59 | . | ||
| 60 | .It Nm gen Op Fl t Ar N | ||
| 61 | Generate all tables used by nissy. Run this to complete your installation. | ||
| 62 | If | ||
| 63 | .Ar N | ||
| 64 | is specified, | ||
| 65 | .Ar N | ||
| 66 | CPU threads will be used (defaults to 64, use less only if you don't want | ||
| 67 | nissy to use all of your CPU resources). | ||
| 68 | . | ||
| 69 | .It Nm help Op Ar command | ||
| 70 | Display help. If no | ||
| 71 | .Ar command | ||
| 72 | is given, a generic help message is printed, otherwise a specific help | ||
| 73 | relative to | ||
| 74 | .Ar command | ||
| 75 | is returned. | ||
| 76 | . | ||
| 77 | .It Nm invert Ar scramble | ||
| 78 | Invert the given scramble. | ||
| 79 | . | ||
| 80 | .It Nm print Ar scramble | ||
| 81 | Display a text-only description of the cube obtained after applying | ||
| 82 | .Ar scramble . | ||
| 83 | . | ||
| 84 | .It Nm quit | ||
| 85 | Quit nissy. | ||
| 86 | . | ||
| 87 | .It Nm scramble Oo Fl n Ar N Oc Oo Ar type Oc | ||
| 88 | Print a randomly-generated (random position) scramble | ||
| 89 | . | ||
| 90 | If | ||
| 91 | .Ar N | ||
| 92 | is given, it produces | ||
| 93 | .Ar N | ||
| 94 | scrambles. | ||
| 95 | .Ar type | ||
| 96 | can be specified to be one of the following: | ||
| 97 | .Bl -tag -width Ds | ||
| 98 | .It Ar corners | ||
| 99 | Scramble with solved edges (only cornes are scrambled). | ||
| 100 | .It Ar dr | ||
| 101 | Scramble with solved DR on U/D. | ||
| 102 | .It Ar edges | ||
| 103 | Scramble with solved corners (only edges are scrambled). | ||
| 104 | .It Ar eo | ||
| 105 | Scramble with solved EO on F/B axis. | ||
| 106 | .It Ar fmc | ||
| 107 | Scramble the full cube and the resulting scramble starts and ends with | ||
| 108 | the moves R\(aq U\(aq F. | ||
| 109 | .It Ar htr | ||
| 110 | Scramble with HTR solved. | ||
| 111 | .El | ||
| 112 | . | ||
| 113 | .It Nm solve Ar step Oo Ar options Oc Ar scramble | ||
| 114 | Solve the given | ||
| 115 | .Ar step | ||
| 116 | on the given | ||
| 117 | .Ar scramble. | ||
| 118 | By default it finds only one (shortest) solution, without using niss, and it | ||
| 119 | displays the number of moves at the end of the line. | ||
| 120 | . | ||
| 121 | The options for the | ||
| 122 | .Ar solve | ||
| 123 | command are the following: | ||
| 124 | . | ||
| 125 | .Bl -tag -width Ds | ||
| 126 | . | ||
| 127 | .It Fl a | ||
| 128 | Print all solutions: some solutions are filtered out by default for some | ||
| 129 | steps, for examples EOs that finish with F\(aq, with this options they are not. | ||
| 130 | . | ||
| 131 | .It Fl c | ||
| 132 | Display only the number of solutions found, not the solutions themselves. | ||
| 133 | . | ||
| 134 | .It Fl m Ar min | ||
| 135 | Only look for solution that are at least | ||
| 136 | .Ar min | ||
| 137 | moves long. | ||
| 138 | . | ||
| 139 | .It Fl M Ar MAX | ||
| 140 | Only look for solution that are at most | ||
| 141 | .Ar MAX | ||
| 142 | moves long. | ||
| 143 | . | ||
| 144 | .It Fl n Ar N | ||
| 145 | Try to find | ||
| 146 | .Ar N | ||
| 147 | solutions. By default and unless the | ||
| 148 | .Fl M | ||
| 149 | or | ||
| 150 | .Fl o | ||
| 151 | options are used, at most one solution is returned. | ||
| 152 | If at least one of | ||
| 153 | .Fl M | ||
| 154 | and | ||
| 155 | .Fl o | ||
| 156 | is used, all the solutions found within the given bounds are returned. | ||
| 157 | The option | ||
| 158 | .Fl s | ||
| 159 | overwrites these default behaviors and at most | ||
| 160 | .Ar N | ||
| 161 | solutions are returned, still satisfiyng the other constraints. | ||
| 162 | . | ||
| 163 | .It Fl N | ||
| 164 | Allow use of NISS. | ||
| 165 | . | ||
| 166 | .It Fl o | ||
| 167 | Only find solutions that require the minimum number of moves. | ||
| 168 | . | ||
| 169 | .It Fl O Ar N | ||
| 170 | Only find solutions that require at most | ||
| 171 | .Ar N | ||
| 172 | moves more than the optimal solution. If | ||
| 173 | .Ar N | ||
| 174 | is 0, this is equivalent to | ||
| 175 | .Fl o | ||
| 176 | . | ||
| 177 | .It Fl p | ||
| 178 | Plain style: do not print the number of moves. | ||
| 179 | . | ||
| 180 | .It Fl t Ar N | ||
| 181 | Use | ||
| 182 | .Ar N | ||
| 183 | CPU threads. By default nissy uses only 1 thread. Using more than one | ||
| 184 | thread will improve performance, but the optimal number depends on your | ||
| 185 | machine and operating system. Generally, using one less than the number | ||
| 186 | of threads of your CPU works quite well. | ||
| 187 | . | ||
| 188 | .It Fl v | ||
| 189 | Verbose mode: print some information during the search and print each solution | ||
| 190 | as it is found instead of only printing them all together at the end. | ||
| 191 | . | ||
| 192 | . | ||
| 193 | .El | ||
| 194 | . | ||
| 195 | .It Nm steps | ||
| 196 | List all available | ||
| 197 | .Ar steps | ||
| 198 | for the | ||
| 199 | .Ar solve | ||
| 200 | command. | ||
| 201 | . | ||
| 202 | .It Nm twophase Ar scramble | ||
| 203 | Find a solution using a two-phase method. This does not guarantee | ||
| 204 | to return an optimal solution (and in fact most often it does not), | ||
| 205 | but it is very fast. | ||
| 206 | . | ||
| 207 | .It Nm unniss Ar scramble | ||
| 208 | Rewrite the scramble without using NISS. | ||
| 209 | . | ||
| 210 | .It Nm version | ||
| 211 | Display version information. | ||
| 212 | . | ||
| 213 | .El | ||
| 214 | . | ||
| 215 | .Sh SCRAMBLES | ||
| 216 | All the commands above that accept a scramble also accept a | ||
| 217 | .Fl Nm i | ||
| 218 | option with no arguments. | ||
| 219 | If this option is given, multiple scrambles are read from standard | ||
| 220 | input (one per line) until and EOF is found, at which point stdin is cleared. | ||
| 221 | . | ||
| 222 | .Sh ENVIRONMENT | ||
| 223 | Data is stored in the folder pointed to by | ||
| 224 | .Nm $NISSYDATA. | ||
| 225 | If that variable is unset the folder | ||
| 226 | .Nm $XDG_DATA_HOME/nissy | ||
| 227 | or | ||
| 228 | .Nm $HOME/.nissy | ||
| 229 | is used instead. If none of this environment variables is defined | ||
| 230 | (e.g. in a non-UNIX system), the current folder is used. | ||
| 231 | . | ||
| 232 | .Sh EXAMPLES | ||
| 233 | .Pp | ||
| 234 | The command: | ||
| 235 | .Dl nissy solve -v -O 1 \(dqR\(aqU\(aqFD2L2FR2U2R2BD2LB2D\(aqB2L\(aqR\(aqBD2BU2LU2R\(aqU\(aqF\(dq | ||
| 236 | Returns: | ||
| 237 | .Dl Searching depth 0 | ||
| 238 | .Dl Searching depth 1 | ||
| 239 | .Dl (some more lines) | ||
| 240 | .Dl Searching depth 16 | ||
| 241 | .Dl D2 F\(aq U2 D2 F\(aq L2 D R2 D F B2 R\(aq L2 F\(aq U\(aq D | ||
| 242 | .Dl Searching depth 17 | ||
| 243 | .Dl D2 F\(aq U2 D2 F\(aq L2 D R2 D F B2 R\(aq L2 F\(aq U\(aq D (16) | ||
| 244 | Notice that the solution is printed twice: the first time it is printed as soon | ||
| 245 | as it is found as requested by the -v option. | ||
| 246 | .Pp | ||
| 247 | The command: | ||
| 248 | .Dl nissy solve eofb -m 4 -M 5 -N -n 6 \(dqR\(aqU\(aqFD2L2 FR2 U2R2BD2 L B2 D\(aq B2 L\(aq R\(aq\(dq | ||
| 249 | Returns: | ||
| 250 | .Dl U B U\(aq B (4) | ||
| 251 | .Dl U (B R\(aq B) (4) | ||
| 252 | .Dl (U B R\(aq B) (4) | ||
| 253 | .Dl U2 F R2 F (4) | ||
| 254 | .Dl U2 B U2 B (4) | ||
| 255 | .Dl (U2 B R\(aq B) (4) | ||
| 256 | .Pp | ||
| 257 | On a UNIX shell, the composite command | ||
| 258 | .Dl nissy scramble -n 2 | nissy solve -i > file.txt | ||
| 259 | Generates two random scrambles, solves them and saves the result to file.txt. | ||
| 260 | The file will look something like this: | ||
| 261 | .Dl >>> Line: D U2 F D B\(aq F L2 D\(aq F2 R2 L B2 L\(aq U2 B2 R F2 L\(aq D2 | ||
| 262 | .Dl U2 R2 F2 L B2 D\(aq R2 D\(aq F U L2 B\(aq U\(aq R2 D2 R2 U (17) | ||
| 263 | .Dl >>> Line: D B R U\(aq B\(aq L2 U L U D2 R L B2 U2 L2 U2 R U2 B2 L F2 | ||
| 264 | .Dl D\(aq F R\(aq D B L2 B R2 L U L U2 B D\(aq U R U F2 (18) | ||
| 265 | . | ||
| 266 | .Sh AUTHORS | ||
| 267 | .An Sebastiano Tronto Aq Mt sebastiano@tronto.net | ||
| 268 | . | ||
| 269 | .Sh SOURCE CODE | ||
| 270 | Source code is available at | ||
| 271 | .Lk https://nissy.tronto.net | ||
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 | ||
diff --git a/src/alg.c b/src/alg.c deleted file mode 100644 index d806178..0000000 --- a/src/alg.c +++ /dev/null | |||
| @@ -1,459 +0,0 @@ | |||
| 1 | #define ALG_C | ||
| 2 | |||
| 3 | #include "alg.h" | ||
| 4 | |||
| 5 | static int axis(Move m); | ||
| 6 | static void free_alglistnode(AlgListNode *aln); | ||
| 7 | static void realloc_alg(Alg *alg, int n); | ||
| 8 | |||
| 9 | void | ||
| 10 | append_alg(AlgList *l, Alg *alg) | ||
| 11 | { | ||
| 12 | AlgListNode *node = malloc(sizeof(AlgListNode)); | ||
| 13 | int i; | ||
| 14 | |||
| 15 | node->alg = new_alg(""); | ||
| 16 | for (i = 0; i < alg->len; i++) | ||
| 17 | append_move(node->alg, alg->move[i], alg->inv[i]); | ||
| 18 | node->next = NULL; | ||
| 19 | |||
| 20 | if (++l->len == 1) | ||
| 21 | l->first = node; | ||
| 22 | else | ||
| 23 | l->last->next = node; | ||
| 24 | l->last = node; | ||
| 25 | } | ||
| 26 | |||
| 27 | void | ||
| 28 | append_move(Alg *alg, Move m, bool inverse) | ||
| 29 | { | ||
| 30 | if (alg->len == alg->allocated) | ||
| 31 | realloc_alg(alg, 2*alg->len); | ||
| 32 | |||
| 33 | alg->move[alg->len] = m; | ||
| 34 | alg->inv [alg->len] = inverse; | ||
| 35 | 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 | } | ||
| 42 | |||
| 43 | static int | ||
| 44 | axis(Move m) | ||
| 45 | { | ||
| 46 | static int aux[] = { | ||
| 47 | [NULLMOVE] = 0, | ||
| 48 | |||
| 49 | [U] = 1, [U2] = 1, [U3] = 1, | ||
| 50 | [D] = 1, [D2] = 1, [D3] = 1, | ||
| 51 | [Uw] = 1, [Uw2] = 1, [Uw3] = 1, | ||
| 52 | [Dw] = 1, [Dw2] = 1, [Dw3] = 1, | ||
| 53 | [E] = 1, [E2] = 1, [E3] = 1, | ||
| 54 | [y] = 1, [y2] = 1, [y3] = 1, | ||
| 55 | |||
| 56 | [R] = 2, [R2] = 2, [R3] = 2, | ||
| 57 | [L] = 2, [L2] = 2, [L3] = 2, | ||
| 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 | |||
| 63 | [F] = 3, [F2] = 3, [F3] = 3, | ||
| 64 | [B] = 3, [B2] = 3, [B3] = 3, | ||
| 65 | [Fw] = 3, [Fw2] = 3, [Fw3] = 3, | ||
| 66 | [Bw] = 3, [Bw2] = 3, [Bw3] = 3, | ||
| 67 | [S] = 3, [S2] = 3, [S3] = 3, | ||
| 68 | [z] = 3, [z2] = 3, [z3] = 3, | ||
| 69 | }; | ||
| 70 | |||
| 71 | return aux[m]; | ||
| 72 | } | ||
| 73 | |||
| 74 | Move | ||
| 75 | base_move(Move m) | ||
| 76 | { | ||
| 77 | if (m == NULLMOVE) | ||
| 78 | return NULLMOVE; | ||
| 79 | else | ||
| 80 | return m - (m-1)%3; | ||
| 81 | } | ||
| 82 | |||
| 83 | bool | ||
| 84 | commute(Move m1, Move m2) | ||
| 85 | { | ||
| 86 | return axis(m1) == axis(m2); | ||
| 87 | } | ||
| 88 | |||
| 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 | ||
| 116 | compose_alg(Alg *alg1, Alg *alg2) | ||
| 117 | { | ||
| 118 | int i; | ||
| 119 | |||
| 120 | for (i = 0; i < alg2->len; i++) | ||
| 121 | append_move(alg1, alg2->move[i], alg2->inv[i]); | ||
| 122 | } | ||
| 123 | |||
| 124 | void | ||
| 125 | copy_alg(Alg *src, Alg *dst) | ||
| 126 | { | ||
| 127 | dst->len = dst->len_normal = dst->len_inverse = 0; | ||
| 128 | compose_alg(dst, src); | ||
| 129 | } | ||
| 130 | |||
| 131 | void | ||
| 132 | free_alg(Alg *alg) | ||
| 133 | { | ||
| 134 | free(alg->move); | ||
| 135 | free(alg->inv); | ||
| 136 | free(alg); | ||
| 137 | } | ||
| 138 | |||
| 139 | void | ||
| 140 | free_alglist(AlgList *l) | ||
| 141 | { | ||
| 142 | AlgListNode *aux, *i = l->first; | ||
| 143 | |||
| 144 | while (i != NULL) { | ||
| 145 | aux = i->next; | ||
| 146 | free_alglistnode(i); | ||
| 147 | i = aux; | ||
| 148 | } | ||
| 149 | free(l); | ||
| 150 | } | ||
| 151 | |||
| 152 | static void | ||
| 153 | free_alglistnode(AlgListNode *aln) | ||
| 154 | { | ||
| 155 | free_alg(aln->alg); | ||
| 156 | free(aln); | ||
| 157 | } | ||
| 158 | |||
| 159 | Alg * | ||
| 160 | inverse_alg(Alg *alg) | ||
| 161 | { | ||
| 162 | Alg *ret = new_alg(""); | ||
| 163 | int i; | ||
| 164 | |||
| 165 | for (i = alg->len-1; i >= 0; i--) | ||
| 166 | append_move(ret, inverse_move(alg->move[i]), alg->inv[i]); | ||
| 167 | |||
| 168 | return ret; | ||
| 169 | } | ||
| 170 | |||
| 171 | Move | ||
| 172 | inverse_move(Move m) | ||
| 173 | { | ||
| 174 | return m == NULLMOVE ? NULLMOVE : m + 2 - 2*((m-1) % 3); | ||
| 175 | } | ||
| 176 | |||
| 177 | char * | ||
| 178 | move_string(Move m) | ||
| 179 | { | ||
| 180 | static char move_string_aux[NMOVES][7] = { | ||
| 181 | [NULLMOVE] = "-", | ||
| 182 | [U] = "U", [U2] = "U2", [U3] = "U\'", | ||
| 183 | [D] = "D", [D2] = "D2", [D3] = "D\'", | ||
| 184 | [R] = "R", [R2] = "R2", [R3] = "R\'", | ||
| 185 | [L] = "L", [L2] = "L2", [L3] = "L\'", | ||
| 186 | [F] = "F", [F2] = "F2", [F3] = "F\'", | ||
| 187 | [B] = "B", [B2] = "B2", [B3] = "B\'", | ||
| 188 | [Uw] = "Uw", [Uw2] = "Uw2", [Uw3] = "Uw\'", | ||
| 189 | [Dw] = "Dw", [Dw2] = "Dw2", [Dw3] = "Dw\'", | ||
| 190 | [Rw] = "Rw", [Rw2] = "Rw2", [Rw3] = "Rw\'", | ||
| 191 | [Lw] = "Lw", [Lw2] = "Lw2", [Lw3] = "Lw\'", | ||
| 192 | [Fw] = "Fw", [Fw2] = "Fw2", [Fw3] = "Fw\'", | ||
| 193 | [Bw] = "Bw", [Bw2] = "Bw2", [Bw3] = "Bw\'", | ||
| 194 | [M] = "M", [M2] = "M2", [M3] = "M\'", | ||
| 195 | [E] = "E", [E2] = "E2", [E3] = "E\'", | ||
| 196 | [S] = "S", [S2] = "S2", [S3] = "S\'", | ||
| 197 | [x] = "x", [x2] = "x2", [x3] = "x\'", | ||
| 198 | [y] = "y", [y2] = "y2", [y3] = "y\'", | ||
| 199 | [z] = "z", [z2] = "z2", [z3] = "z\'", | ||
| 200 | }; | ||
| 201 | |||
| 202 | return move_string_aux[m]; | ||
| 203 | } | ||
| 204 | |||
| 205 | Alg * | ||
| 206 | new_alg(char *str) | ||
| 207 | { | ||
| 208 | Alg *alg; | ||
| 209 | int i; | ||
| 210 | bool niss, move_read; | ||
| 211 | Move j, m; | ||
| 212 | |||
| 213 | alg = malloc(sizeof(Alg)); | ||
| 214 | alg->allocated = 30; | ||
| 215 | alg->move = malloc(alg->allocated * sizeof(Move)); | ||
| 216 | alg->inv = malloc(alg->allocated * sizeof(bool)); | ||
| 217 | alg->move_normal = malloc(alg->allocated * sizeof(Move)); | ||
| 218 | alg->move_inverse = malloc(alg->allocated * sizeof(Move)); | ||
| 219 | alg->len = 0; | ||
| 220 | alg->len_normal = 0; | ||
| 221 | alg->len_inverse = 0; | ||
| 222 | |||
| 223 | niss = false; | ||
| 224 | for (i = 0; str[i]; i++) { | ||
| 225 | if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') | ||
| 226 | continue; | ||
| 227 | |||
| 228 | if (str[i] == '(' && niss) { | ||
| 229 | fprintf(stderr, "Error reading moves: nested ( )\n"); | ||
| 230 | alg->len = alg->len_normal = alg->len_inverse = 0; | ||
| 231 | return alg; | ||
| 232 | } | ||
| 233 | |||
| 234 | if (str[i] == ')' && !niss) { | ||
| 235 | fprintf(stderr, "Error reading moves: unmatched )\n"); | ||
| 236 | alg->len = alg->len_normal = alg->len_inverse = 0; | ||
| 237 | return alg; | ||
| 238 | } | ||
| 239 | |||
| 240 | if (str[i] == '(' || str[i] == ')') { | ||
| 241 | niss = !niss; | ||
| 242 | continue; | ||
| 243 | } | ||
| 244 | |||
| 245 | /* Single slash for comments */ | ||
| 246 | if (str[i] == '/') { | ||
| 247 | while (str[i] && str[i] != '\n') | ||
| 248 | i++; | ||
| 249 | |||
| 250 | if (!str[i]) | ||
| 251 | i--; | ||
| 252 | |||
| 253 | continue; | ||
| 254 | } | ||
| 255 | |||
| 256 | move_read = false; | ||
| 257 | for (j = U; j < NMOVES; j++) { | ||
| 258 | if (str[i] == move_string(j)[0] || | ||
| 259 | (str[i] >= 'a' && str[i] <= 'z' && | ||
| 260 | str[i] == move_string(j)[0]-('A'-'a') && j<=B)) { | ||
| 261 | m = j; | ||
| 262 | if (str[i] >= 'a' && str[i] <= 'z' && j<=B) { | ||
| 263 | m += Uw - U; | ||
| 264 | } | ||
| 265 | if (m <= B && str[i+1]=='w') { | ||
| 266 | m += Uw - U; | ||
| 267 | i++; | ||
| 268 | } | ||
| 269 | if (str[i+1]=='2') { | ||
| 270 | m += 1; | ||
| 271 | i++; | ||
| 272 | } else if (str[i+1] == '\'' || | ||
| 273 | str[i+1] == '3' || | ||
| 274 | str[i+1] == '`' ) { | ||
| 275 | m += 2; | ||
| 276 | i++; | ||
| 277 | } else if ((int)str[i+1] == -62 && | ||
| 278 | (int)str[i+2] == -76) { | ||
| 279 | /* Weird apostrophe */ | ||
| 280 | m += 2; | ||
| 281 | i += 2; | ||
| 282 | } else if ((int)str[i+1] == -30 && | ||
| 283 | (int)str[i+2] == -128 && | ||
| 284 | (int)str[i+3] == -103) { | ||
| 285 | /* MacOS apostrophe */ | ||
| 286 | m += 2; | ||
| 287 | i += 3; | ||
| 288 | } | ||
| 289 | append_move(alg, m, niss); | ||
| 290 | move_read = true; | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | if (!move_read) { | ||
| 296 | free(alg); | ||
| 297 | return new_alg(""); | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | if (niss) { | ||
| 302 | fprintf(stderr, "Error reading moves: unmatched (\n"); | ||
| 303 | alg->len = alg->len_normal = alg->len_inverse = 0; | ||
| 304 | } | ||
| 305 | |||
| 306 | return alg; | ||
| 307 | } | ||
| 308 | |||
| 309 | AlgList * | ||
| 310 | new_alglist() | ||
| 311 | { | ||
| 312 | AlgList *ret = malloc(sizeof(AlgList)); | ||
| 313 | |||
| 314 | ret->len = 0; | ||
| 315 | ret->first = NULL; | ||
| 316 | ret->last = NULL; | ||
| 317 | |||
| 318 | return ret; | ||
| 319 | } | ||
| 320 | |||
| 321 | Alg * | ||
| 322 | on_inverse(Alg *alg) | ||
| 323 | { | ||
| 324 | Alg *ret = new_alg(""); | ||
| 325 | int i; | ||
| 326 | |||
| 327 | for (i = 0; i < alg->len; i++) | ||
| 328 | append_move(ret, alg->move[i], !alg->inv[i]); | ||
| 329 | |||
| 330 | return ret; | ||
| 331 | } | ||
| 332 | |||
| 333 | void | ||
| 334 | print_alg(Alg *alg, bool l) | ||
| 335 | { | ||
| 336 | char fill[4]; | ||
| 337 | int i; | ||
| 338 | bool niss = false; | ||
| 339 | |||
| 340 | for (i = 0; i < alg->len; i++) { | ||
| 341 | if (!niss && alg->inv[i]) | ||
| 342 | strcpy(fill, i == 0 ? "(" : " ("); | ||
| 343 | if (niss && !alg->inv[i]) | ||
| 344 | strcpy(fill, ") "); | ||
| 345 | if (niss == alg->inv[i]) | ||
| 346 | strcpy(fill, i == 0 ? "" : " "); | ||
| 347 | |||
| 348 | printf("%s%s", fill, move_string(alg->move[i])); | ||
| 349 | niss = alg->inv[i]; | ||
| 350 | } | ||
| 351 | |||
| 352 | if (niss) | ||
| 353 | printf(")"); | ||
| 354 | if (l) | ||
| 355 | printf(" (%d)", alg->len); | ||
| 356 | |||
| 357 | printf("\n"); | ||
| 358 | } | ||
| 359 | |||
| 360 | void | ||
| 361 | print_alglist(AlgList *al, bool l) | ||
| 362 | { | ||
| 363 | AlgListNode *i; | ||
| 364 | |||
| 365 | for (i = al->first; i != NULL; i = i->next) | ||
| 366 | print_alg(i->alg, l); | ||
| 367 | } | ||
| 368 | |||
| 369 | static void | ||
| 370 | realloc_alg(Alg *alg, int n) | ||
| 371 | { | ||
| 372 | if (alg == NULL) { | ||
| 373 | fprintf(stderr, "Error: trying to reallocate NULL alg.\n"); | ||
| 374 | return; | ||
| 375 | } | ||
| 376 | |||
| 377 | if (n < alg->len) { | ||
| 378 | fprintf(stderr, "Error: alg too long for reallocation "); | ||
| 379 | fprintf(stderr, "(%d vs %d)\n", alg->len, n); | ||
| 380 | return; | ||
| 381 | } | ||
| 382 | |||
| 383 | if (n > 1000000) { | ||
| 384 | fprintf(stderr, "Warning: very long alg,"); | ||
| 385 | fprintf(stderr, "something might go wrong.\n"); | ||
| 386 | } | ||
| 387 | |||
| 388 | alg->move = realloc(alg->move, n * sizeof(int)); | ||
| 389 | 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; | ||
| 393 | } | ||
| 394 | |||
| 395 | 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) | ||
| 408 | { | ||
| 409 | Move aux; | ||
| 410 | |||
| 411 | aux = *m1; | ||
| 412 | *m1 = *m2; | ||
| 413 | *m2 = aux; | ||
| 414 | } | ||
| 415 | |||
| 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 * | ||
| 445 | unniss(Alg *alg) | ||
| 446 | { | ||
| 447 | int i; | ||
| 448 | Alg *ret; | ||
| 449 | |||
| 450 | ret = new_alg(""); | ||
| 451 | |||
| 452 | for (i = 0; i < alg->len_normal; i++) | ||
| 453 | append_move(ret, alg->move_normal[i], false); | ||
| 454 | |||
| 455 | for (i = 0; i < alg->len_inverse; i++) | ||
| 456 | append_move(ret, inverse_move(alg->move_inverse[i]), false); | ||
| 457 | |||
| 458 | return ret; | ||
| 459 | } | ||
diff --git a/src/alg.h b/src/alg.h deleted file mode 100644 index 967cd92..0000000 --- a/src/alg.h +++ /dev/null | |||
| @@ -1,35 +0,0 @@ | |||
| 1 | #ifndef ALG_H | ||
| 2 | #define ALG_H | ||
| 3 | |||
| 4 | #include <stdio.h> | ||
| 5 | #include <stdlib.h> | ||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | #include "cubetypes.h" | ||
| 9 | #include "utils.h" | ||
| 10 | |||
| 11 | void append_alg(AlgList *l, Alg *alg); | ||
| 12 | void append_move(Alg *alg, Move m, bool inverse); | ||
| 13 | 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); | ||
| 17 | bool commute(Move m1, Move m2); | ||
| 18 | void copy_alg(Alg *src, Alg *dst); | ||
| 19 | void free_alg(Alg *alg); | ||
| 20 | void free_alglist(AlgList *l); | ||
| 21 | Alg * inverse_alg(Alg *alg); | ||
| 22 | Move inverse_move(Move m); | ||
| 23 | char * move_string(Move m); | ||
| 24 | Alg * new_alg(char *str); | ||
| 25 | AlgList * new_alglist(); | ||
| 26 | Alg * on_inverse(Alg *alg); | ||
| 27 | void print_alg(Alg *alg, bool l); | ||
| 28 | void print_alglist(AlgList *al, bool l); | ||
| 29 | void remove_last_move(Alg *alg); | ||
| 30 | void swapmove(Move *m1, Move *m2); | ||
| 31 | char * trans_string(Trans t); /* Here because similar to move_string, move? */ | ||
| 32 | Alg * unniss(Alg *alg); | ||
| 33 | |||
| 34 | #endif | ||
| 35 | |||
diff --git a/src/commands.c b/src/commands.c deleted file mode 100644 index a9e8fc9..0000000 --- a/src/commands.c +++ /dev/null | |||
| @@ -1,569 +0,0 @@ | |||
| 1 | #define COMMANDS_C | ||
| 2 | |||
| 3 | #include "commands.h" | ||
| 4 | |||
| 5 | static bool read_cs(CommandArgs *args, char *str); | ||
| 6 | static bool read_scrtype(CommandArgs *args, char *str); | ||
| 7 | static bool read_scramble(int c, char **v, CommandArgs *args); | ||
| 8 | |||
| 9 | /* Arg parsing functions implementation **************************************/ | ||
| 10 | |||
| 11 | CommandArgs * | ||
| 12 | solve_parse_args(int c, char **v) | ||
| 13 | { | ||
| 14 | int i; | ||
| 15 | bool infinitesols, fixedmsols; | ||
| 16 | long val; | ||
| 17 | |||
| 18 | CommandArgs *a = new_args(); | ||
| 19 | |||
| 20 | a->opts->min_moves = 0; | ||
| 21 | a->opts->max_moves = 20; | ||
| 22 | a->opts->max_solutions = 1; | ||
| 23 | a->opts->nthreads = 1; | ||
| 24 | a->opts->optimal = -1; | ||
| 25 | a->opts->can_niss = false; | ||
| 26 | a->opts->verbose = false; | ||
| 27 | a->opts->all = false; | ||
| 28 | a->opts->print_number = true; | ||
| 29 | a->opts->count_only = false; | ||
| 30 | |||
| 31 | fixedmsols = false; | ||
| 32 | infinitesols = false; | ||
| 33 | |||
| 34 | for (i = 0; i < c; i++) { | ||
| 35 | if (!strcmp(v[i], "-m") && i+1 < c) { | ||
| 36 | val = strtol(v[++i], NULL, 10); | ||
| 37 | if (val < 0 || val > 100) { | ||
| 38 | fprintf(stderr, | ||
| 39 | "Invalid min number of moves" | ||
| 40 | "(0 <= N <= 100).\n"); | ||
| 41 | return a; | ||
| 42 | } | ||
| 43 | a->opts->min_moves = val; | ||
| 44 | } else if (!strcmp(v[i], "-M") && i+1 < c) { | ||
| 45 | val = strtol(v[++i], NULL, 10); | ||
| 46 | if (val < 0 || val > 100) { | ||
| 47 | fprintf(stderr, | ||
| 48 | "Invalid max number of moves" | ||
| 49 | "(0 <= N <= 100).\n"); | ||
| 50 | return a; | ||
| 51 | } | ||
| 52 | a->opts->max_moves = val; | ||
| 53 | infinitesols = true; | ||
| 54 | } else if (!strcmp(v[i], "-t") && i+1 < c) { | ||
| 55 | val = strtol(v[++i], NULL, 10); | ||
| 56 | if (val < 1 || val > 64) { | ||
| 57 | fprintf(stderr, | ||
| 58 | "Invalid number of threads." | ||
| 59 | "1 <= t <= 64\n"); | ||
| 60 | return a; | ||
| 61 | } | ||
| 62 | a->opts->nthreads = val; | ||
| 63 | } else if (!strcmp(v[i], "-n") && i+1 < c) { | ||
| 64 | val = strtol(v[++i], NULL, 10); | ||
| 65 | if (val < 1 || val > 1000000) { | ||
| 66 | fprintf(stderr, | ||
| 67 | "Invalid number of solutions.\n"); | ||
| 68 | return a; | ||
| 69 | } | ||
| 70 | a->opts->max_solutions = val; | ||
| 71 | fixedmsols = true; | ||
| 72 | } else if (!strcmp(v[i], "-o")) { | ||
| 73 | a->opts->optimal = 0; | ||
| 74 | infinitesols = true; | ||
| 75 | } else if (!strcmp(v[i], "-O") && i+1 < c) { | ||
| 76 | val = strtol(v[++i], NULL, 10); | ||
| 77 | if (val < 0 || val > 100 || | ||
| 78 | (val == 0 && strcmp("0", v[i]))) { | ||
| 79 | fprintf(stderr, | ||
| 80 | "Invalid max number of moves" | ||
| 81 | " (0 <= N <= 100).\n"); | ||
| 82 | return a; | ||
| 83 | } | ||
| 84 | a->opts->optimal = val; | ||
| 85 | infinitesols = true; | ||
| 86 | } else if (!strcmp(v[i], "-N")) { | ||
| 87 | a->opts->can_niss = true; | ||
| 88 | } else if (!strcmp(v[i], "-i")) { | ||
| 89 | a->scrstdin = true; | ||
| 90 | } else if (!strcmp(v[i], "-v")) { | ||
| 91 | a->opts->verbose = true; | ||
| 92 | } else if (!strcmp(v[i], "-a")) { | ||
| 93 | a->opts->all = true; | ||
| 94 | } else if (!strcmp(v[i], "-p")) { | ||
| 95 | a->opts->print_number = false; | ||
| 96 | } else if (!strcmp(v[i], "-c")) { | ||
| 97 | a->opts->count_only = true; | ||
| 98 | } else if (!read_cs(a, v[i])) { | ||
| 99 | break; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | if (infinitesols && !fixedmsols) | ||
| 104 | a->opts->max_solutions = 1000000; /* 1M = +infty */ | ||
| 105 | |||
| 106 | a->success = (a->scrstdin && i == c) || read_scramble(c-i, &v[i], a); | ||
| 107 | return a; | ||
| 108 | } | ||
| 109 | |||
| 110 | CommandArgs * | ||
| 111 | scramble_parse_args(int c, char **v) | ||
| 112 | { | ||
| 113 | int i; | ||
| 114 | long val; | ||
| 115 | |||
| 116 | CommandArgs *a = new_args(); | ||
| 117 | |||
| 118 | a->success = true; | ||
| 119 | a->n = 1; | ||
| 120 | |||
| 121 | for (i = 0; i < c; i++) { | ||
| 122 | if (!strcmp(v[i], "-n") && i+1 < c) { | ||
| 123 | val = strtol(v[++i], NULL, 10); | ||
| 124 | if (val < 1 || val > 1000000) { | ||
| 125 | fprintf(stderr, | ||
| 126 | "Invalid number of scrambles.\n"); | ||
| 127 | a->success = false; | ||
| 128 | return a; | ||
| 129 | } | ||
| 130 | a->n = val; | ||
| 131 | } else if (!read_scrtype(a, v[i])) { | ||
| 132 | a->success = false; | ||
| 133 | return a; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | return a; | ||
| 138 | } | ||
| 139 | |||
| 140 | CommandArgs * | ||
| 141 | gen_parse_args(int c, char **v) | ||
| 142 | { | ||
| 143 | int val; | ||
| 144 | CommandArgs *a = new_args(); | ||
| 145 | |||
| 146 | a->opts->nthreads = 64; | ||
| 147 | a->success = false; | ||
| 148 | |||
| 149 | if (c == 0) { | ||
| 150 | a->success = true; | ||
| 151 | } else { | ||
| 152 | if (!strcmp(v[0], "-t") && c > 1) { | ||
| 153 | val = strtol(v[1], NULL, 10); | ||
| 154 | if (val < 1 || val > 64) { | ||
| 155 | fprintf(stderr, | ||
| 156 | "Invalid number of threads." | ||
| 157 | "1 <= t <= 64\n"); | ||
| 158 | return a; | ||
| 159 | } | ||
| 160 | a->opts->nthreads = val; | ||
| 161 | a->success = true; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | return a; | ||
| 166 | } | ||
| 167 | |||
| 168 | CommandArgs * | ||
| 169 | help_parse_args(int c, char **v) | ||
| 170 | { | ||
| 171 | int i; | ||
| 172 | CommandArgs *a = new_args(); | ||
| 173 | |||
| 174 | if (c == 1) { | ||
| 175 | for (i = 0; commands[i] != NULL; i++) | ||
| 176 | if (!strcmp(v[0], commands[i]->name)) | ||
| 177 | a->command = commands[i]; | ||
| 178 | if (a->command == NULL) | ||
| 179 | fprintf(stderr, "%s: command not found\n", v[0]); | ||
| 180 | } | ||
| 181 | |||
| 182 | a->success = c == 0 || (c == 1 && a->command != NULL); | ||
| 183 | return a; | ||
| 184 | } | ||
| 185 | |||
| 186 | CommandArgs * | ||
| 187 | parse_only_scramble(int c, char **v) | ||
| 188 | { | ||
| 189 | CommandArgs *a = new_args(); | ||
| 190 | |||
| 191 | if (!strcmp(v[0], "-i")) { | ||
| 192 | a->scrstdin = true; | ||
| 193 | a->success = c == 1; | ||
| 194 | } else { | ||
| 195 | a->success = read_scramble(c, v, a); | ||
| 196 | } | ||
| 197 | |||
| 198 | return a; | ||
| 199 | } | ||
| 200 | |||
| 201 | CommandArgs * | ||
| 202 | parse_no_arg(int c, char **v) | ||
| 203 | { | ||
| 204 | CommandArgs *a = new_args(); | ||
| 205 | |||
| 206 | a->success = true; | ||
| 207 | |||
| 208 | return a; | ||
| 209 | } | ||
| 210 | |||
| 211 | /* Exec functions implementation *********************************************/ | ||
| 212 | |||
| 213 | void | ||
| 214 | solve_exec(CommandArgs *args) | ||
| 215 | { | ||
| 216 | Cube c; | ||
| 217 | AlgList *sols; | ||
| 218 | Solver *solver[99]; | ||
| 219 | Threader *threader; | ||
| 220 | |||
| 221 | make_solved(&c); | ||
| 222 | apply_alg(args->scramble, &c); | ||
| 223 | /* TODO: adjust */ | ||
| 224 | /* threader = &threader_single;*/ | ||
| 225 | threader = &threader_eager; | ||
| 226 | |||
| 227 | /* TODO: adjust */ | ||
| 228 | int i; | ||
| 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 | |||
| 234 | if (args->opts->count_only) | ||
| 235 | printf("%d\n", sols->len); | ||
| 236 | else | ||
| 237 | print_alglist(sols, args->opts->print_number); | ||
| 238 | |||
| 239 | free_alglist(sols); | ||
| 240 | } | ||
| 241 | |||
| 242 | void | ||
| 243 | scramble_exec(CommandArgs *args) | ||
| 244 | { | ||
| 245 | Cube cube; | ||
| 246 | Alg *scr, *ruf, *aux; | ||
| 247 | int i, j, eo, ep, co, cp; | ||
| 248 | uint64_t ui, uj, uk; | ||
| 249 | |||
| 250 | srand(time(NULL)); | ||
| 251 | |||
| 252 | for (i = 0; i < args->n; i++) { | ||
| 253 | |||
| 254 | if (!strcmp(args->scrtype, "dr")) { | ||
| 255 | ui = rand() % FACTORIAL8; | ||
| 256 | uj = rand() % FACTORIAL8; | ||
| 257 | uk = rand() % FACTORIAL4; | ||
| 258 | |||
| 259 | make_solved(&cube); | ||
| 260 | index_to_perm(ui, 8, cube.cp); | ||
| 261 | index_to_perm(uj, 8, cube.ep); | ||
| 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")) { | ||
| 266 | make_solved(&cube); | ||
| 267 | /* TODO */ | ||
| 268 | } else { | ||
| 269 | ep = rand() % FACTORIAL12; | ||
| 270 | cp = rand() % FACTORIAL8; | ||
| 271 | eo = rand() % POW2TO11; | ||
| 272 | co = rand() % POW3TO7; | ||
| 273 | |||
| 274 | if (!strcmp(args->scrtype, "eo")) { | ||
| 275 | eo = 0; | ||
| 276 | } else if (!strcmp(args->scrtype, "corners")) { | ||
| 277 | eo = 0; | ||
| 278 | ep = 0; | ||
| 279 | } else if (!strcmp(args->scrtype, "edges")) { | ||
| 280 | co = 0; | ||
| 281 | cp = 0; | ||
| 282 | } | ||
| 283 | |||
| 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 | } | ||
| 297 | |||
| 298 | /* TODO: can be optimized for htr and dr using htrfin, drfin */ | ||
| 299 | /* | ||
| 300 | TODO: solve_2phase was removed | ||
| 301 | scr = solve_2phase(&cube, 1); | ||
| 302 | */ | ||
| 303 | |||
| 304 | if (!strcmp(args->scrtype, "fmc")) { | ||
| 305 | aux = new_alg(""); | ||
| 306 | copy_alg(scr, aux); | ||
| 307 | /* Trick to rufify for free: rotate the scramble * | ||
| 308 | * so that it does not start with F or end with R */ | ||
| 309 | for (j = 0; j < NROTATIONS; j++) { | ||
| 310 | if (base_move(scr->move[0]) != F && | ||
| 311 | base_move(scr->move[0]) != B && | ||
| 312 | base_move(scr->move[scr->len-1]) != R && | ||
| 313 | base_move(scr->move[scr->len-1]) != L) | ||
| 314 | break; | ||
| 315 | copy_alg(aux, scr); | ||
| 316 | transform_alg(j, scr); | ||
| 317 | } | ||
| 318 | copy_alg(scr, aux); | ||
| 319 | ruf = new_alg("R' U' F"); | ||
| 320 | copy_alg(ruf, scr); | ||
| 321 | compose_alg(scr, aux); | ||
| 322 | compose_alg(scr, ruf); | ||
| 323 | free_alg(aux); | ||
| 324 | free_alg(ruf); | ||
| 325 | } | ||
| 326 | print_alg(scr, false); | ||
| 327 | free_alg(scr); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | void | ||
| 332 | gen_exec(CommandArgs *args) | ||
| 333 | { | ||
| 334 | /* TODO: | ||
| 335 | int i; | ||
| 336 | |||
| 337 | fprintf(stderr, "Generating coordinates...\n"); | ||
| 338 | fprintf(stderr, "Generating pruning tables...\n"); | ||
| 339 | for (i = 0; all_pd[i] != NULL; i++) | ||
| 340 | genptable(all_pd[i], args->opts->nthreads); | ||
| 341 | */ | ||
| 342 | |||
| 343 | fprintf(stderr, "Done!\n"); | ||
| 344 | } | ||
| 345 | |||
| 346 | void | ||
| 347 | invert_exec(CommandArgs *args) | ||
| 348 | { | ||
| 349 | Alg *inv; | ||
| 350 | |||
| 351 | inv = inverse_alg(args->scramble); | ||
| 352 | print_alg(inv, false); | ||
| 353 | |||
| 354 | free_alg(inv); | ||
| 355 | } | ||
| 356 | |||
| 357 | void | ||
| 358 | steps_exec(CommandArgs *args) | ||
| 359 | { | ||
| 360 | int i; | ||
| 361 | |||
| 362 | for (i = 0; csteps[i] != NULL; i++) | ||
| 363 | printf("%-15s %s\n", csteps[i]->shortname, csteps[i]->name); | ||
| 364 | } | ||
| 365 | |||
| 366 | void | ||
| 367 | commands_exec(CommandArgs *args) | ||
| 368 | { | ||
| 369 | int i; | ||
| 370 | |||
| 371 | for (i = 0; commands[i] != NULL; i++) | ||
| 372 | printf("%s\n", commands[i]->usage); | ||
| 373 | |||
| 374 | } | ||
| 375 | |||
| 376 | void | ||
| 377 | freemem_exec(CommandArgs *args) | ||
| 378 | { | ||
| 379 | /* TODO: | ||
| 380 | int i; | ||
| 381 | |||
| 382 | for (i = 0; all_pd[i] != NULL; i++) | ||
| 383 | free_pd(all_pd[i]); | ||
| 384 | |||
| 385 | for (i = 0; all_sd[i] != NULL; i++) | ||
| 386 | free_sd(all_sd[i]); | ||
| 387 | */ | ||
| 388 | } | ||
| 389 | |||
| 390 | void | ||
| 391 | print_exec(CommandArgs *args) | ||
| 392 | { | ||
| 393 | Cube c; | ||
| 394 | |||
| 395 | make_solved(&c); | ||
| 396 | apply_alg(args->scramble, &c); | ||
| 397 | print_cube(&c); | ||
| 398 | } | ||
| 399 | |||
| 400 | /* | ||
| 401 | void | ||
| 402 | twophase_exec(CommandArgs *args) | ||
| 403 | { | ||
| 404 | Cube c; | ||
| 405 | Alg *sol; | ||
| 406 | |||
| 407 | make_solved(&c); | ||
| 408 | apply_alg(args->scramble, &c); | ||
| 409 | sol = solve_2phase(&c, 1); | ||
| 410 | |||
| 411 | print_alg(sol, false); | ||
| 412 | free_alg(sol); | ||
| 413 | } | ||
| 414 | */ | ||
| 415 | |||
| 416 | void | ||
| 417 | help_exec(CommandArgs *args) | ||
| 418 | { | ||
| 419 | if (args->command == NULL) { | ||
| 420 | printf( | ||
| 421 | "Use the nissy command \"help COMMAND\" for a short " | ||
| 422 | "description of a specific command.\n" | ||
| 423 | "Use the nissy command \"commands\" for a list of " | ||
| 424 | "available commands.\n" | ||
| 425 | "See the manual page for more details. The manual" | ||
| 426 | " page is available with \"man nissy\" on a UNIX" | ||
| 427 | " system (such as Linux or MacOS) or in pdf and html" | ||
| 428 | " format in the docs folder.\n" | ||
| 429 | "Nissy is available for free at " | ||
| 430 | "https://nissy.tronto.net\n" | ||
| 431 | ); | ||
| 432 | } else { | ||
| 433 | printf("Command %s: %s\nusage: %s\n", args->command->name, | ||
| 434 | args->command->description, args->command->usage); | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | void | ||
| 439 | quit_exec(CommandArgs *args) | ||
| 440 | { | ||
| 441 | exit(0); | ||
| 442 | } | ||
| 443 | |||
| 444 | void | ||
| 445 | cleanup_exec(CommandArgs *args) | ||
| 446 | { | ||
| 447 | Alg *alg; | ||
| 448 | |||
| 449 | alg = cleanup(args->scramble); | ||
| 450 | print_alg(alg, false); | ||
| 451 | |||
| 452 | free_alg(alg); | ||
| 453 | } | ||
| 454 | |||
| 455 | void | ||
| 456 | unniss_exec(CommandArgs *args) | ||
| 457 | { | ||
| 458 | Alg *aux; | ||
| 459 | |||
| 460 | aux = unniss(args->scramble); | ||
| 461 | print_alg(aux, false); | ||
| 462 | free(aux); | ||
| 463 | } | ||
| 464 | |||
| 465 | void | ||
| 466 | version_exec(CommandArgs *args) | ||
| 467 | { | ||
| 468 | printf(VERSION"\n"); | ||
| 469 | } | ||
| 470 | |||
| 471 | /* Local functions implementation ********************************************/ | ||
| 472 | |||
| 473 | static bool | ||
| 474 | read_scramble(int c, char **v, CommandArgs *args) | ||
| 475 | { | ||
| 476 | int i, k, n; | ||
| 477 | unsigned int j; | ||
| 478 | char *algstr; | ||
| 479 | |||
| 480 | if (c < 1) { | ||
| 481 | fprintf(stderr, "Error: no scramble given?\n"); | ||
| 482 | return false; | ||
| 483 | } | ||
| 484 | |||
| 485 | for(n = 0, i = 0; i < c; i++) | ||
| 486 | n += strlen(v[i]); | ||
| 487 | |||
| 488 | algstr = malloc((n + 1) * sizeof(char)); | ||
| 489 | k = 0; | ||
| 490 | for (i = 0; i < c; i++) | ||
| 491 | for (j = 0; j < strlen(v[i]); j++) | ||
| 492 | algstr[k++] = v[i][j]; | ||
| 493 | algstr[k] = 0; | ||
| 494 | |||
| 495 | args->scramble = new_alg(algstr); | ||
| 496 | free(algstr); | ||
| 497 | |||
| 498 | if (args->scramble->len == 0) | ||
| 499 | fprintf(stderr, "Error reading scramble\n"); | ||
| 500 | |||
| 501 | return args->scramble->len > 0; | ||
| 502 | } | ||
| 503 | |||
| 504 | static bool | ||
| 505 | read_scrtype(CommandArgs *args, char *str) | ||
| 506 | { | ||
| 507 | int i; | ||
| 508 | static char *scrtypes[20] = | ||
| 509 | { "eo", "corners", "edges", "fmc", "dr", "htr", NULL }; | ||
| 510 | |||
| 511 | for (i = 0; scrtypes[i] != NULL; i++) { | ||
| 512 | if (!strcmp(scrtypes[i], str)) { | ||
| 513 | strcpy(args->scrtype, scrtypes[i]); | ||
| 514 | return true; | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 518 | return false; | ||
| 519 | } | ||
| 520 | |||
| 521 | static bool | ||
| 522 | read_cs(CommandArgs *args, char *str) | ||
| 523 | { | ||
| 524 | int i; | ||
| 525 | |||
| 526 | for (i = 0; csteps[i] != NULL; i++) { | ||
| 527 | if (!strcmp(csteps[i]->shortname, str)) { | ||
| 528 | args->cs = csteps[i]; | ||
| 529 | return true; | ||
| 530 | } | ||
| 531 | } | ||
| 532 | |||
| 533 | return false; | ||
| 534 | } | ||
| 535 | |||
| 536 | /* Public functions implementation *******************************************/ | ||
| 537 | |||
| 538 | void | ||
| 539 | free_args(CommandArgs *args) | ||
| 540 | { | ||
| 541 | if (args == NULL) | ||
| 542 | return; | ||
| 543 | |||
| 544 | if (args->scramble != NULL) | ||
| 545 | free_alg(args->scramble); | ||
| 546 | if (args->opts != NULL) | ||
| 547 | free(args->opts); | ||
| 548 | |||
| 549 | /* step and command must not be freed, they are static! */ | ||
| 550 | |||
| 551 | free(args); | ||
| 552 | } | ||
| 553 | |||
| 554 | CommandArgs * | ||
| 555 | new_args() | ||
| 556 | { | ||
| 557 | CommandArgs *args = malloc(sizeof(CommandArgs)); | ||
| 558 | |||
| 559 | args->success = false; | ||
| 560 | args->scrstdin = false; | ||
| 561 | args->scramble = NULL; /* initialized in read_scramble */ | ||
| 562 | args->opts = malloc(sizeof(SolveOptions)); | ||
| 563 | |||
| 564 | /* step and command are static */ | ||
| 565 | args->cs = csteps[0]; /* default: first step in list */ | ||
| 566 | args->command = NULL; | ||
| 567 | |||
| 568 | return args; | ||
| 569 | } | ||
diff --git a/src/commands.h b/src/commands.h deleted file mode 100644 index 65708e0..0000000 --- a/src/commands.h +++ /dev/null | |||
| @@ -1,211 +0,0 @@ | |||
| 1 | #ifndef COMMANDS_H | ||
| 2 | #define COMMANDS_H | ||
| 3 | |||
| 4 | #include <time.h> | ||
| 5 | |||
| 6 | #include "solve.h" | ||
| 7 | #include "steps.h" | ||
| 8 | #include "solver_step.h" | ||
| 9 | #include "threader_single.h" | ||
| 10 | #include "threader_eager.h" | ||
| 11 | |||
| 12 | void free_args(CommandArgs *args); | ||
| 13 | CommandArgs * new_args(); | ||
| 14 | |||
| 15 | /* Arg parsing functions *****************************************************/ | ||
| 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 | |||
| 211 | #endif | ||
diff --git a/src/coord.c b/src/coord.c deleted file mode 100644 index 673434f..0000000 --- a/src/coord.c +++ /dev/null | |||
| @@ -1,654 +0,0 @@ | |||
| 1 | #define COORD_C | ||
| 2 | |||
| 3 | #include "coord.h" | ||
| 4 | |||
| 5 | static void gen_coord_comp(Coordinate *coord); | ||
| 6 | static void gen_coord_sym(Coordinate *coord); | ||
| 7 | static bool read_coord_mtable(Coordinate *coord); | ||
| 8 | static bool read_coord_sd(Coordinate *coord); | ||
| 9 | static bool read_coord_ttable(Coordinate *coord); | ||
| 10 | static bool write_coord_mtable(Coordinate *coord); | ||
| 11 | static bool write_coord_sd(Coordinate *coord); | ||
| 12 | static bool write_coord_ttable(Coordinate *coord); | ||
| 13 | |||
| 14 | /* Indexers ******************************************************************/ | ||
| 15 | |||
| 16 | uint64_t | ||
| 17 | index_eofb(Cube *cube) | ||
| 18 | { | ||
| 19 | return (uint64_t)digit_array_to_int(cube->eo, 11, 2); | ||
| 20 | } | ||
| 21 | |||
| 22 | uint64_t | ||
| 23 | index_coud(Cube *cube) | ||
| 24 | { | ||
| 25 | return (uint64_t)digit_array_to_int(cube->co, 7, 3); | ||
| 26 | } | ||
| 27 | |||
| 28 | uint64_t | ||
| 29 | index_cp(Cube *cube) | ||
| 30 | { | ||
| 31 | return (uint64_t)perm_to_index(cube->cp, 8); | ||
| 32 | } | ||
| 33 | |||
| 34 | uint64_t | ||
| 35 | index_cpudsep(Cube *cube) | ||
| 36 | { | ||
| 37 | int i, c[8]; | ||
| 38 | |||
| 39 | for (i = 0; i < 8; i++) | ||
| 40 | c[i] = cube->cp[i] < 4 ? 0 : 1; | ||
| 41 | |||
| 42 | return (uint64_t)subset_to_index(c, 8, 4); | ||
| 43 | } | ||
| 44 | |||
| 45 | uint64_t | ||
| 46 | index_epe(Cube *cube) | ||
| 47 | { | ||
| 48 | int i, e[4]; | ||
| 49 | |||
| 50 | for (i = 0; i < 4; i++) | ||
| 51 | e[i] = cube->ep[i+8] - 8; | ||
| 52 | |||
| 53 | return (uint64_t)perm_to_index(e, 4); | ||
| 54 | } | ||
| 55 | |||
| 56 | uint64_t | ||
| 57 | index_epud(Cube *cube) | ||
| 58 | { | ||
| 59 | return (uint64_t)perm_to_index(cube->ep, 8); | ||
| 60 | } | ||
| 61 | |||
| 62 | uint64_t | ||
| 63 | index_epos(Cube *cube) | ||
| 64 | { | ||
| 65 | int i, a[12]; | ||
| 66 | |||
| 67 | for (i = 0; i < 12; i++) | ||
| 68 | a[i] = (cube->ep[i] < 8) ? 0 : 1; | ||
| 69 | |||
| 70 | return (uint64_t)subset_to_index(a, 12, 4); | ||
| 71 | } | ||
| 72 | |||
| 73 | uint64_t | ||
| 74 | index_eposepe(Cube *cube) | ||
| 75 | { | ||
| 76 | int i, j, e[4]; | ||
| 77 | uint64_t epos, epe; | ||
| 78 | |||
| 79 | epos = (uint64_t)index_epos(cube); | ||
| 80 | for (i = 0, j = 0; i < 12; i++) | ||
| 81 | if (cube->ep[i] >= 8) | ||
| 82 | e[j++] = cube->ep[i] - 8; | ||
| 83 | epe = (uint64_t)perm_to_index(e, 4); | ||
| 84 | |||
| 85 | return epos * FACTORIAL4 + epe; | ||
| 86 | } | ||
| 87 | |||
| 88 | /* Inverse indexers **********************************************************/ | ||
| 89 | |||
| 90 | void | ||
| 91 | invindex_eofb(uint64_t ind, Cube *cube) | ||
| 92 | { | ||
| 93 | int_to_sum_zero_array(ind, 2, 12, cube->eo); | ||
| 94 | } | ||
| 95 | |||
| 96 | void | ||
| 97 | invindex_coud(uint64_t ind, Cube *cube) | ||
| 98 | { | ||
| 99 | int_to_sum_zero_array(ind, 3, 8, cube->co); | ||
| 100 | } | ||
| 101 | |||
| 102 | void | ||
| 103 | invindex_cp(uint64_t ind, Cube *cube) | ||
| 104 | { | ||
| 105 | index_to_perm(ind, 8, cube->cp); | ||
| 106 | } | ||
| 107 | |||
| 108 | void | ||
| 109 | invindex_cpudsep(uint64_t ind, Cube *cube) | ||
| 110 | { | ||
| 111 | int i, j, k, c[8]; | ||
| 112 | |||
| 113 | index_to_subset(ind, 8, 4, c); | ||
| 114 | for (i = 0, j = 0, k = 4; i < 8; i++) | ||
| 115 | cube->cp[i] = c[i] == 0 ? j++ : k++; | ||
| 116 | } | ||
| 117 | |||
| 118 | |||
| 119 | void | ||
| 120 | invindex_epe(uint64_t ind, Cube *cube) | ||
| 121 | { | ||
| 122 | int i; | ||
| 123 | |||
| 124 | index_to_perm(ind, 4, &cube->ep[8]); | ||
| 125 | for (i = 0; i < 4; i++) | ||
| 126 | cube->ep[i+8] += 8; | ||
| 127 | } | ||
| 128 | |||
| 129 | void | ||
| 130 | invindex_epud(uint64_t ind, Cube *cube) | ||
| 131 | { | ||
| 132 | index_to_perm(ind, 8, cube->ep); | ||
| 133 | } | ||
| 134 | |||
| 135 | void | ||
| 136 | invindex_epos(uint64_t ind, Cube *cube) | ||
| 137 | { | ||
| 138 | int i, j, k; | ||
| 139 | |||
| 140 | index_to_subset(ind, 12, 4, cube->ep); | ||
| 141 | for (i = 0, j = 0, k = 8; i < 12; i++) | ||
| 142 | if (cube->ep[i] == 0) | ||
| 143 | cube->ep[i] = j++; | ||
| 144 | else | ||
| 145 | cube->ep[i] = k++; | ||
| 146 | } | ||
| 147 | |||
| 148 | void | ||
| 149 | invindex_eposepe(uint64_t ind, Cube *cube) | ||
| 150 | { | ||
| 151 | int i, j, k, e[4]; | ||
| 152 | uint64_t epos, epe; | ||
| 153 | |||
| 154 | epos = ind / FACTORIAL4; | ||
| 155 | epe = ind % FACTORIAL4; | ||
| 156 | |||
| 157 | index_to_subset(epos, 12, 4, cube->ep); | ||
| 158 | index_to_perm(epe, 4, e); | ||
| 159 | |||
| 160 | for (i = 0, j = 0, k = 0; i < 12; i++) | ||
| 161 | if (cube->ep[i] == 0) | ||
| 162 | cube->ep[i] = j++; | ||
| 163 | else | ||
| 164 | cube->ep[i] = e[k++] + 8; | ||
| 165 | } | ||
| 166 | |||
| 167 | /* Other local functions *****************************************************/ | ||
| 168 | |||
| 169 | uint64_t | ||
| 170 | indexers_getmax(Indexer **is) | ||
| 171 | { | ||
| 172 | int i; | ||
| 173 | uint64_t max = 1; | ||
| 174 | |||
| 175 | for (i = 0; is[i] != NULL; i++) | ||
| 176 | max *= is[i]->n; | ||
| 177 | |||
| 178 | return max; | ||
| 179 | } | ||
| 180 | |||
| 181 | uint64_t | ||
| 182 | indexers_getind(Indexer **is, Cube *c) | ||
| 183 | { | ||
| 184 | int i; | ||
| 185 | uint64_t max = 0; | ||
| 186 | |||
| 187 | for (i = 0; is[i] != NULL; i++) { | ||
| 188 | max *= is[i]->n; | ||
| 189 | max += is[i]->index(c); | ||
| 190 | } | ||
| 191 | |||
| 192 | return max; | ||
| 193 | } | ||
| 194 | |||
| 195 | void | ||
| 196 | indexers_makecube(Indexer **is, uint64_t ind, Cube *c) | ||
| 197 | { | ||
| 198 | /* Warning: anti-indexers are applied in the same order as indexers. */ | ||
| 199 | /* We assume order does not matter, but it would make more sense to */ | ||
| 200 | /* apply them in reverse. */ | ||
| 201 | |||
| 202 | int i; | ||
| 203 | uint64_t m; | ||
| 204 | |||
| 205 | make_solved(c); | ||
| 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 | } | ||
| 213 | |||
| 214 | static void | ||
| 215 | gen_coord_comp(Coordinate *coord) | ||
| 216 | { | ||
| 217 | uint64_t ui; | ||
| 218 | Cube c, mvd; | ||
| 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 | |||
| 227 | for (t = 0; t < NTRANS; t++) | ||
| 228 | coord->ttable[t] = malloc(coord->max * sizeof(uint64_t)); | ||
| 229 | |||
| 230 | if (!read_coord_mtable(coord)) { | ||
| 231 | fprintf(stderr, "%s: generating mtable\n", coord->name); | ||
| 232 | |||
| 233 | for (ui = 0; ui < coord->max; ui++) { | ||
| 234 | indexers_makecube(coord->i, ui, &c); | ||
| 235 | for (m = 0; m < NMOVES; m++) { | ||
| 236 | copy_cube(&c, &mvd); | ||
| 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 | |||
| 249 | if (!read_coord_ttable(coord)) { | ||
| 250 | fprintf(stderr, "%s: generating ttable\n", coord->name); | ||
| 251 | |||
| 252 | for (ui = 0; ui < coord->max; ui++) { | ||
| 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 | } | ||
| 266 | |||
| 267 | static void | ||
| 268 | gen_coord_sym(Coordinate *coord) | ||
| 269 | { | ||
| 270 | uint64_t i, in, ui, uj, uu, M, nr; | ||
| 271 | int j; | ||
| 272 | Move m; | ||
| 273 | Trans t; | ||
| 274 | |||
| 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 | |||
| 287 | for (i = 0, nr = 0; i < M; i++) { | ||
| 288 | if (coord->symclass[i] != M+1) | ||
| 289 | continue; | ||
| 290 | |||
| 291 | coord->symrep[nr] = i; | ||
| 292 | coord->transtorep[i] = uf; | ||
| 293 | coord->selfsim[nr] = (uint64_t)0; | ||
| 294 | for (j = 0; j < coord->tgrp->n; j++) { | ||
| 295 | t = coord->tgrp->t[j]; | ||
| 296 | in = trans_coord(coord->base[0], t, i); | ||
| 297 | coord->symclass[in] = nr; | ||
| 298 | if (in == i) | ||
| 299 | coord->selfsim[nr] |= ((uint64_t)1<<t); | ||
| 300 | else | ||
| 301 | coord->transtorep[in] = | ||
| 302 | inverse_trans(t); | ||
| 303 | } | ||
| 304 | nr++; | ||
| 305 | } | ||
| 306 | |||
| 307 | coord->max = nr; | ||
| 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 | } | ||
| 323 | |||
| 324 | if (!read_coord_mtable(coord)) { | ||
| 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 | } | ||
| 339 | |||
| 340 | static bool | ||
| 341 | read_coord_mtable(Coordinate *coord) | ||
| 342 | { | ||
| 343 | FILE *f; | ||
| 344 | char fname[strlen(tabledir)+256]; | ||
| 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 | |||
| 356 | M = coord->max; | ||
| 357 | r = true; | ||
| 358 | for (m = 0; m < NMOVES; m++) | ||
| 359 | r = r && fread(coord->mtable[m], sizeof(uint64_t), M, f) == M; | ||
| 360 | |||
| 361 | if (coord->type == SYM_COORD) | ||
| 362 | for (m = 0; m < NMOVES; m++) | ||
| 363 | r = r && fread(coord->ttrep_move[m], | ||
| 364 | sizeof(Trans), M, f) == M; | ||
| 365 | |||
| 366 | fclose(f); | ||
| 367 | return r; | ||
| 368 | } | ||
| 369 | |||
| 370 | static bool | ||
| 371 | read_coord_sd(Coordinate *coord) | ||
| 372 | { | ||
| 373 | FILE *f; | ||
| 374 | char fname[strlen(tabledir)+256]; | ||
| 375 | uint64_t M, N; | ||
| 376 | bool r; | ||
| 377 | |||
| 378 | strcpy(fname, tabledir); | ||
| 379 | strcat(fname, "/sd_"); | ||
| 380 | strcat(fname, coord->name); | ||
| 381 | |||
| 382 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 383 | return false; | ||
| 384 | |||
| 385 | r = true; | ||
| 386 | r = r && fread(&coord->max, sizeof(uint64_t), 1, f) == 1; | ||
| 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 | |||
| 394 | fclose(f); | ||
| 395 | return r; | ||
| 396 | } | ||
| 397 | |||
| 398 | static bool | ||
| 399 | read_coord_ttable(Coordinate *coord) | ||
| 400 | { | ||
| 401 | FILE *f; | ||
| 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 | |||
| 414 | M = coord->max; | ||
| 415 | r = true; | ||
| 416 | for (t = 0; t < NTRANS; t++) | ||
| 417 | r = r && fread(coord->ttable[t], sizeof(uint64_t), M, f) == M; | ||
| 418 | |||
| 419 | fclose(f); | ||
| 420 | return r; | ||
| 421 | } | ||
| 422 | |||
| 423 | static bool | ||
| 424 | write_coord_mtable(Coordinate *coord) | ||
| 425 | { | ||
| 426 | FILE *f; | ||
| 427 | char fname[strlen(tabledir)+256]; | ||
| 428 | Move m; | ||
| 429 | uint64_t M; | ||
| 430 | bool r; | ||
| 431 | |||
| 432 | strcpy(fname, tabledir); | ||
| 433 | strcat(fname, "/mt_"); | ||
| 434 | strcat(fname, coord->name); | ||
| 435 | |||
| 436 | if ((f = fopen(fname, "wb")) == NULL) | ||
| 437 | return false; | ||
| 438 | |||
| 439 | M = coord->max; | ||
| 440 | r = true; | ||
| 441 | for (m = 0; m < NMOVES; m++) | ||
| 442 | r = r && fwrite(coord->mtable[m], sizeof(uint64_t), M, f) == M; | ||
| 443 | |||
| 444 | if (coord->type == SYM_COORD) | ||
| 445 | for (m = 0; m < NMOVES; m++) | ||
| 446 | r = r && fwrite(coord->ttrep_move[m], | ||
| 447 | sizeof(Trans), M, f) == M; | ||
| 448 | |||
| 449 | fclose(f); | ||
| 450 | return r; | ||
| 451 | } | ||
| 452 | |||
| 453 | static bool | ||
| 454 | write_coord_sd(Coordinate *coord) | ||
| 455 | { | ||
| 456 | FILE *f; | ||
| 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 | |||
| 465 | if ((f = fopen(fname, "wb")) == NULL) | ||
| 466 | return false; | ||
| 467 | |||
| 468 | r = true; | ||
| 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 | } | ||
| 480 | |||
| 481 | static bool | ||
| 482 | write_coord_ttable(Coordinate *coord) | ||
| 483 | { | ||
| 484 | FILE *f; | ||
| 485 | char fname[strlen(tabledir)+256]; | ||
| 486 | Trans t; | ||
| 487 | uint64_t M; | ||
| 488 | bool r; | ||
| 489 | |||
| 490 | strcpy(fname, tabledir); | ||
| 491 | strcat(fname, "/tt_"); | ||
| 492 | strcat(fname, coord->name); | ||
| 493 | |||
| 494 | if ((f = fopen(fname, "wb")) == NULL) | ||
| 495 | return false; | ||
| 496 | |||
| 497 | M = coord->max; | ||
| 498 | r = true; | ||
| 499 | for (t = 0; t < NTRANS; t++) | ||
| 500 | r = r && fwrite(coord->ttable[t], sizeof(uint64_t), M, f) == M; | ||
| 501 | |||
| 502 | fclose(f); | ||
| 503 | return r; | ||
| 504 | } | ||
| 505 | |||
| 506 | /* Public functions **********************************************************/ | ||
| 507 | |||
| 508 | void | ||
| 509 | gen_coord(Coordinate *coord) | ||
| 510 | { | ||
| 511 | int i; | ||
| 512 | |||
| 513 | if (coord == NULL || coord->generated) | ||
| 514 | return; | ||
| 515 | |||
| 516 | for (i = 0; i < 2; i++) | ||
| 517 | gen_coord(coord->base[i]); | ||
| 518 | |||
| 519 | switch (coord->type) { | ||
| 520 | case COMP_COORD: | ||
| 521 | if (coord->i[0] == NULL) | ||
| 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 | } | ||
| 538 | |||
| 539 | coord->generated = true; | ||
| 540 | return; | ||
| 541 | |||
| 542 | error_gc: | ||
| 543 | fprintf(stderr, "Error generating coordinates.\n" | ||
| 544 | "This is a bug, pleae report.\n"); | ||
| 545 | exit(1); | ||
| 546 | } | ||
| 547 | |||
| 548 | uint64_t | ||
| 549 | index_coord(Coordinate *coord, Cube *cube, Trans *offtrans) | ||
| 550 | { | ||
| 551 | uint64_t c[2], cnosym; | ||
| 552 | Trans ttr; | ||
| 553 | |||
| 554 | switch (coord->type) { | ||
| 555 | case COMP_COORD: | ||
| 556 | if (offtrans != NULL) | ||
| 557 | *offtrans = uf; | ||
| 558 | |||
| 559 | return indexers_getind(coord->i, cube); | ||
| 560 | case SYM_COORD: | ||
| 561 | cnosym = index_coord(coord->base[0], cube, NULL); | ||
| 562 | ttr = coord->transtorep[cnosym]; | ||
| 563 | |||
| 564 | if (offtrans != NULL) | ||
| 565 | *offtrans = ttr; | ||
| 566 | |||
| 567 | return coord->symclass[cnosym]; | ||
| 568 | case SYMCOMP_COORD: | ||
| 569 | c[0] = index_coord(coord->base[0], cube, NULL); | ||
| 570 | cnosym = index_coord(coord->base[0]->base[0], cube, NULL); | ||
| 571 | ttr = coord->base[0]->transtorep[cnosym]; | ||
| 572 | c[1] = index_coord(coord->base[1], cube, NULL); | ||
| 573 | c[1] = trans_coord(coord->base[1], ttr, c[1]); | ||
| 574 | |||
| 575 | if (offtrans != NULL) | ||
| 576 | *offtrans = ttr; | ||
| 577 | |||
| 578 | return c[0] * coord->base[1]->max + c[1]; | ||
| 579 | default: | ||
| 580 | break; | ||
| 581 | } | ||
| 582 | |||
| 583 | return coord->max; /* Only reached in case of error */ | ||
| 584 | } | ||
| 585 | |||
| 586 | uint64_t | ||
| 587 | move_coord(Coordinate *coord, Move m, uint64_t ind, Trans *offtrans) | ||
| 588 | { | ||
| 589 | uint64_t i[2], M; | ||
| 590 | Trans ttr; | ||
| 591 | |||
| 592 | /* Some safety checks should be done here, but for performance * | ||
| 593 | * reasons we'd rather do them before calling this function. * | ||
| 594 | * We should check if coord is generated. */ | ||
| 595 | |||
| 596 | switch (coord->type) { | ||
| 597 | case COMP_COORD: | ||
| 598 | if (offtrans != NULL) | ||
| 599 | *offtrans = uf; | ||
| 600 | |||
| 601 | return coord->mtable[m][ind]; | ||
| 602 | case SYM_COORD: | ||
| 603 | ttr = coord->ttrep_move[m][ind]; | ||
| 604 | |||
| 605 | if (offtrans != NULL) | ||
| 606 | *offtrans = ttr; | ||
| 607 | |||
| 608 | return coord->mtable[m][ind]; | ||
| 609 | case SYMCOMP_COORD: | ||
| 610 | M = coord->base[1]->max; | ||
| 611 | i[0] = ind / M; | ||
| 612 | i[1] = ind % M; | ||
| 613 | ttr = coord->base[0]->ttrep_move[m][i[0]]; | ||
| 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 | |||
| 618 | if (offtrans != NULL) | ||
| 619 | *offtrans = ttr; | ||
| 620 | |||
| 621 | return i[0] * M + i[1]; | ||
| 622 | default: | ||
| 623 | break; | ||
| 624 | } | ||
| 625 | |||
| 626 | return coord->max; /* Only reached in case of error */ | ||
| 627 | } | ||
| 628 | |||
| 629 | uint64_t | ||
| 630 | trans_coord(Coordinate *coord, Trans t, uint64_t ind) | ||
| 631 | { | ||
| 632 | uint64_t i[2], M; | ||
| 633 | |||
| 634 | /* Some safety checks should be done here, but for performance * | ||
| 635 | * reasons we'd rather do them before calling this function. * | ||
| 636 | * We should check if coord is generated. */ | ||
| 637 | |||
| 638 | switch (coord->type) { | ||
| 639 | case COMP_COORD: | ||
| 640 | return coord->ttable[t][ind]; | ||
| 641 | case SYM_COORD: | ||
| 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 | } | ||
| 652 | |||
| 653 | return coord->max; /* Only reached in case of error */ | ||
| 654 | } | ||
diff --git a/src/coord.h b/src/coord.h deleted file mode 100644 index 4cd7e47..0000000 --- a/src/coord.h +++ /dev/null | |||
| @@ -1,259 +0,0 @@ | |||
| 1 | #ifndef COORD_H | ||
| 2 | #define COORD_H | ||
| 3 | |||
| 4 | #include "trans.h" | ||
| 5 | |||
| 6 | void gen_coord(Coordinate *coord); | ||
| 7 | uint64_t index_coord(Coordinate *coord, Cube *cube, | ||
| 8 | Trans *offtrans); | ||
| 9 | uint64_t indexers_getind(Indexer **is, Cube *c); | ||
| 10 | void indexers_makecube(Indexer **is, uint64_t ind, Cube *c); | ||
| 11 | uint64_t move_coord(Coordinate *coord, Move m, | ||
| 12 | uint64_t ind, Trans *offtrans); | ||
| 13 | uint64_t trans_coord(Coordinate *coord, Trans t, uint64_t ind); | ||
| 14 | |||
| 15 | /* Base coordinates and their index functions ********************************/ | ||
| 16 | |||
| 17 | #ifndef COORD_C | ||
| 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 | |||
| 258 | #endif | ||
| 259 | |||
diff --git a/src/cube.c b/src/cube.c deleted file mode 100644 index 92c6713..0000000 --- a/src/cube.c +++ /dev/null | |||
| @@ -1,270 +0,0 @@ | |||
| 1 | #define CUBE_C | ||
| 2 | |||
| 3 | #include "cube.h" | ||
| 4 | |||
| 5 | static int where_is_piece(int piece, int *arr, int n); | ||
| 6 | |||
| 7 | void | ||
| 8 | compose_centers(Cube *c2, Cube *c1) | ||
| 9 | { | ||
| 10 | apply_permutation(c2->xp, c1->xp, 6); | ||
| 11 | } | ||
| 12 | |||
| 13 | void | ||
| 14 | compose_corners(Cube *c2, Cube *c1) | ||
| 15 | { | ||
| 16 | apply_permutation(c2->cp, c1->cp, 8); | ||
| 17 | apply_permutation(c2->cp, c1->co, 8); | ||
| 18 | sum_arrays_mod(c2->co, c1->co, 8, 3); | ||
| 19 | } | ||
| 20 | |||
| 21 | void | ||
| 22 | compose_edges(Cube *c2, Cube *c1) | ||
| 23 | { | ||
| 24 | apply_permutation(c2->ep, c1->ep, 12); | ||
| 25 | apply_permutation(c2->ep, c1->eo, 12); | ||
| 26 | sum_arrays_mod(c2->eo, c1->eo, 12, 2); | ||
| 27 | } | ||
| 28 | |||
| 29 | void | ||
| 30 | compose(Cube *c2, Cube *c1) | ||
| 31 | { | ||
| 32 | compose_centers(c2, c1); | ||
| 33 | compose_corners(c2, c1); | ||
| 34 | compose_edges(c2, c1); | ||
| 35 | } | ||
| 36 | |||
| 37 | void | ||
| 38 | copy_cube_centers(Cube *src, Cube *dst) | ||
| 39 | { | ||
| 40 | memcpy(dst->xp, src->xp, 6 * sizeof(int)); | ||
| 41 | } | ||
| 42 | |||
| 43 | void | ||
| 44 | copy_cube_corners(Cube *src, Cube *dst) | ||
| 45 | { | ||
| 46 | memcpy(dst->cp, src->cp, 8 * sizeof(int)); | ||
| 47 | memcpy(dst->co, src->co, 8 * sizeof(int)); | ||
| 48 | } | ||
| 49 | |||
| 50 | void | ||
| 51 | copy_cube_edges(Cube *src, Cube *dst) | ||
| 52 | { | ||
| 53 | memcpy(dst->ep, src->ep, 12 * sizeof(int)); | ||
| 54 | memcpy(dst->eo, src->eo, 12 * sizeof(int)); | ||
| 55 | } | ||
| 56 | |||
| 57 | void | ||
| 58 | copy_cube(Cube *src, Cube *dst) | ||
| 59 | { | ||
| 60 | copy_cube_centers(src, dst); | ||
| 61 | copy_cube_corners(src, dst); | ||
| 62 | copy_cube_edges(src, dst); | ||
| 63 | } | ||
| 64 | |||
| 65 | bool | ||
| 66 | equal(Cube *c1, Cube *c2) | ||
| 67 | { | ||
| 68 | int i; | ||
| 69 | |||
| 70 | for (i = 0; i < 12; i++) | ||
| 71 | if (c1->ep[i] != c2->ep[i] || c1->eo[i] != c2->eo[i]) | ||
| 72 | return false; | ||
| 73 | |||
| 74 | for (i = 0; i < 8; i++) | ||
| 75 | if (c1->cp[i] != c2->cp[i] || c1->co[i] != c2->co[i]) | ||
| 76 | return false; | ||
| 77 | |||
| 78 | for (i = 0; i < 6; i++) | ||
| 79 | if (c1->xp[i] != c2->xp[i]) | ||
| 80 | return false; | ||
| 81 | |||
| 82 | return true; | ||
| 83 | } | ||
| 84 | |||
| 85 | void | ||
| 86 | invert_cube_centers(Cube *cube) | ||
| 87 | { | ||
| 88 | int i; | ||
| 89 | Cube aux; | ||
| 90 | |||
| 91 | copy_cube_centers(cube, &aux); | ||
| 92 | |||
| 93 | for (i = 0; i < 6; i++) | ||
| 94 | cube->xp[aux.xp[i]] = i; | ||
| 95 | } | ||
| 96 | |||
| 97 | void | ||
| 98 | invert_cube_corners(Cube *cube) | ||
| 99 | { | ||
| 100 | int i; | ||
| 101 | Cube aux; | ||
| 102 | |||
| 103 | copy_cube_corners(cube, &aux); | ||
| 104 | |||
| 105 | for (i = 0; i < 8; i++) { | ||
| 106 | cube->cp[aux.cp[i]] = i; | ||
| 107 | cube->co[aux.cp[i]] = (3 - aux.co[i]) % 3; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | void | ||
| 112 | invert_cube_edges(Cube *cube) | ||
| 113 | { | ||
| 114 | int i; | ||
| 115 | Cube aux; | ||
| 116 | |||
| 117 | copy_cube_edges(cube, &aux); | ||
| 118 | |||
| 119 | for (i = 0; i < 12; i++) { | ||
| 120 | cube->ep[aux.ep[i]] = i; | ||
| 121 | cube->eo[aux.ep[i]] = aux.eo[i]; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | void | ||
| 126 | invert_cube(Cube *cube) | ||
| 127 | { | ||
| 128 | invert_cube_centers(cube); | ||
| 129 | invert_cube_corners(cube); | ||
| 130 | invert_cube_edges(cube); | ||
| 131 | } | ||
| 132 | |||
| 133 | bool | ||
| 134 | is_admissible(Cube *c) { | ||
| 135 | bool perm; | ||
| 136 | int sign, i; | ||
| 137 | int sum_e, sum_c; | ||
| 138 | |||
| 139 | perm = is_perm(c->ep, 12) && is_perm(c->cp, 8) && is_perm(c->xp, 6); | ||
| 140 | |||
| 141 | sign = perm_sign(c->ep,12) + perm_sign(c->cp,8) + perm_sign(c->xp,6); | ||
| 142 | |||
| 143 | for (i = 0, sum_e = 0; i < 12; i++) | ||
| 144 | if (c->eo[i] > 1) | ||
| 145 | return false; | ||
| 146 | else | ||
| 147 | sum_e += c->eo[i]; | ||
| 148 | |||
| 149 | for (i = 0, sum_c = 0; i < 8; i++) | ||
| 150 | if (c->co[i] > 2) | ||
| 151 | return false; | ||
| 152 | else | ||
| 153 | sum_c += c->co[i]; | ||
| 154 | |||
| 155 | return (perm && sign % 2 == 0 && sum_e % 2 == 0 && sum_c % 2 == 0); | ||
| 156 | } | ||
| 157 | |||
| 158 | bool | ||
| 159 | is_solved(Cube *cube) | ||
| 160 | { | ||
| 161 | Cube solved_cube; | ||
| 162 | make_solved(&solved_cube); | ||
| 163 | |||
| 164 | return equal(cube, &solved_cube); | ||
| 165 | } | ||
| 166 | |||
| 167 | void | ||
| 168 | make_solved_centers(Cube *cube) | ||
| 169 | { | ||
| 170 | static int sorted[6] = {0, 1, 2, 3, 4, 5}; | ||
| 171 | |||
| 172 | memcpy(cube->xp, sorted, 6 * sizeof(int)); | ||
| 173 | } | ||
| 174 | |||
| 175 | void | ||
| 176 | make_solved_corners(Cube *cube) | ||
| 177 | { | ||
| 178 | static int sorted[8] = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
| 179 | |||
| 180 | memcpy(cube->cp, sorted, 8 * sizeof(int)); | ||
| 181 | memset(cube->co, 0, 8 * sizeof(int)); | ||
| 182 | } | ||
| 183 | |||
| 184 | void | ||
| 185 | make_solved_edges(Cube *cube) | ||
| 186 | { | ||
| 187 | static int sorted[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; | ||
| 188 | |||
| 189 | memcpy(cube->ep, sorted, 12 * sizeof(int)); | ||
| 190 | memset(cube->eo, 0, 12 * sizeof(int)); | ||
| 191 | } | ||
| 192 | |||
| 193 | void | ||
| 194 | make_solved(Cube *cube) | ||
| 195 | { | ||
| 196 | make_solved_centers(cube); | ||
| 197 | make_solved_corners(cube); | ||
| 198 | make_solved_edges(cube); | ||
| 199 | } | ||
| 200 | |||
| 201 | void | ||
| 202 | print_cube(Cube *cube) | ||
| 203 | { | ||
| 204 | static char edge_string[12][7] = { | ||
| 205 | [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR", | ||
| 206 | [DF] = "DF", [DL] = "DL", [DB] = "DB", [DR] = "DR", | ||
| 207 | [FR] = "FR", [FL] = "FL", [BL] = "BL", [BR] = "BR" | ||
| 208 | }; | ||
| 209 | |||
| 210 | static char corner_string[8][7] = { | ||
| 211 | [UFR] = "UFR", [UFL] = "UFL", [UBL] = "UBL", [UBR] = "UBR", | ||
| 212 | [DFR] = "DFR", [DFL] = "DFL", [DBL] = "DBL", [DBR] = "DBR" | ||
| 213 | }; | ||
| 214 | |||
| 215 | static char center_string[6][7] = { | ||
| 216 | [U_center] = "U", [D_center] = "D", | ||
| 217 | [R_center] = "R", [L_center] = "L", | ||
| 218 | [F_center] = "F", [B_center] = "B" | ||
| 219 | }; | ||
| 220 | |||
| 221 | for (int i = 0; i < 12; i++) | ||
| 222 | printf(" %s ", edge_string[cube->ep[i]]); | ||
| 223 | printf("\n"); | ||
| 224 | |||
| 225 | for (int i = 0; i < 12; i++) | ||
| 226 | printf(" %" PRIu8 " ", cube->eo[i]); | ||
| 227 | printf("\n"); | ||
| 228 | |||
| 229 | for (int i = 0; i < 8; i++) | ||
| 230 | printf("%s ", corner_string[cube->cp[i]]); | ||
| 231 | printf("\n"); | ||
| 232 | |||
| 233 | for (int i = 0; i < 8; i++) | ||
| 234 | printf(" %" PRIu8 " ", cube->co[i]); | ||
| 235 | printf("\n"); | ||
| 236 | |||
| 237 | for (int i = 0; i < 6; i++) | ||
| 238 | printf(" %s ", center_string[cube->xp[i]]); | ||
| 239 | printf("\n"); | ||
| 240 | } | ||
| 241 | |||
| 242 | int | ||
| 243 | where_is_center(Center x, Cube *c) | ||
| 244 | { | ||
| 245 | return where_is_piece(x, c->xp, 6); | ||
| 246 | } | ||
| 247 | |||
| 248 | int | ||
| 249 | where_is_corner(Corner k, Cube *c) | ||
| 250 | { | ||
| 251 | return where_is_piece(k, c->cp, 8); | ||
| 252 | } | ||
| 253 | |||
| 254 | int | ||
| 255 | where_is_edge(Edge e, Cube *c) | ||
| 256 | { | ||
| 257 | return where_is_piece(e, c->ep, 12); | ||
| 258 | } | ||
| 259 | |||
| 260 | static int | ||
| 261 | where_is_piece(int piece, int *arr, int n) | ||
| 262 | { | ||
| 263 | int i; | ||
| 264 | |||
| 265 | for (i = 0; i < n; i++) | ||
| 266 | if (arr[i] == piece) | ||
| 267 | return i; | ||
| 268 | |||
| 269 | return -1; | ||
| 270 | } | ||
diff --git a/src/cube.h b/src/cube.h deleted file mode 100644 index f182b27..0000000 --- a/src/cube.h +++ /dev/null | |||
| @@ -1,35 +0,0 @@ | |||
| 1 | #ifndef CUBE_H | ||
| 2 | #define CUBE_H | ||
| 3 | |||
| 4 | #include <stdio.h> | ||
| 5 | |||
| 6 | #include "cubetypes.h" | ||
| 7 | #include "env.h" | ||
| 8 | #include "utils.h" | ||
| 9 | |||
| 10 | void compose(Cube *c2, Cube *c1); /* Use c2 as an alg on c1 */ | ||
| 11 | void compose_centers(Cube *c2, Cube *c1); | ||
| 12 | void compose_corners(Cube *c2, Cube *c1); | ||
| 13 | void compose_edges(Cube *c2, Cube *c1); | ||
| 14 | void copy_cube(Cube *src, Cube *dst); | ||
| 15 | void copy_cube_centers(Cube *src, Cube *dst); | ||
| 16 | void copy_cube_corners(Cube *src, Cube *dst); | ||
| 17 | void copy_cube_edges(Cube *src, Cube *dst); | ||
| 18 | bool equal(Cube *c1, Cube *c2); | ||
| 19 | void invert_cube(Cube *cube); | ||
| 20 | void invert_cube_centers(Cube *cube); | ||
| 21 | void invert_cube_corners(Cube *cube); | ||
| 22 | void invert_cube_edges(Cube *cube); | ||
| 23 | bool is_admissible(Cube *cube); | ||
| 24 | bool is_solved(Cube *cube); | ||
| 25 | void make_solved(Cube *cube); | ||
| 26 | void make_solved_centers(Cube *cube); | ||
| 27 | void make_solved_corners(Cube *cube); | ||
| 28 | void make_solved_edges(Cube *cube); | ||
| 29 | void print_cube(Cube *cube); | ||
| 30 | int where_is_center(Center x, Cube *c); | ||
| 31 | int where_is_corner(Corner k, Cube *c); | ||
| 32 | int where_is_edge(Edge e, Cube *c); | ||
| 33 | |||
| 34 | #endif | ||
| 35 | |||
diff --git a/src/cubetypes.h b/src/cubetypes.h deleted file mode 100644 index 3752019..0000000 --- a/src/cubetypes.h +++ /dev/null | |||
| @@ -1,360 +0,0 @@ | |||
| 1 | #ifndef CUBETYPES_H | ||
| 2 | #define CUBETYPES_H | ||
| 3 | |||
| 4 | #include <stdbool.h> | ||
| 5 | #include <inttypes.h> | ||
| 6 | #include <pthread.h> | ||
| 7 | |||
| 8 | #define NMOVES 55 /* Actually 54, but one is NULLMOVE */ | ||
| 9 | #define NTRANS 48 | ||
| 10 | #define NROTATIONS 24 | ||
| 11 | #define entry_group_t uint8_t /* For pruning tables */ | ||
| 12 | |||
| 13 | #define MAX_N_COORD 6 | ||
| 14 | |||
| 15 | /* Enums *********************************************************************/ | ||
| 16 | |||
| 17 | typedef enum | ||
| 18 | center | ||
| 19 | { | ||
| 20 | U_center, D_center, | ||
| 21 | R_center, L_center, | ||
| 22 | F_center, B_center | ||
| 23 | } Center; | ||
| 24 | |||
| 25 | typedef enum | ||
| 26 | corner | ||
| 27 | { | ||
| 28 | UFR, UFL, UBL, UBR, | ||
| 29 | DFR, DFL, DBL, DBR | ||
| 30 | } Corner; | ||
| 31 | |||
| 32 | typedef enum | ||
| 33 | coordtype | ||
| 34 | { | ||
| 35 | COMP_COORD, SYM_COORD, SYMCOMP_COORD | ||
| 36 | } CoordType; | ||
| 37 | |||
| 38 | typedef enum | ||
| 39 | edge | ||
| 40 | { | ||
| 41 | UF, UL, UB, UR, | ||
| 42 | DF, DL, DB, DR, | ||
| 43 | FR, FL, BL, BR | ||
| 44 | } Edge; | ||
| 45 | |||
| 46 | typedef enum | ||
| 47 | move | ||
| 48 | { | ||
| 49 | NULLMOVE, | ||
| 50 | U, U2, U3, D, D2, D3, | ||
| 51 | R, R2, R3, L, L2, L3, | ||
| 52 | F, F2, F3, B, B2, B3, | ||
| 53 | Uw, Uw2, Uw3, Dw, Dw2, Dw3, | ||
| 54 | Rw, Rw2, Rw3, Lw, Lw2, Lw3, | ||
| 55 | Fw, Fw2, Fw3, Bw, Bw2, Bw3, | ||
| 56 | M, M2, M3, | ||
| 57 | S, S2, S3, | ||
| 58 | E, E2, E3, | ||
| 59 | x, x2, x3, | ||
| 60 | y, y2, y3, | ||
| 61 | z, z2, z3, | ||
| 62 | } Move; | ||
| 63 | |||
| 64 | typedef enum | ||
| 65 | trans | ||
| 66 | { | ||
| 67 | uf, ur, ub, ul, | ||
| 68 | df, dr, db, dl, | ||
| 69 | rf, rd, rb, ru, | ||
| 70 | lf, ld, lb, lu, | ||
| 71 | fu, fr, fd, fl, | ||
| 72 | bu, br, bd, bl, | ||
| 73 | uf_mirror, ur_mirror, ub_mirror, ul_mirror, | ||
| 74 | df_mirror, dr_mirror, db_mirror, dl_mirror, | ||
| 75 | rf_mirror, rd_mirror, rb_mirror, ru_mirror, | ||
| 76 | lf_mirror, ld_mirror, lb_mirror, lu_mirror, | ||
| 77 | fu_mirror, fr_mirror, fd_mirror, fl_mirror, | ||
| 78 | bu_mirror, br_mirror, bd_mirror, bl_mirror, | ||
| 79 | } Trans; | ||
| 80 | |||
| 81 | |||
| 82 | /* Typedefs ******************************************************************/ | ||
| 83 | |||
| 84 | typedef struct alg Alg; | ||
| 85 | typedef struct alglist AlgList; | ||
| 86 | typedef struct alglistnode AlgListNode; | ||
| 87 | typedef struct choicestep ChoiceStep; | ||
| 88 | typedef struct command Command; | ||
| 89 | typedef struct commandargs CommandArgs; | ||
| 90 | typedef struct coordinate Coordinate; | ||
| 91 | typedef struct cube Cube; | ||
| 92 | /*typedef struct dfsarg DfsArg;*/ | ||
| 93 | typedef struct fstcube FstCube; | ||
| 94 | typedef struct indexer Indexer; | ||
| 95 | typedef struct movable Movable; | ||
| 96 | typedef struct moveset Moveset; | ||
| 97 | typedef struct prunedata PruneData; | ||
| 98 | typedef struct solveoptions SolveOptions; | ||
| 99 | typedef struct step Step; | ||
| 100 | typedef struct symdata SymData; | ||
| 101 | typedef struct threaddatasolve ThreadDataSolve; | ||
| 102 | typedef struct threaddatagenpt ThreadDataGenpt; | ||
| 103 | typedef struct transgroup TransGroup; | ||
| 104 | |||
| 105 | typedef bool (*Checker) (Cube *); | ||
| 106 | typedef bool (*CubeTester) (Cube *, Alg *); | ||
| 107 | /*typedef bool (*DfsMover) (DfsArg *);*/ | ||
| 108 | typedef void (*DfsExtraCopier) (void *, void *); | ||
| 109 | typedef Alg * (*Validator) (Alg *); | ||
| 110 | typedef void (*Exec) (CommandArgs *); | ||
| 111 | typedef CommandArgs * (*ArgParser) (int, char **); | ||
| 112 | typedef bool (*Tester) (void); | ||
| 113 | typedef int (*TransFinder) (uint64_t, Trans *); | ||
| 114 | |||
| 115 | |||
| 116 | /* Structs *******************************************************************/ | ||
| 117 | |||
| 118 | struct | ||
| 119 | alg | ||
| 120 | { | ||
| 121 | Move * move; | ||
| 122 | bool * inv; | ||
| 123 | int len; | ||
| 124 | int allocated; | ||
| 125 | Move * move_normal; | ||
| 126 | int len_normal; | ||
| 127 | Move * move_inverse; | ||
| 128 | int len_inverse; | ||
| 129 | }; | ||
| 130 | |||
| 131 | struct | ||
| 132 | alglist | ||
| 133 | { | ||
| 134 | AlgListNode * first; | ||
| 135 | AlgListNode * last; | ||
| 136 | int len; | ||
| 137 | }; | ||
| 138 | |||
| 139 | struct | ||
| 140 | alglistnode | ||
| 141 | { | ||
| 142 | Alg * alg; | ||
| 143 | AlgListNode * next; | ||
| 144 | }; | ||
| 145 | |||
| 146 | struct | ||
| 147 | choicestep | ||
| 148 | { | ||
| 149 | char * shortname; | ||
| 150 | char * name; | ||
| 151 | Step * step[99]; | ||
| 152 | Trans t[99]; | ||
| 153 | char * ready_msg; | ||
| 154 | }; | ||
| 155 | |||
| 156 | struct | ||
| 157 | command | ||
| 158 | { | ||
| 159 | char * name; | ||
| 160 | char * usage; | ||
| 161 | char * description; | ||
| 162 | ArgParser parse_args; | ||
| 163 | Exec exec; | ||
| 164 | }; | ||
| 165 | |||
| 166 | struct | ||
| 167 | commandargs | ||
| 168 | { | ||
| 169 | bool success; | ||
| 170 | Alg * scramble; | ||
| 171 | SolveOptions * opts; | ||
| 172 | ChoiceStep * cs; | ||
| 173 | Command * command; /* For help */ | ||
| 174 | int n; | ||
| 175 | char scrtype[20]; | ||
| 176 | bool scrstdin; | ||
| 177 | bool header; | ||
| 178 | }; | ||
| 179 | |||
| 180 | struct | ||
| 181 | coordinate | ||
| 182 | { | ||
| 183 | char * name; | ||
| 184 | CoordType type; | ||
| 185 | bool generated; | ||
| 186 | Indexer * i[99]; | ||
| 187 | uint64_t max; | ||
| 188 | uint64_t * mtable[NMOVES]; | ||
| 189 | uint64_t * ttable[NTRANS]; | ||
| 190 | TransGroup * tgrp; | ||
| 191 | Coordinate * base[2]; | ||
| 192 | uint64_t * symclass; | ||
| 193 | uint64_t * symrep; | ||
| 194 | Trans * transtorep; | ||
| 195 | Trans * ttrep_move[NMOVES]; | ||
| 196 | uint64_t * selfsim; | ||
| 197 | }; | ||
| 198 | |||
| 199 | struct | ||
| 200 | cube | ||
| 201 | { | ||
| 202 | int ep[12]; | ||
| 203 | int eo[12]; | ||
| 204 | int cp[8]; | ||
| 205 | int co[8]; | ||
| 206 | int xp[6]; | ||
| 207 | }; | ||
| 208 | |||
| 209 | /* | ||
| 210 | struct | ||
| 211 | movable | ||
| 212 | { | ||
| 213 | uint64_t val; | ||
| 214 | Trans t; | ||
| 215 | }; | ||
| 216 | */ | ||
| 217 | |||
| 218 | /* | ||
| 219 | struct | ||
| 220 | dfsarg | ||
| 221 | { | ||
| 222 | Cube * cube; | ||
| 223 | Movable ind[MAX_N_COORD]; | ||
| 224 | Trans t; | ||
| 225 | Step * s; | ||
| 226 | SolveOptions * opts; | ||
| 227 | int d; | ||
| 228 | int bound; | ||
| 229 | bool niss; | ||
| 230 | AlgList * sols; | ||
| 231 | pthread_mutex_t * sols_mutex; | ||
| 232 | Alg * current_alg; | ||
| 233 | void * extra; | ||
| 234 | }; | ||
| 235 | */ | ||
| 236 | |||
| 237 | /* | ||
| 238 | struct | ||
| 239 | dfsarg | ||
| 240 | { | ||
| 241 | void * cube_data; | ||
| 242 | SolveOptions * opts; | ||
| 243 | int d; | ||
| 244 | int bound; | ||
| 245 | bool niss; | ||
| 246 | AlgList * sols; | ||
| 247 | Alg * current_alg; | ||
| 248 | Solver * solver; | ||
| 249 | Threader * threader; | ||
| 250 | }; | ||
| 251 | */ | ||
| 252 | |||
| 253 | struct | ||
| 254 | fstcube | ||
| 255 | { | ||
| 256 | uint16_t uf_eofb; | ||
| 257 | uint16_t uf_eposepe; | ||
| 258 | uint16_t uf_coud; | ||
| 259 | uint16_t uf_cp; | ||
| 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 | }; | ||
| 267 | |||
| 268 | struct | ||
| 269 | indexer | ||
| 270 | { | ||
| 271 | int n; | ||
| 272 | uint64_t (*index)(Cube *); | ||
| 273 | void (*to_cube)(uint64_t, Cube *); | ||
| 274 | }; | ||
| 275 | |||
| 276 | struct | ||
| 277 | moveset | ||
| 278 | { | ||
| 279 | char * name; | ||
| 280 | bool (*allowed)(Move); | ||
| 281 | bool (*can_append)(Alg *, Move, bool); | ||
| 282 | bool (*cancel_niss)(Alg *); | ||
| 283 | Move sorted_moves[NMOVES+1]; | ||
| 284 | }; | ||
| 285 | |||
| 286 | struct | ||
| 287 | prunedata | ||
| 288 | { | ||
| 289 | entry_group_t * ptable; | ||
| 290 | uint64_t n; | ||
| 291 | Coordinate * coord; | ||
| 292 | Moveset * moveset; | ||
| 293 | uint64_t count[16]; | ||
| 294 | bool compact; | ||
| 295 | int base; | ||
| 296 | }; | ||
| 297 | |||
| 298 | struct | ||
| 299 | solveoptions | ||
| 300 | { | ||
| 301 | int min_moves; | ||
| 302 | int max_moves; | ||
| 303 | int max_solutions; | ||
| 304 | int nthreads; | ||
| 305 | int optimal; | ||
| 306 | bool can_niss; | ||
| 307 | bool verbose; | ||
| 308 | bool all; | ||
| 309 | bool print_number; | ||
| 310 | bool count_only; | ||
| 311 | }; | ||
| 312 | |||
| 313 | struct | ||
| 314 | step | ||
| 315 | { | ||
| 316 | Checker ready; | ||
| 317 | bool final; | ||
| 318 | Moveset * moveset; | ||
| 319 | int n_coord; | ||
| 320 | Coordinate * coord[MAX_N_COORD]; | ||
| 321 | Trans coord_trans[MAX_N_COORD]; | ||
| 322 | PruneData * pd[MAX_N_COORD]; | ||
| 323 | bool pd_compact[MAX_N_COORD]; | ||
| 324 | Validator is_valid; | ||
| 325 | /*DfsMover custom_move_checkstop;*/ | ||
| 326 | DfsExtraCopier copy_extra; | ||
| 327 | }; | ||
| 328 | |||
| 329 | /* | ||
| 330 | struct | ||
| 331 | threaddatasolve | ||
| 332 | { | ||
| 333 | DfsArg arg; | ||
| 334 | int thid; | ||
| 335 | AlgList * start; | ||
| 336 | AlgListNode ** node; | ||
| 337 | pthread_mutex_t * start_mutex; | ||
| 338 | }; | ||
| 339 | */ | ||
| 340 | |||
| 341 | struct | ||
| 342 | threaddatagenpt | ||
| 343 | { | ||
| 344 | int thid; | ||
| 345 | int nthreads; | ||
| 346 | PruneData * pd; | ||
| 347 | int d; | ||
| 348 | int nchunks; | ||
| 349 | pthread_mutex_t ** mutex; | ||
| 350 | pthread_mutex_t * upmutex; | ||
| 351 | }; | ||
| 352 | |||
| 353 | struct | ||
| 354 | transgroup | ||
| 355 | { | ||
| 356 | int n; | ||
| 357 | Trans t[NTRANS]; | ||
| 358 | }; | ||
| 359 | |||
| 360 | #endif | ||
diff --git a/src/env.c b/src/env.c deleted file mode 100644 index 375bfa8..0000000 --- a/src/env.c +++ /dev/null | |||
| @@ -1,60 +0,0 @@ | |||
| 1 | #define ENV_C | ||
| 2 | |||
| 3 | #include "env.h" | ||
| 4 | |||
| 5 | bool initialized_env = false; | ||
| 6 | char *tabledir; | ||
| 7 | |||
| 8 | void | ||
| 9 | mymkdir(char *d, int m) | ||
| 10 | { | ||
| 11 | #ifdef _WIN32 | ||
| 12 | mkdir(d); | ||
| 13 | #else | ||
| 14 | mkdir(d, m); | ||
| 15 | #endif | ||
| 16 | } | ||
| 17 | |||
| 18 | void | ||
| 19 | init_env() | ||
| 20 | { | ||
| 21 | char *nissydata = getenv("NISSYDATA"); | ||
| 22 | char *localdata = getenv("XDG_DATA_HOME"); | ||
| 23 | char *home = getenv("HOME"); | ||
| 24 | bool read, write; | ||
| 25 | |||
| 26 | if (initialized_env) | ||
| 27 | return; | ||
| 28 | |||
| 29 | if (nissydata != NULL) { | ||
| 30 | tabledir = malloc((strlen(nissydata) + 20) * sizeof(char)); | ||
| 31 | strcpy(tabledir, nissydata); | ||
| 32 | } else if (localdata != NULL) { | ||
| 33 | tabledir = malloc((strlen(localdata) + 20) * sizeof(char)); | ||
| 34 | strcpy(tabledir, localdata); | ||
| 35 | strcat(tabledir, "/nissy"); | ||
| 36 | } else if (home != NULL) { | ||
| 37 | tabledir = malloc((strlen(home) + 20) * sizeof(char)); | ||
| 38 | strcpy(tabledir, home); | ||
| 39 | strcat(tabledir, "/.nissy"); | ||
| 40 | } else { | ||
| 41 | tabledir = malloc(20 * sizeof(char)); | ||
| 42 | strcpy(tabledir, "."); | ||
| 43 | } | ||
| 44 | |||
| 45 | mymkdir(tabledir, 0777); | ||
| 46 | strcat(tabledir, "/tables"); | ||
| 47 | mymkdir(tabledir, 0777); | ||
| 48 | |||
| 49 | read = !access(tabledir, R_OK); | ||
| 50 | write = !access(tabledir, W_OK); | ||
| 51 | |||
| 52 | if (!read) { | ||
| 53 | fprintf(stderr, "Table files cannot be read.\n"); | ||
| 54 | } else if (!write) { | ||
| 55 | fprintf(stderr, "Data directory not writable: "); | ||
| 56 | fprintf(stderr, "tables can be loaded, but not saved.\n"); | ||
| 57 | } | ||
| 58 | |||
| 59 | initialized_env = true; | ||
| 60 | } | ||
diff --git a/src/env.h b/src/env.h deleted file mode 100644 index a49d643..0000000 --- a/src/env.h +++ /dev/null | |||
| @@ -1,15 +0,0 @@ | |||
| 1 | #ifndef ENV_H | ||
| 2 | #define ENV_H | ||
| 3 | |||
| 4 | #include <stdbool.h> | ||
| 5 | #include <stdio.h> | ||
| 6 | #include <stdlib.h> | ||
| 7 | #include <string.h> | ||
| 8 | #include <unistd.h> | ||
| 9 | #include <sys/stat.h> | ||
| 10 | |||
| 11 | void init_env(); | ||
| 12 | |||
| 13 | extern char *tabledir; | ||
| 14 | |||
| 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 deleted file mode 100644 index a9dfdc0..0000000 --- a/src/moves.c +++ /dev/null | |||
| @@ -1,301 +0,0 @@ | |||
| 1 | #define MOVES_C | ||
| 2 | |||
| 3 | #include "moves.h" | ||
| 4 | |||
| 5 | /* Local functions ***********************************************************/ | ||
| 6 | |||
| 7 | static void cleanup_aux(Alg *alg, Alg *ret, bool inv); | ||
| 8 | |||
| 9 | /* Tables and other data *****************************************************/ | ||
| 10 | |||
| 11 | /* Moves are represented as cubes and applied using compose(). Every move is * | ||
| 12 | * translated to a an <U, x, y> alg before filling the transition tables. * | ||
| 13 | * See init_moves(). */ | ||
| 14 | |||
| 15 | static Cube move_array[NMOVES]; | ||
| 16 | |||
| 17 | static char equiv_alg_string[100][NMOVES] = { | ||
| 18 | [NULLMOVE] = "", | ||
| 19 | |||
| 20 | [U] = " U ", | ||
| 21 | [U2] = " UU ", | ||
| 22 | [U3] = " UUU ", | ||
| 23 | [D] = " xx U xx ", | ||
| 24 | [D2] = " xx UU xx ", | ||
| 25 | [D3] = " xx UUU xx ", | ||
| 26 | [R] = " yx U xxxyyy ", | ||
| 27 | [R2] = " yx UU xxxyyy ", | ||
| 28 | [R3] = " yx UUU xxxyyy ", | ||
| 29 | [L] = " yyyx U xxxy ", | ||
| 30 | [L2] = " yyyx UU xxxy ", | ||
| 31 | [L3] = " yyyx UUU xxxy ", | ||
| 32 | [F] = " x U xxx ", | ||
| 33 | [F2] = " x UU xxx ", | ||
| 34 | [F3] = " x UUU xxx ", | ||
| 35 | [B] = " xxx U x ", | ||
| 36 | [B2] = " xxx UU x ", | ||
| 37 | [B3] = " xxx UUU x ", | ||
| 38 | |||
| 39 | [Uw] = " xx U xx y ", | ||
| 40 | [Uw2] = " xx UU xx yy ", | ||
| 41 | [Uw3] = " xx UUU xx yyy ", | ||
| 42 | [Dw] = " U yyy ", | ||
| 43 | [Dw2] = " UU yy ", | ||
| 44 | [Dw3] = " UUU y ", | ||
| 45 | [Rw] = " yyyx U xxxy x ", | ||
| 46 | [Rw2] = " yyyx UU xxxy xx ", | ||
| 47 | [Rw3] = " yyyx UUU xxxy xxx ", | ||
| 48 | [Lw] = " yx U xxxyyy xxx ", | ||
| 49 | [Lw2] = " yx UU xxxyyy xx ", | ||
| 50 | [Lw3] = " yx UUU xxxyyy x ", | ||
| 51 | [Fw] = " xxx U x yxxxyyy ", | ||
| 52 | [Fw2] = " xxx UU x yxxyyy ", | ||
| 53 | [Fw3] = " xxx UUU x yxyyy ", | ||
| 54 | [Bw] = " x U xxx yxyyy ", | ||
| 55 | [Bw2] = " x UU xxx yxxyyy ", | ||
| 56 | [Bw3] = " x UUU xxx yxxxyyy ", | ||
| 57 | |||
| 58 | [M] = " yx U xx UUU yxyyy ", | ||
| 59 | [M2] = " yx UU xx UU xxxy ", | ||
| 60 | [M3] = " yx UUU xx U yxxxy ", | ||
| 61 | [S] = " x UUU xx U yyyx ", | ||
| 62 | [S2] = " x UU xx UU yyx ", | ||
| 63 | [S3] = " x U xx UUU yx ", | ||
| 64 | [E] = " U xx UUU xxyyy ", | ||
| 65 | [E2] = " UU xx UU xxyy ", | ||
| 66 | [E3] = " UUU xx U xxy ", | ||
| 67 | |||
| 68 | [x] = " x ", | ||
| 69 | [x2] = " xx ", | ||
| 70 | [x3] = " xxx ", | ||
| 71 | [y] = " y ", | ||
| 72 | [y2] = " yy ", | ||
| 73 | [y3] = " yyy ", | ||
| 74 | [z] = " yyy x y ", | ||
| 75 | [z2] = " yy xx ", | ||
| 76 | [z3] = " y x yyy " | ||
| 77 | }; | ||
| 78 | |||
| 79 | |||
| 80 | /* Public functions **********************************************************/ | ||
| 81 | |||
| 82 | void | ||
| 83 | apply_alg(Alg *alg, Cube *cube) | ||
| 84 | { | ||
| 85 | Cube aux; | ||
| 86 | int i; | ||
| 87 | |||
| 88 | copy_cube(cube, &aux); | ||
| 89 | make_solved(cube); | ||
| 90 | |||
| 91 | for (i = 0; i < alg->len; i++) | ||
| 92 | if (alg->inv[i]) | ||
| 93 | apply_move(alg->move[i], cube); | ||
| 94 | |||
| 95 | invert_cube(cube); | ||
| 96 | compose(&aux, cube); | ||
| 97 | |||
| 98 | for (i = 0; i < alg->len; i++) | ||
| 99 | if (!alg->inv[i]) | ||
| 100 | apply_move(alg->move[i], cube); | ||
| 101 | } | ||
| 102 | |||
| 103 | void | ||
| 104 | apply_move(Move m, Cube *cube) | ||
| 105 | { | ||
| 106 | compose(&move_array[m], cube); | ||
| 107 | } | ||
| 108 | |||
| 109 | void | ||
| 110 | apply_move_centers(Move m, Cube *cube) | ||
| 111 | { | ||
| 112 | compose_centers(&move_array[m], cube); | ||
| 113 | } | ||
| 114 | |||
| 115 | void | ||
| 116 | apply_move_corners(Move m, Cube *cube) | ||
| 117 | { | ||
| 118 | compose_corners(&move_array[m], cube); | ||
| 119 | } | ||
| 120 | |||
| 121 | void | ||
| 122 | apply_move_edges(Move m, Cube *cube) | ||
| 123 | { | ||
| 124 | compose_edges(&move_array[m], cube); | ||
| 125 | } | ||
| 126 | |||
| 127 | Alg * | ||
| 128 | cleanup(Alg *alg) | ||
| 129 | { | ||
| 130 | int i, j, k, b[2], n, L; | ||
| 131 | Move bb, m; | ||
| 132 | Alg *ret; | ||
| 133 | |||
| 134 | ret = new_alg(""); | ||
| 135 | cleanup_aux(alg, ret, false); | ||
| 136 | cleanup_aux(alg, ret, true); | ||
| 137 | |||
| 138 | do { | ||
| 139 | for (i = 0, j = 0, n = 0; i < ret->len; i = j) { | ||
| 140 | if (ret->move[i] > B3) { | ||
| 141 | ret->move[n] = ret->move[i]; | ||
| 142 | ret->inv[n] = ret->inv[i]; | ||
| 143 | n++; | ||
| 144 | j++; | ||
| 145 | continue; | ||
| 146 | } | ||
| 147 | |||
| 148 | bb = 1 + ((base_move(ret->move[i]) - 1)/6)*6; | ||
| 149 | while (j < ret->len && | ||
| 150 | ret->move[j] <= B3 && | ||
| 151 | ret->inv[j] == ret->inv[i] && | ||
| 152 | 1 + ((base_move(ret->move[j]) - 1)/6)*6 == bb) | ||
| 153 | j++; | ||
| 154 | |||
| 155 | for (k = i, b[0] = 0, b[1] = 0; k < j; k++) { | ||
| 156 | m = ret->move[k]; | ||
| 157 | if (base_move(m) == bb) | ||
| 158 | b[0] = (b[0]+1+m-base_move(m)) % 4; | ||
| 159 | else | ||
| 160 | b[1] = (b[1]+1+m-base_move(m)) % 4; | ||
| 161 | } | ||
| 162 | |||
| 163 | for (k = 0; k < 2; k++) { | ||
| 164 | if (b[k] != 0) { | ||
| 165 | ret->move[n] = bb + b[k] - 1 + 3*k; | ||
| 166 | ret->inv[n] = ret->inv[i]; | ||
| 167 | n++; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | L = ret->len; | ||
| 173 | ret->len = n; | ||
| 174 | } while (L != n); | ||
| 175 | |||
| 176 | return ret; | ||
| 177 | } | ||
| 178 | |||
| 179 | static void | ||
| 180 | cleanup_aux(Alg *alg, Alg *ret, bool inv) | ||
| 181 | { | ||
| 182 | int i, j; | ||
| 183 | Cube c, d; | ||
| 184 | Move m; | ||
| 185 | Alg *equiv_alg; | ||
| 186 | |||
| 187 | make_solved(&c); | ||
| 188 | for (i = 0; i < alg->len; i++) { | ||
| 189 | if (alg->inv[i] != inv) | ||
| 190 | continue; | ||
| 191 | |||
| 192 | equiv_alg = new_alg(equiv_alg_string[alg->move[i]]); | ||
| 193 | |||
| 194 | for (j = 0; j < equiv_alg->len; j++) | ||
| 195 | if (equiv_alg->move[j] == U) | ||
| 196 | append_move(ret, 3 * c.xp[U_center] + 1, inv); | ||
| 197 | else | ||
| 198 | apply_move(equiv_alg->move[j], &c); | ||
| 199 | |||
| 200 | free_alg(equiv_alg); | ||
| 201 | } | ||
| 202 | |||
| 203 | m = NULLMOVE; | ||
| 204 | switch (c.xp[F_center]) { | ||
| 205 | case U_center: | ||
| 206 | m = x3; | ||
| 207 | break; | ||
| 208 | case D_center: | ||
| 209 | m = x; | ||
| 210 | break; | ||
| 211 | case R_center: | ||
| 212 | m = y; | ||
| 213 | break; | ||
| 214 | case L_center: | ||
| 215 | m = y3; | ||
| 216 | break; | ||
| 217 | case B_center: | ||
| 218 | if (c.xp[U_center] == U_center) | ||
| 219 | m = y2; | ||
| 220 | else | ||
| 221 | m = x2; | ||
| 222 | break; | ||
| 223 | default: | ||
| 224 | break; | ||
| 225 | } | ||
| 226 | |||
| 227 | make_solved(&d); | ||
| 228 | apply_move(m, &d); | ||
| 229 | if (m != NULLMOVE) | ||
| 230 | append_move(ret, m, inv); | ||
| 231 | |||
| 232 | m = NULLMOVE; | ||
| 233 | if (c.xp[U_center] == d.xp[D_center]) { | ||
| 234 | m = z2; | ||
| 235 | } else if (c.xp[U_center] == d.xp[R_center]) { | ||
| 236 | m = z3; | ||
| 237 | } else if (c.xp[U_center] == d.xp[L_center]) { | ||
| 238 | m = z; | ||
| 239 | } | ||
| 240 | if (m != NULLMOVE) | ||
| 241 | append_move(ret, m, inv); | ||
| 242 | } | ||
| 243 | |||
| 244 | void | ||
| 245 | init_moves() { | ||
| 246 | static bool initialized = false; | ||
| 247 | if (initialized) | ||
| 248 | return; | ||
| 249 | initialized = true; | ||
| 250 | |||
| 251 | Move m; | ||
| 252 | Alg *equiv_alg[NMOVES]; | ||
| 253 | |||
| 254 | static const Cube mcu = { | ||
| 255 | .ep = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR }, | ||
| 256 | .cp = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR }, | ||
| 257 | }; | ||
| 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 | |||
| 275 | move_array[U] = mcu; | ||
| 276 | move_array[x] = mcx; | ||
| 277 | move_array[y] = mcy; | ||
| 278 | |||
| 279 | for (m = 0; m < NMOVES; m++) | ||
| 280 | equiv_alg[m] = new_alg(equiv_alg_string[m]); | ||
| 281 | |||
| 282 | for (m = 0; m < NMOVES; m++) { | ||
| 283 | switch (m) { | ||
| 284 | case NULLMOVE: | ||
| 285 | make_solved(&move_array[m]); | ||
| 286 | break; | ||
| 287 | case U: | ||
| 288 | case x: | ||
| 289 | case y: | ||
| 290 | break; | ||
| 291 | default: | ||
| 292 | make_solved(&move_array[m]); | ||
| 293 | apply_alg(equiv_alg[m], &move_array[m]); | ||
| 294 | break; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | for (m = 0; m < NMOVES; m++) | ||
| 299 | free_alg(equiv_alg[m]); | ||
| 300 | } | ||
| 301 | |||
diff --git a/src/moves.h b/src/moves.h deleted file mode 100644 index 4e8be7f..0000000 --- a/src/moves.h +++ /dev/null | |||
| @@ -1,17 +0,0 @@ | |||
| 1 | #ifndef MOVES_H | ||
| 2 | #define MOVES_H | ||
| 3 | |||
| 4 | #include "alg.h" | ||
| 5 | #include "cube.h" | ||
| 6 | #include "env.h" | ||
| 7 | |||
| 8 | void apply_alg(Alg *alg, Cube *cube); | ||
| 9 | void apply_move(Move m, Cube *cube); | ||
| 10 | void apply_move_centers(Move m, Cube *cube); | ||
| 11 | void apply_move_corners(Move m, Cube *cube); | ||
| 12 | void apply_move_edges(Move m, Cube *cube); | ||
| 13 | Alg * cleanup(Alg *alg); | ||
| 14 | |||
| 15 | void init_moves(); | ||
| 16 | |||
| 17 | #endif | ||
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/pruning.c b/src/pruning.c deleted file mode 100644 index 3cc9152..0000000 --- a/src/pruning.c +++ /dev/null | |||
| @@ -1,400 +0,0 @@ | |||
| 1 | #define PRUNING_C | ||
| 2 | |||
| 3 | #include "pruning.h" | ||
| 4 | |||
| 5 | #define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) | ||
| 6 | #define ENTRIES_PER_GROUP_COMPACT (4*sizeof(entry_group_t)) | ||
| 7 | |||
| 8 | static int findchunk(PruneData *pd, int nchunks, uint64_t i); | ||
| 9 | static void genptable_bfs(PruneData *pd, int d, int nt, int nc); | ||
| 10 | static void genptable_fixnasty(PruneData *pd, int d, int nthreads); | ||
| 11 | static void * instance_bfs(void *arg); | ||
| 12 | static void * instance_fixnasty(void *arg); | ||
| 13 | static void ptable_update(PruneData *pd, uint64_t ind, int m); | ||
| 14 | static bool read_ptable_file(PruneData *pd); | ||
| 15 | static bool write_ptable_file(PruneData *pd); | ||
| 16 | |||
| 17 | PruneData *active_pd[256]; | ||
| 18 | |||
| 19 | int | ||
| 20 | findchunk(PruneData *pd, int nchunks, uint64_t i) | ||
| 21 | { | ||
| 22 | uint64_t chunksize; | ||
| 23 | |||
| 24 | chunksize = pd->coord->max / (uint64_t)nchunks; | ||
| 25 | chunksize += ENTRIES_PER_GROUP - (chunksize % ENTRIES_PER_GROUP); | ||
| 26 | |||
| 27 | return MIN(nchunks-1, (int)(i / chunksize)); | ||
| 28 | } | ||
| 29 | |||
| 30 | PruneData * | ||
| 31 | genptable(PruneData *pd, int nthreads) | ||
| 32 | { | ||
| 33 | int d, nchunks, i, maxv; | ||
| 34 | uint64_t oldn; | ||
| 35 | |||
| 36 | for (i = 0; active_pd[i] != NULL; i++) { | ||
| 37 | if (active_pd[i]->coord == pd->coord && | ||
| 38 | active_pd[i]->moveset == pd->moveset && | ||
| 39 | active_pd[i]->compact == pd->compact) | ||
| 40 | return active_pd[i]; | ||
| 41 | } | ||
| 42 | |||
| 43 | init_moveset(pd->moveset); | ||
| 44 | gen_coord(pd->coord); | ||
| 45 | |||
| 46 | pd->ptable = malloc(ptablesize(pd) * sizeof(entry_group_t)); | ||
| 47 | |||
| 48 | if (read_ptable_file(pd)) | ||
| 49 | goto genptable_done; | ||
| 50 | |||
| 51 | if (nthreads < 4) { | ||
| 52 | fprintf(stderr, | ||
| 53 | "--- Warning ---\n" | ||
| 54 | "You are using only %d threads to generate the pruning" | ||
| 55 | "tables. This can take a while.\n" | ||
| 56 | "Unless you did this intentionally, you should re-run" | ||
| 57 | "this command with `-t 4' or more.\n" | ||
| 58 | "---------------\n\n", nthreads | ||
| 59 | ); | ||
| 60 | } | ||
| 61 | |||
| 62 | nchunks = MIN(ptablesize(pd), 100000); | ||
| 63 | fprintf(stderr, "Generating pt_%s_%s with %d threads\n", | ||
| 64 | pd->coord->name, pd->moveset->name, nthreads); | ||
| 65 | |||
| 66 | 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 | |||
| 70 | ptable_update(pd, 0, 0); | ||
| 71 | pd->n = 1; | ||
| 72 | oldn = 0; | ||
| 73 | genptable_fixnasty(pd, 0, nthreads); | ||
| 74 | fprintf(stderr, "Depth %d done, generated %" | ||
| 75 | PRIu64 "\t(%" PRIu64 "/%" PRIu64 ")\n", | ||
| 76 | 0, pd->n - oldn, pd->n, pd->coord->max); | ||
| 77 | oldn = pd->n; | ||
| 78 | pd->count[0] = pd->n; | ||
| 79 | |||
| 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); | ||
| 83 | genptable_fixnasty(pd, d+1, nthreads); | ||
| 84 | fprintf(stderr, "Depth %d done, generated %" | ||
| 85 | PRIu64 "\t(%" PRIu64 "/%" PRIu64 ")\n", | ||
| 86 | d+1, pd->n - oldn, pd->n, pd->coord->max); | ||
| 87 | pd->count[d+1] = pd->n - oldn; | ||
| 88 | oldn = pd->n; | ||
| 89 | } | ||
| 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"); | ||
| 94 | |||
| 95 | if (!write_ptable_file(pd)) | ||
| 96 | 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 | } | ||
| 102 | |||
| 103 | static void | ||
| 104 | genptable_bfs(PruneData *pd, int d, int nthreads, int nchunks) | ||
| 105 | { | ||
| 106 | int i; | ||
| 107 | pthread_t t[nthreads]; | ||
| 108 | ThreadDataGenpt td[nthreads]; | ||
| 109 | pthread_mutex_t *mtx[nchunks], *upmtx; | ||
| 110 | |||
| 111 | upmtx = malloc(sizeof(pthread_mutex_t)); | ||
| 112 | pthread_mutex_init(upmtx, NULL); | ||
| 113 | for (i = 0; i < nchunks; i++) { | ||
| 114 | mtx[i] = malloc(sizeof(pthread_mutex_t)); | ||
| 115 | pthread_mutex_init(mtx[i], NULL); | ||
| 116 | } | ||
| 117 | |||
| 118 | for (i = 0; i < nthreads; i++) { | ||
| 119 | td[i].thid = i; | ||
| 120 | td[i].nthreads = nthreads; | ||
| 121 | td[i].pd = pd; | ||
| 122 | td[i].d = d; | ||
| 123 | td[i].nchunks = nchunks; | ||
| 124 | td[i].mutex = mtx; | ||
| 125 | td[i].upmutex = upmtx; | ||
| 126 | pthread_create(&t[i], NULL, instance_bfs, &td[i]); | ||
| 127 | } | ||
| 128 | |||
| 129 | for (i = 0; i < nthreads; i++) | ||
| 130 | pthread_join(t[i], NULL); | ||
| 131 | |||
| 132 | free(upmtx); | ||
| 133 | for (i = 0; i < nchunks; i++) | ||
| 134 | free(mtx[i]); | ||
| 135 | } | ||
| 136 | |||
| 137 | static void | ||
| 138 | genptable_fixnasty(PruneData *pd, int d, int nthreads) | ||
| 139 | { | ||
| 140 | int i; | ||
| 141 | pthread_t t[nthreads]; | ||
| 142 | ThreadDataGenpt td[nthreads]; | ||
| 143 | pthread_mutex_t *upmtx; | ||
| 144 | |||
| 145 | if (pd->coord->type != SYMCOMP_COORD) | ||
| 146 | return; | ||
| 147 | |||
| 148 | upmtx = malloc(sizeof(pthread_mutex_t)); | ||
| 149 | pthread_mutex_init(upmtx, NULL); | ||
| 150 | for (i = 0; i < nthreads; i++) { | ||
| 151 | td[i].thid = i; | ||
| 152 | td[i].nthreads = nthreads; | ||
| 153 | td[i].pd = pd; | ||
| 154 | td[i].d = d; | ||
| 155 | td[i].upmutex = upmtx; | ||
| 156 | pthread_create(&t[i], NULL, instance_fixnasty, &td[i]); | ||
| 157 | } | ||
| 158 | |||
| 159 | for (i = 0; i < nthreads; i++) | ||
| 160 | pthread_join(t[i], NULL); | ||
| 161 | |||
| 162 | free(upmtx); | ||
| 163 | } | ||
| 164 | |||
| 165 | static void * | ||
| 166 | instance_bfs(void *arg) | ||
| 167 | { | ||
| 168 | ThreadDataGenpt *td; | ||
| 169 | uint64_t i, ii, blocksize, rmin, rmax, updated; | ||
| 170 | int j, pval, ichunk, oldc, newc; | ||
| 171 | Move *ms; | ||
| 172 | |||
| 173 | td = (ThreadDataGenpt *)arg; | ||
| 174 | ms = td->pd->moveset->sorted_moves; | ||
| 175 | blocksize = td->pd->coord->max / (uint64_t)td->nthreads; | ||
| 176 | rmin = ((uint64_t)td->thid) * blocksize; | ||
| 177 | rmax = td->thid == td->nthreads - 1 ? | ||
| 178 | td->pd->coord->max : | ||
| 179 | ((uint64_t)td->thid + 1) * blocksize; | ||
| 180 | |||
| 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; | ||
| 195 | for (i = rmin; i < rmax; i++) { | ||
| 196 | ichunk = findchunk(td->pd, td->nchunks, i); | ||
| 197 | pthread_mutex_lock(td->mutex[ichunk]); | ||
| 198 | pval = ptableval(td->pd, i); | ||
| 199 | pthread_mutex_unlock(td->mutex[ichunk]); | ||
| 200 | if (pval == oldc) { | ||
| 201 | for (j = 0; ms[j] != NULLMOVE; j++) { | ||
| 202 | ii = move_coord(td->pd->coord, ms[j], i, NULL); | ||
| 203 | ichunk = findchunk(td->pd, td->nchunks, ii); | ||
| 204 | pthread_mutex_lock(td->mutex[ichunk]); | ||
| 205 | pval = ptableval(td->pd, ii); | ||
| 206 | if (pval > newc) { | ||
| 207 | ptable_update(td->pd, ii, newc); | ||
| 208 | updated++; | ||
| 209 | } | ||
| 210 | pthread_mutex_unlock(td->mutex[ichunk]); | ||
| 211 | } | ||
| 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 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | pthread_mutex_lock(td->upmutex); | ||
| 222 | td->pd->n += updated; | ||
| 223 | pthread_mutex_unlock(td->upmutex); | ||
| 224 | |||
| 225 | return NULL; | ||
| 226 | } | ||
| 227 | |||
| 228 | static void * | ||
| 229 | instance_fixnasty(void *arg) | ||
| 230 | { | ||
| 231 | ThreadDataGenpt *td; | ||
| 232 | uint64_t i, ii, blocksize, rmin, rmax, updated, ss, M; | ||
| 233 | int j, oldc; | ||
| 234 | Trans t; | ||
| 235 | |||
| 236 | td = (ThreadDataGenpt *)arg; | ||
| 237 | |||
| 238 | /* We know type = SYMCOMP_COORD */ | ||
| 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; | ||
| 242 | rmax = td->thid == td->nthreads - 1 ? | ||
| 243 | td->pd->coord->max : | ||
| 244 | ((uint64_t)td->thid + 1) * blocksize; | ||
| 245 | |||
| 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; | ||
| 256 | for (i = rmin; i < rmax; i++) { | ||
| 257 | if (ptableval(td->pd, i) == oldc) { | ||
| 258 | ss = td->pd->coord->base[0]->selfsim[i/M]; | ||
| 259 | for (j = 0; j < td->pd->coord->base[0]->tgrp->n; j++) { | ||
| 260 | t = td->pd->coord->base[0]->tgrp->t[j]; | ||
| 261 | if (t == uf || !(ss & ((uint64_t)1<<t))) | ||
| 262 | continue; | ||
| 263 | ii = trans_coord(td->pd->coord, t, i); | ||
| 264 | if (ptableval(td->pd, ii) > oldc) { | ||
| 265 | ptable_update(td->pd, ii, oldc); | ||
| 266 | updated++; | ||
| 267 | } | ||
| 268 | } | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | pthread_mutex_lock(td->upmutex); | ||
| 273 | td->pd->n += updated; | ||
| 274 | pthread_mutex_unlock(td->upmutex); | ||
| 275 | |||
| 276 | return NULL; | ||
| 277 | } | ||
| 278 | |||
| 279 | void | ||
| 280 | print_ptable(PruneData *pd) | ||
| 281 | { | ||
| 282 | uint64_t i; | ||
| 283 | |||
| 284 | printf("Table %s_%s\n", pd->coord->name, pd->moveset->name); | ||
| 285 | |||
| 286 | if (pd->compact) { | ||
| 287 | printf("Compract table with base value: %d\n", pd->base); | ||
| 288 | printf("Values above %d are inaccurate.\n", pd->base + 3); | ||
| 289 | } | ||
| 290 | |||
| 291 | for (i = 0; i < 16; i++) | ||
| 292 | printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]); | ||
| 293 | } | ||
| 294 | |||
| 295 | uint64_t | ||
| 296 | ptablesize(PruneData *pd) | ||
| 297 | { | ||
| 298 | uint64_t e; | ||
| 299 | |||
| 300 | e = pd->compact ? ENTRIES_PER_GROUP_COMPACT : ENTRIES_PER_GROUP; | ||
| 301 | |||
| 302 | return (pd->coord->max + e - 1) / e; | ||
| 303 | } | ||
| 304 | |||
| 305 | static void | ||
| 306 | ptable_update(PruneData *pd, uint64_t ind, int n) | ||
| 307 | { | ||
| 308 | int sh; | ||
| 309 | entry_group_t f, mask; | ||
| 310 | uint64_t i, e, b; | ||
| 311 | |||
| 312 | e = pd->compact ? ENTRIES_PER_GROUP_COMPACT : ENTRIES_PER_GROUP; | ||
| 313 | b = pd->compact ? 2 : 4; | ||
| 314 | f = pd->compact ? 3 : 15; | ||
| 315 | |||
| 316 | sh = b * (ind % e); | ||
| 317 | mask = f << sh; | ||
| 318 | i = ind / e; | ||
| 319 | |||
| 320 | pd->ptable[i] &= ~mask; | ||
| 321 | pd->ptable[i] |= (((entry_group_t)n) & f) << sh; | ||
| 322 | } | ||
| 323 | |||
| 324 | int | ||
| 325 | ptableval(PruneData *pd, uint64_t ind) | ||
| 326 | { | ||
| 327 | int sh; | ||
| 328 | uint64_t e; | ||
| 329 | entry_group_t m; | ||
| 330 | |||
| 331 | if (pd->compact) { | ||
| 332 | e = ENTRIES_PER_GROUP_COMPACT; | ||
| 333 | m = 3; | ||
| 334 | sh = (ind % e) * 2; | ||
| 335 | } else { | ||
| 336 | e = ENTRIES_PER_GROUP; | ||
| 337 | m = 15; | ||
| 338 | sh = (ind % e) * 4; | ||
| 339 | } | ||
| 340 | |||
| 341 | return (pd->ptable[ind/e] & (m << sh)) >> sh; | ||
| 342 | } | ||
| 343 | |||
| 344 | static bool | ||
| 345 | read_ptable_file(PruneData *pd) | ||
| 346 | { | ||
| 347 | init_env(); | ||
| 348 | |||
| 349 | FILE *f; | ||
| 350 | char fname[strlen(tabledir)+256]; | ||
| 351 | int i; | ||
| 352 | uint64_t r; | ||
| 353 | |||
| 354 | strcpy(fname, tabledir); | ||
| 355 | strcat(fname, "/pt_"); | ||
| 356 | strcat(fname, pd->coord->name); | ||
| 357 | strcat(fname, "_"); | ||
| 358 | strcat(fname, pd->moveset->name); | ||
| 359 | |||
| 360 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 361 | return false; | ||
| 362 | |||
| 363 | r = fread(&(pd->base), sizeof(int), 1, f); | ||
| 364 | for (i = 0; i < 16; i++) | ||
| 365 | r += fread(&(pd->count[i]), sizeof(uint64_t), 1, f); | ||
| 366 | r += fread(pd->ptable, sizeof(entry_group_t), ptablesize(pd), f); | ||
| 367 | |||
| 368 | fclose(f); | ||
| 369 | |||
| 370 | return r == 17 + ptablesize(pd); | ||
| 371 | } | ||
| 372 | |||
| 373 | static bool | ||
| 374 | write_ptable_file(PruneData *pd) | ||
| 375 | { | ||
| 376 | init_env(); | ||
| 377 | |||
| 378 | FILE *f; | ||
| 379 | char fname[strlen(tabledir)+256]; | ||
| 380 | int i; | ||
| 381 | uint64_t w; | ||
| 382 | |||
| 383 | strcpy(fname, tabledir); | ||
| 384 | strcat(fname, "/pt_"); | ||
| 385 | strcat(fname, pd->coord->name); | ||
| 386 | strcat(fname, "_"); | ||
| 387 | strcat(fname, pd->moveset->name); | ||
| 388 | |||
| 389 | if ((f = fopen(fname, "wb")) == NULL) | ||
| 390 | return false; | ||
| 391 | |||
| 392 | w = fwrite(&(pd->base), sizeof(int), 1, f); | ||
| 393 | for (i = 0; i < 16; i++) | ||
| 394 | w += fwrite(&(pd->count[i]), sizeof(uint64_t), 1, f); | ||
| 395 | w += fwrite(pd->ptable, sizeof(entry_group_t), ptablesize(pd), f); | ||
| 396 | fclose(f); | ||
| 397 | |||
| 398 | return w == 17 + ptablesize(pd); | ||
| 399 | } | ||
| 400 | |||
diff --git a/src/pruning.h b/src/pruning.h deleted file mode 100644 index 93ae863..0000000 --- a/src/pruning.h +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | #ifndef PRUNING_H | ||
| 2 | #define PRUNING_H | ||
| 3 | |||
| 4 | #include "coord.h" | ||
| 5 | #include "movesets.h" | ||
| 6 | |||
| 7 | void free_pd(PruneData *pd); | ||
| 8 | PruneData * genptable(PruneData *data, int nthreads); | ||
| 9 | void print_ptable(PruneData *pd); | ||
| 10 | uint64_t ptablesize(PruneData *pd); | ||
| 11 | int ptableval(PruneData *pd, uint64_t ind); | ||
| 12 | |||
| 13 | extern PruneData *active_pd[256]; | ||
| 14 | |||
| 15 | #endif | ||
| 16 | |||
diff --git a/src/shell.c b/src/shell.c deleted file mode 100644 index 4faa0a8..0000000 --- a/src/shell.c +++ /dev/null | |||
| @@ -1,177 +0,0 @@ | |||
| 1 | #define SHELL_C | ||
| 2 | |||
| 3 | #include "shell.h" | ||
| 4 | |||
| 5 | static void cleanwhitespaces(char *line); | ||
| 6 | static int parseline(char *line, char **v); | ||
| 7 | |||
| 8 | bool | ||
| 9 | checkfiles() | ||
| 10 | { | ||
| 11 | /* TODO: add more checks (other files, use checksum...) */ | ||
| 12 | /* How to check for pruning tables with new method? */ | ||
| 13 | /* Solution: use list of steps */ | ||
| 14 | /* | ||
| 15 | char fname[strlen(tabledir)+100]; | ||
| 16 | int i; | ||
| 17 | |||
| 18 | for (i = 0; all_pd[i] != NULL; i++) { | ||
| 19 | strcpy(fname, tabledir); | ||
| 20 | strcat(fname, "/"); | ||
| 21 | strcat(fname, all_pd[i]->filename); | ||
| 22 | if ((f = fopen(fname, "rb")) == NULL) | ||
| 23 | return false; | ||
| 24 | else | ||
| 25 | fclose(f); | ||
| 26 | } | ||
| 27 | */ | ||
| 28 | |||
| 29 | return true; | ||
| 30 | } | ||
| 31 | |||
| 32 | static void | ||
| 33 | cleanwhitespaces(char *line) | ||
| 34 | { | ||
| 35 | char *i; | ||
| 36 | |||
| 37 | for (i = line; *i != 0; i++) | ||
| 38 | if (*i == '\t' || *i == '\n') | ||
| 39 | *i = ' '; | ||
| 40 | } | ||
| 41 | |||
| 42 | /* This function assumes that **v is large enough */ | ||
| 43 | static int | ||
| 44 | parseline(char *line, char **v) | ||
| 45 | { | ||
| 46 | char *t; | ||
| 47 | int n = 0; | ||
| 48 | |||
| 49 | cleanwhitespaces(line); | ||
| 50 | |||
| 51 | for (t = strtok(line, " "); t != NULL; t = strtok(NULL, " ")) | ||
| 52 | strcpy(v[n++], t); | ||
| 53 | |||
| 54 | return n; | ||
| 55 | } | ||
| 56 | |||
| 57 | void | ||
| 58 | exec_args(int c, char **v) | ||
| 59 | { | ||
| 60 | int i; | ||
| 61 | char line[MAXLINELEN]; | ||
| 62 | Command *cmd = NULL; | ||
| 63 | CommandArgs *args; | ||
| 64 | Alg *scramble; | ||
| 65 | |||
| 66 | for (i = 0; commands[i] != NULL; i++) | ||
| 67 | if (!strcmp(v[0], commands[i]->name)) | ||
| 68 | cmd = commands[i]; | ||
| 69 | |||
| 70 | if (cmd == NULL) { | ||
| 71 | fprintf(stderr, "%s: command not found\n", v[0]); | ||
| 72 | return; | ||
| 73 | } | ||
| 74 | |||
| 75 | args = cmd->parse_args(c-1, &v[1]); | ||
| 76 | if (!args->success) { | ||
| 77 | fprintf(stderr, "usage: %s\n", cmd->usage); | ||
| 78 | return; | ||
| 79 | } | ||
| 80 | |||
| 81 | if (args->scrstdin) { | ||
| 82 | while (true) { | ||
| 83 | if (fgets(line, MAXLINELEN, stdin) == NULL) { | ||
| 84 | clearerr(stdin); | ||
| 85 | break; | ||
| 86 | } | ||
| 87 | |||
| 88 | scramble = new_alg(line); | ||
| 89 | |||
| 90 | printf(">>> Line: %s", line); | ||
| 91 | |||
| 92 | if (scramble != NULL && scramble->len > 0) { | ||
| 93 | args->scramble = scramble; | ||
| 94 | cmd->exec(args); | ||
| 95 | free_alg(scramble); | ||
| 96 | args->scramble = NULL; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | } else { | ||
| 100 | cmd->exec(args); | ||
| 101 | } | ||
| 102 | free_args(args); | ||
| 103 | } | ||
| 104 | |||
| 105 | void | ||
| 106 | launch(bool batchmode) | ||
| 107 | { | ||
| 108 | int i, shell_argc; | ||
| 109 | char line[MAXLINELEN], **shell_argv; | ||
| 110 | |||
| 111 | shell_argv = malloc(MAXNTOKENS * sizeof(char *)); | ||
| 112 | for (i = 0; i < MAXNTOKENS; i++) | ||
| 113 | shell_argv[i] = malloc((MAXTOKENLEN+1) * sizeof(char)); | ||
| 114 | |||
| 115 | if (!batchmode) { | ||
| 116 | fprintf(stderr, "Welcome to Nissy "VERSION".\n" | ||
| 117 | "Type \"commands\" for a list of commands.\n"); | ||
| 118 | } | ||
| 119 | |||
| 120 | while (true) { | ||
| 121 | if (!batchmode) { | ||
| 122 | fprintf(stdout, "nissy-# "); | ||
| 123 | } | ||
| 124 | |||
| 125 | if (fgets(line, MAXLINELEN, stdin) == NULL) | ||
| 126 | break; | ||
| 127 | |||
| 128 | if (batchmode) { | ||
| 129 | printf(">>>\n" | ||
| 130 | ">>> Executing command: %s" | ||
| 131 | ">>>\n", line); | ||
| 132 | } | ||
| 133 | |||
| 134 | shell_argc = parseline(line, shell_argv); | ||
| 135 | |||
| 136 | if (shell_argc > 0) | ||
| 137 | exec_args(shell_argc, shell_argv); | ||
| 138 | } | ||
| 139 | |||
| 140 | for (i = 0; i < MAXNTOKENS; i++) | ||
| 141 | free(shell_argv[i]); | ||
| 142 | free(shell_argv); | ||
| 143 | } | ||
| 144 | |||
| 145 | #ifndef TEST | ||
| 146 | int | ||
| 147 | main(int argc, char *argv[]) | ||
| 148 | { | ||
| 149 | char *closing_cmd[1] = { "freemem" }; | ||
| 150 | |||
| 151 | init_env(); | ||
| 152 | init_trans(); | ||
| 153 | |||
| 154 | if (!checkfiles()) { | ||
| 155 | fprintf(stderr, | ||
| 156 | "--- Warning ---\n" | ||
| 157 | "Some pruning tables are missing or unreadable\n" | ||
| 158 | "You can generate them with `nissy gen'.\n" | ||
| 159 | "---------------\n\n" | ||
| 160 | ); | ||
| 161 | } | ||
| 162 | |||
| 163 | if (argc > 1) { | ||
| 164 | if (!strcmp(argv[1], "-b")) { | ||
| 165 | launch(true); | ||
| 166 | } else { | ||
| 167 | exec_args(argc-1, &argv[1]); | ||
| 168 | } | ||
| 169 | } else { | ||
| 170 | launch(false); | ||
| 171 | } | ||
| 172 | |||
| 173 | exec_args(1, closing_cmd); | ||
| 174 | |||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | #endif | ||
diff --git a/src/shell.h b/src/shell.h deleted file mode 100644 index 7e4f785..0000000 --- a/src/shell.h +++ /dev/null | |||
| @@ -1,14 +0,0 @@ | |||
| 1 | #ifndef SHELL_H | ||
| 2 | #define SHELL_H | ||
| 3 | |||
| 4 | #include "commands.h" | ||
| 5 | |||
| 6 | #define MAXLINELEN 10000 | ||
| 7 | #define MAXTOKENLEN 255 | ||
| 8 | #define MAXNTOKENS 255 | ||
| 9 | |||
| 10 | bool checkfiles(); | ||
| 11 | void exec_args(int c, char **v); | ||
| 12 | void launch(bool batchmode); | ||
| 13 | |||
| 14 | #endif | ||
diff --git a/src/solve.c b/src/solve.c deleted file mode 100644 index 2d0c94d..0000000 --- a/src/solve.c +++ /dev/null | |||
| @@ -1,122 +0,0 @@ | |||
| 1 | #define SOLVE_C | ||
| 2 | |||
| 3 | #include "solve.h" | ||
| 4 | |||
| 5 | void | ||
| 6 | dfs(DfsArg *arg, Solver *solver, Threader *threader) | ||
| 7 | { | ||
| 8 | int i; | ||
| 9 | DfsArg newarg; | ||
| 10 | Alg *sol; | ||
| 11 | Move m; | ||
| 12 | |||
| 13 | if (arg->current_alg->len > arg->d) | ||
| 14 | return; | ||
| 15 | |||
| 16 | if (solver->is_solved(solver->param, arg->cubedata)) { | ||
| 17 | /* TODO: the "all" option should be re-implemented as setting | ||
| 18 | validate to null */ | ||
| 19 | |||
| 20 | /* TODO: we also have to check if cancel with NISS; | ||
| 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 | |||
| 27 | if (accepted && !too_short) { | ||
| 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 | } | ||
| 34 | return; | ||
| 35 | } | ||
| 36 | |||
| 37 | if (arg->current_alg->len == arg->d) | ||
| 38 | return; | ||
| 39 | |||
| 40 | /* TODO: do not alloc */ | ||
| 41 | newarg.cubedata = solver->alloc_cubedata(solver->param); | ||
| 42 | for (i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) { | ||
| 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 | |||
| 48 | solver->copy_cubedata( | ||
| 49 | solver->param, arg->cubedata, newarg.cubedata); | ||
| 50 | newarg.threaddata = arg->threaddata; | ||
| 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 | |||
| 59 | remove_last_move(arg->current_alg); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | solver->free_cubedata(solver->param, newarg.cubedata); | ||
| 63 | |||
| 64 | if (arg->opts->can_niss && !arg->niss && | ||
| 65 | solver->niss_makes_sense( | ||
| 66 | solver->param, arg->cubedata, arg->current_alg)) { | ||
| 67 | solver->invert_cube(solver->param, arg->cubedata); | ||
| 68 | arg->niss = true; | ||
| 69 | dfs(arg, solver, threader); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | AlgList * | ||
| 74 | solve(Cube *cube, SolveOptions *opts, Solver **solver, Threader *threader) | ||
| 75 | { | ||
| 76 | int i, d, optimal; | ||
| 77 | bool ready[MAX_SOLVERS], stop, one_ready; | ||
| 78 | DfsArg arg[MAX_SOLVERS]; | ||
| 79 | AlgList *sols; | ||
| 80 | |||
| 81 | one_ready = false; | ||
| 82 | for (i = 0; solver[i] != NULL; i++) { | ||
| 83 | arg[i].cubedata = | ||
| 84 | solver[i]->prepare_cube(solver[i]->param, cube); | ||
| 85 | arg[i].opts = opts; | ||
| 86 | ready[i] = arg[i].cubedata != NULL; | ||
| 87 | one_ready = one_ready || ready[i]; | ||
| 88 | } | ||
| 89 | |||
| 90 | sols = new_alglist(); | ||
| 91 | if (!one_ready) { | ||
| 92 | fprintf(stderr, "Cube not ready for solving\n"); | ||
| 93 | return sols; | ||
| 94 | } | ||
| 95 | |||
| 96 | optimal = opts->max_moves; | ||
| 97 | stop = false; | ||
| 98 | for (d = opts->min_moves; d <= opts->max_moves && !stop; d++) { | ||
| 99 | if (opts->verbose) | ||
| 100 | fprintf(stderr, "Searching depth %d\n", d); | ||
| 101 | |||
| 102 | for (i = 0; solver[i] != NULL && !stop; i++) { | ||
| 103 | if (!ready[i]) | ||
| 104 | continue; | ||
| 105 | |||
| 106 | arg[i].d = d; | ||
| 107 | threader->dispatch(&arg[i], sols, solver[i], threader); | ||
| 108 | |||
| 109 | if (sols->len > 0) | ||
| 110 | optimal = MIN(optimal, d); | ||
| 111 | |||
| 112 | stop = sols->len >= opts->max_solutions; | ||
| 113 | } | ||
| 114 | stop = stop || | ||
| 115 | (opts->optimal != -1 && d >= opts->optimal + optimal); | ||
| 116 | } | ||
| 117 | |||
| 118 | /* TODO: some cleanup (free cubedata) */ | ||
| 119 | /* TODO: actually, preparation should be done somewhere else */ | ||
| 120 | |||
| 121 | return sols; | ||
| 122 | } | ||
diff --git a/src/solve.h b/src/solve.h deleted file mode 100644 index 8182887..0000000 --- a/src/solve.h +++ /dev/null | |||
| @@ -1,54 +0,0 @@ | |||
| 1 | #ifndef SOLVE_H | ||
| 2 | #define SOLVE_H | ||
| 3 | |||
| 4 | #include "moves.h" | ||
| 5 | |||
| 6 | #define MAX_SOLVERS 99 | ||
| 7 | |||
| 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 | |||
| 54 | #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 deleted file mode 100644 index cdba763..0000000 --- a/src/steps.c +++ /dev/null | |||
| @@ -1,177 +0,0 @@ | |||
| 1 | #define STEPS_C | ||
| 2 | |||
| 3 | #include "steps.h" | ||
| 4 | |||
| 5 | /* TODO: change all checkers to use coordinates! */ | ||
| 6 | |||
| 7 | bool | ||
| 8 | check_centers(Cube *cube) | ||
| 9 | { | ||
| 10 | int i; | ||
| 11 | |||
| 12 | for (i = 0; i < 6; i++) | ||
| 13 | if (cube->xp[i] != i) | ||
| 14 | return false; | ||
| 15 | |||
| 16 | return true; | ||
| 17 | } | ||
| 18 | |||
| 19 | bool | ||
| 20 | check_coud_HTM(Cube *cube) | ||
| 21 | { | ||
| 22 | int i; | ||
| 23 | |||
| 24 | for (i = 0; i < 8; i++) | ||
| 25 | if (cube->co[i] != 0) | ||
| 26 | return false; | ||
| 27 | |||
| 28 | return true; | ||
| 29 | } | ||
| 30 | |||
| 31 | bool | ||
| 32 | check_coud_URF(Cube *cube) | ||
| 33 | { | ||
| 34 | Cube c2, c3; | ||
| 35 | |||
| 36 | copy_cube(cube, &c2); | ||
| 37 | copy_cube(cube, &c3); | ||
| 38 | |||
| 39 | apply_move(z, &c2); | ||
| 40 | apply_move(x, &c3); | ||
| 41 | |||
| 42 | return check_coud_HTM(cube) || | ||
| 43 | check_coud_HTM(&c2) || | ||
| 44 | check_coud_HTM(&c3); | ||
| 45 | } | ||
| 46 | |||
| 47 | bool | ||
| 48 | check_cp_HTM(Cube *cube) | ||
| 49 | { | ||
| 50 | int i; | ||
| 51 | |||
| 52 | for (i = 0; i < 8; i++) | ||
| 53 | if (cube->cp[i] != i) | ||
| 54 | return false; | ||
| 55 | |||
| 56 | return true; | ||
| 57 | } | ||
| 58 | |||
| 59 | bool | ||
| 60 | check_corners_HTM(Cube *cube) | ||
| 61 | { | ||
| 62 | return check_coud_HTM(cube) && check_cp_HTM(cube); | ||
| 63 | } | ||
| 64 | |||
| 65 | bool | ||
| 66 | check_corners_URF(Cube *cube) | ||
| 67 | { | ||
| 68 | Cube c; | ||
| 69 | Trans i; | ||
| 70 | |||
| 71 | for (i = 0; i < NROTATIONS; i++) { | ||
| 72 | copy_cube(cube, &c); | ||
| 73 | apply_alg(rotation_alg(i), &c); | ||
| 74 | if (check_corners_HTM(&c)) | ||
| 75 | return true; | ||
| 76 | } | ||
| 77 | |||
| 78 | return false; | ||
| 79 | } | ||
| 80 | |||
| 81 | bool | ||
| 82 | check_cornershtr(Cube *cube) | ||
| 83 | { | ||
| 84 | /* TODO (use coord) */ | ||
| 85 | return true; | ||
| 86 | } | ||
| 87 | |||
| 88 | bool | ||
| 89 | check_eofb(Cube *cube) | ||
| 90 | { | ||
| 91 | /* TODO (use coord) */ | ||
| 92 | return true; | ||
| 93 | } | ||
| 94 | |||
| 95 | bool | ||
| 96 | check_drud(Cube *cube) | ||
| 97 | { | ||
| 98 | /* TODO (use coord) */ | ||
| 99 | return true; | ||
| 100 | } | ||
| 101 | |||
| 102 | bool | ||
| 103 | check_htr(Cube *cube) | ||
| 104 | { | ||
| 105 | /* TODO (check_drud(cube) and coord_htr_drud == 0) */ | ||
| 106 | return true; | ||
| 107 | } | ||
| 108 | |||
| 109 | Alg * | ||
| 110 | validate_singlecw_ending(Alg *alg) | ||
| 111 | { | ||
| 112 | int i; | ||
| 113 | bool nor, inv; | ||
| 114 | Alg *ret; | ||
| 115 | Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; | ||
| 116 | |||
| 117 | for (i = 0; i < alg->len; i++) { | ||
| 118 | if (alg->inv[i]) { | ||
| 119 | l2i = l1i; | ||
| 120 | l1i = alg->move[i]; | ||
| 121 | } else { | ||
| 122 | l2 = l1; | ||
| 123 | l1 = alg->move[i]; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | 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)); | ||
| 129 | |||
| 130 | if (nor && inv) { | ||
| 131 | ret = new_alg(""); | ||
| 132 | copy_alg(alg, ret); | ||
| 133 | } else { | ||
| 134 | ret = NULL; | ||
| 135 | } | ||
| 136 | |||
| 137 | return ret; | ||
| 138 | } | ||
| 139 | |||
| 140 | /* Public functions **********************************************************/ | ||
| 141 | |||
| 142 | /* | ||
| 143 | void | ||
| 144 | compute_ind(Step *s, Cube *cube, Movable *ind) | ||
| 145 | { | ||
| 146 | int i; | ||
| 147 | Cube mvd; | ||
| 148 | Trans t, tt; | ||
| 149 | |||
| 150 | for (i = 0; i < s->n_coord; i++) { | ||
| 151 | t = s->coord_trans[i]; | ||
| 152 | copy_cube(cube, &mvd); | ||
| 153 | apply_trans(t, &mvd); | ||
| 154 | |||
| 155 | ind[i].val = index_coord(s->coord[i], &mvd, &tt); | ||
| 156 | ind[i].t = transform_trans(tt, t); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | */ | ||
| 160 | |||
| 161 | void | ||
| 162 | prepare_cs(ChoiceStep *cs, SolveOptions *opts) | ||
| 163 | { | ||
| 164 | int i, j; | ||
| 165 | Step *s; | ||
| 166 | |||
| 167 | for (i = 0; cs->step[i] != NULL; i++) { | ||
| 168 | s = cs->step[i]; | ||
| 169 | for (j = 0; j < s->n_coord; j++) { | ||
| 170 | s->pd[j] = malloc(sizeof(PruneData)); | ||
| 171 | s->pd[j]->moveset = s->moveset; | ||
| 172 | s->pd[j]->coord = s->coord[j]; | ||
| 173 | s->pd[j]->compact = s->pd_compact[j]; | ||
| 174 | s->pd[j] = genptable(s->pd[j], opts->nthreads); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | } | ||
diff --git a/src/steps.h b/src/steps.h deleted file mode 100644 index 206f8b4..0000000 --- a/src/steps.h +++ /dev/null | |||
| @@ -1,244 +0,0 @@ | |||
| 1 | #ifndef STEPS_H | ||
| 2 | #define STEPS_H | ||
| 3 | |||
| 4 | #include "pruning.h" | ||
| 5 | #include "movesets.h" | ||
| 6 | |||
| 7 | bool check_centers(Cube *cube); | ||
| 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 | |||
| 22 | #ifndef STEPS_C | ||
| 23 | |||
| 24 | extern char check_centers_msg[100]; | ||
| 25 | extern char check_eo_msg[100]; | ||
| 26 | extern char check_dr_msg[100]; | ||
| 27 | extern char check_htr_msg[100]; | ||
| 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 | |||
| 244 | #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 deleted file mode 100644 index 898c2be..0000000 --- a/src/trans.c +++ /dev/null | |||
| @@ -1,190 +0,0 @@ | |||
| 1 | #define TRANS_C | ||
| 2 | |||
| 3 | #include "trans.h" | ||
| 4 | |||
| 5 | /* Local functions ***********************************************************/ | ||
| 6 | |||
| 7 | /* Tables and other data *****************************************************/ | ||
| 8 | |||
| 9 | static Cube mirror_cube = { | ||
| 10 | .ep = { [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL, | ||
| 11 | [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL, | ||
| 12 | [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL }, | ||
| 13 | .cp = { [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL, | ||
| 14 | [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL }, | ||
| 15 | .xp = { [U_center] = U_center, [D_center] = D_center, | ||
| 16 | [R_center] = L_center, [L_center] = R_center, | ||
| 17 | [F_center] = F_center, [B_center] = B_center } | ||
| 18 | }; | ||
| 19 | |||
| 20 | static char rotation_alg_string[100][NROTATIONS] = { | ||
| 21 | [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3", | ||
| 22 | [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2", | ||
| 23 | [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3", | ||
| 24 | [lf] = "z", [ld] = "z y3", [lb] = "z y2", [lu] = "z y", | ||
| 25 | [fu] = "x y2", [fr] = "x y", [fd] = "x", [fl] = "x y3", | ||
| 26 | [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3", | ||
| 27 | }; | ||
| 28 | |||
| 29 | Alg *rotation_alg_arr[NROTATIONS]; | ||
| 30 | Move moves_ttable[NTRANS][NMOVES]; | ||
| 31 | Trans trans_ttable[NTRANS][NTRANS]; | ||
| 32 | Trans trans_itable[NTRANS]; | ||
| 33 | |||
| 34 | /* Public functions **********************************************************/ | ||
| 35 | |||
| 36 | void | ||
| 37 | apply_trans(Trans t, Cube *cube) | ||
| 38 | { | ||
| 39 | Cube aux; | ||
| 40 | Alg *inv; | ||
| 41 | int i; | ||
| 42 | |||
| 43 | inv = inverse_alg(rotation_alg(t % NROTATIONS)); | ||
| 44 | copy_cube(cube, &aux); | ||
| 45 | make_solved(cube); | ||
| 46 | |||
| 47 | if (t >= NROTATIONS) | ||
| 48 | compose(&mirror_cube, cube); | ||
| 49 | apply_alg(inv, cube); | ||
| 50 | compose(&aux, cube); | ||
| 51 | apply_alg(rotation_alg(t % NROTATIONS), cube); | ||
| 52 | if (t >= NROTATIONS) { | ||
| 53 | compose(&mirror_cube, cube); | ||
| 54 | for (i = 0; i < 8; i++) | ||
| 55 | cube->co[i] = (3 - cube->co[i]) % 3; | ||
| 56 | } | ||
| 57 | |||
| 58 | free_alg(inv); | ||
| 59 | } | ||
| 60 | |||
| 61 | /* | ||
| 62 | Trans | ||
| 63 | inverse_trans(Trans t) | ||
| 64 | { | ||
| 65 | static Trans inverse_trans_aux[NTRANS] = { | ||
| 66 | [uf] = uf, [ur] = ul, [ul] = ur, [ub] = ub, | ||
| 67 | [df] = df, [dr] = dr, [dl] = dl, [db] = db, | ||
| 68 | [rf] = lf, [rd] = bl, [rb] = rb, [ru] = fr, | ||
| 69 | [lf] = rf, [ld] = br, [lb] = lb, [lu] = fl, | ||
| 70 | [fu] = fu, [fr] = ru, [fd] = bu, [fl] = lu, | ||
| 71 | [bu] = fd, [br] = ld, [bd] = bd, [bl] = rd, | ||
| 72 | |||
| 73 | [uf_mirror] = uf_mirror, [ur_mirror] = ur_mirror, | ||
| 74 | [ul_mirror] = ul_mirror, [ub_mirror] = ub_mirror, | ||
| 75 | [df_mirror] = df_mirror, [dr_mirror] = dl_mirror, | ||
| 76 | [dl_mirror] = dr_mirror, [db_mirror] = db_mirror, | ||
| 77 | [rf_mirror] = rf_mirror, [rd_mirror] = br_mirror, | ||
| 78 | [rb_mirror] = lb_mirror, [ru_mirror] = fl_mirror, | ||
| 79 | [lf_mirror] = lf_mirror, [ld_mirror] = bl_mirror, | ||
| 80 | [lb_mirror] = rb_mirror, [lu_mirror] = fr_mirror, | ||
| 81 | [fu_mirror] = fu_mirror, [fr_mirror] = lu_mirror, | ||
| 82 | [fd_mirror] = bu_mirror, [fl_mirror] = ru_mirror, | ||
| 83 | [bu_mirror] = fd_mirror, [br_mirror] = rd_mirror, | ||
| 84 | [bd_mirror] = bd_mirror, [bl_mirror] = ld_mirror | ||
| 85 | }; | ||
| 86 | |||
| 87 | return inverse_trans_aux[t]; | ||
| 88 | } | ||
| 89 | */ | ||
| 90 | |||
| 91 | Trans | ||
| 92 | inverse_trans(Trans t) | ||
| 93 | { | ||
| 94 | return trans_itable[t]; | ||
| 95 | } | ||
| 96 | |||
| 97 | Alg * | ||
| 98 | rotation_alg(Trans i) | ||
| 99 | { | ||
| 100 | return rotation_alg_arr[i % NROTATIONS]; | ||
| 101 | } | ||
| 102 | |||
| 103 | void | ||
| 104 | transform_alg(Trans t, Alg *alg) | ||
| 105 | { | ||
| 106 | int i; | ||
| 107 | |||
| 108 | for (i = 0; i < alg->len; i++) | ||
| 109 | alg->move[i] = transform_move(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 | } | ||
| 123 | |||
| 124 | void | ||
| 125 | init_trans() { | ||
| 126 | static bool initialized = false; | ||
| 127 | if (initialized) | ||
| 128 | return; | ||
| 129 | initialized = true; | ||
| 130 | |||
| 131 | int i; | ||
| 132 | Alg *nonsym_alg, *nonsym_inv; | ||
| 133 | Cube aux, cube; | ||
| 134 | Move mi, move; | ||
| 135 | Trans t, u, v; | ||
| 136 | |||
| 137 | init_moves(); | ||
| 138 | |||
| 139 | for (i = 0; i < NROTATIONS; i++) | ||
| 140 | rotation_alg_arr[i] = new_alg(rotation_alg_string[i]); | ||
| 141 | |||
| 142 | for (t = 0; t < NTRANS; t++) { | ||
| 143 | for (mi = 0; mi < NMOVES; mi++) { | ||
| 144 | make_solved(&aux); | ||
| 145 | apply_move(mi, &aux); | ||
| 146 | apply_trans(t, &aux); | ||
| 147 | for (move = 0; move < NMOVES; move++) { | ||
| 148 | copy_cube(&aux, &cube); | ||
| 149 | apply_move(inverse_move(move), &cube); | ||
| 150 | if (is_solved(&cube)) { | ||
| 151 | moves_ttable[t][mi] = move; | ||
| 152 | break; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | nonsym_alg = new_alg("R' U' F"); | ||
| 159 | nonsym_inv = inverse_alg(nonsym_alg); | ||
| 160 | |||
| 161 | for (t = 0; t < NTRANS; t++) { | ||
| 162 | for (u = 0; u < NTRANS; u++) { | ||
| 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; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | } | ||
| 181 | } | ||
| 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 | |||
| 187 | free_alg(nonsym_alg); | ||
| 188 | free_alg(nonsym_inv); | ||
| 189 | } | ||
| 190 | |||
diff --git a/src/trans.h b/src/trans.h deleted file mode 100644 index 0cc8cef..0000000 --- a/src/trans.h +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | #ifndef TRANS_H | ||
| 2 | #define TRANS_H | ||
| 3 | |||
| 4 | #include "moves.h" | ||
| 5 | |||
| 6 | void apply_trans(Trans t, Cube *cube); | ||
| 7 | Trans inverse_trans(Trans t); | ||
| 8 | Alg * rotation_alg(Trans i); | ||
| 9 | void transform_alg(Trans t, Alg *alg); | ||
| 10 | Move transform_move(Trans t, Move m); | ||
| 11 | Trans transform_trans(Trans t, Trans m); | ||
| 12 | |||
| 13 | void init_trans(); | ||
| 14 | |||
| 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 | ||
diff --git a/src/utils.c b/src/utils.c deleted file mode 100644 index cbf951e..0000000 --- a/src/utils.c +++ /dev/null | |||
| @@ -1,290 +0,0 @@ | |||
| 1 | #define UTILS_C | ||
| 2 | |||
| 3 | #include "utils.h" | ||
| 4 | |||
| 5 | void | ||
| 6 | apply_permutation(int *perm, int *set, int n) | ||
| 7 | { | ||
| 8 | int *aux = malloc(n * sizeof(int)); | ||
| 9 | int i; | ||
| 10 | |||
| 11 | if (!is_perm(perm, n)) | ||
| 12 | return; | ||
| 13 | |||
| 14 | for (i = 0; i < n; i++) | ||
| 15 | aux[i] = set[perm[i]]; | ||
| 16 | |||
| 17 | memcpy(set, aux, n * sizeof(int)); | ||
| 18 | free(aux); | ||
| 19 | } | ||
| 20 | |||
| 21 | int | ||
| 22 | binomial(int n, int k) | ||
| 23 | { | ||
| 24 | if (n < 0 || k < 0 || k > n) | ||
| 25 | return 0; | ||
| 26 | |||
| 27 | return factorial(n) / (factorial(k) * factorial(n-k)); | ||
| 28 | } | ||
| 29 | |||
| 30 | int | ||
| 31 | digit_array_to_int(int *a, int n, int b) | ||
| 32 | { | ||
| 33 | int i, ret = 0, p = 1; | ||
| 34 | |||
| 35 | for (i = 0; i < n; i++, p *= b) | ||
| 36 | ret += a[i] * p; | ||
| 37 | |||
| 38 | return ret; | ||
| 39 | } | ||
| 40 | |||
| 41 | int | ||
| 42 | factorial(int n) | ||
| 43 | { | ||
| 44 | int i, ret = 1; | ||
| 45 | |||
| 46 | if (n < 0) | ||
| 47 | return 0; | ||
| 48 | |||
| 49 | for (i = 1; i <= n; i++) | ||
| 50 | ret *= i; | ||
| 51 | |||
| 52 | return ret; | ||
| 53 | } | ||
| 54 | |||
| 55 | void | ||
| 56 | index_to_perm(int p, int n, int *r) | ||
| 57 | { | ||
| 58 | int *a = malloc(n * sizeof(int)); | ||
| 59 | int i, j, c; | ||
| 60 | |||
| 61 | for (i = 0; i < n; i++) | ||
| 62 | a[i] = 0; | ||
| 63 | |||
| 64 | if (p < 0 || p >= factorial(n)) | ||
| 65 | for (i = 0; i < n; i++) | ||
| 66 | r[i] = -1; | ||
| 67 | |||
| 68 | for (i = 0; i < n; i++) { | ||
| 69 | c = 0; | ||
| 70 | j = 0; | ||
| 71 | while (c <= p / factorial(n-i-1)) | ||
| 72 | c += a[j++] ? 0 : 1; | ||
| 73 | r[i] = j-1; | ||
| 74 | a[j-1] = 1; | ||
| 75 | p %= factorial(n-i-1); | ||
| 76 | } | ||
| 77 | |||
| 78 | free(a); | ||
| 79 | } | ||
| 80 | |||
| 81 | void | ||
| 82 | index_to_subset(int s, int n, int k, int *r) | ||
| 83 | { | ||
| 84 | int i, j, v; | ||
| 85 | |||
| 86 | if (s < 0 || s >= binomial(n, k)) { | ||
| 87 | for (i = 0; i < n; i++) | ||
| 88 | r[i] = -1; | ||
| 89 | return; | ||
| 90 | } | ||
| 91 | |||
| 92 | for (i = 0; i < n; i++) { | ||
| 93 | if (k == n-i) { | ||
| 94 | for (j = i; j < n; j++) | ||
| 95 | r[j] = 1; | ||
| 96 | return; | ||
| 97 | } | ||
| 98 | |||
| 99 | if (k == 0) { | ||
| 100 | for (j = i; j < n; j++) | ||
| 101 | r[j] = 0; | ||
| 102 | return; | ||
| 103 | } | ||
| 104 | |||
| 105 | v = binomial(n-i-1, k); | ||
| 106 | if (s >= v) { | ||
| 107 | r[i] = 1; | ||
| 108 | k--; | ||
| 109 | s -= v; | ||
| 110 | } else { | ||
| 111 | r[i] = 0; | ||
| 112 | } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | void | ||
| 117 | int_to_digit_array(int a, int b, int n, int *r) | ||
| 118 | { | ||
| 119 | int i; | ||
| 120 | |||
| 121 | if (b <= 1) | ||
| 122 | for (i = 0; i < n; i++) | ||
| 123 | r[i] = 0; | ||
| 124 | else | ||
| 125 | for (i = 0; i < n; i++, a /= b) | ||
| 126 | r[i] = a % b; | ||
| 127 | } | ||
| 128 | |||
| 129 | void | ||
| 130 | int_to_sum_zero_array(int x, int b, int n, int *a) | ||
| 131 | { | ||
| 132 | int i, s = 0; | ||
| 133 | |||
| 134 | if (b <= 1) { | ||
| 135 | for (i = 0; i < n; i++) | ||
| 136 | a[i] = 0; | ||
| 137 | } else { | ||
| 138 | int_to_digit_array(x, b, n-1, a); | ||
| 139 | for (i = 0; i < n - 1; i++) | ||
| 140 | s = (s + a[i]) % b; | ||
| 141 | a[n-1] = (b - s) % b; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | int | ||
| 146 | invert_digits(int a, int b, int n) | ||
| 147 | { | ||
| 148 | int i, ret, *r = malloc(n * sizeof(int)); | ||
| 149 | |||
| 150 | int_to_digit_array(a, b, n, r); | ||
| 151 | for (i = 0; i < n; i++) | ||
| 152 | r[i] = (b-r[i]) % b; | ||
| 153 | |||
| 154 | ret = digit_array_to_int(r, n, b); | ||
| 155 | free(r); | ||
| 156 | return ret; | ||
| 157 | } | ||
| 158 | |||
| 159 | bool | ||
| 160 | is_perm(int *a, int n) | ||
| 161 | { | ||
| 162 | int *aux = malloc(n * sizeof(int)); | ||
| 163 | int i; | ||
| 164 | bool ret = true; | ||
| 165 | |||
| 166 | for (i = 0; i < n; i++) | ||
| 167 | aux[i] = 0; | ||
| 168 | |||
| 169 | for (i = 0; i < n; i++) { | ||
| 170 | if (a[i] < 0 || a[i] >= n) | ||
| 171 | ret = false; | ||
| 172 | else | ||
| 173 | aux[a[i]] = 1; | ||
| 174 | } | ||
| 175 | |||
| 176 | for (i = 0; i < n; i++) | ||
| 177 | if (!aux[i]) | ||
| 178 | ret = false; | ||
| 179 | |||
| 180 | free(aux); | ||
| 181 | return ret; | ||
| 182 | } | ||
| 183 | |||
| 184 | bool | ||
| 185 | is_subset(int *a, int n, int k) | ||
| 186 | { | ||
| 187 | int i, sum = 0; | ||
| 188 | |||
| 189 | for (i = 0; i < n; i++) | ||
| 190 | sum += a[i] ? 1 : 0; | ||
| 191 | |||
| 192 | return sum == k; | ||
| 193 | } | ||
| 194 | |||
| 195 | int | ||
| 196 | perm_sign(int *a, int n) | ||
| 197 | { | ||
| 198 | int i, j, ret = 0; | ||
| 199 | |||
| 200 | if (!is_perm(a, n)) | ||
| 201 | return -1; | ||
| 202 | |||
| 203 | for (i = 0; i < n; i++) | ||
| 204 | for (j = i+1; j < n; j++) | ||
| 205 | ret += (a[i] > a[j]) ? 1 : 0; | ||
| 206 | |||
| 207 | return ret % 2; | ||
| 208 | } | ||
| 209 | |||
| 210 | int | ||
| 211 | perm_to_index(int *a, int n) | ||
| 212 | { | ||
| 213 | int i, j, c, ret = 0; | ||
| 214 | |||
| 215 | if (!is_perm(a, n)) | ||
| 216 | return factorial(n); | ||
| 217 | |||
| 218 | for (i = 0; i < n; i++) { | ||
| 219 | c = 0; | ||
| 220 | for (j = i+1; j < n; j++) | ||
| 221 | c += (a[i] > a[j]) ? 1 : 0; | ||
| 222 | ret += factorial(n-i-1) * c; | ||
| 223 | } | ||
| 224 | |||
| 225 | return ret; | ||
| 226 | } | ||
| 227 | |||
| 228 | int | ||
| 229 | powint(int a, int b) | ||
| 230 | { | ||
| 231 | if (b < 0) | ||
| 232 | return 0; | ||
| 233 | if (b == 0) | ||
| 234 | return 1; | ||
| 235 | |||
| 236 | if (b % 2) | ||
| 237 | return a * powint(a, b-1); | ||
| 238 | else | ||
| 239 | return powint(a*a, b/2); | ||
| 240 | } | ||
| 241 | |||
| 242 | int | ||
| 243 | subset_to_index(int *a, int n, int k) | ||
| 244 | { | ||
| 245 | int i, ret = 0; | ||
| 246 | |||
| 247 | if (!is_subset(a, n, k)) | ||
| 248 | return binomial(n, k); | ||
| 249 | |||
| 250 | for (i = 0; i < n; i++) { | ||
| 251 | if (k == n-i) | ||
| 252 | return ret; | ||
| 253 | if (a[i]) { | ||
| 254 | ret += binomial(n-i-1, k); | ||
| 255 | k--; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | return ret; | ||
| 260 | } | ||
| 261 | |||
| 262 | void | ||
| 263 | sum_arrays_mod(int *src, int *dst, int n, int m) | ||
| 264 | { | ||
| 265 | int i; | ||
| 266 | |||
| 267 | for (i = 0; i < n; i++) | ||
| 268 | dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; | ||
| 269 | } | ||
| 270 | |||
| 271 | void | ||
| 272 | swap(int *a, int *b) | ||
| 273 | { | ||
| 274 | int aux; | ||
| 275 | |||
| 276 | aux = *a; | ||
| 277 | *a = *b; | ||
| 278 | *b = aux; | ||
| 279 | } | ||
| 280 | |||
| 281 | void | ||
| 282 | swapu64(uint64_t *a, uint64_t *b) | ||
| 283 | { | ||
| 284 | uint64_t aux; | ||
| 285 | |||
| 286 | aux = *a; | ||
| 287 | *a = *b; | ||
| 288 | *b = aux; | ||
| 289 | } | ||
| 290 | |||
diff --git a/src/utils.h b/src/utils.h deleted file mode 100644 index 9ba228d..0000000 --- a/src/utils.h +++ /dev/null | |||
| @@ -1,43 +0,0 @@ | |||
| 1 | #ifndef UTILS_H | ||
| 2 | #define UTILS_H | ||
| 3 | |||
| 4 | #include <stdbool.h> | ||
| 5 | #include <stdint.h> | ||
| 6 | #include <stdlib.h> | ||
| 7 | #include <string.h> | ||
| 8 | |||
| 9 | #define POW2TO6 64ULL | ||
| 10 | #define POW2TO11 2048ULL | ||
| 11 | #define POW2TO12 4096ULL | ||
| 12 | #define POW3TO7 2187ULL | ||
| 13 | #define POW3TO8 6561ULL | ||
| 14 | #define FACTORIAL4 24ULL | ||
| 15 | #define FACTORIAL6 720ULL | ||
| 16 | #define FACTORIAL7 5040ULL | ||
| 17 | #define FACTORIAL8 40320ULL | ||
| 18 | #define FACTORIAL12 479001600ULL | ||
| 19 | #define BINOM12ON4 495ULL | ||
| 20 | #define BINOM8ON4 70ULL | ||
| 21 | #define MIN(a,b) (((a) < (b)) ? (a) : (b)) | ||
| 22 | #define MAX(a,b) (((a) > (b)) ? (a) : (b)) | ||
| 23 | |||
| 24 | void apply_permutation(int *perm, int *set, int n); | ||
| 25 | int binomial(int n, int k); | ||
| 26 | int digit_array_to_int(int *a, int n, int b); | ||
| 27 | int factorial(int n); | ||
| 28 | void index_to_perm(int p, int n, int *r); | ||
| 29 | void index_to_subset(int s, int n, int k, int *r); | ||
| 30 | void int_to_digit_array(int a, int b, int n, int *r); | ||
| 31 | void int_to_sum_zero_array(int x, int b, int n, int *a); | ||
| 32 | int invert_digits(int a, int b, int n); | ||
| 33 | bool is_perm(int *a, int n); | ||
| 34 | bool is_subset(int *a, int n, int k); | ||
| 35 | int perm_sign(int *a, int n); | ||
| 36 | int perm_to_index(int *a, int n); | ||
| 37 | int powint(int a, int b); | ||
| 38 | int subset_to_index(int *a, int n, int k); | ||
| 39 | void sum_arrays_mod(int *src, int *dst, int n, int m); | ||
| 40 | void swap(int *a, int *b); | ||
| 41 | void swapu64(uint64_t *a, uint64_t *b); | ||
| 42 | |||
| 43 | #endif | ||
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 | } | ||
