예제 #1
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """

    frontier = QueueFrontier()
    frontier.add(Node(source, None, None))
    explored_states = set(source)

    while frontier.empty() is False:
        node = frontier.remove()

        if node.state == target:
            path = []
            while node.parent is not None:
                path.insert(0, (node.action, node.state))
                node = node.parent
            return path

        for movie_id, person_id in neighbors_for_person(node.state):
            if person_id not in explored_states:
                frontier.add(Node(person_id, node, movie_id))
                explored_states.add(person_id)

    return None
예제 #2
0
def shortest_path(source, goal):

    queue = QueueFrontier()
    source_movies = people[source]["movies"]

    for i in source_movies:
        temp_node = Node(source, None, i)
        queue.add(temp_node)

    while (queue.empty() != True):

        parent_node = queue.frontier[0]
        neighbours = neighbors_for_person(parent_node.state)
        answer = []
        push = answer.append

        for n in neighbours:
            temp_node = Node(n[1], parent_node, n[0])
            if temp_node.state == goal:
                while (temp_node.parent != None):
                    push((temp_node.action, temp_node.state))
                    temp_node = temp_node.parent
                return answer[::-1]
            else:
                response = any(x.state == temp_node.state
                               for x in queue.frontier)
                if (response == False):
                    queue.add(temp_node)
        queue.remove()
    return None
예제 #3
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """

    # keep track of number of node already explored
    num_explored = 0
    # initilize the explore set
    explore_set = set()

    # create a node which indicates the starting (source)
    start = Node(state=source, parent=None, action=None)
    # create frontier with the starting node using Stack Frontier
    frontier = QueueFrontier()
    # add starting node to frontier
    frontier.add(start)

    # keep trying till find target node
    while True:
        # if frontier is empty then no solution
        if frontier.empty():
            return None
        else:
            # get node from frontier: Stack -> LIFO
            node = frontier.remove()
            num_explored += 1

            # if found, trace back to the source
            if node.state == target:
                # list to store actions of each previous nodes
                actions = []
                # list to store states of each previous nodes
                cells = []
                while node.parent is not None:
                    actions.append(node.action)
                    cells.append(node.state)
                    node = node.parent
                actions.reverse()
                cells.reverse()
                solution = []
                for index in range(len(actions)):
                    solution.append((actions[index], cells[index]))
                print(f"Total Explored: {len(explore_set)}")
                return solution
            # if solution not found yet, explore the next node
            # record the previous node in explore_set (only person_id)
            explore_set.add(node.state)

            # add neighbors node to frontier
            for action, state in neighbors_for_person(node.state):
                if state == None or action == None:
                    return None
                elif not frontier.contains_state(
                        state) and state not in explore_set:
                    child = Node(state=state, parent=node, action=action)
                    # add child node to frontier
                    frontier.add(child)
예제 #4
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """

    # Make the initial state a node
    sourceNode = Node(source)
    targetNode = Node(target)

    # Add initial state node to frontier (using QueueFrontier for BFS)
    frontier = QueueFrontier()
    frontier.add(sourceNode)
    state_frontier = [sourceNode.get_state()]

    # Keep track of explored state
    explored = []

    while True:

        # If the frontier is empty, return None
        if frontier.empty():
            return None

        # Check if the goal state is in the frontier
        if targetNode.get_state() in state_frontier:
            consideredNode = frontier.target_found(targetNode)
            explored.append(consideredNode.get_state())

            # List for the path
            path = []

            # Trace back the path
            while consideredNode.get_parent() is not None:
                temp = (consideredNode.get_action(),
                        consideredNode.get_state())
                path.append(temp)
                consideredNode = consideredNode.get_parent()

            # Reverse the path and return it
            path.reverse()
            return path

        # Move one node in frontier to explored node (this node will now be considered)
        consideredNode = frontier.removeNode()
        explored.append(consideredNode.get_state())

        # Find the neighbour of the considered node that hasn't been explored and add them to the frontier
        for movie, neighbour in neighbors_for_person(
                consideredNode.get_state()):
            if not frontier.contains_state(
                    neighbour) and neighbour not in explored:
                neighbourNode = Node(neighbour, consideredNode, movie)
                frontier.add(neighbourNode)
                state_frontier.append(neighbourNode.get_state())

                if neighbour == targetNode.get_state():
                    targetNode = neighbourNode
예제 #5
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    explored = []
    frontier = QueueFrontier()

    for neighbor in neighbors_for_person(source):
        if neighbor[1] == target:
            return [neighbor]
        frontier.add(Node(neighbor[1], None, neighbor[0]))

    while True:
        if frontier.empty():
            return None

        node = frontier.remove()
        explored.append(node.state)
        for movie_id, person_id in neighbors_for_person(node.state):
            if person_id == target:
                target_node = Node(person_id, node, movie_id)
                return get_result(target_node)

            if person_id not in explored and not frontier.contains_state(
                    person_id):
                add_node = Node(person_id, node, movie_id)
                frontier.add(add_node)
예제 #6
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    # TODO

    frontier = QueueFrontier()
    frontier.add(Node(state=source, parent=None, action=None))

    explored = set()

    while True:
        if frontier.empty():
            return

        node = frontier.remove()
        explored.add(node.state)
        neighbors = neighbors_for_person(node.state)
        for actions, states in neighbors:
            if states not in explored and not frontier.contains_state(states):
                child = Node(state=states, parent=node, action=actions)
                if child.state == target:
                    path = []
                    node = child
                    while node.parent is not None:
                        path.append((node.action, node.state))
                        node = node.parent

                    path.reverse()
                    return path
                frontier.add(child)
    raise NotImplementedError
예제 #7
0
def shorpath(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    frontier = QueueFrontier()
    # Source node storing the actor/actress id in the state, no parent, and no actions has been applied yet
    node = Node(source, None, None)
    # Add the source node to our frontier
    frontier.add(node)

    while True:
        # Node for checking
        node = frontier.remove()
        # Check if the popped node is the target
        if node.state == target:
            # Start backtracking the node until we reach our source node
            path = []
            while node.parent is not None:
                path.append((node.action, node.state))
                node = node.parent
            path.reverse()
            return path
        # If the popped node is not the target, let's check for its neighbors
        else:
            neighbors = neighbors_for_person(node.state)
            for neighbor in neighbors:
                # Let's add the actor/actress to our frontier as long as they haven't been added already
                if not frontier.contains_state(neighbor[1]):
                    frontier.add(Node(neighbor[1], node, neighbor[0]))
        # If there are no nodes left in our frontier, that means we have exhausted all our neighbors, and therefore, there is no connection
        if frontier.empty():
            return None
예제 #8
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """

    num_explored = 0

    # Initialize frontier to just the starting position
    start = Node(state=source, parent=None, action=None)
    # Use a Queue for BFS
    frontier = QueueFrontier()
    frontier.add(start)

    # Initialize an empty explored set
    explored = set()
    # Initialize the solution as None if no solution is found
    solution = None

    # Keep looping until solution found
    while True:

        # If nothing left in frontier, then no path
        if frontier.empty():
            return solution

        # Choose a node from the frontier
        node = frontier.remove()
        num_explored += 1

        # If node is the goal, then we have a solution
        if node.state == target:
            # Actions are the movies
            actions = []
            # Cells are the people in the movies
            cells = []
            # Traverse backwards through the parents to find the connection
            while node.parent is not None:
                actions.append(node.action)
                cells.append(node.state)
                node = node.parent
            # Reverse the actions and cells because algorithm is traversing backwards
            actions.reverse()
            cells.reverse()
            # Zip them into a list of tuple pairs
            solution = list(zip(actions, cells))
            return solution

        # Mark node as explored
        explored.add(node.state)

        # Add neighbors to frontier
        for action, state in neighbors_for_person(node.state):
            if not frontier.contains_state(state) and state not in explored:
                child = Node(state=state, parent=node, action=action)
                frontier.add(child)

    return solution
