├── MANIFEST.in ├── requirements.txt ├── pyproject.toml ├── pyTwistyScrambler ├── miscScrambler.py ├── pyraminxScrambler.py ├── skewbScrambler.py ├── scrambler222.py ├── squareOneScrambler.py ├── scrambler666.py ├── scrambler777.py ├── js_resources │ ├── 1x3x3.js │ ├── 2x2x2.js │ ├── 2x2x3.js │ ├── pyraminx.js │ ├── skewb.js │ ├── cross.js │ ├── mathlib.js │ ├── scramble.js │ ├── megascramble.js │ ├── utilscramble.js │ ├── scramble_sq1.js │ └── scramble_333_edit.js ├── clockScrambler.py ├── megaminxScrambler.py ├── bigCubesScrambler.py ├── scrambler555.py ├── scrambler444.py ├── cuboidsScrambler.py ├── __init__.py ├── ftoScrambler.py ├── rexScrambler.py └── scrambler333.py ├── setup.py ├── LICENSE ├── .gitignore └── README.md /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include pyTwistyScrambler/js_resources/*.js -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | appdirs==1.4.0 2 | packaging==16.8 3 | PyExecJS==1.5.1 4 | pyparsing==2.1.10 5 | six==1.10.0 6 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools>=42", 4 | "wheel" 5 | ] 6 | build-backend = "setuptools.build_meta" 7 | -------------------------------------------------------------------------------- /pyTwistyScrambler/miscScrambler.py: -------------------------------------------------------------------------------- 1 | from . import _UTIL_SCRAMBLER, trim 2 | 3 | # ------------------------------------------------------------------------------ 4 | 5 | 6 | @trim 7 | def get_bicube_scramble(): 8 | """Returns a scramble for a BiCube, aka Meffert's Bandaged Cube.""" 9 | return _UTIL_SCRAMBLER.call("util_scramble.getBicubeScramble") 10 | -------------------------------------------------------------------------------- /pyTwistyScrambler/pyraminxScrambler.py: -------------------------------------------------------------------------------- 1 | from . import _PYRA_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_WCA_scramble(): 7 | """ Gets a WCA scramble of a Pyraminx. """ 8 | return _PYRA_SCRAMBLER.call("pyra_scrambler.getPyraWCAScramble") 9 | 10 | @trim 11 | def get_optimal_scramble(): 12 | """ Gets an optimal scramble of a Pyraminx. """ 13 | return _PYRA_SCRAMBLER.call("pyra_scrambler.getPyraOptimalScramble") -------------------------------------------------------------------------------- /pyTwistyScrambler/skewbScrambler.py: -------------------------------------------------------------------------------- 1 | from . import _MEGA_SCRAMBLER, _SKEWB_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_WCA_scramble(): 7 | """ Gets a WCA scramble of a Skewb. """ 8 | return _SKEWB_SCRAMBLER.call("skewb_scrambler.getSkewbWCAScramble") 9 | 10 | @trim 11 | def get_ULRB_scramble(): 12 | """ Gets a ULRB scramble of a Skewb. """ 13 | return _MEGA_SCRAMBLER.call("megaScrambler.getSkewbULRBScramble") -------------------------------------------------------------------------------- /pyTwistyScrambler/scrambler222.py: -------------------------------------------------------------------------------- 1 | from . import _222_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_WCA_scramble(): 7 | """ Gets a WCA random scramble (sub-optimal) of a 2x2x2 cube. """ 8 | return _222_SCRAMBLER.call("scramble_222.getRandomScramble") 9 | 10 | @trim 11 | def get_random_scramble(): 12 | """ Gets a WCA random scramble (sub-optimal) of a 2x2x2 cube. """ 13 | return _222_SCRAMBLER.call("scramble_222.getRandomScramble") 14 | 15 | @trim 16 | def get_optimal_scramble(): 17 | """ Gets an optimal random state scramble of a 2x2x2 cube. """ 18 | return _222_SCRAMBLER.call("scramble_222.getOptimalScramble") -------------------------------------------------------------------------------- /pyTwistyScrambler/squareOneScrambler.py: -------------------------------------------------------------------------------- 1 | from . import _SQ1_SCRAMBLER, _UTIL_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_WCA_scramble(): 7 | """ Gets a WCA scramble for a Square-1. """ 8 | return _SQ1_SCRAMBLER.call("sql_scrambler.getRandomScramble") 9 | 10 | @trim 11 | def get_face_turn_metric_scramble(n=40): 12 | """ Gets a face turn metric scramble of length `n` for a Square-1. Defaults to csTimer's default length of 40. """ 13 | return _UTIL_SCRAMBLER.call("util_scramble.getSquareOneTurnMetricScramble", n) 14 | 15 | @trim 16 | def get_twist_metric_scramble(n=20): 17 | """ Gets a twist metric scramble for a Square-1. Defaults to csTimer's default length of 20.""" 18 | return _UTIL_SCRAMBLER.call("util_scramble.getSquareOneTwistMetricScramble", n) -------------------------------------------------------------------------------- /pyTwistyScrambler/scrambler666.py: -------------------------------------------------------------------------------- 1 | from . import _MEGA_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_WCA_scramble(n=80): 7 | """ Gets a WCA scramble of length `n` for a 6x6x6 cube. Defaults to csTimer's default length of 80. """ 8 | return _MEGA_SCRAMBLER.call("megaScrambler.get666WCAScramble", n) 9 | 10 | @trim 11 | def get_SiGN_scramble(n=80): 12 | """ Gets a SiGN-notation scramble of length `n` for a 6x6x6 cube. Defaults to csTimer's default length of 80. """ 13 | return _MEGA_SCRAMBLER.call("megaScrambler.get666SiGNScramble", n) 14 | 15 | @trim 16 | def get_edges_scramble(n=8): 17 | """ Gets an edges scramble of length `n` for a 6x6x6 cube. Defaults to csTimer's default length of 8. """ 18 | return _MEGA_SCRAMBLER.call("megaScrambler.get666edgesScramble", n) -------------------------------------------------------------------------------- /pyTwistyScrambler/scrambler777.py: -------------------------------------------------------------------------------- 1 | from . import _MEGA_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_WCA_scramble(n=100): 7 | """ Gets a WCA scramble of length `n` for a 7x7x7 cube. Defaults to csTimer's default length of 100. """ 8 | return _MEGA_SCRAMBLER.call("megaScrambler.get777WCAScramble", n) 9 | 10 | @trim 11 | def get_SiGN_scramble(n=100): 12 | """ Gets a SiGN-notation scramble of length `n` for a 7x7x7 cube. Defaults to csTimer's default length of 100. """ 13 | return _MEGA_SCRAMBLER.call("megaScrambler.get777SiGNScramble", n) 14 | 15 | @trim 16 | def get_edges_scramble(n=8): 17 | """ Gets an edges scramble of length `n` for a 7x7x7 cube. Defaults to csTimer's default length of 8. """ 18 | return _MEGA_SCRAMBLER.call("megaScrambler.get777edgesScramble", n) -------------------------------------------------------------------------------- /pyTwistyScrambler/js_resources/1x3x3.js: -------------------------------------------------------------------------------- 1 | var scrambler133 = (function(circle) { 2 | var solv = new mathlib.Solver(4, 1, [[0, doMove, 384]]); 3 | function doMove(idx, m) { 4 | var perm = idx >> 4; 5 | var ori = idx & 15; 6 | var g = []; 7 | mathlib.set8Perm(g, perm, 4); 8 | if (m == 0) { 9 | circle(g, 0, 1); 10 | } else if (m == 1) { 11 | circle(g, 2, 3); 12 | } else if (m == 2) { 13 | circle(g, 0, 3); 14 | } else if (m == 3) { 15 | circle(g, 1, 2); 16 | } 17 | return (mathlib.get8Perm(g, 4) << 4) + (ori ^ (1 << m)); 18 | } 19 | function generateScramble() { 20 | var c = 1 + mathlib.rn(191); 21 | c = c * 2 + ((mathlib.getNParity(c >> 3, 4) ^ (c >> 1) ^ (c >> 2) ^ c) & 1); 22 | return solv.toStr(solv.search([c], 0), "RLFB", [""]); 23 | } 24 | 25 | return { 26 | get133scramble: generateScramble 27 | } 28 | //scramble.reg('133', generateScramble); 29 | }) (mathlib.circle); -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r", encoding="utf-8") as fh: 4 | long_description = fh.read() 5 | 6 | setuptools.setup( 7 | name="pyTwistyScrambler", 8 | version="1.7", 9 | author="euphwes", 10 | author_email="euphwes@gmail.com", 11 | packages=setuptools.find_packages(), 12 | include_package_data=True, 13 | description="A Python utility package for generating scrambles for twisty puzzles", 14 | long_description=long_description, 15 | long_description_content_type="text/markdown", 16 | url="https://github.com/euphwes/pyTwistyScrambler", 17 | project_urls={ 18 | "Bug Tracker": "https://github.com/euphwes/pyTwistyScrambler/issues", 19 | }, 20 | install_requires=[ 21 | "appdirs", 22 | "packaging", 23 | "PyExecJS", 24 | "pyparsing", 25 | "six", 26 | ], 27 | ) 28 | -------------------------------------------------------------------------------- /pyTwistyScrambler/clockScrambler.py: -------------------------------------------------------------------------------- 1 | from . import _UTIL_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_WCA_scramble(): 7 | """ Gets a WCA scramble for a Rubik's Clock. """ 8 | return _UTIL_SCRAMBLER.call("util_scramble.getClockWCAScramble") 9 | 10 | @trim 11 | def get_Jaap_scramble(): 12 | """ Gets a Jaap-notation scramble for a Rubik's Clock. """ 13 | return _UTIL_SCRAMBLER.call("util_scramble.getClockJaapScramble") 14 | 15 | @trim 16 | def get_concise_scramble(): 17 | """ Gets a concise-notation scramble for a Rubik's Clock. """ 18 | return _UTIL_SCRAMBLER.call("util_scramble.getClockConciseScramble") 19 | 20 | @trim 21 | def get_efficient_pin_order_scramble(): 22 | """ Gets an efficient pin order scramble for a Rubik's Clock. """ 23 | return _UTIL_SCRAMBLER.call("util_scramble.getClockEfficientPinOrderScramble") -------------------------------------------------------------------------------- /pyTwistyScrambler/megaminxScrambler.py: -------------------------------------------------------------------------------- 1 | from . import _UTIL_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_WCA_scramble(n=70): 7 | """ Gets a WCA scramble of length `n` for a Megaminx. Defaults to csTimer's default length of 70. """ 8 | return _UTIL_SCRAMBLER.call("util_scramble.getMegaminxWCAScramble", n).replace('\n','').replace(' ',' ').replace(' ',' ') 9 | 10 | @trim 11 | def get_Carrot_scramble(n=70): 12 | """ Gets a Carrot-notation scramble of length `n` for a Megaminx. Defaults to csTimer's default length of 70. """ 13 | return _UTIL_SCRAMBLER.call("util_scramble.getMegaminxCarrotScramble", n).replace('\n','').replace(' ',' ').replace(' ',' ') 14 | 15 | @trim 16 | def get_old_style_scramble(n=70): 17 | """ Gets an old-style scramble of length `n` for a Megaminx. Defaults to csTimer's default length of 70. """ 18 | return _UTIL_SCRAMBLER.call("util_scramble.getMegaminxOldStyleScramble", n) -------------------------------------------------------------------------------- /pyTwistyScrambler/bigCubesScrambler.py: -------------------------------------------------------------------------------- 1 | from . import _MEGA_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_8x8x8_scramble(n=120): 7 | """ Gets a random scramble (SiGN notation) of length `n` for an 8x8x8 cube. """ 8 | return _MEGA_SCRAMBLER.call("megaScrambler.get888scramble", n) 9 | 10 | @trim 11 | def get_9x9x9_scramble(n=120): 12 | """ Gets a random scramble (SiGN notation) of length `n` for a 9x9x9 cube. """ 13 | return _MEGA_SCRAMBLER.call("megaScrambler.get999scramble", n) 14 | 15 | @trim 16 | def get_10x10x10_scramble(n=120): 17 | """ Gets a random scramble (SiGN notation) of length `n` for a 10x10x10 cube. """ 18 | return _MEGA_SCRAMBLER.call("megaScrambler.get101010scramble", n) 19 | 20 | @trim 21 | def get_11x11x11_scramble(n=120): 22 | """ Gets a random scramble (SiGN notation) of length `n` for an 11x11x11 cube. """ 23 | return _MEGA_SCRAMBLER.call("megaScrambler.get111111scramble", n) -------------------------------------------------------------------------------- /pyTwistyScrambler/scrambler555.py: -------------------------------------------------------------------------------- 1 | from . import _MEGA_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_WCA_scramble(n=60): 7 | """ Gets a WCA scramble of length `n` for a 5x5x5 cube. Defaults to csTimer's default length of 60. """ 8 | return _MEGA_SCRAMBLER.call("megaScrambler.get555WCAScramble", n) 9 | 10 | @trim 11 | def get_5BLD_scramble(n=60): 12 | """ Gets a BLD scramble of length N for a 5x5x5 cube. Alias of get_WCA_scramble. """ 13 | return get_WCA_scramble(n) 14 | 15 | @trim 16 | def get_SiGN_scramble(n=60): 17 | """ Gets a SiGN-notation scramble of length `n` for a 5x5x5 cube. Defaults to csTimer's default length of 60. """ 18 | return _MEGA_SCRAMBLER.call("megaScrambler.get555SiGNScramble", n) 19 | 20 | @trim 21 | def get_edges_scramble(n=8): 22 | """ Gets an edges scramble of length `n` for a 5x5x5 cube. Defaults to csTimer's default length of 8. """ 23 | return _MEGA_SCRAMBLER.call("megaScrambler.get555edgesScramble", n) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 The Python Packaging Authority 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /pyTwistyScrambler/scrambler444.py: -------------------------------------------------------------------------------- 1 | from . import _444_SCRAMBLER, _MEGA_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_random_state_scramble(n=40): 7 | """ Gets a WCA scramble of length N for a 4x4x4 cube. Defaults to csTimer's default length of 40. """ 8 | return _MEGA_SCRAMBLER.call("megaScrambler.get444WCAScramble", n) 9 | 10 | @trim 11 | def get_4BLD_scramble(n=40): 12 | """ Gets a BLD scramble of length N for a 4x4x4 cube. Alias of get_WCA_scramble. """ 13 | return get_random_state_scramble(n) 14 | 15 | @trim 16 | def get_SiGN_scramble(n=40): 17 | """ Gets a SiGN-notation scramble of length N for a 4x4x4 cube. Defaults to csTimer's default length of 40. """ 18 | return _MEGA_SCRAMBLER.call("megaScrambler.get444SiGNScramble", n) 19 | 20 | @trim 21 | def get_WCA_scramble(): 22 | """ Gets a random state scramble of a 4x4x4 cube. """ 23 | return _444_SCRAMBLER.call("scramble_444.getRandomScramble") 24 | 25 | @trim 26 | def get_edges_scramble(n=8): 27 | """ Gets an edges scramble of length `n` for a 4x4x4 cube. Defaults to csTimer's default length of 8. """ 28 | return _MEGA_SCRAMBLER.call("megaScrambler.get444edgesScramble", n) 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # dotenv 80 | .env 81 | 82 | # virtualenv 83 | .venv 84 | venv/ 85 | ENV/ 86 | 87 | # Spyder project settings 88 | .spyderproject 89 | 90 | # Rope project settings 91 | .ropeproject -------------------------------------------------------------------------------- /pyTwistyScrambler/cuboidsScrambler.py: -------------------------------------------------------------------------------- 1 | from . import _MEGA_SCRAMBLER, _223_SCRAMBLER, _133_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_1x1x2_scramble(): 7 | """ Gets a random scramble for a 1x1x2 cuboid (lul). """ 8 | return _MEGA_SCRAMBLER.call("megaScrambler.get112scramble") 9 | 10 | @trim 11 | def get_1x3x3_scramble(): 12 | """ Gets a random scramble for a 1x3x3 cuboid. """ 13 | return _133_SCRAMBLER.call("scrambler133.get133scramble") 14 | 15 | @trim 16 | def get_floppy_cube_scramble(): 17 | """ Gets a random scramble for a 1x3x3 cuboid. Alias of 1x3x3. """ 18 | return get_1x3x3_scramble() 19 | 20 | @trim 21 | def get_super_floppy_cube_scramble(): 22 | """ Gets a random scramble for a 1x3x3 super floppy cuboid. """ 23 | return _MEGA_SCRAMBLER.call("megaScrambler.getSuperFloppyScramble") 24 | 25 | @trim 26 | def get_2x2x3_scramble(): 27 | """ Gets a random scramble for a 2x2x3 cuboid. """ 28 | return _223_SCRAMBLER.call("scrambler223.get223scramble") 29 | 30 | @trim 31 | def get_3x3x2_scramble(): 32 | """ Gets a random scramble for a 3x3x2 cuboid. """ 33 | return _MEGA_SCRAMBLER.call("megaScrambler.get332scramble") 34 | 35 | @trim 36 | def get_3x3x4_scramble(): 37 | """ Gets a random scramble for a 3x3x4 cuboid. """ 38 | return _MEGA_SCRAMBLER.call("megaScrambler.get334scramble") 39 | 40 | @trim 41 | def get_3x3x5_scramble(n=25): 42 | """ Gets a random scramble for a 3x3x5 cuboid, where `n` is the length of the non-3x3x3 portion of the scramble. """ 43 | return _MEGA_SCRAMBLER.call("megaScrambler.get335scramble", n) 44 | 45 | @trim 46 | def get_3x3x6_scramble(): 47 | """ Gets a random scramble for a 3x3x6 cuboid. """ 48 | return _MEGA_SCRAMBLER.call("megaScrambler.get336scramble") 49 | 50 | @trim 51 | def get_3x3x7_scramble(n=40): 52 | """ Gets a random scramble for a 3x3x7 cuboid, where `n` is the length of the non-3x3x3 portion of the scramble. """ 53 | return _MEGA_SCRAMBLER.call("megaScrambler.get337scramble", n) -------------------------------------------------------------------------------- /pyTwistyScrambler/js_resources/2x2x2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var scramble_222 = (function(circle, rn) { 4 | var solv = new mathlib.Solver(3, 3, [[0, doPermMove, 5040], [0, doOriMove, 729]]); 5 | function doPermMove(idx, m) { 6 | var g = []; 7 | mathlib.set8Perm(g, idx, 7); 8 | if (m == 0) { 9 | circle(g, 0, 2, 3, 1); 10 | } else if (m == 1) { 11 | circle(g, 0, 1, 5, 4); 12 | } else if (m == 2) { 13 | circle(g, 0, 4, 6, 2); 14 | } 15 | return mathlib.get8Perm(g, 7); 16 | } 17 | function doOriMove(a, c) { 18 | var b, d, e, h = 0, 19 | g = a, 20 | f = []; 21 | for (b = 1; 6 >= b; b++) e = ~~ (g / 3), 22 | d = g - 3 * e, 23 | g = e, 24 | f[b] = d, 25 | h -= d, 26 | 0 > h && (h += 3); 27 | f[0] = h; 28 | 0 == c ? circle(f, 0, 2, 3, 1) : 1 == c ? (circle(f, 0, 1, 5, 4), f[0] += 2, f[1]++, f[5] += 2, f[4]++) : 2 == c && (circle(f, 0, 4, 6, 2), f[2] += 2, f[0]++, f[4] += 2, f[6]++); 29 | g = 0; 30 | for (b = 6; 1 <= b; b--) g = 3 * g + f[b] % 3; 31 | return g 32 | } 33 | function getScramble(type) { 34 | var a, b, c, g, lim; 35 | a = type == '222o' ? 0 : 9; 36 | g = [[0, 0, 0, 0, 4, 5, 6], 37 | [0, 0, 0, 0, 4, 6, 5], 38 | [0, 0, 0, 0, 5, 4, 6], 39 | [0, 0, 0, 0, 5, 6, 4], 40 | [0, 0, 0, 0, 6, 4, 5], 41 | [0, 0, 0, 0, 6, 5, 4]]; 42 | do { 43 | lim = 2; 44 | if (type == '222o' || type == '222so') { 45 | c = rn(5040); 46 | b = rn(729); 47 | lim = 3; 48 | } else if (type == '222eg') { 49 | c = rn(24); 50 | b = rn(27); 51 | g = g[rn(6)]; 52 | mathlib.set8Perm(g, c, 4); 53 | c = mathlib.get8Perm(g, 7); 54 | } else if (type == '222eg0') { 55 | c = rn(24); 56 | b = rn(27); 57 | g = g[0]; 58 | mathlib.set8Perm(g, c, 4); 59 | c = mathlib.get8Perm(g, 7); 60 | } else if (type == '222eg1') { 61 | c = rn(24); 62 | b = rn(27); 63 | g = g[rn(4) + 2]; 64 | mathlib.set8Perm(g, c, 4); 65 | c = mathlib.get8Perm(g, 7); 66 | } else if (type == '222eg2') { 67 | c = rn(24); 68 | b = rn(27); 69 | g = g[1]; 70 | mathlib.set8Perm(g, c, 4); 71 | c = mathlib.get8Perm(g, 7); 72 | } 73 | } while (c == 0 && b == 0 || solv.search([c, b], lim, lim) != null); 74 | return solv.toStr(solv.search([c, b], a).reverse(), "URF", "'2 "); 75 | } 76 | 77 | function getRandomScramble(){ 78 | return getScramble('222so'); 79 | } 80 | 81 | function getOptimalScramble(){ 82 | return getScramble('222o'); 83 | } 84 | 85 | return { 86 | getRandomScramble: getRandomScramble, 87 | getOptimalScramble: getOptimalScramble, 88 | }; 89 | //scramble.reg(['222o', '222so', '222eg', '222eg0', '222eg1', '222eg2'], getScramble); 90 | }) (mathlib.circle, mathlib.rn); -------------------------------------------------------------------------------- /pyTwistyScrambler/js_resources/2x2x3.js: -------------------------------------------------------------------------------- 1 | var scrambler223 = (function(circle, get8Perm) { 2 | var cmv = []; 3 | var cprun = []; 4 | 5 | function initCornerMoveTable() { 6 | var g = [], 7 | temp; 8 | for (var i = 0; i < 40320; i++) { 9 | cmv[i] = []; 10 | } 11 | for (var i = 0; i < 40320; i++) { 12 | mathlib.set8Perm(g, i); 13 | circle(g, 0, 1, 2, 3); 14 | temp = cmv[0][i] = get8Perm(g); //U 15 | circle(g, 4, 5, 6, 7); 16 | temp = cmv[1][temp] = get8Perm(g); //D 17 | circle(g, 2, 5)(g, 3, 6); 18 | temp = cmv[2][temp] = get8Perm(g); //R 19 | circle(g, 0, 5)(g, 3, 4); 20 | cmv[3][temp] = get8Perm(g); //F 21 | } 22 | } 23 | 24 | function doEdgeMove(idx, m) { 25 | if (m < 2) { 26 | return idx; 27 | } 28 | var g = []; 29 | mathlib.set8Perm(g, idx, 3); 30 | if (m == 2) { 31 | circle(g, 0, 1); 32 | } else if (m == 3) { 33 | circle(g, 0, 2); 34 | } 35 | return get8Perm(g, 3); 36 | } 37 | // function doMv(idx, m) { 38 | // return cmv[~~(idx / 6)][m] * 6 + doEdgeMove(idx % 6, m); 39 | // } 40 | function init() { 41 | initCornerMoveTable(); 42 | mathlib.createPrun(cprun, 0, 40320, 12, cmv, 4, 3); 43 | // mathlib.createPrun([], 0, 40320 * 6, 15, doMv, 4, 3); 44 | } 45 | 46 | function search(corner, edge, maxl, lm, sol) { 47 | if (maxl == 0) { 48 | return corner + edge == 0; 49 | } 50 | if (mathlib.getPruning(cprun, corner) > maxl) return false; 51 | var h, g, f, i; 52 | for (i = 0; i < 4; i++) { 53 | if (i != lm) { 54 | h = corner; 55 | g = edge; 56 | for (f = 0; f < (i < 2 ? 3 : 1); f++) { 57 | h = cmv[i][h]; 58 | g = doEdgeMove(g, i); 59 | if (search(h, g, maxl - 1, i, sol)) { 60 | sol.push(["U", "D", "R2", "F2"][i] + (i < 2 ? " 2'".charAt(f) : "")); 61 | return true; 62 | } 63 | } 64 | } 65 | } 66 | } 67 | 68 | function generateScramble() { 69 | init(); 70 | var d = []; 71 | var a = 0, 72 | b, c; 73 | do { 74 | c = mathlib.rn(40320); 75 | b = mathlib.rn(6); 76 | } while (b + c == 0) 77 | for (a = 0; a < 99; a++) { 78 | if (search(c, b, a, -1, d)) { 79 | break; 80 | } 81 | } 82 | return d.reverse().join(" ") 83 | } 84 | 85 | return { 86 | get223scramble: generateScramble, 87 | } 88 | //scramble.reg('223', generateScramble); 89 | })(mathlib.circle, mathlib.get8Perm); -------------------------------------------------------------------------------- /pyTwistyScrambler/__init__.py: -------------------------------------------------------------------------------- 1 | import execjs 2 | from os import path 3 | 4 | #------------------------------------------------------------------------------ 5 | 6 | def trim(func): 7 | def trimmed_func(*args, **kwargs): 8 | return func(*args, **kwargs).strip() 9 | return trimmed_func 10 | 11 | #------------------------------------------------------------------------------ 12 | 13 | curr_dir = path.dirname(path.realpath(__file__)) 14 | 15 | with open(path.join(curr_dir, 'js_resources/mathlib.js')) as f: 16 | MATHLIB_SRC = f.read() 17 | 18 | with open(path.join(curr_dir, 'js_resources/cross.js')) as f: 19 | CROSS_SRC = f.read() 20 | 21 | with open(path.join(curr_dir, 'js_resources/scramble.js')) as f: 22 | SCRAMBLE_SRC = f.read() 23 | 24 | with open(path.join(curr_dir, 'js_resources/megascramble.js')) as f: 25 | MEGA_SCRAMBLE_SRC = f.read() 26 | 27 | with open(path.join(curr_dir, 'js_resources/utilscramble.js')) as f: 28 | UTIL_SCRAMBLE_SRC = f.read() 29 | 30 | with open(path.join(curr_dir, 'js_resources/scramble_333_edit.js')) as f: 31 | SCRAMBLE_333_SRC = f.read() 32 | 33 | with open(path.join(curr_dir, 'js_resources/scramble_444.js')) as f: 34 | SCRAMBLE_444_SRC = f.read() 35 | 36 | with open(path.join(curr_dir, 'js_resources/scramble_sq1.js')) as f: 37 | SCRAMBLE_SQ1_SRC = f.read() 38 | 39 | with open(path.join(curr_dir, 'js_resources/2x2x2.js')) as f: 40 | SCRAMBLE_222_SRC = f.read() 41 | 42 | with open(path.join(curr_dir, 'js_resources/2x2x3.js')) as f: 43 | SCRAMBLE_223_SRC = f.read() 44 | 45 | with open(path.join(curr_dir, 'js_resources/1x3x3.js')) as f: 46 | SCRAMBLE_133_SRC = f.read() 47 | 48 | with open(path.join(curr_dir, 'js_resources/pyraminx.js')) as f: 49 | PYRAMINX_SRC = f.read() 50 | 51 | with open(path.join(curr_dir, 'js_resources/skewb.js')) as f: 52 | SKEWB_SRC = f.read() 53 | 54 | with open(path.join(curr_dir, 'js_resources/fto.js')) as f: 55 | FTO_SRC = f.read() 56 | 57 | #------------------------------------------------------------------------------ 58 | 59 | _UTIL_SCRAMBLER = execjs.compile(MATHLIB_SRC + SCRAMBLE_SRC + UTIL_SCRAMBLE_SRC) 60 | _PYRA_SCRAMBLER = execjs.compile(MATHLIB_SRC + PYRAMINX_SRC) 61 | _SQ1_SCRAMBLER = execjs.compile(MATHLIB_SRC + SCRAMBLE_SRC + SCRAMBLE_SQ1_SRC) 62 | _133_SCRAMBLER = execjs.compile(MATHLIB_SRC + SCRAMBLE_133_SRC) 63 | _222_SCRAMBLER = execjs.compile(MATHLIB_SRC + SCRAMBLE_222_SRC) 64 | _223_SCRAMBLER = execjs.compile(MATHLIB_SRC + SCRAMBLE_223_SRC) 65 | _333_SCRAMBLER = execjs.compile(MATHLIB_SRC + SCRAMBLE_SRC + CROSS_SRC + SCRAMBLE_333_SRC) 66 | _444_SCRAMBLER = execjs.compile(MATHLIB_SRC + SCRAMBLE_SRC + SCRAMBLE_333_SRC + SCRAMBLE_444_SRC) 67 | _MEGA_SCRAMBLER = execjs.compile(MATHLIB_SRC + SCRAMBLE_SRC + SCRAMBLE_333_SRC + MEGA_SCRAMBLE_SRC) 68 | _SKEWB_SCRAMBLER = execjs.compile(MATHLIB_SRC + SCRAMBLE_SRC + SKEWB_SRC) 69 | _FTO_SCRAMBLER = execjs.compile(FTO_SRC) 70 | -------------------------------------------------------------------------------- /pyTwistyScrambler/ftoScrambler.py: -------------------------------------------------------------------------------- 1 | from . import _FTO_SCRAMBLER, trim 2 | 3 | from random import choice 4 | 5 | #------------------------------------------------------------------------------ 6 | 7 | @trim 8 | def get_random_state_scramble(): 9 | """ Gets a random-state scramble for FTO (face-turning octahedron). """ 10 | return _FTO_SCRAMBLER.call("generate_random_state_scramble") 11 | 12 | 13 | def get_multiple_random_state_scrambles(n): 14 | """ Gets `n` random-state scrambles for FTO (face-turning octahedron). """ 15 | scrambles = _FTO_SCRAMBLER.call("generate_multiple_random_state_scrambles", n) 16 | return [s.strip() for s in scrambles] 17 | 18 | 19 | @trim 20 | def get_random_moves_scramble(scramble_length = 30): 21 | """ Returns a random-moves scramble of length `scramble_length` for FTO. """ 22 | 23 | def __except(exceptions): 24 | """ Returns a list range 0-7 except the specified exceptions. """ 25 | if not exceptions: 26 | return range(8) 27 | values = list(range(8)) 28 | for n in exceptions: 29 | values.remove(n) 30 | return values 31 | 32 | moves = ['F', 'U', 'R', 'L', 'D', 'B', 'BL', 'BR'] 33 | opposites = { 34 | 'U': 'D', 35 | 'D': 'U', 36 | 'F': 'B', 37 | 'B': 'F', 38 | 'L': 'BR', 39 | 'BR': 'L', 40 | 'BL': 'R', 41 | 'R': 'BL' 42 | } 43 | 44 | scramble = list() 45 | move_ix = -1 46 | 47 | for _ in range(scramble_length): 48 | if move_ix == -1: 49 | # If this is the first move, there are no restrictions on which face we can choose. 50 | exceptions = None 51 | else: 52 | # Otherwise, we'll always omit the face we just chose, so we don't choose it again. 53 | exceptions = [move_ix] 54 | 55 | if len(scramble) > 1: 56 | # If the last two faces in the scramble were opposites (ex, U and D), the next move 57 | # needs to exclude both of those faces so we don't end up with cancellations. 58 | # ex: U D U' is no good 59 | # ex: R' BL' R' BL is no good 60 | # By omitting the two opposite faces from the choices for the next move, the face 61 | # chosen will intersect those faces, preventing a cancellation. 62 | face_one_ago = scramble[-1].replace("'", "") 63 | face_two_ago = scramble[-2].replace("'", "") 64 | if opposites[face_one_ago] == face_two_ago: 65 | exceptions.append(moves.index(face_two_ago)) 66 | 67 | # Randomly choose a move from the faces available, ensuring we don't have a cancellation 68 | move_ix = choice(__except(exceptions)) 69 | 70 | # Randomly decide if that turn is clockwise or counterclockwise and apply prime if needed. 71 | scramble.append(moves[move_ix] + choice(["", "'"])) 72 | 73 | return ' '.join(scramble) 74 | -------------------------------------------------------------------------------- /pyTwistyScrambler/js_resources/pyraminx.js: -------------------------------------------------------------------------------- 1 | var pyra_scrambler = (function(circle) { 2 | var solv = new mathlib.Solver(4, 2, [[0, l, 360], [0, i, 2592]]); 3 | 4 | function l(a, c) { 5 | for (var e = [], j = 5517840, f = 0, b = 0; 5 > b; b++) { 6 | var h = k[5 - b], 7 | d = ~~(a / h), 8 | f = f ^ d; 9 | a = a - d * h; 10 | d = d << 2; 11 | e[b] = j >> d & 15; 12 | h = (1 << d) - 1; 13 | j = (j & h) + (j >> 4 & ~h) 14 | } 15 | 0 == (f & 1) ? e[5] = j : (e[5] = e[4], e[4] = j); 16 | 0 == c && circle(e, 0, 1, 3); 17 | 1 == c && circle(e, 1, 2, 5); 18 | 2 == c && circle(e, 0, 4, 2); 19 | 3 == c && circle(e, 3, 5, 4); 20 | a = 0; 21 | j = 5517840; 22 | for (b = 0; 4 > b; b++) d = e[b] << 2, 23 | a *= 6 - b, 24 | a += j >> d & 15, 25 | j -= 1118480 << d; 26 | return a 27 | } 28 | 29 | function i(a, c) { 30 | var e, d, f; 31 | d = 0; 32 | var b = [], 33 | h = a; 34 | for (e = 0; 4 >= e; e++) b[e] = h & 1, 35 | h >>= 1, 36 | d ^= b[e]; 37 | b[5] = d; 38 | for (e = 6; 9 >= e; e++) f = ~~(h / 3), 39 | d = h - 3 * f, 40 | h = f, 41 | b[e] = d; 42 | b[c + 6] = (b[c + 6] + 1) % 3; 43 | 0 == c && (circle(b, 0, 1, 3), b[1] ^= 1, b[3] ^= 1); 44 | 1 == c && (circle(b, 1, 2, 5), b[2] ^= 1, b[5] ^= 1); 45 | 2 == c && (circle(b, 0, 4, 2), b[0] ^= 1, b[2] ^= 1); 46 | 3 == c && (circle(b, 3, 5, 4), b[3] ^= 1, b[4] ^= 1); 47 | h = 0; 48 | for (e = 9; 6 <= e; e--) h = 3 * h + b[e]; 49 | for (e = 4; 0 <= e; e--) h = 2 * h + b[e]; 50 | return h 51 | } 52 | var k = [1, 1, 1, 3, 12, 60, 360]; 53 | 54 | function getScramble(type) { 55 | var l = type == 'pyrso' ? 8 : 0; 56 | 57 | var len = 0; 58 | do { 59 | var st = mathlib.rn(360 * 2592 - 1) + 1; 60 | var i = st % 360; 61 | var g = ~~(st / 360); 62 | 63 | len = solv.search([i, g], 0).length; 64 | k = solv.toStr(solv.search([i, g], l), "ULRB", ["", "'"]) + ' '; 65 | for (g = 0; g < 4; g++) { 66 | i = mathlib.rn(3); 67 | if (i < 2) { 68 | k += "lrbu".charAt(g) + [" ", "' "][i] + " "; 69 | len++; 70 | } 71 | } 72 | } while (len < 6); 73 | return k 74 | } 75 | 76 | function getPyraWCAScramble(){ 77 | return getScramble('pyrso'); 78 | } 79 | 80 | function getPyraOptimalScramble(){ 81 | return getScramble('pyro'); 82 | } 83 | 84 | return { 85 | getPyraWCAScramble: getPyraWCAScramble, 86 | getPyraOptimalScramble: getPyraOptimalScramble 87 | } 88 | 89 | //scramble.reg(['pyro', 'pyrso'], getScramble); 90 | 91 | })(mathlib.circle); -------------------------------------------------------------------------------- /pyTwistyScrambler/rexScrambler.py: -------------------------------------------------------------------------------- 1 | from . import _FTO_SCRAMBLER, trim 2 | 3 | from random import choice 4 | 5 | #------------------------------------------------------------------------------ 6 | 7 | _fto_rex_notation_map = { 8 | "U": "F", 9 | "R": "R", 10 | "F": "f", 11 | "L": "L", 12 | "D": "b", 13 | "BR": "r", 14 | "B": "B", 15 | "BL": "l", 16 | } 17 | _fto_rex_notation_map.update({f"{k}'": f"{v}'" for k, v in _fto_rex_notation_map.items()}) 18 | 19 | def _translate(fto_scramble): 20 | return ' '.join(_fto_rex_notation_map[move] for move in fto_scramble.split()) 21 | 22 | @trim 23 | def get_random_state_scramble(): 24 | """ Gets a random-state scramble for Rex Cube. """ 25 | return _translate(_FTO_SCRAMBLER.call("generate_random_state_scramble")) 26 | 27 | 28 | def get_multiple_random_state_scrambles(n): 29 | """ Gets `n` random-state scrambles for Rex Cube. """ 30 | scrambles = _FTO_SCRAMBLER.call("generate_multiple_random_state_scrambles", n) 31 | return [_translate(s.strip()) for s in scrambles] 32 | 33 | 34 | @trim 35 | def get_random_moves_scramble(scramble_length = 30): 36 | """ Returns a random-moves scramble of length `scramble_length` for FTO. """ 37 | 38 | def __except(exceptions): 39 | """ Returns a list range 0-7 except the specified exceptions. """ 40 | if not exceptions: 41 | return range(8) 42 | values = list(range(8)) 43 | for n in exceptions: 44 | values.remove(n) 45 | return values 46 | 47 | moves = ['F', 'U', 'R', 'L', 'D', 'B', 'BL', 'BR'] 48 | opposites = { 49 | 'U': 'D', 50 | 'D': 'U', 51 | 'F': 'B', 52 | 'B': 'F', 53 | 'L': 'BR', 54 | 'BR': 'L', 55 | 'BL': 'R', 56 | 'R': 'BL' 57 | } 58 | 59 | scramble = list() 60 | move_ix = -1 61 | 62 | for _ in range(scramble_length): 63 | if move_ix == -1: 64 | # If this is the first move, there are no restrictions on which face we can choose. 65 | exceptions = None 66 | else: 67 | # Otherwise, we'll always omit the face we just chose, so we don't choose it again. 68 | exceptions = [move_ix] 69 | 70 | if len(scramble) > 1: 71 | # If the last two faces in the scramble were opposites (ex, U and D), the next move 72 | # needs to exclude both of those faces so we don't end up with cancellations. 73 | # ex: U D U' is no good 74 | # ex: R' BL' R' BL is no good 75 | # By omitting the two opposite faces from the choices for the next move, the face 76 | # chosen will intersect those faces, preventing a cancellation. 77 | face_one_ago = scramble[-1].replace("'", "") 78 | face_two_ago = scramble[-2].replace("'", "") 79 | if opposites[face_one_ago] == face_two_ago: 80 | exceptions.append(moves.index(face_two_ago)) 81 | 82 | # Randomly choose a move from the faces available, ensuring we don't have a cancellation 83 | move_ix = choice(__except(exceptions)) 84 | 85 | # Randomly decide if that turn is clockwise or counterclockwise and apply prime if needed. 86 | scramble.append(moves[move_ix] + choice(["", "'"])) 87 | 88 | return _translate(' '.join(scramble)) 89 | -------------------------------------------------------------------------------- /pyTwistyScrambler/js_resources/skewb.js: -------------------------------------------------------------------------------- 1 | var skewb_scrambler = (function(circle) { 2 | function l(a, c) { 3 | var ax = a % 12; 4 | a = ~~(a / 12); 5 | for (var e = [], j = 5517840, f = 0, b = 0; 5 > b; b++) { 6 | var h = k[5 - b], 7 | d = ~~ (a / h), 8 | f = f ^ d; 9 | a = a - d * h; 10 | d = d << 2; 11 | e[b] = j >> d & 15; 12 | h = (1 << d) - 1; 13 | j = (j & h) + (j >> 4 & ~h) 14 | } 15 | 0 == (f & 1) ? e[5] = j: (e[5] = e[4], e[4] = j); 16 | 0 == c && circle(e, 0, 3, 1); 17 | 2 == c && circle(e, 1, 5, 2); 18 | 1 == c && circle(e, 0, 2, 4); 19 | 3 == c && circle(e, 3, 4, 5); 20 | a = 0; 21 | j = 5517840; 22 | for (b = 0; 4 > b; b++) d = e[b] << 2, 23 | a *= 6 - b, 24 | a += j >> d & 15, 25 | j -= 1118480 << d; 26 | return a * 12 + cornerpermmv[ax][c]; 27 | } 28 | function i(idx, move) { 29 | var fixedtwst = []; 30 | var twst = []; 31 | for (var i = 0; i < 4; i++) { 32 | fixedtwst[i] = idx % 3; 33 | idx = ~~(idx / 3); 34 | } 35 | for (var i = 0; i < 3; i++) { 36 | twst[i] = idx % 3; 37 | idx = ~~(idx / 3); 38 | } 39 | twst[3] = (6 - twst[0] - twst[1] - twst[2]) % 3; 40 | fixedtwst[move] = (fixedtwst[move] + 1) % 3; 41 | var t; 42 | switch (move) { 43 | case 0: 44 | t = twst[0]; 45 | twst[0] = twst[2] + 2; 46 | twst[2] = twst[1] + 2; 47 | twst[1] = t + 2; 48 | break; 49 | case 1: 50 | t = twst[0]; 51 | twst[0] = twst[1] + 2; 52 | twst[1] = twst[3] + 2; 53 | twst[3] = t + 2; 54 | break; 55 | case 2: 56 | t = twst[0]; 57 | twst[0] = twst[3] + 2; 58 | twst[3] = twst[2] + 2; 59 | twst[2] = t + 2; 60 | break; 61 | case 3: 62 | t = twst[1]; 63 | twst[1] = twst[2] + 2; 64 | twst[2] = twst[3] + 2; 65 | twst[3] = t + 2; 66 | break; 67 | default: 68 | } 69 | for (var i = 2; i >= 0; i--) { 70 | idx = idx * 3 + twst[i] % 3; 71 | } 72 | for (var i = 3; i >= 0; i--) { 73 | idx = idx * 3 + fixedtwst[i]; 74 | } 75 | return idx; 76 | } 77 | var k = [1, 1, 1, 3, 12, 60, 360]; 78 | var cornerpermmv = [[ 6, 5, 10, 1 ], [ 9, 7, 4, 2 ], [ 3, 11, 8, 0 ], [ 10, 1, 6, 5 ], 79 | [ 0, 8, 11, 3 ], [ 7, 9, 2, 4 ], [ 4, 2, 9, 7 ], [ 11, 3, 0, 8 ], 80 | [ 1, 10, 5, 6 ], [ 8, 0, 3, 11 ], [ 2, 4, 7, 9 ], [ 5, 6, 1, 10 ] ]; 81 | 82 | var solv = new mathlib.Solver(4, 2, [[0, l, 4320], [0, i, 2187]]); 83 | 84 | function getSolution(sol) { 85 | var ret = []; 86 | var move2str = ["L", "R", "B", "U"];//RLDB (in jaap's notation) rotated by z2 87 | for (var i = 0; i < sol.length; i++) { 88 | var axis = sol[i][0]; 89 | var pow = 1 - sol[i][1]; 90 | if (axis == 2) {//step two. 91 | for (var p=0; p<=pow; p++) { 92 | var temp = move2str[0]; 93 | move2str[0] = move2str[1]; 94 | move2str[1] = move2str[3]; 95 | move2str[3] = temp; 96 | } 97 | } 98 | ret.push(move2str[axis] + ((pow == 1) ? "'" : "")); 99 | } 100 | return ret.join(" "); 101 | } 102 | var ori = [0, 1, 2, 0, 2, 1, 1, 2, 0, 2, 1, 0]; 103 | 104 | function getScramble(type) { 105 | var perm, twst, lim = 5, 106 | l = type == 'skbso' ? 8 : 0; 107 | do { 108 | perm = mathlib.rn(4320); 109 | twst = mathlib.rn(2187); 110 | } while (perm == 0 && twst == 0 || ori[perm % 12] != (twst + ~~(twst / 3) + ~~(twst / 9) + ~~(twst / 27)) % 3 || solv.search([perm, twst], lim, lim) != null); 111 | var sol = solv.search([perm, twst], l).reverse(); 112 | return getSolution(sol); 113 | } 114 | 115 | function getSkewbWCAScramble(){ 116 | return getScramble('skbso'); 117 | } 118 | 119 | return { 120 | getSkewbWCAScramble: getSkewbWCAScramble 121 | } 122 | 123 | //scramble.reg(['skbo', 'skbso'], getScramble); 124 | })(mathlib.circle); -------------------------------------------------------------------------------- /pyTwistyScrambler/scrambler333.py: -------------------------------------------------------------------------------- 1 | from . import _333_SCRAMBLER, _MEGA_SCRAMBLER, trim 2 | 3 | #------------------------------------------------------------------------------ 4 | 5 | @trim 6 | def get_WCA_scramble(): 7 | """ Gets a WCA scramble of a 3x3x3 cube. """ 8 | return _333_SCRAMBLER.call("scramble_333.getRandomScramble") 9 | 10 | @trim 11 | def get_3BLD_scramble(): 12 | """ Gets a BLD scramble of a 3x3x3 cube. """ 13 | return _333_SCRAMBLER.call("scramble_333.get3BLDScramble") 14 | 15 | @trim 16 | def get_random_scramble(): 17 | """ Gets a random scramble of a 3x3x3 cube. """ 18 | return _333_SCRAMBLER.call("scramble_333.getRandomScramble") 19 | 20 | @trim 21 | def get_edges_scramble(): 22 | """ Gets an edges-only scramble of a 3x3x3 cube. """ 23 | return _333_SCRAMBLER.call("scramble_333.getEdgeScramble") 24 | 25 | @trim 26 | def get_corners_scramble(): 27 | """ Gets a corners-only scramble of a 3x3x3 cube. """ 28 | return _333_SCRAMBLER.call("scramble_333.getCornerScramble") 29 | 30 | @trim 31 | def get_LL_scramble(): 32 | """ Gets a last layer scramble of a 3x3x3 cube. """ 33 | return _333_SCRAMBLER.call("scramble_333.getLLScramble") 34 | 35 | @trim 36 | def get_LSLL_scramble(): 37 | """ Gets a last slot last layer scramble of a 3x3x3 cube. """ 38 | return _333_SCRAMBLER.call("scramble_333.getLSLLScramble") 39 | 40 | @trim 41 | def get_ZBLL_scramble(): 42 | """ Gets a Zborowski-Bruchem last layer scramble of a 3x3x3 cube. """ 43 | return _333_SCRAMBLER.call("scramble_333.getZBLLScramble") 44 | 45 | @trim 46 | def get_ZZLL_scramble(): 47 | """ Gets a Zbigniew Zborowski last layer scramble of a 3x3x3 cube. """ 48 | return _333_SCRAMBLER.call("scramble_333.getZZLLScramble") 49 | 50 | @trim 51 | def get_ZBLS_scramble(): 52 | """ Gets a ZBLS scramble of a 3x3x3 cube. """ 53 | return _333_SCRAMBLER.call("scramble_333.getZBLSScramble") 54 | 55 | @trim 56 | def get_F2L_scramble(): 57 | """ Gets an F2L (first two layers) scramble of a 3x3x3 cube. """ 58 | return _333_SCRAMBLER.call("scramble_333.getF2LScramble") 59 | 60 | @trim 61 | def get_LSE_scramble(): 62 | """ Gets an LSE (last six edges) scramble of a 3x3x3 cube. """ 63 | return _333_SCRAMBLER.call("scramble_333.getLSEScramble") 64 | 65 | @trim 66 | def get_EOLine_scramble(): 67 | """ Gets an EO line scramble of a 3x3x3 cube. """ 68 | return _333_SCRAMBLER.call("scramble_333.getEOLineScramble") 69 | 70 | @trim 71 | def get_CMLL_scramble(): 72 | """ Gets a CMLL scramble of a 3x3x3 cube. """ 73 | return _333_SCRAMBLER.call("scramble_333.getCMLLScramble") 74 | 75 | @trim 76 | def get_CLL_scramble(): 77 | """ Gets a CLL scramble of a 3x3x3 cube. """ 78 | return _333_SCRAMBLER.call("scramble_333.getCLLScramble") 79 | 80 | @trim 81 | def get_ELL_scramble(): 82 | """ Gets an ELL scramble of a 3x3x3 cube. """ 83 | return _333_SCRAMBLER.call("scramble_333.getELLScramble") 84 | 85 | @trim 86 | def get_easy_cross_scramble(n): 87 | """ Gets an 'easy cross' scramble, where the cross can be solved in `n` moves.""" 88 | return _333_SCRAMBLER.call("scramble_333.getEasyCrossScramble", n) 89 | 90 | @trim 91 | def get_2genRU_scramble(): 92 | """ Gets a 2-gen scramble with only RU moves for a 3x3x3 cube. """ 93 | return _MEGA_SCRAMBLER.call("megaScrambler.get333_2genRU_scramble") 94 | 95 | @trim 96 | def get_2genLU_scramble(): 97 | """ Gets a 2-gen scramble with only LU moves for a 3x3x3 cube. """ 98 | return _MEGA_SCRAMBLER.call("megaScrambler.get333_2genLU_scramble") 99 | 100 | @trim 101 | def get_2genMU_scramble(): 102 | """ Gets a 2-gen scramble with only MU moves for a 3x3x3 cube. """ 103 | return _MEGA_SCRAMBLER.call("megaScrambler.get333_2genMU_scramble") 104 | 105 | @trim 106 | def get_3genFRU_scramble(): 107 | """ Gets a 3-gen scramble with only FRU moves for a 3x3x3 cube. """ 108 | return _MEGA_SCRAMBLER.call("megaScrambler.get333_3genFRU_scramble") 109 | 110 | @trim 111 | def get_3genRUL_scramble(): 112 | """ Gets a 3-gen scramble with only RUL moves for a 3x3x3 cube. """ 113 | return _MEGA_SCRAMBLER.call("megaScrambler.get333_3genRUL_scramble") 114 | 115 | @trim 116 | def get_3genRrU_scramble(): 117 | """ Gets a 3-gen scramble with only RrU moves for a 3x3x3 cube. """ 118 | return _MEGA_SCRAMBLER.call("megaScrambler.get333_3genRrU_scramble") 119 | 120 | @trim 121 | def get_half_turns_scramble(): 122 | """ Gets a half turns-only scramble for a 3x3x3 cube. """ 123 | return _MEGA_SCRAMBLER.call("megaScrambler.get333_halfTurns_scramble") -------------------------------------------------------------------------------- /pyTwistyScrambler/js_resources/cross.js: -------------------------------------------------------------------------------- 1 | var cross = (function(createMove, edgeMove, createPrun, setNPerm, getNPerm, Cnk, getPruning) { 2 | var permPrun, flipPrun, ecPrun, fullPrun; 3 | var cmv = []; 4 | var pmul = []; 5 | var fmul = []; 6 | 7 | var e1mv = []; 8 | var c1mv = []; 9 | 10 | function pmv(a,c){var b=cmv[c][~~(a/24)];return 24*~~(b/384)+pmul[a%24][(b>>4)%24]} 11 | 12 | function fmv(b,c){var a=cmv[c][b>>4];return~~(a/384)<<4|fmul[b&15][(a>>4)%24]^a&15} 13 | 14 | function i2f(a,c){for(var b=3;0<=b;b--)c[b]=a&1,a>>=1} 15 | 16 | function f2i(c){for(var a=0,b=0;4>b;b++)a<<=1,a|=c[b];return a} 17 | 18 | function fullmv(idx, move) { 19 | var slice = cmv[move][~~(idx / 384)]; 20 | var flip = fmul[idx&15][(slice>>4)%24] ^ slice & 15; 21 | var perm = pmul[(idx>>4)%24][(slice>>4)%24]; 22 | return (~~(slice/384)) * 384 + 16 * perm + flip; 23 | } 24 | 25 | function init() { 26 | for (var i=0; i<24; i++) { 27 | pmul[i] = []; 28 | } 29 | for (var i=0; i<16; i++) { 30 | fmul[i] = []; 31 | } 32 | var pm1 = []; 33 | var pm2 = []; 34 | var pm3 = []; 35 | for (var i=0; i<24; i++) { 36 | for (var j=0; j<24; j++) { 37 | setNPerm(pm1, i, 4); 38 | setNPerm(pm2, j, 4); 39 | for (var k=0; k<4; k++) { 40 | pm3[k] = pm1[pm2[k]]; 41 | } 42 | pmul[i][j] = getNPerm(pm3, 4); 43 | if (i<16) { 44 | i2f(i, pm1); 45 | for (var k=0; k<4; k++) { 46 | pm3[k] = pm1[pm2[k]]; 47 | } 48 | fmul[i][j] = f2i(pm3); 49 | } 50 | } 51 | } 52 | createMove(cmv, 495, getmv); 53 | 54 | permPrun = []; 55 | flipPrun = []; 56 | createPrun(permPrun, 0, 11880, 5, pmv); 57 | createPrun(flipPrun, 0, 7920, 6, fmv); 58 | 59 | //combMove[comb][m] = comb*, flip*, perm* 60 | //newcomb = comb*, newperm = perm x perm*, newflip = flip x perm* ^ flip* 61 | function getmv(comb, m) { 62 | var arr = [0,0,0,0,0,0,0,0,0,0,0,0]; 63 | var r = 4; 64 | for (var i=0; i<12; i++) { 65 | if (comb >= Cnk[11-i][r]) { 66 | comb -= Cnk[11-i][r--]; 67 | arr[i] = r<<1; 68 | } else { 69 | arr[i] = -1; 70 | } 71 | } 72 | edgeMove(arr, m); 73 | comb = 0, r = 4; 74 | var t = 0; 75 | var pm = []; 76 | for (var i=0; i<12; i++) { 77 | if (arr[i] >= 0) { 78 | comb += Cnk[11-i][r--]; 79 | pm[r] = arr[i] >> 1; 80 | t |= (arr[i] & 1) << (3-r); 81 | } 82 | } 83 | return (comb*24 + getNPerm(pm, 4)) << 4 | t; 84 | } 85 | } 86 | 87 | function xinit() { 88 | init(); 89 | for (var i=0; i<24; i++) { 90 | c1mv[i] = []; 91 | e1mv[i] = []; 92 | for (var m=0; m<6; m++) { 93 | c1mv[i][m] = cornMove(i, m); 94 | var edge = [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]; 95 | edge[i>>1] = i & 1; 96 | edgeMove(edge, m); 97 | for (var e=0; e<12; e++) { 98 | if (edge[e] >= 0) { 99 | e1mv[i][m] = e<<1|edge[e]; 100 | break; 101 | } 102 | } 103 | } 104 | } 105 | ecPrun = []; 106 | for (var obj=0; obj<4; obj++) { 107 | var prun = []; 108 | createPrun(prun, (obj+4)*3*24+(obj+4)*2, 576, 5, function(q, m) {return c1mv[~~(q/24)][m]*24+e1mv[q%24][m]}); 109 | ecPrun[obj] = prun; 110 | } 111 | function cornMove(corn, m) { 112 | var idx = ~~(corn / 3); 113 | var twst = corn % 3; 114 | var idxt = [ 115 | [3, 1, 2, 7, 0, 5, 6, 4], 116 | [0, 1, 6, 2, 4, 5, 7, 3], 117 | [1, 2, 3, 0, 4, 5, 6, 7], 118 | [0, 5, 1, 3, 4, 6, 2, 7], 119 | [4, 0, 2, 3, 5, 1, 6, 7], 120 | [0, 1, 2, 3, 7, 4, 5, 6]]; 121 | var twstt = [ 122 | [2, 0, 0, 1, 1, 0, 0, 2], 123 | [0, 0, 1, 2, 0, 0, 2, 1], 124 | [0, 0, 0, 0, 0, 0, 0, 0], 125 | [0, 1, 2, 0, 0, 2, 1, 0], 126 | [1, 2, 0, 0, 2, 1, 0, 0], 127 | [0, 0, 0, 0, 0, 0, 0, 0]]; 128 | twst = (twst + twstt[m][idx]) % 3; 129 | return idxt[m][idx]*3+twst; 130 | } 131 | } 132 | 133 | //e4perm, e4flip, e1, c1 134 | //obj: -1:only cross. 135 | // i-4: end when e==i*2, c==i*3 136 | function idaxcross(q,t,e,c,obj,l,lm,sol){ 137 | if(l==0){ 138 | return q==0 && t==0 && e==(obj+4)*2 && c==(obj+4)*3; 139 | }else{ 140 | if(getPruning(permPrun, q)>l || getPruning(flipPrun, t) > l || getPruning(ecPrun[obj], c*24+e)>l) return false; 141 | var p,s,ex,cx,a,m; 142 | for(m=0;m<6;m++){ 143 | if(m!=lm && m!=lm-3){ 144 | p=q; s=t; ex=e; cx=c; 145 | for(a=0;a<3;a++){ 146 | p=pmv(p, m); 147 | s=fmv(s, m); 148 | ex=e1mv[ex][m]; 149 | cx=c1mv[cx][m]; 150 | if(idaxcross(p,s,ex,cx,obj,l-1,m,sol)) { 151 | sol.push("FRUBLD".charAt(m) + " 2'".charAt(a)); 152 | return(true); 153 | } 154 | } 155 | } 156 | } 157 | } 158 | return false; 159 | } 160 | 161 | //e4perm, e4flip 162 | function idacross(q,t,l,lm,sol){ 163 | if(l==0){ 164 | return q==0 && t==0; 165 | }else{ 166 | if(getPruning(permPrun, q) > l || getPruning(flipPrun, t) > l) return false; 167 | var p,s,a,m; 168 | for(m=0;m<6;m++){ 169 | if(m!=lm && m!=lm-3){ 170 | p=q; s=t; 171 | for(a=0;a<3;a++){ 172 | p=pmv(p, m); 173 | s=fmv(s, m); 174 | if(idacross(p,s,l-1,m,sol)) { 175 | sol.push("FRUBLD".charAt(m) + " 2'".charAt(a)); 176 | return(true); 177 | } 178 | } 179 | } 180 | } 181 | } 182 | return false; 183 | } 184 | 185 | var faceStr = ["D", "U", "L", "R", "F", "B"]; 186 | var moveIdx = ["FRUBLD", "FLDBRU", "FDRBUL", "FULBDR", "URBDLF", "DRFULB"] 187 | var rotIdx = ["  ", "z2", "z'", "z ", "x'", "x "]; 188 | 189 | var curScramble; 190 | 191 | function fullInit() { 192 | init(); 193 | fullPrun = []; 194 | createPrun(fullPrun, 0, 190080, 7, fullmv, 6, 3, 6); 195 | } 196 | 197 | function getEasyCross(length) { 198 | fullInit(); 199 | if (length > 8) { 200 | length = 8; 201 | } 202 | var cases = mathlib.rn([1, 16, 174, 1568, 11377, 57758, 155012, 189978, 190080][length]) + 1; 203 | var i; 204 | for (i=0; i<190080; i++) { 205 | if (getPruning(fullPrun, i) <= length && --cases == 0) { 206 | break; 207 | } 208 | } 209 | var comb = ~~(i / 384); 210 | var perm = (i >> 4) % 24; 211 | var flip = i & 15; 212 | 213 | var arrp = []; 214 | var arrf = []; 215 | var pm = []; 216 | var fl = []; 217 | i2f(flip, fl); 218 | setNPerm(pm, perm, 4); 219 | var r = 4; 220 | var map = [7,6,5,4,10,9,8,11,3,2,1,0]; 221 | for (i=0; i<12; i++) { 222 | if (comb >= Cnk[11-i][r]) { 223 | comb -= Cnk[11-i][r--]; 224 | arrp[map[i]] = pm[r]; 225 | arrf[map[i]] = fl[r]; 226 | } else { 227 | arrp[map[i]] = arrf[map[i]] = -1; 228 | } 229 | } 230 | return [arrp, arrf]; 231 | 232 | 233 | } 234 | 235 | return { 236 | getEasyCross: getEasyCross 237 | } 238 | })(mathlib.createMove, mathlib.edgeMove, mathlib.createPrun, mathlib.setNPerm, mathlib.getNPerm, mathlib.Cnk, mathlib.getPruning); -------------------------------------------------------------------------------- /pyTwistyScrambler/js_resources/mathlib.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var mathlib = (function() { 4 | 5 | var Cnk = [], fact = [1]; 6 | for (var i=0; i<32; ++i) { 7 | Cnk[i] = []; 8 | for (var j=0; j<32; ++j) { 9 | Cnk[i][j] = 0; 10 | } 11 | } 12 | for (var i=0; i<32; ++i) { 13 | Cnk[i][0] = Cnk[i][i] = 1; 14 | fact[i + 1] = fact[i] * (i + 1); 15 | for (var j=1; j1; i--) { 31 | arr[arguments[i]] = arr[arguments[i-1]]; 32 | } 33 | arr[arguments[1]] = temp; 34 | return circle; 35 | } 36 | 37 | function getPruning(table, index) { 38 | return table[index >> 3] >> ((index & 7) << 2) & 15; 39 | } 40 | 41 | function setNPerm(arr, idx, n) { 42 | var i, j; 43 | arr[n - 1] = 0; 44 | for (i = n - 2; i >= 0; --i) { 45 | arr[i] = idx % (n - i); 46 | idx = ~~(idx / (n - i)); 47 | for (j = i + 1; j < n; ++j) { 48 | arr[j] >= arr[i] && ++arr[j]; 49 | } 50 | } 51 | } 52 | 53 | function getNPerm(arr, n) { 54 | var i, idx, j; 55 | idx = 0; 56 | for (i = 0; i < n; ++i) { 57 | idx *= n - i; 58 | for (j = i + 1; j < n; ++j) { 59 | arr[j] < arr[i] && ++idx; 60 | } 61 | } 62 | return idx; 63 | } 64 | 65 | function getNParity(idx, n) { 66 | var i, p; 67 | p = 0; 68 | for (i = n - 2; i >= 0; --i) { 69 | p ^= idx % (n - i); 70 | idx = ~~(idx / (n - i)); 71 | } 72 | return p & 1; 73 | } 74 | 75 | function get8Perm(arr, n) { 76 | if (n === undefined) { 77 | n = 8; 78 | } 79 | var i, idx, v, val; 80 | idx = 0; 81 | val = 1985229328; 82 | for (i = 0; i < n - 1; ++i) { 83 | v = arr[i] << 2; 84 | idx = (n - i) * idx + (val >> v & 7); 85 | val -= 286331152 << v; 86 | } 87 | return idx; 88 | } 89 | 90 | function set8Perm(arr, idx, n) { 91 | if (n === undefined) { 92 | n = 8; 93 | } 94 | n--; 95 | var i, m, p, v, val; 96 | val = 1985229328; 97 | for (i = 0; i < n; ++i) { 98 | p = fact[n - i]; 99 | v = ~~(idx / p); 100 | idx %= p; 101 | v <<= 2; 102 | arr[i] = val >> v & 7; 103 | m = (1 << v) - 1; 104 | val = (val & m) + (val >> 4 & ~m); 105 | } 106 | arr[n] = val & 7; 107 | } 108 | 109 | function createMove(moveTable, size, doMove, N_MOVES) { 110 | N_MOVES = N_MOVES || 6; 111 | for (var j=0; j>>3; i> 3] ^= 15 << ((init & 7) << 2); 145 | // var t = +new Date; 146 | for (var l=0; l<=maxd; l++) { 147 | var done = 0; 148 | var inv = l >= N_INV; 149 | var fill = (l + 1) ^ 15; 150 | var find = inv ? 0xf : l; 151 | var check = inv ? l : 0xf; 152 | out: for (var p=0; p> 3] ^= fill << ((p & 7) << 2); 166 | continue out; 167 | } 168 | prun[q >> 3] ^= fill << ((q & 7) << 2); 169 | } 170 | } 171 | } 172 | if (done == 0) { 173 | break; 174 | } 175 | // console.log(done); 176 | } 177 | } 178 | 179 | //state_params: [[init, doMove, size, [maxd], [N_INV]], [...]...] 180 | function Solver(N_MOVES, N_POWER, state_params) { 181 | this.N_STATES = state_params.length; 182 | this.N_MOVES = N_MOVES; 183 | this.N_POWER = N_POWER; 184 | this.state_params = state_params; 185 | this.inited = false; 186 | } 187 | 188 | var _ = Solver.prototype; 189 | 190 | _.search = function(state, minl, MAXL) { 191 | MAXL = (MAXL || 99) + 1; 192 | if (!this.inited) { 193 | this.move = []; 194 | this.prun = []; 195 | for (var i = 0; i < this.N_STATES; i++) { 196 | var state_param = this.state_params[i]; 197 | var init = state_param[0]; 198 | var doMove = state_param[1]; 199 | var size = state_param[2]; 200 | var maxd = state_param[3]; 201 | var N_INV = state_param[4]; 202 | this.move[i] = []; 203 | this.prun[i] = []; 204 | createMove(this.move[i], size, doMove, this.N_MOVES); 205 | createPrun(this.prun[i], init, size, maxd, this.move[i], this.N_MOVES, this.N_POWER, N_INV); 206 | } 207 | this.inited = true; 208 | } 209 | this.sol = []; 210 | for (var maxl = minl; maxl < MAXL; maxl++) { 211 | if (this.idaSearch(state, maxl, -1)) { 212 | break; 213 | } 214 | } 215 | return maxl == MAXL ? null : this.sol.reverse(); 216 | } 217 | 218 | _.toStr = function(sol, move_map, power_map) { 219 | var ret = []; 220 | for (var i = 0; i < sol.length; i++) { 221 | ret.push(move_map[sol[i][0]] + power_map[sol[i][1]]); 222 | } 223 | return ret.join(' ').replace(/ +/g, ' '); 224 | } 225 | 226 | _.idaSearch = function(state, maxl, lm) { 227 | var N_STATES = this.N_STATES; 228 | if (maxl == 0) { 229 | for (var i = 0; i < N_STATES; i++) { 230 | if (state[i] != 0) { 231 | return false; 232 | } 233 | } 234 | return true; 235 | } 236 | for (var i = 0; i < N_STATES; i++) { 237 | if (getPruning(this.prun[i], state[i]) > maxl) { 238 | return false; 239 | } 240 | } 241 | for (var move = 0; move < this.N_MOVES; move++) { 242 | if (move == lm) { 243 | continue; 244 | } 245 | var cur_state = state.slice(); 246 | for (var power = 0; power < this.N_POWER; power++) { 247 | for (var i = 0; i < N_STATES; i++) { 248 | cur_state[i] = this.move[i][move][cur_state[i]]; 249 | } 250 | if (this.idaSearch(cur_state, maxl - 1, move)) { 251 | this.sol.push([move, power]); 252 | return true; 253 | } 254 | } 255 | } 256 | return false; 257 | } 258 | 259 | function rndEl(x) { 260 | return x[~~(Math.random()*x.length)]; 261 | } 262 | 263 | function rn(n) { 264 | return ~~(Math.random()*n) 265 | } 266 | 267 | function rndProb(plist) { 268 | var cum = 0; 269 | var curIdx = 0; 270 | for (var i = 0; i < plist.length; i++) { 271 | if (plist[i] == 0) { 272 | continue; 273 | } 274 | // console.log(plist, plist[i] / (cum + plist[i])); 275 | if (Math.random() < plist[i] / (cum + plist[i])) { 276 | curIdx = i; 277 | } 278 | cum += plist[i]; 279 | } 280 | return curIdx; 281 | } 282 | 283 | return { 284 | Cnk: Cnk, 285 | fact: fact, 286 | getPruning: getPruning, 287 | setNPerm: setNPerm, 288 | getNPerm: getNPerm, 289 | getNParity: getNParity, 290 | get8Perm: get8Perm, 291 | set8Perm: set8Perm, 292 | createMove: createMove, 293 | edgeMove: edgeMove, 294 | circle: circle, 295 | circleOri: circleOri, 296 | createPrun: createPrun, 297 | rn: rn, 298 | rndEl: rndEl, 299 | rndProb: rndProb, 300 | Solver: Solver 301 | } 302 | 303 | })(); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyTwistyScrambler 2 | A Python package for generating scrambles of various twisty puzzles, including the Rubik's cube, 4x4x4 cube, and others. 3 | Thanks to [csTimer](https://github.com/cs0x7f/cstimer) for providing the bulk of the Javascript scrambling source code around which this project is a wrapper. 4 | Also thanks to [torchlight](https://github.com/torchlight) for the FTO random-state Javascript scrambling source. 5 | 6 | ## Example usage 7 | 8 | ```python 9 | from pyTwistyScrambler import scrambler333, scrambler222, scrambler444,\ 10 | megaminxScrambler, squareOneScrambler, ftoScrambler, rexScrambler 11 | 12 | scrambler333.get_WCA_scramble() 13 | # D2 L F2 L2 F2 U2 L D2 F2 L' B' U2 F2 D' F D2 B' U2 R U' 14 | 15 | scrambler222.get_WCA_scramble() 16 | # R' F2 U2 R' U R2 F' U' F' U' 17 | 18 | scrambler444.get_WCA_scramble() 19 | # L2 F D2 R U Fw' Uw D L F Rw D' F L2 F' Rw' F Uw B' F' L2 B' U' Rw' F B R' D U2 L2 Fw' B D' Rw' Uw' B' Fw' R2 L2 U 20 | 21 | megaminxScrambler.get_WCA_scramble() 22 | # R-- D-- R++ D++ R++ D++ R++ D++ R++ D++ U R-- D++ R-- D++ R-- D++ R-- D++ R-- D-- U' R-- D++ R-- D-- R-- D++ R-- D-- R-- D-- U' R++ D++ R-- D-- R++ D-- R-- D++ R-- D-- U' R-- D-- R++ D++ R++ D-- R++ D++ R++ D-- U' R-- D-- R++ D-- R++ D-- R++ D-- R++ D++ U R++ D-- R++ D-- R++ D++ R-- D-- R++ D++ U 23 | 24 | squareOneScrambler.get_WCA_scramble() 25 | # (0, -1)/(4, 1)/(-4, 5)/(0, -3)/(1, -2)/(3, 0)/(2, 0)/(0, -3)/(4, -3)/(0, -4)/(2, 0)/(5, -2)/(4, 0) 26 | 27 | ftoScrambler.get_random_state_scramble() 28 | # U L' U' L U L' U L' U' L' U' L' U' L' U L U' L' F L R L' F L U' F' R' U' R B R BR R' BL B' 29 | 30 | rexScrambler.get_random_state_scramble() 31 | # f F R F' R' f' F' L' F' f R' f' R F f' L f F R F' f' R f L' f' F' R L' f' L r l L' f L r' 32 | ``` 33 | 34 | ## What scrambles can be generated? 35 | ### 3x3x3 (Rubik's cube) 36 | In `scrambler333` module: 37 | 38 | - `get_WCA_scramble()` random state scramble (WCA) 39 | - `get_3BLD_scramble()` BLD scramble 40 | - `get_edges_scramble()` edges-only 41 | - `get_corners_scramble()` corners-only 42 | - `get_LL_scramble()` LL (last layer) 43 | - `get_F2L_scramble()` F2L (first two layers) 44 | - `get_easy_cross_scramble(n=4)` easy cross (where cross can be solved in `n` moves) 45 | - `get_LSLL_scramble()` LSLL 46 | - `get_ZBLL_scramble()` ZBLL 47 | - `get_ZZLL_scramble()` ZZLL 48 | - `get_ZBLS_scramble()` ZBLS 49 | - `get_LSE_scramble()` LSE 50 | - `get_CMLL_scramble()` CMLL 51 | - `get_CLL_scramble()` CLL 52 | - `get_ELL_scramble()` ELL 53 | - `get_EOLine_scramble()` EO Line 54 | - `get_2genRU_scramble()` 2-gen with RU moves 55 | - `get_2genLU_scramble()` 2-gen with LU moves 56 | - `get_2genMU_scramble()` 2-gen with MU moves 57 | - `get_3genFRU_scramble()` 3-gen with FRU moves 58 | - `get_3genRUL_scramble()` 3-gen with RUL moves 59 | - `get_3genRrU_scramble()` 3-gen with RrU moves 60 | - `get_half_turns_scramble()` half-turns only 61 | 62 | ### 2x2x2 63 | In `scrambler222` module: 64 | 65 | - `get_WCA_scramble()` random scramble (WCA) 66 | - `get_optimal_scramble()` optimal random state scramble 67 | 68 | ### 4x4x4 69 | In `scrambler444` module: 70 | 71 | - `get_WCA_scramble(n=40)` random scramble (WCA) of length `n` 72 | - `get_4BLD_scramble(n=40)` alias of `get_WCA_scramble` 73 | - `get_SiGN_scramble(n=40)` SiGN-notation scramble of length `n` 74 | - `get_random_state_scramble()` random state scramble (note: this is **slow**) 75 | - `get_edges_scramble(n=8)` edges scramble 76 | 77 | ### 5x5x5 78 | In `scrambler555` module: 79 | 80 | - `get_WCA_scramble(n=60)` random scramble (WCA) of length `n` 81 | - `get_5BLD_scramble(n=60)` alias of `get_WCA_scramble` 82 | - `get_SiGN_scramble(n=60)` SiGN-notation scramble of length `n` 83 | - `get_edges_scramble(n=8)` edges scramble 84 | 85 | ### 6x6x6 86 | In `scrambler666` module: 87 | 88 | - `get_WCA_scramble(n=80)` random scramble (WCA) of length `n` 89 | - `get_SiGN_scramble(n=80)` SiGN-notation scramble of length `n` 90 | - `get_edges_scramble(n=8)` edges scramble 91 | 92 | ### 7x7x7 93 | In `scrambler777` module: 94 | 95 | - `get_WCA_scramble(n=100)` random scramble (WCA) of length `n` 96 | - `get_SiGN_scramble(n=100)` SiGN-notation scramble of length `n` 97 | - `get_edges_scramble(n=8)` edges scramble 98 | 99 | ### Pyraminx 100 | In `pyraminxScrambler` module: 101 | 102 | - `get_WCA_scramble()` random scramble (WCA) 103 | - `get_optimal_scramble()` optimal random state scramble 104 | 105 | ### Megaminx 106 | In `megaminxScrambler` module: 107 | 108 | - `get_WCA_scramble(n=70)` random scramble (WCA) of length `n` 109 | - `get_Carrot_scramble(n=70)` Carrot-notation scramble of length `n` 110 | - `get_old_style_scramble(n=70)` old-style scramble of length `n` 111 | 112 | ### Square-1 113 | In `squareOneScrambler` module: 114 | 115 | - `get_WCA_scramble()` random scramble (WCA) 116 | - `get_face_turn_metric_scramble(n=40)` face-turn metric scramble of length `n` 117 | - `get_twist_metric_scramble(n=20)` twist metric scramble of length `n` 118 | 119 | ### Skewb 120 | In `skewbScrambler` module: 121 | 122 | - `get_WCA_scramble()` random scramble (WCA) 123 | - `get_ULRB_scramble()` ULRB scramble 124 | 125 | ### Clock 126 | In `clockScrambler` module: 127 | 128 | - `get_WCA_scramble()` Clock scramble (WCA notation) 129 | - `get_Jaap_scramble()` Clock scramble (Jaap notation) 130 | - `get_concise_scramble()` Clock scramble (concise notation) 131 | - `get_efficient_pin_order_scramble()` Clock scramble (efficient pin order notation) 132 | 133 | ### FTO (Face-turning octahedron) 134 | In `ftoScrambler` module: 135 | 136 | - `get_random_state_scramble()` random-state scramble (note: this takes ~10s per scramble) 137 | - `get_multiple_random_state_scrambles(n)` returns a list of `n` random-state scrambles 138 | - `get_random_moves_scramble(n=30)` random-moves scramble of length `n` 139 | 140 | If you need multiple random-state scrambles, it's much faster to use `get_multiple_random_state_scrambles` than 141 | calling `get_random_state_scramble` multiple times; the former takes the usual ~10s for the first scramble but then 142 | the remaining scrambles are much faster (less than 1s per scramble). This is due to how the underlying FTO scrambler 143 | generates background data during the first scramble which is used to speed up subsequent scrambles. 144 | 145 | ### Rex Cube 146 | In `rexScrambler` module: 147 | 148 | - `get_random_state_scramble()` random-state scramble (note: this takes ~10s per scramble) 149 | - `get_multiple_random_state_scrambles(n)` returns a list of `n` random-state scrambles 150 | - `get_random_moves_scramble(n=30)` random-moves scramble of length `n` 151 | 152 | Since Rex Cube and FTO are mechanically the same puzzle, this is actually a wrapper around `ftoScrambler` which 153 | translates the FTO notation to Rex Cube notation. 154 | 155 | If you need multiple random-state scrambles, it's much faster to use `get_multiple_random_state_scrambles` than 156 | calling `get_random_state_scramble` multiple times; the former takes the usual ~10s for the first scramble but then 157 | the remaining scrambles are much faster (less than 1s per scramble). This is due to how the underlying FTO scrambler 158 | generates background data during the first scramble which is used to speed up subsequent scrambles. 159 | 160 | ### Big cubes 161 | In `bigCubesScrambler` module: 162 | 163 | - `get_8x8x8_scrambler(n=120)` 8x8x8 scramble (SiGN notation) of length `n` 164 | - `get_9x9x9_scrambler(n=120)` 9x9x9 scramble (SiGN notation) of length `n` 165 | - `get_10x10x10_scrambler(n=120)` 10x10x10 scramble (SiGN notation) of length `n` 166 | - `get_11x11x11_scrambler(n=120)` 11x11x11 scramble (SiGN notation) of length `n` 167 | 168 | ### Cuboids 169 | In `cuboidsScrambler` module: 170 | 171 | - `get_1x1x2_scramble()` 1x1x2 cuboid scramble 172 | - `get_1x3x3_scramble()` 1x3x3 cuboid (floppy cube) scramble 173 | - `get_floppy_cube_scramble()` alias of `get_1x3x3_scramble()` 174 | - `get_super_floppy_cube_scramble()` 1x3x3 cuboid (super floppy cube) scramble 175 | - `get_2x2x3_scramble()` 2x2x3 cuboid scramble 176 | - `get_3x3x2_scramble()` 3x3x2 cuboid scramble 177 | - `get_3x3x4_scramble()` 3x3x4 cuboid scramble 178 | - `get_3x3x5_scramble(n=25)` 3x3x5 cuboid scramble, where `n` is the length of the non-3x3 portion of the scramble 179 | - `get_3x3x6_scramble()` 3x3x6 cuboid scramble 180 | - `get_3x3x7_scramble(n=40)` 3x3x7 cuboid scramble, where `n` is the length of the non-3x3 portion of the scramble 181 | -------------------------------------------------------------------------------- /pyTwistyScrambler/js_resources/scramble.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var scramble = (function(rn, rndEl) { 3 | //var div = $('
'); 4 | //var title = $('
').addClass('title'); 5 | //var select = $(''); 7 | //var scrLen = $(''); 8 | //var sdiv = $('
'); 9 | var alias = { 10 | '333fm': '333', 11 | '333oh': '333', 12 | '333ft': '333', 13 | '444bld': '444wca', 14 | '555bld': '555wca' 15 | }; 16 | 17 | //var inputText = $('