Крива Гільберта ASCII


23

Дано ціле число nвиводимо nй ітерації Гільберта кривої в ASCII , використовуючи символи _і |.

Ось перші 4 ітерації:

n=1
 _ 
| |

n=2
 _   _ 
| |_| |
|_   _|
 _| |_

n=3
 _   _   _   _ 
| |_| | | |_| |
|_   _| |_   _|
 _| |_____| |_ 
|  ___   ___  |
|_|  _| |_  |_|
 _  |_   _|  _ 
| |___| |___| |

n=4
 _   _   _   _   _   _   _   _ 
| |_| | | |_| | | |_| | | |_| |
|_   _| |_   _| |_   _| |_   _|
 _| |_____| |_   _| |_____| |_ 
|  ___   ___  | |  ___   ___  |
|_|  _| |_  |_| |_|  _| |_  |_|
 _  |_   _|  _   _  |_   _|  _ 
| |___| |___| |_| |___| |___| |
|_   ___   ___   ___   ___   _|
 _| |_  |_|  _| |_  |_|  _| |_ 
|  _  |  _  |_   _|  _  |  _  |
|_| |_| | |___| |___| | |_| |_|
 _   _  |  ___   ___  |  _   _ 
| |_| | |_|  _| |_  |_| | |_| |
|_   _|  _  |_   _|  _  |_   _|
 _| |___| |___| |___| |___| |_ 

Роз'яснення

  • Моє запитання схоже на « Накресли криву Гільберта» та « Накресли криву Гільберта» за допомогою косої риски .
  • Перетворення між символами підкреслення ( _) і вертикальних стрижнів ( |) є , u=2*v-1де uце кількість _секунд , і vце число |с.
  • Щоб зберегти узгодженість з моїм початковим повідомленням, крива повинна починатися і закінчуватися внизу.
  • Ви можете мати повну програму або функцію.
  • Вихід до stdout (або щось подібне).
  • У вас можуть бути провідні або кінцеві пробіли, висновок потрібно просто вирівняти так, щоб він виглядав як приклади.
  • Це кодовий гольф, тому найкоротша відповідь у виграші байтів.

3
Чи можете ви включити у свою посаду визначення кривої Гільберта та точні характеристики того, як будується версія ASCII?
Loovjo



@Loovjo Я додав у пункті про довжини підкреслених (_) та вертикальних смуг (|) у розділі "Роз'яснення", якщо більше інформації або суворого визначення все ж потрібно, будь ласка, скажіть мені.
Bobas_Pett

@shooqie я видалив тег
Bobas_Pett

Відповіді:


5

Befunge, 444 368 323 байт

&1>\1-:v
0v^*2\<_$00p>
_>:10p\:20pv^_@#-*2g00:+1,+55$
^!-<v*2g000<>$#<0>>-\:v
g2*^>>10g20g+v \ ^*84g_$:88+g,89+g,\1+:00
v#*!-1g02!g01_4^2_
>::00g2*-!\1-:10g-\20g-++>v
87+#^\#p01#<<v!`g01/2\+76:_
vv1-^#1-g01:\_$:2/20g`!
_ 2/^>:10g#vv#`g02/4*3:\+77
v>0p^^/2:/2_
<^2-1-g02</2`#*3:
0g+10p2*:^*3_1
! "#%$
%$"#!
 !!##%
|||_
 _ __

Спробуйте в Інтернеті!

Типовий підхід до малювання кривої Гільберта полягає в тому, щоб слідувати по шляху, як серія штрихів і поворотів, перетворюючи результат у растрову карту чи якусь область пам’яті, а потім виписувати цю візуалізацію, коли шлях закінчений. Це просто неможливо в Befunge, коли у нас є лише 2000 байт пам'яті для роботи, і це включає джерело самої програми.

Отже, підхід, який ми тут застосували, - це придумати формулу, яка точно підказує, який символ виводити для заданої координати x, y. Щоб зрозуміти , як це працює, це найпростіше ігнорувати ASCII рендеринга , щоб почати с, і просто думати про криву , як з коробки символів: , , , , , і .

Коли ми дивимось на криву таким чином, ми можемо відразу побачити, що права рука - це точне дзеркало лівої сторони. Символів праворуч можна просто визначити, дивлячись на свого партнера зліва та відображаючи його по горизонталі (тобто події та міняються місцями, як є і ).

Крива Гільберта 3 рівня, що відображає відбиття по вертикальній осі

Потім, дивлячись на нижній лівий кут, ми знову бачимо, що нижня половина - це відображення верхньої половини. Таким чином, символи на дні просто визначається шляхом пошуку свого партнера вище, і відображає його вертикально (тобто входжень і міняються місцями, так само як і ).

Крива Гільберта 3 рівня, що відображає відображення по горизонтальній осі в нижньому лівому куті

Решта половини цього кута трохи менш очевидна. Правий блок може бути отриманий від вертикального відображення блоку, діагонально прилеглого до нього.

Крива Гільберта 3 рівня, що показує, як можна вивести верхній правий блок нижнього лівого кута

А лівий блок можна отримати від вертикального відображення блоку в самому верхньому лівому куті від повної кривої.

Крива Гільберта 3 рівня, що показує, як можна вивести верхній лівий блок нижнього лівого кута

У цій точці все, що нам залишилося, - це верхній лівий кут, який є лише іншою ітерацією Гільберта на одну ітерацію нижче. Теоретично нам слід просто повторити процес ще раз, але тут є трохи прикуту - на цьому рівні ліва і права половини блоку не є точними дзеркалами один одного.

Тож на будь-якому, окрім верхнього рівня, символи нижнього кута потрібно обробляти як особливий випадок, де персонаж відображається як , а персонаж відображається як .

Крива Гільберта 3 рівня, що показує, як можна вивести верхній лівий блок нижнього лівого кута

Але крім цього, ми дійсно можемо просто повторювати цей процес рекурсивно. На останньому рівні ми жорстко кодуємо верхній лівий символ як , а символ під ним як .

Послідовність зображень, що показують, як виводяться інші частини кривої

Тепер, коли у нас є спосіб визначити форму кривої на певній координаті x, y, як ми переведемо це на візуалізацію ASCII? Насправді це просто просте відображення, що переводить кожну можливу плитку на два символи ASCII.

  • стає  _(пробіл плюс підкреслення)
  • стає   (два пробіли)
  • стає |_(вертикальна смуга плюс підкреслення)
  • стає (вертикальна смуга плюс пробіл)
  • стає (знову вертикальна смуга плюс пробіл)
  • стає __(дві підкреслення)

Це відображення спочатку не інтуїтивно зрозуміло, але ви можете побачити, як воно працює, переглядаючи два відповідні візуалізації поряд.

Крива Гільберта рівня 2 зображена як ASCII мистецтво та з символами коробки

І це в основному все, що там є. Насправді реалізація цього алгоритму в Befunge - це зовсім інша проблема, але я поясню це пояснення для іншого часу.


2

C, 267 байт

const n=4,s=1<<n,a[]={1,-s,-1,s};l,p,q;
t(d){d&=3;p-q||printf("%.2s",&"__|      _|       |___ _|_| | | "[l*8+d*2]);p+=a[l=d];}
h(d,r,n){n--&&(h(d+r,-r,n),t(d+r),h(d,r,n),t(d),h(d,r,n),t(d-r),h(d-r,-r,n));}
main(){for(;p=s*s-s,l=1,q<s*s;++q%s||putchar(10))h(0,1,n),t(3);}

Спробуйте в Інтернеті!

h()використовує рекурсію для генерації обведення кривої Хліберта. t()друкує символ обведення лише в тому випадку, якщо положення ручки pдорівнює поточному вихідному положенню q.

Це неефективно, але просто.

Якщо крива починається вліво зліва, код можна зменшити до 256 байт.


Запропонуйте puts("")замість putchar(10)і "..."+l*8+d*2замість &"..."[l*8+d*2]і n--?h(d+r...-r,n):0замістьn--&&(h(d+r...-r,n))
roofcat
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.