Плетіння прокладки - намалюйте вузол Сьєрпінського


33

Давши ціле число N> = 2, створіть зображення, що показує вузол Сірпіньського ступеня N.

Наприклад, ось вузли ступеня 2, 3, 4 і 5:

2 ступінь 3 ступінь Ступінь 4 5 ступінь

Клацніть на зображення, щоб переглянути повний розмір (чим вище ступінь, тим більше зображення).

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

  1. Вузол Сєрпіньського за ступенем N малюється за допомогою вершин трикутника Сєрпіньського за ступенем N в якості орієнтирів. Трикутник Сєрпіньського за ступенем N - це три трикутники Сєрпіньського ступеня N-1, розташовані у більший трикутник. Трикутник Сєрпіньського ступеня 0 - це рівносторонній трикутник.
  2. Найменша складова трикутників має бічну довжину 64, що дає трикутник Сірпіньського, на якому вузол заснований загальною довжиною сторони 64 * 2 ^ N
  3. Центр зовнішнього трикутника розташований у центрі зображення. Це не дає рівного білого простору вгорі та внизу.
  4. Вихід - це квадратне зображення бічної довжини, стеля (64 * 2 ^ N * 2 / ROOT3)де стеля (х)є ceiling(x)найменше ціле число, що перевищує або дорівнює 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 піксель, залежно від того, що більша" здається більш доцільною.
Річка Рівня Св

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

Так, для масштабування зображення для більшого N. 7 значущі цифри на зображенні 1000000 х 1000000 відповідають 0,1 пікселів, але при проміжних обчисленнях це може бути гірше. Я просто думаю, що stroke-width:3.464102подібне трохи надмірне, якщо ідея полягала в точності 1 пікселя. Я буду йти вперед і включати його таким чином, якщо це є постановою.
Річка Рівня Св

Відповіді:


27

Рубі, 1168 932

Виправлена ​​помилка з минулої ночі, робити більше гольфу після уточнення.

Це (на даний момент) повна програма, яка приймає число від stdin та виводить svgфайл у stdout. Я вибрав 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 має набагато чіткіші краї і виглядає набагато краще.
Рівень річки Св

@trichoplax швидко виправити розмір зображення. Буде гольф ще один день.
Рівень р. Св

1
+1 велика робота. Особливо мені подобається детальне пояснення з кольоровою діаграмою.
трихоплакс

1
Гіперпосилання мертва.
mbomb007
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.