Entfalten des Hexagony-Quellcodes

52

Einführung

Wenn Sie mit Hexagony nicht vertraut sind , ist es eine esoterische Sprache, die von Martin Büttner entwickelt wurde. Die Sache ist, dass diese Sprache mehrere Formen für das Programm akzeptiert. Die folgenden Programme sind alle gleichwertig:

abcdefg

und

 a b
c d e
 f g

Der Code wurde also im Grunde genommen in ein reguläres Sechseck gerollt. Beachten Sie jedoch, dass das Hinzufügen eines neuen Befehls zum Code abcdefghzu folgendem Programm führen würde:

  a b c
 d e f g
h . . . .
 . . . .
  . . .

Wie Sie sehen, wird der Code im ersten Schritt zu einem Sechseck aufgerollt, und danach wird das Sechseck mit No-Ops ( .) bis zur nächsten zentrierten Sechseckzahl ausgefüllt .

Ihre Aufgabe ist einfach: Wenn Sie eine Zeichenfolge (den Quellcode) angeben, geben Sie den vollständigen Hexagon-Quellcode aus.

Die Regeln

  • Sie können ein Programm oder eine Funktion bereitstellen.
  • Ein führendes Leerzeichen ist zulässig, jedoch nur, wenn das Sechseck nicht aus der Form gerät
  • Leerzeichen dürfen nachgestellt werden.
  • Beachten Sie, dass Leerzeichen im Programm ignoriert werden . Ist a b calso gleichabc
  • Es werden nur die druckbaren ASCII-Zeichen ( 32 - 126) verwendet, daher wird nur das reguläre SpaceZeichen ignoriert.
  • Angenommen, die Länge der Zeichenfolge ist größer als 0.
  • Das ist , also gewinnt die Einsendung mit der geringsten Anzahl von Bytes!

Testfälle

Input: ?({{&2'2':{):!/)'*/

Output:
  ? ( {
 { & 2 '
2 ' : { )
 : ! / )
  ' * /


Input: H;e;l;d;*;r;o;Wl;;o;*433;@.>;23<\4;*/

Output:
   H ; e ;
  l ; d ; *
 ; r ; o ; W
l ; ; o ; * 4
 3 3 ; @ . >
  ; 2 3 < \
   4 ; * /


Input: .?'.) .@@/'/ .!.>   +=(<.!)}    (  $>( <%

Output:
   . ? ' .
  ) . @ @ /
 ' / . ! . >
+ = ( < . ! )
 } ( $ > ( <
  % . . . .
   . . . .
Adnan
quelle
6
Ich bin mir auch nicht sicher, ob Sie so wählerisch sein möchten, aber Backticks werden beim Bestimmen der Codebreite ignoriert, da sie das nächste Zeichen mit Anmerkungen versehen. Also abc`defgwürde eigentlich pastebin.com/ZrdJmHiR werden
Martin Ender
2
@ MartinBüttner Oh, das wusste ich nicht :). Bei dieser Herausforderung werden Backticks nicht ignoriert.
Adnan
18
Ich möchte wirklich eine Antwort auf diese Frage in Hexagony sehen.
Arcturus
2
@Adnan Eine wahrscheinlich bessere Antwort wäre "Sie können davon ausgehen, dass die Eingabe keine Debug-Flags ( `Zeichen) enthält."
Riking
4
@Ampora Fragen Sie und Sie erhalten.
Martin Ender

Antworten:

13

Pyth, 57 54 50 49 48 46

V+UJfgh*6sUTlK-zd1_UtJ+*d-JNjd:.[K\.^TJZ=+Z+JN

Test Suite

Gibt in jeder Zeile ein Leerzeichen aus.

Diese Version erfordert einen Beweis, dass 10 ^ n> = 3n (n - 1) + 1 für alle n> = 1 . Vielen Dank an ANerdI und ErickWong für die Beweise.

Wenn man diesen Ungleichungen folgt: 10 ^ n> (1 + 3) ^ n = 1 + 3n + 9n (n - 1) + ...> 3n (n - 1) + 1 , kann man leicht erkennen, dass dies für n> richtig ist = 2 . Die Untersuchung des Falls n = 1 ist eher trivial und ergibt 10> 1 .

Alternativ zeigt die zweimalige Ableitung dieser Gleichungen, dass 10 ^ n eine größere zweite Ableitung für alle n> = 1 hat , die dann auf die ersten Ableitungen und schließlich auf die ursprünglichen Gleichungen herunterkaskadiert werden kann.

Erläuterung

              ##  Implicit: z=input(); Z=0
Jf...1        ##  Save to J the side length of the hexagon the code fills up
              ##  by finding the first number such that:
gh*6sUT       ##  the the T'th hexagonal number is greater than...
              ##  Computes 6 * T'th triangular number (by using sum 1..T-1) + 1
    lK-zd     ##  ...the length of the code without spaces (also save the string value to K)
V+UJ_UtJ      ##  For loop over N = [0, 1, ..., J-1, ..., 0]:
+*d-JN        ##  append J - N spaces to the front of the line
jd            ##  riffle the result of the next operation with spaces
:.[K\.yJ      ##  slice the string given by K padded to be the length of the Jth hexagon
              ##  number with noops
Z=+Z+JN       ##  from Z to Z + J + N, then set Z to be Z + J + N
FryAmTheEggman
quelle
2
Zuerst müssen Sie beweisen, dass ln (10) * 10 ^ n> 6n-3 (die Ableitungen) für n> = 1 ist. Dies ist einfach, da die Ableitungen dieser Ausdrücke in (10) ^ 2 10 ^ n und 6 sind. Da 10 ^ n monoton ansteigt und 10 ^ 1> 6 * 1, ist 10 ^ n für alle größer als 6n-3 n> = 1. Sie können dieselbe Logik verwenden, um den Beweis für 10 ^ n und 3n (n-1) +1 zu vervollständigen.
Arcturus
@Ampora Danke, ich hatte überlegt, Derivate zu verwenden, aber es schien unsauber. Ich konnte keinen besseren Weg finden, so sehr geschätzt!
FryAmTheEggman
Froh, dass ich Helfen kann. Calc kann manchmal wirklich hässlich werden.
Arcturus
im obigen Link pyth.herokuapp.com/?code=etc finde ich, dass der Compiler nicht ausgeführt wird ...
RosLuP
1
@FryAmTheEggman Es gibt eine sehr einfache Möglichkeit, die viel stärkere Bindung 4 ^ n> 3n (n-1) + 1 für n> = 1 anzuzeigen, ohne dass ein Kalkül erforderlich ist. Verwenden Sie einfach die Tatsache, dass (1 + 3) ^ n = 1 + 3n + 9n (n-1) / 2 + ... durch Binomialerweiterung. Der erste und der dritte Term setzen 1 + 3n (n-1) direkt zusammen, sodass die Ungleichung sofort auftritt, wenn der dritte Term existiert (d. H. Für n> = 2). Dies lässt nur den Fall n = 1, der trivial ist, da die RHS 1 ist.
Erick Wong
90

Hexagony , 271 Bytes

Ich präsentiere Ihnen die ersten 3% eines Hexagony-Selbstinterpreten ...

|./...\..._..>}{<$}=<;>'<..../;<_'\{*46\..8._~;/;{{;<..|M..'{.>{{=.<.).|.."~....._.>(=</.\=\'$/}{<}.\../>../..._>../_....@/{$|....>...</..~\.>,<$/'";{}({/>-'(<\=&\><${~-"~<$)<....'.>=&'*){=&')&}\'\'2"'23}}_}&<_3.>.'*)'-<>{=/{\*={(&)'){\$<....={\>}}}\&32'-<=._.)}=)+'_+'&<

Probieren Sie es online! Sie können es auch selbst ausführen, es dauert jedoch ca. 5-10 Sekunden.

Im Prinzip könnte dies in die Seitenlänge 9 passen (für eine Punktzahl von 217 oder weniger), da hier nur 201 Befehle verwendet werden und die ungolfed-Version, die ich zuerst geschrieben habe (auf Seitenlänge 30), nur 178 Befehle benötigte. Ich bin mir jedoch ziemlich sicher, dass es ewig dauern würde, bis wirklich alles passt. Ich bin mir also nicht sicher, ob ich es tatsächlich versuchen werde.

Es sollte auch möglich sein, dies ein bisschen in Größe 10 zu spielen, indem die Verwendung der letzten ein oder zwei Reihen vermieden wird, so dass die nachgestellten No-Ops weggelassen werden können, aber dies würde ein wesentliches Umschreiben als einer der ersten Pfade erfordern joins nutzt die linke untere Ecke.

Erläuterung

Beginnen wir damit, den Code zu entfalten und die Kontrollflusspfade zu kommentieren:

Bildbeschreibung hier eingeben

Das ist immer noch ziemlich chaotisch, also hier das gleiche Diagramm für den "ungolfed" Code, den ich zuerst geschrieben habe (tatsächlich ist das die Seitenlänge 20 und ursprünglich habe ich den Code auf Seitenlänge 30 geschrieben, aber das war so spärlich, dass es nicht so wäre verbessert die Lesbarkeit überhaupt nicht, deshalb habe ich sie ein wenig komprimiert, um die Größe ein wenig vernünftiger zu machen):

Bildbeschreibung hier eingeben
Klicken Sie für eine größere Version.

Die Farben sind bis auf ein paar sehr kleine Details genau gleich, die Befehle ohne Kontrollfluss sind auch genau gleich. Ich werde Ihnen also anhand der ungolfed Version erklären, wie das funktioniert. Wenn Sie wirklich wissen möchten, wie das golfed funktioniert, können Sie überprüfen, welche Teile dort welchen im größeren Sechseck entsprechen. (Der einzige Haken ist, dass der Golf-Code mit einem Spiegel beginnt, sodass der eigentliche Code in der rechten Ecke nach links beginnt.)

Der grundlegende Algorithmus ist fast identisch mit meiner CJam-Antwort . Es gibt zwei Unterschiede:

  • Anstatt die zentrierte hexagonale Zahlengleichung zu lösen, berechne ich einfach aufeinanderfolgende zentrierte hexagonale Zahlen, bis eine gleich oder größer als die Länge der Eingabe ist. Dies liegt daran, dass Hexagony keine einfache Methode zum Berechnen einer Quadratwurzel bietet.
  • Anstatt die Eingabe sofort mit No-Ops aufzufüllen, überprüfe ich später, ob die Befehle in der Eingabe bereits erschöpft sind, und drucke .stattdessen eine aus, wenn vorhanden.

Das heißt, die Grundidee läuft auf Folgendes hinaus:

  • Liest und speichert die Eingabezeichenfolge, während die Länge berechnet wird.
  • Suchen Sie die kleinste Seitenlänge N(und die entsprechende zentrierte hexagonale Zahl hex(N)), die die gesamte Eingabe aufnehmen kann.
  • Berechnen Sie den Durchmesser 2N-1.
  • Berechnen Sie für jede Zeile den Einzug und die Anzahl der Zellen (deren Summe 2N-1). Einzug drucken, Zellen drucken ( .wenn die Eingabe bereits erschöpft ist), Zeilenvorschub drucken.

Beachten Sie, dass es nur No-Ops gibt, so dass der eigentliche Code in der linken Ecke beginnt (der $, der über den springt >, damit wir wirklich auf ,dem dunkelgrauen Pfad beginnen).

Hier ist das anfängliche Speicherraster:

Bildbeschreibung hier eingeben

Der Speicherzeiger beginnt also an der mit input bezeichneten Kante und zeigt nach Norden. ,liest ein Byte von STDIN oder a, -1wenn wir EOF in diese Kante getroffen haben. Daher ist das <Recht danach eine Bedingung dafür, ob wir alle Eingaben gelesen haben. Bleiben wir vorerst in der Eingabeschleife. Der nächste Code, den wir ausführen, ist

{&32'-

Dies schreibt eine 32 in den Rand mit der Bezeichnung " Raum" und subtrahiert sie dann vom Eingabewert in dem Rand mit der Bezeichnung " Diff" . Beachten Sie, dass dies niemals negativ sein kann, da garantiert wird, dass die Eingabe nur druckbares ASCII enthält. Es wird Null sein, wenn die Eingabe ein Leerzeichen war. (Timwi weist darauf hin, dass dies weiterhin funktionieren würde, wenn die Eingabe Zeilenvorschübe oder Tabulatoren enthalten könnte, aber auch alle anderen nicht druckbaren Zeichen mit Zeichencodes unter 32 entfernen würde.) In diesem Fall wird der <verbleibende Anweisungszeiger (IP) abgelenkt und der hellgraue Weg wird genommen. Dieser Pfad setzt einfach die Position des MP mit zurück {=und liest dann das nächste Zeichen - daher werden Leerzeichen übersprungen. Wenn das Zeichen kein Leerzeichen war, führen wir es aus

=}}})&'+'+)=}

Dieser bewegt sich zunächst um das Sechseck durch die Länge Kante bis zu seiner gegenüber dem diff Kante mit =}}}. Dann kopiert den Wert aus gegenüber der Länge Kante in die Länge Kante und inkrementiert sie mit )&'+'+). Wir werden gleich sehen, warum dies Sinn macht. Zum Schluss verschieben wir die Kante mit =}:

Bildbeschreibung hier eingeben

(Die jeweiligen Kantenwerte stammen aus dem letzten in der Challenge angegebenen Testfall.) Zu diesem Zeitpunkt wiederholt sich die Schleife, wobei sich jedoch alles um ein Sechseck nach Nordosten verschoben hat. Nachdem wir ein anderes Zeichen gelesen haben, erhalten wir Folgendes:

Bildbeschreibung hier eingeben

Jetzt können Sie sehen, dass wir die Eingabe (Minuszeichen) schrittweise entlang der Nordostdiagonale schreiben, wobei die Zeichen an jeder anderen Kante und die Länge bis zu diesem Zeichen parallel zur mit Länge bezeichneten Kante gespeichert werden .

Wenn wir mit der Eingabeschleife fertig sind, sieht der Speicher folgendermaßen aus (wo ich bereits ein paar neue Kanten für den nächsten Teil markiert habe):

Bildbeschreibung hier eingeben

Dies %ist das letzte Zeichen, das wir lesen, und die 29Anzahl der Zeichen, die keine Leerzeichen sind. Nun wollen wir die Seitenlänge des Sechsecks ermitteln. Erstens gibt es im dunkelgrünen / grauen Pfad einen linearen Initialisierungscode:

=&''3{

Hier wird =&die Länge (in unserem Beispiel 29) in die mit Länge bezeichnete Kante kopiert . Bewegt ''3sich dann zu der mit 3 bezeichneten Kante und setzt ihren Wert auf 3(den wir nur als Konstante in der Berechnung benötigen). Bewegt {sich schließlich zu der mit N (N-1) bezeichneten Kante .

Nun betreten wir die blaue Schleife. Diese Schleifeninkremente N(in der mit N bezeichneten Zelle gespeichert ) berechnen dann ihre zentrierte hexagonale Zahl und subtrahieren sie von der eingegebenen Länge. Der lineare Code, der das macht, ist:

{)')&({=*'*)'-

Hier {)bewegt sich auf und erhöht N . ')&(bewegt sich zu der mit N-1 bezeichneten Kante , kopiert Ndort und dekrementiert sie. {=*berechnet ihr Produkt in N (N-1) . '*)multipliziert dies mit der Konstanten 3und erhöht das Ergebnis in der mit hex (N) bezeichneten Kante . Wie erwartet ist dies die N-te zentrierte hexagonale Zahl. Zum Schluss wird '-die Differenz zwischen dieser und der eingegebenen Länge berechnet. Wenn das Ergebnis positiv ist, ist die Seitenlänge noch nicht groß genug, und die Schleife wird wiederholt (wobei }}der MP zurück zu der mit N (N-1) bezeichneten Kante bewegt wird ).

Sobald die Seitenlänge groß genug ist, ist die Differenz null oder negativ und wir erhalten Folgendes:

Bildbeschreibung hier eingeben

Als erstes gibt es jetzt den sehr langen linearen grünen Pfad, der einige notwendige Initialisierungen für die Ausgangsschleife vornimmt:

{=&}}}32'"2'=&'*){=&')&}}

Die {=&beginnt mit dem Kopieren des Ergebnisses in der diff Kante in die Länge Rand, weil wir später etwas kraft- es brauchen. }}}32Schreibt eine 32 in den Rand mit der Bezeichnung Leerzeichen . '"2Schreibt eine Konstante 2 in die unbeschriftete Kante über diff . '=&kopiert N-1in die zweite Kante mit dem gleichen Etikett. '*)multipliziert es mit 2 und inkrementiert es, so dass wir den korrekten Wert in der mit 2N-1 bezeichneten Kante oben erhalten. Dies ist der Durchmesser des Sechsecks. {=&')&kopiert den Durchmesser in die andere Kante mit der Bezeichnung 2N-1 . Anschließend }}kehren Sie zu der mit 2N-1 gekennzeichneten Kante oben zurück.

Beschriften wir die Kanten neu:

Bildbeschreibung hier eingeben

Die Kante, auf der wir uns gerade befinden (die immer noch den Durchmesser des Sechsecks enthält), wird verwendet, um über die Linien der Ausgabe zu iterieren. Die mit Einzug bezeichnete Kante berechnet, wie viele Leerzeichen in der aktuellen Zeile benötigt werden. Die randbeschrifteten Zellen werden verwendet, um die Anzahl der Zellen in der aktuellen Zeile zu durchlaufen.

Wir befinden uns jetzt auf dem rosa Pfad, der den Einzug berechnet . ('-dekrementiert den Linien Iterator und subtrahiert es von N-1 (in den Gedankenstrich Flanke). Der kurze blau / graue Zweig im Code berechnet einfach den Modul des Ergebnisses ( ~negiert den Wert, wenn er negativ oder null ist, und nichts passiert, wenn er positiv ist). Der Rest des rosafarbenen Pfads "-~{subtrahiert den Einzug vom Durchmesser in die Zellenkante und bewegt sich dann zurück zur Einzugskante .

Der schmutzige gelbe Pfad druckt jetzt den Einzug. Die Schleifeninhalte sind wirklich gerecht

'";{}(

Wo '"bewegt sich zum Rand des Raums , ;druckt es, {}bewegt sich zurück zum Einzug und (dekrementiert es.

Wenn wir damit fertig sind, sucht der (zweite) dunkelgraue Pfad nach dem nächsten zu druckenden Zeichen. Der =}bewegt sich in Position (dh auf den Zellenrand , zeigt nach Süden). Dann haben wir eine sehr enge Schleife, {}die sich einfach zwei Kanten in Richtung Südwesten nach unten bewegt, bis wir das Ende der gespeicherten Zeichenfolge erreichen:

Bildbeschreibung hier eingeben

Beachten Sie, dass ich dort eine Kante EOF neu etikettiert habe ? . Sobald wir dieses Zeichen verarbeitet haben, machen wir diese Kante negativ, sodass die {}Schleife hier anstelle der nächsten Iteration endet:

Bildbeschreibung hier eingeben

Im Code befinden wir uns am Ende des dunkelgrauen Pfads, wo wir 'einen Schritt zurück zum eingegebenen Zeichen gehen. Handelt es sich bei der Situation um eines der letzten beiden Diagramme (dh es gibt immer noch ein Zeichen aus der Eingabe, die wir noch nicht gedruckt haben), nehmen wir den grünen Pfad (den unteren für Leute, die mit Grün und nicht gut umgehen können) Blau). Das ist ziemlich einfach: ;druckt das Zeichen selbst. 'bewegt sich zu der entsprechenden Raum Kante , die immer noch ein 32 aus früheren und hält ;Druck , den Raum. Dann {~macht unser EOF? Negativ für die nächste Iteration, 'bewegt sich einen Schritt zurück, damit wir mit einer weiteren engen }{Schleife zum nordwestlichen Ende der Saite zurückkehren können . Was auf der Länge endetZelle (die nicht-positiv unter hex (N) . Schließlich }bewegt sich zurück in die Zellen Kante.

Wenn wir die Eingabe jedoch bereits erschöpft haben, sucht die Schleife nach EOF? wird hier tatsächlich enden:

Bildbeschreibung hier eingeben

In diesem Fall bewegen wir uns 'auf die Länge der Zelle und nehmen stattdessen den hellblauen (oberen) Pfad, der ein No-Op ausgibt. Der Code in diesem Zweig ist linear:

{*46;{{;{{=

Der {*46;schreibt eine 46 in die Kante mit der Bezeichnung no-op und druckt sie aus (dh einen Punkt). Bewegt {{;sich dann zum Rand des Raums und druckt diesen aus. Die {{=Bewegungen zurück in den Zellen für die nächste Iteration umranden.

Zu diesem Zeitpunkt verbinden sich die Pfade wieder und (dekrementieren die Zellenkante . Wenn der Iterator noch nicht Null ist, nehmen wir den hellgrauen Pfad, der einfach die Richtung des MP umkehrt =und dann nach dem nächsten zu druckenden Zeichen sucht.

Ansonsten haben wir das Ende der aktuellen Zeile erreicht und die IP nimmt stattdessen den violetten Pfad. So sieht das Speicherraster an diesem Punkt aus:

Bildbeschreibung hier eingeben

Der violette Pfad enthält Folgendes:

=M8;~'"=

Das =kehrt die Richtung des MP wieder um. M8Setzt den Wert des Sets auf 778(da der Zeichencode von Mis 77und die Ziffern an den aktuellen Wert angehängt werden). Das ist zufällig 10 (mod 256)so. Wenn wir es mit drucken ;, erhalten wir einen Zeilenvorschub. Dann ~macht die Flanke wieder negativ, '"bewegt sich zurück zur Linienkante und =kehrt die MP noch einmal um.

Wenn die Linienkante Null ist, sind wir fertig. Die IP nimmt den (sehr kurzen) roten Pfad, auf dem @das Programm beendet wird. Andernfalls fahren wir auf dem violetten Pfad fort, der sich in den rosafarbenen Pfad zurückzieht, um eine weitere Zeile zu drucken.


Kontrollflussdiagramme, die mit dem HexagonyColorer von Timwi erstellt wurden . Speicherdiagramme, die mit dem visuellen Debugger in seiner Esoteric IDE erstellt wurden .

Martin Ender
quelle
19
Ich sage das oft auf Hexagony-Antworten: Nur whoa.
Conor O'Brien
5
Huh ... aber ... wat ... mind = geblasen
Adnan
Ich hoffte, jemand würde das tun und ... Wow. Ich bin sprachlos. Das ist großartig.
Arcturus
19
Schritt zwei - schreiben Sie die anderen 97%. :)
ASCIIThenANSI
Schritt drei - als Antwort mit den wenigsten Bytes.
Tom M
19

CJam, 56 52 50 48 Bytes

Mein erster Gedanke war: "Hey, ich habe bereits Code dafür!" Aber dann konnte ich nicht die Mühe machen, die notwendigen Teile aus dem Ruby-Code zusammen zu ziehen, vor allem, weil sie für das Golfen nicht sehr geeignet zu sein schienen. Also habe ich stattdessen etwas anderes in CJam ausprobiert ...

lS-{_,4*(3/mq:D1%}{'.+}wD{D(2/-z_S*D@-@/(S*N@s}/

Teste es hier.

Erläuterung

Ein bisschen Mathe über zentrierte hexagonale Zahlen zuerst. Wenn das reguläre Sechseck eine Seitenlänge hat N, enthält es 3N(N-1)+1Zellen, die der Quellcodelänge entsprechen müssen k. Wir können das lösen, Nweil es eine einfache quadratische Gleichung ist:

N = 1/2 ± √(1/4 + (k-1)/3)

Wir können die negative Wurzel ignorieren, da dies ein negatives N ergibt. Damit eine Lösung gefunden werden kann, muss die Quadratwurzel eine halbe ganze Zahl sein. Oder mit anderen Worten, es √(1 + 4(k-1)/3) = √((4k-1)/3)muss eine ganze Zahl sein (zum Glück entspricht diese ganze Zahl dem Durchmesser D = 2N-1des Sechsecks, den wir sowieso benötigen). So können wir wiederholt eine einzelne hinzufügen, .bis diese Bedingung erfüllt ist.

Der Rest ist eine einfache Schleife, die das Sechseck auslegt. Eine nützliche Beobachtung für diesen Teil ist, dass sich die Leerzeichen in der Einrückung plus die Nicht-Leerzeichen im Code in jeder Zeile zum Durchmesser addieren.

lS-     e# Read input and remove spaces.
{       e# While the first block yields something truthy, evaluate the second...
  _,    e#   Duplicate the code and get its length k.
  4*(   e#   Compute 4k-1.
  3/    e#   Divide by 3.
  mq    e#   Take the square root.
  :D    e#   Store this in D, just in case we're done, because when we are, this happens
        e#   to be the diameter of the hexagon.
  1%    e#   Take modulo 1. This is 0 for integers, and non-zero for non-integers.
}{      e# ...
  '.+   e#   Append a no-op to the source code.
}w
D{      e# For every i from 0 to D-1...
  D(2/  e#   Compute (D-1)/2 = N, the side length.
  -z    e#   Subtract that from the current i and get its modulus. That's the size of the
        e#   indentation on this line.
  _S*   e#   Duplicate and get a string with that many spaces.
  D@-   e#   Subtract the other copy from D to get the number of characters of code
        e#   in the current line.
  @/    e#   Pull up the source code and split into chunks of this size.
  (S*   e#   Pull off the first chunk and riffle it with spaces.
  N     e#   Push a linefeed character.
  @s    e#   Pull up the remaining chunks and join them back into a single string.
}/

Es stellt sich heraus, dass wir überhaupt keine Doppelarithmetik verwenden müssen (mit Ausnahme der Quadratwurzel). Aufgrund der Multiplikation mit 4 treten beim Teilen durch 3 keine Kollisionen auf, und der gewünschte kWert liefert als erster eine ganzzahlige Quadratwurzel.

Martin Ender
quelle
8

Perl, 203 200 198

enthält + 1 für -p

s/\s//g;{($l=y///c)>($h=1+3*++$n*($n-1))&&redo}$s=$_.'.'x($h-$l);for($a=$n;$a<($d=2*$n-1);$a++){$s=~s/.{$a}/$&\n/,$s=reverse($s)for 0..1}$_=join$/,map{(' 'x abs($n-$i++-1)).$_}$s=~/\S+/g;s/\S/ $&/g

Rennen wie: echo abc | perl -p file.pl

Ein sehr naiver Ansatz:

#!/usr/bin/perl -p

s/\s//g;                            # ignore spaces and EOL etc.
{                                   # find the smallest hex number:
    ($l=y///c)                      # calc string length
    > ($h=1+3*++$n*($n-1))          # 
    && redo                         # (should use 'and', but..)
}

$s = $_                             # save $_ as it is used in the nested for
   . '.' x ($h-$l);                 # append dots to fill hexagon

for ( $a = $n; $a < ($d=2*$n-1); $a++ )
{
        $s=~s/.{$a}/$&\n/,          # split lines
        $s=reverse($s)              # mirror
    for 0..1                        # twice
}

$_ = join$/,                        # join using newline
map {                               # iterate the lines
    (' 'x abs($n-$i++-1)) .$_       # prepend padding
} $s=~/\S+/g;                       # match lines

s/\S/ $&/g                          # prepend spaces to characters
                                    # -p takes care of printing $_

  • Update 200 speichere eine Byte-Verschiebungsvariablenzuweisung und weitere 2 durch Weglassen von final ;; Code sich jetzt unter 200 Bytes!
  • Update 198 spart 2 Bytes durch Verwendung von $s=~/\S+/ganstelle vonsplit/\n/,$s
Kenney
quelle
7

JavaScript (ES6), 162, 172

Anonyme Funktion

Die Sechseckgröße wird gefunden, indem die Gleichung aus Wikipedia aufgelöst wird

3*n*(n-1)-1 = l

Die Lösungsformel ist grundsätzlich

n = ceil(3+sqrt(12*l-3))/6)

Mit etwas Algebra und etwas Näherung (Danke auch an @ user18655) wird es

n = trunc(sqrt(l/3-1/12)+1.4999....)
s=>eval("s=s.match(/\\S/g);m=n=Math.sqrt(s.length/3-1/12)+1.49999|0;p=o=``;for(i=n+n;--i;i>n?++m:--m)for(o+=`\n`+` `.repeat(n+n-m),j=m;j--;o+=` `)o+=s[p++]||`.`")

Mehr lesbar

s=>{
  s=s.match(/\S/g);
  m=n=Math.sqrt(s.length/3-1/12)+1.49999;
  p=o='';
  for(i=n+n; --i; i>n?++m:--m)
    for(o += '\n'+' '.repeat(n+n-m), j=m; j--; o += ' ')
      o+=s[p++]||'.';
  return o
}

Testschnipsel (besser ganze Seite - Laufzeit ~ 1 Minute)

f=s=>eval("s=s.match(/\\S/g);m=n=Math.sqrt(s.length/3-1/12)+1.49999|0;p=o=``;for(i=n+n;--i;i>n?++m:--m)for(o+=`\n`+` `.repeat(n+n-m),j=m;j--;o+=` `)o+=s[p++]||`.`")

t=0;
r='0';
(T=_=>t++<816?(O.innerHTML=f(r=t%10+r),setTimeout(T,20)):0)()
pre { font-size: 66% }
<pre id=O></pre>

edc65
quelle
1
Sie könnten n=...+1-1e-9|0anstelle von n=Math.ceil(...)2 Bytes speichern. Sie könnten auch ES7 verwenden und **0.5stattdessen, Math.sqrtaber das liegt bei Ihnen. Normalerweise behalte ich meine Antworten bei ES6, weil sie in meinem Browser funktionieren, haha!
user81655
@ user81655 guter tipp, danke
edc65
5

Pyth, 52 51 Bytes

Jfgh**3TtTl=H-zd1=+H*\.*lHTV+UJt_UJAcH]+JN+*-JNdjdG

Probieren Sie es online aus. Testsuite.

Jede Zeile hat ein zusätzliches Leerzeichen, wie vom OP zugelassen.

Erläuterung

 f              1          |   find first number n for which
             -zd           |           remove spaces from input
           =H              |         put result in H
          l                |       length of input without spaces
  g                        |     is less than or equal to
   h**3TtT                 |       nth centered hexagonal number
J                          | put result (hexagon side length) in J
                           |
      *lHT                 |      ten times length of input without spaces
   *\.                     |   that amount of dots
=+H                        | append to H
                           |
  UJ                       |    numbers 0 up to side length - 1
 +  t_UJ                   |   add numbers side length - 2 down to 0
V                          | loop over result
            +JN            |       current loop number + side length
         cH]               |     split to two parts at that position
        A                  |   put parts to G and H
                 -JN       |       side length - current loop number - 1
                *   d      |     that many spaces
                     jdG   |     join code on the line (G) by spaces
               +           |   concatenate parts and print
PurkkaKoodari
quelle
5

Netzhaut , 161 Bytes

Vielen Dank an FryAmTheEggman für das Speichern von 2 Bytes.

Diese Antwort ist nicht konkurrierend. Retina hat seit dieser Herausforderung einige Updates gesehen, und ich bin mir ziemlich sicher, dass ich einige der neueren Funktionen verwende (obwohl ich sie nicht überprüft habe).

Die Anzahl der Bytes setzt die Kodierung nach ISO 8859-1 voraus. Die erste Zeile enthält ein einzelnes Leerzeichen. Beachten Sie, dass die meisten ·Punkte tatsächlich Mittelpunkt sind (0xB7).

 

^
$._$*·¶
^·¶
¶
((^·|\2·)*)·\1{5}·+
$2·
^·*
$.&$* ·$&$&$.&$* 
M!&m`(?<=(?= *(·)+)^.*)(?<-1>.)+(?(1)!)|^.+$
+m`^( *·+)· *¶(?=\1)
$& 
·
 ·
O$`(·)|\S
$1
·
.
G-2`

Probieren Sie es online!

Gut...

Erläuterung

Es scheint am einfachsten zu sein, das Layout zuerst mit nur einem Zeichen zu erstellen ( ·in diesem Fall) und dann das resultierende Layout mit den eingegebenen Zeichen zu füllen. Die Hauptgründe dafür sind, dass ich bei der Verwendung eines einzelnen Zeichens auf Rückverweise und Zeichenwiederholungen zurückgreifen kann, bei denen das direkte Layout der Eingabe teure Bilanzkreise erfordern würde.

 

Obwohl es nicht viel aussieht, werden in dieser ersten Phase Leerzeichen aus der Eingabe entfernt.

^
$._$*·¶

Wir beginnen mit dem Voranstellen einer zusätzlichen Zeile mit MMittelpunkten, wobei Mdie Länge der Eingabe (nach dem Entfernen von Leerzeichen) angegeben ist.

^·¶
¶

Wenn es sich bei der Eingabe um ein einzelnes Zeichen handelte, wird der mittlere Punkt wieder entfernt. Dies ist ein unglücklicher Sonderfall, der in der nächsten Phase nicht behandelt wird.

((^·|\2·)*)·\1{5}·+
$2·

Dies berechnet die erforderliche Seitenlänge Nminus 1. So funktioniert das: Zentrierte hexagonale Zahlen haben die Form 3*N*(N-1) + 1. Da es sich um Dreieckszahlen handelt N*(N-1)/2, bedeutet dies, dass sechseckige Zahlen das Sechsfache einer Dreieckszahl plus 1 sind. Dies ist praktisch, da das Zuordnen von Dreieckszahlen (die wirklich nur 1 + 2 + 3 + ... + Naus einer Regex bestehen) mit Vorwärtsreferenzen relativ einfach ist. Das (^·|\2·)*stimmt mit der größten dreieckigen Zahl überein, die es kann. Als netter Bonus hält $2dann der Index diese Dreieckszahl. Um es mit 6 zu multiplizieren, fangen wir es in Gruppen ein 1und gleichen es weitere 5 Mal ab. Wir stellen sicher, dass es mindestens zwei weitere ·mit dem ·und dem gibt·+. Auf diese Weise erhöht sich der Index der gefundenen dreieckigen Zahl erst, wenn ein Zeichen mehr als eine zentrierte hexagonale Zahl vorhanden ist.

Am Ende ergibt diese Übereinstimmung zwei weniger als die Seitenlänge des erforderlichen Sechsecks in der Gruppe $2, daher schreiben wir das zurück, zusammen mit einem weiteren Mittelpunkt, um zu erhalten N-1.

^·*
$.&$* ·$&$&$.&$* 

Dies verwandelt unsere Reihe von N-1Mittelpunkten in N-1Räume, 2N-1Mittelpunkte und andere N-1Räume. Beachten Sie, dass dies die maximale Einrückung ist, gefolgt vom Durchmesser des Sechsecks, gefolgt von der erneuten Einrückung.

M!&m`(?<=(?= *(·)+)^.*)(?<-1>.)+(?(1)!)|^.+$

Dies ist unangenehm lang, aber es gibt uns im Grunde nur alle überlappenden Übereinstimmungen, die entweder a) 2N-1lang und in der ersten Zeile oder b) in der zweiten Zeile sind. Dies erweitert das Ergebnis der vorherigen Stufe in das vollständige, aber merkwürdig eingezogene Sechseck. ZB für die Eingabe würden 12345678wir erhalten:

  ···
 ····
·····
···· 
···  
12345678

Aus diesem Grund mussten wir in der vorherigen Phase auch Leerzeichen anhängen.

+m`^( *·+)· *¶(?=\1)
$& 

Dies behebt den Einzug der Zeilen nach der Mitte, indem alle Zeilen, die kürzer als die vorherigen sind, wiederholt eingerückt werden (wobei nachfolgende Leerzeichen ignoriert werden).

  ···
 ····
·····
 ···· 
  ···  
12345678

Jetzt fügen wir nur einige Leerzeichen mit ein

·
 ·

Welches gibt uns:

   · · ·
  · · · ·
 · · · · ·
  · · · · 
   · · ·  
12345678

Puh, das ist erledigt.

O$`(·)|\S
$1

Zeit, die Eingabezeichenfolge in die mittleren Punkte einzufügen. Dies geschieht mit Hilfe einer Sortierstufe. Wir gleichen alle Mittelpunkte und jedes Zeichen in der letzten Zeile ab und sortieren sie nach dem Ergebnis der angegebenen Ersetzung. Diese Ersetzung ist für die Zeichen in der letzten Zeile und ·für die mittleren Punkte leer. Daher werden die mittleren Punkte einfach bis zum Ende sortiert (da die Sortierung stabil ist). Dies verschiebt die eingegebenen Zeichen an die richtige Stelle:

   1 2 3
  4 5 6 7
 8 · · · ·
  · · · · 
   · · ·  
········

Nur noch zwei Dinge:

·
.

Dadurch werden die mittleren Punkte zu regelmäßigen Perioden.

G-2`

Und das verwirft die letzte Zeile.

Martin Ender
quelle
1

JavaScript (ES6), 144 Byte

(s,n=1,l=0,p=0,m=s.match(/\S/g))=>m[n]?f(s,n+6*++l,l):[...Array(l+l+1)].map((_,i,a)=>a.map((_,j)=>j<l-i|j<i-l?``:m[p++]||`.`).join` `).join`\n`

Wobei \ndas wörtliche Zeilenumbruchzeichen darstellt. Verwendet eine Technik zum Erstellen eines Sechsecks, die ich zuvor für mehrere andere Antworten verwendet habe. Für ES7 ist die Quadratwurzelbildung etwas kürzer als der rekursive Ansatz:

(s,p=0,m=s.match(/\S/g),l=(~-m.length/3)**.5+.5|0)=>[...Array(l+l+1)].map((_,i,a)=>a.map((_,j)=>j<l-i|j<i-l?``:m[p++]||`.`).join` `).join`\n`
Neil
quelle
1

Python 3 , 144 Bytes

c=input().replace(' ','')
n=x=1
while x<len(c):x+=n*6;n+=1
c=c.ljust(x,'.')
while c:print(' '*(x-n)+' '.join(c[:n]));c=c[n:];n-=(len(c)<x/2)*2-1

Probieren Sie es online!

Dabei wird für Sechsecke unterschiedlicher Größe eine unterschiedliche Menge an führenden Leerzeichen verwendet, die allgemeine Form bleibt jedoch erhalten.

Scherzen
quelle