diff --git a/thaumic.py b/thaumic.py index 9f50fa5..f51eefb 100644 --- a/thaumic.py +++ b/thaumic.py @@ -7,11 +7,9 @@ print = pp.pprint # Open the file and load -with open(os.path.join(sys.path[0], 'thaumicjei_itemstack_aspects.json'), 'r') as file: - data = json.load(file) - -with open(os.path.join(sys.path[0], 'aspect_tiers.json'), 'r') as file: - tiers = json.load(file) +thuamicJSON = os.path.join(sys.path[0], 'thaumicjei_itemstack_aspects.json') +aspectJSON = os.path.join(sys.path[0], 'aspect_tiers.json') +data, tiers = json.load(open(thuamicJSON, 'r')), json.load(open(aspectJSON, 'r')) # Dictionary object for keying items # build = { @@ -52,155 +50,70 @@ for aspect in range(len(data)): build[key]['aspects'] = {} build[key]['aspects'][curAspect] = int(value) -# Allows recursive. Sorts by the number of (different) aspects in the list. -# current=key list -# aspect=aspect dictionary -# reverse=reverses how the keys are changed in the key array -def sort_aspect_count(current, aspects, descending=False): - coefficient = max(list(map(len, aspects))) # Maximum value in the list - current = list(map(lambda x : x * (coefficient + 1), current)) # Multiply by coefficient + 1 - # Reversal is done just by counting down FROM the cofficient (maximum value) - if descending: - for index in range(len(aspects)): - current[index] += coefficient - len(aspects[index].keys()) # Add value for the key - # Regular - elif not descending: - for index in range(len(aspects)): - current[index] += len(aspects[index].keys()) # Add value for the key - return current - -# For use in process_sorts(), returns a function where descending has been predetermined -sort_aspect_count_prepare = lambda desc : partial(sort_aspect_count, descending=desc) - -# current=key list -# aspect=aspect dictionary -# target=if specified, only count of a target aspect is considered -def sort_aspect_sum(current, aspects, targets=None, descending=False): - # Target is specified, have to account for the new maximum coefficient - if targets: - coefficient = 0 - for aspectDict in aspects: - # Calculate which targets are in the aspectDict - available = [target for target in targets if target in aspectDict.keys()] - # If any are in it - if len(available) > 0: - # Calculate the sum of the target aspect's count's - # length of available is taken into account, items with higher target counts are prioritized - coefficient = max(coefficient, sum([aspectDict[target] for target in available])) - # Target is not specified, get a blanket sum - elif not targets: - coefficient = max(list(map(sum, [x.values() for x in aspects]))) - # Multiply key list by coefficient - current = list(map(lambda x : x * (coefficient + 1), current)) - # Target is specified - if targets: - # Descending: += (coefficient - value) - # Ascending: += (value) - if descending: - for index in range(len(current)): - # If the target aspect is actually in the dictionary - # then add it's count as the key 'change' - # edit: changed to allow for list of targets, using sum() - available = [target for target in targets if target in aspects[index].keys()] - if len(available) > 0: - current[index] += sum([aspects[index][target] for target in available]) - elif not descending: - for index in range(len(current)): - available = [target for target in targets if target in aspects[index].keys()] - if len(available) > 0: - current[index] += coefficient - (sum([aspects[index][target] for target in available])) - elif not targets: - if descending: - for index in range(len(current)): - # Just add the sum instead - current[index] += sum(aspects[index].values()) - elif not descending: - for index in range(len(current)): - current[index] += coefficient - sum(aspects[index].values()) - return current - -# For use in process_sorts, returns a function where target and descending have been predetermined -sort_aspect_sum_target = lambda targs, desc=False : partial(sort_aspect_sum, targets=targs, descending=desc) - -def sort_target_ratio(current, aspects, targets, descending=False): - keylist = [] - for item in aspects: - available = [aspect for aspect in item if aspect in targets] - sum_target = sum([item[aspect] for aspect in available]) # Sum of target counts - sum_non_target = sum(item.values()) - sum_target # Sum of non-target counts - if sum_non_target == 0: - ratio = sum_target - else: - ratio = sum_target / sum_non_target - keylist.append(ratio) - - pIndex = [i for i in range(len(keylist))] # Create an index for every item in current to preserve order - preSort = list(zip(pIndex, aspects, keylist)) - preSort.sort(key=lambda x : x[2]) - pIndex, aspects, keylist = dezip(preSort) - - # Multiply values to maintain coefficient - coefficient = len(keylist) - current = [value * (coefficient + 1) for value in current] - - # Add values to complete 'sorting' - for index in range(len(keylist)): - current[pIndex[index]] += coefficient - index - return current - -sort_target_ratio_prepare = lambda targs, descending=True : partial(sort_target_ratio, targets=targs, descending=descending) - -# Processes a list of sort_functions against a list of names, aspects and a possible keylist -def process_sorts(sort_functions, names, aspects, keylist=None, reverse=True): - if keylist == None: - keylist = [1 for _ in range(len(names))] - for sort_func in sort_functions: - keylist = sort_func(keylist, aspects) - zipped = list(zip(names, aspects, keylist)) - zipped.sort(key=lambda x : x[2], reverse=reverse) - newNames, newAspects, newKeylist = dezip(zipped) - return newNames, newAspects, newKeylist - -# Filters for or against specific aspects -def filter_aspects(names, aspects, keylist, targets=[], doBlacklist=False): - zipped = zip(names, aspects, keylist) - if not doBlacklist: - zipped = [item for item in zipped if all(target in item[1].keys() for target in targets)] - elif doBlacklist: - zipped = [item for item in zipped if not any(target in item[1].keys() for target in targets)] - names, aspects, keylist = dezip(zipped) - return names, aspects, keylist - -# Quick function to eliminate the tri element unzipping process -def dezip(zipped): - x, y, z = zip(*zipped) - x, y, z = list(x), list(y), list(z) - return x, y, z - -# Filters for or against a specific mod or set of mods. -def filter_mods(names, aspects, keylist, targets=[], doBlacklist=False): - zipped = zip(names, aspects, keylist) - evaluate = lambda item, flip=False : flip ^ (item[0].split(':')[0] in targets) - if doBlacklist: - evaluate = partial(evaluate, flip=True) - zipped = [item for item in zipped if evaluate(item)] - names, aspects, keylist = dezip(zipped) - return names, aspects, keylist - # Get the names, aspects and the keylist generated names = build.keys() aspects = [build[key]['aspects'] for key in build.keys()] current = [1 for _ in range(len(names))] -whitelist = ['ordo'] -blacklist = [] -blacklistMods = ['botania', 'twilightforest'] +# Returns a ratio of the selected (whitelist) aspects compared to others. +# Reverse will make the whitelist into a blacklist. +def ratio_selected_to_others(item, whitelist, reverse=False): + others = filter_count(item, whitelist) + selected = sum(item[1]['aspects'].values()) - others + if reverse: selected, others = others, selected + return selected / max(1.0, others) -# Mod Filtering -names, aspects, current = filter_mods(names, aspects, current, targets=blacklistMods, doBlacklist=True) -# Aspect Filtering, first -names, aspects, current = filter_aspects(names, aspects, current, targets=whitelist) -names, aspects, current = filter_aspects(names, aspects, current, targets=blacklist, doBlacklist=True) -# Sorting, aspect type count, aspect target sum -names, aspects, current = process_sorts([sort_target_ratio_prepare(whitelist, descending=True), sort_aspect_sum_target(targs=whitelist)], names, aspects, reverse=True) -print(list(zip(names, aspects))) \ No newline at end of file +# Returns the count of the selected aspects for an item. +# Reverse will make the whitelist into a blacklist. +def filter_count(item, whitelist, reverse=False): + if not reverse: + return sum(item[1]['aspects'][subitem] for subitem in item[1]['aspects'].keys() if subitem in whitelist) + elif reverse: + return sum(item[1]['aspects'][subitem] for subitem in item[1]['aspects'].keys() if subitem not in whitelist) + +# Returns True if the mod is in the whitelist. +# Reverse turns the whitelist into a blacklist. +def mod_filter(item, whitelist, reverse=False): + mod = item[0].split(':')[0] + value = mod in whitelist + return not value if reverse else value + +# Returns True if the item is in the whitelist. +# Reverse turns the whitelist into a blacklist +def item_filter(item, whitelist, reverse=False): + item = item[0].split(':')[0] + value = item in whitelist + return not value if reverse else value + +# Constants for sorting/filtering +# Empty blacklist/whitelist will do nothing. Both being non-empty may cause unintended behavior. +selected_aspects = ['terra'] +whitelistItems = [] +blacklistItems = [] +whitelistMods = ['bloodmagic'] +blacklistMods = [] + +# Filter the items +build_items = list(build.items()) +# Blacklist Mods +if blacklistMods: build_items = list(filter(partial(mod_filter, whitelist=blacklistMods, reverse=True), build_items)) +# Whitelist Mods +if whitelistMods: build_items = list(filter(partial(mod_filter, whitelist=whitelistMods, reverse=False), build_items)) +# Blackist Items +if blacklistItems: build_items = list(filter(partial(item, whitelist=whitelistItems, reverse=True), build_items)) +# # Whitelist Items +if whitelistItems: build_items = list(filter(partial(item_filter, whitelist=whitelistItems, reverse=False), build_items)) +# build_items = list(filter) + +# Builds the maps +map_selected_ratio = map(partial(ratio_selected_to_others, reverse=True, whitelist=selected_aspects), build_items) +map_selected_count = map(partial(filter_count, reverse=False, whitelist=selected_aspects), build_items) +# Zip the ratios and the items +zipped = list(zip(build_items, map_selected_ratio, map_selected_count)) +# Sort the zipped item based on the maps zipped within +zipped.sort(key=lambda item : item[1:]) +print(zipped[-100:]) + +# x = build_items[0] +# print(x) +# print(mod_filter(x, whitelist=['minecraft'])) \ No newline at end of file