예제 #9
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    frontier = QueueFrontier()
    source_node = Node(parent=None, action=None, state=source)
    frontier.add(source_node)
    explored = set()
    counter = 0
    present = source
    while True:
        if frontier.empty():
            print("It's empty!")
            return None
        node = frontier.remove()
        if node.state == target:
            actions = []
            while node.parent is not None:
                actions.append((node.action, node.state))
                node = node.parent
            actions.reverse()
            return actions

        explored.add(node.state)

        for movie_id, person_id in neighbors_for_person(node.state):
            if not frontier.contains_state(
                    person_id) and person_id not in explored:
                child = Node(state=person_id, action=movie_id, parent=node)
                frontier.add(child)
예제 #10
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    source_node = Node(source, None, None)
    target_node = Node(target, None, None)

    frontier = QueueFrontier()
    frontier.add(source_node)
    explored = {}
    a = False
    while (not frontier.empty()):
        suspect = frontier.remove()
        if (suspect.state == target_node.state):
            a = True
            break
        if suspect.state not in explored:
            explored[suspect.state] = suspect
            actions = neighbors_for_person(suspect.state)
        for i, j in actions:
            frontier.add(Node(j, suspect.state, i))
    if (a):
        solution = []
        current = suspect
        while (current.state != source_node.state):
            solution.insert(0, (current.action, current.state))
            current = explored[current.parent]
        return solution
    else:
        return None
예제 #11
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    frontier = QueueFrontier()
    #frontier = StackFrontier()
    explored = set()
    path = []
    if source == target:
        return path
    frontier.add(Node(source, None, None))

    while True:
        if frontier.empty():
            return None

        node = frontier.remove()
        explored.add(node.state)

        for action, child in neighbors_for_person(node.state):
            if child == target:
                path.append((action, child))
                while node.parent != None:
                    parent_action, parent_state = node.action, node.state
                    path.append((parent_action, parent_state))
                    node = node.parent
                path.reverse()
                return path

            if not frontier.contains_state(child) and (child not in explored):
                frontier.add(Node(child, node, action))
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """

    shorpath = []
    queueFrontier = QueueFrontier()
    queueFrontier.add(Node(source, None, None))
    n = 0
    while (True):
        n += 1
        if queueFrontier.empty():
            return None

        current = queueFrontier.remove()

        if current.state == target:
            while (True):
                shorpath.append([current.action, current.state])
                if current.parent.state == source:
                    break
                current = current.parent

            print(n)
            return shorpath

        expand = neighbors_for_person(current.state)
        lis = list(expand)
        for i in lis:
            node = Node(i[1], current, i[0])
            queueFrontier.add(node)
예제 #13
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    frontier = QueueFrontier()
    explored = []

    source_node = Node(source, None, None)
    frontier.add(source_node)

    while not frontier.empty():

        node = frontier.remove()

        if node.person == target:
            return find_path(node)
            
        else:
            explored.append(node.person)

            for movie, person in neighbors_for_person(node.person):
                if not frontier.contains_person(person) and person not in explored:
                    child = Node(person, node, movie)
                    frontier.add(child)
    return None
예제 #14
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """

    start = Node(state=source, parent=None, action=None)
    frontier = QueueFrontier()
    frontier.add(start)

    explored = set()

    while True:
        if frontier.empty():
            return None

        node = frontier.remove()

        explored.add(node.state)

        for action, state in neighbors_for_person(node.state):
            if not frontier.contains_state(state) and state not in explored:
                child = Node(state=state, parent=node, action=action)
                goal = goal_test(child, target)
                if goal:
                    return goal
                frontier.add(child)

    return None
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    path = list()
    initial = Node(source, None, None)
    explored = set()
    frontier = QueueFrontier()
    frontier.add(initial)
    while True:
        if frontier.empty():
            return None
        node = frontier.remove()
        explored.add(node.state)
        co_stars = neighbors_for_person(node.state)
        for co_star in co_stars:
            if co_star[1] not in explored and not frontier.contains_state(
                    co_star[1]):
                if co_star[1] == target:
                    path.append(co_star)
                    while not node.parent == None:
                        path.append((node.action, node.state))
                        node = node.parent
                    path.reverse()
                    return path
                else:
                    frontier.add(Node(co_star[1], node, co_star[0]))
예제 #16
0
파일: degrees.py 프로젝트: 5pandan8/CS50
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """

    # Keeps track of number of states explored
    num_explored = 0

    # Initiate the frontier to the start state
    start = Node(state=source, parent=None, action=None)
    frontier = QueueFrontier()
    frontier.add(start)

    # Initiate an empty explored set
    explored = set()

    # Keep looping until solution found
    while True:

        # If nothing in frontier, then no path
        if frontier.empty():
            return None

        # Choose a node from the frontier
        node = frontier.remove()
        num_explored += 1

        # If node is the goal, then we have a solution
        if node.state == target:
            solution = []

            # Follow parent nodes to find solution
            while node.parent is not None:
                solution.append((node.action, node.state))
                node = node.parent
            solution.reverse()
            return solution

        # Mark node as explored
        explored.add(node.state)

        # Add neighbours to the frontier
        for movie, actor in neighbors_for_person(node.state):
            if not frontier.contains_state(actor) and actor not in explored:
                child = Node(state=actor, parent=node, action=movie)
                if child.state == target:
                    solution = []
                    # Follow parent nodes to find solution
                    while child.parent is not None:
                        solution.append((child.action, child.state))
                        child = child.parent
                    solution.reverse()
                    return solution
                frontier.add(child)

    # TODO
    raise NotImplementedError
예제 #17
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    frontier = QueueFrontier()
    frontier.add(Node(source, None, None))
    explored = set()

    while True:
        if frontier.empty():
            return None

        node = frontier.remove()
        if node.state == target:
            path = []
            while node.parent is not None:
                path.append((node.action, node.state))
                node = node.parent
            path.reverse()
            return path

        explored.add(node.state)

        for (movie_id, person_id) in neighbors_for_person(node.state):
            if (not frontier.contains_state(person_id)) and (person_id
                                                             not in explored):
                child = Node(person_id, node, movie_id)
                frontier.add(child)
예제 #18
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    node = Node(source, None, None)
    frontier = QueueFrontier()
    frontier.add(node)
    explored = set()

    while True:
        if frontier.empty():
            return None

        node = frontier.remove()
        explored.add(node)
        neighbors = neighbors_for_person(node.state)
        for movies, person in neighbors:
            if person not in explored and not frontier.contains_state(person):
                child = Node(state=person, parent=node, action=movies)
                if child.state == target:
                    path = []
                    while child.parent is not None:
                        path.append((child.action, child.state))
                        child = child.parent
                    path.reverse()
                    return path
                frontier.add(child)
예제 #19
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    if source == target:
        raise Exception("Target must be different from source")

    visited = set()
    frontier = QueueFrontier()
    frontier.add(Node(source, None, None))

    while not frontier.empty():
        parent_node = frontier.remove()
        for movie, person in neighbors_for_person(parent_node.state):
            if person not in visited and not frontier.contains_state(person):
                child_node = Node(person, parent_node, movie)
                if not child_node.state == target:
                    frontier.add(child_node)
                else:
                    path = list()
                    while child_node.parent is not None:
                        path.append((child_node.action, child_node.state))
                        child_node = child_node.parent
                    path.reverse()
                    return path
        visited.add(parent_node.state)
    return None
예제 #20
0
def shortest_path(source, target):

    frontier = QueueFrontier()
    frontier.add(Node(source, None, None))

    explored = set()

    if source == target:
        raise Exception("source should not be target")

    while True:
        if frontier.empty():
            return None
        node = frontier.remove()
        if node.state == target:
            answer = []
            while node.parent is not None:
                answer.append((node.action, node.state))
                node = node.parent
            answer.reverse()
            return answer
        explored.add(node.state)
        for movie_id, person_id in neighbors_for_person(node.state):
            if (not frontier.contains_state(person_id)) and (person_id
                                                             not in explored):
                child = Node(state=person_id, parent=node, action=movie_id)
                frontier.add(child)
예제 #21
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.
    If no possible path, returns None.
    """

    frontier = QueueFrontier()
    frontier.add(Node(source, None, None))
    explored = set()
    # source and target cannot be same.
    if source == target:
        raise Exception("Source cannot be same as target")

    while True:
        if frontier.empty():
            return None
        node = frontier.remove()
        if node.state == target:
            connection = []
            while node.parent is not None:
                connection.append((node.action, node.state))
                node = node.parent
            connection.reverse()
            return connection
        explored.add(node.state)
        for movie_id, person_id in neighbors_for_person(node.state):
            if (not frontier.contains_state(person_id)) and (person_id
                                                             not in explored):
                child = Node(state=person_id, parent=node, action=movie_id)
                frontier.add(child)
예제 #22
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    initialState = Node(source, None, people[source].get('movies'))
    frontier = QueueFrontier()
    frontier.add(initialState)
    while not (frontier.empty()):
        dequeue = frontier.remove()
        if dequeue.state == target:
            return shortest_path_list(dequeue)
        neighbors = neighbors_for_person(dequeue.state)
        if len(neighbors) == 0:
            return None
        for x in neighbors:
            if x[1] == target:
                targetNode = Node(x[1], dequeue, x[0])
                return shortest_path_list(targetNode)
            if frontier.discovered_tuple(x) == 0:
                neighborNode = Node(x[1], dequeue, x[0])
                frontier.add(neighborNode)
    return None
예제 #23
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """

    start = Node(state=source, parent=None, action=None)
    frontier = QueueFrontier()
    frontier.add(start)

    explored = set()

    while True:
        if frontier.empty():
            raise Exception("no solution")

        node = frontier.remove()

        if node.state == target:
            result = []
            while node.parent is not None:
                mov_person = (node.action, node.state)
                result.append(mov_person)
                node = node.parent
            result.reverse()
            return result

        explored.add(node.state)

        for movie, state in neighbors_for_person(node.state):
            if not frontier.contains_state(state) and state not in explored:
                child = Node(state=state, parent=node, action=movie)
                frontier.add(child)
예제 #24
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """

    # Initialize frontier to just the starting position
    start = Node(state=source, parent=None, action=None)
    stack_frontier = StackFrontier()
    queue_frontier = QueueFrontier()
    stack_frontier.add(start)
    queue_frontier.add(start)

    # Count length in path for both technicks to determine the shortest one
    stack_frontier_path = []
    queue_frontier_path = []

    #Keep looping until solution found
    stack_frontier_path = search_frontier(stack_frontier, stack_frontier_path,
                                          target)
    queue_frontier_path = search_frontier(queue_frontier, queue_frontier_path,
                                          target)

    if len(stack_frontier_path) <= len(queue_frontier_path) and len(
            stack_frontier_path) != 0:
        return stack_frontier_path
    elif len(queue_frontier_path) != 0:
        return queue_frontier_path
    else:
        return None
