Advertisement
Guest User

Untitled

a guest
Jun 10th, 2024
799
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.46 KB | None | 0 0
  1. from typing import Set, List
  2. from copy import deepcopy
  3.  
  4. def valid_first_input():
  5. s = input().strip().split(",")
  6. s = [s_i.strip()[:1] for s_i in s]
  7. assert len(s) == 2 or len(s) == 3
  8. valid_symbols = ['c','s','t']
  9. if len(s) == 2:
  10. for sym in valid_symbols:
  11. if not sym in s:
  12. s.append(sym)
  13. break
  14. assert ('t' in s and 'c' in s and 's' in s)
  15. # Valid options are triangle, circle, square
  16. return s
  17.  
  18. def get_inside_symbols():
  19. print("Enter Shapes (Inside):")
  20. while True:
  21. try:
  22. res = valid_first_input()
  23. return res
  24. except KeyboardInterrupt:
  25. raise
  26. except:
  27. print("Error for inside calls, try again")
  28. continue
  29.  
  30. def valid_second_input():
  31. valid_symbols = [
  32. 'sp', 'cy', 'co', 'cu', 'pr', 'py'
  33. ]
  34. # Sphere, Cylinder, Cone, Cube, Prism, Pyramid
  35. s = input().strip().split(",")
  36. s = [s_i.strip()[:2] for s_i in s]
  37. assertion_bool = True
  38. for sym in s:
  39. assert sym in valid_symbols
  40. return s
  41.  
  42. def get_outside_symbols():
  43. print("Enter Solids (Outside):")
  44. while True:
  45. try:
  46. res = valid_second_input()
  47. return res
  48. except KeyboardInterrupt:
  49. raise
  50. except:
  51. print("Error for outside calls, try again")
  52. continue
  53.  
  54. def swap(solids: List[List[str]], swap_ind_1, swap_ind_2, swap_shape_1, swap_shape_2):
  55. """
  56. Solids is a list of solids where a solid is a list containing two shapes
  57. i.e. sphere is circle + circle so the list is ['c', 'c']
  58. cylinder is circle + square so the list is ['c', 's']
  59.  
  60. We swap shapes between solids to create two new solids.
  61. Consider shape set pyramid, sphere, cube:
  62. [['t','t'], ['c','c'], ['s','s']]
  63. (left, mid, right)
  64.  
  65. Let's say we swap between left and right. That corresponds to
  66. swap_ind_1 = 0
  67. swap_ind_2 = 2
  68.  
  69. If we want to swap one triangle from the pyramid and one square from the cube we'd pass
  70. swap_shape_1 = 't'
  71. swap_shape_2 = 's'
  72.  
  73. Then we end up with (and return) new solid set:
  74. [['t','s'], ['c','c'], ['s','t']]
  75. (prism, sphere, prism)
  76. """
  77. assert swap_shape_1 in solids[swap_ind_1]
  78. assert swap_shape_2 in solids[swap_ind_2]
  79. assert swap_shape_1 != swap_shape_2
  80. assert swap_ind_1 != swap_ind_2
  81.  
  82. # Perform the swap
  83. solids[swap_ind_1].remove(swap_shape_1)
  84. solids[swap_ind_1].append(swap_shape_2)
  85.  
  86. solids[swap_ind_2].remove(swap_shape_2)
  87. solids[swap_ind_2].append(swap_shape_1)
  88.  
  89. return solids
  90.  
  91. def generate_successors(solids : List[set]) -> List[List[set]]:
  92. """
  93. Generate all possible swaps/succesors from list of solids, also gives an instruction step for how to reach each of those successors.
  94. """
  95. results = []
  96. result_instructions = []
  97. poss_ind_swaps = [(0, 1), (0, 2), (1,2)]
  98. poss_shape_swaps = [
  99. ('c', 't'),
  100. ('c', 's'),
  101. ('t', 'c'),
  102. ('s', 'c'),
  103. ('s', 't'),
  104. ('t', 's')
  105. ]
  106.  
  107. ind_to_pos = ['LEFT', 'MID', 'RIGHT']
  108. sym_to_call = {
  109. 's' : "SQUARE",
  110. 'c' : "CIRCLE",
  111. 't' : "TRIANGLE"
  112. }
  113.  
  114. for ind_1, ind_2 in poss_ind_swaps:
  115. for shape_1, shape_2 in poss_shape_swaps:
  116. try:
  117. res = swap(deepcopy(solids), ind_1, ind_2, shape_1, shape_2)
  118. instruction = f"Excise {sym_to_call[shape_1]} from {ind_to_pos[ind_1]}, Excise {sym_to_call[shape_2]} from {ind_to_pos[ind_2]}"
  119. results.append(res)
  120. result_instructions.append(
  121. instruction
  122. )
  123. except:
  124. continue
  125.  
  126. return results, result_instructions
  127.  
  128. def node_success(node : List[List], target : List[List]):
  129. if len(node) != len(target):
  130. return False
  131. for s, t in zip(node, target):
  132. if set(s) != set(t): return False
  133. return True
  134.  
  135. def generate_swaps(solids : List[Set], target_solids : List[Set]):
  136. """
  137. Generate a list of swaps (i.e. the parameters to the swap function)
  138. We want to find the minimal list of swaps to convert shapes into target_shapes
  139. """
  140. from collections import deque
  141.  
  142. def bfs(start_node, target_node):
  143. queue = deque([(start_node, [])])
  144. visited = set()
  145.  
  146. while queue:
  147. current_node, instructions = queue.popleft()
  148.  
  149. if node_success(current_node, target_node):
  150. return current_node, instructions
  151.  
  152. if tuple(map(tuple, current_node)) in visited:
  153. continue
  154.  
  155. visited.add(tuple(map(tuple, current_node)))
  156.  
  157. successors, successor_instructions = generate_successors(current_node)
  158. for successor, instruction in zip(successors, successor_instructions):
  159. queue.append((successor, instructions + [instruction]))
  160.  
  161. return None, []
  162.  
  163. start_node = solids
  164. target_node = target_solids
  165. result_node, result_instructions = bfs(start_node, target_node)
  166.  
  167. return result_instructions
  168.  
  169. def create_order(inside, outside):
  170. """
  171. Function takes two lists of strings
  172. First list will have inner symbols i.e. ['c', 's', 't']
  173. Second will have outer symbols i.e. ['sp', 'cy', 'cu']
  174. """
  175. # First decompose into components (as sets) that are combinations of the one letter symbols
  176. outside_lists = []
  177. for sym in outside:
  178. if sym == 'sp':
  179. outside_lists.append(['c', 'c']) # Sphere: circle + circle
  180. elif sym == 'cy':
  181. outside_lists.append(['c', 's']) # Cylinder: circle + square
  182. elif sym == 'co':
  183. outside_lists.append(['c', 't']) # Cone: circle + triangle
  184. elif sym == 'cu':
  185. outside_lists.append(['s', 's']) # Cube: square + square
  186. elif sym == 'pr':
  187. outside_lists.append(['s', 't']) # Prism: square + triangle
  188. elif sym == 'py':
  189. outside_lists.append(['t', 't']) # Pyramid: triangle + triangle
  190.  
  191. if len(outside_lists) == 2:
  192. # Infer the last one by counting how many of each
  193. # Then adding shape made of symbols needed to add to 2 total for each
  194. counts = {k: sum(shape.count(k) for shape in outside_lists) for k in ['c','s','t']}
  195. outside_lists.append([key for key in counts for _ in range(2 - counts[key])])
  196.  
  197. target_solids = []
  198. for shape in inside:
  199. if shape == 'c':
  200. target_solids.append(['s', 't']) # Circle -> Square + Triangle
  201. elif shape == 's':
  202. target_solids.append(['c', 't']) # Square -> Circle + Triangle
  203. elif shape == 't':
  204. target_solids.append(['c', 's']) # Triangle -> Circle + Square
  205.  
  206. swaps = generate_swaps(outside_lists, target_solids)
  207. for i, swap in enumerate(swaps):
  208. print(f"{i}. {swap}")
  209.  
  210. if __name__ == "__main__":
  211. print("====================")
  212. print("Instructions:")
  213. print("Input inside symbols by first letter: i.e. triangle circle square -> t,c,s")
  214. print("Input outside solids by first two letters i.e. SPhere CYlinder CUbe -> sp,cy,cu")
  215. while True:
  216. print("====================")
  217. first_line = get_inside_symbols()
  218. second_line = get_outside_symbols()
  219.  
  220. print("SWAPS ARE:")
  221. create_order(first_line, second_line)
  222. print("====================")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement