Зробіть трохи снігу!


18

Ваше завдання: генерувати сніжинку Коха на n-ту глибину. Не потрібно робити повну сніжинку Коха, лише одну сторону стартового трикутника. Вікіпедія на пластівцях Коха: https://en.wikipedia.org/wiki/Koch_snowflake .

Правила:

  • Програма повинна генерувати одну сторону сніжинки Коха до п’ятої глибини.
  • Вихід повинен бути ASCII.
  • Ви можете створити всю сніжинку; цього не потрібно.
  • Застосовуються стандартні правила введення / виводу, лазівки та ін.
  • Пробіл не має значення, доки всі персонажі знаходяться в потрібному місці відносно один одного.
  • Найкоротший код виграє!

Тестові приклади:

n = 0:

__

n = 1:

__/\__

n = 2:

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

n = 3:

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

Сподіваюся, це має сенс. Зауважте, що у кожному тестовому випадку фрактал можна розділити на три частини, однакові за довжиною. Також зауважте, що ширина кожної сніжинки втричі перевищує ширину попереднього покоління сніжинки.


FYI, було вирішено , що це не боян з цього .
Товариш SparklePony

Я не думаю, що ви належним чином визначили, що таке правильне представлення ASCII n-ї кривої Коха.
orlp

Я не впевнений, що пропорції мають сенс. Некорекція використовується __/\__з двома підкресленнями, що зробило кожну ітерацію послідовно в 3 рази більшою за попередню. Використання лише одного підкреслення, здається, створює протиріччя, які починають ставати справді незручними в n = 3. Наприклад, зовнішні частини мають ширину 12, тоді як середня частина має лише ширину 10, як наслідок /_і _\ занадто тісних. А ще до цього ви _розширилися вдвічі ширше /і \ .
Ørjan Johansen

Я думаю, що є /_і _\ є єдиною насправді фатальною частиною - підкреслення потрібно робити, тому що вони повинні знаходитися в тому ж положенні, що /і \ . Після цього все може розширитися в 3 рази від n = 1 і далі (але n = 0 не відповідає.)
Ørjan Johansen

На жаль, ні, середня частина все ще має ширину, що не відповідає зовнішнім частинам, про що свідчить n = 3, що має ширину 52, а не 54 = 2 * 3 ^ 3. Спробуйте один із них . Я включив перевернуті версії з частинами, що відображаються лише від n = 4 або n = 5 - вони відрізняються від верхніх вершин, у яких підкреслюються підкреслення.
Ørjan Johansen

Відповіді:


10

Haskell , 308 300 299 байт

Зміни:

  • -4 байт: Зміна zipWith(+)до zipWith(-)і регулювальні кодувань і заліки позбулися кожного знака заперечення.
  • -1 байт: Подальше налаштування кодування дозволило видалити кілька імен змінних #, використовуючи r=reverseзамість прямого узгодження шаблону.
  • -2 байти: Використання оператора замість літер для zipWith(-).
  • -1 байт: визначення o=[0,0]скорочення констант списку.
  • -1 байт: Об'єднання двох гілок ?.
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]

Спробуйте в Інтернеті! (На жаль, все, що більше n = 3, стає жахливо завернутим і нечитабельним, але ви можете скопіювати його в іншу програму, щоб побачити його.)

Варіації

Як це працює

  • kце основна функція, вона приймає Int nі повертає a String.
  • iterate(>>=(:[1,4,1]))[6]створює нескінченний список, що містить для кожного n повороти між послідовними лініями в цій ітерації кривої, стиль графіки черепахи, як номінально числа між 0і 5. Кожна ітерація є лише попередньою з 1,4,1переплетеними поворотами . Єдина причина, з якої починаються сублісти, 6а 0не робити gcdхитрощі в fроботі, уникаючи f 0.
  • scanl1(+)перетворює повороти в "абсолютні" напрямки, аж до модуля 6. А 0означає праворуч, то кожне вище число на 60 градусів проти годинникової стрілки від попереднього. (Ну, було б 60 градусів, якби це був правильний малюнок, а не ASCII.)
  • f перетворює абсолютний напрямок у список пар (символів, кодування зміщення), який кодує, які символи потрібно додати до кривої (для горизонтальних напрямків вона генерує дві пари, інакше одну), і як змінюється відносне положення.
  • В #операторі перебирає попередній список (характер, кодування зміщення) пар, генеруючи фактичний (координату, символ) пар.
  • Принципи кодування:
    • Символ від _/\номінально являє собою лінію, проведену від початкового кута через прямокутну клітинку до іншого закінчуючого кута.
    • Координати комірок мають форму [y,x], зверху вниз, зліва направо, так що вони сортуються в тому порядку, в якому ми хочемо їх надрукувати. Стовпці на 1 основі. Списки використовуються замість кортежів для коротшої векторної арифметики з (&)=zipWith(-).
    • Кут позначається з тими ж координатами [y,x], що і клітинка вгорі зліва. Це гарантує, що всі зрушення від кута до сусідніх комірок не мають негативного характеру, уникаючи негативних констант.
    • Однак кутові координати передаються навколо запереченням, щоб дозволити відніманню всіх векторних операцій замість додавання, що дозволяє уникнути всіх інших явних знаків.
    • Зсув кодує список , [y1,x1,x2,y2]де [y1,x1]це зміщення координат від вихідного кута в символьної осередок і [y2,x2]це зміщення від кінця кута в символьної осередок. Це означає:
      • Списки кодування для напрямків 3.. - 5це просто зворотний перелік списків для 0.. 2, що дозволяє генерувати їх [id,r]<*>.
      • Всю необхідну арифметику вектора можна виконати, використовуючи (&)=zipWith(-)або список кодування, або його зворотний бік.
  • Після сортування списку (координатних, символьних) пар вони передаються до ?, що генерує Stringз них фінал .
    • В x?l@(([_,w],c):r) x- координата x попереднього символу, показаного на цьому рядку, або 0якщо на початку рядка; l- це весь поточний список, wє координата x наступного символу, який потрібно додати, cце символ та rсписок, що залишився.
    • На цьому етапі y координати більше не потрібні. Оскільки кожен рядок містить символи, а перший символ кожного рядка знаходиться зліва від кінця попереднього, початок нових рядків виявляється, перевіряючи, чи зменшилась координата x.
    • Підкреслення має більшу величину ASCII, ніж \та /, тому вона стає відсортованою останньою, якщо вона перетинається з іншим символом у тій же позиції. Таким чином, зайвий підкреслення виявляється, перевіряючи, чи була повторена координата x.

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