def search(problem, pop, push):
    """
    a generic solution for searching for a goal state in a problem given the frontier strategy implemented in pop and push functions
    :param problem: the problem
    :param pop: a function to get and remove next state from frontier
    :param push: a function to push a state to the frontier
    :return: list of actions to get to a goal state
    """
    state = problem.getStartState()
    if problem.isGoalState(state):
        return []
    actions = []
    problem.explore(state)
    while True:
        successors = problem.getSuccessors(actions, state)
        for a, s in successors:
            actionsHistory = actions + [a]
            push(actionsHistory, s)
        while problem.isExplored(state):
            next = pop()
            if not next:
                return None
            actions, state = next
        if problem.isGoalState(state):
            return actions
        problem.explore(state)
    return None
