Advertisement
dzocesrce

[VI] Snake

Apr 16th, 2024
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 19.08 KB | None | 0 0
  1. import bisect
  2.  
  3. """
  4. Defining a class for the problem structure that we will solve with a search.
  5. The Problem class is an abstract class from which we make inheritance to define the basic
  6. characteristics of every problem we want to solve
  7. """
  8.  
  9.  
  10. class Problem:
  11.     def __init__(self, initial, goal=None):
  12.         self.initial = initial
  13.         self.goal = goal
  14.  
  15.     def successor(self, state):
  16.         """Given a state, return a dictionary of {action : state} pairs reachable
  17.        from this state. If there are many successors, consider an iterator
  18.        that yields the successors one at a time, rather than building them
  19.        all at once.
  20.  
  21.        :param state: given state
  22.        :return:  dictionary of {action : state} pairs reachable
  23.                  from this state
  24.        :rtype: dict
  25.        """
  26.         raise NotImplementedError
  27.  
  28.     def actions(self, state):
  29.         """Given a state, return a list of all actions possible
  30.        from that state
  31.  
  32.        :param state: given state
  33.        :return: list of actions
  34.        :rtype: list
  35.        """
  36.         raise NotImplementedError
  37.  
  38.     def result(self, state, action):
  39.         """Given a state and action, return the resulting state
  40.  
  41.        :param state: given state
  42.        :param action: given action
  43.        :return: resulting state
  44.        """
  45.         raise NotImplementedError
  46.  
  47.     def goal_test(self, state):
  48.         """Return True if the state is a goal. The default method compares
  49.        the state to self.goal, as specified in the constructor. Implement
  50.        this method if checking against a single self.goal is not enough.
  51.  
  52.        :param state: given state
  53.        :return: is the given state a goal state
  54.        :rtype: bool
  55.        """
  56.         return state == self.goal
  57.  
  58.     def path_cost(self, c, state1, action, state2):
  59.         """Return the cost of a solution path that arrives at state2 from state1
  60.        via action, assuming cost c to get up to state1. If the problem is such
  61.        that the path doesn't matter, this function will only look at state2.
  62.        If the path does matter, it will consider c and maybe state1 and action.
  63.        The default method costs 1 for every step in the path.
  64.  
  65.        :param c: cost of the path to get up to state1
  66.        :param state1: given current state
  67.        :param action: action that needs to be done
  68.        :param state2: state to arrive to
  69.        :return: cost of the path after executing the action
  70.        :rtype: float
  71.        """
  72.         return c + 1
  73.  
  74.     def value(self):
  75.         """For optimization problems, each state has a value.
  76.        Hill-climbing and related algorithms try to maximize this value.
  77.  
  78.        :return: state value
  79.        :rtype: float
  80.        """
  81.         raise NotImplementedError
  82.  
  83.  
  84. """
  85. Definition of the class for node structure of the search.
  86. The class Node is not inherited
  87. """
  88.  
  89.  
  90. class Node:
  91.     def __init__(self, state, parent=None, action=None, path_cost=0):
  92.         """Create node from the search tree,  obtained from the parent by
  93.        taking the action
  94.  
  95.        :param state: current state
  96.        :param parent: parent state
  97.        :param action: action
  98.        :param path_cost: path cost
  99.        """
  100.         self.state = state
  101.         self.parent = parent
  102.         self.action = action
  103.         self.path_cost = path_cost
  104.         self.depth = 0  # search depth
  105.         if parent:
  106.             self.depth = parent.depth + 1
  107.  
  108.     def __repr__(self):
  109.         return "<Node %s>" % (self.state,)
  110.  
  111.     def __lt__(self, node):
  112.         return self.state < node.state
  113.  
  114.     def expand(self, problem):
  115.         """List the nodes reachable in one step from this node.
  116.  
  117.        :param problem: given problem
  118.        :return: list of available nodes in one step
  119.        :rtype: list(Node)
  120.        """
  121.         return [self.child_node(problem, action)
  122.                 for action in problem.actions(self.state)]
  123.  
  124.     def child_node(self, problem, action):
  125.         """Return a child node from this node
  126.  
  127.        :param problem: given problem
  128.        :param action: given action
  129.        :return: available node  according to the given action
  130.        :rtype: Node
  131.        """
  132.         next_state = problem.result(self.state, action)
  133.         return Node(next_state, self, action,
  134.                     problem.path_cost(self.path_cost, self.state,
  135.                                       action, next_state))
  136.  
  137.     def solution(self):
  138.         """Return the sequence of actions to go from the root to this node.
  139.  
  140.        :return: sequence of actions
  141.        :rtype: list
  142.        """
  143.         return [node.action for node in self.path()[1:]]
  144.  
  145.     def solve(self):
  146.         """Return the sequence of states to go from the root to this node.
  147.  
  148.        :return: list of states
  149.        :rtype: list
  150.        """
  151.         return [node.state for node in self.path()[0:]]
  152.  
  153.     def path(self):
  154.         """Return a list of nodes forming the path from the root to this node.
  155.  
  156.        :return: list of states from the path
  157.        :rtype: list(Node)
  158.        """
  159.         x, result = self, []
  160.         while x:
  161.             result.append(x)
  162.             x = x.parent
  163.         result.reverse()
  164.         return result
  165.  
  166.     """We want the queue of nodes at breadth_first_search or
  167.    astar_search to not contain states-duplicates, so the nodes that
  168.    contain the same condition we treat as the same. [Problem: this can
  169.    not be desirable in other situations.]"""
  170.  
  171.     def __eq__(self, other):
  172.         return isinstance(other, Node) and self.state == other.state
  173.  
  174.     def __hash__(self):
  175.         return hash(self.state)
  176.  
  177.  
  178. """
  179. Definitions of helper structures for storing the list of generated, but not checked nodes
  180. """
  181.  
  182.  
  183. class Queue:
  184.     """Queue is an abstract class/interface. There are three types:
  185.        Stack(): Last In First Out Queue (stack).
  186.        FIFOQueue(): First In First Out Queue.
  187.        PriorityQueue(order, f): Queue in sorted order (default min-first).
  188.    """
  189.  
  190.     def __init__(self):
  191.         raise NotImplementedError
  192.  
  193.     def append(self, item):
  194.         """Adds the item into the queue
  195.  
  196.        :param item: given element
  197.        :return: None
  198.        """
  199.         raise NotImplementedError
  200.  
  201.     def extend(self, items):
  202.         """Adds the items into the queue
  203.  
  204.        :param items: given elements
  205.        :return: None
  206.        """
  207.         raise NotImplementedError
  208.  
  209.     def pop(self):
  210.         """Returns the first element of the queue
  211.  
  212.        :return: first element
  213.        """
  214.         raise NotImplementedError
  215.  
  216.     def __len__(self):
  217.         """Returns the number of elements in the queue
  218.  
  219.        :return: number of elements in the queue
  220.        :rtype: int
  221.        """
  222.         raise NotImplementedError
  223.  
  224.     def __contains__(self, item):
  225.         """Check if the queue contains the element item
  226.  
  227.        :param item: given element
  228.        :return: whether the queue contains the item
  229.        :rtype: bool
  230.        """
  231.         raise NotImplementedError
  232.  
  233.  
  234. class Stack(Queue):
  235.     """Last-In-First-Out Queue."""
  236.  
  237.     def __init__(self):
  238.         self.data = []
  239.  
  240.     def append(self, item):
  241.         self.data.append(item)
  242.  
  243.     def extend(self, items):
  244.         self.data.extend(items)
  245.  
  246.     def pop(self):
  247.         return self.data.pop()
  248.  
  249.     def __len__(self):
  250.         return len(self.data)
  251.  
  252.     def __contains__(self, item):
  253.         return item in self.data
  254.  
  255.  
  256. class FIFOQueue(Queue):
  257.     """First-In-First-Out Queue."""
  258.  
  259.     def __init__(self):
  260.         self.data = []
  261.  
  262.     def append(self, item):
  263.         self.data.append(item)
  264.  
  265.     def extend(self, items):
  266.         self.data.extend(items)
  267.  
  268.     def pop(self):
  269.         return self.data.pop(0)
  270.  
  271.     def __len__(self):
  272.         return len(self.data)
  273.  
  274.     def __contains__(self, item):
  275.         return item in self.data
  276.  
  277.  
  278. class PriorityQueue(Queue):
  279.     """A queue in which the minimum (or maximum) element is returned first
  280.     (as determined by f and order). This structure is used in
  281.     informed search"""
  282.  
  283.     def __init__(self, order=min, f=lambda x: x):
  284.         """
  285.        :param order: sorting function, if order is min, returns the element
  286.                      with minimal f (x); if the order is max, then returns the
  287.                      element with maximum f (x).
  288.        :param f: function f(x)
  289.        """
  290.         assert order in [min, max]
  291.         self.data = []
  292.         self.order = order
  293.         self.f = f
  294.  
  295.     def append(self, item):
  296.         bisect.insort_right(self.data, (self.f(item), item))
  297.  
  298.     def extend(self, items):
  299.         for item in items:
  300.             bisect.insort_right(self.data, (self.f(item), item))
  301.  
  302.     def pop(self):
  303.         if self.order == min:
  304.             return self.data.pop(0)[1]
  305.         return self.data.pop()[1]
  306.  
  307.     def __len__(self):
  308.         return len(self.data)
  309.  
  310.     def __contains__(self, item):
  311.         return any(item == pair[1] for pair in self.data)
  312.  
  313.     def __getitem__(self, key):
  314.         for _, item in self.data:
  315.             if item == key:
  316.                 return item
  317.  
  318.     def __delitem__(self, key):
  319.         for i, (value, item) in enumerate(self.data):
  320.             if item == key:
  321.                 self.data.pop(i)
  322.  
  323.  
  324. """
  325. Uninformed graph search
  326. The main difference is that here we do not allow loops,
  327. i.e. repetition of states
  328. """
  329.  
  330.  
  331. def graph_search(problem, fringe):
  332.     """Search through the successors of a problem to find a goal.
  333.     If two paths reach a state, only use the best one.
  334.  
  335.    :param problem: given problem
  336.    :param fringe: empty queue
  337.    :return: Node
  338.    """
  339.     closed = {}
  340.     fringe.append(Node(problem.initial))
  341.     while fringe:
  342.         node = fringe.pop()
  343.         if problem.goal_test(node.state):
  344.             return node
  345.         if node.state not in closed:
  346.             closed[node.state] = True
  347.             fringe.extend(node.expand(problem))
  348.     return None
  349.  
  350.  
  351. def breadth_first_graph_search(problem):
  352.     """Search the shallowest nodes in the search tree first.
  353.  
  354.    :param problem: given problem
  355.    :return: Node
  356.    """
  357.     return graph_search(problem, FIFOQueue())
  358.  
  359.  
  360. class Snake(Problem):
  361.  
  362.     def __init__(self, initial, red_apples, goal=None):
  363.         super().__init__(initial, goal)
  364.         self.red_apples = red
  365.  
  366.     def successor(self, state):
  367.         successors = dict()
  368.  
  369.         snake = state[0]
  370.         green_apples = state[1]
  371.         orientation = state[2]
  372.  
  373.         new_snake, new_apples, new_orientation = ProdolzhiPravo(snake, green_apples, self.red_apples, orientation)
  374.         if new_snake != snake:
  375.             successors['ProdolzhiPravo'] = (new_snake, new_apples, new_orientation)
  376.  
  377.         new_snake, new_apples, new_orientation = SvrtiDesno(snake, green_apples, self.red_apples, orientation)
  378.         if new_snake != snake:
  379.             successors['SvrtiDesno'] = (new_snake, new_apples, new_orientation)
  380.  
  381.         new_snake, new_apples, new_orientation = SvrtiLevo(snake, green_apples, self.red_apples, orientation)
  382.         if new_snake != snake:
  383.             successors['SvrtiLevo'] = (new_snake, new_apples, new_orientation)
  384.  
  385.         return successors
  386.  
  387.     def actions(self, state):
  388.         return self.successor(state).keys()
  389.  
  390.     def result(self, state, action):
  391.         return self.successor(state)[action]
  392.  
  393.     def goal_test(self, state):
  394.         return len(state[1]) == 0
  395.  
  396.  
  397. def ProdolzhiPravo(snake, green_apples, red_apples, orientation):
  398.     head = snake[-1]
  399.     if orientation == 'dolu':
  400.         if head[1] - 1 >= 0 and (head[0], head[1] - 1) not in red_apples and (head[0], head[1] - 1) not in snake:
  401.             snake = list(snake)
  402.             snake.append((head[0], head[1] - 1))
  403.  
  404.             if (head[0], head[1] - 1) in green_apples:
  405.                 green_apples = list(green_apples)
  406.                 green_apples = [x for x in green_apples if x not in snake]
  407.                 green_apples = tuple(green_apples)
  408.             else:
  409.                 snake = snake[1:]
  410.             snake = tuple(snake)
  411.     elif orientation == 'gore':
  412.         if head[1] + 1 < 10 and (head[0], head[1] + 1) not in red_apples and (head[0], head[1] + 1) not in snake:
  413.             snake = list(snake)
  414.             snake.append((head[0], head[1] + 1))
  415.  
  416.             if (head[0], head[1] + 1) in green_apples:
  417.                 green_apples = list(green_apples)
  418.                 green_apples = [x for x in green_apples if x not in snake]
  419.                 green_apples = tuple(green_apples)
  420.             else:
  421.                 snake = snake[1:]
  422.             snake = tuple(snake)
  423.     elif orientation == 'desno':
  424.         if head[0] + 1 < 10 and (head[0] + 1, head[1]) not in red_apples and (head[0] + 1, head[1]) not in snake:
  425.             snake = list(snake)
  426.             snake.append((head[0] + 1, head[1]))
  427.  
  428.             if (head[0] + 1, head[1]) in green_apples:
  429.                 green_apples = list(green_apples)
  430.                 green_apples = [x for x in green_apples if x not in snake]
  431.                 green_apples = tuple(green_apples)
  432.             else:
  433.                 snake = snake[1:]
  434.             snake = tuple(snake)
  435.     elif orientation == 'levo':
  436.         if head[0] - 1 >= 0 and (head[0] - 1, head[1]) not in red_apples and (head[0] - 1, head[1]) not in snake:
  437.             snake = list(snake)
  438.             snake.append((head[0] - 1, head[1]))
  439.  
  440.             if (head[0] - 1, head[1]) in green_apples:
  441.                 green_apples = list(green_apples)
  442.                 green_apples = [x for x in green_apples if x not in snake]
  443.                 green_apples = tuple(green_apples)
  444.             else:
  445.                 snake = snake[1:]
  446.             snake = tuple(snake)
  447.  
  448.     return snake, green_apples, orientation
  449.  
  450.  
  451. def SvrtiDesno(snake, green_apples, red_apples, orientation):
  452.     head = snake[-1]
  453.     if orientation == 'desno':
  454.         if head[1] - 1 >= 0 and (head[0], head[1] - 1) not in red_apples and (head[0], head[1] - 1) not in snake:
  455.             snake = list(snake)
  456.             snake.append((head[0], head[1] - 1))
  457.  
  458.             if (head[0], head[1] - 1) in green_apples:
  459.                 green_apples = list(green_apples)
  460.                 green_apples = [x for x in green_apples if x not in snake]
  461.                 green_apples = tuple(green_apples)
  462.             else:
  463.                 snake = snake[1:]
  464.             snake = tuple(snake)
  465.             orientation = 'dolu'
  466.     elif orientation == 'levo':
  467.         if head[1] + 1 < 10 and (head[0], head[1] + 1) not in red_apples and (head[0], head[1] + 1) not in snake:
  468.             snake = list(snake)
  469.             snake.append((head[0], head[1] + 1))
  470.  
  471.             if (head[0], head[1] + 1) in green_apples:
  472.                 green_apples = list(green_apples)
  473.                 green_apples = [x for x in green_apples if x not in snake]
  474.                 green_apples = tuple(green_apples)
  475.             else:
  476.                 snake = snake[1:]
  477.             snake = tuple(snake)
  478.             orientation = 'gore'
  479.     elif orientation == 'gore':
  480.         if head[0] + 1 < 10 and (head[0] + 1, head[1]) not in red_apples and (head[0] + 1, head[1]) not in snake:
  481.             snake = list(snake)
  482.             snake.append((head[0] + 1, head[1]))
  483.  
  484.             if (head[0] + 1, head[1]) in green_apples:
  485.                 green_apples = list(green_apples)
  486.                 green_apples = [x for x in green_apples if x not in snake]
  487.                 green_apples = tuple(green_apples)
  488.             else:
  489.                 snake = snake[1:]
  490.             snake = tuple(snake)
  491.             orientation = 'desno'
  492.     elif orientation == 'dolu':
  493.         if head[0] - 1 >= 0 and (head[0] - 1, head[1]) not in red_apples and (head[0] - 1, head[1]) not in snake:
  494.             snake = list(snake)
  495.             snake.append((head[0] - 1, head[1]))
  496.  
  497.             if (head[0] - 1, head[1]) in green_apples:
  498.                 green_apples = list(green_apples)
  499.                 green_apples = [x for x in green_apples if x not in snake]
  500.                 green_apples = tuple(green_apples)
  501.             else:
  502.                 snake = snake[1:]
  503.             snake = tuple(snake)
  504.             orientation = 'levo'
  505.  
  506.     return snake, green_apples, orientation
  507.  
  508.  
  509. def SvrtiLevo(snake, green_apples, red_apples, orientation):
  510.     head = snake[-1]
  511.     if orientation == 'levo':
  512.         if head[1] - 1 >= 0 and (head[0], head[1] - 1) not in red_apples and (head[0], head[1] - 1) not in snake:
  513.             snake = list(snake)
  514.             snake.append((head[0], head[1] - 1))
  515.  
  516.             if (head[0], head[1] - 1) in green_apples:
  517.                 green_apples = list(green_apples)
  518.                 green_apples = [x for x in green_apples if x not in snake]
  519.                 green_apples = tuple(green_apples)
  520.             else:
  521.                 snake = snake[1:]
  522.             snake = tuple(snake)
  523.             orientation = 'dolu'
  524.     elif orientation == 'desno':
  525.         if head[1] + 1 < 10 and (head[0], head[1] + 1) not in red_apples and (head[0], head[1] + 1) not in snake:
  526.             snake = list(snake)
  527.             snake.append((head[0], head[1] + 1))
  528.  
  529.             if (head[0], head[1] + 1) in green_apples:
  530.                 green_apples = list(green_apples)
  531.                 green_apples = [x for x in green_apples if x not in snake]
  532.                 green_apples = tuple(green_apples)
  533.             else:
  534.                 snake = snake[1:]
  535.             snake = tuple(snake)
  536.             orientation = 'gore'
  537.     elif orientation == 'dolu':
  538.         if head[0] + 1 < 10 and (head[0] + 1, head[1]) not in red_apples and (head[0] + 1, head[1]) not in snake:
  539.             snake = list(snake)
  540.             snake.append((head[0] + 1, head[1]))
  541.  
  542.             if (head[0] + 1, head[1]) in green_apples:
  543.                 green_apples = list(green_apples)
  544.                 green_apples = [x for x in green_apples if x not in snake]
  545.                 green_apples = tuple(green_apples)
  546.             else:
  547.                 snake = snake[1:]
  548.             snake = tuple(snake)
  549.             orientation = 'desno'
  550.     elif orientation == 'gore':
  551.         if head[0] - 1 >= 0 and (head[0] - 1, head[1]) not in red_apples and (head[0] - 1, head[1]) not in snake:
  552.             snake = list(snake)
  553.             snake.append((head[0] - 1, head[1]))
  554.  
  555.             if (head[0] - 1, head[1]) in green_apples:
  556.                 green_apples = list(green_apples)
  557.                 green_apples = [x for x in green_apples if x not in snake]
  558.                 green_apples = tuple(green_apples)
  559.             else:
  560.                 snake = snake[1:]
  561.             snake = tuple(snake)
  562.             orientation = 'levo'
  563.  
  564.     return snake, green_apples, orientation
  565.  
  566. if __name__ == '__main__':
  567.     n = int(input())
  568.     green = []
  569.  
  570.     for i in range(0, n):
  571.         apple = input().split(',')
  572.         apple = [int(apple[0]), int(apple[1])]
  573.         green.append(tuple(apple))
  574.  
  575.     m = int(input())
  576.     red = []
  577.  
  578.     for i in range(0, m):
  579.         apple = input().split(',')
  580.         apple = [int(apple[0]), int(apple[1])]
  581.         red.append(tuple(apple))
  582.  
  583.     s = ((0, 9), (0, 8), (0, 7))
  584.     orien = 'dolu'
  585.  
  586.     snake_problem = Snake((s, tuple(green), orien), tuple(red))
  587.     print(breadth_first_graph_search(snake_problem).solution())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement