You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

完整实现方案

核心思路

  1. 解析配方数据:将CSV中的字符串格式配料、产物转换为结构化的字典,方便后续计算
  2. 枚举有效组合:筛选出可用配方,计算每个配方的最大制作数量,生成所有不超出物料限制的数量组合
  3. 计算剩余物料:对每个有效组合,统计物料消耗并计算剩余量,整理成要求的输出格式

完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:20:50