Coder Social home page Coder Social logo

hkociemba / rubikscube-twophasesolver Goto Github PK

View Code? Open in Web Editor NEW
564.0 24.0 92.0 87.35 MB

Solve Rubik's Cube in less than 19 moves on average with Python.

License: GNU General Public License v3.0

Python 100.00%
rubik cube python rubikscube-twophasesolver kociemba two-phase-algorithm

rubikscube-twophasesolver's Introduction

RubiksCube-TwophaseSolver

Overview

This project implements the fully developed form of the two-phase-algorithm to solve the Rubik's Cube in Python. While Python is much slower compared to languages such as C++ or Java, the implementation is efficient enough to solve random cubes in less than 20 moves on average within a few seconds on slow hardware like the Raspberry Pi3.

If your goal is simply to solve Rubik's Cube and explore its patterns, Cube Explorer might be the better choice. However, if you aim to gain a deeper understanding of the two-phase-algorithm's intricacies or if you are working on a project to construct a cube-solving robot that achieves near-optimal solutions, then this is the right resource.

Usage

The package is available on PyPI and can be installed with

$ pip install RubikTwoPhase

Once installed, you can import the twophase.solver module into your code:

>>> import twophase.solver  as sv

Some tables need to be created, but only on the first run. These tables take up approximately 80 MB of disk space and require about half an hour or more to generate, depending on your hardware. However, it is with these computationally expensive tables that the algorithm operates efficiently, usually finding near-optimal solutions.

A cube is defined by its cube definition string. A solved cube has the string 'UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB'.

>>> cubestring = 'DUUBULDBFRBFRRULLLBRDFFFBLURDBFDFDRFRULBLUFDURRBLBDUDL'

Refer to https://github.com/hkociemba/RubiksCube-TwophaseSolver/blob/master/enums.py for the exact format.

>>> sv.solve(cubestring,19,2)

This will solve the cube described by the definition string with a desired maximum length of 19 moves and a timeout of 2 seconds. If the timeout is reached, the shortest solution computed so far is returned, even if it exceeds the desired maximum length.

'L3 U1 B1 R2 F3 L1 F3 U2 L1 U3 B3 U2 B1 L2 F1 U2 R2 L2 B2 (19f)'

Here, U, R, F, D, L and B denote the Up, Right, Front, Down, Left and Back faces of the cube. 1, 2, and 3 denote a 90°, 180° and 270° clockwise rotation of the corresponding face.

If you prefer to allocate a constant time t for each solution and receive only the shortest maneuver found within that time t, use the following command:

>>> sv.solve(cubestring,0,t)

You can test the performance of the algorithm on your machine with something similar to

>>> import twophase.performance as pf
>>> pf.test(100,0.3)

This example generates 100 random cubes, solves each one in 0.3 s and displays a statistic about the solution lengths.

You also have the possibility to solve a cube not to the solved position but to some favorite pattern represented by the goalstring.

>>> sv.solveto(cubestring,goalstring,20,0.1)

will grant e.g. 0.1 s to find a solution with <= 20 moves.


Another feature is to start a local server listening on a port of your choice. It accepts the cube definition string and returns the solution.

>>> import twophase.server as srv
>>> srv.start(8080, 20, 2)

Alternatively, start the server in the background:

>>> import twophase.start_server as ss
>>> from threading import Thread
>>> bg = Thread(target=ss.start, args=(8080, 20, 2))
>>> bg.start()

Upon successful initiation, a message like

Server socket created
Server now listening...

indicates the proper functioning of the server. In this example, the server is listening on port 8080, with a desired maximum length of 20 moves and a timeout of 2 seconds.

You can access the server, which may also run on a remote machine, using various methods:

http://localhost:8080/DUUBULDBFRBFRRULLLBRDFFFBLURDBFDFDRFRULBLUFDURRBLBDUDL
via a web browser and the server on the same machine on port 8080.

http://myserver.com:8081/DUUBULDBFRBFRRULLLBRDFFFBLURDBFDFDRFRULBLUFDURRBLBDUDL
via a web browser and the server on the remote machine myserver.com on port 8081.

echo DUUBULDBFRBFRRULLLBRDFFFBLURDBFDFDRFRULBLUFDURRBLBDUDL | nc localhost 8080
using netcat (nc) and the server on the same machine on port 8080.

You can also communicate with the server using a small GUI program that allows you to interactively enter the cube definition string:

>>> import twophase.client_gui


Please note that the following module is experimental and requires the installation of the OpenCV package, which can be done with
$ pip install opencv-python
Additionally, you'll need the numpy package, which can be installed with
$ pip install numpy

Load the module with

>>> import twophase.computer_vision

Ensure that the webserver is running, and a webcam is connected to the client.
You can use the webcam to input the facelet colors. There are several parameters that affect the quality of the facelet detection. If you are using a Raspberry Pi with the Raspberry Pi Camera Module and not a USB webcam make sure you do "sudo modprobe bcm2835-v4l2" first.

You can find more information on how to set the parameters here: Computer vision and Rubik's cube


Performance Metrics

We conducted tests solving 1000 random cubes in various scenarios on a Windows 10 machine with an AMD Ryzen 7 3700X 3.59 GHz. Differentiating between the standard CPython interpreter and PyPy (pypy3) with a Just-in-Time compiler yielded speedups of approximately 10x.

test(1000, t) generates 1000 random cubes, the computing time for each cube is t seconds. The distribution of the solving lengths also is given.

Standard CPython

test(1000,30): {14: 0, 15: 2, 16: 12, 17: 74, 18: 279, 19: 534, 20: 99, 21: 0}, average 18.63 moves
test(1000,10): {14: 0, 15: 1, 16: 8, 17: 51, 18: 242, 19: 532, 20: 166, 21: 0}, average 18.79 moves
test(1000,1): {14: 0, 15: 2, 16: 4, 17: 28, 18: 127, 19: 401, 20: 405, 21: 33, 22: 0}, average 19.27 moves
test(1000,0.1): {15: 0, 16: 2, 17: 6, 18: 46, 19: 186, 20: 451, 21: 293, 22: 16, 23: 0}, average 20.02 moves

PyPy (pypy3) with Just-in-Time compiler

test(1000,10): {14: 0, 15: 1, 16: 11, 17: 100, 18: 423, 19: 433, 20: 32, 21: 0}, average 18.37 moves
test(1000,1): {14: 0, 15: 1, 16: 10, 17: 49, 18: 259, 19: 535, 20: 145, 21: 1, 22: 0}, average 18.76 moves
test(1000,0.1): {15: 0, 16: 4, 17: 23, 18: 100, 19: 429, 20: 401, 21: 43, 22: 0}, average 19.33 moves
test(1000,0.01): {16: 0, 17: 1, 18: 25, 19: 95, 20: 349, 21: 461, 22: 69, 23: 0}, average 20.45 moves

To achieve an average of less than 19 moves, a computation time of 10 s in the case of CPython or 1 s in the case of PyPy is sufficient. For an average of 0.5 moves more, a computation time of 1 s with CPython and 0.1 s with PyPy is sufficient.

Star History

Star History Chart

rubikscube-twophasesolver's People

Contributors

hkociemba avatar tazeg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rubikscube-twophasesolver's Issues

Sub-optimal / not solution to R1 U1 F1

I discovered this problem on my CUBOTino autonomous
Orientate the cube with Green F, White U
R1 U1 F1

Cube status (via BGR color distance): UUUUUULLDFBBFRRFRRFFRFFRDDRRRUDDBDDBFFDLLDLLBLLLUBBUBB
Camera warm-up, camera setting, cube status (BGR), and solution, in: 50.0 secs

Cube solution: 9 moves  F3 U1 D2 R2 L2 U2 D2 R1 L2
Robot moves string: applied optimization type 2
Total robot movements: 47

total amount of servo movements: 47

And it DOESN'T SOLVE

Testing just the RubikTwoPhase library:

On Pi Zero W
(Andrea Favero bult the code code, possibly on a Pi Zero 2 W, in case that is significant)

(.virtualenvs) root@cubotino:/home/pi/cubotino/src# python
Python 3.7.3 (default, Oct 31 2022, 14:04:00)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import twophase.solver  as sv
loading conj_twist table...
loading conj_ud_edges table...
loading flipslice sym-tables...
loading corner sym-tables...
loading move_twist table...
loading move_flip table...
loading move_slice_sorted table...
loading move_u_edges table...
loading move_d_edges table...
loading move_ud_edges table...
loading move_corners table...
loading phase1_prun table...
loading phase2_prun table...
loading phase2_cornsliceprun table...
>>> cubestring = 'UUUUUULLDFBBFRRFRRFFRFFRDDRRRUDDBDDBFFDLLDLLBLLLUBBUBB'
>>> sv.solve(cubestring,19,2)                                            
'F3 U1 D2 R2 L2 U2 D2 R1 L2 (9f)'
>>> 

