aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--INSTALL81
-rw-r--r--LICENSE636
-rw-r--r--Makefile68
-rw-r--r--README.md130
-rw-r--r--TODO/2.1.md51
-rw-r--r--TODO/build-options.md33
-rw-r--r--TODO/documentation.md41
-rw-r--r--TODO/easy.md16
-rw-r--r--TODO/installation.md14
-rw-r--r--TODO/new-feature-ideas.md32
-rw-r--r--TODO/parser.md13
-rw-r--r--TODO/refactoring.md28
-rw-r--r--TODO/testing.md6
-rw-r--r--TODO/webapp.md19
-rw-r--r--doc/nissy.1271
-rw-r--r--old/maybe-useful-coord.c181
-rw-r--r--old/maybe-useful-steps.c1111
-rw-r--r--old/solve_old.c447
-rw-r--r--old/solve_old.h9
-rw-r--r--src/alg.c459
-rw-r--r--src/alg.h35
-rw-r--r--src/commands.c569
-rw-r--r--src/commands.h211
-rw-r--r--src/coord.c654
-rw-r--r--src/coord.h259
-rw-r--r--src/cube.c270
-rw-r--r--src/cube.h35
-rw-r--r--src/cubetypes.h360
-rw-r--r--src/env.c60
-rw-r--r--src/env.h15
-rw-r--r--src/fst.c401
-rw-r--r--src/fst.h13
-rw-r--r--src/moves.c301
-rw-r--r--src/moves.h17
-rw-r--r--src/movesets.c194
-rw-r--r--src/movesets.h15
-rw-r--r--src/pruning.c400
-rw-r--r--src/pruning.h16
-rw-r--r--src/shell.c177
-rw-r--r--src/shell.h14
-rw-r--r--src/solve.c122
-rw-r--r--src/solve.h54
-rw-r--r--src/solver_step.c306
-rw-r--r--src/solver_step.h12
-rw-r--r--src/steps.c177
-rw-r--r--src/steps.h244
-rw-r--r--src/threader_eager.c163
-rw-r--r--src/threader_eager.h8
-rw-r--r--src/threader_single.c35
-rw-r--r--src/threader_single.h8
-rw-r--r--src/trans.c190
-rw-r--r--src/trans.h32
-rw-r--r--src/utils.c290
-rw-r--r--src/utils.h43
-rw-r--r--tests/alg_tests.c266
-rw-r--r--tests/alg_tests.h21
-rw-r--r--tests/coord_tests.c50
-rw-r--r--tests/coord_tests.h13
-rw-r--r--tests/fst_tests.c184
-rw-r--r--tests/fst_tests.h19
-rw-r--r--tests/test.c85
-rw-r--r--tests/test_common.h41
-rw-r--r--www/download/index.html217
-rw-r--r--www/examples/index.html49
-rw-r--r--www/favicon.pngbin6550 -> 0 bytes
-rw-r--r--www/index.html93
-rw-r--r--www/screenshot.pngbin61239 -> 0 bytes
-rw-r--r--www/style-3.css105
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 @@
1doc/*.html
2doc/*.pdf
3nissy
4nissy-*
5test
diff --git a/INSTALL b/INSTALL
deleted file mode 100644
index ffc461d..0000000
--- a/INSTALL
+++ /dev/null
@@ -1,81 +0,0 @@
1# Website
2
3Nissy is available at https://nissy.tronto.net
4
5# Requirements
6
7A full installation of nissy requires about 3Gb of space, of which
82.3Gb are occupied by the huge pruning table for fast optimal solving,
9and running it requires the same amount of RAM. One can choose to never
10use this function and not to install the relative pruning table. There
11is an alternative (slower) optimal solving function that uses about
12500Mb of RAM. When generating the pruning tables automatically (see
13the section Tables below), at least 5.3Gb or RAM are required.
14
15# Installation
16
17## On Windows
18
19Try downloading and executing in a terminal the file nissy.exe, then
20follow the instructions in the Tables section below for installing the
21pruning tables. If nissy.exe does not work, you can try following the
22UNIX instructions in WSL (Windows Subsystem for Linux) or in a similar
23environment.
24
25## On a UNIX system:
26
27Download the source archive (.tar.gz). Extract it with your favorite
28archive program, for example with
29
30 tar -xvzf nissy-VERSION.tar.gz
31
32Open a terminal in the directory just extracted. If you wish, edit the
33Makefile to match your local configuration (this is usually not necessary,
34but you may want to change the PREFIX variable to change the installation
35path) and run
36
37 make
38
39followed by
40
41 make install
42
43Then follow the instructions below to install the pruning tables.
44
45## Tables
46
47Once you have installed nissy, run
48
49 nissy gen
50
51to generate all the tables that Nissy will ever need. Running this
52command requires around 5.3Gb of RAM, and it can take some time (about
5340 minutes on my fairly old but decent laptop, with 8 CPU threads).
54
55Some unnecessary technical detail: by default this command is going to
56use 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
58want to run this command in the background while you do other stuff)
59with the -t option, for example nissy gen -t 1.
60
61Alternatively, you can download all the tables (1.7Gb) and copy them
62into the correct folder (see manual page, ENVIRONMENT section). On UNIX
63operating systems this folder is either .nissy/tables in the user's
64home directory or $XDG_DATA_HOME/nissy/tables if the XDG variable
65is configured. On Windows it is the same directory as the nissy.exe
66executable file.
67
68You 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
74If you already have nissy installed and you want to upgrade to a more
75recent 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
80Between each version new table files might have been added, or old ones
81may 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 @@
1The following license applies to every C source code and header file
2distributed 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
28software and other kinds of works.
29
30 The licenses for most software and other practical works are designed
31to take away your freedom to share and change the works. By contrast,
32the GNU General Public License is intended to guarantee your freedom to
33share and change all versions of a program--to make sure it remains free
34software for all its users. We, the Free Software Foundation, use the
35GNU General Public License for most of our software; it applies also to
36any other work released this way by its authors. You can apply it to
37your programs, too.
38
39 When we speak of free software, we are referring to freedom, not
40price. Our General Public Licenses are designed to make sure that you
41have the freedom to distribute copies of free software (and charge for
42them if you wish), that you receive source code or can get it if you
43want it, that you can change the software or use pieces of it in new
44free programs, and that you know you can do these things.
45
46 To protect your rights, we need to prevent others from denying you
47these rights or asking you to surrender the rights. Therefore, you have
48certain responsibilities if you distribute copies of the software, or if
49you modify it: responsibilities to respect the freedom of others.
50
51 For example, if you distribute copies of such a program, whether
52gratis or for a fee, you must pass on to the recipients the same
53freedoms that you received. You must make sure that they, too, receive
54or can get the source code. And you must show them these terms so they
55know 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
59giving you legal permission to copy, distribute and/or modify it.
60
61 For the developers' and authors' protection, the GPL clearly explains
62that there is no warranty for this free software. For both users' and
63authors' sake, the GPL requires that modified versions be marked as
64changed, so that their problems will not be attributed erroneously to
65authors of previous versions.
66
67 Some devices are designed to deny users access to install or run
68modified versions of the software inside them, although the manufacturer
69can do so. This is fundamentally incompatible with the aim of
70protecting users' freedom to change the software. The systematic
71pattern of such abuse occurs in the area of products for individuals to
72use, which is precisely where it is most unacceptable. Therefore, we
73have designed this version of the GPL to prohibit the practice for those
74products. If such problems arise substantially in other domains, we
75stand ready to extend this provision to those domains in future versions
76of the GPL, as needed to protect the freedom of users.
77
78 Finally, every program is threatened constantly by software patents.
79States should not allow patents to restrict development and use of
80software on general-purpose computers, but in those that do, we wish to
81avoid the special danger that patents applied to a free program could
82make it effectively proprietary. To prevent this, the GPL assures that
83patents cannot be used to render the program non-free.
84
85 The precise terms and conditions for copying, distribution and
86modification 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
95works, such as semiconductor masks.
96
97 "The Program" refers to any copyrightable work licensed under this
98License. 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
102in a fashion requiring copyright permission, other than the making of an
103exact copy. The resulting work is called a "modified version" of the
104earlier work or a work "based on" the earlier work.
105
106 A "covered work" means either the unmodified Program or a work based
107on the Program.
108
109 To "propagate" a work means to do anything with it that, without
110permission, would make you directly or secondarily liable for
111infringement under applicable copyright law, except executing it on a
112computer or modifying a private copy. Propagation includes copying,
113distribution (with or without modification), making available to the
114public, and in some countries other activities as well.
115
116 To "convey" a work means any kind of propagation that enables other
117parties to make or receive copies. Mere interaction with a user through
118a computer network, with no transfer of a copy, is not conveying.
119
120 An interactive user interface displays "Appropriate Legal Notices"
121to the extent that it includes a convenient and prominently visible
122feature that (1) displays an appropriate copyright notice, and (2)
123tells the user that there is no warranty for the work (except to the
124extent that warranties are provided), that licensees may convey the
125work under this License, and how to view a copy of this License. If
126the interface presents a list of user commands or options, such as a
127menu, 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
132for making modifications to it. "Object code" means any non-source
133form of a work.
134
135 A "Standard Interface" means an interface that either is an official
136standard defined by a recognized standards body, or, in the case of
137interfaces specified for a particular programming language, one that
138is widely used among developers working in that language.
139
140 The "System Libraries" of an executable work include anything, other
141than the work as a whole, that (a) is included in the normal form of
142packaging a Major Component, but which is not part of that Major
143Component, and (b) serves only to enable use of the work with that
144Major Component, or to implement a Standard Interface for which an
145implementation 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
149produce 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
152the source code needed to generate, install, and (for an executable
153work) run the object code and to modify the work, including scripts to
154control those activities. However, it does not include the work's
155System Libraries, or general-purpose tools or generally available free
156programs which are used unmodified in performing those activities but
157which are not part of the work. For example, Corresponding Source
158includes interface definition files associated with source files for
159the work, and the source code for shared libraries and dynamically
160linked subprograms that the work is specifically designed to require,
161such as by intimate data communication or control flow between those
162subprograms and other parts of the work.
163
164 The Corresponding Source need not include anything that users
165can regenerate automatically from other parts of the Corresponding
166Source.
167
168 The Corresponding Source for a work in source code form is that
169same work.
170
171 2. Basic Permissions.
172
173 All rights granted under this License are granted for the term of
174copyright on the Program, and are irrevocable provided the stated
175conditions are met. This License explicitly affirms your unlimited
176permission to run the unmodified Program. The output from running a
177covered work is covered by this License only if the output, given its
178content, constitutes a covered work. This License acknowledges your
179rights 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
182convey, without conditions so long as your license otherwise remains
183in force. You may convey covered works to others for the sole purpose
184of having them make modifications exclusively for you, or provide you
185with facilities for running those works, provided that you comply with
186the terms of this License in conveying all material for which you do
187not control copyright. Those thus making or running the covered works
188for you must do so exclusively on your behalf, under your direction
189and control, on terms that prohibit them from making any copies of
190your copyrighted material outside their relationship with you.
191
192 Conveying under any other circumstances is permitted solely under
193the conditions stated below. Sublicensing is not allowed; section 10
194makes 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
199measure under any applicable law fulfilling obligations under article
20011 of the WIPO copyright treaty adopted on 20 December 1996, or
201similar laws prohibiting or restricting circumvention of such
202measures.
203
204 When you convey a covered work, you waive any legal power to forbid
205circumvention of technological measures to the extent such circumvention
206is effected by exercising rights under this License with respect to
207the covered work, and you disclaim any intention to limit operation or
208modification of the work as a means of enforcing, against the work's
209users, your or third parties' legal rights to forbid circumvention of
210technological measures.
211
212 4. Conveying Verbatim Copies.
213
214 You may convey verbatim copies of the Program's source code as you
215receive it, in any medium, provided that you conspicuously and
216appropriately publish on each copy an appropriate copyright notice;
217keep intact all notices stating that this License and any
218non-permissive terms added in accord with section 7 apply to the code;
219keep intact all notices of the absence of any warranty; and give all
220recipients 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,
223and 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
228produce it from the Program, in the form of source code under the
229terms 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
253works, which are not by their nature extensions of the covered work,
254and which are not combined with it such as to form a larger program,
255in or on a volume of a storage or distribution medium, is called an
256"aggregate" if the compilation and its resulting copyright are not
257used to limit the access or legal rights of the compilation's users
258beyond what the individual works permit. Inclusion of a covered work
259in an aggregate does not cause this License to apply to the other
260parts 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
265of sections 4 and 5, provided that you also convey the
266machine-readable Corresponding Source under the terms of this License,
267in 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
311from the Corresponding Source as a System Library, need not be
312included in conveying the object code work.
313
314 A "User Product" is either (1) a "consumer product", which means any
315tangible personal property which is normally used for personal, family,
316or household purposes, or (2) anything designed or sold for incorporation
317into a dwelling. In determining whether a product is a consumer product,
318doubtful cases shall be resolved in favor of coverage. For a particular
319product received by a particular user, "normally used" refers to a
320typical or common use of that class of product, regardless of the status
321of the particular user or of the way in which the particular user
322actually uses, or expects or is expected to use, the product. A product
323is a consumer product regardless of whether the product has substantial
324commercial, industrial or non-consumer uses, unless such uses represent
325the only significant mode of use of the product.
326
327 "Installation Information" for a User Product means any methods,
328procedures, authorization keys, or other information required to install
329and execute modified versions of a covered work in that User Product from
330a modified version of its Corresponding Source. The information must
331suffice to ensure that the continued functioning of the modified object
332code is in no case prevented or interfered with solely because
333modification has been made.
334
335 If you convey an object code work under this section in, or with, or
336specifically for use in, a User Product, and the conveying occurs as
337part of a transaction in which the right of possession and use of the
338User Product is transferred to the recipient in perpetuity or for a
339fixed term (regardless of how the transaction is characterized), the
340Corresponding Source conveyed under this section must be accompanied
341by the Installation Information. But this requirement does not apply
342if neither you nor any third party retains the ability to install
343modified object code on the User Product (for example, the work has
344been installed in ROM).
345
346 The requirement to provide Installation Information does not include a
347requirement to continue to provide support service, warranty, or updates
348for a work that has been modified or installed by the recipient, or for
349the User Product in which it has been modified or installed. Access to a
350network may be denied when the modification itself materially and
351adversely affects the operation of the network or violates the rules and
352protocols for communication across the network.
353
354 Corresponding Source conveyed, and Installation Information provided,
355in accord with this section must be in a format that is publicly
356documented (and with an implementation available to the public in
357source code form), and must require no special password or key for
358unpacking, reading or copying.
359
360 7. Additional Terms.
361
362 "Additional permissions" are terms that supplement the terms of this
363License by making exceptions from one or more of its conditions.
364Additional permissions that are applicable to the entire Program shall
365be treated as though they were included in this License, to the extent
366that they are valid under applicable law. If additional permissions
367apply only to part of the Program, that part may be used separately
368under those permissions, but the entire Program remains governed by
369this License without regard to the additional permissions.
370
371 When you convey a copy of a covered work, you may at your option
372remove any additional permissions from that copy, or from any part of
373it. (Additional permissions may be written to require their own
374removal in certain cases when you modify the work.) You may place
375additional permissions on material, added by you to a covered work,
376for which you have or can give appropriate copyright permission.
377
378 Notwithstanding any other provision of this License, for material you
379add to a covered work, you may (if authorized by the copyright holders of
380that 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
406restrictions" within the meaning of section 10. If the Program as you
407received it, or any part of it, contains a notice stating that it is
408governed by this License along with a term that is a further
409restriction, you may remove that term. If a license document contains
410a further restriction but permits relicensing or conveying under this
411License, you may add to a covered work material governed by the terms
412of that license document, provided that the further restriction does
413not survive such relicensing or conveying.
414
415 If you add terms to a covered work in accord with this section, you
416must place, in the relevant source files, a statement of the
417additional terms that apply to those files, or a notice indicating
418where to find the applicable terms.
419
420 Additional terms, permissive or non-permissive, may be stated in the
421form of a separately written license, or stated as exceptions;
422the above requirements apply either way.
423
424 8. Termination.
425
426 You may not propagate or modify a covered work except as expressly
427provided under this License. Any attempt otherwise to propagate or
428modify it is void, and will automatically terminate your rights under
429this License (including any patent licenses granted under the third
430paragraph of section 11).
431
432 However, if you cease all violation of this License, then your
433license from a particular copyright holder is reinstated (a)
434provisionally, unless and until the copyright holder explicitly and
435finally terminates your license, and (b) permanently, if the copyright
436holder fails to notify you of the violation by some reasonable means
437prior to 60 days after the cessation.
438
439 Moreover, your license from a particular copyright holder is
440reinstated permanently if the copyright holder notifies you of the
441violation by some reasonable means, this is the first time you have
442received notice of violation of this License (for any work) from that
443copyright holder, and you cure the violation prior to 30 days after
444your receipt of the notice.
445
446 Termination of your rights under this section does not terminate the
447licenses of parties who have received copies or rights from you under
448this License. If your rights have been terminated and not permanently
449reinstated, you do not qualify to receive new licenses for the same
450material 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
455run a copy of the Program. Ancillary propagation of a covered work
456occurring solely as a consequence of using peer-to-peer transmission
457to receive a copy likewise does not require acceptance. However,
458nothing other than this License grants you permission to propagate or
459modify any covered work. These actions infringe copyright if you do
460not accept this License. Therefore, by modifying or propagating a
461covered 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
466receives a license from the original licensors, to run, modify and
467propagate that work, subject to this License. You are not responsible
468for enforcing compliance by third parties with this License.
469
470 An "entity transaction" is a transaction transferring control of an
471organization, or substantially all assets of one, or subdividing an
472organization, or merging organizations. If propagation of a covered
473work results from an entity transaction, each party to that
474transaction who receives a copy of the work also receives whatever
475licenses to the work the party's predecessor in interest had or could
476give under the previous paragraph, plus a right to possession of the
477Corresponding Source of the work from the predecessor in interest, if
478the predecessor has it or can get it with reasonable efforts.
479
480 You may not impose any further restrictions on the exercise of the
481rights granted or affirmed under this License. For example, you may
482not impose a license fee, royalty, or other charge for exercise of
483rights granted under this License, and you may not initiate litigation
484(including a cross-claim or counterclaim in a lawsuit) alleging that
485any patent claim is infringed by making, using, selling, offering for
486sale, 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
491License of the Program or a work on which the Program is based. The
492work thus licensed is called the contributor's "contributor version".
493
494 A contributor's "essential patent claims" are all patent claims
495owned or controlled by the contributor, whether already acquired or
496hereafter acquired, that would be infringed by some manner, permitted
497by this License, of making, using, or selling its contributor version,
498but do not include claims that would be infringed only as a
499consequence of further modification of the contributor version. For
500purposes of this definition, "control" includes the right to grant
501patent sublicenses in a manner consistent with the requirements of
502this License.
503
504 Each contributor grants you a non-exclusive, worldwide, royalty-free
505patent license under the contributor's essential patent claims, to
506make, use, sell, offer for sale, import and otherwise run, modify and
507propagate the contents of its contributor version.
508
509 In the following three paragraphs, a "patent license" is any express
510agreement or commitment, however denominated, not to enforce a patent
511(such as an express permission to practice a patent or covenant not to
512sue for patent infringement). To "grant" such a patent license to a
513party means to make such an agreement or commitment not to enforce a
514patent against the party.
515
516 If you convey a covered work, knowingly relying on a patent license,
517and the Corresponding Source of the work is not available for anyone
518to copy, free of charge and under the terms of this License, through a
519publicly available network server or other readily accessible means,
520then you must either (1) cause the Corresponding Source to be so
521available, or (2) arrange to deprive yourself of the benefit of the
522patent license for this particular work, or (3) arrange, in a manner
523consistent with the requirements of this License, to extend the patent
524license to downstream recipients. "Knowingly relying" means you have
525actual knowledge that, but for the patent license, your conveying the
526covered work in a country, or your recipient's use of the covered work
527in a country, would infringe one or more identifiable patents in that
528country that you have reason to believe are valid.
529
530 If, pursuant to or in connection with a single transaction or
531arrangement, you convey, or propagate by procuring conveyance of, a
532covered work, and grant a patent license to some of the parties
533receiving the covered work authorizing them to use, propagate, modify
534or convey a specific copy of the covered work, then the patent license
535you grant is automatically extended to all recipients of the covered
536work and works based on it.
537
538 A patent license is "discriminatory" if it does not include within
539the scope of its coverage, prohibits the exercise of, or is
540conditioned on the non-exercise of one or more of the rights that are
541specifically granted under this License. You may not convey a covered
542work if you are a party to an arrangement with a third party that is
543in the business of distributing software, under which you make payment
544to the third party based on the extent of your activity of conveying
545the work, and under which the third party grants, to any of the
546parties who would receive the covered work from you, a discriminatory
547patent license (a) in connection with copies of the covered work
548conveyed by you (or copies made from those copies), or (b) primarily
549for and in connection with specific products or compilations that
550contain the covered work, unless you entered into that arrangement,
551or that patent license was granted, prior to 28 March 2007.
552
553 Nothing in this License shall be construed as excluding or limiting
554any implied license or other defenses to infringement that may
555otherwise 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
560otherwise) that contradict the conditions of this License, they do not
561excuse you from the conditions of this License. If you cannot convey a
562covered work so as to satisfy simultaneously your obligations under this
563License and any other pertinent obligations, then as a consequence you may
564not convey it at all. For example, if you agree to terms that obligate you
565to collect a royalty for further conveying from those to whom you convey
566the Program, the only way you could satisfy both those terms and this
567License 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
572permission to link or combine any covered work with a work licensed
573under version 3 of the GNU Affero General Public License into a single
574combined work, and to convey the resulting work. The terms of this
575License will continue to apply to the part which is the covered work,
576but the special requirements of the GNU Affero General Public License,
577section 13, concerning interaction through a network will apply to the
578combination as such.
579
580 14. Revised Versions of this License.
581
582 The Free Software Foundation may publish revised and/or new versions of
583the GNU General Public License from time to time. Such new versions will
584be similar in spirit to the present version, but may differ in detail to
585address new problems or concerns.
586
587 Each version is given a distinguishing version number. If the
588Program specifies that a certain numbered version of the GNU General
589Public License "or any later version" applies to it, you have the
590option of following the terms and conditions either of that numbered
591version or of any later version published by the Free Software
592Foundation. If the Program does not specify a version number of the
593GNU General Public License, you may choose any version ever published
594by the Free Software Foundation.
595
596 If the Program specifies that a proxy can decide which future
597versions of the GNU General Public License can be used, that proxy's
598public statement of acceptance of a version permanently authorizes you
599to choose that version for the Program.
600
601 Later license versions may give you additional or different
602permissions. However, no additional obligations are imposed on any
603author or copyright holder as a result of your choosing to follow a
604later version.
605
606 15. Disclaimer of Warranty.
607
608 THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
609APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
610HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
611OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
612THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
613PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
614IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
615ALL 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
620WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
621THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
622GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
623USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
624DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
625PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
626EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
627SUCH DAMAGES.
628
629 17. Interpretation of Sections 15 and 16.
630
631 If the disclaimer of warranty and limitation of liability provided
632above cannot be given local legal effect according to their terms,
633reviewing courts shall apply local law that most closely approximates
634an absolute waiver of all civil liability in connection with the
635Program, unless a warranty or assumption of liability accompanies a
636copy 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
3VERSION = post-2.0.2
4
5PREFIX = /usr/local
6MANPREFIX = ${PREFIX}/share/man
7
8CPPFLAGS = -DVERSION=\"${VERSION}\"
9CFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \
10 -Wno-unused-parameter -O3 ${CPPFLAGS}
11DBGFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \
12 -Wno-unused-parameter -g ${CPPFLAGS}
13
14CC = cc
15
16all: nissy
17
18nissy: clean
19 ${CC} ${CFLAGS} -o nissy src/*.c
20
21nissy.exe:
22 x86_64-w64-mingw32-gcc ${CFLAGS} -static -o nissy.exe src/*.c
23
24debug:
25 ${CC} ${DBGFLAGS} -o nissy src/*.c
26
27test:
28 ${CC} ${DBGFLAGS} -DTEST -o test src/*.c tests/*.c
29
30clean:
31 rm -rf nissy nissy*.exe nissy*.tar.gz doc/nissy.html doc/nissy.pdf
32
33dist: 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
45upload: 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
51website:
52 rsync -rv --rsync-path=openrsync \
53 www/ tronto.net:/var/www/htdocs/nissy.tronto.net
54
55install: 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
64uninstall:
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
diff --git a/README.md b/README.md
index 8aa6a2d..7b0beda 100644
--- a/README.md
+++ b/README.md
@@ -1,104 +1,50 @@
1# WARNING 1# Where is nissy?
2 2
3I am currently rewriting some important parts of the code 3In April 2023 I have decided to split nissy in 2 separate projects: an
4and the git version is not working. 4optimal solver and an FMC assistant. These two projects are not usable
5You can download the last stable version from the 5yet, so in the meantime I will keep a third branch where I update the
6[download page](https://nissy.tronto.net/download). 6classic version of nissy with bugfixes and minor improvements.
7 7
8# Nissy 8You can find these three branches at the following pages (also
9on github, links below are to my personal git instance):
9 10
10A Rubik's cube solver and FMC assistant. 11* [nissy-classic](https://git.tronto.net/nissy-classic): The stable
11For 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
14With 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
15optimal 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
17Nissy 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).
19It can be useful to analyze your DR solves (and more, once I implement more features).
20 28
21You can get Nissy from [nissy.tronto.net](https://nissy.tronto.net). 29If you are happy with using nissy as it is, you can keep using it.
22The 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 31When nissy-fmc and nissy-classic are ready, you can chek them out too.
26 32
27You 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?
28I strived to keep it legible but I did not write many comments (barely any at all).
29I'll try to explain here the main parts of the program.
30 34
31### Cube, moves and transformations 35Then I encourage you to keep using nissy-classic :-)
32 36
33There are many ways to represent a cube. In Nissy I use two: 37See
38[my blog post](https://sebastiano.tronto.net/blog/2023-04-10-the-big-rewrite/)
39for 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?
36of 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
38to the three axes), 3 for corner orientation, and so on. Edge permutation is a bit
39complicated because encoding 12 factorial as a single number is too large for some
40practical reasons, so I use 3 integers for that.
41 42
42Moves are easy to apply on the array form, but they are slow. So `moves.c` 43If you want to check out the git repository of the version you are
43contains the instructions to create all the transition tables necessary 44running, you probably want nissy-classic. The newer nissy-fmc will
44to get the next position for the cube with just 11 lookup operations 45eventually be nicer and easier to read, containing more or less
45(one for each of the 11 integers in the second representation). 46the same functionality (except for optimal solving).
46These transition tables are saved in the `mtables` file in the
47`tables` folder in binary format.
48
49The 11 integers are obviously redundant, but keeping all of them makes it easy
50to apply transformations. A transformation is a rotation of the whole cube, possibly
51combined with a mirror operation. Applying a transformation to a cube (say obtained
52by applying a scramble to the solved cube) means applying the transformation to a
53solved cube, then the scramble and then the inverse of the transformation
54(i.e. conjugating by it).
55
56### Coordinates and pruning tables
57
58A *coordinate* consists of a function that takes a cube (in the 11-integer
59representation) and return an (unsigned, 64-bit) integer. They are used
60to "linearize" a cube and build pruning tables, which speed up significantly the
61solving process. To be able to access the pruning table quickly, the function
62needs to be very fast (e.g. it should not convert between the two representations
63of the cube if not necessary).
64
65Some coordinates make use of symmetries to reduce the size of the resulting
66pruning table. Unfortunately this complicates the code a lot, but it is a huge
67advantage: it reduces by a factor of about 16 the pruning table size.
68
69Pruning tables are related to a specific step, a moveset and a coordinate. They
70contain one value from 0 to 15 (4 bits) for each possible value for the coordinate,
71which is less or equal than the minimum number of moves required to solve the
72given step with the given moveset for a cube which has the given coordinate. For example,
73say the coordinate `neo` gives the number of non-oriented edges (say with respect to
74F/B). Then the possible values for the coordinate are 0,2,4,...,12. An associated
75pruning 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
78The values for most pruning tables are memorized modulo 16, so they only occupy
794 bits per entry, and values larger than 15 are saved as 15. This is good enough
80for most applications.
81Some large tables are memorized in compact form using only 2 bits, similarly
82to what [nxopt](https://github.com/rokicki/cube20src/blob/master/nxopt.md) does:
83a base value `b` is picked and a value of `n` is saved as `MIN(3,MAX(0,n-b))`.
84When 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`
86is picked to maximize the sum frequency of the values `1,2,3`.
87
88In order to generate the pruning tables, it is necessary to be able to move
89a transform a coordinate; it is possible to do so without passing through a
90complete cube representations, in a way similar to what Cube Explorer does.
91This used to be different before version 2.1 (June 2022).
92
93More documentation on this and on the different types of coordinates (base
94vs composed) is work in progress.
95
96### Solving
97
98Solving is implemented as a generic function that takes both a step and
99a (scrambled) cube as input, as well as some extra parameters that say e.g.
100how many solution one wants. A step consists, among other things, of
101an estimator function that, given a cube, gives a lower bound for the number
102of moves needed to complete the step. Many of these estimators simply
103look up the corresponding values in the appropriate pruning table.
104 47
48If you want to follow my progress on an advanced optimal Rubik's
49cube solver, you can check out nissy-nx - just remember that it
50does 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
17data 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
21in 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
27merged at the end. Ideal when all solutions of a certain length are requested.
28* (Done) Eager multithread: current implementation, branches communicate the
29number and list of solutions to stop as soon as possible. Good when only one
30solution 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
22Where to collect random information like this table?
23
24Table pt_nxopt31_HTM
25Base value: 9
260 1
271 6
282 29
293 164
304 1433
315 16772
326 205033
337 2513871
348 30329976
359 342440769
3610 2815191126
3711 6147967200
3812 524918774
3913 3546
4014 0
4115 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
3This file contains non-refined ideas. Once an idea gets refined, it will
4get 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
3First, 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
17is a Rubik's Cube solver.
18It uses techniques from Herbert Kociemba's Cube Explorer and
19Tomas Rokicki's nxopt. With 4 cores at 2.5GHz and using about 3Gb
20of RAM, Nissy can find the optimal solution for a random Rubik's cube position
21in about a minute on average.
22Nissy can also solve different substeps of the Thistlethwaite's algorithm and more.
23.Pp
24When run without any argument an interactive shell is launched, otherwise
25the provided
26.Ar command
27is executed and nissy terminates. If the option
28.Fl b
29is given, every argument after it is ignored and the shell is launched without
30any prompt or welcome message. This can be used to run nissy in batch mode,
31for example writing a list of commands in a
32.Ar file
33(one per line) and running
34.Ar nissy -b < file
35.Pp
36The commands that can be run in the interactive shell are the same that can
37be run non-interactively and are provided below.
38.
39.Sh COMMANDS
40The available
41.Ar commands
42are the following:
43.
44.Bl -tag -width Ds
45.
46.It Nm cleanup Ar scramble
47Rewrites the given scramble using only the 18 base (HTM) moves and at most two
48rotations at the end. If
49Ar scramble
50uses NISS, all moves done on normal scramble are written first, followed by
51all moves done on inverse.
52.
53.It Nm commands
54List all available commands.
55.
56.It Nm freemem
57Release some large tables from memory. You can use this command in case
58you want to keep nissy open without using too much RAM.
59.
60.It Nm gen Op Fl t Ar N
61Generate all tables used by nissy. Run this to complete your installation.
62If
63.Ar N
64is specified,
65.Ar N
66CPU threads will be used (defaults to 64, use less only if you don't want
67nissy to use all of your CPU resources).
68.
69.It Nm help Op Ar command
70Display help. If no
71.Ar command
72is given, a generic help message is printed, otherwise a specific help
73relative to
74.Ar command
75is returned.
76.
77.It Nm invert Ar scramble
78Invert the given scramble.
79.
80.It Nm print Ar scramble
81Display a text-only description of the cube obtained after applying
82.Ar scramble .
83.
84.It Nm quit
85Quit nissy.
86.
87.It Nm scramble Oo Fl n Ar N Oc Oo Ar type Oc
88Print a randomly-generated (random position) scramble
89.
90If
91.Ar N
92is given, it produces
93.Ar N
94scrambles.
95.Ar type
96can be specified to be one of the following:
97.Bl -tag -width Ds
98.It Ar corners
99Scramble with solved edges (only cornes are scrambled).
100.It Ar dr
101Scramble with solved DR on U/D.
102.It Ar edges
103Scramble with solved corners (only edges are scrambled).
104.It Ar eo
105Scramble with solved EO on F/B axis.
106.It Ar fmc
107Scramble the full cube and the resulting scramble starts and ends with
108the moves R\(aq U\(aq F.
109.It Ar htr
110Scramble with HTR solved.
111.El
112.
113.It Nm solve Ar step Oo Ar options Oc Ar scramble
114Solve the given
115.Ar step
116on the given
117.Ar scramble.
118By default it finds only one (shortest) solution, without using niss, and it
119displays the number of moves at the end of the line.
120.
121The options for the
122.Ar solve
123command are the following:
124.
125.Bl -tag -width Ds
126.
127.It Fl a
128Print all solutions: some solutions are filtered out by default for some
129steps, for examples EOs that finish with F\(aq, with this options they are not.
130.
131.It Fl c
132Display only the number of solutions found, not the solutions themselves.
133.
134.It Fl m Ar min
135Only look for solution that are at least
136.Ar min
137moves long.
138.
139.It Fl M Ar MAX
140Only look for solution that are at most
141.Ar MAX
142moves long.
143.
144.It Fl n Ar N
145Try to find
146.Ar N
147solutions. By default and unless the
148.Fl M
149or
150.Fl o
151options are used, at most one solution is returned.
152If at least one of
153.Fl M
154and
155.Fl o
156is used, all the solutions found within the given bounds are returned.
157The option
158.Fl s
159overwrites these default behaviors and at most
160.Ar N
161solutions are returned, still satisfiyng the other constraints.
162.
163.It Fl N
164Allow use of NISS.
165.
166.It Fl o
167Only find solutions that require the minimum number of moves.
168.
169.It Fl O Ar N
170Only find solutions that require at most
171.Ar N
172moves more than the optimal solution. If
173.Ar N
174is 0, this is equivalent to
175.Fl o
176.
177.It Fl p
178Plain style: do not print the number of moves.
179.
180.It Fl t Ar N
181Use
182.Ar N
183CPU threads. By default nissy uses only 1 thread. Using more than one
184thread will improve performance, but the optimal number depends on your
185machine and operating system. Generally, using one less than the number
186of threads of your CPU works quite well.
187.
188.It Fl v
189Verbose mode: print some information during the search and print each solution
190as it is found instead of only printing them all together at the end.
191.
192.
193.El
194.
195.It Nm steps
196List all available
197.Ar steps
198for the
199.Ar solve
200command.
201.
202.It Nm twophase Ar scramble
203Find a solution using a two-phase method. This does not guarantee
204to return an optimal solution (and in fact most often it does not),
205but it is very fast.
206.
207.It Nm unniss Ar scramble
208Rewrite the scramble without using NISS.
209.
210.It Nm version
211Display version information.
212.
213.El
214.
215.Sh SCRAMBLES
216All the commands above that accept a scramble also accept a
217.Fl Nm i
218option with no arguments.
219If this option is given, multiple scrambles are read from standard
220input (one per line) until and EOF is found, at which point stdin is cleared.
221.
222.Sh ENVIRONMENT
223Data is stored in the folder pointed to by
224.Nm $NISSYDATA.
225If that variable is unset the folder
226.Nm $XDG_DATA_HOME/nissy
227or
228.Nm $HOME/.nissy
229is 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
234The command:
235.Dl nissy solve -v -O 1 \(dqR\(aqU\(aqFD2L2FR2U2R2BD2LB2D\(aqB2L\(aqR\(aqBD2BU2LU2R\(aqU\(aqF\(dq
236Returns:
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)
244Notice that the solution is printed twice: the first time it is printed as soon
245as it is found as requested by the -v option.
246.Pp
247The 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
249Returns:
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
257On a UNIX shell, the composite command
258.Dl nissy scramble -n 2 | nissy solve -i > file.txt
259Generates two random scrambles, solves them and saves the result to file.txt.
260The 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
270Source 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 @@
1int
2array_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
23void
24epos_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
47void
48epos_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
63void
64fix_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
85void
86fix_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
106Cube
107admissible_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
130int
131edge_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
143int
144piece_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
5static 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 */
11static bool check_centers(Cube cube);
12static bool check_coud_HTM(Cube cube);
13static bool check_coud_URF(Cube cube);
14static bool check_corners_HTM(Cube cube);
15static bool check_corners_URF(Cube cube);
16static bool check_cornershtr(Cube cube);
17static bool check_eofb(Cube cube);
18static bool check_drud(Cube cube);
19static bool check_htr(Cube cube);
20
21static bool always_valid(Alg *alg);
22static bool validate_singlecw_ending(Alg *alg);
23
24/* Messages for when cube is not ready ***************************************/
25
26static char check_centers_msg[100] = "cube must be oriented (centers solved)";
27static char check_eo_msg[100] = "EO must be solved on given axis";
28static char check_dr_msg[100] = "DR must be solved on given axis";
29static char check_htr_msg[100] = "HTR must be solved";
30static char check_drany_msg[100] = "DR must be solved on at least one axis";
31
32/* Steps *********************************************************************/
33
34/* Optimal solvers *******************/
35
36Step
37optimal_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
55Step
56optimal_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
76Step
77eofin_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
95Step
96eofbfin_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
114Step
115eorlfin_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
133Step
134eoudfin_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 **************************/
153Step
154eoany_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
172Step
173eofb_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
191Step
192eorl_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
210Step
211eoud_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 **************************/
230Step
231coany_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
248Step
249coud_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
266Step
267corl_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
284Step
285cofb_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
302Step
303coany_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
320Step
321coud_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
338Step
339corl_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
356Step
357cofb_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 *****************/
375Step
376cornershtr_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
393Step
394cornershtr_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
411Step
412corners_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
429Step
430corners_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 **************************/
448Step
449drany_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
467Step
468drud_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
486Step
487drrl_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
505Step
506drfb_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 */
525Step
526dr_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
544Step
545dr_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
563Step
564dr_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
582Step
583dr_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
601Step
602drud_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
620Step
621drrl_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
639Step
640drud_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
658Step
659drfb_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
677Step
678drfb_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
696Step
697drrl_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 */
716Step
717dranyfin_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
735Step
736drudfin_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
754Step
755drrlfin_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
773Step
774drfbfin_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 */
793Step
794htr_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
812Step
813htr_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
831Step
832htr_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
850Step
851htr_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 */
870Step
871htrfin_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
889Step *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
951static bool
952check_centers(Cube cube)
953{
954 return cube.cpos == 0;
955}
956
957static bool
958check_coud_HTM(Cube cube)
959{
960 return cube.coud == 0;
961}
962
963static bool
964check_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
974static bool
975check_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
989static bool
990check_corners_HTM(Cube cube)
991{
992 return cube.cp == 0 && cube.coud == 0;
993}
994
995static bool
996check_cornershtr(Cube cube)
997{
998 return coord_cornershtr.index(cube) == 0;
999}
1000
1001static bool
1002check_eofb(Cube cube)
1003{
1004 return cube.eofb == 0;
1005}
1006
1007static bool
1008check_drud(Cube cube)
1009{
1010 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
1011}
1012
1013static bool
1014check_htr(Cube cube)
1015{
1016 return check_drud(cube) && coord_htr_drud.index(cube) == 0;
1017}
1018
1019static bool
1020always_valid(Alg *alg)
1021{
1022 return true;
1023}
1024
1025static bool
1026validate_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
1050void
1051compute_ind(StepAlt *a, Cube *cube, uint64_t *ind)
1052{
1053
1054}
1055
1056int
1057estimate_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
1078void
1079prepare_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
7static void copy_dfsarg(DfsArg *src, DfsArg *dst);
8static void dfs(DfsArg *arg);
9static void dfs_add_sol(DfsArg *arg);
10static void dfs_niss(DfsArg *arg);
11static bool dfs_move_checkstop(DfsArg *arg);
12static void * instance_thread(void *arg);
13static void multidfs(DfsArg *arg);
14static bool niss_makes_sense(DfsArg *arg);
15static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols);
16
17/* Local functions ***********************************************************/
18
19static void
20copy_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
43static void
44dfs(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
74static void
75dfs_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
99static void
100dfs_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
130static bool
131dfs_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
164static void *
165instance_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
212static void
213multidfs(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
268static bool
269niss_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
292static bool
293solvestop(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
306AlgList *
307solve(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! */
389Alg *
390solve_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
6AlgList * solve(Cube *cube, ChoiceStep *cs, SolveOptions *opts);
7Alg * 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
5static int axis(Move m);
6static void free_alglistnode(AlgListNode *aln);
7static void realloc_alg(Alg *alg, int n);
8
9void
10append_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
27void
28append_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
43static int
44axis(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
74Move
75base_move(Move m)
76{
77 if (m == NULLMOVE)
78 return NULLMOVE;
79 else
80 return m - (m-1)%3;
81}
82
83bool
84commute(Move m1, Move m2)
85{
86 return axis(m1) == axis(m2);
87}
88
89int
90compare(Move m1, Move m2)
91{
92 if (!commute(m1, m2))
93 return 0;
94
95 return m1 < m2 ? 1 : -1;
96}
97
98int
99compare_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
115void
116compose_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
124void
125copy_alg(Alg *src, Alg *dst)
126{
127 dst->len = dst->len_normal = dst->len_inverse = 0;
128 compose_alg(dst, src);
129}
130
131void
132free_alg(Alg *alg)
133{
134 free(alg->move);
135 free(alg->inv);
136 free(alg);
137}
138
139void
140free_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
152static void
153free_alglistnode(AlgListNode *aln)
154{
155 free_alg(aln->alg);
156 free(aln);
157}
158
159Alg *
160inverse_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
171Move
172inverse_move(Move m)
173{
174 return m == NULLMOVE ? NULLMOVE : m + 2 - 2*((m-1) % 3);
175}
176
177char *
178move_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
205Alg *
206new_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
309AlgList *
310new_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
321Alg *
322on_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
333void
334print_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
360void
361print_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
369static void
370realloc_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
395void
396remove_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
406void
407swapmove(Move *m1, Move *m2)
408{
409 Move aux;
410
411 aux = *m1;
412 *m1 = *m2;
413 *m2 = aux;
414}
415
416char *
417trans_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
444Alg *
445unniss(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
11void append_alg(AlgList *l, Alg *alg);
12void append_move(Alg *alg, Move m, bool inverse);
13Move base_move(Move m);
14int compare(Move m1, Move m2); /* Return 1 (m1<m2), 0 or -1 (m1>m2) */
15int compare_last(Alg *alg, Move m, bool inverse);
16void compose_alg(Alg *alg1, Alg *alg2);
17bool commute(Move m1, Move m2);
18void copy_alg(Alg *src, Alg *dst);
19void free_alg(Alg *alg);
20void free_alglist(AlgList *l);
21Alg * inverse_alg(Alg *alg);
22Move inverse_move(Move m);
23char * move_string(Move m);
24Alg * new_alg(char *str);
25AlgList * new_alglist();
26Alg * on_inverse(Alg *alg);
27void print_alg(Alg *alg, bool l);
28void print_alglist(AlgList *al, bool l);
29void remove_last_move(Alg *alg);
30void swapmove(Move *m1, Move *m2);
31char * trans_string(Trans t); /* Here because similar to move_string, move? */
32Alg * 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
5static bool read_cs(CommandArgs *args, char *str);
6static bool read_scrtype(CommandArgs *args, char *str);
7static bool read_scramble(int c, char **v, CommandArgs *args);
8
9/* Arg parsing functions implementation **************************************/
10
11CommandArgs *
12solve_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
110CommandArgs *
111scramble_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
140CommandArgs *
141gen_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
168CommandArgs *
169help_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
186CommandArgs *
187parse_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
201CommandArgs *
202parse_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
213void
214solve_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
242void
243scramble_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
331void
332gen_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
346void
347invert_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
357void
358steps_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
366void
367commands_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
376void
377freemem_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
390void
391print_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/*
401void
402twophase_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
416void
417help_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
438void
439quit_exec(CommandArgs *args)
440{
441 exit(0);
442}
443
444void
445cleanup_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
455void
456unniss_exec(CommandArgs *args)
457{
458 Alg *aux;
459
460 aux = unniss(args->scramble);
461 print_alg(aux, false);
462 free(aux);
463}
464
465void
466version_exec(CommandArgs *args)
467{
468 printf(VERSION"\n");
469}
470
471/* Local functions implementation ********************************************/
472
473static bool
474read_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
504static bool
505read_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
521static bool
522read_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
538void
539free_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
554CommandArgs *
555new_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
12void free_args(CommandArgs *args);
13CommandArgs * new_args();
14
15/* Arg parsing functions *****************************************************/
16
17CommandArgs * gen_parse_args(int c, char **v);
18CommandArgs * help_parse_args(int c, char **v);
19CommandArgs * parse_only_scramble(int c, char **v);
20CommandArgs * parse_no_arg(int c, char **v);
21CommandArgs * solve_parse_args(int c, char **v);
22CommandArgs * scramble_parse_args(int c, char **v);
23
24/* Exec functions ************************************************************/
25
26void gen_exec(CommandArgs *args);
27void cleanup_exec(CommandArgs *args);
28void invert_exec(CommandArgs *args);
29void solve_exec(CommandArgs *args);
30void scramble_exec(CommandArgs *args);
31void steps_exec(CommandArgs *args);
32void commands_exec(CommandArgs *args);
33void freemem_exec(CommandArgs *args);
34void print_exec(CommandArgs *args);
35/*void twophase_exec(CommandArgs *args);*/
36void help_exec(CommandArgs *args);
37void quit_exec(CommandArgs *args);
38void unniss_exec(CommandArgs *args);
39void version_exec(CommandArgs *args);
40
41/* Commands ******************************************************************/
42
43#ifndef COMMANDS_C
44
45extern Command cleanup_cmd;
46extern Command commands_cmd;
47extern Command freemem_cmd;
48extern Command gen_cmd;
49extern Command help_cmd;
50extern Command invert_cmd;
51extern Command print_cmd;
52extern Command quit_cmd;
53extern Command scramble_cmd;
54extern Command solve_cmd;
55extern Command steps_cmd;
56extern Command unniss_cmd;
57extern Command version_cmd;
58
59extern Command *commands[];
60
61#else
62
63Command
64solve_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
72Command
73scramble_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
81Command
82gen_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
90Command
91invert_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
99Command
100steps_cmd = {
101 .name = "steps",
102 .usage = "steps",
103 .description = "List available steps",
104 .parse_args = parse_no_arg,
105 .exec = steps_exec
106};
107
108Command
109commands_cmd = {
110 .name = "commands",
111 .usage = "commands",
112 .description = "List available commands",
113 .parse_args = parse_no_arg,
114 .exec = commands_exec
115};
116
117Command
118freemem_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
126Command
127print_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
135Command
136help_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/*
145Command
146twophase_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
155Command
156quit_cmd = {
157 .name = "quit",
158 .usage = "quit",
159 .description = "Quit nissy",
160 .parse_args = parse_no_arg,
161 .exec = quit_exec,
162};
163
164Command
165cleanup_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
173Command
174unniss_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
182Command
183version_cmd = {
184 .name = "version",
185 .usage = "version",
186 .description = "print nissy version",
187 .parse_args = parse_no_arg,
188 .exec = version_exec,
189};
190
191Command *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
5static void gen_coord_comp(Coordinate *coord);
6static void gen_coord_sym(Coordinate *coord);
7static bool read_coord_mtable(Coordinate *coord);
8static bool read_coord_sd(Coordinate *coord);
9static bool read_coord_ttable(Coordinate *coord);
10static bool write_coord_mtable(Coordinate *coord);
11static bool write_coord_sd(Coordinate *coord);
12static bool write_coord_ttable(Coordinate *coord);
13
14/* Indexers ******************************************************************/
15
16uint64_t
17index_eofb(Cube *cube)
18{
19 return (uint64_t)digit_array_to_int(cube->eo, 11, 2);
20}
21
22uint64_t
23index_coud(Cube *cube)
24{
25 return (uint64_t)digit_array_to_int(cube->co, 7, 3);
26}
27
28uint64_t
29index_cp(Cube *cube)
30{
31 return (uint64_t)perm_to_index(cube->cp, 8);
32}
33
34uint64_t
35index_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
45uint64_t
46index_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
56uint64_t
57index_epud(Cube *cube)
58{
59 return (uint64_t)perm_to_index(cube->ep, 8);
60}
61
62uint64_t
63index_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
73uint64_t
74index_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
90void
91invindex_eofb(uint64_t ind, Cube *cube)
92{
93 int_to_sum_zero_array(ind, 2, 12, cube->eo);
94}
95
96void
97invindex_coud(uint64_t ind, Cube *cube)
98{
99 int_to_sum_zero_array(ind, 3, 8, cube->co);
100}
101
102void
103invindex_cp(uint64_t ind, Cube *cube)
104{
105 index_to_perm(ind, 8, cube->cp);
106}
107
108void
109invindex_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
119void
120invindex_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
129void
130invindex_epud(uint64_t ind, Cube *cube)
131{
132 index_to_perm(ind, 8, cube->ep);
133}
134
135void
136invindex_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
148void
149invindex_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
169uint64_t
170indexers_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
181uint64_t
182indexers_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
195void
196indexers_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
214static void
215gen_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
267static void
268gen_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
340static bool
341read_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
370static bool
371read_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
398static bool
399read_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
423static bool
424write_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
453static bool
454write_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
481static bool
482write_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
508void
509gen_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
542error_gc:
543 fprintf(stderr, "Error generating coordinates.\n"
544 "This is a bug, pleae report.\n");
545 exit(1);
546}
547
548uint64_t
549index_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
586uint64_t
587move_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
629uint64_t
630trans_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
6void gen_coord(Coordinate *coord);
7uint64_t index_coord(Coordinate *coord, Cube *cube,
8 Trans *offtrans);
9uint64_t indexers_getind(Indexer **is, Cube *c);
10void indexers_makecube(Indexer **is, uint64_t ind, Cube *c);
11uint64_t move_coord(Coordinate *coord, Move m,
12 uint64_t ind, Trans *offtrans);
13uint64_t trans_coord(Coordinate *coord, Trans t, uint64_t ind);
14
15/* Base coordinates and their index functions ********************************/
16
17#ifndef COORD_C
18
19extern Coordinate coord_eofb;
20extern Coordinate coord_coud;
21extern Coordinate coord_cp;
22extern Coordinate coord_cpudsep;
23extern Coordinate coord_epos;
24extern Coordinate coord_epe;
25extern Coordinate coord_eposepe;
26extern Coordinate coord_epud;
27extern Coordinate coord_eofbepos;
28extern Coordinate coord_coud_cpudsep;
29extern Coordinate coord_eofbepos_sym16;
30extern Coordinate coord_cp_sym16;
31extern Coordinate coord_corners_sym16;
32extern Coordinate coord_drud_sym16;
33extern Coordinate coord_drudfin_noE_sym16;
34extern Coordinate coord_nxopt31;
35
36extern Coordinate *all_coordinates[];
37
38#else
39
40/* Indexers ******************************************************************/
41
42uint64_t index_eofb(Cube *cube);
43void invindex_eofb(uint64_t ind, Cube *ret);
44Indexer
45i_eofb = {
46 .n = POW2TO11,
47 .index = index_eofb,
48 .to_cube = invindex_eofb,
49};
50
51uint64_t index_coud(Cube *cube);
52void invindex_coud(uint64_t ind, Cube *ret);
53Indexer
54i_coud = {
55 .n = POW3TO7,
56 .index = index_coud,
57 .to_cube = invindex_coud,
58};
59
60uint64_t index_cp(Cube *cube);
61void invindex_cp(uint64_t ind, Cube *ret);
62Indexer
63i_cp = {
64 .n = FACTORIAL8,
65 .index = index_cp,
66 .to_cube = invindex_cp,
67};
68
69uint64_t index_cpudsep(Cube *cube);
70void invindex_cpudsep(uint64_t ind, Cube *ret);
71Indexer
72i_cpudsep = {
73 .n = BINOM8ON4,
74 .index = index_cpudsep,
75 .to_cube = invindex_cpudsep,
76};
77
78uint64_t index_epos(Cube *cube);
79void invindex_epos(uint64_t ind, Cube *ret);
80Indexer
81i_epos = {
82 .n = BINOM12ON4,
83 .index = index_epos,
84 .to_cube = invindex_epos,
85};
86
87uint64_t index_epe(Cube *cube);
88void invindex_epe(uint64_t ind, Cube *ret);
89Indexer
90i_epe = {
91 .n = FACTORIAL4,
92 .index = index_epe,
93 .to_cube = invindex_epe,
94};
95
96uint64_t index_eposepe(Cube *cube);
97void invindex_eposepe(uint64_t ind, Cube *ret);
98Indexer
99i_eposepe = {
100 .n = BINOM12ON4 * FACTORIAL4,
101 .index = index_eposepe,
102 .to_cube = invindex_eposepe,
103};
104
105uint64_t index_epud(Cube *cube);
106void invindex_epud(uint64_t ind, Cube *ret);
107Indexer
108i_epud = {
109 .n = FACTORIAL8,
110 .index = index_epud,
111 .to_cube = invindex_epud,
112};
113
114/* Composite coordinates *****************************************************/
115
116Coordinate
117coord_eofb = {
118 .name = "eofb",
119 .type = COMP_COORD,
120 .i = {&i_eofb, NULL},
121};
122
123Coordinate
124coord_coud = {
125 .name = "coud",
126 .type = COMP_COORD,
127 .i = {&i_coud, NULL},
128};
129
130Coordinate
131coord_cp = {
132 .name = "cp",
133 .type = COMP_COORD,
134 .i = {&i_cp, NULL},
135};
136
137Coordinate
138coord_cpudsep = {
139 .name = "cpudsep",
140 .type = COMP_COORD,
141 .i = {&i_cpudsep, NULL},
142};
143
144Coordinate
145coord_epos = {
146 .name = "epos",
147 .type = COMP_COORD,
148 .i = {&i_epos, NULL},
149};
150
151Coordinate
152coord_epe = {
153 .name = "epe",
154 .type = COMP_COORD,
155 .i = {&i_epe, NULL},
156};
157
158Coordinate
159coord_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
165Coordinate
166coord_epud = {
167 .name = "epud",
168 .type = COMP_COORD,
169 .i = {&i_epud, NULL},
170};
171
172Coordinate
173coord_eofbepos = {
174 .name = "eofbepos",
175 .type = COMP_COORD,
176 .i = {&i_epos, &i_eofb, NULL},
177};
178
179Coordinate
180coord_coud_cpudsep = {
181 .name = "coud_cpudsep",
182 .type = COMP_COORD,
183 .i = {&i_coud, &i_cpudsep, NULL},
184};
185
186/* Symcoordinates ************************************************************/
187
188Coordinate
189coord_eofbepos_sym16 = {
190 .name = "eofbepos_sym16",
191 .type = SYM_COORD,
192 .base = {&coord_eofbepos, NULL},
193 .tgrp = &tgrp_udfix,
194};
195
196Coordinate
197coord_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
206Coordinate
207coord_corners_sym16 = {
208 .name = "corners_sym16",
209 .type = SYMCOMP_COORD,
210 .base = {&coord_cp_sym16, &coord_coud},
211};
212
213Coordinate
214coord_drud_sym16 = {
215 .name = "drud_sym16",
216 .type = SYMCOMP_COORD,
217 .base = {&coord_eofbepos_sym16, &coord_coud},
218};
219
220Coordinate
221coord_drudfin_noE_sym16 = {
222 .name = "drudfin_noE_sym16",
223 .type = SYMCOMP_COORD,
224 .base = {&coord_cp_sym16, &coord_epud},
225};
226
227Coordinate
228coord_nxopt31 = {
229 .name = "nxopt31",
230 .type = SYMCOMP_COORD,
231 .base = {&coord_eofbepos_sym16, &coord_coud_cpudsep},
232};
233
234/* All coordinates ***********************************************************/
235
236Coordinate *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
5static int where_is_piece(int piece, int *arr, int n);
6
7void
8compose_centers(Cube *c2, Cube *c1)
9{
10 apply_permutation(c2->xp, c1->xp, 6);
11}
12
13void
14compose_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
21void
22compose_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
29void
30compose(Cube *c2, Cube *c1)
31{
32 compose_centers(c2, c1);
33 compose_corners(c2, c1);
34 compose_edges(c2, c1);
35}
36
37void
38copy_cube_centers(Cube *src, Cube *dst)
39{
40 memcpy(dst->xp, src->xp, 6 * sizeof(int));
41}
42
43void
44copy_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
50void
51copy_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
57void
58copy_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
65bool
66equal(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
85void
86invert_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
97void
98invert_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
111void
112invert_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
125void
126invert_cube(Cube *cube)
127{
128 invert_cube_centers(cube);
129 invert_cube_corners(cube);
130 invert_cube_edges(cube);
131}
132
133bool
134is_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
158bool
159is_solved(Cube *cube)
160{
161 Cube solved_cube;
162 make_solved(&solved_cube);
163
164 return equal(cube, &solved_cube);
165}
166
167void
168make_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
175void
176make_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
184void
185make_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
193void
194make_solved(Cube *cube)
195{
196 make_solved_centers(cube);
197 make_solved_corners(cube);
198 make_solved_edges(cube);
199}
200
201void
202print_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
242int
243where_is_center(Center x, Cube *c)
244{
245 return where_is_piece(x, c->xp, 6);
246}
247
248int
249where_is_corner(Corner k, Cube *c)
250{
251 return where_is_piece(k, c->cp, 8);
252}
253
254int
255where_is_edge(Edge e, Cube *c)
256{
257 return where_is_piece(e, c->ep, 12);
258}
259
260static int
261where_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
10void compose(Cube *c2, Cube *c1); /* Use c2 as an alg on c1 */
11void compose_centers(Cube *c2, Cube *c1);
12void compose_corners(Cube *c2, Cube *c1);
13void compose_edges(Cube *c2, Cube *c1);
14void copy_cube(Cube *src, Cube *dst);
15void copy_cube_centers(Cube *src, Cube *dst);
16void copy_cube_corners(Cube *src, Cube *dst);
17void copy_cube_edges(Cube *src, Cube *dst);
18bool equal(Cube *c1, Cube *c2);
19void invert_cube(Cube *cube);
20void invert_cube_centers(Cube *cube);
21void invert_cube_corners(Cube *cube);
22void invert_cube_edges(Cube *cube);
23bool is_admissible(Cube *cube);
24bool is_solved(Cube *cube);
25void make_solved(Cube *cube);
26void make_solved_centers(Cube *cube);
27void make_solved_corners(Cube *cube);
28void make_solved_edges(Cube *cube);
29void print_cube(Cube *cube);
30int where_is_center(Center x, Cube *c);
31int where_is_corner(Corner k, Cube *c);
32int 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
17typedef enum
18center
19{
20 U_center, D_center,
21 R_center, L_center,
22 F_center, B_center
23} Center;
24
25typedef enum
26corner
27{
28 UFR, UFL, UBL, UBR,
29 DFR, DFL, DBL, DBR
30} Corner;
31
32typedef enum
33coordtype
34{
35 COMP_COORD, SYM_COORD, SYMCOMP_COORD
36} CoordType;
37
38typedef enum
39edge
40{
41 UF, UL, UB, UR,
42 DF, DL, DB, DR,
43 FR, FL, BL, BR
44} Edge;
45
46typedef enum
47move
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
64typedef enum
65trans
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
84typedef struct alg Alg;
85typedef struct alglist AlgList;
86typedef struct alglistnode AlgListNode;
87typedef struct choicestep ChoiceStep;
88typedef struct command Command;
89typedef struct commandargs CommandArgs;
90typedef struct coordinate Coordinate;
91typedef struct cube Cube;
92/*typedef struct dfsarg DfsArg;*/
93typedef struct fstcube FstCube;
94typedef struct indexer Indexer;
95typedef struct movable Movable;
96typedef struct moveset Moveset;
97typedef struct prunedata PruneData;
98typedef struct solveoptions SolveOptions;
99typedef struct step Step;
100typedef struct symdata SymData;
101typedef struct threaddatasolve ThreadDataSolve;
102typedef struct threaddatagenpt ThreadDataGenpt;
103typedef struct transgroup TransGroup;
104
105typedef bool (*Checker) (Cube *);
106typedef bool (*CubeTester) (Cube *, Alg *);
107/*typedef bool (*DfsMover) (DfsArg *);*/
108typedef void (*DfsExtraCopier) (void *, void *);
109typedef Alg * (*Validator) (Alg *);
110typedef void (*Exec) (CommandArgs *);
111typedef CommandArgs * (*ArgParser) (int, char **);
112typedef bool (*Tester) (void);
113typedef int (*TransFinder) (uint64_t, Trans *);
114
115
116/* Structs *******************************************************************/
117
118struct
119alg
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
131struct
132alglist
133{
134 AlgListNode * first;
135 AlgListNode * last;
136 int len;
137};
138
139struct
140alglistnode
141{
142 Alg * alg;
143 AlgListNode * next;
144};
145
146struct
147choicestep
148{
149 char * shortname;
150 char * name;
151 Step * step[99];
152 Trans t[99];
153 char * ready_msg;
154};
155
156struct
157command
158{
159 char * name;
160 char * usage;
161 char * description;
162 ArgParser parse_args;
163 Exec exec;
164};
165
166struct
167commandargs
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
180struct
181coordinate
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
199struct
200cube
201{
202 int ep[12];
203 int eo[12];
204 int cp[8];
205 int co[8];
206 int xp[6];
207};
208
209/*
210struct
211movable
212{
213 uint64_t val;
214 Trans t;
215};
216*/
217
218/*
219struct
220dfsarg
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/*
238struct
239dfsarg
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
253struct
254fstcube
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
268struct
269indexer
270{
271 int n;
272 uint64_t (*index)(Cube *);
273 void (*to_cube)(uint64_t, Cube *);
274};
275
276struct
277moveset
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
286struct
287prunedata
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
298struct
299solveoptions
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
313struct
314step
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/*
330struct
331threaddatasolve
332{
333 DfsArg arg;
334 int thid;
335 AlgList * start;
336 AlgListNode ** node;
337 pthread_mutex_t * start_mutex;
338};
339*/
340
341struct
342threaddatagenpt
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
353struct
354transgroup
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
5bool initialized_env = false;
6char *tabledir;
7
8void
9mymkdir(char *d, int m)
10{
11#ifdef _WIN32
12 mkdir(d);
13#else
14 mkdir(d, m);
15#endif
16}
17
18void
19init_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
11void init_env();
12
13extern 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
5static FstCube ep_to_fst_epos(int *ep);
6static void init_fst_corner_invtables();
7static void init_fst_eo_invtables();
8static void init_fst_eo_update(uint64_t, uint64_t, int, Cube *);
9static void init_fst_where_is_edge();
10static bool read_fst_tables_file();
11static bool write_fst_tables_file();
12
13static 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
17static uint16_t inv_coud[FACTORIAL8][POW3TO7];
18static uint16_t inv_cp[FACTORIAL8];
19static uint16_t uf_cp_to_fr_cp[FACTORIAL8];
20static uint16_t uf_cp_to_rd_cp[FACTORIAL8];
21static uint16_t eo_invtable[3][POW2TO11][BINOM12ON4*FACTORIAL4];
22static uint16_t fst_where_is_edge_arr[3][12][BINOM12ON4*FACTORIAL4];
23
24FstCube
25cube_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
49static FstCube
50ep_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
112FstCube
113fst_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
154FstCube
155fst_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
179void
180fst_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
208void
209init_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
228static void
229init_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
259static void
260init_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
285static void
286init_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
297static void
298init_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
329static bool
330read_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
366static bool
367write_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
6FstCube cube_to_fst(Cube *cube);
7FstCube fst_inverse(FstCube fst);
8FstCube fst_move(Move m, FstCube fst);
9void fst_to_cube(FstCube fst, Cube *cube);
10void 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
7static 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
15static Cube move_array[NMOVES];
16
17static 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
82void
83apply_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
103void
104apply_move(Move m, Cube *cube)
105{
106 compose(&move_array[m], cube);
107}
108
109void
110apply_move_centers(Move m, Cube *cube)
111{
112 compose_centers(&move_array[m], cube);
113}
114
115void
116apply_move_corners(Move m, Cube *cube)
117{
118 compose_corners(&move_array[m], cube);
119}
120
121void
122apply_move_edges(Move m, Cube *cube)
123{
124 compose_edges(&move_array[m], cube);
125}
126
127Alg *
128cleanup(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
179static void
180cleanup_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
244void
245init_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
8void apply_alg(Alg *alg, Cube *cube);
9void apply_move(Move m, Cube *cube);
10void apply_move_centers(Move m, Cube *cube);
11void apply_move_corners(Move m, Cube *cube);
12void apply_move_edges(Move m, Cube *cube);
13Alg * cleanup(Alg *alg);
14
15void 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
5static bool allowed_HTM(Move m);
6static bool allowed_URF(Move m);
7static bool allowed_eofb(Move m);
8static bool allowed_drud(Move m);
9static bool allowed_htr(Move m);
10static bool can_append_HTM(Move l2, Move l1, Move m);
11static bool can_append_HTM_cached(Alg *alg, Move m, bool inverse);
12static bool cancel_niss_HTM_cached(Alg *alg);
13static void init_can_append_HTM();
14
15Moveset
16moveset_HTM = {
17 .name = "HTM",
18 .allowed = allowed_HTM,
19 .can_append = can_append_HTM_cached,
20 .cancel_niss = cancel_niss_HTM_cached,
21};
22
23Moveset
24moveset_URF = {
25 .name = "URF",
26 .allowed = allowed_URF,
27 .can_append = can_append_HTM_cached,
28 .cancel_niss = cancel_niss_HTM_cached,
29};
30
31Moveset
32moveset_eofb = {
33 .name = "eofb",
34 .allowed = allowed_eofb,
35 .can_append = can_append_HTM_cached,
36 .cancel_niss = cancel_niss_HTM_cached,
37};
38
39Moveset
40moveset_drud = {
41 .name = "drud",
42 .allowed = allowed_drud,
43 .can_append = can_append_HTM_cached,
44 .cancel_niss = cancel_niss_HTM_cached,
45};
46
47Moveset
48moveset_htr = {
49 .name = "htr",
50 .allowed = allowed_htr,
51 .can_append = can_append_HTM_cached,
52 .cancel_niss = cancel_niss_HTM_cached,
53};
54
55Moveset *
56all_movesets[] = {
57 &moveset_HTM,
58 &moveset_URF,
59 &moveset_eofb,
60 &moveset_drud,
61 &moveset_htr,
62 NULL
63};
64
65static uint64_t can_append_HTM_mask[NMOVES][NMOVES];
66
67static bool
68allowed_HTM(Move m)
69{
70 return m >= U && m <= B3;
71}
72
73static bool
74allowed_URF(Move m)
75{
76 Move b = base_move(m);
77
78 return b == U || b == R || b == F;
79}
80
81static bool
82allowed_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
90static bool
91allowed_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
99static bool
100allowed_htr(Move m)
101{
102 Move b = base_move(m);
103
104 return moveset_HTM.allowed(m) && m == b + 1;
105}
106
107static bool
108can_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
119static bool
120can_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
142static bool
143cancel_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
159static void
160init_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
172void
173init_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
187void
188init_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
6void init_moveset(Moveset *);
7void init_movesets();
8
9extern Moveset moveset_HTM;
10extern Moveset moveset_URF;
11extern Moveset moveset_eofb;
12extern Moveset moveset_drud;
13extern 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
8static int findchunk(PruneData *pd, int nchunks, uint64_t i);
9static void genptable_bfs(PruneData *pd, int d, int nt, int nc);
10static void genptable_fixnasty(PruneData *pd, int d, int nthreads);
11static void * instance_bfs(void *arg);
12static void * instance_fixnasty(void *arg);
13static void ptable_update(PruneData *pd, uint64_t ind, int m);
14static bool read_ptable_file(PruneData *pd);
15static bool write_ptable_file(PruneData *pd);
16
17PruneData *active_pd[256];
18
19int
20findchunk(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
30PruneData *
31genptable(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
98genptable_done:
99 for (i = 0; active_pd[i] != NULL; i++);
100 return active_pd[i] = pd;
101}
102
103static void
104genptable_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
137static void
138genptable_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
165static void *
166instance_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
228static void *
229instance_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
279void
280print_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
295uint64_t
296ptablesize(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
305static void
306ptable_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
324int
325ptableval(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
344static bool
345read_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
373static bool
374write_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
7void free_pd(PruneData *pd);
8PruneData * genptable(PruneData *data, int nthreads);
9void print_ptable(PruneData *pd);
10uint64_t ptablesize(PruneData *pd);
11int ptableval(PruneData *pd, uint64_t ind);
12
13extern 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
5static void cleanwhitespaces(char *line);
6static int parseline(char *line, char **v);
7
8bool
9checkfiles()
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
32static void
33cleanwhitespaces(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 */
43static int
44parseline(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
57void
58exec_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
105void
106launch(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
146int
147main(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
10bool checkfiles();
11void exec_args(int c, char **v);
12void 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
5void
6dfs(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
18validate to null */
19
20/* TODO: we also have to check if cancel with NISS;
21we can't because we have no access to the s->final field
22this 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
73AlgList *
74solve(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
8typedef struct dfsarg DfsArg;
9typedef struct threader Threader;
10typedef struct solver Solver;
11
12/* TODO: add solver and threader in DfsData, remove from dispatch args and similar */
13
14struct dfsarg {
15 void * cubedata;
16 void * threaddata;
17 SolveOptions * opts;
18 int d;
19 bool niss;
20 Alg * current_alg;
21};
22
23struct 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
30struct 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
50void dfs(DfsArg *, Solver *, Threader *);
51/* TODO: remove dependence on Cube, preparation should be done before */
52AlgList * 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
3typedef struct {
4 Cube * cube;
5 uint64_t * val;
6 Trans * t;
7} CubeData;
8
9static void apply_move_cubedata(void *, void *, Move);
10static void init_indexes(Step *, CubeData *);
11static void * prepare_cube(void *, Cube *);
12static bool move_check_stop_eager(void *, DfsArg *, Threader *);
13static bool move_check_stop_lazy(void *, DfsArg *, Threader *);
14static bool move_check_stop_nonsol(void *, DfsArg *, Threader *);
15static bool is_solved_step(void *, void *);
16static Alg * validate_solution(void *, Alg *);
17static void * alloc_cubedata(void *);
18static void copy_cubedata(void *, void *, void *);
19static void free_cubedata(void *, void *);
20static void invert_cubedata(void *, void *);
21static bool niss_makes_sense(void *, void *, Alg *);
22static Solver * new_stepsolver_nocheckstop(Step *step);
23
24static void
25apply_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
38static void
39init_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
54static void *
55prepare_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
84static bool
85move_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
96static bool
97move_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 */
110static bool
111move_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
146static bool
147is_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
163static Alg *
164validate_solution(void *param, Alg *alg)
165{
166 return ((Step *)param)->is_valid(alg);
167}
168
169static void *
170alloc_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
185static void
186copy_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
205static void
206free_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
218static void
219invert_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
231static bool
232niss_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
257static Solver *
258new_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
280Solver *
281new_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
291Solver *
292new_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
302void
303free_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
8Solver *new_stepsolver_eager(Step *);
9Solver *new_stepsolver_lazy(Step *);
10void 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
7bool
8check_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
19bool
20check_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
31bool
32check_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
47bool
48check_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
59bool
60check_corners_HTM(Cube *cube)
61{
62 return check_coud_HTM(cube) && check_cp_HTM(cube);
63}
64
65bool
66check_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
81bool
82check_cornershtr(Cube *cube)
83{
84 /* TODO (use coord) */
85 return true;
86}
87
88bool
89check_eofb(Cube *cube)
90{
91 /* TODO (use coord) */
92 return true;
93}
94
95bool
96check_drud(Cube *cube)
97{
98 /* TODO (use coord) */
99 return true;
100}
101
102bool
103check_htr(Cube *cube)
104{
105 /* TODO (check_drud(cube) and coord_htr_drud == 0) */
106 return true;
107}
108
109Alg *
110validate_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/*
143void
144compute_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
161void
162prepare_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
7bool check_centers(Cube *cube);
8bool check_coud_HTM(Cube *cube);
9bool check_coud_URF(Cube *cube);
10bool check_cp_HTM(Cube *cube);
11bool check_corners_HTM(Cube *cube);
12bool check_corners_URF(Cube *cube);
13bool check_cornershtr(Cube *cube);
14bool check_eofb(Cube *cube);
15bool check_drud(Cube *cube);
16bool check_htr(Cube *cube);
17/*void compute_ind(Step *a, Cube *cube, Movable *ind);*/
18void prepare_cs(ChoiceStep *cs, SolveOptions *opts);
19bool always_valid(Alg *alg);
20Alg * validate_singlecw_ending(Alg *alg);
21
22#ifndef STEPS_C
23
24extern char check_centers_msg[100];
25extern char check_eo_msg[100];
26extern char check_dr_msg[100];
27extern char check_htr_msg[100];
28extern char check_drany_msg[100];
29
30extern Step step_eofb_HTM;
31extern Step step_drud_HTM;
32extern Step step_drfin_drud;
33
34extern ChoiceStep optimal_HTM;
35extern ChoiceStep eoany_HTM;
36extern ChoiceStep eofb_HTM;
37extern ChoiceStep eorl_HTM;
38extern ChoiceStep eoud_HTM;
39extern ChoiceStep drany_HTM;
40extern ChoiceStep drud_HTM;
41extern ChoiceStep drrl_HTM;
42extern ChoiceStep drfb_HTM;
43extern ChoiceStep dranyfin_DR;
44extern ChoiceStep drudfin_drud;
45extern ChoiceStep drrlfin_drrl;
46extern ChoiceStep drfbfin_drfb;
47
48extern ChoiceStep *csteps[];
49
50#else
51
52char check_centers_msg[100] = "cube must be oriented (centers solved)";
53char check_eo_msg[100] = "EO must be solved on given axis";
54char check_dr_msg[100] = "DR must be solved on given axis";
55char check_htr_msg[100] = "HTR must be solved";
56char 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
64Step
65step_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};
74ChoiceStep
75eoany_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};
82ChoiceStep
83eofb_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};
90ChoiceStep
91eorl_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};
98ChoiceStep
99eoud_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
120Step
121step_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};
130ChoiceStep
131drany_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};
138ChoiceStep
139drud_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};
146ChoiceStep
147drrl_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};
154ChoiceStep
155drfb_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 */
164Step
165step_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};
174ChoiceStep
175dranyfin_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};
183ChoiceStep
184drudfin_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};
191ChoiceStep
192drrlfin_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};
199ChoiceStep
200drfbfin_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
214ChoiceStep *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
223NULL
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
4typedef struct {
5 AlgList * sols;
6 pthread_mutex_t * sols_mutex;
7} ThreadData;
8
9typedef 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
18static void append_sol(Alg *, void *);
19static void * instance_thread(void *);
20static void dispatch(DfsArg *, AlgList *, Solver *, Threader *);
21static AlgList * possible_starts(DfsArg *, Solver *);
22static int get_nsol(void *);
23
24Threader threader_eager = {
25 .append_sol = append_sol,
26 .dispatch = dispatch,
27 .get_nsol = get_nsol,
28};
29
30static void
31append_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
40static AlgList *
41possible_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
70static void *
71instance_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
114static void
115dispatch(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
153static int
154get_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
6extern 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
3static void append_sol(Alg *, void *);
4static void dispatch(DfsArg *, AlgList *, Solver *, Threader *);
5static int get_nsol(void *);
6
7Threader threader_single = {
8 .append_sol = append_sol,
9 .dispatch = dispatch,
10 .get_nsol = get_nsol,
11};
12
13static void
14append_sol(Alg *alg, void *threaddata)
15{
16 append_alg((AlgList *)threaddata, alg);
17}
18
19static void
20dispatch(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
31static int
32get_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
6extern 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
9static 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
20static 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
29Alg *rotation_alg_arr[NROTATIONS];
30Move moves_ttable[NTRANS][NMOVES];
31Trans trans_ttable[NTRANS][NTRANS];
32Trans trans_itable[NTRANS];
33
34/* Public functions **********************************************************/
35
36void
37apply_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/*
62Trans
63inverse_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
91Trans
92inverse_trans(Trans t)
93{
94 return trans_itable[t];
95}
96
97Alg *
98rotation_alg(Trans i)
99{
100 return rotation_alg_arr[i % NROTATIONS];
101}
102
103void
104transform_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
112Move
113transform_move(Trans t, Move m)
114{
115 return moves_ttable[t][m];
116}
117
118Trans
119transform_trans(Trans t, Trans m)
120{
121 return trans_ttable[t][m];
122}
123
124void
125init_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
6void apply_trans(Trans t, Cube *cube);
7Trans inverse_trans(Trans t);
8Alg * rotation_alg(Trans i);
9void transform_alg(Trans t, Alg *alg);
10Move transform_move(Trans t, Move m);
11Trans transform_trans(Trans t, Trans m);
12
13void init_trans();
14
15#ifndef TRANS_C
16
17extern TransGroup tgrp_udfix;
18
19#else
20
21TransGroup
22tgrp_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
5void
6apply_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
21int
22binomial(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
30int
31digit_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
41int
42factorial(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
55void
56index_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
81void
82index_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
116void
117int_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
129void
130int_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
145int
146invert_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
159bool
160is_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
184bool
185is_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
195int
196perm_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
210int
211perm_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
228int
229powint(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
242int
243subset_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
262void
263sum_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
271void
272swap(int *a, int *b)
273{
274 int aux;
275
276 aux = *a;
277 *a = *b;
278 *b = aux;
279}
280
281void
282swapu64(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
24void apply_permutation(int *perm, int *set, int n);
25int binomial(int n, int k);
26int digit_array_to_int(int *a, int n, int b);
27int factorial(int n);
28void index_to_perm(int p, int n, int *r);
29void index_to_subset(int s, int n, int k, int *r);
30void int_to_digit_array(int a, int b, int n, int *r);
31void int_to_sum_zero_array(int x, int b, int n, int *a);
32int invert_digits(int a, int b, int n);
33bool is_perm(int *a, int n);
34bool is_subset(int *a, int n, int k);
35int perm_sign(int *a, int n);
36int perm_to_index(int *a, int n);
37int powint(int a, int b);
38int subset_to_index(int *a, int n, int k);
39void sum_arrays_mod(int *src, int *dst, int n, int m);
40void swap(int *a, int *b);
41void 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
3bool testmethod_append_move(void *);
4bool testmethod_new_alg(void *);
5/*
6bool testmethod_compose_alg(void *);
7bool testmethod_inverse_alg(void *);
8bool testmethod_on_inverse(void *);
9bool testmethod_unniss(void *);
10*/
11
12typedef struct {
13 Move *move;
14 bool *inv;
15 int len;
16 Move m;
17 bool inverse;
18} append_move_t;
19
20Move m_app1[] = {F, x, D3};
21bool i_app1[] = {true, false, false};
22append_move_t append_move_case1 = {
23 .move = m_app1,
24 .inv = i_app1,
25 .len = 3,
26 .m = L3,
27 .inverse = false,
28};
29
30Move m_app2[] = {S, U, x2, M2};
31bool i_app2[] = {true, false, true, true};
32append_move_t append_move_case2 = {
33 .move = m_app2,
34 .inv = i_app2,
35 .len = 4,
36 .m = R,
37 .inverse = true,
38};
39
40Move m_app3[] = {U, U, U, U, U};
41bool i_app3[] = {false, false, false, false, false};
42append_move_t append_move_case3 = {
43 .move = m_app3,
44 .inv = i_app3,
45 .len = 5,
46 .m = U,
47 .inverse = false,
48};
49
50append_move_t *append_move_cases[] = {
51 &append_move_case1,
52 &append_move_case2,
53 &append_move_case3,
54};
55
56Test test_append_move = {
57 .name = "Appending a move to and alg",
58 .t = testmethod_append_move,
59 .cases = (void **)append_move_cases,
60};
61
62typedef 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 */
74Move m_new1[] = {F, U, B3, L3, D, x, M, S, y3};
75Move mn_new1[] = {F, U, B3, x, M, y3};
76Move mi_new1[] = {L3, D, S};
77bool i_new1[] = {false, false, false, true, true, false, false, true, false};
78new_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};
88new_alg_t *new_alg_cases[] = {&new_alg_case1};
89
90Test test_new_alg = {
91 .name = "Initializing an alg from a string",
92 .t = testmethod_new_alg,
93 .cases = (void **)new_alg_cases,
94};
95
96Test *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};
108TestSuite alg_suite = {
109 .setup = NULL,
110 .tests = alg_all_tests,
111 .teardown = NULL,
112};
113
114TestSuite *alg_suites[] = {
115 &alg_suite,
116 NULL
117};
118
119bool
120testmethod_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
202append_move_fail:
203 free(alg);
204 return false;
205}
206
207bool
208testmethod_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
263new_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
7extern Test test_append_move;
8extern Test test_new_alg;
9/*
10extern Test remove_last_move;
11extern Test test_compose_alg;
12extern Test test_inverse_alg;
13extern Test test_on_inverse;
14extern Test test_unniss;
15*/
16
17extern TestSuite alg_suite;
18
19extern 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
3bool testmethod_indexes_consistent(void *);
4
5Test test_indexes_consistent = {
6 .name = "Consitency of index and anti-index",
7 .t = testmethod_indexes_consistent,
8 .cases = (void **)all_coordinates,
9};
10Test *coord_pre_init[] = {
11 &test_indexes_consistent,
12 NULL
13};
14TestSuite coord_pre_init_suite = {
15 .setup = NULL,
16 .tests = coord_pre_init,
17 .teardown = NULL,
18};
19
20TestSuite *coord_suites[] = {
21 &coord_pre_init_suite,
22 NULL
23};
24
25bool
26testmethod_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
7extern Test test_indexes_consistent;
8
9extern TestSuite coord_pre_init_suite;
10
11extern 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
3static bool testmethod_fst_is_consistent(void *);
4static bool testmethod_cube_to_fst_to_cube(void *);
5static bool testmethod_fst_move(void *);
6static bool testmethod_fst_inverse(void *);
7static bool check_equal_and_log(Cube *, Cube *);
8static void void_to_cube(void *, Cube *);
9
10char *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
25Test test_fst_is_consistent = {
26 .name = "Consitency of FST (converted from cube)",
27 .t = testmethod_fst_is_consistent,
28 .cases = (void **)algs,
29};
30Test 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};
35Test test_fst_move = {
36 .name = "FST move",
37 .t = testmethod_fst_move,
38 .cases = (void **)algs,
39};
40Test test_fst_inverse = {
41 .name = "FST inverse",
42 .t = testmethod_fst_inverse,
43 .cases = (void **)algs,
44};
45
46Test *fst_pre_init[] = {
47 &test_fst_is_consistent,
48 &test_cube_to_fst_to_cube,
49 NULL
50};
51TestSuite fst_pre_init_suite = {
52 .setup = NULL,
53 .tests = fst_pre_init,
54 .teardown = NULL,
55};
56
57Test *fst_post_init[] = {
58 &test_fst_move,
59 &test_fst_inverse,
60 NULL
61};
62TestSuite fst_post_init_suite = {
63 .setup = init_fst,
64 .tests = fst_post_init,
65 .teardown = NULL,
66};
67
68TestSuite *fst_suites[] = {
69 &fst_pre_init_suite,
70 &fst_post_init_suite,
71 NULL
72};
73
74static bool
75check_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
91static void
92void_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
104bool
105testmethod_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
138bool
139testmethod_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
151bool
152testmethod_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
174bool
175testmethod_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
7extern char *algs[];
8
9extern Test test_fst_is_consistent;
10extern Test test_cube_to_fst_to_cube;
11extern Test test_fst_move;
12extern Test test_fst_inverse;
13
14extern TestSuite fst_pre_init_suite;
15extern TestSuite fst_post_init_suite;
16
17extern 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
7static bool run_test(Test *);
8static bool run_suite(TestSuite *);
9
10static bool
11run_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
27static bool
28run_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
43static bool
44module_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
52int 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
21typedef void (*VoidMethod)(void);
22typedef bool (*TestMethod)(void *);
23
24typedef struct {
25 char * name;
26 TestMethod t;
27 void ** cases;
28} Test;
29
30typedef struct {
31 VoidMethod setup;
32 Test ** tests;
33 VoidMethod teardown;
34} TestSuite;
35
36typedef 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>
43In this page you can find download links (see above),
44<a href="#Installation">installation instructions</a> and
45<a href="#Upgrade">upgrade instructions</a>
46for nissy. If instead you wish to clone the
47<a href="https://git.tronto.net/nissy/">git repository</a>,
48you can use git:
49</p>
50
51<pre>
52<code>git clone https://git.tronto.net/nissy</code>
53</pre>
54
55<p>
56For 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
58the git repository.
59</p>
60
61<h2 id="Installation">Installation</h2>
62
63<h3>System requirements</h3>
64
65<p>
66A full installation of nissy requires about 3.1Gb of space,
67of which 2.3Gb are occupied by the huge pruning table for fast optimal solving,
68and running it requires the same amount of RAM.
69One can choose to never use this function and not to install the relative
70pruning table. There is an alternative (slower)
71optimal solving function that uses about 500Mb of RAM.
72
73When generating the pruning tables automatically (see the section Tables below),
74at least 5.3Gb or RAM are required.
75</p>
76
77<h3>Windows</h3>
78
79<p>
80Try downloading and executing in a terminal the file <code>nissy.exe</code>,
81then follow the instructions in the <strong>Tables</strong> section below for
82installing the pruning tables.
83If <code>nissy.exe</code> does not work, you can try following the UNIX instructions
84in WSL (Windows Subsystem for Linux) or in a similar environment.
85</p>
86
87<h3>UNIX (Linux, MacOS, *BSD...)</h3>
88<p>
89Download the source archive (.tar.gz). Extract it
90with your favorite archive program, for example with
91</p>
92<pre><code>tar -xvzf nissy-VERSION.tar.gz</code></pre>
93<p>
94Open a terminal in the directory just extracted.
95If 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>
100followed by
101</p>
102<pre><code>make install</code></pre>
103<p>
104Then follow the instructions below to install the pruning tables.
105</p>
106
107<h3>Tables</h3>
108
109<p>
110Once you have installed nissy, run
111</p>
112
113<pre><code>nissy gen</code></pre>
114
115<p>
116to generate all the tables that Nissy will ever need.
117Running 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>
122Some unnecessary technical detail: by default this command is going to use
123at most 64 threads. If you want you can choose to use more threads (if your CPU
124is very powerful) or fewer threads (if you for example want to run this command
125in the background while you do other stuff) with the <code>-t</code> option, for
126example <code>nissy gen -t 1</code>.
127</p>
128
129<p>
130Alternatively, you can
131<a href="/nissy-tables-2.0.2.zip">download all the tables (1.7Gb)</a> and
132copy them into the correct folder (see manual page, <code>ENVIRONMENT</code>
133section). 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.
136On Windows it is the same directory as the <code>nissy.exe</code> executable
137file.
138</p>
139
140<h2 id="Upgrade">Upgrading</h2>
141<p>
142If you already have nissy installed and you want to upgrade to a more
143recent version, you can simply repeat the installation process:
144</p>
145<ul>
146<li>
147On Windows: simply replace nissy.exe with the new file with the same name.
148</li>
149<li>
150On UNIX systems: download the new version of the source code, extract it in
151a new folder and run <code>make</code> and <code>make install</code> again.
152</li>
153</ul>
154<p>
155Between each version new table files might have been added, or old ones
156may 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>
194Nissy v1 was released in 2020. It was slow, full of bugs and the code
195was 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>
34Nissy is a command-line Rubik's cube solver. It can find optimal solutions
35for random positions using techniques from Herbert Kociemba's
36<a href="http://kociemba.org/cube.htm">Cube Explorer</a> and
37Tomas Rokicki's
38<a href="https://github.com/rokici/cube20src/blob/master/nxopt.md">nxopt</a>.
39With 4 cores at 2.5GHz and using about 3Gb of RAM, Nissy can find an optimal
40solution in about a minute on average.
41</p>
42
43<p>
44Nissy aims at being a complete tool
45for FMC (Fewest Moves Challenge) practice. It can solve different steps
46of Thistlethwaite's algorithm (also know as DR/HTR) and cans use NISS
47(Normal-Inverse Scramble Switch).
48</p>
49
50<p>
51You should use Nissy if:
52</p>
53<ul>
54<li>
55You 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>
59You just want a Rubik's cube solver and you like command line interfaces.
60</li>
61<li>
62You want an alternative to Cube Explorer.
63</li>
64</ul>
65
66<p>
67To get started, head to the <a href="/download/">download</a> page.
68</p>
69
70<p>
71You 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
24body {
25 margin: auto 8px 20px 8px;
26}
27
28img {
29 display: block;
30 margin-left: auto;
31 margin-right: auto;
32 max-width: 100%;
33}
34
35code {
36 background-color: #eeeeee;
37 padding: 2px;
38}
39
40pre code {
41 padding: 0px;
42}
43
44pre {
45 background-color: #eeeeee;
46 border: 2px solid;
47 padding: 6px;
48}
49
50#blob {
51 background: #ffffff;
52 border: none;
53}
54
55a {
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
70a:hover {
71 text-decoration: underline;
72}
73
74html {
75 margin: 1em auto;
76 max-width: 42em;
77}
78
79h1 {
80 text-align: center;
81}
82
83td h1 {
84 text-align: left;
85 font-size: 1.5em;
86}
87
88table {
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}

Generated with cgit - Back to sebastiano.tronto.net