from base64 import decode from utils import load_dict from colors import colors, colornames, decode_color import math def calculate_leather_color(recipes): cache = {} for layer in recipes: for color in recipes[layer]: cache[color] = { "color": decode_color(color), "step": layer } return cache def color_distance(c1, c2): return sum([abs(x - y) for x, y in zip(c1, c2)]) def find_closest_color(cache, color, max_step=-1): min_dist = 10000 closest_color = None for name, this_color in cache.items(): if max_step > 0 and this_color['step'] > max_step: continue this_dist = color_distance(color, this_color['color']) if this_dist < min_dist: min_dist = this_dist closest_color = name return closest_color, min_dist def decode_recipe(encoded): encoded = int(encoded, base=16) counts = [] while len(counts) < 16: counts.append(encoded%9) encoded //=9 return {name:count for name, count in zip(colornames, counts) if count > 0} def query_recipe(recipes, name): # search color layer. recipe = None for layer in recipes: recipe = recipes[layer].get(name, None) if recipe is not None: break if recipe is None: raise ValueError('Color not craftable.') base_color, recipe = recipe recipe = decode_recipe(recipe) if base_color == '#000000': return [recipe] else: steps = query_recipe(recipes, base_color) steps.append(recipe) return steps def explain_recipe(steps): infos = [] for i, step in enumerate(steps): info = ','.join(['{0}*{1}'.format(colors[name]['name'], count) for name, count in step.items()]) infos.append(info) print('->'.join(infos)) def calculate_multipler(diff, enchant=False): diff = 256 if diff > 256 else diff multiplier = None if enchant: multiplier = 1 - (0.50) * (256.0 - diff)*0.5 / 256.0 else: multiplier = 1 - (0.50) * (256.0 - diff) / 256.0 multiplier = multiplier * math.log(80) / math.log(125) # single cloth. return multiplier def show_protection(diff): print('============= 减伤系数 =============') multiplier = calculate_multipler(diff, enchant=False) multiplier_full = multiplier**4 multiplier_elytra = multiplier**3 * math.log(432) / math.log(125) info = '\n'.join([ "无附魔情况下,单件衣服减伤系数为:{0}".format(multiplier), "无附魔情况下,全套衣服减伤系数为:{0}".format(multiplier_full), "无附魔情况下,三件衣服+鞘翅减伤系数为:{0}".format(multiplier_elytra), ]) print(info) multiplier = calculate_multipler(diff, enchant=True) multiplier_full = multiplier**4 multiplier_elytra = multiplier**3 * math.log(432) / math.log(125) info = '\n'.join([ "有附魔情况下,单件衣服减伤系数为:{0}".format(multiplier), "有附魔情况下,全套衣服减伤系数为:{0}".format(multiplier_full), "有附魔情况下,三件衣服+鞘翅减伤系数为:{0}".format(multiplier_elytra), ]) print(info) print('在有保护类附魔存在时,实际减伤表格如下所示。其中横排分别表示单件、全套、有鞘翅三种情况,纵列分别表示保护系数为0/1/2/3/4/5') print('(保护系数的计算:上限为5,其中保护四记为1,火焰、爆炸、弹射物保护对其对应的伤害时记为2,摔落保护对摔落保护记为3,每件衣服的保护系数可以直接相加且上限为5,超过5记为5)') multiplier_protection = [1 - x*4/25 for x in range(6)] multiplier_protect_enchant = [multiplier*this_protection for this_protection in multiplier_protection] multiplier_full_protect_enchant = [multiplier_full*this_protection for this_protection in multiplier_protection] multiplier_elytra_protect_enchant = [multiplier_elytra*this_protection for this_protection in multiplier_protection] info = '\n'.join([ ' '.join(['%.4f']*6)%tuple(multiplier_protect_enchant), ' '.join(['%.4f']*6)%tuple(multiplier_full_protect_enchant), ' '.join(['%.4f']*6)%tuple(multiplier_elytra_protect_enchant) ]) print(info) if __name__ == '__main__': print('正在加载配方数据...') recipes = load_dict('./recipes.json') print('配方数据库加载完成!正在准备数据...') leather_color_cache = calculate_leather_color(recipes) print('数据准备完毕,共加载{0}种可合成颜色。'.format(len(leather_color_cache))) note = '\n'.join( [ '请输入你的幸运色,用空格分隔。', '如你的幸运色为100, 200, 100, 请输入 100 200 100。', '默认所有颜色可用,若你希望限制合成的步骤数量,可以在幸运色后追加一个数字表示每种颜色的最大合成步骤', '如 100 200 100 2 表示给出的配方中最多进行两次合成。' ]) print(note) while True: luckycolor = None max_step = -1 while luckycolor is None: try: luckycolor_str = input('>>> ') luckycolor = luckycolor_str.split() luckycolor = [int(x) for x in luckycolor] if len(luckycolor) < 3 or len(luckycolor) > 4: raise ValueError if len(luckycolor) == 4: max_step = luckycolor[3] luckycolor = luckycolor[:3] except Exception: print('幸运色颜色格式错误qwq') luckycolor = None print('正在寻找最接近的可合成颜色...') name, dist = find_closest_color(leather_color_cache, luckycolor, max_step=max_step) color = decode_color(name) print('最接近的可合成颜色为: {0}{1},曼哈顿距离误差为:{2}'.format( name, tuple(color), dist )) show_protection(dist) print('查找配方中...') crafting_steps = query_recipe(recipes, name) print('合成配方如下:') explain_recipe(crafting_steps)