예제 #25
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    frontier = QueueFrontier()
    start = Node(source, parent=None, action=None)
    frontier.add(start)
    while True:
        if frontier.empty():
            return None

        node = frontier.remove()

        for neighbor in neighbors_for_person(node.state):
            newNode = Node(neighbor[1], node, neighbor[0])
            if neighbor[1] == target:
                path = []
                while newNode.parent is not None:
                    path.append((newNode.action, newNode.state))
                    newNode = newNode.parent
                path.reverse()
                return path
            frontier.add(newNode)
예제 #26
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """

    frontier = QueueFrontier()
    frontier.add(Node(state=source, parent=None, action=None))
    explored = set()

    if (source == target):
        raise Exception("Both names are same")

    while not frontier.empty():
        test = frontier.remove()
        explored.add(test.state)
        for movie_id, person_id in neighbors_for_person(test.state):
            if not (person_id in explored):
                child = Node(person_id, test, movie_id)
                frontier.add(child)
                if child.state == target:
                    solution = []
                    while child.parent is not None:
                        solution.append((child.action, child.state))
                        child = child.parent
                    solution.reverse()
                    return solution
    return None
예제 #27
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.

    """
    explored = []
    path = []
    node = Node(source, None, None)
    frontier = QueueFrontier()
    frontier.add(node)
    targetNotReached = True
    
    while (targetNotReached): 
        node = frontier.remove()
        possiblePaths = neighbors_for_person(node.state)
        explored.append(node)

        for step in possiblePaths:
            if (step[1] == source):
                continue
            node = Node(step[1], explored[len(explored)-1], step[0])
            frontier.add(node)
            if (node.state == target):
                targetNotReached = False
                break       

    while (node.state != source):
        path.insert(0, (node.action, node.state))
        node = node.parent

    return path
예제 #28
0
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    num_explored = 0

    start = Node(state=source, parent=None, action=None)

    frontier = QueueFrontier()
    frontier.add(start)

    explored = set()

    while True:
        if frontier.empty():
            raise Exception("No solution")\

        node = frontier.remove()
        num_explored += 1
        if node.state == target:
            return build_result(node)

        explored.add(node.state)
        # status_update(num_explored)
        for action, state in neighbors_for_person(node.state):
            if not frontier.contains_state(state) and state not in explored:
                child = Node(state=state, parent=node, action=action)
                if child.state == target:
                    return build_result(child)
                else:    
                    frontier.add(child)   
def shortest_path(source, target):
    """
    Returns the shortest list of (movie_id, person_id) pairs
    that connect the source to the target.

    If no possible path, returns None.
    """
    # TODO
    res = []
    Queue = QueueFrontier()
    start = Node(source, None, None)
    Queue.add(start)
    Explored_set = set()
    while True:
        if Queue.empty():
            return None

        node = Queue.remove()
        state = node.state
        Explored_set.add(state)

        for movie in people[state]['movies']:
            for person in movies[movie]['stars']:
                if person not in Explored_set:
                    if person == target:
                        res.append((movie, person))
                        while node.parent is not None:
                            res.append((node.action, node.state))
                            node = node.parent
                        res.reverse()

                        return res
                    else:
                        child = Node(person, node, movie)
                        Queue.add(child)
def shortest_path(source, target):
    start = Node(state=source, parent=None, action=None)
    frontier = QueueFrontier()
    frontier.add(start)
    
    
    explored = set()
    explored_count = 0

    
    while True:

        # If nothing left in the frontier, then no path
        if frontier.empty():
            return None
        node = frontier.remove()
        neighbors = neighbors_for_person(node.state)

        for movie, actor in neighbors:
            if actor not in explored and not frontier.contains_state(actor):
                child = Node(state=actor, parent=node, action=movie)
                frontier.add(child)
                print(f" actor is {child.state} in movies {child.action}")
                
                if child.state == target:
                    path = []
                    while child.parent is not None:
                        path.append((child.action,child.state))
                        child = child.parent
                    path.reverse()
                    return path
        
            #node = frontier.remove()
            explored_count += 1
            explored.add(node.state)