Tejido de juntas: dibuja un nudo Sierpiński


33

Dado un número entero N> = 2, produce una imagen que muestra un nudo Sierpiński de grado N.

Por ejemplo, aquí hay nudos de grado 2, 3, 4 y 5:

Grado 2 Grado 3 Grado 4 Grado 5

Haga clic en las imágenes para verlas a tamaño completo (cuanto mayor sea el grado, mayor será la imagen).

Especificación

  1. Se dibuja un nudo Sierpiński de grado N utilizando los vértices de un triángulo Sierpiński de grado N como puntos de guía. Un triángulo de Sierpiński de grado N son tres triángulos de Sierpiński de grado N-1 dispuestos en un triángulo más grande. Un triángulo de Sierpiński de grado 0 es un triángulo equilátero.
  2. Los triángulos componentes más pequeños tienen una longitud lateral de 64, dando al triángulo de Sierpiński en el que se basa el nudo una longitud lateral total de 64 * 2 ^ N
  3. El centro del triángulo exterior se coloca en el centro de la imagen. Esto no da el mismo espacio en blanco en la parte superior e inferior.
  4. La salida es una imagen cuadrada de longitud lateral techo (64 * 2 ^ N * 2 / ROOT3)donde techo (x)es ceiling(x), el entero más pequeño mayor o igual a x. Esto es lo suficientemente grande como para que el vértice superior del triángulo de Sierpiński subyacente esté contenido dentro de la imagen cuando el centro del triángulo está en el centro de la imagen.
  5. La curva única debe pasar sobre y debajo de sí misma, estrictamente alternando. Las soluciones pueden elegir entre debajo, luego encima o más de debajo.
  6. Las imágenes de ejemplo muestran primer plano negro y fondo blanco. Puede elegir cualquiera de los dos colores fácilmente distinguibles. El suavizado está permitido pero no es necesario.
  7. No debe haber huecos donde dos arcos se encuentran o donde la curva pasa sobre o debajo de sí misma.
  8. La salida puede ser a cualquier archivo de imagen de formato ráster o a cualquier archivo de imagen de formato vectorial que incluya un tamaño de visualización predeterminado correcto. Si visualiza directamente en la pantalla, esto debe estar en una forma que permita el desplazamiento para ver la imagen completa cuando sea más grande que la pantalla.

Determinación del centro del arco, radio y grosor

  1. El nudo se construye como una serie de arcos circulares que se encuentran en puntos donde sus tangentes son paralelas, para dar una unión perfecta. Estos arcos se muestran como sectores anulares (arcos con grosor).
  2. Los centros de estos arcos son los vértices de los triángulos invertidos más pequeños. Cada uno de esos vértices es el centro de exactamente un arco.
  3. Cada arco tiene un radio de 64 * ROOT3 / 2
  4. La excepción es que los arcos en los tres triángulos más externos (en las esquinas del triángulo grande) tienen un centro que es el punto medio de los dos vértices internos adyacentes, y por lo tanto tienen un radio de 64 * (ROOT3 / 2-1 / 2)
  5. Cada arco se representa con un grosor total (diferencia entre el radio interno y el radio externo) 64 * (ROOT3 / 2) / 4y cada uno de los bordes negros tiene un grosor. 64 * (ROOT3 / 2) / 16La curva debe tener estos bordes, y no solo una tira sólida.

Unidades de medida

  1. Todas las distancias están en píxeles (1 es la distancia horizontal o vertical entre 2 píxeles adyacentes).
  2. La raíz cuadrada de 3 debe ser precisa para 7 cifras significativas. Es decir, sus cálculos deben ser equivalentes a usar un ROOT3 tal que1.7320505 <= ROOT3 < 1.7320515

Tanteo

El código más corto en bytes gana.


Para aquellos que se preguntan, N = 0 y N = 1 no están incluidos porque corresponden a un círculo y un trébol, que no coinciden con el patrón que se aplica para N> = 2. Esperaría que la mayoría de los enfoques para este desafío tendrían que agregar un código de caso especial para 0 y 1, por lo que decidí omitirlos.


1
¿Sería útil tener un diagrama que muestre con qué se relacionan todos los números?
Trichoplax

Antes de jugar golf mi respuesta / agregar esquinas, ¿son realmente necesarias 7 cifras significativas para pequeños detalles como el grosor de la línea, etc.? Una precisión como "7 cifras significativas o 1 píxel, la que sea mayor" parece más apropiada.
Level River St

@LevelRiverSt debido a que el tamaño de la imagen se escala con la entrada, incluso 7 cifras significativas son insuficientes para una precisión de 1 píxel para una N. mayor. estándar.
trichoplax

Sí, es necesario para la escala de la imagen para N. mayor 7 cifras significativas en una imagen de 1000000 x 1000000 corresponde a 0,1 píxeles, pero con cálculos intermedios podría ser peor que eso. Solo pienso stroke-width:3.464102y similar es un poco excesivo si la idea era obtener una precisión de 1 píxel. Sin embargo, seguiré adelante y lo incluiré así, si ese es el fallo.
Level River St

Respuestas:


27

Ruby, 1168 932

Se corrigió un error de anoche, más golf para hacer después de aclarar.

Este es (actualmente) un programa completo que acepta un número de stdin y genera un svgarchivo en stdout. Elegí svg porque sabía que era posible cumplir con todos los requisitos de la pregunta, pero tenía algunos problemas. en particular, SVG solo admite arcos de círculos como parte del pathobjeto, y no los define en términos de su centro, sino más bien los dos puntos finales.

Código

n=gets.to_i
r=64*w=0.75**0.5
m=1<<n-2
z=128*m/w
a=(s="<path style='fill:none;stroke:black;stroke-width:3.464102' transform='translate(%f %f)'
")%[0,r-r*m*8/3]+"d='M18.11943,-2A#{b=r-6*w-32} #{b} 0 0,0 #{-b} 0#{k='A%f %f 0 0 '%([58*w]*2)}0 0,38.71692
M28.58980,1.968882#{l='A%f %f 0 0 '%([70*w]*2)}0 #{c=r+6*w-32} 0A#{c} #{c} 0 0,0 #{-c} 0#{l}0 -9 44.65423'/>"
p=2
m.times{|i|(i*2+1).times{|j|(p>>j)%8%3==2&&a<<s%[128*(j-i),r*3+r*i*4-r*m*8/3]+
"d='M-55,44.65423#{k}0 11.5,25.11473#{l}1 35.41020,1.968882
M-64,51.48786#{l}0 20.5,30.31089#{k}1 36.82830,13.17993
M-82.17170,-2.408529#{l}1 -11.5,25.11473#{k}0 0,38.71692
M-81.52984 8.35435#{k}1 -20.5,30.31089#{l}0 -9,44.65423
M9,44.65423#{k}0 81.52984,8.35435
M0,51.48786#{l}0 91.17169,13.17993'/>"}
p^=p*4}
puts "<svg xmlns='http://www.w3.org/2000/svg' viewBox='#{-z} #{-z} #{e=2*z+1} #{e}' width='#{e}px' height='#{e}px'>"+
"<g transform='rotate(%d)'>#{a}</g>"*3%[0,120,240]+"</svg>"

Salida N = 4

reescalado por cambio de pila. Se ve mucho mejor como original.

ingrese la descripción de la imagen aquí Explicación

Al principio consideré algo como http://euler.nmt.edu/~jstarret/sierpinski.html donde el triángulo se divide en tres hebras de diferentes colores, cada una de las cuales forma un camino de una esquina a otra. Los círculos incompletos se muestran como hexágonos incompletos allí. inscribir círculos dentro de los hexágonos muestra que el radio del círculo debe ser sqrt(3)/2multiplicado por la longitud lateral. Los filamentos podrían acumularse recursivamente como se muestra, pero hay una complicación adicional porque las esquinas deben redondearse y es difícil saber en qué dirección curvar, por lo que no utilicé este enfoque.

Lo que hice fue lo siguiente.

En la imagen a continuación puede ver que hay giros horizontales que pertenecen a las unidades N = 2 (en verde) dispuestas en un triángulo sierpinski y giros de puente adicionales (en azul).

Es de conocimiento común que los números impares en el triángulo de Pascal forman un triángulo sierpinski. Se puede obtener un triángulo sierpinski de dígitos binarios de manera análoga comenzando con el número p=1y xorándolo iterativamente conp<<1 .

p=2Modifiqué este enfoque, comenzando en e iterando repetidamente con p*4. Esto da un triángulo sierpinski alternando con columnas de ceros.

Ahora podemos desplazar los derechos p e inspeccionar los últimos tres bits usando %8. Si es 010así, necesitamos dibujar un giro verde que pertenezca a una unidad N = 2. si es 101así, necesitamos dibujar un giro azul y puente. Para probar ambos números juntos, encontramos el módulo %3y si este es 2, necesitamos dibujar el giro.

Finalmente, además de los giros horizontales, hacemos dos copias giradas 120 y 240 grados para dibujar los giros diagonales y completar la imagen. Todo lo que queda es agregar las esquinas.

Código comentado

n=gets.to_i

#r=vertical distance between rows 
r=64*w=0.75**0.5

#m=number of rows of horizontal twists
m=1<<n-2

#z=half the size of the viewport
z=128*m/w

#s=SVG common to all paths
s="<path style='fill:none;stroke:black;stroke-width:3.464102' transform='translate(%f %f)'
"

#initialize a with SVG to draw top corner loop. Set k and l to the SVG common to all arcs of 58*w and 70*w radius 
a=s%[0,r-r*m*8/3]+
"d='M18.11943,-2A#{b=r-6*w-32} #{b} 0 0,0 #{-b} 0#{k='A%f %f 0 0 '%([58*w]*2)}0 0,38.71692
M28.58980,1.968882#{l='A%f %f 0 0 '%([70*w]*2)}0 #{c=r+6*w-32} 0A#{c} #{c} 0 0,0 #{-c} 0#{l}0 -9 44.65423'/>"

#p is the pattern variable, top row of twists has one twist so set to binary 00000010
p=2

#loop vertically and horizontally
m.times{|i|
 (i*2+1).times{|j|

   #leftshift p. if 3 digits inspected are 010 or 101 
   (p>>j)%8%3==2&&

   #append to a, the common parts of a path...
   a<<s%[128*(j-i),r*3+r*i*4-r*m*8/3]+

   #...and the SVG for the front strand and left and right parts of the back strand (each strand has 2 borders)
"d='M-55,44.65423#{k}0 11.5,25.11473#{l}1 35.41020,1.968882
M-64,51.48786#{l}0 20.5,30.31089#{k}1 36.82830,13.17993
M-82.17170,-2.408529#{l}1 -11.5,25.11473#{k}0 0,38.71692
M-81.52984 8.35435#{k}1 -20.5,30.31089#{l}0 -9,44.65423
M9,44.65423#{k}0 81.52984,8.35435
M0,51.48786#{l}0 91.17169,13.17993'/>"}

#modify the pattern by xoring with 4 times itself for the next row
p^=p*4}

#output complete SVG of correct size with three copies of the finished pattern rotated through 0,120,240 degrees.
puts "<svg xmlns='http://www.w3.org/2000/svg' viewBox='#{-z} #{-z} #{e=2*z+1} #{e}' width='#{e}px' height='#{e}px'>"+
"<g transform='rotate(%d)'>#{a}</g>"*3%[0,120,240]+"</svg>"

ingrese la descripción de la imagen aquí


Cuando diga "Se ve mucho mejor como original", podría valer la pena agregar algo como "(haga clic en la imagen para verlo a tamaño completo)" para cualquiera que no se dé cuenta.
trichoplax

@trichoplax no se me ocurrió hacer clic en la imagen. Pero de todos modos, este es un PNG, porque el intercambio de pila no acepta imágenes svg, por lo que los bordes se borran deliberadamente. Mi archivo SVG local tiene bordes mucho más nítidos y se ve mucho mejor.
Level River St

@trichoplax solución rápida en el tamaño de la imagen realizada. Golf más más otro día.
Level River St

1
+1 gran trabajo. Particularmente me gusta la explicación detallada con el diagrama codificado por colores.
Trichoplax

1
El hipervínculo está muerto.
mbomb007
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.