Saturday, November 19, 2016

Creating the move list and searchable database

I created the algorithm to generate the searchable list of positions with "known" solutions. It took a little bumbling around to get it right, but it wasn't conceptually too difficult. It's just thinking through how I would manually create the list step by step. When do I add a new item, how do I cycle to the next item in the list, and then how do I backtrack after I've exhausted the list.

But as I'm thinking about this, I'm somewhat worried that I'm going to need to rewrite the program a bit. I think some of the pieces have become too spread out and disorganized for me to go to the next step (the solving step). Also, while I have definitely liked the graphical representation as I've been double checking the various permutations corresponding to the moves, Pygame just takes so much time to load and running the program in IDLE instead of in a terminal just feels so much slower.

So I'm about to embark on a rewriting of the program. I've built all of the bits and pieces, but I need to pull it apart and reorganize it a bit so that I can call the things I want to call when I want to call them. I've got the ability to run long processes and then dump the results into a file (pickling), which means that I don't need to rerun those processes again and again.

So the way I see it, I need to create the following functions:
  • Reset the cube
  • Perform a sequence of moves to the cube
  • Compare the current state of the cube with one from a list, including the ability to ignore gray pieces
  • Find the "next" sequence to check given a maximum move depth and the current sequence.
It may take a while for me to get there, so here's the code in its current form:
import pygame
import pickle
import time

# Global Variables
sGap = 5
bGap = 10
boxSize = 30

def posCalc(bS, sG, bG):
    return bS*boxSize + sG*sGap + bG*bGap

# Define drawing data

sqPos = [ [ [posCalc(3,3,1), posCalc(0,1,0)],
            [posCalc(4,4,1), posCalc(0,1,0)],
            [posCalc(5,5,1), posCalc(0,1,0)],
            [posCalc(3,3,1), posCalc(1,2,0)],
            [posCalc(4,4,1), posCalc(1,2,0)],
            [posCalc(5,5,1), posCalc(1,2,0)],
            [posCalc(3,3,1), posCalc(2,3,0)],
            [posCalc(4,4,1), posCalc(2,3,0)],
            [posCalc(5,5,1), posCalc(2,3,0)] ],
          [ [posCalc(0,1,0), posCalc(3,3,1)],
            [posCalc(1,2,0), posCalc(3,3,1)],
            [posCalc(2,3,0), posCalc(3,3,1)],
            [posCalc(0,1,0), posCalc(4,4,1)],
            [posCalc(1,2,0), posCalc(4,4,1)],
            [posCalc(2,3,0), posCalc(4,4,1)],
            [posCalc(0,1,0), posCalc(5,5,1)],
            [posCalc(1,2,0), posCalc(5,5,1)],
            [posCalc(2,3,0), posCalc(5,5,1)] ],
          [ [posCalc(3,3,1), posCalc(3,3,1)],
            [posCalc(4,4,1), posCalc(3,3,1)],
            [posCalc(5,5,1), posCalc(3,3,1)],
            [posCalc(3,3,1), posCalc(4,4,1)],
            [posCalc(4,4,1), posCalc(4,4,1)],
            [posCalc(5,5,1), posCalc(4,4,1)],
            [posCalc(3,3,1), posCalc(5,5,1)],
            [posCalc(4,4,1), posCalc(5,5,1)],
            [posCalc(5,5,1), posCalc(5,5,1)] ],
          [ [posCalc(6,5,2), posCalc(3,3,1)],
            [posCalc(7,6,2), posCalc(3,3,1)],
            [posCalc(8,7,2), posCalc(3,3,1)],
            [posCalc(6,5,2), posCalc(4,4,1)],
            [posCalc(7,6,2), posCalc(4,4,1)],
            [posCalc(8,7,2), posCalc(4,4,1)],
            [posCalc(6,5,2), posCalc(5,5,1)],
            [posCalc(7,6,2), posCalc(5,5,1)],
            [posCalc(8,7,2), posCalc(5,5,1)] ],
          [ [posCalc(9,7,3), posCalc(3,3,1)],
            [posCalc(10,8,3), posCalc(3,3,1)],
            [posCalc(11,9,3), posCalc(3,3,1)],
            [posCalc(9,7,3), posCalc(4,4,1)],
            [posCalc(10,8,3), posCalc(4,4,1)],
            [posCalc(11,9,3), posCalc(4,4,1)],
            [posCalc(9,7,3), posCalc(5,5,1)],
            [posCalc(10,8,3), posCalc(5,5,1)],
            [posCalc(11,9,3), posCalc(5,5,1)] ],
          [ [posCalc(3,3,1), posCalc(6,5,2)],
            [posCalc(4,4,1), posCalc(6,5,2)],
            [posCalc(5,5,1), posCalc(6,5,2)],
            [posCalc(3,3,1), posCalc(7,6,2)],
            [posCalc(4,4,1), posCalc(7,6,2)],
            [posCalc(5,5,1), posCalc(7,6,2)],
            [posCalc(3,3,1), posCalc(8,7,2)],
            [posCalc(4,4,1), posCalc(8,7,2)],
            [posCalc(5,5,1), posCalc(8,7,2)] ]
        ]

sqColor = [ [ i for ii in range(9) ] for i in range(6) ]

drawColor = [ pygame.Color(0,0,255),
              pygame.Color(255,0,0),
              pygame.Color(255,255,0),
              pygame.Color(255,100,0),
              pygame.Color(255,255,255),
              pygame.Color(0,255,0),
              pygame.Color(100,100,100) ]

# Initialize
pygame.init()

window1Width = posCalc(12,10,3)
window1Height = posCalc(9,8,2)
window1 = pygame.display.set_mode((window1Width,window1Height))

# Functions

def menu():
    menuSelect = 0
    while menuSelect == 0:
        print('''
Main Menu:
(1) Free Play
(2) Set up Cube
(6) Generate Position Lookup
(7) Generate Solution Lookup Move List
(8) Reset Cube
(9) Quit
''')
        comm = input('Select Menu Option: ')
        if comm in ['1', '2', '6', '7', '8', '9']:
            menuSelect = 1
    return int(comm)

def drawIt1(window, sqPos, sqColor, drawColor):
    for i in range(6):
        for ii in range(9):
            pygame.draw.rect(window,
                             drawColor[sqColor[i][ii]],
                             ( sqPos[i][ii][0], sqPos[i][ii][1], boxSize, boxSize ),
                             0)
    pygame.display.update()
    return

def playCube(sqColor):
    commands = ["U", "U2", "U'",
                "L", "L2", "L'",
                "F", "F2", "F'",
                "R", "R2", "R'",
                "B", "B2", "B'",
                "D", "D2", "D'"]
    commList = "U, U2, U', L, L2, L', F, F2, F', R, R2, R', B, B2, B', D, D2, D'"
    comm = ""
    while comm != "Q":
        print("Execute which command?")
        print(commList)
        comm = input('Enter a squence of moves separated by spaces or Q to quit: ' )
        validComm = 1
        commSeq = comm.split()
        for move in commSeq:
            if move not in commList:
                validComm = 0
        if validComm == 1:
            for move in commSeq:
                sqColor = permute(move, sqColor)
        elif validComm == 0 and comm != "Q":
            print("Invalid move sequence.")
        drawIt1(window1, sqPos, sqColor, drawColor)
    return

def permute(comm, sqColor):
    if comm == "U":
        swap4(sqColor, [0,0], [0,2], [0,8], [0,6])
        swap4(sqColor, [0,1], [0,5], [0,7], [0,3])
        swap4(sqColor, [4,0], [3,0], [2,0], [1,0])
        swap4(sqColor, [4,1], [3,1], [2,1], [1,1])
        swap4(sqColor, [4,2], [3,2], [2,2], [1,2])
    elif comm == "U2":
        swap2(sqColor, [0,0], [0,8])
        swap2(sqColor, [0,2], [0,6])
        swap2(sqColor, [0,1], [0,7])
        swap2(sqColor, [0,3], [0,5])
        swap2(sqColor, [1,0], [3,0])
        swap2(sqColor, [1,1], [3,1])
        swap2(sqColor, [1,2], [3,2])
        swap2(sqColor, [2,0], [4,0])
        swap2(sqColor, [2,1], [4,1])
        swap2(sqColor, [2,2], [4,2])
    elif comm == "U'":
        swap4(sqColor, [0,0], [0,6], [0,8], [0,2])
        swap4(sqColor, [0,1], [0,3], [0,7], [0,5])
        swap4(sqColor, [1,0], [2,0], [3,0], [4,0])
        swap4(sqColor, [1,1], [2,1], [3,1], [4,1])
        swap4(sqColor, [1,2], [2,2], [3,2], [4,2])
    elif comm == "L":
        swap4(sqColor, [1,0], [1,2], [1,8], [1,6])
        swap4(sqColor, [1,1], [1,5], [1,7], [1,3])
        swap4(sqColor, [0,0], [2,0], [5,0], [4,8])
        swap4(sqColor, [0,3], [2,3], [5,3], [4,5])
        swap4(sqColor, [0,6], [2,6], [5,6], [4,2])
    elif comm == "L2":
        swap2(sqColor, [1,0], [1,8])
        swap2(sqColor, [1,2], [1,6])
        swap2(sqColor, [1,1], [1,7])
        swap2(sqColor, [1,3], [1,5])
        swap2(sqColor, [2,0], [4,8])
        swap2(sqColor, [2,3], [4,5])
        swap2(sqColor, [2,6], [4,2])
        swap2(sqColor, [0,0], [5,0])
        swap2(sqColor, [0,3], [5,3])
        swap2(sqColor, [0,6], [5,6])
    elif comm == "L'":
        swap4(sqColor, [1,0], [1,6], [1,8], [1,2])
        swap4(sqColor, [1,1], [1,3], [1,7], [1,5])
        swap4(sqColor, [5,0], [2,0], [0,0], [4,8])
        swap4(sqColor, [5,3], [2,3], [0,3], [4,5])
        swap4(sqColor, [5,6], [2,6], [0,6], [4,2])
    elif comm == "F":
        swap4(sqColor, [2,0], [2,2], [2,8], [2,6])
        swap4(sqColor, [2,1], [2,5], [2,7], [2,3])
        swap4(sqColor, [0,6], [3,0], [5,2], [1,8])
        swap4(sqColor, [0,7], [3,3], [5,1], [1,5])
        swap4(sqColor, [0,8], [3,6], [5,0], [1,2])
    elif comm == "F2":
        swap2(sqColor, [2,0], [2,8])
        swap2(sqColor, [2,2], [2,6])
        swap2(sqColor, [2,1], [2,7])
        swap2(sqColor, [2,3], [2,5])
        swap2(sqColor, [0,6], [5,2])
        swap2(sqColor, [0,7], [5,1])
        swap2(sqColor, [0,8], [5,0])
        swap2(sqColor, [1,8], [3,0])
        swap2(sqColor, [1,5], [3,3])
        swap2(sqColor, [1,2], [3,6])
    elif comm == "F'":
        swap4(sqColor, [2,0], [2,6], [2,8], [2,2])
        swap4(sqColor, [2,1], [2,3], [2,7], [2,5])
        swap4(sqColor, [0,6], [1,8], [5,2], [3,0])
        swap4(sqColor, [0,7], [1,5], [5,1], [3,3])
        swap4(sqColor, [0,8], [1,2], [5,0], [3,6])
    elif comm == "R":
        swap4(sqColor, [3,0], [3,2], [3,8], [3,6])
        swap4(sqColor, [3,1], [3,5], [3,7], [3,3])
        swap4(sqColor, [0,8], [4,0], [5,8], [2,8])
        swap4(sqColor, [0,5], [4,3], [5,5], [2,5])
        swap4(sqColor, [0,2], [4,6], [5,2], [2,2])
    elif comm == "R2":
        swap2(sqColor, [3,0], [3,8])
        swap2(sqColor, [3,2], [3,6])
        swap2(sqColor, [3,1], [3,7])
        swap2(sqColor, [3,3], [3,5])
        swap2(sqColor, [2,2], [4,6])
        swap2(sqColor, [2,5], [4,3])
        swap2(sqColor, [2,8], [4,0])
        swap2(sqColor, [0,8], [5,8])
        swap2(sqColor, [0,5], [5,5])
        swap2(sqColor, [0,2], [5,2])
    elif comm == "R'":
        swap4(sqColor, [3,0], [3,6], [3,8], [3,2])
        swap4(sqColor, [3,1], [3,3], [3,7], [3,5])
        swap4(sqColor, [0,8], [2,8], [5,8], [4,0])
        swap4(sqColor, [0,5], [2,5], [5,5], [4,3])
        swap4(sqColor, [0,2], [2,2], [5,2], [4,6])
    elif comm == "B":
        swap4(sqColor, [4,0], [4,2], [4,8], [4,6])
        swap4(sqColor, [4,1], [4,5], [4,7], [4,3])
        swap4(sqColor, [0,2], [1,0], [5,6], [3,8])
        swap4(sqColor, [0,1], [1,3], [5,7], [3,5])
        swap4(sqColor, [0,0], [1,6], [5,8], [3,2])
    elif comm == "B2":
        swap2(sqColor, [4,0], [4,8])
        swap2(sqColor, [4,2], [4,6])
        swap2(sqColor, [4,1], [4,7])
        swap2(sqColor, [4,3], [4,5])
        swap2(sqColor, [0,2], [5,6])
        swap2(sqColor, [0,1], [5,7])
        swap2(sqColor, [0,0], [5,8])
        swap2(sqColor, [1,0], [3,8])
        swap2(sqColor, [1,3], [3,5])
        swap2(sqColor, [1,6], [3,2])
    elif comm == "B'":
        swap4(sqColor, [4,0], [4,6], [4,8], [4,2])
        swap4(sqColor, [4,1], [4,3], [4,7], [4,5])
        swap4(sqColor, [0,2], [3,8], [5,6], [1,0])
        swap4(sqColor, [0,1], [3,5], [5,7], [1,3])
        swap4(sqColor, [0,0], [3,2], [5,8], [1,6])
    elif comm == "D":
        swap4(sqColor, [5,0], [5,2], [5,8], [5,6])
        swap4(sqColor, [5,1], [5,5], [5,7], [5,3])
        swap4(sqColor, [1,6], [2,6], [3,6], [4,6])
        swap4(sqColor, [1,7], [2,7], [3,7], [4,7])
        swap4(sqColor, [1,8], [2,8], [3,8], [4,8])
    elif comm == "D2":
        swap2(sqColor, [5,0], [5,8])
        swap2(sqColor, [5,2], [5,6])
        swap2(sqColor, [5,1], [5,7])
        swap2(sqColor, [5,3], [5,5])
        swap2(sqColor, [1,6], [3,6])
        swap2(sqColor, [1,7], [3,7])
        swap2(sqColor, [1,8], [3,8])
        swap2(sqColor, [2,6], [4,6])
        swap2(sqColor, [2,7], [4,7])
        swap2(sqColor, [2,8], [4,8])
    elif comm == "D'":
        swap4(sqColor, [5,0], [5,6], [5,8], [5,2])
        swap4(sqColor, [5,1], [5,3], [5,7], [5,5])
        swap4(sqColor, [1,6], [4,6], [3,6], [2,6])
        swap4(sqColor, [1,7], [4,7], [3,7], [2,7])
        swap4(sqColor, [1,8], [4,8], [3,8], [2,8])

    return sqColor

def swap4(sqColor, p0, p1, p2, p3):
    temp = sqColor[p0[0]][p0[1]]
    sqColor[p0[0]][p0[1]] = sqColor[p3[0]][p3[1]]
    sqColor[p3[0]][p3[1]] = sqColor[p2[0]][p2[1]]
    sqColor[p2[0]][p2[1]] = sqColor[p1[0]][p1[1]]
    sqColor[p1[0]][p1[1]] = temp
    return sqColor

def swap2(sqColor, p0, p1):
    temp = sqColor[p0[0]][p0[1]]
    sqColor[p0[0]][p0[1]] = sqColor[p1[0]][p1[1]]
    sqColor[p1[0]][p1[1]] = temp
    return sqColor

def setCube(sqColor):
    done = 0
    print('''
 Faces             Positions
  0                  0 1 2
1 2 3 4              3 4 5
  5                  6 7 8

0 = Blue, 1 = Red, 2 = Yellow, 3 = Orange, 4 = White, 5 = Green, 6 = Gray

Use Face = -1 to quit
''')
    face = input('Enter a face to change: ')
    if face in ['0', '1', '2', '3', '4', '5']:
        pos = input('Enter a position to chance: ')
        if pos in ['0', '1', '2', '3', '4', '5', '6', '7', '8']:
            color = input('Enter the color: ')
            if color in ['0', '1', '2', '3', '4', '5', '6']:
                face = int(face)
                pos = int(pos)
                color = int(color)
                sqColor[face][pos] = color
    elif face == '-1':
        done = 1
    return done, sqColor

