Похоже, элегантным решением для этого является линейное программирование . Я могу помочь с этим, если вы предоставите более подробную информацию.
только с 88 предметами, разбросанными по десяти слотам, грубое принуждение также не будет ужасным. Некоторая комбинация двух может быть самой легкой.
Обновление:
Основываясь на обновлении, которое вы дали, я думаю, что линейное программирование излишне (и его трудно применить). Я написал вам это довольно общее решение. Изучите это и поймите это. Если у кого-то есть исправления или улучшения, я бы хотел их услышать.
from itertools import ifilter, product
# Definition of ITEMS cut for brevity. See below.
def find_best(slots, maximize, constraints):
"""example call:
find_best(['helm', 'chest'], ['slashing', 'bludgeon'],
{'encumbrance': 12})
"""
# save the slot names to construct a nice return value
slot_names = slots
# pull the actual lists of items for each slot out of the global dict
slots = [ITEMS[slot] for slot in slots]
# this function calculates the value of a solution
value = lambda solution: sum(float(slot[attr]) for attr in maximize
for slot in solution)
# replace our constraints with functions to check solutions
constraints = [lambda solution:
sum(float(slot[attr]) for slot in solution) < constraint
for attr, limit in constraints.items()]
# start with all possible combinations
solutions = product(*slots)
# chain together ifilters to weed out the ones that fail any of the
# constraints. Note that for optimum performance, you should place the
# constraints in descending order of probability to fail
for constraint in constraints:
solutions = ifilter(constraint, solutions)
# We're going to do decorate, max, undecorate
solutions = ((value(solution), solution) for solution in solutions)
value, solution = max(solutions)
# get the indexes and return
return dict((name, slot.index(item)) for name, slot, item
in zip(slot_names, slots, solution))
Обратите внимание, что вы должны хранить значения как числа с плавающей запятой, а , а не как строки! Проще (потому что это часто автоматически, когда вам это нужно) приводить к строке, чем к плавающей точке. Тогда вы можете убрать уродливые броски из моего кода. Мне просто было лень делать это для тебя. Обратите внимание, что вы можете вызывать столько ограничений, сколько хотите, но только один набор атрибутов для максимизации. Это имело смысл для меня. Если вы изучите код и поймете его, вы сможете изменить его по своему вкусу.
Вот как я изменил вашу структуру данных.
ITEMS = { 'helm': [{'Acid':' 2.71',
'Bludgeoning': '1.04',
'Cold': '2.71',
'Encumbrance': '8.00',
'Fire': '2.71',
'Holy': '2.71',
'Impact': '1.30',
'Lightning': '2.00',
'Name': 'Plate Helm',
'Piercing': '1.17',
'Slashing': '1.30',
'Unholy': '2.71'},
{'Acid': '2.18',
'Bludgeoning': '0.92',
'Cold': '2.18',
'Encumbrance': '7.00',
'Fire': '2.18',
'Holy': '2.18',
'Impact': '1.15',
'Lightning': '1.65',
'Name': 'Scale Helm',
'Piercing': '1.03',
'Slashing': '1.15',
'Unholy': '2.18'}],
'chest':[{'Acid': '5.47',
'Bludgeoning': '2.05',
'Cold': '5.47',
'Encumbrance': '32.00',
'Fire': '5.47',
'Holy': '5.47',
'Impact': '2.57',
'Lightning': '4.06',
'Name': 'Plate Chest',
'Piercing': '2.31',
'Slashing': '2.57',
'Unholy': '5.47'},
{'Acid': '4.45',
'Bludgeoning': '1.84',
'Cold': '4.45',
'Encumbrance': '28.00',
'Fire': '4.45',
'Holy': '4.45',
'Impact': '2.30',
'Lightning': '3.31',
'Name': 'Scale Cuirass',
'Piercing': '2.07',
'Slashing': '2.30',
'Unholy': '4.45'}]}
обратите внимание, что значения внешнего словаря являются списками, а не кортежами, как вы сказали. Существует огромное различие!