Example #1
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    left_checked = {}
    right_checked = {}
    left_current = {start: []}
    right_current = {end: []}
    left_new = {}
    right_new = {}
    left_depth = 0
    right_depth = 0

    while left_depth < 8:
        for x in left_current.keys():
            y = right_current.get(x, None)
            if y is not None:
                ans = left_current[x] + [
                    rubik.perm_inverse(move) for move in reversed(y)
                ]
                return ans
        for x in left_current.keys():
            for move in rubik.quarter_twists:
                r = rubik.perm_apply(move, x)
                if not left_checked.get(r, None) and not left_current.get(
                        r, None):
                    left_new[r] = left_current[x] + [move]
            left_checked[x] = left_current[x]
        left_current = left_new
        left_new = {}
        left_depth += 1

    while right_depth < 8:
        for x in right_current.keys():
            y = left_current.get(x, None)
            if y is not None:
                ans = y + [
                    rubik.perm_inverse(move)
                    for move in reversed(right_current[x])
                ]
                return ans
        for x in right_current.keys():
            for move in rubik.quarter_twists:
                r = rubik.perm_apply(move, x)
                if not right_checked.get(r, None) and not right_current.get(
                        r, None):
                    right_new[r] = right_current[x] + [move]
            right_checked[x] = right_current[x]
        right_current = right_new
        right_new = {}
        right_depth += 1

    return None
Example #2
0
def calculate_path(start_parent, end_parent, position):
    """
    Assumes start_parent and end_parent are as specified in shortest_path.
    Assumes position is in both start_parent and end_parent.
    Returns a list of moves to get from start to end.
    """
    start_half = []
    current_position = position
    while (start_parent[current_position] is not None):
        pair = start_parent[current_position]
        parent_position = pair[0]
        move = pair[1]
        current_position = parent_position
        # move inserted at beginning, because we are walking back to start.
        start_half.insert(0, move)

    end_half = []
    current_position = position
    while (end_parent[current_position] is not None):
        pair = end_parent[current_position]
        parent_position = pair[0]
        move = pair[1]
        # Inverse is taken, because move wass originally away from end.
        inverse_move = rubik.perm_inverse(move)
        current_position = parent_position
        end_half.append(inverse_move)

    return start_half + end_half
Example #3
0
def calculate_path(start_parent, end_parent, position):
    """
    Assumes start_parent and end_parent are as specified in shortest_path.
    Assumes position is in both start_parent and end_parent.
    Returns a list of moves to get from start to end.
    """
    start_half = []
    current_position = position
    while(start_parent[current_position] is not None):
        pair = start_parent[current_position]
        parent_position = pair[0]
        move = pair[1]
        current_position = parent_position
        # move inserted at beginning, because we are walking back to start.
        start_half.insert(0, move)

    end_half = []
    current_position = position
    while(end_parent[current_position] is not None):
        pair = end_parent[current_position]
        parent_position = pair[0]
        move = pair[1]
        # Inverse is taken, because move wass originally away from end.
        inverse_move = rubik.perm_inverse(move)
        current_position = parent_position
        end_half.append(inverse_move)
    
    return start_half + end_half
Example #4
0
def shortest_path(start, end):
    if start == end: return []
    fparents = {start: None}
    bparents = {end: None}
    fmoves = {}
    bmoves = {}
    for move in rubik.quarter_twists:
        fmoves[move] = move
        bmoves[rubik.perm_inverse(move)] = move
    forward = (fmoves, fparents, bparents)
    backward = (bmoves, bparents, fparents)
    queue = deque([(start, forward), (end, backward), None])

    for i in xrange(7):
        while True:
            vertex = queue.popleft()
            if vertex is None:
                queue.append(None)
                break
            position = vertex[0]
            moves, parents, other_parents = vertex[1]
            for move in moves:
                nextp = rubik.perm_apply(move, position)
                if nextp not in parents:
                    parents[nextp] = (moves[move], position)
                    queue.append((nextp, vertex[1]))
                    if nextp in other_parents:
                        forwardp = path(nextp, fparents)
                        backwardp = path(nextp, bparents)
                        forwardp.reverse()
                        return forwardp + backwardp
    return None
