Mach etwas Schnee!

18

Ihre Aufgabe: Eine Kochschneeflocke bis in die n-te Tiefe erzeugen. Sie müssen keine vollständige Kochschneeflocke herstellen, nur eine Seite des Startdreiecks. Wikipedia zu Koch Flakes: https://en.wikipedia.org/wiki/Koch_snowflake .

Regeln:

  • Das Programm muss eine Seite der Kochschneeflocke bis zur n-ten Tiefe erzeugen.
  • Die Ausgabe muss ASCII sein.
  • Sie können die ganze Schneeflocke erzeugen; Dies ist nicht erforderlich.
  • Es gelten die Standardregeln für Input / Output und Lücken.
  • Leerzeichen spielen keine Rolle, solange sich alle Zeichen an der richtigen Stelle relativ zueinander befinden.
  • Kürzester Code gewinnt!

Testfälle:

n = 0:

__

n = 1:

__/\__

n = 2:

      __/\__
      \    /
__/\__/    \__/\__

n = 3:

                        __/\__
                        \    /
                  __/\__/    \__/\__
                  \                /
                  /_              _\
                    \            /
      __/\__      __/            \__      __/\__
      \    /      \                /      \    /
__/\__/    \__/\__/                \__/\__/    \__/\__

Ich hoffe das macht Sinn. Beachten Sie, dass das Fraktal in jedem Testfall in drei Teile gleicher Länge unterteilt werden kann. Beachten Sie auch, dass die Breite jeder Schneeflocke das Dreifache der Breite der vorherigen Schneeflockengeneration beträgt.

Genosse SparklePony
quelle
FYI, wurde vereinbart , dass dies kein Narr ist dies .
Genosse SparklePony
Ich glaube nicht, dass Sie die richtige ASCII-Darstellung der n-ten Koch-Kurve angemessen definiert haben.
Orlp
Ich bin mir nicht sicher, ob die Proportionen Sinn machen. Die Nicht-Duplikation wurde __/\__mit zwei Unterstreichungen verwendet, wodurch jede Iteration konsistent dreimal so groß war wie die vorherige. Die Verwendung von nur einer Unterstreichung scheint zu Widersprüchen zu führen, die in n = 3 sehr unangenehm werden. ZB haben die Außenteile die Breite 12, während das Mittelteil nur die Breite 10 hat, als Folge der /_und _\ die zu eng sind. Und schon vorher haben Sie die _doppelte Breite von /und \ .
Ørjan Johansen
Ich denke das /_und _\ sind der einzige wirklich fatale Teil - die Unterstriche müssen weg, weil sie in der gleichen Position wie das /und sein müssen \ . Sobald dies erledigt ist, können sich die Dinge von n = 1 an um das Dreifache erweitern (aber n = 0 passt nicht.)
Ørjan Johansen
Ach, nein, der mittlere Teil hat immer noch eine Breite, die nicht mit den äußeren Teilen übereinstimmt, wie dies durch n = 3 mit einer Breite von 52 anstelle von 54 = 2 · 3 ^ 3 belegt ist. Probieren Sie eines davon aus . Ich habe verkehrte Versionen mit Teilen aufgenommen, die nur ab n = 4 oder n = 5 angezeigt werden - sie unterscheiden sich von den Teilen nach oben, bei denen die Unterstriche weggelassen werden.
Ørjan Johansen

Antworten:

10

Haskell , 308 300 299 Bytes

Bearbeitungen:

  • -4 Bytes: Ändern zipWith(+)zu zipWith(-)und Einstellen Kodierungen und Offsets jeder Negation Zeichen losgeworden.
  • -1 Byte: Durch weitere Optimierung der Codierung konnten mehrere Variablennamen #gelöscht werden, indem r=reverseanstelle des direkten Mustervergleichs der Wert verwendet wurde.
  • -2 Bytes: Verwenden eines Operators anstelle von alphanum für zipWith(-).
  • -1 Byte: Definiert o=[0,0]das Kürzen von Listenkonstanten.
  • -1 Byte: Zusammenführen von zwei Zweigen von ?.
import Data.List
k n=0?sort(o#(f=<<scanl1(+)(iterate(>>=(:[1,4,1]))[6]!!n)))
x?l@(([_,w],c):r)|x>w='\n':0?l|0<1=([2..w-x]>>" ")++[c|w>x]++w?r
_?_=""
w#((c,l):m)=(l&w,c):r l&(l&w)#m
_#_=[]
f x=zip"_/\\_/\\"([id,r]<*>[0:1:o,[0,1,0,1],o++[1,1]])!!mod x 6<$[1,3..gcd 3x]
(&)=zipWith(-)
r=reverse
o=[0,0]

Probieren Sie es online! (Leider wird alles, was größer als n = 3 ist, fürchterlich verpackt und unlesbar, aber Sie können es in ein anderes Programm kopieren, um es zu sehen.)

Variationen

Wie es funktioniert

  • kist die Hauptfunktion, es dauert ein Int nund gibt ein zurück String.
  • iterate(>>=(:[1,4,1]))[6]generiert eine unendliche Liste, die für jedes n die Umdrehungen zwischen aufeinanderfolgenden Linien in dieser Kurveniteration (Turtle-Grafikstil) als nominelle Zahlen zwischen 0und enthält 5. Jede Iteration ist nur die vorherige mit den überlappenden 1,4,1Runden. Der einzige Grund , warum die Unterlisten beginnen mit , 6anstatt 0ist das zu machen gcdTrick in fArbeit zu vermeiden f 0.
  • scanl1(+)konvertiert die Windungen in "absolute" Richtungen, bis zu Modulo 6. A 0bedeutet nach rechts, dann ist jede höhere Zahl 60 Grad gegen den Uhrzeigersinn von der vorherigen. (Nun, es wären 60 Grad, wenn dies eine richtige Zeichnung wäre und nicht ASCII.)
  • f konvertiert eine absolute Richtung in eine Liste von (Zeichen-, Offset-Codierungs-) Paaren, die codiert, welche Zeichen zur Kurve hinzugefügt werden sollen (für horizontale Richtungen werden zwei Paare generiert, andernfalls eines) und wie sich die relative Position ändert.
  • Der #Operator durchläuft die vorherige Liste von (Zeichen-, Offset-Codierungs-) Paaren und generiert tatsächliche (Koordinaten-, Zeichen-) Paare.
  • Kodierungsprinzipien:
    • Ein Zeichen von _/\nominal repräsentiert eine Linie, die von einer Startecke durch eine rechteckige Zelle zu einer anderen Endecke gezogen wird.
    • Die Zellenkoordinaten haben die Form von [y,x]oben nach unten und von links nach rechts, sodass sie in der Reihenfolge sortiert werden, in der sie gedruckt werden sollen. Spalten sind 1-basiert. Listen werden anstelle von Tupeln für kürzere Vektorarithmetik mit verwendet (&)=zipWith(-).
    • Eine Ecke wird mit denselben Koordinaten [y,x]wie die Zelle oben links angegeben. Dies stellt sicher, dass alle Offsets von einer Ecke zu den benachbarten Zellen nicht negativ sind, wodurch negative Konstanten vermieden werden.
    • Allerdings Ecke Koordinaten werden herumgereicht negiert alle Vektoroperationen zu ermöglichen , Subtraktionen anstelle von Ergänzungen zu sein, die alle anderen expliziten Zeichen vermeidet.
    • Eine Offset - Liste Codierung ist , [y1,x1,x2,y2]wo [y1,x1]die von der Start Ecke zur Zeichenzelle Offset - Koordinate und [y2,x2]wird die von der Endecke an die Zeichenzelle versetzt. Das heisst:
      • Die Codierungslisten für die Richtungen 3.. 5sind nur die Umkehrung der Listen für 0.. 2, mit denen sie generiert werden können [id,r]<*>.
      • Alle erforderlichen Vektorarithmetiken können (&)=zipWith(-)entweder mit einer Codierungsliste oder umgekehrt durchgeführt werden.
  • Nach dem Sortieren der Liste der (Koordinaten-, Zeichen-) Paare werden sie an übergeben ?, wodurch das Finale Stringaus ihnen generiert wird .
    • In x?l@(([_,w],c):r) xist die x-Koordinate des vorherigen Zeichens, das in dieser Zeile oder 0am Anfang einer Zeile angezeigt wird. list die gesamte aktuelle Liste, wist die x-Koordinate des nächsten hinzuzufügenden cZeichens, ist das Zeichen und rist die verbleibende Liste.
    • Zu diesem Zeitpunkt werden die y-Koordinaten nicht mehr benötigt. Da jede Zeile Zeichen enthält und das erste Zeichen jeder Zeile weit links vom Ende der vorherigen Zeile steht, wird der Beginn neuer Zeilen erkannt, indem überprüft wird, ob sich die x-Koordinate verringert hat.
    • Der Unterstrich hat einen größeren ASCII-Wert als \und /, daher wird er zuletzt sortiert, wenn er sich mit einem anderen Zeichen an derselben Position überschneidet. Somit wird ein redundanter Unterstrich erkannt, indem überprüft wird, ob eine x-Koordinate wiederholt wurde.
Ørjan Johansen
quelle
Nett! Ich werde dies akzeptieren, wenn diese Frage heute nicht mehr beantwortet wird.
Genosse SparklePony