Was ist der beste Weg, um eine kombinatorische Explosion von Interaktionen aufzulösen?

9

Eines der Dinge, an denen ich gerade arbeite, hat einige Ähnlichkeiten mit einem Spiel. Zur Veranschaulichung werde ich mein Problem anhand eines Beispiels erläutern, das aus einem fiktiven hypothetischen Spiel stammt.

Nennen wir es DeathBlaster 4: Die Deathening . In DB4 haben Sie eine Reihe von Ship -Objekten, die periodisch und zufällig auf Phenomena treffen, während sie reisen. Ein gegebenes Phenomenon kann null, eins oder mehr Effects auf einem Ship haben, das darauf trifft. Zum Beispiel könnten wir vier Arten von Ships und drei Arten von Phenomena haben.

%Vor%

Zusätzlich kann Effects miteinander interagieren. Zum Beispiel kann ein GreenShip , das sowohl in GravityWell als auch in NebulaField liegt, eine Art Synergie zwischen den generierten SpeedEffect und ShieldEffect ableiten. In solchen Fällen ist der synergistische Effekt selbst ein Effect - zum Beispiel könnte ein PowerLevelSynergyEffect aus dieser Interaktion resultieren. Keine andere Information als die Menge von Effects , die auf eine Ship wirkt, wird benötigt, um zu klären, was das Endergebnis sein soll.

Sie sehen vielleicht ein Problem, das hier auftaucht. Als naive erste Herangehensweise muss jeder Ship wissen, wie er mit jedem Phenomenon umgehen kann, oder jeder Phenomenon muss über jeden Ship Bescheid wissen. Dies ist offensichtlich inakzeptabel, daher möchten wir diese Verantwortung anderswo verschieben. Offensichtlich gibt es hier mindestens eine externe Klasse, vielleicht eine Mediator oder Visitor irgendeiner Art.

Aber was ist der beste Weg, das zu tun? Die ideale Lösung wird wahrscheinlich diese Eigenschaften haben:

  • Genauso einfach, ein neues Ship hinzuzufügen, wie es ist, ein neues Phenomenon hinzuzufügen.
  • Interaktionen, die keine Auswirkungen haben, sind die Standardeinstellung und erfordern keinen zusätzlichen Code zur Darstellung. Konvention über Konfiguration.
  • Versteht, wie Effects miteinander interagieren und diese Interaktionen verwalten können, um zu entscheiden, was das Endergebnis sein wird.

Ich habe bereits entschieden, wie mein Ansatz aussehen wird, denke ich, aber ich bin interessiert zu hören, was der best-design-Konsens ist. Wo würdest du anfangen? Welche Wege würden Sie erkunden?

Folge-Update: Vielen Dank für Ihre Antworten. Hier ist, was ich getan habe. Meine Hauptbeobachtung war, dass die Anzahl der verschiedenen Effects im Verhältnis zur Anzahl der möglichen% Co_de% × Phenomena Wechselwirkungen klein zu sein scheint. Das heißt, obwohl es viele mögliche Kombinationen von Interaktionen gibt, ist die Anzahl der Arten von Ergebnissen dieser Interaktionen eine kleinere Zahl.

Sie können sehen, dass zum Beispiel, obwohl es 12 Interaktionskombinationen in der Tabelle gibt, nur fünf Arten von Effekten gibt: Modifikationen an Geschwindigkeit, Modifikationen an der Macht, Modifikationen an Schild, Unverwundbarkeit, Tod.

Ich habe eine dritte Klasse eingeführt, die Ships , um das Ergebnis von Interaktionen zu bestimmen. Es enthält ein Dictionary, das InteractionResolver -Paare auf Ship-Phenomenon abbildet (was im Prinzip ein Delegat ist, der den Effekt und einige Metadaten ausführt). Jedes Effects erhält ein Ship , das dem EffectStack entspricht, das auftritt, wenn das Ergebnis der Berechnung der Interaktion abgeschlossen ist.

Effects Verwenden Sie dann Ships , um das tatsächliche Ergebnis von EffectStack zu ermitteln, indem Sie den vorhandenen Attributen und Eigenschaften Modifikatoren hinzufügen.

Ich mag das, weil:

  1. Schiffe brauchen nie etwas über Phänomene zu wissen.
    • Die Komplexität der Ship-Phenomena-Beziehung wird in den InteractionResolver abstrahiert.
    • Die Details zur Behebung mehrerer und möglicherweise komplexer Effekte werden durch Effects abstrahiert. Schiffe müssen die Effekte nur bei Bedarf anwenden.
    • Dies ermöglicht zusätzliche nützliche Refactorings. Zum Beispiel könnte der Weg , in dem ein Schiff Effekte verarbeitet, durch ein InteractionResolver unterschieden werden. Der Standard könnte sein, alle Effekte zu verarbeiten, aber ein EffectProcessorStrategy könnte kleinere Effekte ignorieren, indem er ein anderes BossShip .
    • verwendet
John Feminella 25.03.2009, 23:55
quelle

7 Antworten

1

Eine interessante mögliche Option wäre die Verwendung einer Variante des Besuchermusters .

Judith Bishop und R. Nigel Horspool haben einen Artikel über Entwurfsmustereffizienz geschrieben, in dem Sie erklärten verschiedene Varianten des klassischen Besuchermusters mit C # 3-Funktionen.

Insbesondere würde ich mir ansehen, wie sie mit Delegierten zusammenarbeiten, um das Besuchermuster zu handhaben. Das Verwenden einer Liste oder eines Stapels von Delegaten könnte Ihnen eine interessante Möglichkeit geben, mehrere Effekte von mehreren Objekten zu handhaben und es ist viel einfacher, beide Seiten der Klassenhierarchie zu erweitern (Schiffe hinzufügen oder Effekte hinzufügen), ohne große Änderungen am Code vorzunehmen.

    
Reed Copsey 26.03.2009, 00:14
quelle
0

Nicht ganz eine Antwort, aber für mich schreit das ziemlich "Eigenschaftsmuster". Es gibt ein bekanntes Geschwätz darüber, ich denke, es wird dir ein paar anständige Hinweise geben.

Ссылка

    
callingshotgun 26.03.2009 00:05
quelle
0

Das sieht nach dem klassischen OOP-Polymorphismus / Besucher-Dilemma aus. Ihre Anforderungen machen es jedoch einfacher.

Grundsätzlich würde ich eine Basisklasse Ship erstellen, von der alle konkreten Schiffe stammen. Diese Klasse hätte Methoden:

%Vor%

mit leeren Standardkörpern. Wenn Sie ein neues Phänomen hinzufügen, fügen Sie einfach eine neue Methode mit leerem Körper hinzu. (Die Methoden können Argumente haben, wie Koordinaten oder das Gewicht des Schwarzen Lochs etc.)

Für die Effekte und ihre Interaktion - ich denke, du solltest mehr Informationen darüber hinzufügen, wie du es willst, z. Sind die Wechselwirkungen selten oder üblich, sind sie kumulativ, sind sie auf eine begrenzte Anzahl von Variablen beschränkt, die sie kontrollieren ...

    
jpalecek 26.03.2009 00:12
quelle
0

Klingt wie ein klassisches Problem mit mehreren Zustellungen für mich.

    
user60401 26.03.2009 00:20
quelle
0

Interessante Frage

Auf die eine oder andere Weise muss ein Schiff wissen, welche Phänomene es beeinflussen können und welche Auswirkungen es auf welchem ​​Schiff hat.

Dies könnte in einer XML-Datei gespeichert werden, die zur Laufzeit geparst wird.

Vielleicht könnten Sie das Dekorationsmuster verwenden, um die Effekte zu berechnen. Sie generieren verschiedene Phänomene zur Laufzeit.

Angenommen, Ihre Schiffe implementieren ein Interface IShip und überall in Ihrem Code verwenden Sie IShips.

Nehmen Sie jetzt an, dass alle Ihre Phänomene auch das Interface IShip (das vom Dekorator-Designmuster benötigt wird) implementieren.

%Vor%