Example #5
0
def shortest_path_optmized(start, end):
    """
    For Question 2, using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    movesStart = dict()
    movesStart[start] = []
    movesEnd = dict()
    movesEnd[end] = []
    qStart = collections.deque()
    qEnd = collections.deque()
    qStart.append(start)
    qEnd.append(end)
    found = False
    finalMoves = []

    while (len(qStart) != 0 and len(qEnd) != 0 and not found):
        s = qStart.popleft()
        e = qEnd.popleft()
        m = movesStart[s]
        n = movesEnd[e]
        if len(m) > 8 and len(n) > 8:
            break
        if s == end:
            finalMoves = m
            found = True
            break
        if s in movesEnd:
            finalMoves = m + movesEnd[s][::-1]
            found = True
            break
        if e in movesStart:
            finalMoves = movesStart[e] + n[::-1]
            found = True
            break

        for i in range(6):
            x = rubik.perm_apply(rubik.quarter_twists[i], s)
            y = rubik.perm_apply(rubik.quarter_twists[i], e)
            if x not in movesStart:
                qStart.append(x)
                movesStart[x] = m + [
                    rubik.quarter_twists_names[rubik.quarter_twists[i]]
                ]
            if y not in movesEnd:
                qEnd.append(y)
                movesEnd[y] = n + [
                    rubik.quarter_twists_names[rubik.perm_inverse(
                        rubik.quarter_twists[i])]
                ]
    if found:
        sys.stdout.write(str(finalMoves) + "\n")
        return finalMoves
    else:
        sys.stdout.write(str("No solution\n"))
        return [None]
 def adj(u, dir):
     adj_u = []
     for move in rubik.quarter_twists:
         if(dir):
             adj_u.append(rubik.perm_apply(move, u))
         else:
             adj_u.append(rubik.perm_apply(rubik.perm_inverse(move), u))
     return adj_u
Example #7
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    if not (legal(start) or legal(end)):
        return None
    
    if start==end:
        return[]
    f_visited={}
    b_visited={}
    f_visited[start] = {'parent':None, 'move':None}
    b_visited[end] = {'parent':None, 'move':None}
    forward_frontier=[start]
    backward_frontier=[end]
    count=0
    ans=None
    
    while count<8:
        
        f_next=[]
        b_next=[]
        
        BFS(forward_frontier, f_visited, f_next)
        BFS(backward_frontier, b_visited, b_next)
        
        for seq in f_next:
            if not b_visited.get(seq, False):
                continue
            else:
                ans=seq
                break
        forward_frontier=f_next
        backward_frontier=b_next
        count+=1
        if ans!=None:
            break
    
    if ans==None:
        return ans
    
    answer=[]
    value=f_visited[ans]
    while value['move']:
        answer.append(value['move'])
        value=f_visited[value['parent']]
    answer=answer[::-1]
    
    value = b_visited[ans]
    while value['move']:
        answer.append(rubik.perm_inverse(value['move']))
        value=b_visited[value['parent']]
    
    return answer
def find_move(u, v, dir):
    for move in rubik.quarter_twists:
        if(dir):
            if v == rubik.perm_apply(move, u):
                return move
        else:
            if v == rubik.perm_apply(rubik.perm_inverse(move), u):
                return move
    return -1
Example #9
0
def build_path(parents, start_config, current_config, path, backward):
    """
    Shamelessly stolen from CLRS (where it's called PRINT_PATH).
    """
    if current_config == start_config:
        # Bottom of the recursion. We've reached our goal config, so we don't need
        # to record it - we'll get the permutation required to GET to our goal config
        # when we step back up the call stack.
        pass
    else:
        next_config = rubik.perm_apply(
            rubik.perm_inverse(parents[current_config]), current_config)
        build_path(parents, start_config, next_config, path, backward)

        if backward:
            # We don't add the configuration to the path, we add the PERMUTATION
            # required to GET to the next configuration.
            path.append(rubik.perm_inverse(parents[current_config]))
        else:
            path.append(parents[current_config])
Example #10
0
def get_moves(parentS, parentE, position):
    start_moves = []
    current_position = position
    while parentS[current_position] is not None:
        (current_position, move) = parentS[current_position]
        start_moves.insert(0, move)

    end_moves = []
    current_position = position
    while parentE[current_position] is not None:
        (current_position, move) = parentE[current_position]
        end_moves.append(rubik.perm_inverse(move))
    
    return start_moves + end_moves
Example #11
0
def two_way_bfs(start, end):
    if start == end:
        return []

    # initialize moves for backward bfs'
    forward_moves = dict()
    backward_moves = dict()
    for move in rubik.quarter_twists:
        forward_moves[move] = move
        backward_moves[rubik.perm_inverse(move)] = move

    # item format
    # next_position: (twist, position)
    forward_parents = {start: None}
    backward_parents = {end: None}

    # set indicators for forward and backward
    # (moves, parents, other parents)
    forward = (forward_moves, forward_parents, backward_parents)
    backward = (backward_moves, backward_parents, forward_parents)
    
    # every depth level ends with None as indicator
    queue = deque([(start, forward), (end, backward), None])

    for i in range(7):
        while True:
            vertex = queue.popleft()
            if vertex is None:
                # next depth level
                queue.append(None)
                break

            position = vertex[0]
            moves, parents, other_parents = vertex[1]

            for move in moves:
                next_position = rubik.perm_apply(move, position)

                if next_position in parents:
                    # do not bother with cycles
                    continue

                parents[next_position] = (moves[move], position)
                queue.append((next_position, vertex[1]))

                if next_position in other_parents:
                    forward_path = path(next_position, forward_parents)
                    backward_path = path(next_position, backward_parents)
                    return forward_path + backward_path[::-1]
Example #12
0
def shortest_path_optmized(start, end):
    q1 = deque()
    q2 = deque()
    visited1 = {}
    visited2 = {}
    path1 = {}
    path2 = {}

    visited1[start] = 1
    visited2[end] = 1
    path1[start] = []
    path2[end] = []
    q1.append(start)
    q2.append(end)
    while (q1 and q2):
        curr1 = q1[0]
        curr2 = q2[0]
        q1.popleft()
        q2.popleft()
        for i in rubik.quarter_twists:
            p1 = rubik.perm_apply(curr1, i)
            if (visited1.has_key(p1) == False):
                visited1[p1] = 1
                path1[p1] = path1[curr1] + [rubik.quarter_twists_names[i]]
                #print(rubik.quarter_twists_names[i])
                q1.append(p1)
                if (visited2.has_key(p1) == True):
                    return path1[p1] + path2[p1]
        for i in rubik.quarter_twists:
            p2 = rubik.perm_apply(curr2, i)
            if (visited2.has_key(p2) == False):
                visited2[p2] = 1
                path2[p2] = [
                    rubik.quarter_twists_names[rubik.perm_inverse(i)]
                ] + path2[curr2]
                #print(rubik.quarter_twists_names[i])
                q2.append(p2)
                if (visited1.has_key(p2) == True):
                    return path1[p2] + path2[p2]

    return []
    """
    For Question 2, using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    raise NotImplementedError
Example #13
0
def construct_path_two_ends(start_end, parent_from_start, end_end,
                            parent_from_end):
    position = start_end
    result = []
    while parent_from_start[position] is not None:
        result.append(position[1])
        position = parent_from_start[position]
    result.reverse()

    position = end_end
    while parent_from_end[position] is not None:
        result.append(rubik.perm_inverse(position[1]))
        position = parent_from_end[position]

    return result
Example #14
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    level = {start:0}
    backLevel = {end:0}
    parent = {start:None}
    backParent = {end:None}
    i = 1
    frontier = [start]
    solution = []
    backFrontier = [end]
    connected = False
    connections = []
    while (not connected) and (i <= 7):              # explore graph
        next = []
        for u in frontier:                           # move forwards
            for move in rubik.quarter_twists:
                v = rubik.perm_apply(move,u)
                if v not in level:
                    level[v] = i
                    parent[v] = (u,move)
                    next.append(v)
        frontier = next
        backNext = []
        for u in backFrontier:                      # move backwards
            for move in rubik.quarter_twists:
                v = rubik.perm_apply(move,u)
                if v not in backLevel:
                    backLevel[v] = i
                    backParent[v] = (u,rubik.perm_inverse(move))
                    backNext.append(v)
        backFrontier = backNext
        for config in level.keys():                 # check for a solution
            if config in backLevel:
                connected = True
                connections.append(config)
        i += 1
    if not connected:  # we have explored all options and found no solution
        return None
    minConn = findShortestPath(connections,level,backLevel)
    buildSolution(level,parent,minConn,solution,'forwards')
    buildSolution(backLevel,backParent,minConn,solution,'backwards')
    return solution
def bidirectional_bfs_search(
        start,
        end=rubik.I,
        next_fun=lambda x: [(rubik.perm_apply(t, x), t)
                            for t in rubik.quarter_twists],
        rev_edge=lambda e: rubik.perm_inverse(e),
):
    """ next_fun should return a list of tuples [(neighbour, edge)].
        rev_edge should return the reverse of an edge (so we can reverse when joining final path)
        """
    # Setup
    print(f"Start: {start}")
    if start == end:
        return []
    move_before = {start: None}  # Gets the last move before given state.
    move_before_reverse = {
        end: None
    }  # Same but for the opposite end of the search.
    # When we do the search, this lets us know which dictionary to use. (reverse or not.)
    forward, backward = (
        (start, move_before, move_before_reverse),
        (end, move_before_reverse, move_before),
    )

    # Search
    q = deque([forward, backward, None])  # None helps keep track of level
    for i in range(GODS_NUMBER // 2):
        while True:
            node = q.popleft()
            if node is None:
                q.append(None)
                break
            cur_state, cur_moves, other_moves = node[0], node[1], node[2]
            for next_state, edge in next_fun(cur_state):
                if next_state in cur_moves:
                    continue  # We already recorded this state.
                cur_moves[next_state] = edge
                q.append((next_state, cur_moves, other_moves))
                # next_state is the common 'middle' node, and we have to join 2 paths to find it.
                if next_state in other_moves:
                    first_path = _path(start, next_state, move_before,
                                       rev_edge)
                    second_path = _path(end, next_state, move_before_reverse,
                                        rev_edge)
                    second_path.reverse()
                    return first_path + [rev_edge(e) for e in second_path]
    raise ValueError("Invalid starting point")
Example #16
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    
    """
    processed_f = set()
    processed_b = set()
    parent_f = {start: None}
    parent_b = {end: None}
    frontier_f = [start]
    frontier_b = [end]
    isforward = True
    for i in range(16):
        frontier = frontier_f if isforward else frontier_b
        parent = parent_f if isforward else parent_b
        processed = processed_f if isforward else processed_b
        next_ = []
        for u in frontier:
            process(u, parent, next_)
            processed.add(u)
            break_ = (u in processed_b) if isforward else (u in processed_f)
            if break_:
                x = u
                break
        if break_: break
        if isforward: frontier_f = next_
        else: frontier_b = next_
        isforward = not isforward
    else:
        return None
    path = []
    u = x
    while u != start:
        path.insert(0, parent_f[u][0])
        u = parent_f[u][1]
    u = x
    while u != end:
        path.append(rubik.perm_inverse(parent_b[u][0]))
        u = parent_b[u][1]
    return path
def bfs(s, e):
    front_parents = {s: None}
    back_parents = {e: None} 
    # front_moves = rubik.quarter_twists
    #back_moves = (rubik.perm_inverse(move) for move in rubik.quarter_twists)
    front_moves={}
    back_moves = {}
    for move in rubik.quarter_twists:
        front_moves[move] = move
        back_moves[rubik.perm_inverse(move)] = move
    front = (front_moves, front_parents, back_parents)
    back = (back_moves, back_parents, front_parents)
    queue = deque([(s, front), (e, back), None])

    for i in range(7):
        while True:
            node = queue.popleft()
            if node is None: # One Level of BFS complete
                queue.append(None)
                break
            current_node = node[0]
            moves, parents, other_parents = node[1]
            for move in moves:
                next_node = rubik.perm_apply(move, current_node)
                if next_node in parents: continue
                parents[next_node] = (moves[move], current_node)
                queue.append((next_node, node[1]))
                if next_node in other_parents:
                    return (front_parents, back_parents, next_node)


    return None









    """
Example #18
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    if start == end:
        return []

    forward_parents = {start: None}
    backward_parents = {end: None}
    forward_moves = {}
    backward_moves = {}
    for move in rubik.quarter_twists:
        forward_moves[move] = move
        backward_moves[rubik.perm_inverse(move)] = move
    forward = (forward_moves, forward_parents, backward_parents)
    backward = (backward_moves, backward_parents, forward_parents)
    queue = deque([(start, forward), (end, backward), None])

    for i in range(7):
        while True:
            vertex = queue.popleft()
            if vertex is None:
                queue.append(None)
                break
            position = vertex[0]
            moves, parents, other_parents = vertex[1]
            for move in moves:
                next_position = rubik.perm_apply(move, position)
                if next_position in parents: continue
                parents[next_position] = (moves[move], position)
                queue.append((next_position, vertex[1]))
                if next_position in other_parents:
                    forward_path = path(next_position, forward_parents)
                    backward_path = path(next_position, backward_parents)
                    backward_path.reverse()
                    return forward_path + backward_path

    return None
Example #19
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    if start == end:
        return []  
    forward = ([start], {start : []})  
    backward = ([end], {end : []})
    for iter in range(7):
        (forward_states, forward_moves) = forward
        (backward_states, backward_moves) = backward

        next_forward_states = []
        for state in forward_states:
            moves = forward_moves[state]
            for twist in rubik.quarter_twists:
                next_state = rubik.perm_apply(twist, state)  
                if next_state in backward_moves:
                    return moves + [twist] + backward_moves[next_state]
                if not next_state in forward_moves:
                    next_forward_states.append(next_state) 
                    forward_moves[next_state] = moves + [twist]

        next_backward_states = []
        for state in backward_states:
            moves = backward_moves[state]
            for twist in rubik.quarter_twists:
                next_state = rubik.perm_apply(rubik.perm_inverse(twist), state)  
                if next_state in forward_moves:
                    return forward_moves[next_state] + [twist] + moves 
                if not next_state in backward_moves:
                    next_backward_states.append(next_state) 
                    backward_moves[next_state] = [twist] + moves

        forward = (next_forward_states, forward_moves)
        backward = (next_backward_states, backward_moves)

    return None
Example #20
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    if start == end:
        return []
    forward = ([start], {start: []})
    backward = ([end], {end: []})
    for iter in range(7):
        (forward_states, forward_moves) = forward
        (backward_states, backward_moves) = backward

        next_forward_states = []
        for state in forward_states:
            moves = forward_moves[state]
            for twist in rubik.quarter_twists:
                next_state = rubik.perm_apply(twist, state)
                if next_state in backward_moves:
                    return moves + [twist] + backward_moves[next_state]
                if not next_state in forward_moves:
                    next_forward_states.append(next_state)
                    forward_moves[next_state] = moves + [twist]

        next_backward_states = []
        for state in backward_states:
            moves = backward_moves[state]
            for twist in rubik.quarter_twists:
                next_state = rubik.perm_apply(rubik.perm_inverse(twist), state)
                if next_state in forward_moves:
                    return forward_moves[next_state] + [twist] + moves
                if not next_state in backward_moves:
                    next_backward_states.append(next_state)
                    backward_moves[next_state] = [twist] + moves

        forward = (next_forward_states, forward_moves)
        backward = (next_backward_states, backward_moves)

    return None
Example #21
0
def construct_path(overlap, Ldict, Rdict):

    Lpath = []
    Rpath = []
    Lcurr = overlap
    Rcurr = overlap
    # starting with overlap, prepend moves to the left list until the start is found
    while True:
        if Ldict[Lcurr][0] == 's':
            break
        Lpath.insert(0, Ldict[Lcurr][0])
        Lcurr = Ldict[Lcurr][1]
    # starting with overlap, append inverse moves to the right list until the end is found
    while True:
        if Rdict[Rcurr][0] == 'e':
            break
        Rpath.append(rubik.perm_inverse(Rdict[Rcurr][0]))
        Rcurr = Rdict[Rcurr][1]
    # return right list appended to left list for the complete moveset
    return Lpath + Rpath
Example #22
0
def solution(startParents, endParents, state):
	moves = []    # Array to store sequence of moves
	
	currentState = state    # Intermediate state of rubiks cube
	# Working way back up to start state
	while startParents[currentState] is not None:
		parent = startParents[currentState]    # Parent state + move to current state
		currentState = parent[0]               # Move one level towards initial state
		move = parent[1]                       
		moves.insert(0, move)                  # Store moves in FILO (Start -> Intermediate)
	
	currentState = state    # Return to intermediate state of rubiks cube
	# Working way back down to end state
	while endParents[currentState] is not None:
		parent = endParents[currentState]      # Parent state + move to current state
		currentState = parent[0]               # Move on level towards end state
		move = parent[1]
		moves.append(rubik.perm_inverse(move)) # Store inverse of moves in FIFO (Intermediate -> End)

	return moves
Example #23
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    if start == end: return []
    
    forward_parents = {start: None}
    backward_parents = {end: None}
    forward_moves = {}
    backward_moves = {}
    for move in rubik.quarter_twists:
        forward_moves[move] = move
        backward_moves[rubik.perm_inverse(move)] = move
    forward = (forward_moves, forward_parents, backward_parents)
    backward = (backward_moves, backward_parents, forward_parents)
    queue = deque([(start, forward), (end, backward), None])
    
    for i in range(7):
        while True:
            vertex = queue.popleft()
            if vertex is None:
                queue.append(None)
                break
            position = vertex[0]
            moves, parents, other_parents = vertex[1]
            for move in moves:
                next_position = rubik.perm_apply(move, position)
                if next_position in parents: continue
                parents[next_position] = (moves[move], position)
                queue.append((next_position, vertex[1]))
                if next_position in other_parents:
                    forward_path = path(next_position, forward_parents)
                    backward_path = path(next_position, backward_parents)
                    backward_path.reverse()
                    return forward_path + backward_path
    
    return None
Example #24
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start to end position.
    Returns a list of moves and assumes the rubik.quarter_twists move set.
    """

    if start == end: return []                             #if no shortest path exists (start==end), return empty list
    
    fparents = {start: None}                               #first half parents
    sparents = {end: None}                                 #second half parents
    fmoves = {}                                            #first half moves
    smoves = {}                                            #second half moves
    for turn in rubik.quarter_twists:
        fmoves[turn] = turn                                #insert forward moves from quarter_twists
        smoves[rubik.perm_inverse(turn)] = turn            #insert reverse moves (starting from second half)
    forward = (fmoves, fparents, sparents)                 #set of moves and first/second half parents
    backward = (smoves, sparents, fparents)                #set of inverse moves with first/second half parents
    Q = deque([(start, forward), (end, backward), None])   #create new deque(quicklist) Q = (first half, second half, None)
    
    for x in range(7):                                     #for each move in quarter_twist
        while True:                                        #loop
            v = Q.popleft()                                #return leftmost element from Q
            if v is None:                                  #if at the end of Q (None)
                Q.append(None)                             #add None to Q
                break                                      #break from loop
            position = v[0]                                #set vertex to start or end
            moves, parents, otherparents = v[1]            #set moves, parents, other parents to forward or backward
            for i in moves:                                #start two way BFS
                nextpos = rubik.perm_apply(i, position)    #set node to search
                if nextpos in parents: continue            #if node in parents, continue
                parents[nextpos] = (moves[i], position)    #set parent pointer to node, vertex
                Q.append((nextpos, v[1]))                  #add expanded search to Q
                if nextpos in otherparents:                #if node discovered in both searches
                    fpath = path(nextpos, fparents)        #forward path set with node + parent pointers
                    spath = path(nextpos, sparents)        #backward path set with node + parent pointers
                    spath.reverse()                        #must reverse the inverse path before joining it with forward path
                    return fpath + spath                   #return list of moves for the shortest path (forward + backward moves)
    
    return None                                            #else return None
Example #25
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    # raise NotImplementedError
    forward_dict = {start: []}
    backward_dict = {end: []}
    forward_path, backward_path = two_way_trans(forward_dict, backward_dict, 0)
    if forward_path is None and backward_path is None:
        return None
    margin_path = []
    for iterator in forward_path:
        if iterator != []:
            margin_path.append(iterator)
    for i in range(len(backward_path) - 1, -1, -1):
        if backward_path[i] != []:
            margin_path.append(rubik.perm_inverse(backward_path[i]))
    return margin_path
Example #26
0
def shortest_path_optmized(start, end):
    """
    For Question 2, using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    # simultaneous bfs from both the ends and maintain visted_nodes_1 and 2.
    # when node is discovered while bfs of start check if it is present in visite_nodes_2 and vice versa to check meeting point

    # SPECIAL CASE, better not to do all the next if unneeded
    if start == end: return []

    # INITIALISATION
    # returned list of moves
    result_path = []
    # bfs distance and recovery dictionaries
    dist_front , recover_front = {} , {}
    dist_back  , recover_back  = {} , {}
    # bfs queues, using deque instead of list to have O(1) removal of 1st element
    q_front = __import__('collections').deque()
    q_back  = __import__('collections').deque()

    # SETTING UP
    # setting up bfs from front
    q_front.append(start)
    dist_front[start] = 0
    recover_front[start] = (None,None)
    # setting up bfs from back
    q_back.append(end)
    dist_back[end] = 0
    recover_back[end] = (None,None)
    # setting up the intersection point
    intersection_pt = None

    # BFS LOOP - runs till both bfs intersect
    done = False
    #
    while not done:
        # state to act on in front bfs
        curr = q_front.popleft()

        # If 7 levels have been visited and no intersection,
        #       no solution.
        if 7 < dist_front[curr]: break

        # visiting all neighbours
        for move in rubik.quarter_twists:
            # find neighbour by applying move
            neighbour = rubik.perm_apply(move, curr)
            # if this has not been explored yet
            if neighbour not in dist_front:
                dist_front[neighbour]    = dist_front[curr] + 1
                recover_front[neighbour] = (curr, move)
                q_front.append(neighbour)
            # if this has been explored from back, then intersection
            if neighbour in dist_back:
                intersection_pt = neighbour
                done = True
                break

        # no need to continue back bfs if intersection found
        if done: break

        # state to act on in back bfs
        curr = q_back.popleft()

        # If 7 levels have been visited and no intersection,
        #       no solution.
        if 7 < dist_back[curr]: break

        # visiting all neighbours
        for move in rubik.quarter_twists:
            # find neighbour by applying move
            neighbour = rubik.perm_apply(move, curr)
            # if this has not been explored yet
            if neighbour not in dist_back:
                dist_back[neighbour]    = dist_back[curr] + 1
                recover_back[neighbour] = (curr, move)
                q_back.append(neighbour)
            # if this has been explored from front, then intersection
            if neighbour in dist_front:
                intersection_pt = neighbour
                done = True
                break

    # SPECIAL CASE: No solution
    if intersection_pt == None: return None

    # BACKTRACKING
    # recover moves from start to current state
    #         using recovery list of front bfs
    ptr = intersection_pt
    while ptr != start:
        result_path.append(recover_front[ptr][1])
        ptr = recover_front[ptr][0]
    result_path = result_path[::-1]
    # recover moves from current state to end
    #         using recovery list of back bfs
    ptr = intersection_pt
    while ptr != end:
        result_path.append(rubik.perm_inverse(recover_back[ptr][1]))
        ptr = recover_back[ptr][0]

    # SANITY CHECK
    cube = start[:]
    for move in result_path:
        cube = rubik.perm_apply(move, cube)
    assert cube == end

    return list(map(lambda x: rubik.quarter_twists_names[x], result_path))
Example #27
0
def shortest_path(start, end):

    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    if start==end:
        return []
    startroot=node(start)
    endroot=node(end)
    startq=queue([startroot,None])
    endq=queue([endroot,None])
    starth=[]
    endh=[]
    for i in range(0,335923):
        starth.append([])
        endh.append([])
    starth[hash(start)].append((start,None,None))
    endh[hash(end)].append((end,None,None))
    #startd[startroot.list]=(startroot.list,startroot.parent,startroot.orientation)
    #endd[endroot.list]=(endroot.list,endroot.parent,endroot.orientation)
    move=[rubik.F,rubik.Fi,rubik.L,rubik.Li,rubik.U,rubik.Ui]
    i=0
    while i<7:
        while True:
            g=startq.dequeue()
            if g is None:
                startq.enqueue(None)
                break
            j=0
            for k in move:
                m=rubik.perm_apply(k,g.list)
                if search(m,starth[hash(m)]) is None:
                    g.child[j]=node(m,g,k)
                    starth[hash(m)].append((m,g,k))
                    startq.enqueue(g.child[j])
                if search(m,endh[hash(m)]) is not None:
                    fr=path(m,starth[hash(m)])
                    br=path(m,endh[hash(m)])

                    fr.reverse()
                    return fr + br
                j+=1

        while True:
            g=endq.dequeue()
            if g is None:
                endq.enqueue(None)
                break
            j=0
            for k in move:
                m=rubik.perm_apply(rubik.perm_inverse(k),g.list)
                if search(m,endh[hash(m)]) is None:
                    g.child[j]=node(m,g,k)
                    endh[hash(m)].append((m,g,k))
                    endq.enqueue(g.child[j])

                if search(m,starth[hash(m)]) is not None:
                    fr=path(m,starth[hash(m)])
                    br=path(m,endh[hash(m)])
                    fr.reverse()

                    return fr + br

                j+=1
        i+=1
        #print i
    return None
Example #28
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    
    Each move can be applied using rubik.perm_apply
    """
    if start == end:
        return []

    # keep track of states that have been expanded from the start
    parent = {start: None}  # child_node: (parent_node, perm)
    # where perm_apply(parent_node) = child_node

    # keep track of states that have been expanded from the end
    child = {end: None}  # parent_node: (child_node, perm)
    # where perm_appry(parent_node) = child_node

    Q = [start]  # first in, first out queue for forward expansion
    R = [end]  # first in, first out queue for backward expansion

    count = 0
    found = None
    while count < 6000:
        # forward expansion
        current_state = Q.pop()  # dequeue
        for twist in rubik.quarter_twists:  # explore current_state
            state = rubik.perm_apply(twist, current_state)
            if state not in parent:
                parent[state] = (current_state, twist)
                Q = [state] + Q
        # forward expansion done once

        # if end node is found
        if end in parent:
            return [parent[end][1]]

        # backward expansion
        current_state = R.pop()  # dequeue
        for twist in rubik.quarter_twists:
            state = rubik.perm_apply(rubik.perm_inverse(twist), current_state)
            if state not in child:
                child[state] = (current_state, twist)
                R = [state] + R
            if state in parent:
                found = state
                break

        # backward expansion done once
        if found is not None:
            break
        count += 1

    if found is None:
        return None

    result = []
    current_state = found
    while current_state != start:
        pred_pair = parent[current_state]
        result = [pred_pair[1]] + result
        current_state = pred_pair[0]

    current_state = found
    while current_state != end:
        succ_pair = child[current_state]
        result = result + [succ_pair[1]]
        current_state = succ_pair[0]

    return result
Example #29
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves.

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply

    The forward and backward search use exactly the same code, so it seems prudent
    to refactor them into a function. However, the number of variables that must be
    passed in order for this to work makes it seem like a clumsy solution. I wonder
    if there's something better...
    """
    if start == end:
        # Length 0 path.
        return []

    # Initialize level counters and parent pointers.
    level = {start: 0, end: 0}
    forward_parent = {start: None}
    backward_parent = {end: None}

    # Initialize forward and backward search frontiers.
    i = 1
    found = False
    middle = None
    forward_frontier = [start]
    backward_frontier = [end]

    # Keep track of whether a given node has been discovered by both searches.
    found_by_forward_search = set()
    found_by_forward_search.add(start)
    found_by_backward_search = set()
    found_by_backward_search.add(end)

    # Once the same node has been touched by both searches, we're done.
    # Checking only out to level 9 is an ugly hack! There has to be a better way to
    # determine if there's no solution. I've read some things about permutation parity
    # and checking corner twists, but I'm not sure how to do that.
    while (forward_frontier or backward_frontier) and not found and i < 9:
        # Reset next level of both search frontiers.
        next_forward = []
        next_backward = []

        # Search forward frontier (one level).
        for config in forward_frontier:
            # Find the config's neighbors by applying all possible moves.
            for permutation in rubik.quarter_twists:
                neighbor = rubik.perm_apply(permutation, config)

                # Avoid duplicates.
                if neighbor not in forward_parent:
                    # Set the level and parent of the neighbor.
                    level[neighbor] = i
                    forward_parent[neighbor] = permutation
                    # Add the neighbor to the new search frontier.
                    next_forward.append(neighbor)

        # Search backward frontier (one level).
        for config in backward_frontier:
            # Find the config's neighbors by applying all possible moves.
            for permutation in rubik.quarter_twists:
                neighbor = rubik.perm_apply(permutation, config)

                # Avoid duplicates.
                if neighbor not in backward_parent:
                    # Set the level and parent of the neighbor.
                    level[neighbor] = i
                    backward_parent[neighbor] = permutation
                    # Add the neighbor to the new search frontier.
                    next_backward.append(neighbor)

        # Check to see if any neighbors have been discovered by both searches. If one
        # has, we're done.
        found_by_forward_search = found_by_forward_search.union(
            set(next_forward))
        found_by_backward_search = found_by_backward_search.union(
            set(next_backward))
        found_by_both = found_by_forward_search.intersection(
            found_by_backward_search)
        if found_by_both:
            found = True
            middle = found_by_both.pop()

        # Move to the new search frontiers, one level deeper.
        forward_frontier = next_forward
        backward_frontier = next_backward
        i += 1

    # Return the shortest path between the start and end configurations.
    if middle is None:
        # No path exists between the two configurations.
        return None
    elif middle == start or middle == end:
        # Path of length 1.
        if middle == start:
            return [rubik.perm_inverse(backward_parent[middle])]
        else:
            return [forward_parent[middle]]
    else:
        # Path of length >1.
        moves_to_end = build(backward_parent, end, middle, backward=True)
        moves_to_end.reverse()
        moves_to_start = build(forward_parent, start, middle, backward=False)

        path = moves_to_start
        path.extend(moves_to_end)

        return path
Example #30
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves.

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """

    # Start side of BFS
    start_init = node_info(start, (None, None), 0)
    s_frontier = deque([start_init])
    s_parents = []

    # End side of BFS
    end_init = node_info(end, (None, None), 0)
    e_frontier = deque([end_init])
    e_parents = []

    # Flag determines which side we need to advance the frontier
    # When flag is 1 it means that we might advance the left frontier
    # When flag is -1 it means we might advance the right frontier
    flag = 1

    # Test to see if the two given states (start, end) are the same
    # We know to return an empty list
    """
    Invariant: At each iteration, the position of l_elm in s_frontier is less than the len(s_frontier)
    Initialization: There is a list called s_frontier that has elements in it
    Maintenance: Given that there are still elements in s_frontier to go through, the loop will continue 
    Termination: We have reached the end of s_frontier or the two given states are the same, thus returning an 
                 empty list because no path needs to be found
    """
    for l_elm in s_frontier:
        """
        Invariant: At each iteration, the position of r_elm in e_frontier is less than the len(e_frontier)
        Initialization: There is a list called e_frontier that has elements in it
        Maintenance: Given that there are still elements in e_frontier to go through, the loop will continue and 
                     check to see if the the states are the same
        Termination: We have reached the end of e_frontier or the two given states are the same, thus returning an 
                     empty list because no path needs to be found
        """
        for r_elm in e_frontier:
            if l_elm.st == r_elm.st:
                return []

    found = False
    """
    Invariant: At each iteration, the solution has not been found
    Initialization: found = False 
    Maintenance: Given that we have not found a solution, the function will alternate between the start and end 
                 sides (bidirectional) to create a new frontier and check its values for a solution
    Termination: The cube is unsolvable (order exceeds 7) or we have found a solution
    """
    # Run while False
    while not found:
        # Checks the depth of the nodes in both frontiers
        # If their order exceeds 7, then there is no shortest path
        if s_frontier[0].order > 6 and e_frontier[0].order > 6:
            return None

        # Flag alternates the sides
        if flag == 1:
            # Gets the next frontier
            next_frontier(s_frontier, s_parents)
            flag = flag * (-1)
        else:
            # Gets the next frontier
            next_frontier(e_frontier, e_parents)
            flag = flag * (-1)

        # Checking to see if there is the same block state in each list
        """
        Invariant: At each iteration, the position of l_elm in s_frontier is less than the len(s_frontier)
        Initialization: There is a list called s_frontier that has elements in it
        Maintenance: Given that there are still elements in s_frontier to go through, the loop will continue 
        Termination: We have reached the end of s_frontier or the intersection of the two ends has been found
        """
        # Grabs a left element from the starting frontier
        for l_elm in s_frontier:
            """
            Invariant: At each iteration, the position of r_elm in e_frontier is less than the len(e_frontier)
            Initialization: There is a list called e_frontier that has elements in it
            Maintenance: Given that there are still elements in e_frontier to go through, the loop will continue and 
                         check to see if s_frontier and e_frontier has an intersection
            Termination: We have reached the end of e_frontier or the intersection of the two ends has been found
            """
            # Compares it to each of the right elements from the end frontier
            for r_elm in e_frontier:
                # If we find an element that matches
                if l_elm.st == r_elm.st:
                    # Find the intersect of the two lists
                    intersect = (l_elm, r_elm)
                    # We set found to true
                    found = True
                    # Then break out of the loop
                    break
            # If the element was found we can break out of this loop as well
            if found == True:
                break
    # Creates a lsit for return
    final_list = []
    # Temp variable to hold l_elm
    l_temp = intersect[0]
    """
    Invariant: At each iteration, there are still nodes to be added to the final solution list
    Initialization: The current node does not equal the first parent node of start
    Maintenance: Given that we have not reached the first parent node of start, the parent of the current node is 
                 added to the beginning of the final solution list. The new node to look at is then updated.
    Termination: We have reached the first parent node of start and now have a list of its path
    """

    # Gets the parent of l_temp (l_elm) until the start state
    while (l_temp.st != start):
        final_list.insert(0, l_temp.parent[0])
        l_temp = l_temp.parent[1]

    r_temp = intersect[1]
    """
    Invariant: At each iteration, there are still nodes to be added to the final solution list
    Initialization: The current node does not equal the first parent node of end
    Maintenance: Given that we have not reached the first parent node of end, the parent of the current node is 
                 added to the end of the final solution list. The new node to look at is then updated.
    Termination: We have reached the first parent node of end and now have a list of its path connecting start to end
    """
    # Gets the parent of r_temp (r_elm) until the end state
    # Perm inverse is because we have to do the inverse of each move to get the parent.
    while (r_temp.st != end):
        final_list.append(rubik.perm_inverse(r_temp.parent[0]))
        r_temp = r_temp.parent[1]

    return final_list
Example #31
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """

    if start == end:
        return []

    queueF = deque([start])
    queueB = deque([end])
    visited = {}
    forwardParents = {}
    backwardParents = {}
    intersection = []
    counter = 0
    queuedItemsF = {}
    queuedItemsB = {}
    queuedItemsF[start] = 1
    queuedItemsB[end] = 1

    forward_moves = {}
    for move in rubik.quarter_twists:
        forward_moves[move] = move

    while len(intersection) == 0 and counter < 3047:
        currF = queueF.popleft()
        currB = queueB.popleft()
        queuedItemsF.pop(currF)
        queuedItemsB.pop(currB)

        #Forwards
        for twist in forward_moves:
            config = rubik.perm_apply(twist, currF)
            if config not in visited and config not in queuedItemsF:
                forwardParents[config] = (twist, currF)
                if config == end:
                    intersection.append(config)
                    break

                queueF.append(config)
                queuedItemsF[config] = 1

        #Backwards
        for twist in forward_moves:
            config = rubik.perm_apply(twist, currB)
            if config not in visited and config not in queuedItemsB:
                backwardParents[config] = (twist, currB)
                queueB.append(config)
                queuedItemsB[config] = 1

        visited[currF] = 1
        visited[currB] = 1

        intersect = list(set(queueF).intersection(queueB))

        if len(intersect) != 0:
            intersection.append(intersect[0])

        counter += 1

    if len(intersection) == 0:
        return None

    ans = []
    curr = intersection[0]
    while start != curr:
        twist, curr = forwardParents[curr]
        ans.insert(0, twist)

    curr = intersection[0]
    while end != curr:
        twist, curr = backwardParents[curr]
        ans.append(rubik.perm_inverse(twist))

    return ans
def shortest_path(start, end):

    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    if start==end:
        return []
    startroot=node(start)
    endroot=node(end)
    startq=queue([startroot,None])
    endq=queue([endroot,None])

    startd={}
    startd[start]=(start,None,None)
    endd={}
    endd[end]=(end,None,None)

    i=0
    while i<7:
        while True:
            g=startq.dequeue()
            if g==None:
                startq.enqueue(None)
                break

            if rubik.perm_apply(rubik.F,g.list) not in startd:
                g.child[0]=node(rubik.perm_apply(rubik.F,g.list),g.list,rubik.F)
                startd[rubik.perm_apply(rubik.F,g.list)]=(rubik.perm_apply(rubik.F,g.list),g.list,rubik.F)
                startq.enqueue(g.child[0])
            if rubik.perm_apply(rubik.F,g.list) in endd:
                fr=moves(rubik.perm_apply(rubik.F,g.list),startd)
                br=moves(rubik.perm_apply(rubik.F,g.list),endd)
                fr.reverse()

                z=fr+br

                return z


            if rubik.perm_apply(rubik.Fi,g.list) not in startd:
                g.child[1]=node(rubik.perm_apply(rubik.Fi,g.list),g.list,rubik.Fi)
                startd[rubik.perm_apply(rubik.Fi,g.list)]=(rubik.perm_apply(rubik.Fi,g.list),g.list,rubik.Fi)
                startq.enqueue(g.child[1])
            if rubik.perm_apply(rubik.Fi,g.list) in endd:
                fr=moves(rubik.perm_apply(rubik.Fi,g.list),startd)
                br=moves(rubik.perm_apply(rubik.Fi,g.list),endd)
                fr.reverse()

                z=fr+br

                return z


            if rubik.perm_apply(rubik.L,g.list) not in startd:
                g.child[2]=node(rubik.perm_apply(rubik.L,g.list),g.list,rubik.L)
                startd[rubik.perm_apply(rubik.L,g.list)]=(rubik.perm_apply(rubik.L,g.list),g.list,rubik.L)
                startq.enqueue(g.child[2])
            if rubik.perm_apply(rubik.L,g.list) in endd:
                fr=moves(rubik.perm_apply(rubik.L,g.list),startd)
                br=moves(rubik.perm_apply(rubik.L,g.list),endd)
                fr.reverse()

                z=fr+br

                return z


            if rubik.perm_apply(rubik.Li,g.list) not in startd:
                g.child[3]=node(rubik.perm_apply(rubik.Li,g.list),g.list,rubik.Li)
                startd[rubik.perm_apply(rubik.Li,g.list)]=(rubik.perm_apply(rubik.Li,g.list),g.list,rubik.Li)
                startq.enqueue(g.child[3])
            if rubik.perm_apply(rubik.Li,g.list) in endd:
                fr=moves(rubik.perm_apply(rubik.Li,g.list),startd)
                br=moves(rubik.perm_apply(rubik.Li,g.list),endd)
                fr.reverse()

                z=fr+br

                return z


            if rubik.perm_apply(rubik.U,g.list) not in startd:
                g.child[4]=node(rubik.perm_apply(rubik.U,g.list),g.list,rubik.U)
                startd[rubik.perm_apply(rubik.U,g.list)]=(rubik.perm_apply(rubik.U,g.list),g.list,rubik.U)
                startq.enqueue(g.child[4])
            if rubik.perm_apply(rubik.U,g.list) in endd:
                fr=moves(rubik.perm_apply(rubik.U,g.list),startd)
                br=moves(rubik.perm_apply(rubik.U,g.list),endd)
                fr.reverse()

                z=fr+br

                return z


            if rubik.perm_apply(rubik.Ui,g.list) not in startd:
                g.child[5]=node(rubik.perm_apply(rubik.Ui,g.list),g.list,rubik.Ui)
                startd[rubik.perm_apply(rubik.Ui,g.list)]=(rubik.perm_apply(rubik.Ui,g.list),g.list,rubik.Ui)
                startq.enqueue(g.child[5])
            if rubik.perm_apply(rubik.Li,g.list) in endd:
                fr=moves(rubik.perm_apply(rubik.Ui,g.list),startd)
                br=moves(rubik.perm_apply(rubik.Ui,g.list),endd)
                fr.reverse()

                z=fr+br

                return z

    


        while True:
            k=endq.dequeue()
            if k==None:
                endq.enqueue(None)
                break

            if rubik.perm_apply(rubik.perm_inverse(rubik.F),k.list) not in endd:
                k.child[0]=node(rubik.perm_apply(rubik.perm_inverse(rubik.F),k.list),k.list,rubik.F)
                endd[rubik.perm_apply(rubik.perm_inverse(rubik.F),k.list)]=(rubik.perm_apply(rubik.perm_inverse(rubik.F),k.list),k.list,rubik.F)
                endq.enqueue(k.child[0])
            if  rubik.perm_apply(rubik.perm_inverse(rubik.F),k.list) in startd:
                fr=moves(rubik.perm_apply(rubik.perm_inverse(rubik.F),k.list),startd)
                br=moves(rubik.perm_apply(rubik.perm_inverse(rubik.F),k.list),endd)
                fr.reverse()
                z=fr+br

                return z

            if rubik.perm_apply(rubik.perm_inverse(rubik.Fi),k.list) not in endd:
                k.child[1]=node(rubik.perm_apply(rubik.perm_inverse(rubik.Fi),k.list),k.list,rubik.Fi)
                endd[rubik.perm_apply(rubik.perm_inverse(rubik.Fi),k.list)]=(rubik.perm_apply(rubik.perm_inverse(rubik.Fi),k.list),k.list,rubik.Fi)
                endq.enqueue(k.child[1])
            if  rubik.perm_apply(rubik.perm_inverse(rubik.Fi),k.list) in startd:
                fr=moves(rubik.perm_apply(rubik.perm_inverse(rubik.Fi),k.list),startd)
                br=moves(rubik.perm_apply(rubik.perm_inverse(rubik.Fi),k.list),endd)
                fr.reverse()
                z=fr+br

                return z


            if rubik.perm_apply(rubik.perm_inverse(rubik.L),k.list) not in endd:
                k.child[2]=node(rubik.perm_apply(rubik.perm_inverse(rubik.L),k.list),k.list,rubik.L)
                endd[rubik.perm_apply(rubik.perm_inverse(rubik.L),k.list)]=(rubik.perm_apply(rubik.perm_inverse(rubik.L),k.list),k.list,rubik.L)
                endq.enqueue(k.child[2])
            if  rubik.perm_apply(rubik.perm_inverse(rubik.L),k.list) in startd:
                fr=moves(rubik.perm_apply(rubik.perm_inverse(rubik.L),k.list),startd)
                br=moves(rubik.perm_apply(rubik.perm_inverse(rubik.L),k.list),endd)
                fr.reverse()
                z=fr+br

                return z


            if rubik.perm_apply(rubik.perm_inverse(rubik.Li),k.list) not in endd:
                k.child[3]=node(rubik.perm_apply(rubik.perm_inverse(rubik.Li),k.list),k.list,rubik.Li)
                endd[rubik.perm_apply(rubik.perm_inverse(rubik.Li),k.list)]=(rubik.perm_apply(rubik.perm_inverse(rubik.Li),k.list),k.list,rubik.Li)
                endq.enqueue(k.child[3])
            if  rubik.perm_apply(rubik.perm_inverse(rubik.Li),k.list) in startd:
                fr=moves(rubik.perm_apply(rubik.perm_inverse(rubik.Li),k.list),startd)
                br=moves(rubik.perm_apply(rubik.perm_inverse(rubik.Li),k.list),endd)
                fr.reverse()
                z=fr+br

                return z


            if rubik.perm_apply(rubik.perm_inverse(rubik.U),k.list) not in endd:
                k.child[4]=node(rubik.perm_apply(rubik.perm_inverse(rubik.U),k.list),k.list,rubik.U)
                endd[rubik.perm_apply(rubik.perm_inverse(rubik.U),k.list)]=(rubik.perm_apply(rubik.perm_inverse(rubik.U),k.list),k.list,rubik.U)
                endq.enqueue(k.child[4])
            if  rubik.perm_apply(rubik.perm_inverse(rubik.U),k.list) in startd:
                fr=moves(rubik.perm_apply(rubik.perm_inverse(rubik.U),k.list),startd)
                br=moves(rubik.perm_apply(rubik.perm_inverse(rubik.U),k.list),endd)
                fr.reverse()
                z=fr+br

                return z


            if rubik.perm_apply(rubik.perm_inverse(rubik.Ui),k.list) not in endd:
                k.child[5]=node(rubik.perm_apply(rubik.perm_inverse(rubik.Ui),k.list),k.list,rubik.Ui)
                endd[rubik.perm_apply(rubik.perm_inverse(rubik.Ui),k.list)]=(rubik.perm_apply(rubik.perm_inverse(rubik.Ui),k.list),k.list,rubik.Ui)
                endq.enqueue(k.child[5])
            if  rubik.perm_apply(rubik.perm_inverse(rubik.Ui),k.list) in startd:
                fr=moves(rubik.perm_apply(rubik.perm_inverse(rubik.Ui),k.list),startd)
                br=moves(rubik.perm_apply(rubik.perm_inverse(rubik.Ui),k.list),endd)
                fr.reverse()
                z=fr+br

                return z


        i+=1
    return None
Example #33
0
def shortest_path(start, end):
    # Start side of BFS
    start_init = node_info(start, (None, None), 0)
    s_frontier = deque([start_init])
    s_parents = []

    # End side of BFS
    end_init = node_info(end, (None, None), 0)
    e_frontier = deque([end_init])
    e_parents = []

    # Flag determines which side we need to advance the frontier
    # When flag is 1 it means that we might advance the left frontier
    # When flag is -1 it means we might advance the right frontier
    flag = 1

    # Test to see if the two given states (start, end) are the same
    # We know to return an empty list

    for l_elm in s_frontier:
        for r_elm in e_frontier:
            if l_elm.st == r_elm.st:
                return []

    found = False

    # Given that we have not found a solution, the function will alternate between the start and end
    # sides (bidirectional) to create a new frontier and check its values for a solution
    while not found:
        # Checks the depth of the nodes in both frontiers
        # If their order exceeds 7, then there is no shortest path
        if s_frontier[0].order > 6 and e_frontier[0].order > 6:
            return None

        # Flag alternates the sides
        if flag == 1:
            # Gets the next frontier
            next_frontier(s_frontier, s_parents)
            flag = flag * (-1)
        else:
            # Gets the next frontier
            next_frontier(e_frontier, e_parents)
            flag = flag * (-1)

        # Checking to see if there is the same block state in each list

        # Grabs a left element from the starting frontier
        for l_elm in s_frontier:
            # Compares it to each of the right elements from the end frontier
            for r_elm in e_frontier:
                # If we find an element that matches
                if l_elm.st == r_elm.st:
                    # Find the intersect of the two lists
                    intersect = (l_elm, r_elm)
                    # We set found to true
                    found = True
                    # Then break out of the loop
                    break
            # If the element was found we can break out of this loop as well
            if found == True:
                break
    # Creates a lsit for return
    final_list = []
    # Temp variable to hold l_elm
    l_temp = intersect[0]

    # Gets the parent of l_temp (l_elm) until the start state
    while (l_temp.st != start):
        final_list.insert(0, l_temp.parent[0])
        l_temp = l_temp.parent[1]

    r_temp = intersect[1]

    # Gets the parent of r_temp (r_elm) until the end state
    # Perm inverse is because we have to do the inverse of each move to get the parent.
    while (r_temp.st != end):
        final_list.append(rubik.perm_inverse(r_temp.parent[0]))
        r_temp = r_temp.parent[1]

    return final_list
Example #34
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves.

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    if start == end:
        return []

    front = {0: [start]}
    back = {0: [end]}

    front_discovered = {start: (None, None)}  # position: parent, twist
    back_discovered = {end: (None, None)}

    common = None

    try:
        for i in range(0, 8):
            front[i + 1] = []
            for position in front.get(i):
                for twist in rubik.quarter_twists:
                    new = rubik.perm_apply(twist, position)

                    if position in back_discovered:
                        common = position
                        raise LoopException  #TODO this is ugly as hell

                    if new not in front_discovered:
                        front[i + 1].append(new)
                        front_discovered[new] = (position, twist)

            back[i + 1] = []
            for position in back.get(i):
                for twist in rubik.quarter_twists:
                    new = rubik.perm_apply(rubik.perm_inverse(twist), position)

                    if position in front_discovered:
                        common = position
                        raise LoopException  # TODO this is ugly as hell

                    if new not in back_discovered:
                        back[i + 1].append(new)
                        back_discovered[new] = (position, twist)
    finally:
        result = []
        current = common
        front_parent, twist = front_discovered[current]

        while front_parent is not None:
            result.append(twist)
            current = front_parent
            front_parent, twist = front_discovered[current]

        result.reverse()

        current = common
        back_parent, twist = back_discovered[current]

        while back_parent is not None:
            result.append(twist)
            current = back_parent
            back_parent, twist = back_discovered[current]

        return result
Example #35
0
def shortest_path(start, end):
	"""
	Using 2-way BFS, finds the shortest path from start_position to
	end_position. Returns a list of moves. 
	Assumes the rubik.quarter_twists move set.
	"""
	root1=node(start)
	root2=node(end)
	arr1=[[] for wqw in range(8)]
	arr2=[[] for qwq in range(8)]
	ser1=[[] for lp in range(10000)]
	ser2=[[] for lp2 in range(10000)]
	arr1[0].append(root1)
	arr2[0].append(root2)
	ser1[(hash(start))%10000].append(start)
	ser2[(hash(end))%10000].append(end)
	flag=0
	chk=None
	res=[]
	res1=[]
	res2=[]
	for h in range(0,8):
		chk=check_match(arr1[h],arr2[h],ser2)
		if not chk is None:
			flag=1
			break
		else:
			for w in range(len(arr1[h])):
				fin=insert_e(arr1[h][w],h+1,arr1,ser1)
				arr1=fin[0]
				ser1=fin[1]
		if (h+1)<8:
			chk=check_match(arr2[h],arr1[h+1],ser1)
			if not chk is None:
				flag=2
				break
			else:
				for q in range(len(arr2[h])):
					fim=insert_e(arr2[h][q],h+1,arr2,ser2)
					arr2=fim[0]
					ser2=fim[1]
	if flag==1:
		while not chk[0].parent is None:
			res1.append(chk[0].per)
			chk[0]=chk[0].parent
		if not res1 is None:
			res+=res1[::-1]
		while not chk[1].parent is None:
			res2.append(chk[1].per)
			chk[1]=chk[1].parent
		if not res2 is None:
			res+=[rubik.perm_inverse(i) for i in res2]
		return res
	elif flag==2:
		while not chk[1].parent is None:
			res1.append(chk[1].per)
			chk[1]=chk[1].parent
		if not res1 is None:
			res+=res1[::-1]
		while not chk[0].parent is None:
			res2.append(chk[0].per)
			chk[0]=chk[0].parent
		if not res2 is None:
			res+=[rubik.perm_inverse(i) for i in res2]
		return res
	else:
		print "The given configuration is not solvable/wrong."
Example #36
0
def getInverse(moves):
    for m in range(len(moves)):
        moves[m] = rubik.perm_inverse(moves[m])
Example #37
0
def getPath(beg, end):
    end.reverse()
    for x in end:
        beg.append(rubik.perm_inverse(x))
    return beg
Example #38
0
def shortest_path(start, end):

    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """
    if start == end:
        return []
    startroot = node(start)
    endroot = node(end)
    startq = queue([startroot, None])
    endq = queue([endroot, None])
    starth = []
    endh = []
    for i in range(0, 335923):
        starth.append([])
        endh.append([])
    startd = {}
    starth[hash(start)] = (start, None, None)
    endd = {}
    endh[hash(end)] = (end, None, None)
    startd[startroot.list] = (startroot.list, startroot.parent, startroot.orientation)
    endd[endroot.list] = (endroot.list, endroot.parent, endroot.orientation)
    i = 0
    while i < 7:
        while True:
            g = startq.dequeue()
            if g == None:
                startq.enqueue(None)
                break

            if rubik.perm_apply(rubik.F, g.list) is not starth[hash(rubik.perm_apply(rubik.F, g.list))]:
                g.child[0] = node(rubik.perm_apply(rubik.F, g.list), g.list, rubik.F)
                starth[hash(rubik.perm_apply(rubik.F, g.list))].append(
                    (rubik.perm_apply(rubik.F, g.list), g.list, rubik.F)
                )
                startq.enqueue(g.child[0])
            if rubik.perm_apply(rubik.F, g.list) is endh[hash(rubik.perm_apply(rubik.F, g.list))]:
                fr = moves(rubik.perm_apply(rubik.F, g.list), starth)
                br = moves(rubik.perm_apply(rubik.F, g.list), endh)
                fr.reverse()

                z = fr + br

                return z

            if rubik.perm_apply(rubik.Fi, g.list) is not starth[hash(rubik.perm_apply(rubik.Fi, g.list))]:
                g.child[1] = node(rubik.perm_apply(rubik.Fi, g.list), g.list, rubik.Fi)
                starth[hash(rubik.perm_apply(rubik.Fi, g.list))].append(
                    (rubik.perm_apply(rubik.Fi, g.list), g.list, rubik.Fi)
                )
                startq.enqueue(g.child[1])
            if rubik.perm_apply(rubik.Fi, g.list) is endh[hash(rubik.perm_apply(rubik.Fi, g.list))]:
                fr = moves(rubik.perm_apply(rubik.Fi, g.list), starth)
                br = moves(rubik.perm_apply(rubik.Fi, g.list), endh)
                fr.reverse()

                z = fr + br

                return z

            if rubik.perm_apply(rubik.L, g.list) is not starth[hash(rubik.perm_apply(rubik.L, g.list))]:
                g.child[2] = node(rubik.perm_apply(rubik.L, g.list), g.list, rubik.L)
                starth[hash(rubik.perm_apply(rubik.L, g.list))].append(
                    (rubik.perm_apply(rubik.L, g.list), g.list, rubik.L)
                )
                startq.enqueue(g.child[2])
            if rubik.perm_apply(rubik.L, g.list) is endh[hash(rubik.perm_apply(rubik.L, g.list))]:
                fr = moves(rubik.perm_apply(rubik.L, g.list), starth)
                br = moves(rubik.perm_apply(rubik.L, g.list), endh)
                fr.reverse()

                z = fr + br

                return z

            if rubik.perm_apply(rubik.Li, g.list) is not starth[hash(rubik.perm_apply(rubik.Li, g.list))]:
                g.child[3] = node(rubik.perm_apply(rubik.Li, g.list), g.list, rubik.Li)
                starth[hash(rubik.perm_apply(rubik.Li, g.list))].append(
                    (rubik.perm_apply(rubik.Li, g.list), g.list, rubik.Li)
                )
                startq.enqueue(g.child[3])
            if rubik.perm_apply(rubik.Li, g.list) is endh[hash(rubik.perm_apply(rubik.Li, g.list))]:
                fr = moves(rubik.perm_apply(rubik.Li, g.list), starth)
                br = moves(rubik.perm_apply(rubik.Li, g.list), endh)
                fr.reverse()

                z = fr + br

                return z

            if rubik.perm_apply(rubik.U, g.list) is not starth[hash(rubik.perm_apply(rubik.U, g.list))]:
                g.child[4] = node(rubik.perm_apply(rubik.U, g.list), g.list, rubik.U)
                starth[hash(rubik.perm_apply(rubik.U, g.list))].append(
                    (rubik.perm_apply(rubik.U, g.list), g.list, rubik.U)
                )
                startq.enqueue(g.child[4])
            if rubik.perm_apply(rubik.U, g.list) is endh[hash(rubik.perm_apply(rubik.U, g.list))]:
                fr = moves(rubik.perm_apply(rubik.U, g.list), starth)
                br = moves(rubik.perm_apply(rubik.U, g.list), endh)
                fr.reverse()

                z = fr + br

                return z

            if rubik.perm_apply(rubik.Ui, g.list) is not starth[hash(rubik.perm_apply(rubik.Ui, g.list))]:
                g.child[5] = node(rubik.perm_apply(rubik.Ui, g.list), g.list, rubik.Ui)
                starth[hash(rubik.perm_apply(rubik.Ui, g.list))].append(
                    (rubik.perm_apply(rubik.Ui, g.list), g.list, rubik.Ui)
                )
                startq.enqueue(g.child[5])
            if rubik.perm_apply(rubik.Li, g.list) is endh[hash(rubik.perm_apply(rubik.Ui, g.list))]:
                fr = moves(rubik.perm_apply(rubik.Ui, g.list), starth)
                br = moves(rubik.perm_apply(rubik.Ui, g.list), endh)
                fr.reverse()

                z = fr + br

                return z

        while True:
            k = endq.dequeue()
            if k == None:
                endq.enqueue(None)
                break

            if (
                rubik.perm_apply(rubik.perm_inverse(rubik.F), k.list)
                is not endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.F), k.list))]
            ):
                k.child[0] = node(rubik.perm_apply(rubik.perm_inverse(rubik.F), k.list), k.list, rubik.F)
                endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.F), k.list))].append(
                    (rubik.perm_apply(rubik.perm_inverse(rubik.F), k.list), k.list, rubik.F)
                )
                endq.enqueue(k.child[0])
            if (
                rubik.perm_apply(rubik.perm_inverse(rubik.F), k.list)
                is starth[hash(rubik.perm_apply(rubik.perm_inverse(rubik.F), k.list))]
            ):
                fr = moves(rubik.perm_apply(rubik.perm_inverse(rubik.F), k.list), starth)
                br = moves(rubik.perm_apply(rubik.perm_inverse(rubik.F), k.list), endh)
                fr.reverse()
                z = fr + br

                return z

            if (
                rubik.perm_apply(rubik.perm_inverse(rubik.Fi), k.list)
                is not endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.Fi), k.list))]
            ):
                k.child[1] = node(rubik.perm_apply(rubik.perm_inverse(rubik.Fi), k.list), k.list, rubik.Fi)
                endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.Fi), k.list))] = (
                    rubik.perm_apply(rubik.perm_inverse(rubik.Fi), k.list),
                    k.list,
                    rubik.Fi,
                )
                endq.enqueue(k.child[1])
            if rubik.perm_apply(rubik.perm_inverse(rubik.Fi), k.list) is startd:
                fr = moves(rubik.perm_apply(rubik.perm_inverse(rubik.Fi), k.list), starth)
                br = moves(rubik.perm_apply(rubik.perm_inverse(rubik.Fi), k.list), endh)
                fr.reverse()
                z = fr + br

                return z

            if (
                rubik.perm_apply(rubik.perm_inverse(rubik.L), k.list)
                is not endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.L), k.list))]
            ):
                k.child[2] = node(rubik.perm_apply(rubik.perm_inverse(rubik.L), k.list), k.list, rubik.L)
                endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.L), k.list))] = (
                    rubik.perm_apply(rubik.perm_inverse(rubik.L), k.list),
                    k.list,
                    rubik.L,
                )
                endq.enqueue(k.child[2])
            if (
                rubik.perm_apply(rubik.perm_inverse(rubik.L), k.list)
                is starth[hash(rubik.perm_apply(rubik.perm_inverse(rubik.L), k.list))]
            ):
                fr = moves(rubik.perm_apply(rubik.perm_inverse(rubik.L), k.list), starth)
                br = moves(rubik.perm_apply(rubik.perm_inverse(rubik.L), k.list), endh)
                fr.reverse()
                z = fr + br

                return z

            if (
                rubik.perm_apply(rubik.perm_inverse(rubik.Li), k.list)
                is not endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.Li), k.list))]
            ):
                k.child[3] = node(rubik.perm_apply(rubik.perm_inverse(rubik.Li), k.list), k.list, rubik.Li)
                endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.Li), k.list))] = (
                    rubik.perm_apply(rubik.perm_inverse(rubik.Li), k.list),
                    k.list,
                    rubik.Li,
                )
                endq.enqueue(k.child[3])
            if (
                rubik.perm_apply(rubik.perm_inverse(rubik.Li), k.list)
                is starth[hash(rubik.perm_apply(rubik.perm_inverse(rubik.Li), k.list))]
            ):
                fr = moves(rubik.perm_apply(rubik.perm_inverse(rubik.Li), k.list), starth)
                br = moves(rubik.perm_apply(rubik.perm_inverse(rubik.Li), k.list), endh)
                fr.reverse()
                z = fr + br

                return z

            if (
                rubik.perm_apply(rubik.perm_inverse(rubik.U), k.list)
                is not endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.U), k.list))]
            ):
                k.child[4] = node(rubik.perm_apply(rubik.perm_inverse(rubik.U), k.list), k.list, rubik.U)
                endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.U), k.list))] = (
                    rubik.perm_apply(rubik.perm_inverse(rubik.U), k.list),
                    k.list,
                    rubik.U,
                )
                endq.enqueue(k.child[4])
            if (
                rubik.perm_apply(rubik.perm_inverse(rubik.U), k.list)
                is starth[hash(rubik.perm_apply(rubik.perm_inverse(rubik.U), k.list))]
            ):
                fr = moves(rubik.perm_apply(rubik.perm_inverse(rubik.U), k.list), starth)
                br = moves(rubik.perm_apply(rubik.perm_inverse(rubik.U), k.list), endh)
                fr.reverse()
                z = fr + br

                return z

            if (
                rubik.perm_apply(rubik.perm_inverse(rubik.Ui), k.list)
                is not endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.Ui), k.list))]
            ):
                k.child[5] = node(rubik.perm_apply(rubik.perm_inverse(rubik.Ui), k.list), k.list, rubik.Ui)
                endh[hash(rubik.perm_apply(rubik.perm_inverse(rubik.Ui), k.list))] = (
                    rubik.perm_apply(rubik.perm_inverse(rubik.Ui), k.list),
                    k.list,
                    rubik.Ui,
                )
                endq.enqueue(k.child[5])
            if (
                rubik.perm_apply(rubik.perm_inverse(rubik.Ui), k.list)
                is starth[hash(rubik.perm_apply(rubik.perm_inverse(rubik.Ui), k.list))]
            ):
                fr = moves(rubik.perm_apply(rubik.perm_inverse(rubik.Ui), k.list), starth)
                br = moves(rubik.perm_apply(rubik.perm_inverse(rubik.Ui), k.list), endh)
                fr.reverse()
                z = fr + br

                return z

        i += 1
    return None
Example #39
0
def shortest_path(start, end):
    """
    Using 2-way BFS, finds the shortest path from start_position to
    end_position. Returns a list of moves. 

    You can use the rubik.quarter_twists move set.
    Each move can be applied using rubik.perm_apply
    """

    #Set of moves the rubik's cube can make
    moves = [rubik.F, rubik.Fi, rubik.L, rubik.Li,  rubik.U, rubik.Ui]

    #Depth of search
    depth = 1

    startQ = [start] #Holds the starting values we make the frontier from
    endQ = [end] #Holds the ending values we compare the frontier to
    visit = [] #Holds all positions we have already visited
    heapq.heappush(visit, start) #adds start and end to the visited heap
    heapq.heappush(visit, end)
    path = {start: None} #Hold the paths from the node to the start position
    pathE = {end: None} #Holds the paths from the node to the end position
    fromStart = True #True if we are oriendted from the start position

    #true if cube is already solved
    if start == end:
        return []

    #While there exists a list of values to test we will continue to generate the frontier to
    # compare to the end points
    #Termination: When startQ no longer exists we know there is no end points to compare to so
    # we have reached the point where no solution is possible
    while startQ:

        nextQ = []

        depth += 1
        if depth >= 14:  # if we go beyond what is the shortest path, terminate
            break


        # While startQ exists and has values that a frontier can be made from the loop will continue to generate the
        # frontier until a match is found or the end of the list is reached
        # Termination: The loop will terminate when either a match is found signalling that the shortest path has
        # been found or it reaches the end of the startQ meaning that the next frontier has been found
        for i in range(len(startQ)):

            adjList = genAdj(startQ[i])#generates the frontier by calculating all adjacent moves

            #j - 0=F, 1=Fi, 2=L, 3=Li, 4=U, 5=Ui
            #j is the specific move done to the cube
            #While there exists a node j in the adjList we will compare it to the frontier on the other side
            #If a match is found we return the shortest path other wise we add the node to the visisted heap
            #and add its path to the dictionary
            for j in range(len(adjList)):
                #While an element k exists in the endQ frontier we will compare every element k with every element
                #j from the adjList to see if an equality exists, if one exists then a match and by extension a shortest
                #path has been found.
                #The loop will terminate when the end frontier has been completly checked meaning that element j is not
                # on both the start and ending frontiers
                for k in range(len(endQ)):
                    #This is where we merge the list depending on if we are currently adding from the start side
                    #or the end side
                    if adjList[j] == endQ[k]:
                        if fromStart:#If we are oriented from the start
                            tPath = []
                            if path.get(startQ[i]) != None:
                                tPath = path.get(startQ[i])
                            tPath.append(moves[j])
                            sPath = []
                            if pathE.get(endQ[k]) != None:
                                sPath = pathE.get(endQ[k])
                            q = len(sPath) - 1
                            #Loops through the path oriented on the end in reverse appending it to the working path
                            while(q >= 0):
                                tPath.append(perm_inverse(sPath[q]))
                                q -= 1
                            return tPath
                        else: #If we are oriented from the end side
                            tPath = []
                            if path.get(endQ[k]) != None:
                                tPath = path.get(endQ[k])
                            tPath.append(perm_inverse(moves[j]))
                            sPath = []
                            if pathE.get(startQ[i]) != None:
                                sPath = pathE.get(startQ[i])
                            q = len(sPath) - 1
                            # Loops through the path oriented on the end in reverse appending it to the working path
                            while q >= 0:
                                tPath.append(perm_inverse(sPath[q]))
                                q -= 1
                            return tPath
                #This will check if we have already visited the current node and if we did not, we add its path to the
                #corresonding dictionary
                if adjList[j] not in visit:
                    heapq.heappush(visit, adjList[j]) #add to visit
                    heapq.heappush(nextQ, adjList[j]) #add to the next frontier
                    if fromStart: #If we are oriendted from the start
                        tPath = []
                        if path.get(startQ[i]) != None:
                            tPath = path.get(startQ[i])
                        tPath.append(moves[j])
                        nuPath = {adjList[j]: tPath}
                        path.update(nuPath)
                    else: #If we are oriendinted from the end/target
                        tPath = []
                        if path.get(startQ[i]) != None:
                            tPath = pathE.get(startQ[i])
                        tPath.append(moves[j])
                        nuPath = {adjList[j]: tPath}
                        pathE.update(nuPath)
        #This will flip the algorithm to either fuction from the start of the graph or the end
        if(len(nextQ) < len(endQ)):
            startQ = nextQ
        else:
            startQ = endQ
            endQ = nextQ
            if fromStart:
                fromStart = False
            else:
                fromStart = True

    return