Alt-F4 #33 – Vanilla: Geschüttelt, nicht gerührt  30.04.2021

Geschrieben von Villfuk02, redlabel, editiert von stringweasel, Nanogamer7, Conor_, Therenas, Firerazer,
übersetzt von Nanogamer7, lektoriert von BluePsyduck, dexteritas

Inhaltsverzeichnis

In dieser wunderbaren 33. Ausgabe von Alt-F4 präsentiert Villfuk02 seine neuste Mod: Den Rezepte-Zufallsgenerator! Die Designprobleme, die man für einen guten Zufallsgenerator lösen muss, stehen hierbei besonders im Rampenlicht. Danach kündigt redlabel das neuste COMFY Event an, welches vermutlich sehr bombastisch wird.

Vanilla: Geschüttelt, nicht gerührt Villfuk02

Vill‘s Recipe Randomizer (zu Deutsch: „Vills Rezepte-Zufallsgenerator“) macht genau, was der Name vermuten lässt – er würfelt Rezepte neu. Auf den ersten Blick mag das zwar nach einer sehr dummen, aber einfachen Idee klingen, allerdings wird es sehr schnell sehr komplex, wenn du versuchst es weniger dumm zu machen.

Gratis Spaghetti-Kostprobe
Eine Beispielfabrik, welche Produktionswissenschaftspakete aus Ablenker-Kapseln, Stromschaltern und Brennstoff für Flammenwerfer herstellt.

Wie es begann

Angefangen habe ich mit dem Projekt im September 2020. Damals wollte ich eine Mod machen, die sowohl einfach, als auch einzigartig ist. Sie war nicht gedacht, spielbar zu sein, oder sogar gut, sondern nur etwas lustiges zum Programmieren. Nachdem ich auf ein paar Probleme gestoßen bin, gab ich mit dem Hintergedanken, dass sowieso niemand die Mod spielen würde, auf und fasste Programmieren nie wieder an.

Nach zwei weiteren gescheiterten Projekten zog es mich zurück zu Factorio, diesmal als Spieler. Ich spielte Vanilla, dann Industrial Revolution 2 und dann probierte ich Space Exploration. Ich liebe Überholungsmods, weil ich dadurch neue Rezepte lernen, neue Fabriklayouts entdecken, und neue Logistikprobleme lösen kann. Aber die meisten Überholungsmods beanspruchen sehr viel Zeit und werden schnell langweilig. Das war der Punkt, an dem mir auffiel, zufällige Rezepte haben sogar einen Zweck: Sie sind wie ein unendlicher Vorrat an Überholungsmods, die dabei das Vanillagefühl behalten! Das beste dabei für mich war aber, dass ich keine neuen Maschinen oder Grafiken machen muss, weil ich ja nur mit Zahlen und Buchstaben herumspiele.

Nicht so einfach wie es scheint

Die Mod könnte einfach jedes Rezept nehmen und zufällige Gegenstände als Input verlangen. Das wäre ziemlich nutzlos, wenn zum Beispiel rote Wissenschaft Kernbrennstoff als Zutat brauchen würde, aber du ihn noch nicht freigeschalten hast. Daher ließ ich es sich durch die Technologien graben, und für jedes Rezept, dass freigeschaltet wird, nur Gegenstände von früheren Technologien nehmen. Es gibt natürlich Ausnahmen mit manchen Mods, bei denen du ein Rezept freischalten kannst, bevor du es auch herstellen kannst, also vielleicht sollte ich ein bisschen vorsichtiger sein.

Du willst vermutlich unterirdische Fließbänder nicht aus Dampfmaschinen und Laboren herstellen, das wäre viel zu teuer. Ich brauchte einen Weg, die Rezepte auszugleichen. Daher entschied ich mich, einen Algorithmus zu implementieren, der den Wert jedes Gegenstandes anhand der benötigten Ressourcen berechnet. Wir können uns ohne Problem berechnen, dass ein Schaltkreis 1 Eisenerz und 1,5 Kupfererz benötigt:

Wie es gemacht wird: Elektronische Schaltkreise
1,5 Kupfererz plus 1 Eisenerz resultieren in einem elektronischen Schaltkreis.

Sagen wir, dass Kupfer- und Eisenerz beide einen Wert von 1 haben. Das heißt, elektrische Schaltkreise einen Wert von 2,5 haben. Jetzt kann der Zufallsgenerator zum Beispiel ein Fließband (Wert 1,5) und ein Kupfererz (Wert 1) als neues Rezept für Schaltkreis festlegen. Es gibt ein bisschen Variation im Endergebnis, was die Rezepte etwas einzigartiger macht, aber viel wichtiger, wird es dadurch auch einfacher, eine gültige Kombination zu finden, was den Zufallsgenerator schneller macht.

Mit diesem Stand veröffentlichte ich die Mod, und durch einiges an Feedback und Testen wurde schnell klar, dass es (natürlicherweise) viele Bugs und zwei „große“ Probleme gab. Groß unter Anführungszeichen, da die Mod trotzdem wesentlich spielbarer war, als man von so viel Zufall vermuten möge. Ich wollte aber Spielern ein angenehmes Erlebnis bieten, nicht nur ein Erlebnis.

Die ersten paar Probleme

Das erste Problem war Holz. Die Standardeinstellung stellte sicher, dass Holz nicht gewürfelt wird, aber viele Rezepte verwenden hölzerne Strommasten! Die Lösung hätte war ziemlich einfach und langweilig, wie du dir vorstellen kannst. Ich habe einen Marker für „unzufällige“ Ressourcen – wie Holz – hinzugefügt, und jeder Gegenstand der etwas mit diesem Marker benötigte, hat ihn auch übernommen.

Das zweite war, dass selbst wenn Rezepte die richtige Menge and Ressourcen benötigt haben, sie oft zu komplex und unfair waren. Die Mod beachtete nicht die Anzahl an Schritten oder Zeit eines Fertigungsprozess. Ein gutes Beispiel ist die (rote) Automatisierungwissenschaft. Sie ist sehr billig, mit einem Wert von nur 3, aber benötigt 5 Sekunden zum Herstellen. Sie wurde in vielen einfachen Komponenten ähnlich wie Eisenzahnräder verwendet. Ihre lange Herstellungszeit hieß, dass du etliche Montagemaschinen benötigen könntest, nur um unterirdische Fließbänder herzustellen. Ein weiteres problematisches Bespiel ist, dass einfache Gegenstände wie Eisenzahnräder viele Schritte benötigen könnten, wie zum Beispiel mit Ziegelsteinen, welche aus Eisenstangen, welche wiederum aus Röhren gemacht werden könnten usw. Daher hab ich einen zweiten Wert namens Komplexität zu jedem Gegenstand hinzugefügt. Komplexität beachtet die Anzahl an Schritten, die Menge unterschiedlicher Zutaten (und Produkte) und auch die Zeit.

Rohe Ressourcen ausgleichen

Es wirkt, als wäre ich am perfektem Zufallsgenerator angekommen, aber wieder mal zeigten sich einige Probleme (und Bugs). Häufig nutzen viele Rezepte hauptsächlich eine Ressource (oft Eisen oder Stein), was recht fad war, da du weit nach Erz suchen musstest, weil du einfach so viel von der gewählten Zutat benötigst. Und Öl wurde öfters nicht einmal benötigt, um überhaupt eine Rakete zu starten. Für jedes Rezept war es für alle Gegenstände gleich wahrscheinlich, gewählt zu werden, daher übertrafen Gegenstände ohne Öl die paar wenigen mit Öl in Anzahl massiv. Ich habe ein bisschen probiert, den Algorithmus in die richtige Richtung zu schieben, aber nichts hat wirklich funktioniert. Ich könnte ihm einfach sagen, mehr Plastik oder Festbrennstoff oder so zu verwenden, aber was wenn du mit Mods spielen willst, und es noch mehr Gegenstände zum Priorisieren gibt? Ich will eine universelle Lösung.

Mir war bereits ein Ansatz bekannt, der das lösen könnte, aber ich wollte ihn nicht implementieren, da es alles wesentlich komplizierter gemacht hätte. Das würde mehr Entwicklungszeit, mehr Bugs und potenziell wesentlich längere Ladezeiten mit sich bringen. Aber nachdem ich erfolglos versucht habe über einen einfacheren Weg ein ähnliches Ergebnis zu erzielen, entschloss ich mich doch diese kompliziertere Lösung zu nehmen.

Die Idee war es die Anzahl an rohen Ressourcen statt nur dem Wert zu nehmen. Dadurch kann die Mod sicherstellen, dass jedes zufällige Ergebnis die richtige Menge an roher Ressourcen nimmt, sicherstellend dass alle Rohzutaten genutzt werden. Ähnlich wie beim gesamten Wert dürfen die Rohzutaten für jedes Rezept ein bisschen variieren, oder je nach Mod-Einstellungen auch komplett zufällig sein. Recht einfach, oder? Naja, anstatt mit einer Nummer zu rechnen muss ich jetzt mehrere Zahlen beachten und die Logik ist auch um einiges komplexer. Glücklicherweise funktioniert die Mod dank einigen Optimierungen und gründlichem Testen trotzdem noch und ist weiterhin recht schnell.

Und das ist die Geschichte von Vill‘s Recipe Randomizer!

Wir müssen tiefer

Außer dass ich ein paar GROẞE Probleme nicht angesprochen habe (beachte die fehlenden Anführungszeichen und die Großbuchstaben), welche von Anfang an da waren. Eines davon sind Rezeptschleifen. Der Algorithmus könnte beim Versuch, den Wert eines Rezeptes zu berechnen, stecken bleiben, oder ihn falsch berechnen. Schleifen innerhalb eines Rezeptes sind einfach zu lösen: Um das Rezept zu quantifizieren entfernt der Algorithmus die Gegenstände, die auf beiden Seiten – Input und Output – auftauchen, und löst dadurch die Schleife. Er kann dann die entfernten Gegenstände wieder hinzufügen, da deren Wert jetzt bekannt ist, um das Rezept zum Würfeln fertig zu machen. In Vanilla trifft das auf den Kovarex-Anreicherungsprozess und Kohleverflüssigung zu:

Räum es auf!
40 U-235 und 2 U-238 können von Kovarex und 25 Schweröl können von Kohleverflüssigung entfernt werden.

Schleifen mit mehr als einem Rezept sind etwas schwieriger. Es gibt in Vanilla keine Schleifen mit mehr als einem Rezept (abgesehen von Fässer füllen und leeren, welche standardmäßig aber sowieso nicht verändert werden), daher sind sie ziemlich einfach zu übersehen, aber in Mods gibt es sie überall! Der Zufallsgenerator kann unter bestimmten Bedingungen eventuell aus Versehen eine Schleife machen. Um das Problem zu illustrieren, brauchen wir ein Beispiel. Nehmen wir synthetische Saphire in Industrial Revolution 2. Du braucht reines Nickel, Siliziumdioxid, und Saphirstaub um Saphire herzustellen, aber Saphirstaub wird durch Zerschmettern von Saphiren gemacht, wodurch eine Schleife entsteht:

Saphir-Schleife

Ich habe dieses Problem behoben, indem ich Schleifen, wenn sie entdeckt werden, aufschneide, und die Rezepte dann in eines zusammenfüge. Das neue Rezept wird dann statt der geöffneten Schleife für die Berechnungen verwendet. Hier werden die beiden Rezepte zusammengefügt, indem die drei Saphirstaub in der Mitte entfernt werden, und dann können wir noch zwei Saphire, die sowohl im Input als auch im Output vorhanden sind, entfernen:

„Entschleifter“ Saphir

Wir bekommen damit ein Rezept für Saphire, das die problematischen Details weglässt! Aber was passiert, wenn es Abzweigungen in Schleifen, oder Schleifen in Schleifen gibt?

„Schleifiges“ Diagramm
Das basiert nicht auf irgendeinem bestimmten Rezept, aber ich bin mir sicher, dass etwas mindestens so kompliziertes wie im Diagramm in irgendeiner Mod existiert.

Sagen wir einfach, es wird schleifig. Ich glaube ich habe das halbwegs gelöst, aber ich werde jetzt nicht weiter ins Detail gehen, wir sind hier ja schließlich nicht in einem Graphentheoriekurs, und ich bin mir auch nicht einmal sicher, ob meine Lösung überhaupt funktioniert.

Mein Erzfeind

Und jetzt das größte aller Probleme: Rezepte mit mehreren Produkten. Nehmen wir fortgeschrittene Ölverarbeitung als Beispiel.

Fortgeschrittene Ölverarbeitung

Standardmäßig hat Rohöl einen Wert von 0,4 (wir ignorieren Wasser fürs erste). Das heißt, das Rezept hat einen Gesamtwert von 40. Wir wissen daher, dass 25 Schweröl + 45 Leichtöl + 55 Flüssiggas einen Wert von insgesamt 40 haben, aber wie teilt sich das auf die einzelnen Produkte auf? Es gibt viele Wege, das anzugehen, und es zu versuchen hat das meiste meiner Zeit gekostet und mir viele Kopfschmerzen bereitet. Gehen wir mal durch die zwei unterschiedlichsten Möglichkeiten.

Die einfachste: Jedes Produkt bekommt einen gleichen Teil des Gesamtwerts. Das ist großteils sinnvoll, bis du Abfallprodukte beachtest. Kovarex-Anreicherung zum Beispiel stellt 41 U-235 und 2 U-238 her, und der Algorithmus würde davon ausgehen, beide hätten denselben Wert, aber du wirst vermutlich wissen, dass U-235 wesentlich wertvoller ist. Dieser Ansatz ist daher nicht wirklich hilfreich.

Die „beste“: Jeder Teil bekommt den vollen Wert, aber merke die Nebenprodukte, damit du sie später abziehen kannst. Zum Beispiel hat Schweröl bei fortgeschrittener Ölverarbeitung Leichtöl und Flüssiggas als Nebenprodukte. Das heißt Schmiermittel hat sie auch als Nebenprodukte, weil es nur aus Schweröl hergestellt wird. Wenn wir ein Express-Teilerfließband herstellen wollen, brauchen wir unter anderem Schmiermittel und erweiterte Schaltkreise. Erweiterte Schaltkreise benötigen Flüssiggas, aber wir haben noch etwas als Nebenprodukt vom Schmiermittel über, von dem wir es abziehen können. Als einziges Nebenprodukt ist jetzt nur noch Leichtöl übrig. Was machen wir mit Leichtöl? Wir können es natürlich zu Flüssiggas spalten, um noch mehr davon zu sparen. Aber das braucht Wasser. Ist es billiger mehr Wasser oder mehr Flüssiggas zu verwenden? Berechnen wir sicherheitshalber mal beide Möglichkeiten, für alle Fälle.

Wie dir vielleicht auffällt, ist dieser Ansatz unglaublich kompliziert. Es gibt viele Randfälle und Fragen zu beantworten. Wie, was machst du mit überflüssigen Nebenprodukten, wenn andere Rezepte sie nicht brauchen? Ich habe versucht eine Version dieses Ansatzes zu implementieren, und muss sagen, sie war sogar ziemlich erfolgreich. Es hat nur zirka 100 Stunden gebraucht und ich musste etwa eine Million Bugs beheben, und was war das Ergebnis? Naja, die Lösung ist immer noch nicht perfekt, auch wenn sie sehr nahe kommt. Ich kann aber auch nicht einmal mehr meinen eigenen Code verstehen. Alles zerfällt jedes mal, wenn ich irgendwas ändern will. Und am dramatischsten, die Mod in Vanilla Factorio zu laden braucht irgendwas zwischen 10 Sekunden und 10 Minuten. Nachdem ich die Mod mit so vielen anderen Mods wie möglich kompatibel halten will (und Funktionalität mit Vanilla wäre auch nice), entschied ich mich, dass das nicht die Lösung ist.

Schlussendlich, nach noch mehr Denken, bin ich zu dem Algorithmus gekommen, den ich heute verwende. Er ist eigentlich ein Kompromiss zwischen den beiden oben beschriebenen Ansätzen. Er funktioniert gut und ist recht einfach, wenn auch nicht einfach genug, um ihn zu erklären, da ich etliche andere Eigenarten auch erklären müsste. Er evaluiert nicht alle Rezepte mit mehreren Produkten in allen Fällen gleich gut, aber er bereitet auch bei Randfällen keine Probleme (hoffe ich).

Letzte Gedanken

Damit wäre ich mit dem Einblick in das Innenleben meines Recipe Randomizer am Ende. Falls du noch weitere Fragen oder Vorschläge hast, kannst du mir auf meinem Discord-Server schreiben. Und wenn wir schon dabei sind, möchte ich allen Leuten danken, die beigetreten sind, um Bugs, Ideen und Getestetes zu posten oder mich anders während der Entwicklung unterstützt haben. Die Mod wäre ohne euch nicht so weit gekommen!

COMFY Minesweeper! redlabel

Um eine neue Karte vom legendären Kartenersteller mewmew und einem glänzend neuem Ryzen 9 5950X von Gerkiz zu feiern, organisiert COMFY Factorio ein spezielles Event am 1. Mai um 19 Uhr MESZ. Jeder ist inkl. Familie eingeladen, eine Antwort wird nicht benötigt.

Minesweeper in Factorio

Falls sich jemand wundert, was Minesweeper ist: Es ist eine neue Karte, bei der du die Basis vergrößerst, indem du ein Minesweeper-Puzzle löst. Um eine Mine zu entschärfen, musst du einen Ofen darauf platzieren. Ihn auf einer freien Kachel zu platzieren löst eine Explosion aus, und draufzusteigen führt zum selben Ergebnis. Fehler sind teuer, da sie Beißer freilassen und Atomexplosionen verursachen. Spieler können auch Punkte bekommen (oder verlieren), je nachdem wie gut sie sind, und sich über eine Anzeigetafel vergleichen, welche die Punkte anzeigt.

COMFY ist eine der führenden Mehrspieler-Factorio-Communities und einige unserer Werke sind Bergfestungen, Beißerschlachten, Fischverteidigung, Chronozug und Cave Miner. Und sehr, sehr bald eine Karte über Piraten und Segelschiffe! Bleib also dran.

Du kannst der COMFY-Community mit fast 3500 Mitgliedern auf unserem Discord beitreten.

Der Countdown ist vorbei

Beitragen

Wie immer suchen wir nach Leuten, die zu Alt-F4 beitragen wollen, sei es mit einem Artikel oder durch Hilfe bei Übersetzungen. Wenn du etwas Interessantes im Kopf hast, das du mit der Community in einer eleganten Art teilen möchtest, hier kannst du das tun. Falls du dir unsicher bist, beantworten wir gerne Fragen zu Inhalt und Struktur. Falls das nach etwas klingt, woran du interessiert bist, tritt unserem Discord bei, um es nicht zu verpassen!