如何用Python基于输入物料集合计算所有可行配方产出组合?
配方物料组合计算功能实现
问题背景
我有一个名为recipes.csv的CSV文件,内容如下:
name,alternate,time,ingredients,products,producedIn,classifiedAs Iron Plate,False,6,30.0x Iron Ingot,20.0x Iron Plate,Constructor,Iron Iron Rod,False,4,15.0x Iron Ingot,15.0x Iron Rod,Constructor,Iron Wire,False,4,15.0x Copper Ingot,30.0x Wire,Constructor,Copper...
功能需求
给定输入物料字典(示例输入):
{'Iron Ingot':60, 'Copper Ingot':20}
需要生成所有可能的制作结果列表,每个元素为字典:
- 键为配方名称,值为该配方的可制作数量
- 包含
Leftover键,对应剩余物料的字典
示例输出:
[ {'Iron Plate':2, 'Wire':1, 'Leftover':{'Copper Ingot':5}}, {'Iron Rod':4, 'Wire':1, 'Leftover':{'Copper Ingot':5}}, {'Iron Plate':1,'Iron Rod':2, 'Wire':1, 'Leftover':{'Copper Ingot':5}}, ]
现有代码
目前已完成配方文件的初步读取,但未实现核心计算逻辑:
import csv import pandas as pd df = pd.read_csv("recipes.csv", usecols = ['name','ingredients', 'products']) # Original Header: ['name', 'alternate', 'time', 'ingredients', 'products', 'producedIn', 'classifiedAs'] # New Header: ['name', 'ingredients', 'products'] # Iron Plate: #139 # Iron Rod: #140 # Wire: #214 df.to_csv('recipes_new.csv') with open('recipes_new.csv') as csvFile: recipes = csv.reader(csvFile) # Print out recipes: i = 0 for row in recipes: print(row) i += 1
完整实现方案
核心思路
- 解析配方数据:将CSV中的字符串格式配料、产物转换为结构化的字典,方便后续计算
- 枚举有效组合:筛选出可用配方,计算每个配方的最大制作数量,生成所有不超出物料限制的数量组合
- 计算剩余物料:对每个有效组合,统计物料消耗并计算剩余量,整理成要求的输出格式
完整代码
import pandas as pd from itertools import product import pprint def parse_quantity_item(s): """解析类似'30.0x Iron Ingot'的字符串,返回(数量, 物料名)""" parts = s.strip().split('x ', 1) quantity = float(parts[0]) item = parts[1] return quantity, item def load_recipes(csv_path): """加载并解析配方CSV,返回结构化的配方列表""" df = pd.read_csv(csv_path, usecols=['name', 'ingredients', 'products']) recipes = [] for _, row in df.iterrows(): # 解析配料 ing_map = {} for ing_str in row['ingredients'].split(', '): qty, item = parse_quantity_item(ing_str) ing_map[item] = qty # 解析产物(默认每个配方对应单一产物) prod_qty, prod_name = parse_quantity_item(row['products']) recipes.append({ 'name': row['name'], 'ingredients': ing_map, 'output_qty': prod_qty, 'product': prod_name }) return recipes def generate_possible_combinations(recipes, initial_materials): """生成所有符合物料限制的制作组合""" # 筛选可制作的配方(至少能做一次) valid_recipes = [] for rec in recipes: can_make = True for item, req_qty in rec['ingredients'].items(): if item not in initial_materials or initial_materials[item] < req_qty: can_make = False break if can_make: valid_recipes.append(rec) # 计算每个配方的最大制作数量 max_counts = [] for rec in valid_recipes: current_max = float('inf') for item, req_qty in rec['ingredients'].items(): count = int(initial_materials[item] // req_qty) if count < current_max: current_max = count max_counts.append(current_max) # 生成所有可能的数量组合(包含0,后续跳过全0) count_ranges = [range(0, mc+1) for mc in max_counts] all_combinations = product(*count_ranges) results = [] for counts in all_combinations: if sum(counts) == 0: continue # 计算该组合的总物料消耗 total_consumed = {item: 0 for item in initial_materials} valid = True for rec, cnt in zip(valid_recipes, counts): if cnt == 0: continue for item, req_qty in rec['ingredients'].items(): consumed = req_qty * cnt if total_consumed[item] + consumed > initial_materials[item]: valid = False break if not valid: break total_consumed[item] += req_qty * cnt if not valid: continue # 计算剩余物料 leftover = {} for item, init_qty in initial_materials.items(): remaining = init_qty - total_consumed[item] if remaining > 0: leftover[item] = remaining # 整理结果字典 result_dict = {} for rec, cnt in zip(valid_recipes, counts): if cnt > 0: result_dict[rec['name']] = cnt result_dict['Leftover'] = leftover results.append(result_dict) return results # 示例运行 if __name__ == "__main__": # 加载配方 recipe_list = load_recipes('recipes.csv') # 初始物料 starting_materials = {'Iron Ingot':60, 'Copper Ingot':20} # 生成结果 possible_results = generate_possible_combinations(recipe_list, starting_materials) # 格式化打印 pprint.pprint(possible_results)
代码说明
parse_quantity_item:处理配方中的数量和物料名称拆分,将字符串转为可计算的数值和名称load_recipes:读取CSV并转换为结构化的配方数据,每个配方包含名称、所需物料、产出数量等信息generate_possible_combinations:核心逻辑,负责筛选有效配方、生成数量组合、验证物料消耗、计算剩余物料并整理结果
运行上述代码后,将得到与示例一致的输出结果。
内容的提问来源于stack exchange,提问作者dimani128
相关产品推荐
相关产品推荐

