Plagiator

Aus KaroWiki
Zur Navigation springen Zur Suche springen

Plagiator ist ein von ultimate geschriebener Kartengenerator. Seit dem <tbd> ist er in Karopapier eingebunden.

Der Generator ist kein "normaler" Generator in dem Sinne, dass er eine Strecke "aus dem Nichts" erzeugt. Stattdessen erzeugt er Karten durch "Plagiieren", d.h. Transformieren und leichtes Verändern, existierender Karten. Zur Verfügung stehen die Transformationen Skalierung (unabhängig in X- und Y-Richtung, einschließlich Spiegeln) sowie Rotation. Zu den leichten Veränderungen zählen Start und Ziel tauschen und Trimmen. Bei einer Skalierung kann zudem zwischen zwei Algorithmen gewählt werden.

Funktionsweise

Der Plagiator arbeitet nach der folgenden Funktionsweise:

  1. Laden des Karten-Codes aus der Karodatenbank
  2. (optional) Tauschen von Start und Ziel
  3. Erzeugen einer 3x3 Transformations-Matrix aus den Parametern Größe X, Größe Y und Rotation
  4. Kompensation des ggf. durch Rotation entstehenden Offsets
  5. Berechnung der Inversen Matrix
  6. Karoweise transformation der Karte anhand des entsprechenden Skalierungsalgorithmus
  7. (optional) Trimmen der Karte

Parameter

Plagiator kann durch folgende Parameter beeinflusst werden:

  • Karte - MID der zu plagiierenden/transformierenden Karte. Hinweis: aus offensichtlichen Gründen können keine Nachtkarten transformiert werden.
  • Größe X & Größe Y - Skalierungsfaktor in der jeweiligen Richtung; Faktoren mit |scale| > 1 vergrößern die Karte; Faktoren mit |scale| < 1 verkleinern sie; negativen Faktoren spiegeln die Karte entlang der entsprechenden Achse; 0 ist nicht erlaubt
  • Rotation - Drehung der Karte im Uhrzeigersinn in Grad; es sind beliebige Winkel zulässig, für die bessere Bedienbarkeit sind im Frontend jedoch Winkel die Vielfache von 45° sind mit Tickmarks leichter anwählbar
  • Skalierungsmodus - zur Auswahl stehen zwei Modi: ultimate und nearestneighbor. Details dazu unter Skalierungsalgorithmen
  • Start und Ziel tauschen - ist dieses Flag gesetzt werden alle Startfelder durch Zielfelder ausgetauscht und umgekehrt. Hinweis: dadurch ändert sich ggf. die Anzahl der Startplätze
  • Trimmen - normalerweise werden Eckbereiche, die bei der Rotation entstehend durch fortsetzen des Geländes aufgefüllt. Möchte man dies nicht, kann man die Karte trimmen lassen. Die Karte wird dann soweit verkleinert, dass nur noch ein 1-Karo-breiter, nicht-befahrbarer Rand um die Strecke übrig bleibt (ggf. kann dies auch Karten ohne Rotation kleiner machen, wenn diese mehr Rand haben)

Skalierungsalgorithmen

Die Herausforderung beim Skalieren von Karten besteht darin sicherzustellen, dass das Ergebnis einerseits optisch ansprechend, aber trotzdem auch spannend zu fahren ist. Dazu habe ich (ultimate) ein bisschen rumprobiert und zwei unterschiedliche Algorithmen implementiert, die man enstprechend auswählen kann.

(Beispiele siehe #Beispielkarten)

nearestneighbor

Der Nearest-Neighbor-Algorithmus ist ein aus der Bildverarbeitung bekannter Algorithmus. Die Zielkoordinaten werden einfach mit dem Skalierungsfaktor verrechnet und vom Ergebnis Nachkommastellen abgeschnitten um auf die Ursprungskoordinaten zu kommen. Bei Faktor 2 wird also beispielsweise jedes Karo durch 2x2 identische Karos ersetzt...

ultimate

Da bei Verwendung des Nearest-Neighbor-Algorithmus zwangsläufig "langweilige" Kartenelemente entstehen können - wie z.B. einfach nur größere Versionen von schachbrettartigen Stellen, wollte ich einen Algorithmus bauen, der für Karopapier optimierte Ergebnisse ausgibt, die spannender sind. Dazu wird bei der Skalierung zwischen Straßenfeldern (also Asphalt, CPs, Start, Ziel) und nicht-Straßenfeldern (Gras, Sand, Wasser, etc.) unterschieden und unter der Berücksichtigung der umliegenden Karos und der Sub-Karo-Position der Zielkoordinaten ein skaliertes Straße-/Nicht-Straße-Muster ausgewählt. Es entstehen so 256 mögliche Anordnungen mit teilweise noch unterschiedlichen Ergbnissen jenachdem ob man "oben-links", "mittig", oder woanders innerhalb des Karo ist. Diese Anordnungen und Subfälle wurden alle händisch analysiert und anschließend für jede Kombination dann ebenfalls händisch ein entsprechendes Straße-/Nicht-Straße-Muster programmiert.

Im Detail läuft das so ob:

  1. für die Zielkoordinaten (ganzzahlig) werden die folgenden Werte berechnet:
    • Ursprungskoordinaten (Kommazahl)
    • Zone innerhalb des Ursprungskaros = unterteilt nach north, south, east, west
    • Ecke innerhalb des Ursprungskaros = unterteilt nach northwest, northeast, southeast, southwest und center
    • Maske der umliegenden Pixel = 1-Bit pro umliegenden Karo startend von "obenlinks", über "oben", "obenrechts", ... im Uhrzeigersinn, bis "links"
    • Modulo Wert des Zielkaros = es wird quasi ein 1-Karo-Schachbrett über die ganze Zielkarte aufgespannt und die schwarzen bekommen 1 und die weißen 0 als Wert
  2. alle möglichen 256 Masken werden in einem riesigen Switch-Case-Statement abgebildet, wobei jedoch einige Anordnungen zum selben Ergebnis führen und demnach nicht alle einzeln runterprogrammiert sind
  3. für jede Maske gibt es dann bis zu zwei If-Statements, in denen anhand der Zone und/oder Ecke entschieden wird, welchen Wert das Karo bekommt. Zur Auswahl stehen:
    • der Center-Wert (also das Karo anhand Nearest-Neighbor-Algorithmus)
    • der Nachbar-Wert entsprechend der Seite, wo das Karo näher dran ist (so entstehen softere Diagonalen)
    • der Schachbrett-Wert (der wiederum anhand des Modulo-Werts alternatierend Center-Wert oder Nachbar-Wert zurück gibt)

Trivia

  • der Plagiator arbeitet 100% deterministisch, d.h. es ist kein Zufall im Spiel und bei gleichen Parameter kommt auch immer das gleiche Ergebnis raus
  • aufgrund des deterministischen Verhaltens können mit dem Plagiator keine Nachtkarten erzeugt werden (man könnte sonst schummeln). Um dennoch zufällige (Nacht)-Karten fahren zu können,
  • es kann sein, dass bestimmte Parameterkombinationen zu nicht fahrbaren Karten führen - Ursachen für nicht fahrbare Karten können sein:
    • Verkleinerung oder Rotation macht Strecke unpassierbar (ggf. abhängig vom Skalierungsalgorithmus)
    • Tausch von Start und Ziel macht Route für einige Spieler unpassierbar (z.B. weil es dekorative Ziele gibt, die dann zu nicht fahrbaren Starts führen)

Beispielkarten

Hier zur Veranschaulichung mal die Gegenüberstellung einiger Plagiate mit unterschiedlichen Parametern... Unterschiede zwischen 1 und 2 sind fett hervorgehoben

Plagiat 1 Beschreibung 1 Plagiat 2 Beschreibung 2
Plagiator 1 x2y2 nn.png MID = 1
scaleX = 2
scaleY = 2
scaler = nearestneighbor
Plagiator 1 x2y2 u.png MID = 1
scaleX = 2
scaleY = 2
scaler = ultimate
Plagiator 1 x3y1 nn 90 sf.png MID = 1
scaleX = 3
scaleY = 1
scaler = nearestneighbor
rotation = 90
Start Ziel getauscht
Plagiator 1 x3y1 nn 66.png MID = 1
scaleX = 3
scale1 = 2
scaler = nearestneighbor
rotation = 66
getrimmt
Plagiator 28 x2y2 nn.png MID = 28
scaleX = 2
scaleY = 2
scaler = nearestneighbor
Plagiator 28 x2y2 u.png MID = 28
scaleX = 2
scaleY = 2
scaler = ultimate
Plagiator 28 x1.5y1.5 nn 135.png MID = 28
scaleX = 1.5
scaleY = 1.5
scaler = nearestneighbor
rotation = 135
Plagiator 28 x1.5y1.5 u 135.png MID = 28
scaleX = 1.5
scaleY = 1.5
scaler = ultimate
rotation = 135