Нарисуйте кривую Гильберта

12

Кривая Гильберта - это тип кривой заполнения пространства, и она в основном отображает линию на плоскость. Каждая точка на линии соответствует только одной точке на плоскости, а каждая точка на плоскости соответствует только одной точке на линии. Показаны итерации с 0 по 4 кривой Гильберта:

Итерации от 0 до 4:

Цель этой задачи: написать код, который рисует четвертую итерацию кривой Гильберта, как определено выше. Ваш код должен быть полным - другими словами, если вы создаете функцию для рисования кривой Гильберта, ваш код должен вызывать эту функцию. Вывод может быть либо отображен непосредственно на экране, либо вы можете записать вывод в файл изображения. Кривая может быть повернута или перевернута, но линии должны пересекаться под прямым углом, и выход не может быть растянут. Искусство ASCII ценится, но не будет принято. Самый короткий код в байтах побеждает!

Х. Антонио Перес
источник
Сколько раз вход? Или мы можем выбрать любое значение по крайней мере 4?
Луис Мендо
Искусство ASCII считается графическим?
Габриэль Бенами
Нет; извините - тогда это будет дубликат другого вопроса
Х. Антонио Перес
@JorgePerez Может ли кривая иметь другую ориентацию? Как версия ваших примеров, развернутая вертикально или на 90 градусов
Луис Мендо
Да! Хотя общая форма все еще должна быть квадратной
Х. Антонио Перес

Ответы:

7

R, 90 байт

n=scan();a=1+1i;b=1-1i;z=0;for(k in 1:n)z=c((w<-1i*Conj(z))-a,z-b,z+a,b-w)/2;plot(z,t="s")

Бесстыдный R-порт алгоритма, используемый в ссылке, размещенной @Luis Mendo.

Ибо n=5мы получаем:

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

Billywob
источник
7

MATL , 39 38 байт

O5:"tZjJ*JQ-wJq+t2+&y2j+_v2/]XG25Y01ZG

Это принимает количество итераций в качестве входных данных. Если вы хотите жестко закодировать его, замените iего на номер.

Программа является портом кода Matlab от Jonas Lundgren, показанного здесь .

Результат показан ниже. Вы также можете попробовать это в MATL Online! Требуется пара секунд, чтобы произвести вывод. Этот компилятор является экспериментальным; вам может понадобиться обновить страницу и снова нажать «Выполнить», если она изначально не работает.

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

объяснение

O          % Push 0. This is the initial value of "z" in the original code
5:"        % Do 5 times
  t        %   Duplicate
  Zj       %   Complex conjugate
  J*       %   Multiply by 1j (imaginary unit). This is "w" in the original code
  JQ-      %   Subtract 1+1j
  w        %   Swap: brings copy of "z" to top
  Jq+      %   Add 1-1j
  t        %   Duplicate
  2+       %   Add 2
  &y       %   Duplicate the third element from top
  2j+_     %   Add 2j and negate
  v        %   Concatenate the three matrices vertically
  2/       %   Divide by 2
]          % End
XG         % Plot (in complex plane). The numbers are joined by straight lines
25Y0       % Push string 'square'
1ZG        % Make axis square
Луис Мендо
источник
Не могли бы вы объяснить, как работает ваш код?
Х. Антонио Перес
Алгоритм в точности как в ссылке. Но я добавлю объяснение
Луис Мендо
Добавлено @Jorge Объяснение
Луис Мендо
о боже, тот, на котором ты основал свой, намного проще моего = /
flawr
@flawr Вся заслуга Джонаса Лундгрена :-)
Луис Мендо
6

MATLAB, 264 262 161 байт

Это работает во многом так же, за исключением того, что мы в основном вычисляем «производную» кривой Гильберта, которую мы затем «интегрируем» через «cumsum». Это уменьшает размер кода на кучу байтов.

function c;plot(cumsum([0,h(1,1+i,4)]));axis equal;end function v=h(f,d,l);v=d*[i*f,1,-i*f];if l;l=l-1;D=i*d*f;w=h(f,d,l);x=h(-f,D,l);v=[x,D,w,d,w,-D,-x];end;end

Старая версия

Это просто рекурсивный подход. Я использовал комплексные числа для хранения векторной информации для простоты. Вы можете изменить кривую на детали h(0,1,1+i,4). Первый аргумент p=0- это начальная позиция, второй аргумент f- это флаг ориентации ( +1или -1), третий аргумент d- это направление / вращение, в котором должна быть нарисована кривая, а четвертый l- глубина рекурсии.

function c;hold on;h(0,1,1+i,4);axis equal;end function p=h(p,f,d,l);q=@plot;if l;l=l-1;d=i*d*f;p=h(p,-f,d,l);q(p+[0,d]);p=p+d;d=-i*d*f;p=h(p,f,d,l);q(p+[0,d]);p=p+d;p=h(p,f,d,l);d=-i*d*f;q(p+[0,d]);p=p+d;p=h(p,-f,d,l);else;q(p + d*[0,i*f,1+i*f,1]);p=p+d;end;end

Вот как это выглядит в старых версиях:

Вот как это выглядит в 2015b:

->
flawr
источник
1
В Matlab R2015b он отображает цвета <3
Луис Мендо
Ха-ха, круто :)
flawr
@ LuisMendo Теперь я смог немного поиграть в гольф с cumsumидеей, которая просто великолепна!
flawr
3

MATLAB / Octave, 202 байта

Я заметил, что версия @LuisMendo, связанная с ней , была намного короче, чем предыдущее решение "ручной работы", но использует совершенно другой подход. Я выкладываю здесь версию для гольфа как CW:

Эта версия основана на системном подходе Линденмайера:

A=zeros(0,2);B=A;C=A;D=A;n=[0,1];e=[1,0];for k=1:4;a=[B;n;A;e;A;-n;C];b=[A;e;B;n;B;-e;D];c=[D;-e;C;-n;C;e;A];D=[C;-n;D;-e;D;n;B];A=a;B=b;C=c;end;A=[0,0;cumsum(A)];plot(A(:,1),A(:,2));axis off;axis equal

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

flawr
источник
3

JavaScript (ES6), 266 ... 233 232 байта

SVG-рендеринг кривой Гильберта.

document.write('<svg><path fill=none stroke=red d="M8 8'+(f=(i,s='2',d=x=y=8)=>i?f(i-1,s.replace(/./g,c=>[32410401423,,10432423401][+c]||c)):s.replace(/./g,c=>c-4?(d+=c&1&&c-2,''):`L${x+=4-'4840'[d&=3]} ${y+=4-'0484'[d]}`))(5)+'">')

Сохранено 1 байт благодаря Нейлу

Arnauld
источник
1
Попробуйтеfill=none
Нил
2

Python 3, 177 175 171 байт

Простая реализация системы Линденмайера для кривой Гильберта. Предложения по игре в гольф приветствуются!

Редактировать: -2 байта благодаря Kade. -3 байта от перестройки построения кривой Гильберта. -1 байт благодаря ETHproductions.

from turtle import*;s="a";exec('t=""\nfor c in s:t+=c>"F"and"+-abFF-+baFFba-+FFab+-"[c<"b"::2]or c\ns=t;'*5)
for c in s:
 if"-">c:rt(90)
 elif"F">c:lt(90)
 elif"a">c:fd(9)

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

Ungolfing

import turtle

hilbert_seq = "a"

for _ in range(5):
    new_seq = ""
    for char in hilbert_seq:
        if char == "a":
            new_seq += "-bF+aFa+Fb-"
        elif char == "b":
            new_seq += "+aF-bFb-Fa+"
        else:
            new_seq += char
    hilbert_seq = new_seq

for char in hilbert_seq:
    if char == "F":
        turtle.forward(9)
    elif char == "+":
        turtle.right(90)
    elif char == "-":
        turtle.left(90)
Sherlock9
источник
Изменение , как вы формируете tможет сохранить два байта: t+=[[c,"+AF-BFB-FA+"][c=="B"],"-BF+AFA+FB-"][c=="A"]. Поскольку модель для них двоих почти одинакова, мне интересно, есть ли способ использовать это ..
Kade
Возможно изменить, if c>"E":чтобы if"E"<c:сохранить байт?
ETHproductions
1

MSWLogo (версия 6.5b), 136 байт

На основании окончательной программы кривой Гильберта здесь .

to h :n :a :l
if :n=0[stop]
rt :a
h :n-1(-:a):l
fd :l
lt :a
h :n-1 :a :l
fd :l
h :n-1 :a :l
lt :a
fd :l
h :n-1(-:a):l
rt :a
end
h 5 90 9

hОпределяется функция , которая принимает количество итераций :n( начиная с 1), угол :a, длину :l. Это рекурсивно, вызывая более низкую итерацию с углом :aв двух случаях, чтобы получить правильную ориентацию.

  • rt :a, lt :aповерните черепаху (треугольник, чей путь прослежен) вправо, влево на :aградусы.
  • fd :lдвигает черепаху вперед по :lшагам.

Наконец, функция называется: h 5 90 9. Черепаха может быть скрыта за дополнительные 2 байта ht.

(5-1) -я итерация

для Моники
источник
Что происходит в левом верхнем углу?
Flawr
@flawr Это черепаха. Это может быть скрыто путем добавления ht.
для Моники
1

Mathematica 128 байт

Graphics[Line@AnglePath[Total/@Split[Cases[Nest[#/.{-2->(s=##&@@#&)[l={-1,2,0,1,-2,0,-2,1,0,2,-1}],2->s@-l}&,{-2},4],-1|1|0],#!=0&][[;;-2,;;-2]]*Pi/2]]

Замените 4 выше с другим количеством итераций, если хотите.

Выполнено как система Линденмайера с целочисленными последовательностями, а не с последовательностями строк, поэтому второе производственное правило является просто отрицательным по отношению к первому правилу. Эта версия составляет 151 байт.

Порт кода MATLAB Джонаса Лундгрена составляет всего 128 байт.

z=0;Graphics[Line[{Re[#],Im[#]}&/@Flatten[Table[w=I*Conjugate[z];z={w-(a=1+I),z-(b=1-I),z+a,b-w}/2,{k,5}][[5]]]],AspectRatio->1]

Я вижу, что в будущей версии Mathematica это может стать очень коротким, что-то вроде:

Graphics@HilbertCurve[n]

http://mathworld.wolfram.com/HilbertCurve.html

Келли Лоудер
источник
1

LindenMASM , 63 байта

Еще один вопрос с ответом LindenMASM? Потрясающие!

STT
AXI A
INC 5
SET F 0
RPL A -BF+AFA+FB-
RPL B +AF-BFB-FA+
END

Еще раз, из-за некоторых ошибок рисования в Python turtle, иногда, когда вы запускаете это, весь рисунок не появляется. Однако вы можете видеть, что это действительно работает:

4-я итерация

Када
источник