user: def explore(start, goal, grid,visited, h=False):
    start.g = 0
    start.cost =start.h
    goal.g = math.inf
    heap = []
    steps = 0
    heapq.heappush(heap, (start.cost, start))

    while len(heap) > 0:
        u = heapq.heappop(heap)[1]
        goalPoint=[goal.row, goal.col]
        if visited[u.row][u.col]:
            continue
        visited[u.row][u.col] = True
        steps += 1
        if ([u.row, u.col] ==goalPoint) :
            goal.parent = u.parent
            found = True
            break

        for i in u.adjacent(grid):       
            if (visited[i[0]][i[1]] == True): 
                continue
            adj = Node(i[0], i[1], grid[i[0]][i[1]], parent=u)
            adj.g = u.g + 1
            if h == True:
                adj.h = adj.distance(goal)
            adj.cost = adj.g + adj.h
            heapq.heappush(heap, (adj.cost, adj))

    if found and h:
        print(f"It takes {steps} steps to find a path using A*")
    elif found and not h:
        print(f"It takes {steps} steps to find a path using Dijkstra")
    else:
        print("No path found")
    return goal, steps

assistant: This code defines a function called "explore" which finds a path from a given starting point to a given goal point on a grid. The function takes the following parameters:

*    "start": an instance of the "Node" class representing the starting point
*    "goal": an instance of the "Node" class representing the goal point
*    "grid": a 2D list representing the grid, where each element is either 0 or 1 (0 represents a free cell and 1 represents an obstacle)
*    "visited": a 2D list representing whether each cell has been visited or not (initially all values are False)
*    "h": a boolean indicating whether to use the A* algorithm (True) or Dijkstra's algorithm (False)

The function starts by setting the g-value (cost from the starting node to the current node) of the starting node to 0, and the g-value of the goal node to infinity. It then creates an empty heap and adds the starting node to it with a priority value based on its h-value (heuristic estimate of the cost from the current node to the goal node, if "h" is True) or just its g-value (if "h" is False).

The function then enters a loop where it repeatedly pops the node with the lowest priority value (i.e., the node that is closest to the goal according to the chosen algorithm) from the heap. If the popped node has already been visited, it is skipped. Otherwise, the function marks the node as visited and increments a counter "steps".

If the popped node is the goal node, the function sets the parent of the goal node to the parent of the current node, indicating the path that was found, and breaks out of the loop. Otherwise, the function considers each adjacent node of the current node and adds it to the heap with a priority value based on its g-value (cost from the starting node to the adjacent node) and h-value (if "h" is True).

Finally, if a path was found and "h" is True, the function prints the number of steps it took to find the path using A*, or if "h" is False, the function prints the number of steps it took to find the path using Dijkstra. If no path was found, the function simply prints "No path found". The function then returns the goal node and the number of steps taken to find the path.