Bei den Phänomenen werden die Methoden vom ursprünglichen Schiff umschlossen, sodass Sie die Eigenschaften und alles ändern können.

Wenn Sie das Strategie-Muster verwenden, können Sie auch beliebige andere Phänomene erzeugen.

>

Das Entfernen eines Phänomens kann verwendet werden, indem man den Stapel dekorierter Schiffe, die man hat, durchwandert und umwickelt, so dass ich dort kein Problem sehe.

Was die Synergien angeht, denke ich, dass ich ein leicht modifiziertes Phänomen verwenden würde, das nur funktioniert, wenn das Zielschiff alle Phänomene auf sich hat.

    
Martin 26.03.2009 00:22
quelle
0
  

muss jedes Schiff wissen   wie man mit jedem Phänomen umgeht, oder   jedes Phänomen muss es wissen   über jedes Schiff.

Ich denke, das ist der Schlüssel zu Ihrem Problem und es ist wahr, wenn jede Schiffsphänomen-Interaktion einzigartig ist. In der Tabelle, die Sie erstellt haben, scheint dies der Fall zu sein, also müssen Sie für n Schiffe und m Phänomene n * m Interaktion angeben. Sie haben Recht, ein Wartungsproblem zu riechen.

Der einzige Ausweg besteht darin, Schiffsphänomenwechselwirkungen nicht so einzigartig zu machen, indem man den Effekt von Phänomenen von den Eigenschaften des Schiffes abhängig macht. Zum Beispiel könnten wir sagen, dass nur Schiffe, die mit merkwürdigem Aluminiumoxid gebaut sind, ein schwarzes Loch überleben werden.

Aber wenn Sie nur eine Eigenschaft haben, kaufen Sie nichts, Sie könnten genauso gut angeben, welche Schiffe von schwarzen Löchern betroffen sind. Der Schlüssel ist, dass mehrere Eigenschaften die gleiche kombinatorische Explosion aufweisen.

So werden Schiffe, die mit merkwürdigem Aluminiumoxid gebaut sind, schwarze Löcher überleben, und Schiffe, die ohne gebaut werden, können schneller gehen. 1 Eigenschaft erlaubt Ihnen, 2 Dinge zu spezifizieren (1 Bit = 2 Möglichkeiten). Schiffe mit Corbite-Triebwerken werden in einer Warp-Zone schneller gehen. Schiffe mit Corbite-Triebwerken und eigenartigem Aluminiumoxid werden 50% Schild in einem Nebelfeld usw. erhalten.

Das Hinzufügen von Eigenschaften zu Schiffen ermöglicht es Ihnen, zu vermeiden, wie jedes Phänomen mit jedem Schiff interagiert, und dennoch haben jedes Phänomen und jedes Schiff ein angemessenes Verhalten.

Wenn es M Schiffe gibt, dann brauchen Sie nur log2 (M) Eigenschaften, um jedem Schiff ein einzigartiges Verhalten zu geben.

    
Paul 26.03.2009 00:41
quelle
0

Ich denke, die Antwort eines Problems hängt davon ab, wie gut die Frage ist.

Ich denke, der Weg zum Design hängt davon ab, was die Frage ist (oder die Frage wird in der Zukunft gehen)

Sie geben eine Tabelle, dann denke ich, dass die Lösung eine Tabelle pflegen und abfragen soll.

Python-Code hier: (nicht getestet und zeigt nur für ein Beispiel)

%Vor%

Wenn die Prozessmethode geändert wurde, ändern Sie einfach die Prozessmethode in der Phenomena-Klasse.

Wenn Sie denken, dass das Schiff wissen muss, wie man Phänomene verarbeitet, dann ändern Sie die Prozessmethode in die Schiffsklasse.

oder du denkst, es gibt andere Dinge, nicht nur Phänomene müssen den Status eines Schiffes ändern (wie andere Schiffe, Untiefen), Sie müssen eine Prozesstabelle in der Schiffsklasse pflegen und Phänomene dazu machen,

Sprechen Sie noch einmal, wie Design ist abhängig von der Frage selbst.

    
linjunhalida 27.03.2009 03:34
quelle