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

#/usr/bin/python
from json.decoder import JSONDecodeError
import json
import re
import sys
ITEMS = {}
################################################################################################################################
# file operations #
# this section is dedicated to operations that save, load, and parse data stored to disk #
# || || || || || || || || || || || #
# \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ #
################################################################################################################################
def to_dict(obj):
return obj.__dict_repr__
def from_dict(d):
name = d['name']
type = d.pop('type')
cls = globals()[type]
instance = cls(**d)
instance.__dict__.update(d)
global ITEMS
ITEMS[name] = instance
def to_json(init=False):
if not init:
ret = list(map(to_dict,ITEMS.values()))
with open('__cache__','w') as file:
json.dump(ret,file)
else:
with open('__cache__','w') as file:
json.dump([],file)
def from_json():
global ITEMS
with open('__cache__') as file:
data = json.load(file)
for item in data:
from_dict(item)
################################################################################################################################
# user input #
# this section is dedicated to operations that will not have any purpose other than collecting data #
# || || || || || || || || || || || #
# \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ #
################################################################################################################################
class user_input:
def __init__(self,comp_name):
print("~{}~".format(comp_name),)
i = 1
while True:
inp = input('sub #{} ({{comp_name}} * {{count}}): '.format(i))
# null data means quit
if inp == '':
break
# initialize on the first iteration
if i == 1:
self.subs = {}
# parse infix expression
sr = re.split(r' *\* *',inp)
# default count is 1
name = sr[0]
if len(sr) == 1:
count = 1
else:
count = int(sr[1])
self.subs[name] = count
i += 1
# `i` was never incremented, so the loop terminated early implying no sub components aka raw
if i == 1:
self.type = 'raw'
else:
self.type = 'compound'
def recursive_fill_in(comp_name):
global ITEMS
if not comp_name in ITEMS.keys():
res = user_input(comp_name)
if res.type == 'raw':
ITEMS[comp_name] = raw_material(comp_name)
else:
ITEMS[comp_name] = complex_item(comp_name,res.subs)
for sub in res.subs.keys():
recursive_fill_in(sub)
################################################################################################################################
# complexity #
# this section is dedicated to operations that involve all processing and understanding of the input data #
# || || || || || || || || || || || #
# \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ #
################################################################################################################################
class item:
def __init__(self,name):
self.name = name
self.__dict_repr__ = {
'name':name,
'type':type(self).__name__
}
class raw_material(item):
def __init__(self,name,**placeholder):
super().__init__(name)
self.complexity = 0
class complex_item(item):
def __init__(self,name,sub_components,**placeholder):
super().__init__(name)
self.sub_components = sub_components
self.__dict_repr__['sub_components'] = sub_components
self.naive_complexity = True
self.__dict_repr__['naive_complexity'] = True
self.all_sub = set(self.sub_components.keys())
def recalculate_total_completixy(self):
for name in self.sub_components.keys():
component = ITEMS[name]
if isinstance(component,complex_item):
if component.naive_complexity:
component.recalculate_total_completixy()
component.naive_complexity = False
self.all_sub.update(component.all_sub)
@property
def complexity(self):
if self.naive_complexity:
self.recalculate_total_completixy()
self.naive_complexity = False
return len(self.all_sub)
def get_raw_material_cost(self,numb=1,ret = {}):
for name,count in self.sub_components.items():
component = ITEMS[name]
if isinstance(component,raw_material):
prev = ret.get(name,0)
ret[name] = prev + count*numb
elif isinstance(component,complex_item):
component.get_raw_material_cost(count*numb,ret)
return ret
def get_component_cost(self,numb=1,ret = {}):
for name,count in self.sub_components.items():
component = ITEMS[name]
if isinstance(component,complex_item):
prev = ret.get(name,0)
ret[name] = prev + count*numb
component.get_component_cost(count*numb,ret)
return ret
def get_build_info(self):
material_view = self.get_raw_material_cost()
component_view = self.get_component_cost()
build_order = component_view.items()
build_order = sorted(build_order,key = lambda item: ITEMS[item[0]].complexity)
return material_view,build_order
def main(args):
print(args)
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument('query')
args = parser.parse_args(args)
if not os.path.exists('__cache__'):
to_json(init=True)
try:
from_json()
except JSONDecodeError:
to_json(init=True)
from_json()
recursive_fill_in(args.query)
print(*ITEMS[args.query].get_build_info(),sep='\n')
to_json()
if __name__ == "__main__":
main(sys.argv[1:])