Advertisement
Guest User

import sys import bisect class Problem: def __init__(se

a guest
Mar 28th, 2020
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.35 KB | None | 0 0
  1. import sys
  2. import bisect
  3.  
  4. class Problem:
  5. def __init__(self, initial, goal=None):
  6. self.initial = initial
  7. self.goal = goal
  8.  
  9. def successor(self, state):
  10. """За дадена состојба, врати речник од парови {акција : состојба}
  11. достапни од оваа состојба. Ако има многу следбеници, употребете
  12. итератор кој би ги генерирал следбениците еден по еден, наместо да
  13. ги генерирате сите одеднаш.
  14. :param state: дадена состојба
  15. :return: речник од парови {акција : состојба} достапни од оваа
  16. состојба
  17. :rtype: dict
  18. """
  19. raise NotImplementedError
  20.  
  21. def actions(self, state):
  22. """За дадена состојба state, врати листа од сите акции што може да
  23. се применат над таа состојба
  24. :param state: дадена состојба
  25. :return: листа на акции
  26. :rtype: list
  27. """
  28. raise NotImplementedError
  29.  
  30. def result(self, state, action):
  31. """За дадена состојба state и акција action, врати ја состојбата
  32. што се добива со примена на акцијата над состојбата
  33. :param state: дадена состојба
  34. :param action: дадена акција
  35. :return: резултантна состојба
  36. """
  37. raise NotImplementedError
  38.  
  39. def goal_test(self, state):
  40. """Врати True ако state е целна состојба. Даденава имплементација
  41. на методот директно ја споредува state со self.goal, како што е
  42. специфицирана во конструкторот. Имплементирајте го овој метод ако
  43. проверката со една целна состојба self.goal не е доволна.
  44. :param state: дадена состојба
  45. :return: дали дадената состојба е целна состојба
  46. :rtype: bool
  47. """
  48. return state == self.goal
  49.  
  50. def path_cost(self, c, state1, action, state2):
  51. """Врати ја цената на решавачкиот пат кој пристигнува во состојбата
  52. state2 од состојбата state1 преку акцијата action, претпоставувајќи
  53. дека цената на патот до состојбата state1 е c. Ако проблемот е таков
  54. што патот не е важен, оваа функција ќе ја разгледува само состојбата
  55. state2. Ако патот е важен, ќе ја разгледува цената c и можеби и
  56. state1 и action. Даденава имплементација му доделува цена 1 на секој
  57. чекор од патот.
  58. :param c: цена на патот до состојбата state1
  59. :param state1: дадена моментална состојба
  60. :param action: акција која треба да се изврши
  61. :param state2: состојба во која треба да се стигне
  62. :return: цена на патот по извршување на акцијата
  63. :rtype: float
  64. """
  65. return c + 1
  66.  
  67. def value(self):
  68. """За проблеми на оптимизација, секоја состојба си има вредност.
  69. Hill-climbing и сличните алгоритми се обидуваат да ја максимизираат
  70. оваа вредност.
  71. :return: вредност на состојба
  72. :rtype: float
  73. """
  74. raise NotImplementedError
  75.  
  76.  
  77. """
  78. Дефинирање на класата за структурата на јазел од пребарување.
  79. Класата Node не се наследува
  80. """
  81.  
  82.  
  83. class Node:
  84. def __init__(self, state, parent=None, action=None, path_cost=0):
  85. """Креирај јазол од пребарувачкото дрво, добиен од parent со примена
  86. на акцијата action
  87. :param state: моментална состојба (current state)
  88. :param parent: родителска состојба (parent state)
  89. :param action: акција (action)
  90. :param path_cost: цена на патот (path cost)
  91. """
  92. self.state = state
  93. self.parent = parent
  94. self.action = action
  95. self.path_cost = path_cost
  96. self.depth = 0 # search depth
  97. if parent:
  98. self.depth = parent.depth + 1
  99.  
  100. def __repr__(self):
  101. return "<Node %s>" % (self.state,)
  102.  
  103. def __lt__(self, node):
  104. return self.state < node.state
  105.  
  106. def expand(self, problem):
  107. """Излистај ги јазлите достапни во еден чекор од овој јазол.
  108. :param problem: даден проблем
  109. :return: листа на достапни јазли во еден чекор
  110. :rtype: list(Node)
  111. """
  112.  
  113. return [self.child_node(problem, action)
  114. for action in problem.actions(self.state)]
  115.  
  116. def child_node(self, problem, action):
  117. """Дете јазел
  118. :param problem: даден проблем
  119. :param action: дадена акција
  120. :return: достапен јазел според дадената акција
  121. :rtype: Node
  122. """
  123. next_state = problem.result(self.state, action)
  124. return Node(next_state, self, action,
  125. problem.path_cost(self.path_cost, self.state,
  126. action, next_state))
  127.  
  128. def solution(self):
  129. """Врати ја секвенцата од акции за да се стигне од коренот до овој јазол.
  130. :return: секвенцата од акции
  131. :rtype: list
  132. """
  133. return [node.action for node in self.path()[1:]]
  134.  
  135. def solve(self):
  136. """Врати ја секвенцата од состојби за да се стигне од коренот до овој јазол.
  137. :return: листа од состојби
  138. :rtype: list
  139. """
  140. return [node.state for node in self.path()[0:]]
  141.  
  142. def path(self):
  143. """Врати ја листата од јазли што го формираат патот од коренот до овој јазол.
  144. :return: листа од јазли од патот
  145. :rtype: list(Node)
  146. """
  147. x, result = self, []
  148. while x:
  149. result.append(x)
  150. x = x.parent
  151. result.reverse()
  152. return result
  153.  
  154. """Сакаме редицата од јазли кај breadth_first_search или
  155. astar_search да не содржи состојби - дупликати, па јазлите што
  156. содржат иста состојба ги третираме како исти. [Проблем: ова може
  157. да не биде пожелно во други ситуации.]"""
  158.  
  159. def __eq__(self, other):
  160. return isinstance(other, Node) and self.state == other.state
  161.  
  162. def __hash__(self):
  163. return hash(self.state)
  164.  
  165.  
  166. """
  167. Дефинирање на помошни структури за чување на листата на генерирани, но непроверени јазли
  168. """
  169.  
  170.  
  171. class Queue:
  172. """Queue е апстрактна класа / интерфејс. Постојат 3 типа:
  173. Stack(): Last In First Out Queue (стек).
  174. FIFOQueue(): First In First Out Queue (редица).
  175. PriorityQueue(order, f): Queue во сортиран редослед (подразбирливо,од најмалиот кон
  176. најголемиот јазол).
  177. """
  178.  
  179. def __init__(self):
  180. raise NotImplementedError
  181.  
  182. def append(self, item):
  183. """Додади го елементот item во редицата
  184. :param item: даден елемент
  185. :return: None
  186. """
  187. raise NotImplementedError
  188.  
  189. def extend(self, items):
  190. """Додади ги елементите items во редицата
  191. :param items: дадени елементи
  192. :return: None
  193. """
  194. raise NotImplementedError
  195.  
  196. def pop(self):
  197. """Врати го првиот елемент од редицата
  198. :return: прв елемент
  199. """
  200. raise NotImplementedError
  201.  
  202. def __len__(self):
  203. """Врати го бројот на елементи во редицата
  204. :return: број на елементи во редицата
  205. :rtype: int
  206. """
  207. raise NotImplementedError
  208.  
  209. def __contains__(self, item):
  210. """Проверка дали редицата го содржи елементот item
  211. :param item: даден елемент
  212. :return: дали queue го содржи item
  213. :rtype: bool
  214. """
  215. raise NotImplementedError
  216.  
  217.  
  218. class Stack(Queue):
  219. """Last-In-First-Out Queue."""
  220.  
  221. def __init__(self):
  222. self.data = []
  223.  
  224. def append(self, item):
  225. self.data.append(item)
  226.  
  227. def extend(self, items):
  228. self.data.extend(items)
  229.  
  230. def pop(self):
  231. return self.data.pop()
  232.  
  233. def __len__(self):
  234. return len(self.data)
  235.  
  236. def __contains__(self, item):
  237. return item in self.data
  238.  
  239.  
  240. class FIFOQueue(Queue):
  241. """First-In-First-Out Queue."""
  242.  
  243. def __init__(self):
  244. self.data = []
  245.  
  246. def append(self, item):
  247. self.data.append(item)
  248.  
  249. def extend(self, items):
  250. self.data.extend(items)
  251.  
  252. def pop(self):
  253. return self.data.pop(0)
  254.  
  255. def __len__(self):
  256. return len(self.data)
  257.  
  258. def __contains__(self, item):
  259. return item in self.data
  260.  
  261.  
  262. class PriorityQueue(Queue):
  263. """Редица во која прво се враќа минималниот (или максималниот) елемент
  264. (како што е определено со f и order). Оваа структура се користи кај
  265. информирано пребарување"""
  266. """"""
  267.  
  268. def __init__(self, order=min, f=lambda x: x):
  269. """
  270. :param order: функција за подредување, ако order е min, се враќа елементот
  271. со минимална f(x); ако order е max, тогаш се враќа елементот
  272. со максимална f(x).
  273. :param f: функција f(x)
  274. """
  275. assert order in [min, max]
  276. self.data = []
  277. self.order = order
  278. self.f = f
  279.  
  280. def append(self, item):
  281. bisect.insort_right(self.data, (self.f(item), item))
  282.  
  283. def extend(self, items):
  284. for item in items:
  285. bisect.insort_right(self.data, (self.f(item), item))
  286.  
  287. def pop(self):
  288. if self.order == min:
  289. return self.data.pop(0)[1]
  290. return self.data.pop()[1]
  291.  
  292. def __len__(self):
  293. return len(self.data)
  294.  
  295. def __contains__(self, item):
  296. return any(item == pair[1] for pair in self.data)
  297.  
  298. def __getitem__(self, key):
  299. for _, item in self.data:
  300. if item == key:
  301. return item
  302.  
  303. def __delitem__(self, key):
  304. for i, (value, item) in enumerate(self.data):
  305. if item == key:
  306. self.data.pop(i)
  307.  
  308.  
  309.  
  310. def graph_search(problem, fringe):
  311. """Пребарувај низ следбениците на даден проблем за да најдеш цел.
  312. Ако до дадена состојба стигнат два пата, употреби го најдобриот пат.
  313. :param problem: даден проблем
  314. :type problem: Problem
  315. :param fringe: празна редица (queue)
  316. :type fringe: FIFOQueue or Stack or PriorityQueue
  317. :return: Node or None
  318. :rtype: Node
  319. """
  320. closed = set()
  321. fringe.append(Node(problem.initial))
  322. while fringe:
  323. node = fringe.pop()
  324. if problem.goal_test(node.state):
  325. return node
  326. if node.state not in closed:
  327. closed.add(node.state)
  328. fringe.extend(node.expand(problem))
  329. return None
  330.  
  331.  
  332. def breadth_first_graph_search(problem):
  333. """Експандирај го прво најплиткиот јазол во пребарувачкиот граф.
  334. :param problem: даден проблем
  335. :type problem: Problem
  336. :return: Node or None
  337. :rtype: Node
  338. """
  339. return graph_search(problem, FIFOQueue())
  340.  
  341.  
  342. def depth_first_graph_search(problem):
  343. """Експандирај го прво најдлабокиот јазол во пребарувачкиот граф.
  344. :param problem: даден проблем
  345. :type problem: Problem
  346. :return: Node or None
  347. :rtype: Node
  348. """
  349. return graph_search(problem, Stack())
  350.  
  351.  
  352. def depth_limited_search(problem, limit=50):
  353. """Експандирај го прво најдлабокиот јазол во пребарувачкиот граф
  354. со ограничена длабочина.
  355. :param problem: даден проблем
  356. :type problem: Problem
  357. :param limit: лимит за длабочината
  358. :type limit: int
  359. :return: Node or None
  360. :rtype: Node
  361. """
  362.  
  363. def recursive_dls(node, problem, limit):
  364. """Помошна функција за depth limited"""
  365. cutoff_occurred = False
  366. if problem.goal_test(node.state):
  367. return node
  368. elif node.depth == limit:
  369. return 'cutoff'
  370. else:
  371. for successor in node.expand(problem):
  372. result = recursive_dls(successor, problem, limit)
  373. if result == 'cutoff':
  374. cutoff_occurred = True
  375. elif result is not None:
  376. return result
  377. if cutoff_occurred:
  378. return 'cutoff'
  379. return None
  380.  
  381. return recursive_dls(Node(problem.initial), problem, limit)
  382.  
  383.  
  384. def iterative_deepening_search(problem):
  385. """Експандирај го прво најдлабокиот јазол во пребарувачкиот граф
  386. со ограничена длабочина, со итеративно зголемување на длабочината.
  387. :param problem: даден проблем
  388. :type problem: Problem
  389. :return: Node or None
  390. :rtype: Node
  391. """
  392. for depth in range(sys.maxsize):
  393. result = depth_limited_search(problem, depth)
  394. if result is not 'cutoff':
  395. return result
  396.  
  397.  
  398. def uniform_cost_search(problem):
  399. """Експандирај го прво јазолот со најниска цена во пребарувачкиот граф.
  400. :param problem: даден проблем
  401. :type problem: Problem
  402. :return: Node or None
  403. :rtype: Node
  404. """
  405. return graph_search(problem, PriorityQueue(min, lambda a: a.path_cost))
  406.  
  407.  
  408. def d1(index,lista):
  409. lista1 = lista
  410. if index+1 < len(lista1) - 1 and lista1[index+1] == 0:
  411. lista1[index], lista1[index+1] = lista1[index+1], lista1[index]
  412. return lista1
  413. return False
  414.  
  415. def d2(index,lista):
  416. lista1 = lista
  417. if index+2 < len(lista1) - 1 and lista1[index+2] == 0:
  418. if lista1[index+1] != 0:
  419. lista1[index], lista1[index+2] = lista1[index+2], lista1[index]
  420. return lista1
  421. return False
  422.  
  423. def l1(index,lista):
  424. lista1 = lista
  425. if index-1 > - 1 and lista1[index-1] == 0:
  426. lista1[index], lista1[index-1] = lista1[index-1], lista1[index]
  427. return lista1
  428.  
  429. return False
  430.  
  431. def l2(index,lista):
  432. lista1 = lista
  433. if index-2 > - 1 and lista1[index-2] == 0:
  434. if lista1[index-1] != 0:
  435. lista1[index], lista1[index-2] = lista1[index-2], lista1[index]
  436. return lista1
  437. return False
  438.  
  439.  
  440. class Disk(Problem):
  441.  
  442. def __init__(self, initial, goal=None):
  443. super().__init__(initial,goal)
  444.  
  445. def successor(self, state):
  446. successors = dict()
  447. pomLista = list(state)
  448. indexOfelements = [pomLista.index(pomLista[i]) for i in range(0,len(pomLista)) if pomLista[i] != 0]
  449. #elements = [pomLista[i] for i in range(0,len(pomLista)) if pomLista[i] != 0]
  450. for elem in indexOfelements:
  451. new_list = d1(elem,list(state))
  452. if new_list != False:
  453. successors[f'D1: Disk {pomLista[elem]}'] = tuple(new_list)
  454. new_list2 = d2(elem,list(state))
  455. if new_list2 != False:
  456. successors[f'D2: Disk {pomLista[elem]}'] = tuple(new_list2)
  457. new_list3 = l1(elem,list(state))
  458. if new_list3 != False:
  459. successors[f'L1: Disk {pomLista[elem]}'] = tuple(new_list3)
  460. new_list4 = l2(elem,list(state))
  461. if new_list4 != False:
  462. successors[f'L2: Disk {pomLista[elem]}'] = tuple(new_list4)
  463.  
  464. return successors
  465.  
  466. def actions(self, state):
  467. return self.successor(state).keys()
  468.  
  469. def result(self, state, action):
  470. return self.successor(state)[action]
  471.  
  472. def goal_test(self, state):
  473. return state == self.goal
  474.  
  475. if __name__ == '__main__':
  476. n = int(input())
  477. l = int(input())
  478. lista = [0 for i in range(0,l)]
  479. for i in range(0,n):
  480. lista[i] = i+1
  481. goal_list = lista[::-1]
  482. disk = Disk(tuple(lista),tuple(goal_list))
  483. result = breadth_first_graph_search(disk)
  484. print(result.solution())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement