解决交互组合爆炸的最佳方法是什么? [英] What's the best way to resolve a combinatorial explosion of interactions?
问题描述
我现在正在做的一件事情与游戏有一些相似之处。为了说明起见,我将使用一个虚拟的假设游戏中的示例来说明我的问题。
我们将其称为 DeathBlaster 4:The Deathening 。在DB4中,您有许多 Ship
对象,它们在旅行时定期且随机遇到现象
。给定的现象
在船$上可能具有零个,一个或多个
效果
c $ c>遇到它。例如,我们可能有四种船
和三种现象
。
现象
=================================== =======
运送GravityWell BlackHole NebulaField
------------ ------------------- -----------------------
RedShip + 20%速度-50%力量-50%盾
BlueShip无影响各种
GreenShip -20%的速度死亡+ 50%的盾牌现象在船舶上
YellowShip的死亡+ 50%的力量没有影响
此外, 您可能开始在这里看到一个问题。作为天真的第一方法,每个 但是最好的方法是什么?理想的解决方案可能具有以下属性: 我已经确定了我的方法,但是我很想听听最佳设计的共识是什么。你将从哪里开始?您将探索什么途径? 后续更新:感谢您的回复,大家这是我最后要做的事情。我的主要观察结果是,相对于可能的<现象> 效果
可能会相互影响。例如,在 GravityWell
和 NebulaField $ c中的
GreenShip
$ c>可能会在生成的 SpeedEffect
和 ShieldEffect
之间产生某种协同作用。在这种情况下,协同效应本身就是 Effect
-例如,可能会产生 PowerLevelSynergyEffect
这种互动。除了作用于 Ship
的一组 Effects
以外,不需要任何其他信息即可解决最终结果。 / p>
Ship
都必须知道如何处理每个现象
或每个现象
必须知道每个 Ship
。这显然是不可接受的,因此我们希望将这些责任移到其他地方。显然,这里至少有一个外部类,也许是 Mediator
或 Visitor
的某种形式。
Ship
一样容易它是添加新的现象
。
效果
如何相互影响,并能够管理这些交互来决定最终结果是什么
效果
的数量似乎很小。 c $ c> Shipp 互动。也就是说,尽管存在许多可能的相互作用的组合,但是这些相互作用的结果种类的数量却较少。
例如,您可以看到,尽管表中有12种交互组合,但只有五种种类效果:对速度的修改,对功率的修改,对屏蔽的修改,无敌性,死亡。
我介绍了第三类 InteractionResolver
,以确定交互的结果。它包含一个字典,该字典将 Ship-Phenomenon
对映射到 Effects
(基本上是执行效果的委托,有些元数据)。每个 Ship
都被交给一个 EffectStack
对应于 Effects
Ships
然后使用 EffectStack
通过在其现有属性和属性上添加修饰符来确定效果
对它们的实际结果。
我喜欢这是因为:
-
船
永远不需要了解现象
。 -
Ship
-现象
的复杂性关系被抽象到InteractionResolver
。 - <$ c抽象了如何解决多种甚至复杂效果的细节。 $ c> InteractionResolver 。船只需要根据需要应用效果。
- 这将启用其他有用的重构。例如,通过制作
EffectProcessorStrategy
可以区分船舶处理效果的 way 。默认设置可能是处理所有效果,但是,例如,BossShip
可能会通过具有不同的EffectProcessorStrategy
来忽略次要效果。 。
一个有趣的潜在选择是使用访客模式。
Judith Bishop和R. Nigel Horspool写了一篇有关设计模式效率的论文,其中他们解释了各种
特别是,我将研究它们如何与委托一起处理访问者模式。使用委托的列表或堆栈可能会为您提供一种有趣的方式来处理来自多个对象的多个效果,并且更容易扩展类层次结构的任一侧(添加功能或添加效果)而无需进行重大的代码更改。
One of the things I'm working on right now has some similarities to a game. For purposes of illustration, I'm going to explain my problem using an example drawn from a fictitious, hypothetical game.
Let's call it DeathBlaster 4: The Deathening. In DB4, you have a number of Ship
objects which periodically and randomly encounter Phenomena
as they travel. A given Phenomenon
may have zero, one, or more Effects
on a Ship
that encounters it. For example, we might have four kinds of Ships
and three kinds of Phenomena
.
Phenomena ========================================== Ships GravityWell BlackHole NebulaField ------------ ------------------------------------------ RedShip +20% speed -50% power -50% shield BlueShip no effect invulnerable death Effects of Various GreenShip -20% speed death +50% shield Phenomena on Ships YellowShip death +50% power no effect
Additionally, Effects
may interact with each other. For example, a GreenShip
that is in both a GravityWell
and a NebulaField
may derive some kind of synergy between the generated SpeedEffect
and ShieldEffect
. In such cases, the synergistic effect is itself an Effect
-- for example, there might be a PowerLevelSynergyEffect
that results from this interaction. No information other than the set of Effects
acting on a Ship
is needed to resolve what the final result should be.
You may begin to see a problem emerging here. As a naive first approach, either every Ship
will have to know how to handle every Phenomenon
, or every Phenomenon
will have to know about every Ship
. This is obviously unacceptable, so we would like to move these responsibilities elsewhere. Clearly there's at least one external class here, perhaps a Mediator
or Visitor
of some sort.
But what's the best way to do that? The ideal solution will probably have these properties:
- It's just as easy to add a new
Ship
as it is to add a newPhenomenon
. - Interactions that produce no effect are the default and don't require additional code to represent. Convention over configuration.
- Understands how
Effects
interact with each other and is capable of managing these interactions to decide what the final result will be.
I've already decided what my approach will be, I think, but I'm interested to hear what the best-design consensus is. Where would you start? What avenues would you explore?
Follow-up update: Thanks for your responses, everybody. Here's what I wound up doing. My main observation was that the number of different Effects
seems to be small relative to the number of possible Phenomena
× Ships
interactions. That is, although there are many possible combinations of interactions, the number of kinds of results of those interactions is a smaller number.
You can see that, for example, although there are 12 interaction combinations in the table, there are only five kinds of effects: modifications to speed, modifications to power, modifications to shield, invulnerability, death.
I introduced a third class, the InteractionResolver
, to determine the result of interactions. It contains a dictionary that maps Ship-Phenomenon
pairs to Effects
(which are basically a delegate that performs the effect and some metadata). Each Ship
is handed an EffectStack
corresponding to the Effects
it's experiencing when the result of computing the interaction is complete.
Ships
then use the EffectStack
to determine the actual result of the Effects
on them, by adding modifiers to their existing attributes and properties.
I like this because:
Ship
s never need to know aboutPhenomena
.- The complexity of the
Ship
-Phenomena
relationship is abstracted into theInteractionResolver
. - The details of how to resolve multiple and possibly complex effects is abstracted away by the
InteractionResolver
. Ships only have to apply the effects as necessary. - This enables additional useful refactorings. For example, the way in which a ship processes effects could be differentiated by making an
EffectProcessorStrategy
. The default might be to process all effects, but, say, aBossShip
might ignore minor effects by having a differentEffectProcessorStrategy
.
An interesting potential option would be to use a variant of the Visitor Pattern.
Judith Bishop and R. Nigel Horspool wrote a paper about design pattern efficiency in which they explained various variants on the classic visitor pattern using C# 3 features.
In particular, I would take a look at how they work with delegates to handle the visitor pattern. Using a list or stack of delegates could potentally give you an interesting way to handle multiple effects from multiple objects, and be much easier to extend either side of the class hierarchy (add ships or add effects) without huge breaking code changes.
这篇关于解决交互组合爆炸的最佳方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!