Плетение с набивкой - нарисуйте узел Серпинского


33

Если задано целое число N> = 2, создайте изображение, показывающее узел Серпинского с степенью N.

Например, вот узлы степени 2, 3, 4 и 5:

Степень 2 Степень 3 Степень 4 5 степень

Нажмите на изображение для просмотра в полном размере (чем выше степень, тем больше изображение).

Спецификация

  1. Узел Серпинского по степени N рисуется с использованием вершин треугольника Серпинского по степени N в качестве ориентиров. Треугольник Серпинского по степени N - это три треугольника Серпинского по степени N-1, сгруппированных в больший треугольник. Треугольник Серпинского с нулевой степенью является равносторонним треугольником.
  2. Наименьшие составляющие треугольники имеют длину стороны 64, что дает треугольник Серпинского, на котором основан узел, общую длину стороны 64 * 2 ^ N
  3. Центр внешнего треугольника расположен в центре изображения. Это не дает равных пробелов сверху и снизу.
  4. Выход представляет собой квадратное изображение с длиной стороны , потолок (64 * 2 ^ N * 2 / ROOT3)где потолок (х)находится ceiling(x), наименьшее целое число , большее или равное х. Это просто достаточно для размещения верхней вершины нижележащего треугольника Серпинского в изображении, когда центр треугольника находится в центре изображения.
  5. Одна кривая должна проходить над и под собой, строго чередуясь. Решения могут быть выбраны между «ниже» или «над», а затем «под»
  6. Примеры изображений показывают черный передний план и белый фон. Вы можете выбрать любые два легко различимых цвета. Сглаживание разрешено, но не обязательно.
  7. Не должно быть промежутков, где встречаются две дуги или где кривая проходит над или под собой.
  8. Выходные данные могут быть в любой файл изображения в растровом формате или в любой файл изображения в векторном формате, который содержит правильный размер экрана по умолчанию. При непосредственном отображении на экране это должно быть в форме, позволяющей прокручивать изображение, чтобы увидеть полное изображение, когда оно больше экрана.

Определение центра дуги, радиуса и толщины

  1. Узел построен как серия дуг окружности, которые встречаются в точках, где их касательные параллельны, чтобы дать бесшовное соединение. Эти дуги отображаются в виде кольцевых секторов (дуг с толщиной).
  2. Центры этих дуг - вершины самых маленьких перевернутых треугольников. Каждая такая вершина является центром ровно одной дуги.
  3. Каждая дуга имеет радиус 64 * ROOT3 / 2
  4. Исключением является то, что дуги в трех самых внешних треугольниках (в углах большого треугольника) имеют центр, который является средней точкой двух смежных внутренних вершин, и, следовательно, имеют радиус 64 * (ROOT3 / 2-1 / 2)
  5. Каждая дуга представлена ​​с общей толщиной (разницей между внутренним радиусом и внешним радиусом), 64 * (ROOT3 / 2) / 4и черные границы каждой из них имеют толщину 64 * (ROOT3 / 2) / 16. Кривая должна иметь эти границы, а не просто сплошную полосу.

Единицы измерения

  1. Все расстояния указаны в пикселях (1 - горизонтальное или вертикальное расстояние между 2 соседними пикселями).
  2. Квадратный корень из 3 должен быть точным до 7 значащих цифр. То есть ваши расчеты должны быть эквивалентны использованию ROOT3 таким образом, чтобы1.7320505 <= ROOT3 < 1.7320515

счет

Самый короткий код в байтах побеждает.


Для тех, кому интересно, N = 0 и N = 1 не включены, потому что они соответствуют окружности и трилистнику, которые не совсем соответствуют шаблону, который применяется для N> = 2. Я ожидаю, что большинству подходов к этой задаче потребуется добавить специальный код случая для 0 и 1, поэтому я решил их опустить.


1
Будет ли полезно иметь диаграмму, показывающую, к чему относятся все числа?
трихоплакс

Прежде чем я отдам свой ответ / добавлю углы, действительно ли нужны 7 значащих цифр для таких мелких деталей, как толщина линии и т. Д.? Точность типа «7 значащих цифр или 1 пиксель, в зависимости от того, что больше» кажется более подходящей.
Уровень Река St

@LevelRiverSt, поскольку размер изображения масштабируется с учетом входных данных, даже 7 значащих цифр недостаточно для точности в 1 пиксель для больших N. После некоторого обсуждения в чате я остановился на 7 значащих цифрах, так что все ответы будут одинаковыми стандарт.
трихоплакс

Да, это необходимо для масштабирования изображения для больших N. 7 значащих цифр на изображении 1000000 x 1000000 соответствуют 0,1 пикселя, но при промежуточных вычислениях это может быть хуже. Я просто думаю, что stroke-width:3.464102подобное немного излишне, если идея заключалась в том, чтобы получить точность в 1 пиксель. Я продолжу и включу это так, хотя, если это - решение.
Уровень Река St

Ответы:


27

Рубин, 1168 932

Исправлена ​​ошибка с прошлой ночи, больше игры в гольф нужно делать после уточнения.

Это (в настоящее время) полная программа, которая принимает число из стандартного ввода и выводит svgфайл в стандартный вывод. Я выбрал svg, потому что знал, что можно выполнить все требования вопроса, но у него были некоторые проблемы. в частности, SVG поддерживает только дуги окружностей как часть pathобъекта и определяет их не по центру, а по двум конечным точкам.

Код

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

Выход N = 4

перепродан обменом стека. Выглядит намного лучше, чем оригинал.

введите описание изображения здесь объяснение

Сначала я рассмотрел что-то вроде http://euler.nmt.edu/~jstarret/sierpinski.html, где треугольник разбит на три разноцветных нити, каждая из которых образует путь от одного угла к другому. Неполные круги показаны там как неполные шестиугольники. вписывание кружков внутри шестиугольников показывает, что радиус окружности должен быть sqrt(3)/2кратен длине стороны. Нити можно построить рекурсивно, как показано, но есть дополнительное осложнение, потому что углы должны быть закруглены, и трудно определить, в каком направлении нужно изгибаться, поэтому я не использовал этот подход.

То, что я сделал, было следующим.

На изображении ниже вы можете видеть горизонтальные повороты, относящиеся к N = 2 единицам (зеленым цветом), расположенные в треугольнике Серпинского, и дополнительные соединительные завихрения (синим цветом).

Общеизвестно, что нечетные числа в треугольнике Паскаля образуют треугольник Серпинского. Треугольник Серпинского из двоичных цифр может быть получен аналогичным образом, начиная с числа p=1и итеративно записывая его с помощью p<<1.

Я изменил этот подход, начиная с p=2итеративного ксинга с p*4. Это дает треугольник Серпинского, чередующийся со столбцами нулей.

Теперь мы можем сместить права p и проверить последние три бита, используя %8. Если это так, 010нам нужно нарисовать зеленый поворот, относящийся к единице с N = 2. если они есть, 101нам нужно нарисовать синий, соединяющий поворот. Чтобы проверить оба эти числа вместе, мы находим модуль по модулю, %3и если это 2, нам нужно нарисовать поворот.

Наконец, в дополнение к горизонтальным поворотам, мы делаем две копии, повернутые на 120 и 240 градусов, чтобы нарисовать диагональные повороты и завершить картину. Осталось только добавить углы.

Код комментария

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

введите описание изображения здесь


Там, где вы говорите «выглядит намного лучше оригинала», возможно, стоит добавить что-то вроде «(нажмите на изображение, чтобы увидеть в полном размере)» для тех, кто не понимает.
трихоплакс

@trichoplax мне не пришло в голову кликнуть на изображение. Но в любом случае, это PNG, потому что обмен стека не принимает изображения SVG, поэтому края намеренно размыты. Мой локальный файл SVG имеет гораздо более четкие края и выглядит намного лучше.
Уровень Река St

@trichoplax быстрое исправление размера изображения сделано. Будет ли гольф больше другого дня.
Уровень Река St

1
+1 отличная работа. Мне особенно нравится подробное объяснение с цветовой схемой.
трихоплакс

1
Гиперссылка мертва.
mbomb007
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.