Das Crafting-System in Minecraft verwendet ein 2x2- oder 3x3-Raster. Sie legen Zutaten auf das Gitter und wenn Sie die richtigen Zutaten in das richtige Muster setzen, wird das Rezept aktiviert.
Einige interessante Punkte zum Design:
- Einige Rezepte können bestimmte Zutaten gegen andere austauschen. Zum Beispiel verwendet ein Pick Stöcke für den Griff und kann Holzbretter, Kopfsteinpflaster, Eisenbarren, Goldbarren oder Diamantedelsteine für den Kopf verwenden.
- Es kommt auf die relative Position innerhalb des Musters an, nicht auf die absolute Position auf dem Gitter. Das heißt, Sie können eine Fackel herstellen, indem Sie den Stab und die Kohle (oder Holzkohle) im richtigen Muster an einer der sechs Positionen des 3x3-Gitters platzieren.
- Muster können horizontal gespiegelt werden.
Ich mag es überdenken, aber dies scheint ein interessantes Problem bei der Suche / Reduzierung von Sätzen zu sein. Wie funktioniert (oder könnte) das algorithmisch?
minecraft-modding
patterns
search
David Eyk
quelle
quelle
Antworten:
Eine andere Lösung besteht darin, einen etwas komplizierten Baum zu verwenden. Die Verzweigungsknoten in Ihrem Baum werden erstellt, indem Sie das Rezept durchlaufen (erneut verwenden
for (y) { for (x) }
). Dies ist Ihre Standard-Baumstruktur. Ihr letzter Knoten würde eine zusätzliche Struktur (Dictionary
/HashMap
) enthalten, die den Rezepten Dimensionen zuordnet.Im Wesentlichen geht es um Folgendes:
Die schwarzen Knoten sind Ihre Zweige, die den Elementtyp angeben - die roten sind Ihre Blätter (Abschlusszeichen), mit denen Sie Größe / Ausrichtung unterscheiden können.
Um diesen Baum zu durchsuchen, müssen Sie zuerst den Begrenzungsrahmen finden (wie in meiner ersten Antwort beschrieben ) und dann die Knoten in der gleichen Reihenfolge durchlaufen, in der Sie den Baum durchlaufen. Schließlich würden Sie einfach die Dimension in Ihrem
Dictionary
oder nachschlagenHashMap
und das Ergebnis des Rezepts erhalten.Nur zum Spaß habe ich das implementiert - was wahrscheinlich meine Antwort verdeutlichen wird. Außerdem : Mir ist klar, dass dies eine andere Antwort ist - und das zu Recht: Es ist eine andere Lösung.
quelle
Sie müssen sich daran erinnern, dass Minecraft nur einen sehr kleinen Satz möglicher Rezepte verwendet, so dass nichts allzu Schlaues erforderlich ist.
Das heißt, ich würde das kleinste Gitter finden, das passt (dh leere Zeilen und Spalten ignorieren, um herauszufinden, ob es ein 2x2 oder 3x3 oder 2x3 (Tür) ist). Durchlaufen Sie dann die Liste der Rezepte mit dieser Größe und überprüfen Sie einfach, ob der Elementtyp derselbe ist (dh im schlimmsten Fall 9 Ganzzahlvergleiche in Minecraft, da eine Ganzzahltyp-ID für Elemente und Blöcke verwendet wird), und hören Sie auf, wenn Sie eine Übereinstimmung finden.
Auf diese Weise wird auch die relative Position der Gegenstände irrelevant (Sie können eine Fackel an einer beliebigen Stelle auf dem Herstellungsgitter platzieren und es funktioniert, da es sich um eine 1x2-Box handelt, nicht um eine 3x3-Box, die größtenteils leer ist).
Wenn Sie eine große Anzahl von Rezepten haben, so dass eine lineare Suche durch die möglichen Übereinstimmungen zu lange dauert, ist es möglich, die Liste zu sortieren und eine binäre Suche durchzuführen (O (log (N)) vs O (N)). Dies würde einige zusätzliche Arbeit beim Erstellen der Liste verursachen, kann jedoch beim Start einmal ausgeführt und anschließend im Speicher behalten werden.
Um das Rezept am einfachsten horizontal spiegeln zu können, fügen Sie einfach die gespiegelte Version zur Liste hinzu.
Wenn Sie dies tun möchten, ohne ein zweites Rezept hinzuzufügen, können Sie überprüfen, ob das Eingangsrezept einen Eintrag in [0,0] mit einer höheren ID als in [0,2] (oder [0,1] für 2x2 hat, ohne dass eine Überprüfung erforderlich ist für 1x2 und wenn ja, spiegeln Sie es, wenn Sie die nächste Zeile nicht bis zum Ende durchsehen, und stellen Sie sicher, dass die Rezepte in der richtigen Rotation hinzugefügt wurden.
quelle
Zu sehen, ob eine bestimmte Gitterkonfiguration mit einem bestimmten Rezept übereinstimmt, ist einfach, wenn Sie das 3x3-Gitter als Zeichenfolge codieren und eine Übereinstimmung mit regulären Ausdrücken verwenden . Das Nachschlagen zu beschleunigen ist eine andere Sache, über die ich am Ende sprechen werde. Lesen Sie weiter für weitere Informationen.
Schritt 1) Codiere das Gitter als String
Geben Sie einfach eine Zeichen-ID für jeden Zellentyp an und verknüpfen Sie alles in dieser Reihenfolge nebeneinander:
Betrachten Sie als konkretes Beispiel das Stabrezept, bei dem W für Holz steht und E eine leere Zelle ist (Sie könnten einfach ein leeres Zeichen '' verwenden):
Schritt 2) Rezept mit regulärem Ausdruck abgleichen (oder String.Contains mit ein wenig Verarbeitung der Daten)
Selbst wenn wir die Formation bewegen, befindet sich im obigen Beispiel noch ein Muster in der Zeichenfolge (WEEW wird auf beiden Seiten mit E aufgefüllt):
Unabhängig davon, wo Sie den Stick bewegen, entspricht er dem folgenden regulären Ausdruck:
/^E*WEEWE*$/
Mit regulären Ausdrücken können Sie auch das von Ihnen erwähnte bedingte Verhalten ausführen. Zum Beispiel (erfundenes Rezept), wenn Sie eine Spitzhacke aus Eisen oder Stein haben möchten , um das gleiche Ergebnis zu erzielen:
Sie können beide zu einem regulären Ausdruck kombinieren:
/^(III)|(SSS)EWEEWE$/
Genauso einfach können auch horizontale Flips hinzugefügt werden (auch mit dem Operator |).
Bearbeiten: Wie auch immer, der Regex-Teil ist nicht unbedingt erforderlich. Dies ist nur eine Möglichkeit, das Problem in einem einzelnen Ausdruck zu kapseln. Für das Problem mit der variablen Position können Sie jedoch auch die Rasterzeichenfolge aller Auffüllbereiche (oder in diesem Beispiel die von "E") abschneiden und ein String.Contains () ausführen. Und für das Problem mit mehreren Zutaten oder die gespiegelten Rezepte könnten Sie einfach alle als mehrere (dh separate) Rezepte mit derselben Ausgabe behandeln.
Schritt 3) Beschleunigen der Suche
Um die Suche zu reduzieren, müssen Sie eine Datenstruktur erstellen, um Rezepte zu gruppieren und bei der Suche zu helfen. Das Behandeln des Gitters als Zeichenfolge hat auch hier einige Vorteile :
Sie können die "Länge" eines Rezepts als den Abstand zwischen dem ersten nicht leeren Zeichen und dem letzten nicht leeren Zeichen definieren. Ein einfacher
Trim().Length()
würde Ihnen diese Informationen geben. Rezepte können nach Länge gruppiert und in einem Wörterbuch gespeichert werden.oder
Eine alternative Definition von "Länge" könnte die Anzahl nicht leerer Zeichen sein. Sonst ändert sich nichts. Sie können Rezepte auch nach diesen Kriterien gruppieren.
Wenn Punkt Nummer 1 nicht ausreicht, können die Rezepte auch nach der Art der ersten Zutat, die im Rezept enthalten ist, weiter gruppiert werden. Dies wäre so einfach wie das Ausführen
Trim().CharAt(0)
(und das Sichern gegen Trimmen, was zu einer leeren Zeichenfolge führt).So würden Sie beispielsweise Rezepte speichern in:
Und führen Sie die Suche wie folgt aus:
quelle
Ich kann dir nicht sagen, wie Minecraft funktioniert - obwohl ich mir sicher bin, dass du es herausfinden könntest, wenn du dir MCP ansiehst (wenn du eine legale Kopie von Minecraft hast).
Ich würde das wie folgt umsetzen:
for (y) { for (x) }
).Nehmen wir zum Beispiel an, wir haben zwei Zutaten; X und Y und Leerzeichen sind *. Nimm das folgende Rezept:
Zuerst erarbeiten wir den Begrenzungsrahmen und geben nach
(2,0)-(2,2)
. Daher würde unser Schlüssel so aussehen[1][3]
(1 Breite, 3 Höhe). Als nächstes durchlaufen wir jedes Element innerhalb des Begrenzungsrahmens und hängen die ID an, so dass der Schlüssel wird[1][3][X][Y][Y]
- Sie sehen dies dann in Ihrem Wörterbuch / Ihrer Datenbank nach und erhalten das Ergebnis dieses Rezepts.Beachten Sie das folgende Rezept, um die Unabhängigkeit in Schritt 2 klarer zu erläutern:
Oben / links steht eindeutig 0,0 - das erste Element, auf das Sie normalerweise stoßen, ist jedoch entweder 0,1 oder 1,0 (abhängig von Ihrer Schleife). Wenn Sie jedoch die erste nicht leere Spalte sowie die erste nicht leere Zeile finden und diese Koordinaten kombinieren, erhalten Sie 0,0 - das gleiche Prinzip gilt für die untere / rechte Ecke des Begrenzungsrahmens.
quelle
So habe ich es in Block Story gemacht:
quelle