def buildLib():
    xAxis = [["F"], ["F2"], ["F'"], ["B"], ["B2"], ["B'"],
             ["F", "B"], ["F", "B2"], ["F", "B'"],
             ["F2", "B"], ["F2", "B2"], ["F2", "B'"],                           
             ["F'", "B"], ["F'", "B2"], ["F'", "B'"] ]
    yAxis = [["L"], ["L2"], ["L'"], ["R"], ["R2"], ["R'"],
             ["L", "R"], ["L", "R2"], ["L", "R'"],
             ["L2", "R"], ["L2", "R2"], ["L2", "R'"],                           
             ["L'", "R"], ["L'", "R2"], ["L'", "R'"] ]
    zAxis = [["U"], ["U2"], ["U'"], ["D"], ["D2"], ["D'"],
             ["U", "D"], ["U", "D2"], ["U", "D'"],
             ["U2", "D"], ["U2", "D2"], ["U2", "D'"],                           
             ["U'", "D"], ["U'", "D2"], ["U'", "D'"] ]

    maxDepth = 3

    moveList = [ [move] for move in xAxis+yAxis+zAxis]

    for firstMove in xAxis+yAxis+zAxis:
        thisComm = [ firstMove ]
        done = 0
        goBack = 0
        while done == 0:
            if len( moveList ) % 1000 == 0:
                print(len(moveList))
            if len( thisComm ) < maxDepth and goBack == 0:
                if thisComm[-1] in xAxis:
                    thisComm.append( yAxis[0] )
                else:
                    thisComm.append( xAxis[0] )
            else:
                goBack = 0
                lastMove = thisComm[-1]
                if lastMove in xAxis:
                    if xAxis.index( lastMove ) < len( xAxis ) - 1:
                        thisComm[-1] = xAxis[ xAxis.index( lastMove ) + 1]
                    else:
                        if thisComm[-2] in yAxis:
                            thisComm[-1] = zAxis[0]
                        else:
                            thisComm[-1] = yAxis[0]
                elif lastMove in yAxis:
                    if yAxis.index( lastMove ) < len( yAxis ) - 1:
                        thisComm[-1] = yAxis[ yAxis.index( lastMove ) + 1]
                    else:
                        if thisComm[-1] in xAxis:
                            thisComm[-1] = zAxis[0]
                        else:
                            if thisComm[-2] in xAxis:
                                thisComm[-1] = zAxis[0]
                            else:
                                thisComm = thisComm[:-1]
                                goBack = 1
                elif lastMove in zAxis:
                    if zAxis.index( lastMove ) < len( xAxis) - 1:
                        thisComm[-1] = zAxis[ zAxis.index( lastMove ) + 1]
                    else:
                        thisComm = thisComm[:-1]
                        goBack = 1
            if len( thisComm ) == 1:
                done = 1
            if goBack == 0 and done == 0:
                moveList.append( thisComm[:] )
    flatList = []
    for move in moveList:
        flatList.append( [ item for sublist in move for item in sublist ] )
    pickle_out = open("flatList.pickle", 'wb')
    pickle.dump(flatList, pickle_out)
    pickle_out.close()
    return

def buildPosLib():
    pickle_in = open("flatList.pickle",'rb')
    flatList = pickle.load(pickle_in)
    pickle_in.close()

    posList = [ [ [ i for ii in range(9) ] for i in range(6) ] ]
    solList = [ [] ]

    for moveSeq in flatList:
        if len(solList) % 1000 == 0:
            print(len(solList))
        sqColor = [ [ i for ii in range(9) ] for i in range(6) ]
        for move in moveSeq:
            sqColor = permute(move, sqColor)
        posList.append( [ sqColor ] )
        solList.append( invertMoves( moveSeq ) )

    pickle_out = open("posList.pickle",'wb')
    pickle.dump(posList, pickle_out)
    pickle_out.close()
    pickle_out = open("solList.pickle",'wb')
    pickle.dump(solList, pickle_out)
    pickle_out.close()


def invertMoves( seq ):
    inverted = []
    for i in range(len(seq)):
        j = i+1
        if seq[-j] == "F":
            inverted.append("F'")
        elif seq[-j] == "F'":
            inverted.append("F")
        elif seq[-j] == "B":
            inverted.append("B'")
        elif seq[-j] == "B'":
            inverted.append("B")
        elif seq[-j] == "R":
            inverted.append("R'")
        elif seq[-j] == "R'":
            inverted.append("R")
        elif seq[-j] == "L":
            inverted.append("L'")
        elif seq[-j] == "L'":
            inverted.append("L")
        elif seq[-j] == "U":
            inverted.append("U'")
        elif seq[-j] == "U'":
            inverted.append("U")
        elif seq[-j] == "D":
            inverted.append("D'")
        elif seq[-j] == "D'":
            inverted.append("D")
        else:
            inverted.append( seq[-j] )
    return inverted


### Main program

comm = 0
while comm != 9:
    comm = menu()
    if comm == 1:
        drawIt1(window1, sqPos, sqColor, drawColor)
        playCube(sqColor)
    elif comm == 2:
        finished = 0
        while finished == 0:
            drawIt1(window1, sqPos, sqColor, drawColor)
            finished, sqColor = setCube(sqColor)
        drawIt1(window1, sqPos, sqColor, drawColor)
    elif comm == 6:
        buildPosLib()
    elif comm == 7:
        buildLib()
    elif comm == 8:
        sqColor = [ [ i for ii in range(9) ] for i in range(6) ]
    elif comm == 9:
        quit()

No comments:

Post a Comment