BFS for Rubik's Cube terminating early?

40 views Asked by At

I am trying to complete a breadth first search to find the number of moves it takes to get to a permutation of a (masked) Rubik's cube, and then output this to a dictionary.

For testing, I have given it a cube where all facelets (face segments) have the same 'color' except one (this is the masked cube) - therefore it should return a dictionary with all possible locations of this one unique facelet, and how many moves it takes to get there. However, for some reason, it only manages to find 4 permutations - one for each 90 degree rotation of the face the facelet is on. I have tested the rotations of the other faces, and they work.

I thought this might have something to do with python not making deep copies of the cube/newCube variables - I have tried to work around this to no avail.

from cube import *
from solutionTools import *
from queue import Queue
import json

class Masker:
    def __init__(self):
        pass

    def mask(self, cube: Cube, mask: list, maskTo: list, defaultMask: str="X") -> Cube:
        ifCube = ifCubeGen(cube).constructIFCube().getState()
        outCube = Cube().getState()
        for i in range(6):
            for j in range(3):
                for k in range(3):
                    if ifCube[i][j][k] in mask:
                        outCube[i][j][k] = maskTo[mask.index(ifCube[i][j][k])]
                    else:
                        outCube[i][j][k] = defaultMask
        
        return Cube(state=outCube)
    
class GeneratePruningTable:
    def __init__(self):
        pass

    def BFS(self, start: Cube) -> dict:
        queue: Queue[Cube] = Queue()
        depth = 0
        table = {}
        queue.put(start)
        while queue.qsize() > 0:
            layer_size = queue.qsize()
            while layer_size > 0:
                cube = queue.get()
                key = cube.generateKey()
                if key not in table:
                    table[key] = depth
                    for i in range(6):
                        for j in range(2):
                            newCube = Cube(state=cube.getState().copy())
                            if j == 0:
                                dir = 1
                            else:
                                dir = -1
                            newCube.rotateFace(i, dir)
                            queue.put(Cube(state=newCube.getState().copy()))
                layer_size -= 1
            print(f"Depth {depth} complete")
            depth += 1
        return table
    
    def writeTableToFile(self, table: dict, directory: str):
        with open(directory, "w") as f:
            json.dump(table, f)

cube = Cube()

mask = ["U0"]
maskTo = ["U"]

m = Masker()
masked = m.mask(cube, mask, maskTo)
#masked.rotateFace(4, 1)

#print(masked.generateKey())

gen = GeneratePruningTable()

table = gen.BFS(masked)
gen.writeTableToFile(table, r"testDB.json")

Output (in testDB.json): - This shows that the 'U' facelet is staying within the U face.

{"UXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX": 0, "XXXXXUXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX": 1, "XXUXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX": 1, "XXXXXXXUXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX": 2}
1

There are 1 answers

0
Iby Morris On

SOLUTION FOUND

My suspicion was correct but I stupidly thought I was deep copying by using list.copy().

Instead, import copy and use copy.deepcopy(list).

This now works.