(.virtualenvs) root@cubotino:/home/pi/cubotino/src# pip list | grep RubikTwoPhase
RubikTwoPhase         1.0.9

(.virtualenvs) root@cubotino:/home/pi/cubotino/src# uname -a
Linux cubotino 5.10.103+ #1529 Tue Mar 8 12:19:18 GMT 2022 armv6l GNU/Linux
(.virtualenvs) root@cubotino:/home/pi/cubotino/src# cat /proc/cpuinfo
processor       : 0
model name      : ARMv6-compatible processor rev 7 (v6l)
BogoMIPS        : 797.66
Features        : half thumb fastmult vfp edsp java tls
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xb76
CPU revision    : 7

Hardware        : BCM2835
Revision        : 9000c1
Serial          : 0000000083b98790
Model           : Raspberry Pi Zero W Rev 1.1

On Mac

(CUBOTino_venv) porta-mac:PC_files johnm$ python
Python 3.8.3 (v3.8.3:6f8c8320e9, May 13 2020, 16:29:34)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import twophase.solver as sv
loading conj_twist table...
loading conj_ud_edges table...
loading flipslice sym-tables...
loading corner sym-tables...
loading move_twist table...
loading move_flip table...
loading move_slice_sorted table...
loading move_u_edges table...
loading move_d_edges table...
loading move_ud_edges table...
loading move_corners table...
loading phase1_prun table...
loading phase2_prun table...
loading phase2_cornsliceprun table...
loading phase2_edgemerge table...
>>> cubestring = 'UUUUUULLDFBBFRRFRRFFRFFRDDRRRUDDBDDBFFDLLDLLBLLLUBBUBB'
>>> sv.solve(cubestring,19,2)
'F3 U3 R1 U2 D2 R2 L2 U2 D2 L2 (10f)'
>>> 
(CUBOTino_venv) porta-mac:CUBOT johnm$ pip list | grep RubikTwoPhase
RubikTwoPhase 1.1.1

10 Moves, but it is a solution.

Since opencv 3.2 findContours does not modify the source image

This resultes in an issue in vision2.py, line 262 in find_squares:

im2, contours, hierarchy = cv2.findContours(j, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

maybe this would render the code version proof:

major = cv2.__version__.split('.')[0]
if major == '3':
    im2, contours, hierarchy = cv2.findContours(j, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
else:
    contours, hierarchy = cv2.findContours(j, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

Tables files

This is not issue, just a question.
The files generated on first run this program. What are these files? And why we need these file?

from enum import IntEnum

Hello there
I cant run this program , the file class enum.py is missing
this is being imported from enums.py
from enums import IntEnum

it doesn't run , do you have the type of IntEnum ? or the class ? so I can run it

Solver fails to solve certain states

This solver fails to correctly solve the following state: UUUUUUUUURRRRRLRRRFFFFFBFFFDDDDDDDDDLLLLLRLLLBBBFBBBBB. The server simply responds with the empty solution string (0f) as if it were the solved state (which it isn't).

Some isomorphic states also produce this problem. Curiously, however, this doesn't appear to affect all isomorphic states. In particular, if I give it the isomorphic state UUUUUUUDURRRRRRRRRFFFFFFFBFDDDDDDDUDLLLLLLLLLBBBBBBBFB, then it's able to produce an 8f solution (R2 F2 R2 U2 L2 B2 L2 U2). Best I can tell, the bug occurs on all isomorphic states that keep the up and down slices solved.

kociemba.org down

Hello !
Just to inform you that your web-site kociemba.org is down.
Thanks for your work :D

Tables to sub-folder?

Hi, I want to use your solver for an app. Everything works fine so far. I just have a request of a more cosmetic nature. Is there any simple solution to move all the table files away from the root folder of my app and hide them in some sub-folder?

webcam feature?

do you work on a webcam (RPI Camera) feature similar to cube explorer ?

EOFError: read() didn't return enough bytes

2020-12-02T12:49:17.639736+00:00 app[web.1]: loading conj_twist table...
2020-12-02T12:49:17.640385+00:00 app[web.1]: loading conj_ud_edges table...
2020-12-02T12:49:17.643817+00:00 app[web.1]: loading flipslice sym-tables...
2020-12-02T12:49:17.648517+00:00 app[web.1]: Traceback (most recent call last):
2020-12-02T12:49:17.648585+00:00 app[web.1]: File "start_server.py", line 3, in
2020-12-02T12:49:17.648830+00:00 app[web.1]: import sockets
2020-12-02T12:49:17.648859+00:00 app[web.1]: File "/app/sockets.py", line 6, in
2020-12-02T12:49:17.649051+00:00 app[web.1]: import solver
2020-12-02T12:49:17.649100+00:00 app[web.1]: File "/app/solver.py", line 5, in
2020-12-02T12:49:17.649299+00:00 app[web.1]: import symmetries as sy
2020-12-02T12:49:17.649337+00:00 app[web.1]: File "/app/symmetries.py", line 217, in
2020-12-02T12:49:17.649690+00:00 app[web.1]: flipslice_rep.fromfile(fh, N_FLIPSLICE_CLASS)
2020-12-02T12:49:17.649745+00:00 app[web.1]: EOFError: read() didn't return enough bytes

So i'am trying to use this on heroku but this error occurs

Cam is not working correctly

Hi, I have a mac and the webcam does not work correctly. I think it's because of the version of python or opencv. If someone could tell me in which verisons it works I would be grateful.

list index out of range

Hi, i tried to solve some cubes on a raspberry with your great software on a raspberry.

here is what i get when i send this to the server:
echo DDDDUDDDDRRRRRRRRRBBBBFBBBBUUUUDUUUULLLLLLLLLFFFFBFFFF |nc 127.0.0.1 8080

pi@raspberrypi:~/RubiksCube-TwophaseSolver $ python3 start_server.py

loading conj_twist table...
loading conj_ud_edges table...
loading flipslice sym-tables...
loading move_twist table...
loading move_flip table...
loading move_slice_sorted table...
loading move_u_edges table...
loading move_d_edges table...
loading move_ud_edges table...
loading move_corners table...
loading phase1_prun table...
loading phase2_prun table...
loading phase2_cornsliceprun table...
startserver
Server socket created
Server now listening...
Connected with 127.0.0.1:40968, 2017.10.28  12:16:34
Exception in thread Thread-3:
Traceback (most recent call last):
  File "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
    self.run()
  File "/home/pi/RubiksCube-TwophaseSolver/solver.py", line 193, in run
    self.search(self.co_cube.flip, self.co_cube.twist, self.co_cube.slice_sorted, dist, togo1)
  File "/home/pi/RubiksCube-TwophaseSolver/solver.py", line 114, in search
    m = self.sofar_phase1[-1]
IndexError: list index out of range

Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
    self.run()
  File "/home/pi/RubiksCube-TwophaseSolver/solver.py", line 193, in run
    self.search(self.co_cube.flip, self.co_cube.twist, self.co_cube.slice_sorted, dist, togo1)
  File "/home/pi/RubiksCube-TwophaseSolver/solver.py", line 114, in search
    m = self.sofar_phase1[-1]
IndexError: list index out of range

Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
    self.run()
  File "/home/pi/RubiksCube-TwophaseSolver/solver.py", line 193, in run
    self.search(self.co_cube.flip, self.co_cube.twist, self.co_cube.slice_sorted, dist, togo1)
  File "/home/pi/RubiksCube-TwophaseSolver/solver.py", line 114, in search
    m = self.sofar_phase1[-1]
IndexError: list index out of range

DDDDUDDDDRRRRRRRRRBBBBFBBBBUUUUDUUUULLLLLLLLLFFFFBFFFF
Connection closed

Even a already solved cube results in a server error

echo UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB |nc 127.0.0.1 8080

pi@raspberrypi:~/RubiksCube-TwophaseSolver $ python3 start_server.py
loading conj_twist table...
loading conj_ud_edges table...
loading flipslice sym-tables...
loading move_twist table...
loading move_flip table...
loading move_slice_sorted table...
loading move_u_edges table...
loading move_d_edges table...
loading move_ud_edges table...
loading move_corners table...
loading phase1_prun table...
loading phase2_prun table...
loading phase2_cornsliceprun table...
startserver
Server socket created
Server now listening...
Connected with 127.0.0.1:40972, 2017.10.28  12:23:35
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
    self.run()
  File "/home/pi/RubiksCube-TwophaseSolver/solver.py", line 193, in run
    self.search(self.co_cube.flip, self.co_cube.twist, self.co_cube.slice_sorted, dist, togo1)
  File "/home/pi/RubiksCube-TwophaseSolver/solver.py", line 114, in search
    m = self.sofar_phase1[-1]
IndexError: list index out of range

UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB
Connection closed

What am i doing wrong here, thanks, chester

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.