# Path: tests/search/dummies.py
# class DummyProblem(object):
#     def actions(self, state):
#         return ['a', 'b', 'c'] if len(state) < len(GOAL) else []
# 
#     def result(self, state, action):
#         return state + action
# 
#     def is_goal(self, state):
#         return state == GOAL
# 
#     def heuristic(self, state):
#         # incorrect or missing actions
#         return (len(GOAL) - self.value(state)) - 1
# 
#     def value(self, state):
#         # correct actions
#         return sum(1 if state[i] == GOAL[i] else 0
#                    for i in range(min(len(GOAL), len(state)))) - 1
# 
#     def cost(self, state1, action, state2):
#         return 1
# 
#     def generate_random_state(self):
#         return 'i'
# 
# Path: simpleai/search/models.py
# class SearchNode(object):
#     '''Node of a search process.'''
# 
#     def __init__(self, state, parent=None, action=None, cost=0, problem=None,
#                  depth=0):
#         self.state = state
#         self.parent = parent
#         self.action = action
#         self.cost = cost
#         self.problem = problem or parent.problem
#         self.depth = depth
# 
#     def expand(self, local_search=False):
#         '''Create successors.'''
#         new_nodes = []
#         for action in self.problem.actions(self.state):
#             new_state = self.problem.result(self.state, action)
#             cost = self.problem.cost(self.state,
#                                      action,
#                                      new_state)
#             nodefactory = self.__class__
#             new_nodes.append(nodefactory(state=new_state,
#                                          parent=None if local_search else self,
#                                          problem=self.problem,
#                                          action=action,
#                                          cost=self.cost + cost,
#                                          depth=self.depth + 1))
#         return new_nodes
# 
#     def path(self):
#         '''Path (list of nodes and actions) from root to this node.'''
#         node = self
#         path = []
#         while node:
#             path.append((node.action, node.state))
#             node = node.parent
#         return list(reversed(path))
# 
#     def __eq__(self, other):
#         return isinstance(other, SearchNode) and self.state == other.state
# 
#     def state_representation(self):
#         return self.problem.state_representation(self.state)
# 
#     def action_representation(self):
#         return self.problem.action_representation(self.action)
# 
#     def __repr__(self):
#         return 'Node <%s>' % self.state_representation().replace('\n', ' ')
# 
#     def __hash__(self):
#         return hash((
#             self.state,
#             self.parent,
#             self.action,
#             self.cost,
#             self.depth,
#         ))
# 
# class SearchNodeCostOrdered(SearchNode):
#     def __lt__(self, other):
#         return self.cost < other.cost
# 
# class SearchNodeValueOrdered(SearchNode):
#     def __init__(self, *args, **kwargs):
#         super(SearchNodeValueOrdered, self).__init__(*args, **kwargs)
#         self.value = self.problem.value(self.state)
# 
#     def __lt__(self, other):
#         # value must work inverted, because heapq sorts 1-9
#         # and we need 9-1 sorting
#         return -self.value < -other.value
# 
# class SearchNodeHeuristicOrdered(SearchNode):
#     def __init__(self, *args, **kwargs):
#         super(SearchNodeHeuristicOrdered, self).__init__(*args, **kwargs)
#         self.heuristic = self.problem.heuristic(self.state)
# 
#     def __lt__(self, other):
#         return self.heuristic < other.heuristic
# 
# class SearchNodeStarOrdered(SearchNodeHeuristicOrdered):
#     def __lt__(self, other):
#         return self.heuristic + self.cost < other.heuristic + other.cost


import unittest
from tests.search.dummies import DummyProblem
from simpleai.search.models import (SearchNode, SearchNodeCostOrdered,
                                    SearchNodeValueOrdered,
                                    SearchNodeHeuristicOrdered,
                                    SearchNodeStarOrdered)
        self.assertFalse(n1 == n4)


class TestOrderedSearchNodeClasses(unittest.TestCase):
    def setUp(self):
        self.problem = DummyProblem()

    def test_search_node_cost_sorted(self):
        n1 = SearchNodeCostOrdered(problem=self.problem, state='i', cost=1)
        n2 = SearchNodeCostOrdered(problem=self.problem, state='i', cost=2)

        self.assertTrue(n1 < n2)
        self.assertFalse(n2 < n1)

    def test_search_node_value_sorted(self):
        n1 = SearchNodeValueOrdered(problem=self.problem, state='iab')
        n2 = SearchNodeValueOrdered(problem=self.problem, state='iba')

        self.assertTrue(n1 < n2)
        self.assertFalse(n2 < n1)

    def test_search_node_heuristic_sorted(self):
        n1 = SearchNodeHeuristicOrdered(problem=self.problem, state='iab')
        n2 = SearchNodeHeuristicOrdered(problem=self.problem, state='iba')

        self.assertTrue(n1 < n2)
        self.assertFalse(n2 < n1)

    def test_search_node_star_sorted(self):
        n1 = SearchNodeStarOrdered(problem=self.problem, state='iab', cost=1)

