You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
7.0 KiB

7 years ago
7 years ago
  1. #!/usr/bin/python
  2. from json.decoder import JSONDecodeError
  3. import json
  4. import re
  5. import sys
  6. ITEMS = {}
  7. ################################################################################################################################
  8. # file operations #
  9. # this section is dedicated to operations that save, load, and parse data stored to disk #
  10. # || || || || || || || || || || || #
  11. # \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ #
  12. ################################################################################################################################
  13. def to_dict(obj):
  14. return obj.__dict_repr__
  15. def from_dict(d):
  16. name = d['name']
  17. type = d.pop('type')
  18. cls = globals()[type]
  19. instance = cls(**d)
  20. instance.__dict__.update(d)
  21. global ITEMS
  22. ITEMS[name] = instance
  23. def to_json(init=False):
  24. if not init:
  25. ret = list(map(to_dict,ITEMS.values()))
  26. with open('__cache__','w') as file:
  27. json.dump(ret,file)
  28. else:
  29. with open('__cache__','w') as file:
  30. json.dump([],file)
  31. def from_json():
  32. global ITEMS
  33. with open('__cache__') as file:
  34. data = json.load(file)
  35. for item in data:
  36. from_dict(item)
  37. ################################################################################################################################
  38. # user input #
  39. # this section is dedicated to operations that will not have any purpose other than collecting data #
  40. # || || || || || || || || || || || #
  41. # \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ #
  42. ################################################################################################################################
  43. class user_input:
  44. def __init__(self,comp_name):
  45. print("~{}~".format(comp_name),)
  46. i = 1
  47. while True:
  48. inp = input('sub #{} ({{comp_name}} * {{count}}): '.format(i))
  49. # null data means quit
  50. if inp == '':
  51. break
  52. # initialize on the first iteration
  53. if i == 1:
  54. self.subs = {}
  55. # parse infix expression
  56. sr = re.split(r' *\* *',inp)
  57. # default count is 1
  58. name = sr[0]
  59. if len(sr) == 1:
  60. count = 1
  61. else:
  62. count = int(sr[1])
  63. self.subs[name] = count
  64. i += 1
  65. # `i` was never incremented, so the loop terminated early implying no sub components aka raw
  66. if i == 1:
  67. self.type = 'raw'
  68. else:
  69. self.type = 'compound'
  70. def recursive_fill_in(comp_name):
  71. global ITEMS
  72. if not comp_name in ITEMS.keys():
  73. res = user_input(comp_name)
  74. if res.type == 'raw':
  75. ITEMS[comp_name] = raw_material(comp_name)
  76. else:
  77. ITEMS[comp_name] = complex_item(comp_name,res.subs)
  78. for sub in res.subs.keys():
  79. recursive_fill_in(sub)
  80. ################################################################################################################################
  81. # complexity #
  82. # this section is dedicated to operations that involve all processing and understanding of the input data #
  83. # || || || || || || || || || || || #
  84. # \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ #
  85. ################################################################################################################################
  86. class item:
  87. def __init__(self,name):
  88. self.name = name
  89. self.__dict_repr__ = {
  90. 'name':name,
  91. 'type':type(self).__name__
  92. }
  93. class raw_material(item):
  94. def __init__(self,name,**placeholder):
  95. super().__init__(name)
  96. self.complexity = 0
  97. class complex_item(item):
  98. def __init__(self,name,sub_components,**placeholder):
  99. super().__init__(name)
  100. self.sub_components = sub_components
  101. self.__dict_repr__['sub_components'] = sub_components
  102. self.naive_complexity = True
  103. self.__dict_repr__['naive_complexity'] = True
  104. self.all_sub = set(self.sub_components.keys())
  105. def recalculate_total_completixy(self):
  106. for name in self.sub_components.keys():
  107. component = ITEMS[name]
  108. if isinstance(component,complex_item):
  109. if component.naive_complexity:
  110. component.recalculate_total_completixy()
  111. component.naive_complexity = False
  112. self.all_sub.update(component.all_sub)
  113. @property
  114. def complexity(self):
  115. if self.naive_complexity:
  116. self.recalculate_total_completixy()
  117. self.naive_complexity = False
  118. return len(self.all_sub)
  119. def get_raw_material_cost(self,numb=1,ret = {}):
  120. for name,count in self.sub_components.items():
  121. component = ITEMS[name]
  122. if isinstance(component,raw_material):
  123. prev = ret.get(name,0)
  124. ret[name] = prev + count*numb
  125. elif isinstance(component,complex_item):
  126. component.get_raw_material_cost(count*numb,ret)
  127. return ret
  128. def get_component_cost(self,numb=1,ret = {}):
  129. for name,count in self.sub_components.items():
  130. component = ITEMS[name]
  131. if isinstance(component,complex_item):
  132. prev = ret.get(name,0)
  133. ret[name] = prev + count*numb
  134. component.get_component_cost(count*numb,ret)
  135. return ret
  136. def get_build_info(self):
  137. material_view = self.get_raw_material_cost()
  138. component_view = self.get_component_cost()
  139. build_order = component_view.items()
  140. build_order = sorted(build_order,key = lambda item: ITEMS[item[0]].complexity)
  141. return material_view,build_order
  142. def main(args):
  143. print(args)
  144. import argparse
  145. import os
  146. parser = argparse.ArgumentParser()
  147. parser.add_argument('query')
  148. args = parser.parse_args(args)
  149. if not os.path.exists('__cache__'):
  150. to_json(init=True)
  151. try:
  152. from_json()
  153. except JSONDecodeError:
  154. to_json(init=True)
  155. from_json()
  156. recursive_fill_in(args.query)
  157. print(*ITEMS[args.query].get_build_info(),sep='\n')
  158. to_json()
  159. if __name__ == "__main__":
  160. main(sys.argv[1:])