class Problem(object):
    """ An abstract problem is modeled by this elements:
        - Initial State : The initial State of the world for the problem
        - Goal Test : goal_test(s) function that checks if the state s is in the final states list
        - Actions: specified by actions_in(s), A set of possible actions to be executed in the state s
        - Transition model : specified by result(s,a) that return a new state generated by applying action a to state s
        - Cost Function: function that allow to extimate the cost of a path
        - Step Cost: specified by step_cost(s,a,s1), represent the cost of taking action a in state s to reach 
        state s
    """

    def __init__(self, initial_state, goal_state=None):
        """ Initialize a new Problem with an initial state and a set of goal states."""
        self.initial_state = initial_state
        self.goal_state = goal_state

    def actions(self, state):
        """ Given a particular state s, actions_in(s) returns the set of actions that can be executed in s. Each of 
        these actions is applicable in s."""
        raise NotImplementedError

    def result(self, state, action):
        """ Returns a new state generated by applying the given action to te given state."""
        raise NotImplementedError

    def goal_test(self, state):
        """ Returns true if the given state is in the list of the final states.
         If the final state is only one, then the function return true only if the given state is equal to it."""
        if isinstance(self.goal_state, list):
            return state in self.goal_state
        return self.goal_state == state

    def step_cost(self, c, state1=None, action=None, state2=None):
        """ Returns an integer representing the cost of taking action a in state s1 to reach state s2"""
        return c + 1

    def solve_problem(self, actions):
        print("\nInitial State:\n")
        print(self.initial_state)
        print("\nGoal State   :\n")
        print(self.goal_state)
        state = self.initial_state
        for action in actions:
            print("\n")
            state = self.result(state, action)
            print(state)

    @staticmethod
    def same_state(state1, state2):
        """ Return true if state1 is equal to state2 """
        return state1.__eq__(state2)
