Skip to main content

A Python implementation of Kociemba's two-phase algorithm for solving the Rubik's Cube

Project description

rubik-solver-py

A pure-Python implementation of Kociemba's two-phase algorithm for solving the Rubik's Cube optimally (≤22 moves). Port of the TypeScript rubik-solver library.

Installation

pip install rubik-solver-py

Quick Start

from rubik_solver import Cube, init_solver, solve, scramble

# init_solver() pre-computes move and pruning tables (~30-60 s, one-time cost).
# Call it once at application startup before solving anything.
init_solver()

# Solve from a move sequence
cube = Cube().move("R U R' U' R' F R2 U' R' U' R U R' F'")
solution = solve(cube)
print(solution)  # e.g. "F R U R' U' F'"

# Generate a random scramble
print(scramble())

API Reference

init_solver()

Pre-computes all move and pruning tables required by the solver.

Must be called once before solve() or scramble().

Safe to call multiple times — subsequent calls are no-ops.


solve(cube, max_depth=22) → str | None

Solves the given Cube instance using Kociemba's two-phase algorithm.

Parameter Type Default Description
cube Cube The cube to solve
max_depth int 22 Maximum move count; returns Noneif exceeded

Returns a move string like "R U R' U'", or None if no solution was found.


scramble() → str

Returns a random scramble sequence as a move string.


Cube

The main cube class.

Method / Property Description
Cube() Creates a solved cube
.move(alg) Applies an algorithm string in place; returns self
.clone() Returns a deep copy
.is_solved() Returns Trueif the cube is solved
.as_string() Returns the 54-char facelet string
.randomize() Randomizes the cube in place; returns self
.verify() Returns Trueif valid, or an error string
Cube.from_string(s) Parses a 54-char facelet string into a Cube
Cube.random() Returns a new randomized Cube
Cube.inverse(alg) Inverts an algorithm string

Supported Move Notation

Faces: U R F D L B

Slice moves: E M S

Rotations: x y z

Wide moves: u r f d l b

Modifiers: ' (inverse), 2 (double)


Usage Examples

Build and verify a cube manually

from rubik_solver import Cube

# Solved cube
cube = Cube()
print(cube.is_solved())    # True

# Apply moves
cube.move("R U R' U'")
print(cube.is_solved())    # False

# Serialize to 54-char facelet string
print(cube.as_string())
# "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"

# Parse from a facelet string
cube2 = Cube.from_string("UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB")

# Invert an algorithm
print(Cube.inverse("R U R' U'"))  # "U R U' R'"

Solve a random cube

from rubik_solver import Cube, init_solver, solve

init_solver()
cube = Cube.random()
solution = solve(cube)
print(f"Solution ({len(solution.split())} moves): {solution}")

Validate a cube from facelet string

from rubik_solver import Cube

cube = Cube.from_string("UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB")
result = cube.verify()
if result is True:
    print("Cube is valid!")
else:
    print(f"Invalid: {result}")

Architecture

rubik_solver/
├── __init__.py        ← Public API exports
├── types.py           ← Enums (Center, Corner, Edge) and CubeState dataclass
├── constants.py       ← Table sizes, facelet mappings, base move data
├── math_utils.py      ← cnk, factorial, rotate_left, rotate_right
├── cube.py            ← Cube class (core logic, coordinates, serialization)
├── tables/
│   └── tables.py      ← Move table and pruning table generation
└── solver/
    ├── search_state.py ← SearchState used in phase 1 & 2 search
    └── solver.py       ← init_solver(), solve(), scramble(), two-phase search

Performance

Scenario Time
init_solver()— first ever call ~8 s (builds NumPy tables, writes cache)
init_solver()— subsequent calls ~15 ms (loads from ~/.cache/rubik_solver/)
solve()per cube ~0.1 – 1 s
scramble() ~0.5 – 2 s

Tables are cached automatically as .npy files. You can override the cache directory:

export RUBIK_SOLVER_CACHE_DIR=/path/to/your/cache

To force a rebuild:

from rubik_solver import clear_cache, init_solver
clear_cache()
init_solver(verbose=True)  # prints progress

Why not 10 ms like JavaScript?

V8 JIT-compiles the table construction loops. Python uses NumPy for vectorised BFS (fast) but the coordinate-computation inner loop still runs in CPython. The disk cache makes the difference negligible in practice — after the first run startup is ~15 ms regardless.

Publishing to PyPI

# Install build tools
pip install build twine

# Build the package
python -m build

# Upload to TestPyPI first (recommended)
twine upload --repository testpypi dist/*

# Upload to PyPI
twine upload dist/*

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rubik_solver_py-0.1.0.tar.gz (15.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rubik_solver_py-0.1.0-py3-none-any.whl (17.6 kB view details)

Uploaded Python 3

File details

Details for the file rubik_solver_py-0.1.0.tar.gz.

File metadata

  • Download URL: rubik_solver_py-0.1.0.tar.gz
  • Upload date:
  • Size: 15.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for rubik_solver_py-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9c1992a53ef3dcbb1d6d0a848254033928cb81085c064a42bd3f62e42e2f4204
MD5 2b4af7b37d5051744f2c3e7b79253912
BLAKE2b-256 600cf8bb870939742ee75f174bddc753b255dd1e05cea0d152e4351d78e6b046

See more details on using hashes here.

File details

Details for the file rubik_solver_py-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for rubik_solver_py-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ff68b77dbe1de48514badcf8adeec6da3f63413832d84ecc431f70d624cc5398
MD5 717bd177779312d3fd27d8ae5045e96f
BLAKE2b-256 dfd72922d51489961bdea2a31451d77fbec642a265a1876484c782dc3f3b718f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page