解决交互组合爆炸的最佳方法是什么? [英] What's the best way to resolve a combinatorial explosion of interactions?

查看:162
本文介绍了解决交互组合爆炸的最佳方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我现在正在做的一件事情与游戏有一些相似之处。为了说明起见,我将使用一个虚拟的假设游戏中的示例来说明我的问题。


我们将其称为 DeathBlaster 4:The Deathening 。在DB4中,您有许多 Ship 对象,它们在旅行时定期且随机遇到现象。给定的现象效果 c $ c>遇到它。例如,我们可能有四种和三种现象

 
现象
=================================== =======
运送GravityWell BlackHole NebulaField
------------ ------------------- -----------------------
RedShip + 20%速度-50%力量-50%盾
BlueShip无影响各种
GreenShip -20%的速度死亡+ 50%的盾牌现象在船舶上
YellowShip的死亡+ 50%的力量没有影响

此外,效果可能会相互影响。例如,在 GravityWell NebulaField 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 new Phenomenon.
  • 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:

  • Ships never need to know about Phenomena.
  • The complexity of the Ship-Phenomena relationship is abstracted into the InteractionResolver.
  • 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, a BossShip might ignore minor effects by having a different EffectProcessorStrategy.

解决方案

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