A flexible Rubik's Cube engine and problem generator for NΓNΓN cubes
cubieval is a pure Python library for simulating and manipulating Rubik's Cubes of any size. It provides:
- Flexible cube engine supporting 2Γ2, 3Γ3, 4Γ4, and larger cubes
- Standard notation parser for Rubik's Cube moves (R, L, U, D, F, B, and their variants)
- Problem set generator creating structured puzzles with 5 difficulty levels
- State persistence with JSON storage and transition tracking
- Zero external dependencies for core functionality
Perfect for:
- Educational projects and tutorials
- Algorithm development and testing
- Benchmark generation for AI/ML models
- Puzzle generation for competitions
# Using uv (recommended)
uv pip install cubieval
# Using pip
pip install cubieval
# From source
git clone <repository-url>
cd cubieval/cubes_py
uv pip install -e .Note: The CLI command is
cubesfor easy typing. Run commands from thecubes_pydirectory usingpython main.py <command>. After installing with pip, you can usecubes <command>directly.
# Get help and library info
python main.py info
python main.py version
# Create and manipulate a cube
python main.py create my3x3 3
python main.py apply my3x3 "R U R' U'"
python main.py state my3x3
# Generate problem sets
python main.py generate my3x3 3
python main.py generate my_4x4 4 --output problems/custom.jsonUse in your Python scripts - Everything is saved automatically to JSON in cube_storage/ in your current directory:
from cubes_py import get_registry, generate_problems
# Create a cube (saved to cube_storage/mycube.json)
registry = get_registry()
cube = registry.create_cube("mycube", 3)
# Apply moves - state and all transitions are saved automatically
registry.apply("mycube", "R U R' U'")
registry.apply("mycube", "F B' L2 D")
# Get current state - read from saved JSON
state = registry.get_state("mycube")
print(state) # Shows the current cube configuration
# All moves are tracked in cube_storage/mycube.json with:
# - Current state
# - Full transition history
# - Timestamps for each move
# Generate problem sets (saved to problems/ directory)
problems = generate_problems(cube_size=3)Key Points:
- β All cube states saved automatically as JSON
- β Full move history tracked
- β Files saved in your current working directory
- β No manual saving needed
Try it now:
# Run the included example script
python my_cube_script.py
# Creates in your directory:
# - cube_storage/my_puzzle.json (your cube with full history)
# - my_problems.json (generated problems)The cube engine supports standard Rubik's Cube notation:
- Basic moves:
R,L,U,D,F,B(clockwise 90Β°) - Counter-clockwise:
R',L',U', etc. - 180Β° rotations:
R2,L2,U2, etc. - Inner layer moves:
R1,L1, etc. (for cubes larger than 3Γ3)
from cubes_py import get_registry
registry = get_registry()
cube = registry.create_cube("my3x3", size=3)CLI:
cubes create my3x3 3# Apply a sequence of moves
new_state = registry.apply("my3x3", "R U R' U'")
# Moves are parsed automatically
registry.apply("my3x3", "R2 L2 U2 D2 F2 B2")CLI:
cubes apply my3x3 "R U R' U'"state = registry.get_state("my3x3")
# Returns a dict with face configurations:
# {"U": [[...]], "D": [[...]], "L": [[...]], "R": [[...]], "F": [[...]], "B": [[...]]}CLI:
cubes state my3x3Generate structured problem sets with progressive difficulty levels (original generator).
from cubes_py import generate_problems
# Generate problems for a 3Γ3Γ3 cube
problems = generate_problems(cube_size=3)
# Problems structure:
# {
# "level_0": {
# "problem_1": { "start_state": {...}, "end_state": {...}, "moves": [...], ... },
# ...
# },
# "level_1": { ... },
# ...
# }CLI:
# Generate and save to default location (cubes_py/problems/<cube_id>_<size>x<size>.json)
cubes generate my3x3 3
# Specify custom output path
cubes generate my3x3 3 --output problems/my_problems.jsonEach generated problem set includes:
- Level 0: 6 single-move problems (one for each face)
- Levels 1-5: 10 problems each with increasing complexity
- Total: 56 problems per cube size
Each problem contains:
{
"start_state": { /* Cube state before moves */ },
"end_state": { /* Cube state after moves */ },
"moves": ["R", "U", "R'"],
"layers_touched": ["R0", "U0"],
"total_states": {
"state_0": { /* initial */ },
"state_1": { /* after move 1 */ },
"state_2": { /* after move 2 */ },
...
},
"complexity": {
"t": 3, // Number of moves
"k": 2, // Number of unique layers affected
"p": 1, // Difficulty level
"difficulty_level": 5 // Complexity rating (1-10)
}
}NEW! Enhanced problem generator with multiple strategies, complexity analysis, and scoring.
1. Progressive - Controlled randomness from solved state
from cubes_py import ProblemGenerator
generator = ProblemGenerator(cube_size=3)
problem = generator.generate_progressive(target_moves=10, randomness=0.3)2. Pattern-Based - Known cube patterns
problem = generator.generate_pattern_based(pattern_type="corners", depth=2)
# Patterns: corners, edges, t_perm, checkerboard, cube_in_cube3. Difficulty-Scaled - Auto-scaled by difficulty level
problem = generator.generate_difficulty_scaled(difficulty_level=7)
# Difficulty 1-10 auto-scales moves, randomness, complexity4. Bidirectional - Setup for bidirectional search
problem = generator.generate_bidirectional(target_depth=5)Generate full problem sets with complexity theory and scoring:
from cubes_py import generate_problem_set
result = generate_problem_set(
cube_size=3,
strategy="mixed", # or progressive, pattern_based, etc.
count=20,
difficulty_range=(1, 10),
output_file="advanced_problems.json"
)
# Result includes:
# - metadata: generation info
# - complexity_theory: explanation of difficulty factors
# - scoring_system: how to score solutions
# - problems: array of generated problemsCLI:
python main.py generate-advanced 3 \
--count 20 \
--strategy mixed \
--min-difficulty 1 \
--max-difficulty 10 \
--output advanced_problems.jsonScore solution attempts with detailed breakdown:
from cubes_py import ScoringSystem
score = ScoringSystem.score_solution(
actual_moves=15,
optimal_moves=10,
reached_goal=True,
time_taken=2.5,
memory_used=80
)
print(f"Score: {score['total_score']}/100")
print(f"Grade: {score['grade']}")
print(f"Efficiency: {score['efficiency']}")Scoring System (100 points total):
- Correctness (40 pts): Reaching target state
- Efficiency (40 pts): Move count vs optimal (exponential decay)
- Time Bonus (10 pts): Speed (<1s=10pts, <5s=5pts, <10s=2pts)
- Memory Bonus (10 pts): Memory usage (<50MB=10pts, <100MB=5pts)
Examples:
- Optimal solution: 90-100 points (A+)
- 2Γ optimal moves: 67-77 points (C-B)
- 3Γ optimal moves: 54-64 points (D-C)
Each problem includes complexity metrics:
{
"complexity": {
"move_count": 10,
"unique_faces": 4,
"move_diversity": 0.8,
"randomness_factor": 0.5,
"estimated_difficulty": 7
}
}Difficulty Factors:
- Low (1-3): Few moves, solved start, familiar patterns
- Medium (4-7): More moves, some randomness, mixed patterns
- High (8-10): Many moves, random start, no patterns
Verify and score user solution attempts against problem sets.
python main.py verify --generate-examples
# Creates:
# examples/basic_results_example.json
# examples/advanced_results_example.json{
"cube_size": 3,
"data": {
"level_0": {
"problem_1": {
"solution": ["R"],
"time_taken": 0.5,
"memory_used": 45
}
}
}
}{
"cube_size": 3,
"solutions": [
{
"problem_id": 1,
"solution": ["R", "U", "R'", "U'"],
"time_taken": 2.5,
"memory_used": 80,
"algorithm_used": "BFS"
}
]
}# Basic verification
python main.py verify \
--problem-file problems/my3x3_3x3.json \
--results-file my_results.json
# With details
python main.py verify \
--problem-file problems/advanced.json \
--results-file my_results.json \
--show-details
# Save verification output
python main.py verify \
--problem-file problems/advanced.json \
--results-file my_results.json \
--output verification_report.jsonPython API:
from cubes_py import auto_verify_results
verification = auto_verify_results(
problem_file="problems/my3x3_3x3.json",
results_file="my_results.json",
output_file="verification.json"
)
print(f"Correct: {verification['correct']}/{verification['total_problems']}")
print(f"Average Score: {verification['average_score']}/100")
print(f"Grade Distribution: {verification['grade_distribution']}")Verification Output:
{
"total_problems": 10,
"correct": 7,
"incorrect": 3,
"average_score": 72.5,
"grade_distribution": {
"A+": 2,
"A": 3,
"B": 2,
"F": 3
},
"problems": [
{
"problem_id": 1,
"correct": true,
"user_moves": 10,
"optimal_moves": 10,
"score": {
"total_score": 90,
"grade": "A+",
"efficiency": 40,
"time_bonus": 10
}
}
]
}All cubes are automatically persisted to cube_storage/<cube_id>.json:
{
"cube_id": "my3x3",
"size": 3,
"created_at": "2025-01-15T10:30:00",
"state": { /* current cube state */ },
"transitions": [
{
"timestamp": "2025-01-15T10:31:00",
"from_state": { /* ... */ },
"move": "R",
"to_state": { /* ... */ }
}
]
}Create a file my_cube_script.py in your project:
#!/usr/bin/env python3
"""Example: Using cubes-py in your own scripts"""
from cubes_py import get_registry, generate_problems
import json
# Initialize the registry
registry = get_registry()
# Create a 3x3 cube - automatically saved to cube_storage/my_puzzle.json
print("Creating cube...")
cube = registry.create_cube("my_puzzle", size=3)
print(f"β Created {cube.size}Γ{cube.size}Γ{cube.size} cube")
# Get initial solved state
initial_state = registry.get_state("my_puzzle")
print(f"\nInitial U face: {initial_state['U'][0]}")
# Apply a scramble sequence
scramble = "R U R' U' L' B L B'"
print(f"\nApplying scramble: {scramble}")
registry.apply("my_puzzle", scramble)
# Check the scrambled state
scrambled = registry.get_state("my_puzzle")
print(f"Scrambled U face: {scrambled['U'][0]}")
# Apply more moves
print("\nApplying solution moves...")
registry.apply("my_puzzle", "B' L' B L U R U' R'")
# Final state
final = registry.get_state("my_puzzle")
print(f"Final U face: {final['U'][0]}")
# Everything is saved automatically in cube_storage/my_puzzle.json
# including all moves, timestamps, and state transitions!
print("\nβ All state saved to cube_storage/my_puzzle.json")
# You can also generate problem sets
print("\nGenerating problem set...")
problems = generate_problems(cube_size=3)
print(f"β Generated {len(problems)} difficulty levels")
# Save problems to your own location
with open("my_problems.json", "w") as f:
json.dump({"data": problems}, f, indent=2)
print("β Problems saved to my_problems.json")Run it:
python my_cube_script.pyWhat gets created in your directory:
your_project/
βββ my_cube_script.py # Your script
βββ cube_storage/ # Auto-created
β βββ my_puzzle.json # Your cube with full history
βββ my_problems.json # Generated problems
The saved cube_storage/my_puzzle.json contains:
{
"cube_id": "my_puzzle",
"size": 3,
"created_at": "2025-10-11T...",
"state": {
"U": [["W", "W", "O"], ...],
"D": [...],
"L": [...],
"R": [...],
"F": [...],
"B": [...]
},
"transitions": [
{
"timestamp": "2025-10-11T...",
"from_state": {...},
"move": "R",
"to_state": {...}
},
// ... every move tracked
]
}# Demonstrate move effects
from cubes_py import get_registry
registry = get_registry()
registry.create_cube("demo", 3)
print("Initial state:", registry.get_state("demo"))
registry.apply("demo", "R")
print("After R move:", registry.get_state("demo"))# Test solving algorithms
from cubes_py import RubiksCube, generate_move_sequence
cube = RubiksCube(n=3)
scramble = generate_move_sequence(num_moves=20, cube_size=3, complexity=7)
for move in scramble:
cube.execute_move(move)
# Now test your solving algorithm# Generate problems for AI/ML evaluation
from cubes_py import generate_problems
import json
for size in [2, 3, 4]:
problems = generate_problems(cube_size=size)
with open(f"benchmark_{size}x{size}.json", "w") as f:
json.dump({
"cube_size": size,
"total_levels": 6,
"problems_per_level": 10,
"data": problems
}, f, indent=2)cubes_py/
βββ cubes/ # Core engine
β βββ cube.py # Cube class and operations
β βββ state.py # State representation
β βββ moves.py # Move execution logic
β βββ parser.py # Move notation parser
β βββ storage.py # Persistence layer
β βββ registry.py # Cube registry/manager
β βββ errors.py # Custom exceptions
βββ gen_problem.py # Problem set generator
βββ main.py # CLI entry point
βββ __init__.py # Public API
from cubes_py import generate_move_sequence
# Generate random sequences with complexity control
moves = generate_move_sequence(
num_moves=10,
cube_size=3,
complexity=7 # 1-10, higher = more complex moves
)from cubes_py import get_registry, IllegalMoveError, CubeNotFoundError
registry = get_registry()
try:
registry.apply("nonexistent", "R U")
except CubeNotFoundError as e:
print(f"Cube not found: {e}")
try:
registry.apply("my3x3", "INVALID_MOVE")
except IllegalMoveError as e:
print(f"Invalid move: {e}")from cubes_py import RubiksCube
import copy
cube = RubiksCube(n=3)
# Save state
saved_state = cube.copy_state()
# Apply moves
cube.execute_move("R")
cube.execute_move("U")
# Compare states
current_state = cube.copy_state()
print(f"States differ: {saved_state != current_state}")| Command | Description | Example |
|---|---|---|
python main.py info |
Show library information | python main.py info |
python main.py version |
Show version number | python main.py version |
python main.py create <id> <size> |
Create a new cube | python main.py create my3x3 3 |
python main.py state <id> |
Get cube state | python main.py state my3x3 |
python main.py apply <id> <moves> |
Apply move sequence | python main.py apply my3x3 "R U R'" |
python main.py generate <id> <size> |
Generate basic problems | python main.py generate my3x3 3 |
python main.py generate-advanced <size> --output <file> |
Generate advanced problems | python main.py generate-advanced 3 -o advanced.json |
python main.py verify --problem-file <p> --results-file <r> |
Verify user results | python main.py verify --problem-file p.json --results-file r.json |
Quick Start - Run this first:
python my_cube_script.pyShows the complete workflow: create cube β apply moves β everything saved to JSON automatically.
Advanced Features Demo:
python advanced_demo.pyDemonstrates advanced problem generation:
- 4 generation strategies (progressive, pattern, difficulty-scaled, bidirectional)
- Solution scoring with grade breakdown
- Complexity analysis and theory
- Full problem set generation
Comprehensive Examples:
python example_usage.pyDemonstrates all basic features:
- Basic cube operations (create, apply moves, get state)
- Problem set generation
- Custom move sequences with different complexities
- Direct cube usage without persistence
- Proper error handling
Use the direct invocation from the cubes_py directory:
python main.py <command>Make sure you're in the right directory or install the package:
cd cubes_py
pip install -e .Verify imports work:
python -c "from cubes import get_registry; print('β Imports working')"Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE file for details
- Standard Rubik's Cube notation based on official WCA guidelines
- Inspired by various cube simulation projects in the community
my_cube_script.py- Quick start example (run this first!)advanced_demo.py- Advanced generation & scoring demoexample_usage.py- Comprehensive examples of all featuresadvanced_gen_problem.py- Advanced generator source codeINSTRUCTIONS.md- Detailed move notation and rulesstate_instructions.md- State representation formatproblems/- Directory containing sample problem sets
get_registry()- Get the global cube registry (singleton)generate_problems(cube_size)- Generate basic problem setgenerate_move_sequence(num_moves, cube_size, complexity)- Generate random move sequences
generate_problem_set(cube_size, strategy, count, difficulty_range, output_file)- Generate advanced problemsProblemGenerator(cube_size, seed)- Advanced generator with multiple strategies.generate_progressive(target_moves, randomness)- Progressive difficulty.generate_pattern_based(pattern_type, depth)- Pattern-based problems.generate_difficulty_scaled(difficulty_level)- Auto-scaled by difficulty.generate_bidirectional(target_depth)- Bidirectional search setup
ScoringSystem.score_solution(actual_moves, optimal_moves, reached_goal, time_taken, memory_used)- Score solutionsScoringSystem.get_scoring_explanation()- Get scoring details
auto_verify_results(problem_file, results_file, output_file)- Auto-detect format and verifyverify_basic_results(problem_file, results_file)- Verify basic format resultsverify_advanced_results(problem_file, results_file)- Verify advanced format resultsgenerate_example_result_files()- Generate example result templates
Cube- Internal cube representationCubeRegistry- Cube manager with persistenceRubiksCube- Standalone cube for in-memory operationsCubeState- State representationProblemGenerator- Advanced problem generatorScoringSystem- Solution scoring system
IllegalMoveError- Invalid move notation or execution errorCubeNotFoundError- Cube ID not found in registryInvalidCubeSizeError- Invalid cube size (must be >= 2)
Made with β€οΈ for the puzzle-solving community