Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

cubieval

A flexible Rubik's Cube engine and problem generator for NΓ—NΓ—N cubes

Python 3.12+ License: MIT

πŸ“¦ What is this?

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

πŸš€ Quick Start

Installation

# 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 .

Command Line Usage

Note: The CLI command is cubes for easy typing. Run commands from the cubes_py directory using python main.py <command>. After installing with pip, you can use cubes <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.json

Python API

Use 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)

πŸ“– Documentation

Cube Operations

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)

Create a Cube

from cubes_py import get_registry

registry = get_registry()
cube = registry.create_cube("my3x3", size=3)

CLI:

cubes create my3x3 3

Apply Moves

# 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'"

Get State

state = registry.get_state("my3x3")
# Returns a dict with face configurations:
# {"U": [[...]], "D": [[...]], "L": [[...]], "R": [[...]], "F": [[...]], "B": [[...]]}

CLI:

cubes state my3x3

Basic Problem Generation

Generate 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.json

Problem Set Structure

Each 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)
  }
}

Advanced Problem Generation

NEW! Enhanced problem generator with multiple strategies, complexity analysis, and scoring.

Generation Strategies

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_cube

3. Difficulty-Scaled - Auto-scaled by difficulty level

problem = generator.generate_difficulty_scaled(difficulty_level=7)
# Difficulty 1-10 auto-scales moves, randomness, complexity

4. Bidirectional - Setup for bidirectional search

problem = generator.generate_bidirectional(target_depth=5)

Complete Problem Sets

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 problems

CLI:

python main.py generate-advanced 3 \
  --count 20 \
  --strategy mixed \
  --min-difficulty 1 \
  --max-difficulty 10 \
  --output advanced_problems.json

Solution Scoring

Score 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)

Complexity Theory

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

Result Verification & Scoring

Verify and score user solution attempts against problem sets.

Generate Example Result Files

python main.py verify --generate-examples
# Creates:
#   examples/basic_results_example.json
#   examples/advanced_results_example.json

Basic Results Format

{
  "cube_size": 3,
  "data": {
    "level_0": {
      "problem_1": {
        "solution": ["R"],
        "time_taken": 0.5,
        "memory_used": 45
      }
    }
  }
}

Advanced Results Format

{
  "cube_size": 3,
  "solutions": [
    {
      "problem_id": 1,
      "solution": ["R", "U", "R'", "U'"],
      "time_taken": 2.5,
      "memory_used": 80,
      "algorithm_used": "BFS"
    }
  ]
}

Verify Results

# 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.json

Python 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
      }
    }
  ]
}

State Persistence

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": { /* ... */ }
    }
  ]
}

🎯 Complete Example - Using in Your Python Code

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.py

What 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
  ]
}

🎯 More Use Cases

Educational

# 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"))

Algorithm Testing

# 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

Benchmark Generation

# 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)

πŸ—οΈ Architecture

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

πŸ”§ Advanced Usage

Custom Move Sequences

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
)

Error Handling

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}")

Working with State Directly

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 Reference

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

πŸ§ͺ Examples

Quick Start - Run this first:

python my_cube_script.py

Shows the complete workflow: create cube β†’ apply moves β†’ everything saved to JSON automatically.

Advanced Features Demo:

python advanced_demo.py

Demonstrates 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.py

Demonstrates 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

πŸ”§ Troubleshooting

Command Not Found: cubes

Use the direct invocation from the cubes_py directory:

python main.py <command>

ModuleNotFoundError

Make sure you're in the right directory or install the package:

cd cubes_py
pip install -e .

Import Errors

Verify imports work:

python -c "from cubes import get_registry; print('βœ“ Imports working')"

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

πŸ“„ License

MIT License - see LICENSE file for details

πŸ™ Acknowledgments

  • Standard Rubik's Cube notation based on official WCA guidelines
  • Inspired by various cube simulation projects in the community

πŸ“š Additional Resources

  • my_cube_script.py - Quick start example (run this first!)
  • advanced_demo.py - Advanced generation & scoring demo
  • example_usage.py - Comprehensive examples of all features
  • advanced_gen_problem.py - Advanced generator source code
  • INSTRUCTIONS.md - Detailed move notation and rules
  • state_instructions.md - State representation format
  • problems/ - Directory containing sample problem sets

πŸ“¦ API Reference

Core Functions

  • get_registry() - Get the global cube registry (singleton)
  • generate_problems(cube_size) - Generate basic problem set
  • generate_move_sequence(num_moves, cube_size, complexity) - Generate random move sequences

Advanced Functions

  • generate_problem_set(cube_size, strategy, count, difficulty_range, output_file) - Generate advanced problems
  • ProblemGenerator(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 solutions
  • ScoringSystem.get_scoring_explanation() - Get scoring details

Verification Functions

  • auto_verify_results(problem_file, results_file, output_file) - Auto-detect format and verify
  • verify_basic_results(problem_file, results_file) - Verify basic format results
  • verify_advanced_results(problem_file, results_file) - Verify advanced format results
  • generate_example_result_files() - Generate example result templates

Classes

  • Cube - Internal cube representation
  • CubeRegistry - Cube manager with persistence
  • RubiksCube - Standalone cube for in-memory operations
  • CubeState - State representation
  • ProblemGenerator - Advanced problem generator
  • ScoringSystem - Solution scoring system

Exceptions

  • IllegalMoveError - Invalid move notation or execution error
  • CubeNotFoundError - Cube ID not found in registry
  • InvalidCubeSizeError - Invalid cube size (must be >= 2)

Made with ❀️ for the puzzle-solving community

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages