Advertisement
Guest User

Zadaca3

a guest
Jan 25th, 2020
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.93 KB | None | 0 0
  1. import bisect
  2. import sys
  3.  
  4.  
  5. """
  6. Дефинирање на класа за структурата на проблемот кој ќе го решаваме со пребарување.
  7. Класата Problem е апстрактна класа од која правиме наследување за дефинирање на основните
  8. карактеристики на секој проблем што сакаме да го решиме
  9. """
  10.  
  11.  
  12. class Problem:
  13. def __init__(self, initial, goal=None):
  14. self.initial = initial
  15. self.goal = goal
  16.  
  17. def successor(self, state):
  18. """За дадена состојба, врати речник од парови {акција : состојба}
  19. достапни од оваа состојба. Ако има многу следбеници, употребете
  20. итератор кој би ги генерирал следбениците еден по еден, наместо да
  21. ги генерирате сите одеднаш.
  22.  
  23. :param state: дадена состојба
  24. :return: речник од парови {акција : состојба} достапни од оваа
  25. состојба
  26. :rtype: dict
  27. """
  28. raise NotImplementedError
  29.  
  30. def actions(self, state):
  31. """За дадена состојба state, врати листа од сите акции што може да
  32. се применат над таа состојба
  33.  
  34. :param state: дадена состојба
  35. :return: листа на акции
  36. :rtype: list
  37. """
  38. return self.successor(state).keys()
  39.  
  40. def result(self, state, action):
  41. """За дадена состојба state и акција action, врати ја состојбата
  42. што се добива со примена на акцијата над состојбата
  43.  
  44. :param state: дадена состојба
  45. :param action: дадена акција
  46. :return: резултантна состојба
  47. """
  48. possible = self.successor(state)
  49. return possible[action]
  50.  
  51.  
  52. def goal_test(self, state):
  53. """Врати True ако state е целна состојба. Даденава имплементација
  54. на методот директно ја споредува state со self.goal, како што е
  55. специфицирана во конструкторот. Имплементирајте го овој метод ако
  56. проверката со една целна состојба self.goal не е доволна.
  57.  
  58. :param state: дадена состојба
  59. :return: дали дадената состојба е целна состојба
  60. :rtype: bool
  61. """
  62. return state == self.goal
  63.  
  64. def path_cost(self, c, state1, action, state2):
  65. """Врати ја цената на решавачкиот пат кој пристигнува во состојбата
  66. state2 од состојбата state1 преку акцијата action, претпоставувајќи
  67. дека цената на патот до состојбата state1 е c. Ако проблемот е таков
  68. што патот не е важен, оваа функција ќе ја разгледува само состојбата
  69. state2. Ако патот е важен, ќе ја разгледува цената c и можеби и
  70. state1 и action. Даденава имплементација му доделува цена 1 на секој
  71. чекор од патот.
  72.  
  73. :param c: цена на патот до состојбата state1
  74. :param state1: дадена моментална состојба
  75. :param action: акција која треба да се изврши
  76. :param state2: состојба во која треба да се стигне
  77. :return: цена на патот по извршување на акцијата
  78. :rtype: float
  79. """
  80. return c + 1
  81.  
  82. def value(self):
  83. """За проблеми на оптимизација, секоја состојба си има вредност. 
  84. Hill-climbing и сличните алгоритми се обидуваат да ја максимизираат
  85. оваа вредност.
  86.  
  87. :return: вредност на состојба
  88. :rtype: float
  89. """
  90. raise NotImplementedError
  91.  
  92.  
  93. """
  94. Дефинирање на класата за структурата на јазел од пребарување.
  95. Класата Node не се наследува
  96. """
  97.  
  98.  
  99. class Node:
  100. def __init__(self, state, parent=None, action=None, path_cost=0):
  101. """Креирај јазол од пребарувачкото дрво, добиен од parent со примена
  102. на акцијата action
  103.  
  104. :param state: моментална состојба (current state)
  105. :param parent: родителска состојба (parent state)
  106. :param action: акција (action)
  107. :param path_cost: цена на патот (path cost)
  108. """
  109. self.state = state
  110. self.parent = parent
  111. self.action = action
  112. self.path_cost = path_cost
  113. self.depth = 0 # search depth
  114. if parent:
  115. self.depth = parent.depth + 1
  116.  
  117. def __repr__(self):
  118. return "<Node %s>" % (self.state,)
  119.  
  120. def __lt__(self, node):
  121. return self.state < node.state
  122.  
  123. def expand(self, problem):
  124. """Излистај ги јазлите достапни во еден чекор од овој јазол.
  125.  
  126. :param problem: даден проблем
  127. :return: листа на достапни јазли во еден чекор
  128. :rtype: list(Node)
  129. """
  130. return [self.child_node(problem, action)
  131. for action in problem.actions(self.state)]
  132.  
  133. def child_node(self, problem, action):
  134. """Дете јазел
  135.  
  136. :param problem: даден проблем
  137. :param action: дадена акција
  138. :return: достапен јазел според дадената акција
  139. :rtype: Node
  140. """
  141. next_state = problem.result(self.state, action)
  142. return Node(next_state, self, action,
  143. problem.path_cost(self.path_cost, self.state,
  144. action, next_state))
  145.  
  146. def solution(self):
  147. """Врати ја секвенцата од акции за да се стигне од коренот до овој јазол.
  148.  
  149. :return: секвенцата од акции
  150. :rtype: list
  151. """
  152. return [node.action for node in self.path()[1:]]
  153.  
  154. def solve(self):
  155. """Врати ја секвенцата од состојби за да се стигне од коренот до овој јазол.
  156.  
  157. :return: листа од состојби
  158. :rtype: list
  159. """
  160. return [node.state for node in self.path()[0:]]
  161.  
  162. def path(self):
  163. """Врати ја листата од јазли што го формираат патот од коренот до овој јазол.
  164.  
  165. :return: листа од јазли од патот
  166. :rtype: list(Node)
  167. """
  168. x, result = self, []
  169. while x:
  170. result.append(x)
  171. x = x.parent
  172. result.reverse()
  173. return result
  174.  
  175. """Сакаме редицата од јазли кај breadth_first_search или
  176. astar_search да не содржи состојби - дупликати, па јазлите што
  177. содржат иста состојба ги третираме како исти. [Проблем: ова може
  178. да не биде пожелно во други ситуации.]"""
  179.  
  180. def __eq__(self, other):
  181. return isinstance(other, Node) and self.state == other.state
  182.  
  183. def __hash__(self):
  184. return hash(self.state)
  185.  
  186.  
  187. """
  188. Дефинирање на помошни структури за чување на листата на генерирани, но непроверени јазли
  189. """
  190.  
  191.  
  192. class Queue:
  193. """Queue е апстрактна класа / интерфејс. Постојат 3 типа:
  194.         Stack(): Last In First Out Queue (стек).
  195.         FIFOQueue(): First In First Out Queue (редица).
  196.         PriorityQueue(order, f): Queue во сортиран редослед (подразбирливо,од најмалиот кон
  197. најголемиот јазол).
  198.     """
  199.  
  200. def __init__(self):
  201. raise NotImplementedError
  202.  
  203. def append(self, item):
  204. """Додади го елементот item во редицата
  205.  
  206. :param item: даден елемент
  207. :return: None
  208. """
  209. raise NotImplementedError
  210.  
  211. def extend(self, items):
  212. """Додади ги елементите items во редицата
  213.  
  214. :param items: дадени елементи
  215. :return: None
  216. """
  217. raise NotImplementedError
  218.  
  219. def pop(self):
  220. """Врати го првиот елемент од редицата
  221.  
  222. :return: прв елемент
  223. """
  224. raise NotImplementedError
  225.  
  226. def __len__(self):
  227. """Врати го бројот на елементи во редицата
  228.  
  229. :return: број на елементи во редицата
  230. :rtype: int
  231. """
  232. raise NotImplementedError
  233.  
  234. def __contains__(self, item):
  235. """Проверка дали редицата го содржи елементот item
  236.  
  237. :param item: даден елемент
  238. :return: дали queue го содржи item
  239. :rtype: bool
  240. """
  241. raise NotImplementedError
  242.  
  243.  
  244. class Stack(Queue):
  245. """Last-In-First-Out Queue."""
  246.  
  247. def __init__(self):
  248. self.data = []
  249.  
  250. def append(self, item):
  251. self.data.append(item)
  252.  
  253. def extend(self, items):
  254. self.data.extend(items)
  255.  
  256. def pop(self):
  257. return self.data.pop()
  258.  
  259. def __len__(self):
  260. return len(self.data)
  261.  
  262. def __contains__(self, item):
  263. return item in self.data
  264.  
  265.  
  266. class FIFOQueue(Queue):
  267. """First-In-First-Out Queue."""
  268.  
  269. def __init__(self):
  270. self.data = []
  271.  
  272. def append(self, item):
  273. self.data.append(item)
  274.  
  275. def extend(self, items):
  276. self.data.extend(items)
  277.  
  278. def pop(self):
  279. return self.data.pop(0)
  280.  
  281. def __len__(self):
  282. return len(self.data)
  283.  
  284. def __contains__(self, item):
  285. return item in self.data
  286.  
  287.  
  288. class PriorityQueue(Queue):
  289. """Редица во која прво се враќа минималниот (или максималниот) елемент
  290. (како што е определено со f и order). Оваа структура се користи кај
  291. информирано пребарување"""
  292. """"""
  293.  
  294. def __init__(self, order=min, f=lambda x: x):
  295. """
  296. :param order: функција за подредување, ако order е min, се враќа елементот
  297. со минимална f(x); ако order е max, тогаш се враќа елементот
  298. со максимална f(x).
  299. :param f: функција f(x)
  300. """
  301. assert order in [min, max]
  302. self.data = []
  303. self.order = order
  304. self.f = f
  305.  
  306. def append(self, item):
  307. bisect.insort_right(self.data, (self.f(item), item))
  308.  
  309. def extend(self, items):
  310. for item in items:
  311. bisect.insort_right(self.data, (self.f(item), item))
  312.  
  313. def pop(self):
  314. if self.order == min:
  315. return self.data.pop(0)[1]
  316. return self.data.pop()[1]
  317.  
  318. def __len__(self):
  319. return len(self.data)
  320.  
  321. def __contains__(self, item):
  322. return any(item == pair[1] for pair in self.data)
  323.  
  324. def __getitem__(self, key):
  325. for _, item in self.data:
  326. if item == key:
  327. return item
  328.  
  329. def __delitem__(self, key):
  330. for i, (value, item) in enumerate(self.data):
  331. if item == key:
  332. self.data.pop(i)
  333.  
  334. #------------------------------------------------------------------------------------------------------------------------
  335.  
  336. """
  337. Неинформирано пребарување во рамки на дрво.
  338. Во рамки на дрвото не разрешуваме јамки.
  339. """
  340.  
  341.  
  342. def tree_search(problem, fringe):
  343. """ Пребарувај низ следбениците на даден проблем за да најдеш цел.
  344.  
  345. :param problem: даден проблем
  346. :param fringe: празна редица (queue)
  347. :return: Node
  348. """
  349. fringe.append(Node(problem.initial))
  350. while fringe:
  351. node = fringe.pop()
  352. print(node.state)
  353. if problem.goal_test(node.state):
  354. return node
  355. fringe.extend(node.expand(problem))
  356. return None
  357.  
  358.  
  359. def breadth_first_tree_search(problem):
  360. """Експандирај го прво најплиткиот јазол во пребарувачкото дрво.
  361.  
  362. :param problem: даден проблем
  363. :return: Node
  364. """
  365. return tree_search(problem, FIFOQueue())
  366.  
  367.  
  368. def depth_first_tree_search(problem):
  369. """Експандирај го прво најдлабокиот јазол во пребарувачкото дрво.
  370.  
  371. :param problem:даден проблем
  372. :return: Node
  373. """
  374. return tree_search(problem, Stack())
  375.  
  376.  
  377. """
  378. Неинформирано пребарување во рамки на граф
  379. Основната разлика е во тоа што овде не дозволуваме јамки,
  380. т.е. повторување на состојби
  381. """
  382.  
  383.  
  384. def graph_search(problem, fringe):
  385. """Пребарувај низ следбениците на даден проблем за да најдеш цел.
  386. Ако до дадена состојба стигнат два пата, употреби го најдобриот пат.
  387.  
  388. :param problem: даден проблем
  389. :param fringe: празна редица (queue)
  390. :return: Node
  391. """
  392. closed = set()
  393. fringe.append(Node(problem.initial))
  394. while fringe:
  395. node = fringe.pop()
  396. if problem.goal_test(node.state):
  397. return node
  398. if node.state not in closed:
  399. closed.add(node.state)
  400. fringe.extend(node.expand(problem))
  401. return None
  402.  
  403.  
  404. def breadth_first_graph_search(problem):
  405. """Експандирај го прво најплиткиот јазол во пребарувачкиот граф.
  406.  
  407. :param problem: даден проблем
  408. :return: Node
  409. """
  410. return graph_search(problem, FIFOQueue())
  411.  
  412.  
  413. def depth_first_graph_search(problem):
  414. """Експандирај го прво најдлабокиот јазол во пребарувачкиот граф.
  415.  
  416. :param problem: даден проблем
  417. :return: Node
  418. """
  419. return graph_search(problem, Stack())
  420.  
  421.  
  422. def depth_limited_search(problem, limit=50):
  423. def recursive_dls(node, problem, limit):
  424. """Помошна функција за depth limited"""
  425. cutoff_occurred = False
  426. if problem.goal_test(node.state):
  427. return node
  428. elif node.depth == limit:
  429. return 'cutoff'
  430. else:
  431. for successor in node.expand(problem):
  432. result = recursive_dls(successor, problem, limit)
  433. if result == 'cutoff':
  434. cutoff_occurred = True
  435. elif result is not None:
  436. return result
  437. if cutoff_occurred:
  438. return 'cutoff'
  439. return None
  440.  
  441. return recursive_dls(Node(problem.initial), problem, limit)
  442.  
  443.  
  444. def iterative_deepening_search(problem):
  445. for depth in range(sys.maxsize):
  446. result = depth_limited_search(problem, depth)
  447. if result is not 'cutoff':
  448. return result
  449.  
  450.  
  451. def uniform_cost_search(problem):
  452. """Експандирај го прво јазолот со најниска цена во пребарувачкиот граф."""
  453. return graph_search(problem, PriorityQueue(min, lambda a: a.path_cost))
  454.  
  455.  
  456. # ---------------------------------------------------------------------------------------------------------------------------------
  457.  
  458. obstacles = [(1,4), (1,6), (1,8), (2,3), (2,9), (4,2), (4,7), (4,8), (5,5), (5,7), (6,1), (6,2), (6,4), (6,7)]
  459.  
  460.  
  461. def move_up(first, second, third):
  462. while(first not in obstacles) and (first not in (second, third)) and (first[0] > 0):
  463. x = first[0] - 1
  464. first = x, first[1]
  465. position_new = first[0] + 1, first[1]
  466. return position_new
  467.  
  468.  
  469. def move_down(first, second, third):
  470. while(first not in obstacles) and (first not in (second, third)) and (first[0] < 8):
  471. x = first[0] + 1
  472. first = x, first[1]
  473. position_new = first[0] - 1, first[1]
  474. return position_new
  475.  
  476.  
  477. def move_left(first, second, third):
  478. while(first not in obstacles) and (first not in (second, third)) and (first[1] > 0):
  479. y = first[1] - 1
  480. first = first[0], y
  481. position_new = first[0], first[1] + 1
  482. return position_new
  483.  
  484.  
  485. def move_right(first, second, third):
  486. while(first not in obstacles) and (first not in (second, third)) and (first[1] < 10):
  487. y = first[1] + 1
  488. first = first[0], y
  489. position_new = first[0], first[1] - 1
  490. return position_new
  491.  
  492.  
  493. class Molekula(Problem):
  494.  
  495. def __init__(self, initial):
  496. super().__init__(initial,None)
  497.  
  498. def goal_test(self, state):
  499. h1_x = state[0]
  500. h1_y = state[1]
  501. o_x = state[2]
  502. o_y = state[3]
  503. h2_x = state[4]
  504. h2_y = state[5]
  505. return h1_x == o_x and o_x == h2_x and h1_y == o_y - 1 and o_y == h2_y - 1
  506.  
  507. def successor(self, state):
  508. successors = dict()
  509. h1 = state[0], state[1]
  510. o = state[2], state[3]
  511. h2 = state[4], state[5]
  512.  
  513. # h1 gore
  514. h1_new = move_up(h1,o,h2)
  515. state_new = h1_new + o + h2
  516. if state_new != state:
  517. successors["GoreH1"] = state_new
  518.  
  519. # h1 dolu
  520. h1_new = move_down(h1, o, h2)
  521. state_new = h1_new + o + h2
  522. if state_new != state:
  523. successors["DoluH1"] = state_new
  524.  
  525. # h1 levo
  526. h1_new = move_left(h1, o, h2)
  527. state_new = h1_new + o + h2
  528. if state_new != state:
  529. successors["LevoH1"] = state_new
  530.  
  531. # h1 desno
  532. h1_new = move_right(h1, o, h2)
  533. state_new = h1_new + o + h2
  534. if state_new != state:
  535. successors["DesnoH1"] = state_new
  536.  
  537. # o gore
  538. o_new = move_up(o, h1, h2)
  539. state_new = h1 + o_new + h2
  540. if state_new != state:
  541. successors["GoreO"] = state_new
  542.  
  543. # o dolu
  544. o_new = move_down(o, h1, h2)
  545. state_new = h1 + o_new + h2
  546. if state_new != state:
  547. successors["DoluO"] = state_new
  548.  
  549. # o levo
  550. o_new = move_left(o, h1, h2)
  551. state_new = h1 + o_new + h2
  552. if state_new != state:
  553. successors["LevoO"] = state_new
  554.  
  555. # o desno
  556. o_new = move_right(o, h1, h2)
  557. state_new = h1 + o_new + h2
  558. if state_new != state:
  559. successors["DesnoO"] = state_new
  560.  
  561. # h2 gore
  562. h2_new = move_up(h2, o, h1)
  563. state_new = h1 + o + h2_new
  564. if state_new != state:
  565. successors["GoreH2"] = state_new
  566.  
  567. # h2 dolu
  568. h2_new = move_down(h2, o, h1)
  569. state_new = h1 + o + h2_new
  570. if state_new != state:
  571. successors["DoluH2"] = state_new
  572.  
  573. # h2 levo
  574. h2_new = move_left(h2, o, h1)
  575. state_new = h1 + o + h2_new
  576. if state_new != state:
  577. successors["LevoH2"] = state_new
  578.  
  579. # h2 desno
  580. h2_new = move_right(h2, o, h1)
  581. state_new = h1 + o + h2_new
  582. if state_new != state:
  583. successors["DesnoH2"] = state_new
  584.  
  585. return successors
  586.  
  587. def value(self):
  588. pass
  589.  
  590.  
  591. if __name__ == '__main__':
  592. h1_atom_row = int(input())
  593. h1_atom_column = int(input())
  594. o_atom_row = int(input())
  595. o_atom_column = int(input())
  596. h2_atom_row = int(input())
  597. h2_atom_column = int(input())
  598.  
  599. molekula = Molekula((h1_atom_row, h1_atom_column, o_atom_row, o_atom_column, h2_atom_row, h2_atom_column))
  600. answer = breadth_first_graph_search(molekula)
  601. print(answer.solution())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement