Rozkładanie kodu źródłowego Hexagony

52

Wprowadzenie

Jeśli nie znasz Hexagony , jest to ezoteryczny język stworzony przez Martina Büttnera. Chodzi o to, że ten język akceptuje wiele formularzy dla programu. Następujące programy są równoważne:

abcdefg

i

 a b
c d e
 f g

Zasadniczo kod został zwinięty w zwykły sześciokąt. Należy jednak pamiętać, że dodanie nowego kodu do kodu, które abcdefghbyłoby wynikiem w następującym programie:

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

Jak widać, pierwszym krokiem jest zrolowanie kodu do sześciokąta, a następnie sześciokąt zostaje wypełniony opcjami „no” ( .) do następnej wyśrodkowanej liczby heksagonalnej .

Twoje zadanie jest proste, gdy otrzymasz ciąg znaków (kod źródłowy), wypisz pełny sześciokątny kod źródłowy.

Zasady

  • Możesz podać program lub funkcję.
  • Wiodące białe znaki są dozwolone, ale tylko wtedy, gdy sześciokąt nie wychodzi z kształtu
  • Końcowe białe znaki są dozwolone.
  • Zauważ, że białe znaki w programie są ignorowane . Więc a b cjest równyabc
  • 32 - 126Używane są tylko drukowalne znaki ASCII ( ), więc Spaceignorowany jest tylko zwykły znak.
  • Załóżmy, że długość ciągu jest większa niż 0.
  • To jest , więc wygrywanie z najmniejszą ilością bajtów wygrywa!

Przypadki testowe

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
źródło
6
Nie jestem też pewien, czy chcesz być tak wybredny, ale backsticks są ignorowane w procesie określania szerokości kodu, ponieważ opisują następny znak. Tak abc`defgnaprawdę stałby się pastebin.com/ZrdJmHiR
Martin Ender
2
@ MartinBüttner Och, nie wiedziałem o tym :). W przypadku tego wyzwania kopnięcia wsteczne nie zostaną zignorowane.
Adnan
18
Naprawdę chcę zobaczyć odpowiedź w Hexagony na to pytanie.
Arcturus,
2
@Adnan Prawdopodobnie lepszą odpowiedzią byłoby „Możesz założyć, że dane wejściowe nie zawierają flag debugowania ( `znaków)”.
Riking
4
@Ampora Zapytaj, a otrzymasz.
Martin Ender,

Odpowiedzi:

13

Pyth, 57 54 50 49 48 46

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

Pakiet testowy

Drukuje spację wiodącą w każdej linii.

Ta wersja wymaga dowodu, że 10 ^ n> = 3n (n - 1) + 1 dla wszystkich n> = 1 . Dzięki ANerdI i ErickWong za dostarczenie dowodów.

Po tych nierównościach: 10 ^ n> (1 + 3) ^ n = 1 + 3n + 9n (n - 1) + ...> 3n (n - 1) + 1 łatwo można zauważyć, że jest to poprawne dla n> = 2 . Badanie przypadku n = 1 jest dość trywialne, dając 10> 1 .

Alternatywnie, dwukrotne pobranie pochodnych tych równań pokazuje, że 10 ^ n ma większą drugą pochodną dla wszystkich n> = 1 , które można następnie kaskadowo obniżyć do pierwszych pochodnych, a na koniec do pierwotnych równań.

Wyjaśnienie

              ##  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
źródło
2
Najpierw musisz udowodnić, że ln (10) * 10 ^ n> 6n-3 (pochodne) dla n> = 1. Jest to łatwe, ponieważ pochodnymi tych wyrażeń są ln (10) ^ 2 10 ^ n i 6. Ponieważ 10 ^ n rośnie monotonicznie, a 10 ^ 1> 6 * 1, 10 ^ n jest większe niż 6n-3 dla wszystkich n> = 1. Możesz użyć tej samej logiki, aby uzupełnić dowód dla 10 ^ n i 3n (n-1) +1.
Arcturus
@Ampora Dzięki, zastanawiałem się nad wykorzystaniem instrumentów pochodnych, ale wydawało się to nieczyste. Nie mogłem znaleźć lepszego sposobu, tak bardzo doceniony!
FryAmTheEggman,
Miło, że mogłem pomóc. Czasami Calc może stać się naprawdę brzydki.
Arcturus,
w linku pyth.herokuapp.com/?code=etc powyżej znajduję, że kompilator nie działa ...
RosLuP 26.09.16
1
@FryAmTheEggman Jest bardzo łatwy sposób, aby pokazać znacznie silniejszą granicę 4 ^ n> 3n (n-1) + 1 dla n> = 1, nie jest wymagany rachunek różniczkowy. Wystarczy użyć faktu, że (1 + 3) ^ n = 1 + 3n + 9n (n-1) / 2 + ... przez rozwinięcie dwumianowe. Pierwszy i trzeci termin bezpośrednio składają się z 1 + 3n (n-1), więc nierówność jest natychmiastowa, jeśli istnieje trzeci termin (to znaczy dla n> = 2). Pozostaje tylko przypadek n = 1, który jest trywialny, ponieważ RHS wynosi 1.
Erick Wong
90

Sześciokąty , 271 bajtów

Przedstawiam wam, pierwsze 3% autopretera Hexagony ...

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

Wypróbuj online! Możesz także uruchomić go na sobie, ale zajmie to około 5-10 sekund.

Zasadniczo może się to zmieścić w boku o długości 9 (dla wyniku 217 lub mniej), ponieważ używa tylko 201 poleceń, a wersja bez golfa, którą napisałem jako pierwsza (na boku o długości 30), potrzebowała tylko 178 poleceń. Jestem jednak pewien, że wszystko zajmie wieczność, więc nie jestem pewien, czy spróbuję.

Powinno być także możliwe zagranie w golfa nieco w rozmiarze 10, unikając użycia ostatniego jednego lub dwóch rzędów, tak aby można było pominąć końcowe brakujące operacje, ale wymagałoby to znacznego przepisania, jako jednej z pierwszych ścieżek złączenia wykorzystuje lewy dolny róg.

Wyjaśnienie

Zacznijmy od rozwinięcia kodu i opatrzenia adnotacjami ścieżek kontroli:

wprowadź opis zdjęcia tutaj

To wciąż dość niechlujny, więc oto ten sam schemat dla kodu „nie golfowego”, który napisałem jako pierwszy (w rzeczywistości jest to długość boku 20 i pierwotnie napisałem kod na boku długości 30, ale był tak rzadki, że nie w ogóle nie poprawiają czytelności, więc trochę go skompaktowałem, aby rozmiar był bardziej rozsądny):

wprowadź opis zdjęcia tutaj
Kliknij, aby zobaczyć większą wersję.

Kolory są dokładnie takie same, z wyjątkiem kilku bardzo drobnych szczegółów, polecenia niekontrolowanego przepływu również są dokładnie takie same. Wyjaśnię więc, jak to działa w oparciu o wersję bez golfa, a jeśli naprawdę chcesz wiedzieć, jak działa gra w golfa, możesz sprawdzić, które części odpowiadają tym w większym sześciokącie. (Jedynym haczykiem jest to, że kod do gry w golfa zaczyna się od lustra, tak że rzeczywisty kod zaczyna się w prawym rogu, po lewej stronie.)

Podstawowy algorytm jest prawie identyczny z moją odpowiedzią CJam . Istnieją dwie różnice:

  • Zamiast rozwiązać wyśrodkowane równanie liczb heksagonalnych, po prostu obliczam kolejne wyśrodkowane liczby heksagonalne, aż jedna będzie równa lub większa niż długość danych wejściowych. Wynika to z faktu, że Hexagony nie ma prostego sposobu na obliczenie pierwiastka kwadratowego.
  • Zamiast od razu uzupełniać dane wejściowe brakiem operacji, sprawdzam później, czy wyczerpałem już polecenia wejściowe i .zamiast tego wypisuję polecenie .

Oznacza to, że podstawowa idea sprowadza się do:

  • Odczytaj i zapisz ciąg wejściowy podczas obliczania jego długości.
  • Znajdź najmniejszą długość boku N(i odpowiadającą jej wyśrodkowaną liczbę sześciokątną hex(N)), która może pomieścić całe dane wejściowe.
  • Oblicz średnicę 2N-1.
  • Dla każdej linii oblicz wcięcie i liczbę komórek (które sumują się 2N-1). Wydrukuj wcięcie, wydrukuj komórki (używając, .jeśli dane wejściowe są już wyczerpane), wydrukuj linię.

Zauważ, że nie ma żadnych operacji, więc rzeczywisty kod zaczyna się w lewym rogu (ten $, który przeskakuje nad >, więc naprawdę zaczynamy od ,ciemnoszarej ścieżki).

Oto początkowa siatka pamięci:

wprowadź opis zdjęcia tutaj

Wskaźnik pamięci zaczyna się od wejścia oznaczonego krawędziami , wskazując na północ. ,czyta bajt ze STDIN lub a, -1jeśli trafiliśmy EOF w tę krawędź. Dlatego <zaraz po tym jest warunek, czy przeczytaliśmy wszystkie dane wejściowe. Pozostańmy na razie w pętli wejściowej. Następny kod, który wykonujemy, to

{&32'-

Spowoduje to zapisanie 32 w przestrzeni oznaczonej krawędzią , a następnie odejmuje ją od wartości wejściowej w różnicy oznaczonej krawędzią . Zauważ, że to nigdy nie może być ujemne, ponieważ gwarantujemy, że dane wejściowe zawierają tylko drukowalne ASCII. Wyniesie zero, gdy wejście będzie spacją. (Jak wskazuje Timwi, nadal działałoby to, gdyby dane wejściowe mogły zawierać linie lub tabulatory, ale również usuwałyby wszystkie inne niedrukowalne znaki o kodach znaków mniejszych niż 32.) W takim przypadku <odchyla wskaźnik instrukcji (IP) w lewo i wybrano jasnoszarą ścieżkę. Ta ścieżka po prostu resetuje pozycję MP za pomocą, {=a następnie odczytuje następny znak - w ten sposób spacje są pomijane. W przeciwnym razie, jeśli postać nie jest spacją, wykonujemy

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

To najpierw porusza się wokół sześciokąta przez krawędź długości, aż znajdzie się naprzeciwko krawędzi różnicy , przy pomocy =}}}. Następnie kopiuje wartość z naprzeciwko długości krawędzi do długości krawędzi i inkrementuje się )&'+'+). Zobaczymy za chwilę, dlaczego ma to sens. Wreszcie przenosimy nową przewagę dzięki =}:

wprowadź opis zdjęcia tutaj

(Konkretne wartości krawędzi pochodzą z ostatniego przypadku testowego podanego w wyzwaniu). W tym momencie pętla się powtarza, ale wszystko przesuwa się o jeden sześciokąt na północny wschód. Po przeczytaniu innej postaci otrzymujemy:

wprowadź opis zdjęcia tutaj

Teraz możesz zobaczyć, że stopniowo zapisujemy dane wejściowe (minus spacje) wzdłuż północno-wschodniej przekątnej, z znakami na każdej drugiej krawędzi, a długość do tego znaku jest przechowywana równolegle do długości oznaczonej krawędzi .

Kiedy skończymy z pętlą wejściową, pamięć będzie wyglądać następująco (gdzie już oznaczyłem kilka nowych krawędzi dla następnej części):

wprowadź opis zdjęcia tutaj

Jest %to ostatni znak, który czytamy, 29to liczba znaków spacji, które czytamy. Teraz chcemy znaleźć długość boku sześciokąta. Po pierwsze, na ciemnozielonej / szarej ścieżce znajduje się kod liniowej inicjalizacji:

=&''3{

Tutaj =&skopiuj długość (29 w naszym przykładzie) na długość oznaczoną krawędzią . Następnie ''3przechodzi do krawędzi oznaczonej jako 3 i ustawia jego wartość na 3(której potrzebujemy po prostu jako stałej w obliczeniach). Na koniec {przechodzi do krawędzi oznaczonej jako N (N-1) .

Teraz wchodzimy w niebieską pętlę. Przyrosty pętli N(przechowywane w komórce oznaczonej jako N ) obliczają następnie wyśrodkowaną liczbę heksagonalną i odejmują ją od długości wejściowej. Kod liniowy, który to robi, to:

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

Tutaj, {)przesuwa się i zwiększa N . ')&(przesuwa się do krawędzi oznaczonej jako N-1 , kopiuje Ntam i zmniejsza ją. {=*oblicza swój produkt w N (N-1) . '*)mnoży to przez stałą 3i inkrementuje wynik na krawędzi oznaczonej hex (N) . Zgodnie z oczekiwaniami jest to n-ta środkowa liczba heksagonalna. Na koniec '-oblicza różnicę między tym a długością wejściową. Jeśli wynik jest dodatni, długość boku nie jest jeszcze wystarczająco duża, a pętla powtarza się (tam, gdzie }}przesuwa się MP z powrotem do krawędzi oznaczonej N (N-1) ).

Gdy długość boku będzie wystarczająco duża, różnica wyniesie zero lub będzie ujemna i otrzymamy to:

wprowadź opis zdjęcia tutaj

Po pierwsze, jest teraz naprawdę długa zielona liniowa ścieżka, która dokonuje niezbędnej inicjalizacji pętli wyjściowej:

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

Do {=&rozpoczyna kopiując wynik w diff krawędzi do długości krawędzi, bo później trzeba coś tam non-dodatnich. }}}32zapisuje 32 w spacji oznaczonej krawędzią . '"2zapisuje stałą 2 w nieoznakowanej krawędzi nad różnicą . '=&kopiuje N-1na drugą krawędź z tą samą etykietą. '*)mnoży go przez 2 i zwiększa, aby uzyskać prawidłową wartość na krawędzi oznaczonej 2N-1 u góry. Jest to średnica sześciokąta. {=&')&kopiuje średnicę na drugą krawędź oznaczoną 2N-1 . Na koniec }}przesuwa się z powrotem do krawędzi oznaczonej 2N-1 u góry.

Ponownie oznakuj krawędzie:

wprowadź opis zdjęcia tutaj

Krawędź, na której się obecnie znajdujemy (która nadal ma średnicę sześciokąta), zostanie wykorzystana do iteracji po liniach wyjścia. Wcięcie oznaczone krawędzią obliczy, ile spacji jest potrzebnych w bieżącym wierszu. Komórki oznaczone krawędzią zostaną użyte do iteracji po liczbie komórek w bieżącym wierszu.

Jesteśmy teraz na różowej ścieżce, która oblicza wcięcie . ('-zmniejsza iterator linii i odejmuje go od N-1 (do krawędzi wcięcia ). Krótka niebieska / szara gałąź w kodzie po prostu oblicza moduł wyniku ( ~neguje wartość, jeśli jest ujemna lub zero, i nic się nie dzieje, jeśli jest dodatnia). Reszta różowej ścieżki "-~{odejmuje wcięcie od średnicy do krawędzi komórki, a następnie przesuwa się z powrotem do krawędzi wcięcia .

Brudna żółta ścieżka drukuje teraz wcięcie. Zawartość pętli jest naprawdę sprawiedliwa

'";{}(

Gdzie '"przesuwa się do krawędzi przestrzeni , ;drukuje ją, {}wraca do wcięcia i (zmniejsza.

Kiedy skończymy, (druga) ciemnoszara ścieżka szuka następnego znaku do wydrukowania. W =}przesuwa się w pozycji (co oznacza, na komórki krawędzi, wskazujące na południu). Następnie mamy bardzo ciasną pętlę, {}która po prostu przesuwa się w dół o dwie krawędzie w kierunku południowo-zachodnim, dopóki nie trafimy na koniec przechowywanego ciągu:

wprowadź opis zdjęcia tutaj

Czy zauważyłeś, że ponownie oznakowałem jedną krawędź EOF? . Po przetworzeniu tego znaku zmienimy krawędź na ujemną, aby {}pętla zakończyła się tutaj zamiast następnej iteracji:

wprowadź opis zdjęcia tutaj

W kodzie jesteśmy na końcu ciemnoszarej ścieżki, gdzie 'cofamy się o jeden krok na znak wejściowy. Jeśli sytuacja jest jednym z dwóch ostatnich schematów (tzn. Z danych wejściowych, których jeszcze nie wydrukowaliśmy, jest jeszcze znak), to podążamy zieloną ścieżką (dolną, dla osób, które nie są dobre w zieleni i niebieski). To jest dość proste: ;drukuje samą postać. 'przesuwa się na odpowiednią krawędź spacji, która wciąż zawiera 32 z wcześniejszego miejsca i ;drukuje tę przestrzeń. To {~sprawia, że ​​nasz EOF? ujemny dla następnej iteracji, 'przesuwa się o krok wstecz, abyśmy mogli powrócić do północno-zachodniego końca struny za pomocą kolejnej ciasnej }{pętli. Która kończy się na długościkomórka (nie dodatnia poniżej heksa (N) . W końcu }przesuwa się z powrotem do krawędzi komórki .

Jeśli jednak wyczerpaliśmy już dane wejściowe, to pętla, która szuka EOF? zakończy się tutaj:

wprowadź opis zdjęcia tutaj

W takim przypadku 'przesuwa się na komórkę długości i zamiast tego bierzemy jasnoniebieską (górną) ścieżkę, która drukuje brak operacji. Kod w tej gałęzi jest liniowy:

{*46;{{;{{=

W {*46;zapisuje 46 do krawędzi oznaczony nie-op i drukuje (to znaczy okres). Następnie {{;przesuwa się do krawędzi przestrzeni i drukuje to. W {{=wraca do komórek krawędzi dla kolejnej iteracji.

W tym momencie ścieżki łączą się ze sobą i (zmniejszają krawędź komórek . Jeśli iterator nie jest jeszcze zerowy, pójdziemy jasnoszarą ścieżką, która po prostu odwraca kierunek MP, =a następnie szuka następnej postaci do wydrukowania.

W przeciwnym razie dotarliśmy do końca bieżącej linii, a adres IP przejdzie purpurową ścieżką. Oto jak wygląda siatka pamięci w tym momencie:

wprowadź opis zdjęcia tutaj

Purpurowa ścieżka zawiera to:

=M8;~'"=

=Odwraca kierunek MP ponownie. M8ustawia ustawia jego wartość na 778(ponieważ kod znaku Mjest, 77a cyfry dołączą się do bieżącej wartości). Tak się dzieje 10 (mod 256), więc kiedy go wydrukujemy ;, otrzymujemy wysuw linii. Następnie ponownie ~powoduje, że krawędź jest ujemna, '"wraca do krawędzi linii i ponownie =odwraca MP.

Teraz, jeśli krawędź linii wynosi zero, jesteśmy skończeni. Adres IP podąży (bardzo krótką) czerwoną ścieżką, gdzie @kończy program. W przeciwnym razie kontynuujemy fioletową ścieżkę, która zapętla się z powrotem do różowej, aby wydrukować kolejną linię.


Kontroluj diagramy przepływu utworzone za pomocą HexagonyColorer firmy Timwi . Diagramy pamięci utworzone za pomocą wizualnego debuggera w jego Esoteric IDE .

Martin Ender
źródło
19
Często mówię to na temat odpowiedzi w heksagonii: Po prostu whoa.
Conor O'Brien,
5
Huh ... ale .. wat ... mind = dmuchane
Adnan
Miałem nadzieję, że ktoś to zrobi i ... Wow. Nie wiem co powiedzieć. To cudownie.
Arcturus,
19
Krok drugi - napisz pozostałe 97%. :)
ASCIIThenANSI,
Krok trzeci - jako odpowiedź z najmniejszą liczbą bajtów.
Tom M
19

CJam, 56 52 50 48 bajtów

Moją pierwszą myślą było: „hej, mam już do tego kod!” Ale potem nie mogłem się martwić wyciągnięciem niezbędnych elementów z kodu Ruby, szczególnie dlatego, że nie nadawały się do gry w golfa. Więc zamiast tego spróbowałem czegoś innego w CJam ...

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

Sprawdź to tutaj.

Wyjaśnienie

Najpierw trochę matematyki na temat wyśrodkowanych liczb heksagonalnych. Jeśli zwykły sześciokąt ma długość boku N, wówczas będzie zawierać 3N(N-1)+1komórki, które muszą być równe długości kodu źródłowego k. Możemy to rozwiązać, Nponieważ jest to proste równanie kwadratowe:

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

Możemy zignorować pierwiastek ujemny, ponieważ daje to ujemną N. Aby to rozwiązać, potrzebujemy pierwiastka kwadratowego z liczby całkowitej. Innymi słowy, √(1 + 4(k-1)/3) = √((4k-1)/3)musi być liczbą całkowitą (na szczęście ta liczba całkowita to średnica D = 2N-1sześciokąta, której i tak będziemy potrzebować). Możemy więc wielokrotnie dodawać jeden, .dopóki ten warunek nie zostanie spełniony.

Reszta to prosta pętla, która określa sześciokąt. Przydatną obserwacją dla tej części jest to, że spacje we wcięciu plus spacje w kodzie w każdej linii sumują się do średnicy.

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.
}/

Okazuje się, że wcale nie musimy stosować podwójnej arytmetyki (z wyjątkiem pierwiastka kwadratowego). Ze względu na mnożenie przez 4, nie ma kolizji podczas dzielenia przez 3, a pożądana kbędzie pierwsza, która da pierwiastek kwadratowy z liczby całkowitej.

Martin Ender
źródło
8

Perl, 203 200 198

zawiera + 1 dla -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

Uruchom jako: echo abc | perl -p file.pl

Bardzo naiwne podejście:

#!/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 $_

  • aktualizacja 200 zapisz bajtowe przypisanie zmiennej ruchomej, a kolejne 2 przez pominięcie końcowego ;; sam kod poniżej 200 bajtów!
  • aktualizacja 198 zapisz 2 bajty, używając $s=~/\S+/gzamiastsplit/\n/,$s
Kenney
źródło
7

JavaScript (ES6), 162 172

Funkcja anonimowa

Znaleziono rozmiar sześciokąta rozwiązujący równanie z wikipedii

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

Formuła rozwiązywania jest w zasadzie

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

Z pewną algebrą i pewnym przybliżeniem (również dla @ user18655) staje się

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++]||`.`")

Bardziej czytelny

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
}

Fragment testowy (lepsza pełna strona - czas działania ~ 1 minuta)

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
źródło
1
Możesz użyć n=...+1-1e-9|0zamiast n=Math.ceil(...)zapisać 2 bajty. Możesz także użyć ES7 i używać **0.5zamiast, Math.sqrtale to zależy od ciebie. Zwykle zachowuję swoje odpowiedzi ES6, ponieważ działają one w mojej przeglądarce haha!
user81655,
@ user81655 dobra podpowiedź, dzięki
edc65
5

Pyth, 52 51 bajtów

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

Wypróbuj online. Zestaw testowy.

Każda linia ma jedno dodatkowe pole wiodące, na co pozwala OP.

Wyjaśnienie

 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
źródło
5

Retina , 161 bajtów

Dzięki FryAmTheEggman za zapisanie 2 bajtów.

Ta odpowiedź nie jest konkurencyjna. Retina widziała kilka aktualizacji od tego wyzwania i jestem prawie pewien, że korzystam z niektórych nowszych funkcji (chociaż nie sprawdziłem).

Liczba bajtów zakłada kodowanie ISO 8859-1. Pierwszy wiersz zawiera pojedynczą spację. Zauważ, że większość z nich ·to w rzeczywistości kropki środkowe (0xB7).

 

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

Wypróbuj online!

Dobrze...

Wyjaśnienie

Najłatwiej jest najpierw zbudować układ, używając tylko jednego znaku ( ·w tym przypadku), a następnie wypełnić wynikowy układ znakami wejściowymi. Głównymi tego przyczynami są to, że użycie pojedynczej postaci pozwala mi korzystać z odwołań wstecznych i powtarzania postaci, przy czym bezpośrednie wprowadzenie danych wymagałoby kosztownych grup równoważących.

 

Chociaż nie wygląda to zbyt wiele, te pierwsze etapy usuwają spacje z wejścia.

^
$._$*·¶

Zaczynamy od przygotowania dodatkowej linii zawierającej Mpunkty środkowe, gdzie Mjest długość wejścia (po usunięciu spacji).

^·¶
¶

Jeśli wprowadzony tekst był pojedynczym znakiem, ponownie usuwamy tę środkową kropkę. Jest to niefortunny przypadek specjalny, który nie jest objęty następnym etapem.

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

To oblicza wymaganą długość boku Nminus 1. Oto jak to działa: wyśrodkowane liczby heksagonalne mają postać 3*N*(N-1) + 1. Ponieważ liczby trójkątne są N*(N-1)/2, oznacza to , że liczby heksagonalne są sześciokrotnie większe od liczby trójkątnej plus 1. Jest to wygodne, ponieważ dopasowanie liczb trójkątnych (które są naprawdę sprawiedliwe 1 + 2 + 3 + ... + N) w wyrażeniu regularnym jest dość łatwe z odniesieniami do przodu. Te (^·|\2·)*mecze największa liczba trójkątna to możliwe. Jako niezły bonus, $2będzie wtedy trzymał indeks tej trójkątnej liczby. Aby pomnożyć przez 6, przechwytujemy go do grupy 1i dopasowujemy kolejne 5 razy. Zapewniamy, że są jeszcze co najmniej dwa ·z ·i·+. W ten sposób indeks znalezionej liczby trójkątnej nie wzrośnie, dopóki jeden znak nie będzie więcej niż wyśrodkowana liczba heksagonalna.

Ostatecznie to dopasowanie daje nam dwa razy mniej niż długość boku wymaganego sześciokąta w grupie $2, więc piszemy to z powrotem razem z jeszcze jedną środkową kropką, aby uzyskać N-1.

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

To zamienia nasz ciąg N-1środkowych kropek w N-1spacje, 2N-1środkowe kropki i inne N-1spacje. Zauważ, że jest to maksymalne wcięcie, po którym następuje średnica sześciokąta, a następnie ponownie wcięcie.

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

Jest to nieprzyjemnie długie, ale w zasadzie daje nam tylko wszystkie nakładające się dopasowania, które są albo a) 2N-1długimi znakami i w pierwszej linii lub b) drugą linią. To rozszerza wynik z poprzedniego etapu do pełnego, ale dziwnie wciętego sześciokąta. Np. Za dane wejściowe 12345678otrzymalibyśmy:

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

Dlatego też musieliśmy dodać spacje również na poprzednim etapie.

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

To naprawia wcięcie linii po środku, poprzez wielokrotne wcięcie dowolnej linii, która jest krótsza niż poprzednia (ignorując końcowe spacje), więc otrzymujemy:

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

Teraz wstawiamy tylko spacje

·
 ·

Co daje nam:

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

Uff, gotowe.

O$`(·)|\S
$1

Czas wypełnić łańcuch wejściowy w środkowe kropki. Odbywa się to za pomocą etapu sortowania. Dopasowujemy wszystkie środkowe kropki i każdy znak w ostatnim wierszu i sortujemy je według wyniku podanego podstawienia. To podstawienie jest puste dla znaków w ostatnim wierszu i ·dla środkowych kropek, więc dzieje się tak, że środkowe kropki są po prostu sortowane do końca (ponieważ sortowanie jest stabilne). To przenosi znaki wejściowe na miejsce:

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

Zostały tylko dwie rzeczy:

·
.

To zamienia środkowe kropki w regularne okresy.

G-2`

I to odrzuca ostatnią linię.

Martin Ender
źródło
1

JavaScript (ES6), 144 bajty

(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`

Gdzie \nreprezentuje dosłowny znak nowej linii. Wykorzystuje technikę tworzenia sześciokąta, którą wcześniej stosowałem w kilku innych odpowiedziach . W przypadku ES7 przyjmowanie pierwiastków kwadratowych jest nieco krótsze niż podejście rekurencyjne:

(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
źródło
1

Python 3 , 144 bajty

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

Wypróbuj online!

Wykorzystuje dość różną ilość wiodących białych znaków dla sześciokątów o różnych rozmiarach, ale ogólny kształt przetrwa.

Jo King
źródło