Spiegare il codice sorgente di Hexagony


52

introduzione

Se non hai familiarità con Hexagony , è un linguaggio esoterico creato da Martin Büttner. Il fatto è che questa lingua accetta più moduli per il programma. I seguenti programmi sono tutti equivalenti:

abcdefg

e

 a b
c d e
 f g

Quindi, sostanzialmente, il codice è stato arrotolato in un esagono regolare. Ma nota che l'aggiunta di un nuovo comando al codice, che abcdefghsarebbe il risultato nel seguente programma:

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

Come puoi vedere, il primo passo è far rotolare il codice in un esagono, e successivamente l'esagono viene riempito con no-ops ( .) al numero esagonale centrato successivo .

Il tuo compito è semplice, quando viene data una stringa (il codice sorgente), genera l'intero codice sorgente esagonale.

Le regole

  • È possibile fornire un programma o una funzione.
  • Lo spazio bianco iniziale è consentito, ma solo quando l'esagono non si deforma
  • È consentito lo spazio bianco finale.
  • Si noti che gli spazi bianchi nel programma vengono ignorati . Quindi a b cè uguale aabc
  • 32 - 126Vengono utilizzati solo i caratteri ASCII stampabili ( ), quindi Spaceviene ignorato solo il carattere normale .
  • Supponiamo che la lunghezza della stringa sia maggiore di 0.
  • Questo è , quindi vince l'invio con il minor numero di byte!

Casi test

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:
   . ? ' .
  ) . @ @ /
 ' / . ! . >
+ = ( < . ! )
 } ( $ > ( <
  % . . . .
   . . . .

6
Inoltre, non sono sicuro che tu voglia essere così esigente, ma i backtick vengono ignorati nel processo di determinazione della larghezza del codice perché annotano il carattere successivo. Quindi abc`defgdiventerebbe effettivamente pastebin.com/ZrdJmHiR
Martin Ender il

2
@ MartinBüttner Oh, non lo sapevo :). Per questa sfida, i backtick non verranno ignorati.
Adnan,

18
Voglio davvero vedere una risposta in Hexagony per questa domanda.
Arcturus,

2
@Adnan Probabilmente una risposta migliore sarebbe "Puoi presumere che l'input non contenga flag di debug ( `caratteri)".
Riking

4
@Ampora Chiedi e riceverai.
Martin Ender,

Risposte:


13

Pyth, 57 54 50 49 48 46

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

Test Suite

Stampa uno spazio iniziale su ogni riga.

Questa versione richiede una prova che 10 ^ n> = 3n (n - 1) + 1 per tutti n> = 1 . Grazie a ANerdI ed ErickWong per aver fornito prove.

Seguendo queste disuguaglianze: 10 ^ n> (1 + 3) ^ n = 1 + 3n + 9n (n - 1) + ...> 3n (n - 1) + 1 si può facilmente vedere che questo è corretto per n> = 2 . Esaminare il caso n = 1 è piuttosto banale, dando 10> 1 .

In alternativa, prendere due volte le derivate di queste equazioni mostra che 10 ^ n ha una seconda derivata maggiore per tutti n> = 1 , che può quindi essere ridotta a cascata fino alle prime derivate e infine alle equazioni originali.

Spiegazione

              ##  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

2
Per prima cosa devi dimostrare che ln (10) * 10 ^ n> 6n-3 (i derivati) per n> = 1. Questo è facile, poiché le derivate di queste espressioni sono ln (10) ^ 2 10 ^ n e 6. Poiché 10 ^ n è monotonicamente crescente e 10 ^ 1> 6 * 1, 10 ^ n è maggiore di 6n-3 per tutti n> = 1. È possibile utilizzare la stessa logica per completare la prova per 10 ^ n e 3n (n-1) +1.
Arcturus,

@Ampora Grazie, avevo preso in considerazione l'uso di derivati, ma mi sembrava impuro. Tuttavia non sono riuscito a trovare un modo migliore, molto apprezzato!
FryAmTheEggman,

Felice di aiutare. Calc può diventare davvero brutto a volte.
Arcturus,

nel link pyth.herokuapp.com/?code=etc sopra trovo che il compilatore non è in esecuzione ...
RosLuP,

1
@FryAmTheEggman C'è un modo molto semplice per mostrare il limite molto più forte 4 ^ n> 3n (n-1) + 1 per n> = 1, nessun calcolo richiesto. Basta usare il fatto che (1 + 3) ^ n = 1 + 3n + 9n (n-1) / 2 + ... per espansione binomiale. Il primo e il terzo termine ingrandiscono direttamente 1 + 3n (n-1), quindi la disuguaglianza è immediata se esiste il terzo termine (cioè per n> = 2). Questo lascia solo il caso n = 1, il che è banale poiché l'RHS è 1.
Erick Wong,

90

Esagonia , 271 byte

Vi presento, il primo 3% di un auto-interprete Hexagony ...

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

Provalo online! Puoi anche eseguirlo su se stesso, ma ci vorranno circa 5-10 secondi.

In linea di principio, questo potrebbe adattarsi alla lunghezza del lato 9 (per un punteggio di 217 o meno), perché utilizza solo 201 comandi e la versione non modificata che ho scritto per prima (sul lato 30) ha richiesto solo 178 comandi. Tuttavia, sono abbastanza sicuro che ci vorrebbe un'eternità per rendere davvero tutto adatto, quindi non sono sicuro che ci proverò davvero.

Dovrebbe anche essere possibile giocare a golf un po 'nella dimensione 10 evitando l'uso dell'ultima o due file, in modo che le no-op finali possano essere omesse, ma ciò richiederebbe una sostanziale riscrittura, come uno dei primi percorsi join utilizza l'angolo in basso a sinistra.

Spiegazione

Iniziamo spiegando il codice e annotando i percorsi del flusso di controllo:

inserisci qui la descrizione dell'immagine

È ancora piuttosto disordinato, quindi ecco lo stesso diagramma per il codice "non golfato" che ho scritto per primo (in effetti, questo è un lato 20 e in origine ho scritto il codice sul lato 30 ma era così scarso che non avrebbe non migliorare affatto la leggibilità, quindi l'ho compattato un po 'per rendere le dimensioni un po' più ragionevoli):

inserisci qui la descrizione dell'immagine
Clicca per una versione più grande.

I colori sono esattamente gli stessi, a parte alcuni dettagli molto minori, anche i comandi non control-flow sono esattamente gli stessi. Quindi spiegherò come funziona basato sulla versione non golfata, e se vuoi davvero sapere come funziona quella golfizzata, puoi controllare quali parti lì corrispondono a quali nell'esagono più grande. (L'unico problema è che il codice golfizzato inizia con uno specchio in modo che il codice effettivo inizi nell'angolo destro andando a sinistra.)

L'algoritmo di base è quasi identico alla mia risposta CJam . Ci sono due differenze:

  • Invece di risolvere l'equazione del numero esagonale centrato, computo solo numeri esagonali centrati consecutivi fino a quando uno è uguale o maggiore della lunghezza dell'input. Questo perché Hexagony non ha un modo semplice per calcolare una radice quadrata.
  • Invece di riempire subito l'input con no-ops, controllo più tardi se ho già esaurito i comandi nell'input e stampo un .invece se ho.

Ciò significa che l'idea di base si riduce a:

  • Leggere e memorizzare la stringa di input mentre ne calcola la lunghezza.
  • Trova la più piccola lunghezza laterale N(e il corrispondente numero esagonale centrato hex(N)) che può contenere l'intero input.
  • Calcola il diametro 2N-1.
  • Per ogni riga, calcola il rientro e il numero di celle (che si sommano a 2N-1). Stampa il rientro, stampare le celle (usando .se l'ingresso è già esaurita), stampare un avanzamento riga.

Nota che ci sono solo no-op, quindi il codice effettivo inizia nell'angolo sinistro (il $, che salta sopra il >, quindi iniziamo davvero sul ,nel percorso grigio scuro).

Ecco la griglia di memoria iniziale:

inserisci qui la descrizione dell'immagine

Quindi il puntatore della memoria inizia sull'input etichettato edge , puntando verso nord. ,legge un byte da STDIN o un -1se abbiamo colpito EOF in quel bordo. Quindi, il <dopo è una condizione per aver letto tutti gli input. Rimaniamo nel circuito di input per ora. Il prossimo codice che eseguiamo è

{&32'-

Questo scrive un 32 nello spazio etichettato sul bordo e quindi lo sottrae dal valore di input nel diff etichettato sul bordo . Nota che questo non può mai essere negativo perché siamo certi che l'input contiene solo ASCII stampabile. Sarà zero quando l'ingresso era uno spazio. (Come sottolinea Timwi, funzionerebbe comunque se l'input potesse contenere avanzamenti di riga o schede, ma eliminerebbe anche tutti gli altri caratteri non stampabili con codici di caratteri inferiori a 32.) In tal caso, il <puntatore dell'istruzione (IP) viene lasciato verso sinistra e viene preso il percorso grigio chiaro. Quel percorso reimposta semplicemente la posizione del MP con {=e quindi legge il carattere successivo, quindi gli spazi vengono saltati. Altrimenti, se il personaggio non era uno spazio, eseguiamo

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

Questo prima si sposta attorno all'esagono attraverso il bordo della lunghezza fino a quando non è opposto al bordo del diff , con =}}}. Poi copia il valore dal fronte alla lunghezza spigolo nella lunghezza bordo, e l'incrementa con )&'+'+). Vedremo tra un secondo perché questo ha senso. Infine, spostiamo un nuovo vantaggio con =}:

inserisci qui la descrizione dell'immagine

(I valori dei bordi particolari sono tratti dall'ultimo caso di test fornito nella sfida.) A questo punto, il ciclo si ripete, ma con tutto spostato di un esagono a nord-est. Quindi dopo aver letto un altro personaggio, otteniamo questo:

inserisci qui la descrizione dell'immagine

Ora puoi vedere che stiamo gradualmente scrivendo l'input (meno spazi) lungo la diagonale nord-est, con i caratteri su ogni altro bordo e la lunghezza fino a quel carattere che viene memorizzata parallelamente alla lunghezza etichettata del bordo .

Quando avremo finito con il loop di input, la memoria sarà simile a questa (dove ho già etichettato alcuni nuovi bordi per la parte successiva):

inserisci qui la descrizione dell'immagine

L' %è l'ultimo carattere si legge, il 29è il numero di caratteri non-spazio che leggiamo. Ora vogliamo trovare la lunghezza laterale dell'esagono. Innanzitutto, esiste un codice di inizializzazione lineare nel percorso verde scuro / grigio:

=&''3{

Qui, =&copia la lunghezza (29 nel nostro esempio) nella lunghezza con etichetta del bordo . Quindi si ''3sposta sul bordo etichettato 3 e ne imposta il valore 3(di cui abbiamo solo bisogno come costante nel calcolo). Alla fine si {sposta sul bordo etichettato N (N-1) .

Ora entriamo nel ciclo blu. Questo ciclo incrementa N(memorizzato nella cella etichettata N ) quindi calcola il suo numero esagonale centrato e lo sottrae dalla lunghezza di input. Il codice lineare che lo fa è:

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

Qui, {)si sposta e incrementi N . ')&(si sposta sul bordo etichettato N-1 , copia Nlì e lo decrementa. {=*calcola il loro prodotto in N (N-1) . '*)moltiplica quello per la costante 3e incrementa il risultato nell'esagono etichettato con il bordo (N) . Come previsto, questo è l'ennesimo numero esagonale centrato. '-Calcola infine la differenza tra quella e la lunghezza dell'input. Se il risultato è positivo, la lunghezza del lato non è ancora abbastanza grande e il loop si ripete (dove }}sposta la MP di nuovo sul bordo etichettato N (N-1) ).

Una volta che la lunghezza del lato è abbastanza grande, la differenza sarà zero o negativa e otteniamo questo:

inserisci qui la descrizione dell'immagine

Prima di tutto, ora esiste il percorso verde lineare molto lungo che esegue l'inizializzazione necessaria per il circuito di uscita:

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

Le {=&inizia copiando il risultato nel diff bordo nella lunghezza di bordo, perché abbiamo seguito c'è bisogno di qualcosa di non positivo. }}}32scrive un 32 nello spazio contrassegnato dal bordo . '"2scrive una costante 2 nel bordo senza etichetta sopra diff . '=&copia N-1nel secondo bordo con la stessa etichetta. '*)lo moltiplica per 2 e lo incrementa in modo da ottenere il valore corretto nel bordo etichettato 2N-1 in alto. Questo è il diametro dell'esagono. {=&')&copia il diametro nell'altro bordo etichettato 2N-1 . Infine, }}torna al bordo etichettato 2N-1 in alto.

Etichettiamo nuovamente i bordi:

inserisci qui la descrizione dell'immagine

Il bordo su cui ci troviamo attualmente (che contiene ancora il diametro dell'esagono) verrà utilizzato per scorrere le linee dell'output. Il rientro contrassegnato dal bordo calcolerà quanti spazi sono necessari sulla linea corrente. Le celle con etichetta sul bordo verranno utilizzate per scorrere il numero di celle nella riga corrente.

Ora siamo sulla strada rosa che calcola il rientro . ('-decrementa l' iteratore di linee e lo sottrae da N-1 (nel bordo del rientro ). Il breve ramo blu / grigio nel codice calcola semplicemente il modulo del risultato ( ~nega il valore se è negativo o zero e nulla accade se è positivo). Il resto del percorso rosa è quello "-~{che sottrae il rientro dal diametro al bordo delle celle e quindi si sposta indietro al bordo del rientro .

Il sentiero giallo sporco ora stampa il rientro. I contenuti del loop sono davvero giusti

'";{}(

Dove si '"sposta sul bordo dello spazio , lo ;stampa, {}torna al rientro e lo (diminuisce.

Quando abbiamo finito, il (secondo) percorso grigio scuro cerca il personaggio successivo da stampare. Si =}sposta in posizione (il che significa, sul bordo delle celle , rivolto a sud). Quindi abbiamo un ciclo molto stretto di {}cui si sposta semplicemente verso il basso di due bordi nella direzione sud-ovest, fino a quando non colpiamo la fine della stringa memorizzata:

inserisci qui la descrizione dell'immagine

Notate che ho rietichettato un vantaggio lì EOF? . Una volta che abbiamo elaborato questo personaggio, renderemo quel bordo negativo, in modo che il {}ciclo finisca qui invece della successiva iterazione:

inserisci qui la descrizione dell'immagine

Nel codice, siamo alla fine del percorso grigio scuro, dove si 'sposta indietro di un passo sul carattere di input. Se la situazione è uno degli ultimi due diagrammi (ovvero c'è ancora un carattere dall'input che non abbiamo ancora stampato), allora stiamo prendendo il percorso verde (quello in basso, per le persone che non sono brave con il verde e blu). Quello è abbastanza semplice: ;stampa il personaggio stesso. 'si sposta sul bordo dello spazio corrispondente che contiene ancora un 32 di prima e ;stampa quello spazio. Quindi {~rende il nostro EOF? negativo per la successiva iterazione, 'sposta un passo indietro in modo da poter tornare all'estremità nord-occidentale della stringa con un altro }{loop stretto . Che termina sulla lunghezzacella (quella non positiva al di sotto dell'esagono (N) . Infine, }torna indietro al bordo delle celle .

Se abbiamo già esaurito l'input, allora il loop che cerca EOF? terminerà effettivamente qui:

inserisci qui la descrizione dell'immagine

In tal caso, ci 'spostiamo sulla cella della lunghezza e stiamo invece prendendo il percorso azzurro (in alto), che stampa un no-op. Il codice in questo ramo è lineare:

{*46;{{;{{=

La {*46;scrive un 46 nel bordo etichettato no-op e lo stampa (cioè un periodo). Poi {{;si muove alla spazio bordo e stampe che. I {{=torna al cellule bordi per la successiva iterazione.

A questo punto i percorsi si ricongiungono e (diminuiscono il bordo delle celle . Se l'iteratore non è ancora zero, prenderemo il percorso grigio chiaro, che inverte semplicemente la direzione del MP con =e quindi cerca il personaggio successivo da stampare.

Altrimenti, abbiamo raggiunto la fine della riga corrente e l'IP prenderà invece il percorso viola. Ecco come appare la griglia di memoria a quel punto:

inserisci qui la descrizione dell'immagine

Il percorso viola contiene questo:

=M8;~'"=

Il =inverte la direzione della MP di nuovo. M8imposta il valore su 778(perché il codice carattere di Mis 77e cifre si aggiungeranno al valore corrente). Questo accade 10 (mod 256), quindi quando lo stampiamo con ;, otteniamo un avanzamento di riga. Quindi ~rende nuovamente il bordo negativo, '"torna al bordo delle linee e =inverte di nuovo il MP.

Ora se il bordo delle linee è zero, abbiamo finito. L'IP prenderà il percorso (molto breve) rosso, dove @termina il programma. Altrimenti, continuiamo sul sentiero viola che ritorna a quello rosa, per stampare un'altra linea.


Diagrammi di flusso di controllo creati con HexagonyColorer di Timwi . Diagrammi di memoria creati con il debugger visivo nel suo IDE esoterico .


19
Mi ritrovo a dire molto su risposte esagonali: solo whoa.
Conor O'Brien,

5
Eh ... ma ... wat ... mind = blown
Adnan,

Speravo che qualcuno lo facesse e ... Wow. Sono senza parole. È fantastico
Arcturus,

19
Passo 2: scrivi l'altro 97%. :)
ASCIIThenANSI il

Passaggio tre: come risposta con il minor numero di byte.
Tom M,

19

CJam, 56 52 50 48 byte

Il mio primo pensiero è stato: "Ehi, ho già un codice per questo!" Ma poi non potevo preoccuparmi di mettere insieme i pezzi necessari dal codice Ruby, soprattutto perché non sembravano molto adatti per essere golfati. Quindi ho provato qualcos'altro in CJam invece ...

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

Provalo qui.

Spiegazione

Prima un po 'di matematica sui numeri esagonali centrati. Se l'esagono regolare ha una lunghezza laterale N, conterrà 3N(N-1)+1celle, che devono essere uguali alla lunghezza del codice sorgente k. Possiamo risolverlo Nperché è una semplice equazione quadratica:

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

Possiamo ignorare la radice negativa, perché ciò dà un N. negativo. Per avere una soluzione, è necessario che la radice quadrata sia un numero intero. O in altre parole, √(1 + 4(k-1)/3) = √((4k-1)/3)deve essere un numero intero (per fortuna, questo numero intero sembra essere il diametro D = 2N-1dell'esagono, di cui avremo comunque bisogno). Quindi possiamo aggiungere ripetutamente un singolo .fino a quando tale condizione non viene soddisfatta.

Il resto è un semplice anello che stabilisce l'esagono. Un'osservazione utile per questa parte è che gli spazi nell'indentazione più i non spazi nel codice in ciascuna riga si sommano al diametro.

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

Si scopre che non è necessario usare la doppia aritmetica (tranne per la radice quadrata). A causa della moltiplicazione per 4, non ci sono collisioni quando si divide per 3 e il desiderato ksarà il primo a produrre una radice quadrata intera.


8

Perl, 203 200 198

include + 1 per -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

correre come: echo abc | perl -p file.pl

Un approccio molto ingenuo:

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

  • l'aggiornamento 200 salva un byte spostando l'assegnazione variabile e altri 2 omettendo final ;; codice stesso sotto 200 byte ora!
  • l'aggiornamento 198 salva 2 byte usando $s=~/\S+/ginvece displit/\n/,$s

7

JavaScript (ES6), 162 172

Funzione anonima

La dimensione dell'esagono si trova risolvendo l'equazione da Wikipedia

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

La formula di risoluzione è fondamentalmente

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

Con un po 'di algebra e un po' di approssimazione (grazie anche a @ user18655) diventa

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

Più leggibile

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
}

Snippet di prova (migliore pagina intera - tempo di esecuzione ~ 1 minuto)

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>


1
È possibile utilizzare n=...+1-1e-9|0invece di n=Math.ceil(...)salvare 2 byte. Potresti anche usare ES7 e utilizzarlo al **0.5posto di Math.sqrtma dipende da te. Di solito mantengo le mie risposte ES6 perché funzionano nel mio browser haha!
user81655

@ user81655 buon suggerimento, grazie
edc65

5

Pyth, 52 51 byte

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

Provalo online. Suite di test.

Ogni riga ha uno spazio iniziale aggiuntivo, come consentito dall'OP.

Spiegazione

 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

5

Retina , 161 byte

Grazie a FryAmTheEggman per aver salvato 2 byte.

Questa risposta è non competitiva. Retina ha visto alcuni aggiornamenti da questa sfida e sono abbastanza sicuro che sto usando alcune delle funzionalità più recenti (anche se non ho controllato).

Il conteggio dei byte presuppone la codifica ISO 8859-1. La prima riga contiene un singolo spazio. Si noti che la maggior parte di questi ·sono in realtà punti centrali (0xB7).

 

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

Provalo online!

Bene...

Spiegazione

Sembra più semplice creare prima il layout usando solo un singolo carattere ( ·in questo caso) e quindi riempire il layout risultante con i caratteri di input. Le ragioni principali di ciò sono che l'uso di un singolo carattere mi consente di utilizzare riferimenti secondari e ripetizione di caratteri, in cui la disposizione diretta dell'input richiederebbe costosi gruppi di bilanciamento.

 

Sebbene non sembri molto, questa prima fase rimuove gli spazi dall'input.

^
$._$*·¶

Iniziamo anteponendo una linea aggiuntiva che contiene Mpunti centrali, dove si Mtrova la lunghezza dell'input (dopo aver rimosso gli spazi).

^·¶
¶

Se l'input era un singolo carattere, rimuoviamo di nuovo quel punto centrale. Questo è uno sfortunato caso speciale che non sarà coperto dalla fase successiva.

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

Questo calcola la lunghezza del lato richiesta Nmeno 1. Ecco come funziona: i numeri esagonali centrati sono della forma 3*N*(N-1) + 1. Poiché i numeri triangolari lo sono N*(N-1)/2, ciò significa che i numeri esagonali sono sei volte un numero triangolare più 1. È utile perché abbinare i numeri triangolari (che sono davvero solo 1 + 2 + 3 + ... + N) in una regex è abbastanza facile con i riferimenti in avanti. L' (^·|\2·)*corrisponde al maggior numero triangolare che può. Come un bel bonus, $2manterrà quindi l'indice di questo numero triangolare. Per moltiplicarlo per 6, lo catturiamo in gruppo 1e lo abbiniamo altre 5 volte. Ci assicuriamo che ce ne siano almeno altri due ·con il ·e il·+. In questo modo l'indice del numero triangolare trovato non aumenta finché non c'è un carattere in più di un numero esagonale centrato.

Alla fine, questa partita ci dà due meno della lunghezza laterale dell'esagono richiesto in gruppo $2, quindi scriviamo di nuovo insieme con un altro punto centrale per ottenere N-1.

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

Questo trasforma la nostra serie di N-1punti centrali in N-1spazi, 2N-1punti centrali e altri N-1spazi. Si noti che questa è la massima rientranza, seguita dal diametro dell'esagono, seguita nuovamente dalla rientranza.

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

Questo è spiacevolmente lungo, ma fondamentalmente ci dà solo tutte le partite sovrapposte , che sono o a) 2N-1caratteri lunghi e sulla prima riga oppure b) sulla seconda riga. Questo espande il risultato della fase precedente nell'esagono completo, ma stranamente rientrato. Ad esempio per l'input 12345678avremmo:

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

Questo è il motivo per cui dovevamo aggiungere spazi anche nella fase precedente.

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

Questo risolve il rientro delle linee dopo il centro, indentando ripetutamente qualsiasi linea più corta della precedente (ignorando gli spazi finali), quindi otteniamo questo:

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

Ora inseriamo solo degli spazi con

·
 ·

Che ci dà:

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

Accidenti, è fatto.

O$`(·)|\S
$1

Tempo di riempire la stringa di input nei punti centrali. Questo viene fatto con l'aiuto di una fase di smistamento. Abbiniamo tutti i punti centrali e ogni carattere sull'ultima riga e li ordiniamo in base al risultato della sostituzione data. Tale sostituzione è vuota per i caratteri sull'ultima riga e ·per i punti centrali, quindi ciò che accade è che i punti centrali sono semplicemente ordinati fino alla fine (poiché l'ordinamento è stabile). Questo sposta i caratteri di input in posizione:

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

Sono rimaste solo due cose:

·
.

Questo trasforma i punti centrali in periodi regolari.

G-2`

E questo scarta l'ultima riga.


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`

Dove \nrappresenta il carattere letterale di newline. Utilizza una tecnica per creare un esagono che ho usato in precedenza su diverse altre risposte a . Per ES7 l'assunzione di radici quadrate risulta leggermente più breve dell'approccio ricorsivo:

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

1

Python 3 , 144 byte

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

Provalo online!

Questo utilizza una quantità piuttosto variabile di spazi bianchi iniziali per esagoni di dimensioni diverse, ma la forma generale sopravvive.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.