Я пытаюсь создать словарь, который выглядит так (для забавного проекта):
_cardLibrary = {
1: {'name': 'Strike',
'cost': 1,
'type': 'attack',
'rarity': 'common',
'action': [deal_damage]
},
2: {'name': 'Defend',
'cost': 1,
'type': 'skill',
'rarity': 'common',
'action': [give_block]
},
3: {'name': 'Bash',
'cost': 2,
'type': 'attack',
'rarity': 'common',
'action':
[deal_damage,
apply_status]
}
}
Я хотел бы создать функцию " use (i) ", которая берет конкретную карту и выполняет код, хранящийся внутри "action". Как вы можете видеть в третьем элементе, «действие» должно содержать несколько функций, каждая из которых требует определенных аргументов.
Например, Deal_damage требует 3 аргумента. Применить статус требует 4.
Deal_damage (заклинатель, цель, базовый урон) apply_status (заклинатель, цель, статус, интенсивность)
Есть ли способ создать функцию, которая вызывает все функции, хранящиеся внутри каждой конкретной карты?
Мне также нужен какой-то способ передать фактические аргументы каждой из функций... Некоторые из аргументов могут быть постоянными значениями. Например, для этой конкретной карты статус всегда равен 1, а интенсивность равна 1. Однако цель и заклинатель действительно должны быть определены в функции начального использования (заклинатель, цель)...
До сих пор я пытался перебрать каждую функцию, однако это оставляет меня с проблемой невозможности передать конкретные аргументы каждой функции...
Я также попробовал эту ссылку: Python: итерация функций с разными аргументами
Но по какой-то причине я не могу заставить код работать
Если это вообще не работает, я рассматривал возможность сделать каждую отдельную карту функцией, однако это проблематично по другим причинам... особенно в отношении масштабируемости.
Любые идеи о том, как я могу подойти к этому?
Спасибо вам всем
Когда очередь начинается, так сказать, вы сами определяете аргументы. Таким образом, если вы хотите нанести врагу урон, вы просто выполняете Deal_damage('self', 0, 10), чтобы нанести 10 единиц урона врагу с номером 0. Когда враг атакует, его формулы будут выглядеть как Deal_damage(0 ,'я',10) вместо этого. Если это действие должно было применить статус, аргументы статуса также должны быть определены... Карты должны попытаться сгруппировать действия. Таким образом, только определяя заклинателя и цель, другие аргументы уже будут определяться самой картой ... я ответил на ваш вопрос?
Итак, если я правильно понимаю, у всех функций есть аргументы caster и target, но другие аргументы не совпадают между функциями? И эти другие аргументы остаются неизменными на протяжении всей игры?
Нет, они меняются. Они специфичны для каждой карты. возможно, я мог бы сохранить эти определенные аргументы в самой карте. Например, Bash должен применить 2 интенсивности статуса 1. Каждая другая карта будет чем-то похожа.
«Итак, если вы хотите нанести урон врагу, вы просто выполните Deal_damage('self', 0, 10), чтобы нанести 10 единиц урона врагу с номером 0». Нет, это не вопрос. Предположим, что код выбирает карту 'Strike'. Как вы узнаете значения, которые должны быть переданы для вызова deal_damage? Когда вы используете карту 'Bash', я предполагаю, что caster и target будут одинаковыми и что они выбираются извне в зависимости от того, кто разыграл карту, верно? А вот урон, который будет нанесен цели - откуда он? Какой статус будет применяться, с какой интенсивностью?
Возможно, эта информация является неотъемлемой частью карты? Или это будет зависеть от некоторой информации, которую можно получить от заклинателя и/или цели? (В последнем случае, почему эти отдельные параметры, если мы все равно должны передавать заклинателя и цель?) В принципе, вопрос еще недостаточно четко определен; вам нужно больше думать о том, что должно произойти, когда разыгрывается карта.
Ты прав Карл, я строю систему как бы "на лету". Пока работает, но я все еще думаю об общей игровой петле. Вместо того, чтобы быть «карточной игрой», это должен быть ИИ, который выбирает лучшую игровую карту в любое время, учитывая вероятность того, что может произойти в следующие ходы. Чтобы полностью ответить на ваш вопрос. Конкретные аргументы функции нанесения урона действительно присущи каждой карте. Удар, всегда наносит 6 единиц урона. Bash всегда применяет к цели один и тот же статус и наносит 8 единиц урона. и т.д. То же самое для блочных карт
Однако одна и та же функция Deal_damage() ведет себя по-разному в зависимости от цели и заклинателя. Например, если заклинатель имеет «+3 к силе», то атака нанесет цели урон +3. Если цель в данный момент находится под действием «уязвимости», она получит на 50% больше урона и так далее…
Вы можете использовать functools.partial, чтобы предварительно определить некоторые аргументы для каждой функции. Затем, когда вам нужно вызвать функции, вам нужно будет указать только аргументы caster и target:
from functools import partial
def deal_damage(caster, target, basedamage):
print(f"{caster} dealt {basedamage} damage to {target}")
def give_block(caster, target, defense):
print(f"{caster} blocked {defense} damage from {target}")
def apply_status(caster, target, status, intensity):
print(f"{caster} applied {intensity}x{status} to {target}")
_cardLibrary = {
"strike": {'name': 'Strike',
'cost': 1,
'type': 'attack',
'rarity': 'common',
'actions': [partial(deal_damage, basedamage=10)]
},
"defend": {'name': 'Defend',
'cost': 1,
'type': 'skill',
'rarity': 'common',
'actions': [partial(give_block, defense=5)]
},
"bash": {'name': 'Bash',
'cost': 2,
'type': 'attack',
'rarity': 'common',
'actions':
[partial(deal_damage, basedamage=5),
partial(apply_status, status='stun', intensity=5)]
}
}
Обратите внимание, что я изменил ключи словаря на строки, а ключ 'action' в каждой карточке на 'actions', потому что на одной карточке может быть несколько действий.
Затем в игровом цикле вы можете вызывать эти partial объекты как обычную функцию:
while True:
print(f"You have {len(_cardLibrary)} cards: ")
print(", ".join(_cardLibrary))
u_in = input("What would you like to do? (or quit) ").lower()
if u_in == "quit":
print("Goodbye")
break
try:
card = _cardLibrary[u_in]
except KeyError:
print("Invalid choice. Please choose again")
continue
print(f"You played the {card['name']} card")
for action in card['actions']:
print("ACTION: ", end = "")
action(caster = "You", target = "Enemy")
Это дает следующий результат:
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) strike
You played the Strike card
ACTION: You dealt 10 damage to Enemy
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) bash
You played the Bash card
ACTION: You dealt 5 damage to Enemy
ACTION: You applied 5xstun to Enemy
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) defend
You played the Defend card
ACTION: You blocked 5 damage from Enemy
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) quit
Goodbye
Я буду пробовать это прямо сейчас. Большое спасибо!! Кроме того, как вы пишете код так быстро!? Вы еле ответили за 5 минут. Большое спасибо!!!! :)
Сделал именно это. Еще раз спасибо, приятель.
Вы можете сделать так, чтобы все ваши списки параметров функций заканчивались ,**_, что позволит им получать (и игнорировать) параметры, которые они на самом деле не обрабатывают. Это позволит вам добавлять параметры с фиксированными значениями непосредственно в словарь _cardLibrary и использовать их в качестве параметров функций. Затем определите свою функцию use(), чтобы добавить свой собственный список именованных аргументов к фиксированным значениям словаря в качестве переопределения:
def deal_damage(caster,target,basedamage,**_):
# ...
def use(card, **kwargs):
for function in _cardLibrary[card]['action']:
function(**{**_cardLibrary[card],**kwargs})
Применение:
use(1,caster = "orc",target = "human")
# assuming _cardLibrary supplies the default value for "baseDamage" on card #1
Чувак, я действительно иногда чувствую себя таким нубом. Я даже не знал, что ты можешь это сделать. Это супер полезно. Большое спасибо!
Откуда вы берете эти аргументы? То есть, если бы у вас была только одна функция в списке actions, как бы вы ее назвали? Все ли они имеют одни и те же переменные аргументы, и только постоянные аргументы меняются между функциями?