Faça alguma neve!

18

Sua tarefa: gerar um floco de neve Koch até a enésima profundidade. Você não precisa fazer um floco de neve Koch completo, apenas um lado do triângulo inicial. Wikipedia em flocos de Koch: https://en.wikipedia.org/wiki/Koch_snowflake .

Regras:

  • O programa deve gerar um lado do floco de neve Koch até a enésima profundidade.
  • A saída deve ser ASCII.
  • Você pode gerar o floco de neve inteiro; isso não é necessário.
  • Aplicam-se regras padrão para entrada / saída, brechas e outras coisas.
  • Espaço em branco não importa, desde que todos os caracteres estejam no lugar certo em relação um ao outro.
  • O código mais curto vence!

Casos de teste:

n = 0:

__

n = 1:

__/\__

n = 2:

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

n = 3:

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

Espero que isto faça sentido. Observe que em cada caso de teste, o fractal pode ser dividido em três partes iguais em comprimento. Observe também que a largura de cada floco de neve é ​​três vezes a largura da geração anterior do floco de neve.

Camarada SparklePony
fonte
Para sua informação, foi acordado que isso não é um engodo disso .
Camarada SparklePony
Eu não acho que você tenha definido adequadamente qual é a representação ASCII apropriada da enésima curva de Koch.
orlp
Não sei se as proporções fazem sentido. O non-dupe usou __/\__com dois sublinhados, que tornaram cada iteração consistentemente três vezes maior que a anterior. Usar apenas um sublinhado parece dar contradições que começam a ficar realmente estranhas em n = 3. Por exemplo, as partes externas têm largura 12, enquanto a parte do meio tem apenas largura 10, como conseqüência /_e _\ que são muito apertadas. E mesmo antes disso, você tem _expandido para o dobro da largura de /e \ .
Ørjan Johansen
Eu acho que a /_e _\ é a única parte realmente fatal - os sublinhados precisam desaparecer, porque precisam estar na mesma posição que o /e \ . Uma vez feito isso, as coisas podem se expandir por 3 vezes de n = 1 em diante (mas n = 0 não se encaixa.)
Ørjan Johansen
Infelizmente, não, a parte do meio ainda tem largura que não corresponde às partes externas, como evidenciado por n = 3 tendo largura 52 em vez de 54 = 2 * 3 ^ 3. Experimente um destes . Incluí versões de cabeça para baixo, com partes aparecendo apenas de n = 4 ou n = 5 - elas diferem das superiores em que os sublinhados são removidos.
Ørjan Johansen

Respostas:

10

Haskell , 308 300 299 bytes

Editar% s:

  • -4 Bytes: Mudando zipWith(+)para zipWith(-)e ajustando codificações e deslocamentos se livrou de cada sinal de negação.
  • -1 byte: aprimorando ainda mais a codificação permitiu que vários nomes de variáveis #fossem descartados usando em r=reversevez da correspondência direta de padrões.
  • -2 bytes: usando um operador em vez de alfanum para zipWith(-).
  • -1 byte: Definindo o=[0,0]para reduzir as constantes da lista.
  • -1 byte: mesclando dois ramos de ?.
import Data.List
k n=0?sort(o#(f=<<scanl1(+)(iterate(>>=(:[1,4,1]))[6]!!n)))
x?l@(([_,w],c):r)|x>w='\n':0?l|0<1=([2..w-x]>>" ")++[c|w>x]++w?r
_?_=""
w#((c,l):m)=(l&w,c):r l&(l&w)#m
_#_=[]
f x=zip"_/\\_/\\"([id,r]<*>[0:1:o,[0,1,0,1],o++[1,1]])!!mod x 6<$[1,3..gcd 3x]
(&)=zipWith(-)
r=reverse
o=[0,0]

Experimente online! (Infelizmente, qualquer coisa maior que n = 3 fica terrivelmente quebrada e ilegível, mas você pode copiá-lo para outro programa para vê-lo.)

Variações

Como funciona

  • ké a função principal, pega um Int ne retorna a String.
  • iterate(>>=(:[1,4,1]))[6]gera uma lista infinita contendo, para cada n, as voltas entre linhas consecutivas nessa iteração de curva, estilo gráfico de tartaruga, como números nominalmente entre 0e 5. Cada iteração é apenas a anterior com as curvas 1,4,1intercaladas. A única razão pela qual os sublistas começam, em 6vez de, 0é fazer o gcdtruque no ftrabalho, evitando f 0.
  • scanl1(+)converte as curvas em direções "absolutas", até o módulo 6. A 0significa para a direita, então cada número mais alto é de 60 graus no sentido anti-horário do anterior. (Bem, seria 60 graus se esse fosse um desenho adequado, e não ASCII.)
  • f converte uma direção absoluta em uma lista de pares (caractere, codificação de deslocamento) que codifica quais caracteres adicionar à curva (para direções horizontais, gera dois pares, caso contrário um) e como a posição relativa é alterada.
  • O #operador itera pela lista anterior de pares (caractere, codificação de deslocamento), gerando pares reais (coordenada, caractere).
  • Princípios de codificação:
    • Um caractere _/\nominal representa uma linha desenhada de um canto inicial através de uma célula retangular para um canto final diferente.
    • As coordenadas das células são do formato [y,x], de cima para baixo, da esquerda para a direita, para que sejam ordenadas na ordem em que queremos imprimi-las. As colunas são baseadas em 1. As listas são usadas em vez de tuplas para aritmética vetorial mais curta (&)=zipWith(-).
    • Um canto é indicado com as mesmas coordenadas [y,x]que a célula no canto superior esquerdo. Isso garante que todos os deslocamentos de um canto para as células vizinhas não sejam negativos, evitando constantes negativas.
    • No entanto, as coordenadas de canto são negadas para permitir que todas as operações de vetor sejam subtrações em vez de adições, o que evita todos os outros sinais explícitos.
    • Uma lista de codificação de deslocamento é [y1,x1,x2,y2]onde [y1,x1]está o deslocamento de coordenadas do canto inicial para a célula de caracteres e [y2,x2]é o deslocamento do canto final para a célula de caracteres. Isso significa:
      • As listas de codificação para as direções 3.. 5são apenas o inverso das listas para 0.. 2, permitindo que elas sejam geradas com [id,r]<*>.
      • Toda aritmética vetorial necessária pode ser feita usando (&)=zipWith(-)uma lista de codificação ou seu inverso.
  • Após classificar a lista de pares (coordenadas, caracteres), eles são passados ​​para ?, o que gera a final Stringdeles.
    • In x?l@(([_,w],c):r) xé a coordenada x do caractere anterior mostrado nesta linha, ou 0se no início de uma linha; lé a lista atual inteira, wé a coordenada x do próximo caractere a ser adicionado, cé o caractere e ré a lista restante.
    • Nesta fase, as coordenadas y não são mais necessárias. Como cada linha contém caracteres e o primeiro caractere de cada linha fica bem à esquerda do final do anterior, o início de novas linhas é detectado verificando se a coordenada x diminuiu.
    • O sublinhado possui um valor ASCII maior que \e /, portanto, é classificado por último se sobrepor a outro caractere na mesma posição. Assim, um sublinhado redundante é detectado verificando se uma coordenada x foi repetida.
Ørjan Johansen
fonte
Agradável! Aceito isso se não houver mais atividade sobre essa questão hoje.
Camarada SparklePony