Introdução
Se você não conhece o Hexagony , é uma linguagem esotérica criada por Martin Büttner. O fato é que esse idioma aceita vários formulários para o programa. Os seguintes programas são todos equivalentes:
abcdefg
e
a b
c d e
f g
Então, basicamente, o código foi acumulado em um hexágono regular. Mas observe que a adição de um novo comando ao código abcdefgh
resultaria no seguinte programa:
a b c
d e f g
h . . . .
. . . .
. . .
Como você pode ver, o primeiro passo é acumular o código em um hexágono e, depois disso, o hexágono é preenchido com no-ops ( .
) para o próximo número hexagonal centralizado .
Sua tarefa é simples, quando uma string (o código fonte) recebe um código fonte hexagonal completo.
As regras
- Você pode fornecer um programa ou uma função.
- Espaços em branco à esquerda são permitidos, mas somente quando o hexágono não sai de forma
- Espaço em branco à direita é permitido.
- Observe que os espaços em branco no programa são ignorados . Então
a b c
é igual aabc
- Somente os caracteres ASCII imprimíveis (
32 - 126
) são usados, portanto, apenas oSpace
caractere regular é ignorado. - Suponha que o comprimento da string seja maior que 0.
- Isso é código-golfe , então a submissão com a menor quantidade de bytes ganha!
Casos de teste
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:
. ? ' .
) . @ @ /
' / . ! . >
+ = ( < . ! )
} ( $ > ( <
% . . . .
. . . .
abc`defg
, na verdade, ele se tornaria pastebin.com/ZrdJmHiR`
caracteres)".Respostas:
Pyth,
575450494846Suíte de teste
Imprime um espaço à esquerda em cada linha.
Esta versão requer uma prova de que 10 ^ n> = 3n (n - 1) + 1 para todos os n> = 1 . Agradecemos a ANerdI e ErickWong por fornecer provas.
Seguindo essas desigualdades: 10 ^ n> (1 + 3) ^ n = 1 + 3n + 9n (n - 1) + ...> 3n (n - 1) + 1 pode-se ver facilmente que isso está correto para n> = 2 . Examinar o caso n = 1 é bastante trivial, fornecendo 10> 1 .
Como alternativa, pegar as derivadas dessas equações duas vezes mostra que 10 ^ n tem uma segunda derivada maior para todos n> = 1 , que pode ser cascateada até as primeiras derivadas e, finalmente, às equações originais.
Explicação
fonte
Hexagonia , 271 bytes
Apresento a vocês os primeiros 3% de um auto-intérprete da Hexagony ...
Experimente online! Você também pode executá-lo por si só, mas isso levará cerca de 5 a 10 segundos.
Em princípio, isso pode caber no comprimento lateral 9 (para uma pontuação de 217 ou menos), porque ele usa apenas 201 comandos, e a versão desolfada que escrevi primeiro (no comprimento lateral 30) precisava de apenas 178 comandos. No entanto, tenho certeza de que levaria uma eternidade para realmente fazer tudo encaixar, então não tenho certeza se vou realmente tentar.
Também deve ser possível jogar um pouco no tamanho 10, evitando o uso das últimas uma ou duas linhas, de modo que os no-ops finais possam ser omitidos, mas isso exigiria uma reescrita substancial, como um dos primeiros caminhos junta faz uso do canto inferior esquerdo.
Explicação
Vamos começar desdobrando o código e anotando os caminhos do fluxo de controle:
Isso ainda é bastante confuso, então aqui está o mesmo diagrama para o código "não-destruído" que eu escrevi primeiro (na verdade, esse é o comprimento do lado 20 e originalmente eu escrevi o código no comprimento do lado 30, mas era tão escasso que não para melhorar a legibilidade, então eu a compactuei um pouco para tornar o tamanho um pouco mais razoável):
Clique para uma versão maior.
As cores são exatamente as mesmas, com exceção de alguns detalhes muito menores, os comandos sem fluxo de controle também são exatamente os mesmos. Então, eu vou explicar como isso funciona com base na versão sem golfinhos, e se você realmente quiser saber como funciona a versão com golfe, poderá verificar quais partes correspondem a qual no hexágono maior. (O único problema é que o código golfado começa com um espelho, para que o código real comece no canto direito, à esquerda.)
O algoritmo básico é quase idêntico à minha resposta CJam . Existem duas diferenças:
.
se tiver.Isso significa que a ideia básica se resume a:
N
(e o número hexagonal centralizado correspondentehex(N)
) que pode conter toda a entrada.2N-1
.2N-1
). Imprima o recuo, imprima as células (usando.
se a entrada já estiver esgotada), imprima um avanço de linha.Observe que existem apenas no-ops; portanto, o código real começa no canto esquerdo (o
$
, que pula sobre o>
, de modo que realmente começamos no,
caminho no cinza escuro).Aqui está a grade de memória inicial:
Portanto, o ponteiro da memória começa na entrada rotulada pela borda , apontando para o norte.
,
lê um byte de STDIN ou a-1
se tivermos atingido o EOF nessa borda. Portanto, o<
seguinte é uma condição para saber se lemos toda a entrada. Vamos permanecer no loop de entrada por enquanto. O próximo código que executamos éIsso grava um 32 no espaço rotulado pela borda e subtrai-o do valor de entrada no diff rotulado pela borda . Observe que isso nunca pode ser negativo, porque garantimos que a entrada contém apenas ASCII imprimível. Será zero quando a entrada for um espaço. (Como Timwi aponta, isso ainda funcionaria se a entrada pudesse conter linhas ou tabulações, mas também removeria todos os outros caracteres não imprimíveis com códigos de caracteres menores que 32.) Nesse caso, ele
<
desvia o ponteiro de instrução (IP) restante e o caminho cinza claro é seguido. Esse caminho simplesmente redefine a posição do MP{=
e depois lê o próximo caractere - assim, os espaços são ignorados. Caso contrário, se o personagem não fosse um espaço, executamosIsso primeiro se move ao redor do hexágono pela borda do comprimento até seu lado oposto à borda do diferencial , com
=}}}
. Em seguida, ele copia o valor da frente do comprimento de aresta para o comprimento do bordo, e incrementa com)&'+'+)
. Veremos em um segundo por que isso faz sentido. Por fim, movemos a nova borda com=}
:(Os valores das arestas particulares são do último caso de teste apresentado no desafio.) Nesse ponto, o loop se repete, mas com tudo mudou um hexágono para nordeste. Então, depois de ler outro personagem, temos o seguinte:
Agora você pode ver que estamos escrevendo gradualmente a entrada (menos espaços) ao longo da diagonal nordeste, com os caracteres em todas as outras arestas, e o comprimento até esse caractere sendo armazenado paralelamente ao comprimento rotulado pela borda .
Quando terminarmos o loop de entrada, a memória ficará assim (onde eu já identifiquei algumas novas arestas para a próxima parte):
O
%
é o último caractere que lemos,29
é o número de caracteres não espaciais que lemos. Agora queremos encontrar o comprimento lateral do hexágono. Primeiro, há algum código de inicialização linear no caminho verde / cinza escuro:Aqui,
=&
copia o comprimento (29 no nosso exemplo) para o comprimento rotulado da borda . Em seguida,''3
move-se para a aresta rotulada 3 e define seu valor como3
(o que precisamos apenas como uma constante no cálculo). Finalmente,{
move-se para a aresta rotulada N (N-1) .Agora entramos no loop azul. Esse loop é incrementado
N
(armazenado na célula N ) e calcula seu número hexagonal centralizado e subtrai-o do comprimento da entrada. O código linear que faz isso é:Aqui,
{)
move-se para e incrementa N .')&(
move-se para a borda N-1 , copiaN
lá e diminui-o.{=*
calcula seu produto em N (N-1) .'*)
multiplica isso pela constante3
e incrementa o resultado na aresta rotulada hex (N) . Como esperado, este é o número hexagonal centésimo enésimo. Finalmente'-
calcula a diferença entre isso e o comprimento da entrada. Se o resultado for positivo, o comprimento lateral ainda não é grande o suficiente e o loop será repetido (onde}}
mova o MP de volta para a borda rotulada N (N-1) ).Quando o comprimento lateral for grande o suficiente, a diferença será zero ou negativa e obtemos o seguinte:
Primeiro, agora existe o caminho verde linear realmente longo, que faz alguma inicialização necessária para o loop de saída:
Os
{=&
começa por copiar o resultado do diff borda no comprimento de ponta, porque depois precisa de algo não-positivo lá.}}}32
grava um 32 no espaço rotulado da borda .'"2
escreve uma constante 2 na aresta não identificada acima de diff .'=&
copiaN-1
para a segunda borda com a mesma etiqueta.'*)
multiplica por 2 e incrementa para obter o valor correto na aresta 2N-1 na parte superior. Este é o diâmetro do hexágono.{=&')&
copia o diâmetro para a outra borda rotulada 2N-1 . Finalmente,}}
volta para a borda 2N-1 na parte superior.Vamos rotular novamente as arestas:
A borda em que estamos atualmente (que ainda mantém o diâmetro do hexágono) será usada para iterar sobre as linhas da saída. O recuo rotulado da borda calculará quantos espaços são necessários na linha atual. As células rotuladas de borda serão usadas para iterar sobre o número de células na linha atual.
Agora estamos no caminho rosa que calcula o recuo .
('-
diminui o iterador de linhas e o subtrai de N-1 (para a borda de recuo ). O pequeno ramo azul / cinza no código simplesmente calcula o módulo do resultado (~
nega o valor se for negativo ou zero e nada acontece se for positivo). O restante do caminho rosa é o"-~{
que subtrai o recuo do diâmetro para a borda das células e depois volta para a borda do recuo .O caminho amarelo sujo agora imprime o recuo. O conteúdo do loop é realmente apenas
Onde se
'"
move para a borda do espaço ,;
imprime,{}
volta para recuo e(
diminui.Quando terminamos, o (segundo) caminho cinza escuro procura o próximo caractere a ser impresso. Os
=}
movimentos na posição (o que significa, na borda da célula , apontando para o sul). Então temos um loop muito apertado,{}
que simplesmente desce duas arestas na direção sudoeste, até atingirmos o final da string armazenada:Percebe que eu rotulei uma borda para lá EOF? . Depois de processarmos esse caractere, tornaremos a borda negativa, para que o
{}
loop termine aqui em vez da próxima iteração:No código, estamos no final do caminho cinza escuro, onde
'
retrocede um passo no caractere de entrada. Se a situação for um dos dois últimos diagramas (ou seja, ainda houver um caractere da entrada que ainda não imprimimos), seguiremos o caminho verde (o inferior, para pessoas que não são boas com verde e azul). Essa é bastante simples:;
imprime o próprio personagem.'
move-se para a borda do espaço correspondente que ainda retém 32 e;
imprime esse espaço. Então{~
faz o nosso EOF? negativo para a próxima iteração,'
recua um passo para que possamos retornar ao extremo noroeste da sequência com outro}{
loop apertado . Que termina no comprimento(a não positiva abaixo de hex (N) . Finalmente,}
retorna à borda da célula .Se já esgotamos a entrada, o loop que procura por EOF? realmente terminará aqui:
Nesse caso,
'
move-se para a célula de comprimento e seguimos o caminho azul claro (superior), que imprime um não-op. O código neste ramo é linear:Ele
{*46;
grava um 46 na borda rotulada como não operacional e o imprime (isto é, um ponto). Depois,{{;
move-se para a borda do espaço e imprime isso. A{{=
volta para a borda da célula para a próxima iteração.Nesse ponto, os caminhos se juntam novamente e
(
diminuem a borda das células . Se o iterador ainda não for zero, seguiremos o caminho cinza claro, que simplesmente inverte a direção do MP=
e depois procura o próximo caractere a ser impresso.Caso contrário, chegamos ao final da linha atual e o IP seguirá o caminho roxo. É assim que a grade de memória se parece nesse ponto:
O caminho roxo contém o seguinte:
O
=
inverte a direção do MP novamente.M8
define o valor definido como778
(porque o código de caractere deM
é77
e dígitos serão anexados ao valor atual). Isso acontece10 (mod 256)
, então, quando o imprimimos;
, obtemos um avanço de linha. Em seguida,~
torna a aresta negativa novamente,'"
volta para a aresta das linhas e=
reverte o MP mais uma vez.Agora, se a borda das linhas é zero, terminamos. O IP seguirá o caminho vermelho (muito curto), onde
@
finaliza o programa. Caso contrário, continuamos no caminho púrpura, que volta ao rosa, para imprimir outra linha.Diagramas de fluxo de controle criados com o HexagonyColorer da Timwi . Diagramas de memória criados com o depurador visual em seu IDE esotérico .
fonte
CJam,
56525048 bytesMeu primeiro pensamento foi: "ei, eu já tenho código para isso!" Mas não me incomodei em juntar as peças necessárias do código Ruby, principalmente porque elas não pareciam muito adequadas para jogar golfe. Então tentei outra coisa no CJam ...
Teste aqui.
Explicação
Um pouco de matemática sobre números hexagonais centralizados primeiro. Se o hexágono regular tiver comprimento lateral
N
, ele conterá3N(N-1)+1
células, que devem ser iguais ao comprimento do código-fontek
. Podemos resolver issoN
porque é uma equação quadrática simples:Podemos ignorar a raiz negativa, porque isso dá um N. negativo. Para que isso tenha uma solução, precisamos que a raiz quadrada seja um meio inteiro. Ou, em outras palavras,
√(1 + 4(k-1)/3) = √((4k-1)/3)
precisa ser um número inteiro (felizmente, esse número inteiro é o diâmetroD = 2N-1
do hexágono, que será necessário de qualquer maneira). Portanto, podemos adicionar repetidamente um único.
até que essa condição seja atendida.O resto é um loop simples que define o hexágono. Uma observação útil para esta parte é que os espaços no recuo mais os não espaços no código em cada linha somam o diâmetro.
Acontece que não precisamos usar aritmética dupla (exceto a raiz quadrada). Devido à multiplicação por 4, não há colisões ao dividir por 3, e o desejado
k
será o primeiro a produzir uma raiz quadrada inteira.fonte
Perl,
203200198inclui + 1 para
-p
correr como:
echo abc | perl -p file.pl
Uma abordagem muito ingênua:
;
; codifique-se com menos de 200 bytes agora!$s=~/\S+/g
vez desplit/\n/,$s
fonte
JavaScript (ES6), 162
172Função anônima
O tamanho do hexágono é encontrado resolvendo a equação da wikipedia
A fórmula de solução é basicamente
Com alguma álgebra e alguma aproximação (thx para @ user18655 também), torna-se
Mais legível
Snippet de teste (melhor página inteira - tempo de execução ~ 1 minuto)
fonte
n=...+1-1e-9|0
vez den=Math.ceil(...)
salvar 2 bytes. Você também pode ir ES7 e usar**0.5
em vez deMath.sqrt
, mas isso é até você. Normalmente eu apenas mantenho minhas respostas ES6 porque elas funcionam no meu navegador haha!Pitão,
5251 bytesExperimente online. Suíte de teste.
Cada linha possui um espaço inicial extra, conforme permitido pelo OP.
Explicação
fonte
Retina , 161 bytes
Agradecemos a FryAmTheEggman por salvar 2 bytes.
Esta resposta não é competitiva. O Retina recebeu algumas atualizações desde esse desafio e tenho certeza de que estou usando alguns dos recursos mais recentes (embora ainda não tenha verificado).
A contagem de bytes assume a codificação ISO 8859-1. A primeira linha contém um único espaço. Observe que a maioria dos
·
pontos são na verdade pontos centrais (0xB7).Experimente online!
Bem...
Explicação
Parece mais fácil criar o layout primeiro usando apenas um único caractere (
·
nesse caso) e, em seguida, preencher o layout resultante com os caracteres de entrada. As principais razões para isso são que o uso de um único caractere permite que eu use referências anteriores e repetição de caracteres, onde o layout da entrada diretamente exigiria grupos de balanceamento caros.Embora não pareça muito, esse primeiro estágio remove espaços da entrada.
Começamos anexando uma linha adicional que contém
M
pontos centrais, ondeM
é o comprimento da entrada (após remover os espaços).Se a entrada tiver um único caractere, removeremos esse ponto central novamente. Este é um caso especial infeliz que não é coberto pela próxima etapa.
Isso calcula o comprimento lateral necessário
N
menos 1. Aqui está como isso funciona: os números hexagonais centralizados têm a forma3*N*(N-1) + 1
. Como os números triangulares sãoN*(N-1)/2
, isso significa que os números hexagonais são seis vezes um número triangular mais 1. Isso é conveniente porque combinar números triangulares (que na verdade são justos1 + 2 + 3 + ... + N
) em uma regex é bastante fácil com referências a frente. A(^·|\2·)*
corresponde ao maior número triangular que pode. Como um bom bônus,$2
manterá o índice desse número triangular. Para multiplicá-lo por 6, capturamos em grupo1
e combinamos mais 5 vezes. Garantimos que há pelo menos mais dois·
com·
os·+
. Dessa forma, o índice do número triangular encontrado não aumenta até que exista um caractere a mais que um número hexagonal centralizado.No final, essa partida nos dá dois a menos do que o comprimento lateral do hexágono necessário no grupo
$2
, então escrevemos isso de volta junto com mais um ponto central a ser obtidoN-1
.Isso transforma nossa série de
N-1
pontos centrais emN-1
espaços,2N-1
pontos centrais e outrosN-1
espaços. Observe que esse é o recuo máximo, seguido pelo diâmetro do hexágono, seguido pelo recuo novamente.Isso é desagradávelmente longo, mas basicamente nos fornece todas as correspondências sobrepostas , que são: a)
2N-1
caracteres longos e na primeira linha ou b) na segunda linha. Isso expande o resultado do estágio anterior para o hexágono completo, mas estranhamente recuado. Por exemplo, para entrada12345678
, obteríamos:É por isso que também precisamos acrescentar espaços no estágio anterior.
Isso corrige o recuo das linhas após o centro, recuando repetidamente qualquer linha que seja mais curta que a anterior (ignorando os espaços finais), para obtermos o seguinte:
Agora apenas inserimos alguns espaços com
O que nos dá:
Ufa, está feito.
Hora de preencher a sequência de entrada nos pontos centrais. Isso é feito com a ajuda de um estágio de classificação. Combinamos todos os pontos centrais e cada caractere na última linha e os ordenamos pelo resultado da substituição fornecida. Essa substituição está vazia para os caracteres na última linha e
·
para os pontos centrais, então o que acontece é que os pontos centrais são simplesmente classificados até o fim (já que a classificação é estável). Isso move os caracteres de entrada no lugar:Restam apenas duas coisas:
Isso transforma pontos centrais em períodos regulares.
E isso descarta a última linha.
fonte
JavaScript (ES6), 144 bytes
Onde
\n
representa o caractere literal de nova linha. Usa uma técnica para criar um hexágono que eu já usei em várias outras respostas da grade hexagonal . Para o ES7, a obtenção de raízes quadradas é um pouco menor que a abordagem recursiva:fonte
Python 3 , 144 bytes
Experimente online!
Isso usa uma quantidade bastante variável de espaço em branco à esquerda para hexágonos de tamanhos diferentes, mas a forma geral sobrevive.
fonte