# Path: tests/search/dummies.py
# class DummyProblem(object):
#     def actions(self, state):
#         return ['a', 'b', 'c'] if len(state) < len(GOAL) else []
# 
#     def result(self, state, action):
#         return state + action
# 
#     def is_goal(self, state):
#         return state == GOAL
# 
#     def heuristic(self, state):
#         # incorrect or missing actions
#         return (len(GOAL) - self.value(state)) - 1
# 
#     def value(self, state):
#         # correct actions
#         return sum(1 if state[i] == GOAL[i] else 0
#                    for i in range(min(len(GOAL), len(state)))) - 1
# 
#     def cost(self, state1, action, state2):
#         return 1
# 
#     def generate_random_state(self):
#         return 'i'
# 
# Path: simpleai/search/models.py
# class SearchNode(object):
#     '''Node of a search process.'''
# 
#     def __init__(self, state, parent=None, action=None, cost=0, problem=None,
#                  depth=0):
#         self.state = state
#         self.parent = parent
#         self.action = action
#         self.cost = cost
#         self.problem = problem or parent.problem
#         self.depth = depth
# 
#     def expand(self, local_search=False):
#         '''Create successors.'''
#         new_nodes = []
#         for action in self.problem.actions(self.state):
#             new_state = self.problem.result(self.state, action)
#             cost = self.problem.cost(self.state,
#                                      action,
#                                      new_state)
#             nodefactory = self.__class__
#             new_nodes.append(nodefactory(state=new_state,
#                                          parent=None if local_search else self,
#                                          problem=self.problem,
#                                          action=action,
#                                          cost=self.cost + cost,
#                                          depth=self.depth + 1))
#         return new_nodes
# 
#     def path(self):
#         '''Path (list of nodes and actions) from root to this node.'''
#         node = self
#         path = []
#         while node:
#             path.append((node.action, node.state))
#             node = node.parent
#         return list(reversed(path))
# 
#     def __eq__(self, other):
#         return isinstance(other, SearchNode) and self.state == other.state
# 
#     def state_representation(self):
#         return self.problem.state_representation(self.state)
# 
#     def action_representation(self):
#         return self.problem.action_representation(self.action)
# 
#     def __repr__(self):
#         return 'Node <%s>' % self.state_representation().replace('\n', ' ')
# 
#     def __hash__(self):
#         return hash((
#             self.state,
#             self.parent,
#             self.action,
#             self.cost,
#             self.depth,
#         ))
# 
# class SearchNodeCostOrdered(SearchNode):
#     def __lt__(self, other):
#         return self.cost < other.cost
# 
# class SearchNodeValueOrdered(SearchNode):
#     def __init__(self, *args, **kwargs):
#         super(SearchNodeValueOrdered, self).__init__(*args, **kwargs)
#         self.value = self.problem.value(self.state)
# 
#     def __lt__(self, other):
#         # value must work inverted, because heapq sorts 1-9
#         # and we need 9-1 sorting
#         return -self.value < -other.value
# 
# class SearchNodeHeuristicOrdered(SearchNode):
#     def __init__(self, *args, **kwargs):
#         super(SearchNodeHeuristicOrdered, self).__init__(*args, **kwargs)
#         self.heuristic = self.problem.heuristic(self.state)
# 
#     def __lt__(self, other):
#         return self.heuristic < other.heuristic
# 
# class SearchNodeStarOrdered(SearchNodeHeuristicOrdered):
#     def __lt__(self, other):
#         return self.heuristic + self.cost < other.heuristic + other.cost


# Path: tests/search/test_models.py
import unittest
from tests.search.dummies import DummyProblem
from simpleai.search.models import (SearchNode, SearchNodeCostOrdered,
                                    SearchNodeValueOrdered,
                                    SearchNodeHeuristicOrdered,
                                    SearchNodeStarOrdered)

        self.assertFalse(n1 == n4)


class TestOrderedSearchNodeClasses(unittest.TestCase):
    def setUp(self):
        self.problem = DummyProblem()

    def test_search_node_cost_sorted(self):
        n1 = SearchNodeCostOrdered(problem=self.problem, state='i', cost=1)
        n2 = SearchNodeCostOrdered(problem=self.problem, state='i', cost=2)

        self.assertTrue(n1 < n2)
        self.assertFalse(n2 < n1)

    def test_search_node_value_sorted(self):
        n1 = SearchNodeValueOrdered(problem=self.problem, state='iab')
        n2 = SearchNodeValueOrdered(problem=self.problem, state='iba')

        self.assertTrue(n1 < n2)
        self.assertFalse(n2 < n1)

    def test_search_node_heuristic_sorted(self):
        n1 = SearchNodeHeuristicOrdered(problem=self.problem, state='iab')
        n2 = SearchNodeHeuristicOrdered(problem=self.problem, state='iba')

        self.assertTrue(n1 < n2)
        self.assertFalse(n2 < n1)

    def test_search_node_star_sorted(self):
        n1 = SearchNodeStarOrdered(problem=self.problem, state='iab', cost=1)

        n2 = SearchNodeStarOrdered(problem=self.problem, state='iba', cost=2)