Нарисуй кривую дракона

19

Ваша задача на сегодня: нарисовать кривую дракона!

Если вы не знаете, что такое «Кривая Дракона», вот вступительное видео ViHart (очень круто, пожалуйста, смотрите!)

Ваша задача: нарисовать кривую дракона, повторенную как минимум 9 раз. Вам не нужно показывать итерации с 1 по 9, вам просто нужно показать окончательную кривую, полученную после выполнения (как минимум) 9 итераций. Кривая должна быть нарисована в виде прямых линий, соединяющих точки на кривой; выходные данные должны соответствовать одному из изображений ниже, которые показывают 9 или более итераций (вплоть до отражения, поворота, масштабирования и изменения ширины линии, цвета линии и цвета фона). Ваш вывод должен быть достаточно большим, чтобы отдельные строки и «прямоугольники», которые они образуют, можно было отличить друг от друга; если две линии не пересекаются на кривой, они не должны занимать одинаковые или смежные пиксели в выводе (между ними должен быть хотя бы один пиксель фона). Вы можете либо отобразить изображение на экране, либо сохранить изображение в файл принят. Вывод должен быть графическим - это не может быть ASCII-арт.

Самый короткий код в байтах выигрывает, однако директивы для библиотек не должны включаться в число байтов, и вы можете использовать графические библиотеки или другие библиотеки, написанные для вашего языка по вашему выбору, если они были написаны до публикации.

Пожалуйста, включите изображение вывода вашей программы.

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

Пропустите этот абзац, если вы смотрели видео:Для тех из вас, кто решил не смотреть видео, первые 12 итераций кривой дракона показаны ниже. Для целей этой задачи кривая дракона - это кривая, сгенерированная по следующему правилу: возьмите конечную точку текущей кривой, создайте вторую кривую, повернутую на 90 градусов вокруг этой конечной точки, чтобы конечная точка оригинала кривая является отправной точкой новой кривой, и объедините две кривые в одну кривую, где они встречаются. На изображениях, показанных ниже, каждая новая итерация генерируется путем поворота предыдущей итерации на 90 градусов по часовой стрелке вокруг конечной точки каждой итерации. Когда кривая отображается на экране, не очевидно, какой конец считается «конечной точкой», однако, когда кривая хранится как массив точек, легко определить «конечную точку» в качестве последней точки в массив.

Искусство Ascii ценится, но не принимается: это графический вывод, а не ascii-art.

Х. Антонио Перес
источник
3
Существуют ли какие-либо спецификации по размеру, окраске и т. Д.? Как это точный вывод немного неясно.
Rɪᴋᴇʀ
3
Относящиеся .
Fatalize
6
Я удалил тег с кривой дракона, потому что он, похоже, ничего не добавил
Blue
1
Также связано.
Мартин Эндер
3
Это не дубликат; методы программирования для ее решения совершенно разные (за исключением, возможно, древесного угля). Большинство ответов используют графические библиотеки черепах, которые вообще не будут работать в контексте ASCII.

Ответы:

2

x86, MSDOS, 16 байт

Я написал это некоторое время назад, насколько мне известно, самую маленькую процедуру создания драконьего фрактала. Он не использует никаких реальных итераций, а отображает каждый отдельный дискретный пиксель внутри фрактала, показывая окончательное изображение. Он включен во многие другие крошечные произведения в этом пакете . 16-байтовая версия была концом моих усилий, чтобы получить как можно меньший фрактал дракона, начиная с 2014 года с этим 32-байтовым производством .

наговор

14 10 19 CA D1 FA 10 DE 01 D1 CD 10 B4 0C EB F0

Код

S: 
adc al,0x10
sbb dx,cx       
sar dx,0x01 
adc dh,bl
add cx,dx
int 0x10
mov ah,0x0C
jmp short S

Скриншот

HellMood
источник
1
Это ... Удивительно, если не сказать больше. Как бы я запустил его?
Х. Антонио Перес
Самый быстрый способ - это DosBox онлайн, twt86.co?c=FBAZytH6EN4B0c0QtAzr8A%3D%3D. Вы можете скопировать исходный код здесь и скомпилировать его там. Классический способ - загрузить DosBox (0.74) и запустить его там. Самый реальный способ - получить загрузочный пакет MSDos или FreeDos (Rufus) и запустить его для реального #noemu;)
HellMood
9

Python 2/3, 169 167 150 111 98 78 байт

Обратите внимание, что импорт не включен в число байтов в соответствии со спецификациями вызова.

Спасибо @AlexHall за сохранение 39 (!) Байтов и @ nedla2004 за еще 13

from turtle import*
o=[90]
for z in o*9:o+=[90]+[-x for x in o[::-1]]
fd(5)
for i in o:rt(i);fd(5)

Начинается с создания списка или правого (90) и левого (-90) поворотов, затем проходит по списку и перемещает черепаху.

Сгенерированный выход: введите описание изображения здесь

РЕДАКТИРОВАТЬ: Если это слишком скучно смотреть, добавьте speed(0)прямо перед первым fd(5). Он будет работать так же, только черепаха будет двигаться намного быстрее.

Тео
источник
Картинка была бы хороша :)
Kritixi Lithos
Не могли бы вы опубликовать картинку или скриншот с выводом? Даже не ясно, что этот код печатает что-либо на экране
Х. Антонио Перес
Ваше изображение обрезали
Х. Антонио Перес
Должно быть исправлено сейчас :)
Тео
@AlexHall Спасибо! Я знал, что должен был быть способ сделать эту петлю более короткой :)
Тео
8

Логотип, 43 байта

for[i 1 512][fd 9 lt :i/(bitand :i -:i)*90]

Попробуйте с переводчиком на http://www.calormen.com/jslogo/#

В нем используется тот же принцип, что и в моем предыдущем ответе по искусству ASCII, и формула в википедии, за исключением того, что я изменил направление, чтобы соответствовать изображению в вопросе:

Во-первых, выразите n в форме, k*(2^m)где k нечетное число. Направление n-го поворота определяется k mod 4, т. Е. Остаток остается, когда k делится на 4. Если k mod 4 равно 1, то n-й ход равен R L; если k mod 4 равно 3, то n-й ход равен L R

bitand :i -:iнаходит наименее значимый бит i. Мы делим iна это, чтобы погасить iнужную сумму, давая требуемое нечетное число k. Нет необходимости различать левый и правый повороты; мы просто поворачиваем налево на несколько k*90градусов и полагаемся на тот факт, что вращение является операцией по модулю 360, чтобы выполнить по модулю для нас.

Выход

используйте, htчтобы скрыть черепаху, если требуется.

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

Выход (модифицированный)

Ниже показано, как кривая представляет собой одну цепь.

bk 6 for[i 1 512][fd 6 rt :i/(bitand :i -:i)%4*45-90 fd 3 rt :i/(bitand :i -:i)%4*45-90]

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

Уровень реки St
источник
4

LindenMASM , 51 байт

LindenMASM был языком, который я недавно создал для испытания, и он всегда будет жить в Песочнице. Это использует концепцию систем Lindenmayer для рисования таких вещей, как кривые Дракона, фрактальные растения, треугольники Серпинского и т. Д.

Исходный код выглядит следующим образом:

STT
AXI FX
INC 9
SET F 0
RPL X X+YF+
RPL Y -FX-Y
END

Чтобы настроить это, n = 6например:

STT
AXI FX
INC 6
SET F 0
RPL X X+YF+
RPL Y -FX-Y
END

Это создает следующее изображение через Python 3 turtle:

6 поколений

Для итераций может быть небольшое различие в нумерации, поскольку в системе Линденмайера первая итерация представляет собой одну строку. Вот как это выглядит n = 10:

10 поколений

Просто для забавы, вот как это выглядит с 15 поколениями (с добавленной инструкцией, MOV 2чтобы сделать его немного меньше):

15 поколений

Как только вы получаете до 20 поколений (с MOV 0.5), вы больше не можете видеть линии, и для создания требуется МНОГО шагов (пары +-и -+не оптимизированы). Вот что вы получаете:

20 поколений

Обратите внимание, что текущий интерпретатор может представлять графические проблемы для меньшего количества поколений, то есть, возможно, не отображать на экране. К сожалению, когда был создан этот интерпретатор, проблем не было, возможное изменение в Python 3 могло вызвать это, или это могла быть просто моя система

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

Недогрузка, 196 байт

()()(<svg width="99" height="147">)S(<g transform="translate):S((33,33)">)S((3,0)rotate)*a(*a(~*)*~("><path d="M0h3" stroke="#"/>)~*a(*)**:(-90)a~^~(90)a~^)*::*:**:*^S(</g>)(:*)::*:**:*^S(</svg>)S

Я подумал, что было бы интересно попробовать этот вызов на маломощном эзоланге; Недостаточная загрузка достаточно хороша для языка с таким небольшим количеством команд.

В результате получается файл SVG с очень сильно вложенными тегами и некоторыми ярлыками для игры в гольф. До сих пор я не нашел браузер, который мог бы отображать его (Firefox зависает на несколько минут, пытаясь загрузить его, и Firefox и Chromium дают пустой экран). Большинство программ обработки изображений также не могут загрузить его (что затрудняет его преобразование в другой формат), но мне удалось загрузить его в средство просмотра изображений Eye of Gnome (которое является частью установки по умолчанию в Ubuntu). Поэтому я сделал снимок экрана с изображением, чтобы вы могли его видеть (фактическое изображение имеет прозрачный фон, но вы не можете по-настоящему сделать его прозрачным):

Снимок экрана: кривая дракона в недогрузке

Нам нужно явно указать размер изображения. Выбор подходящего ориентации для изображения, используя все при минимальном размере правовой, и делать минимальное количество итераций , предусмотренных вызовом, дает нам образ , который только вписывается в 99 пикселей в ширину, экономя байт. Приятно, когда все получается так.

Общий алгоритм, используемый для рисования изображения, состоит в том, чтобы поддерживать две переменные (Underload не называет переменные, но я думал о них как о x и y ), обе изначально были пустыми. Затем мы неоднократно заменяем ( x , y ) на ( x , повернуть налево и двигаться вперед, y ) и ( x , повернуть направо и двигаться вперед, y ). После десяти итераций и x, и y содержат кривую дракона из девяти итераций.

Также есть несколько микро-оптимизаций и трюков, связанных с недогрузкой. Чтобы избежать излишней путаницы с вершиной стека, каждую итерацию цикла, мы начинаем с объединения x и y в функцию «вернуть строку, созданную путем конкатенации: x , инструкция поворота, аргумент функции, перемещение вперед инструкция, и у . " Эта функция занимает только один пробел в стеке, поэтому мы можем продублировать ее, вызвать ее -90в качестве аргумента, поменять местами возвращаемое значение в дубликате и вызвать его 90в качестве аргумента, чтобы получить новые значения для x и yбез необходимости касаться более двух верхних элементов стека (которые являются наиболее доступными). Эта функция генерируется кодом во время выполнения. Сам генератор также генерируется кодом во время выполнения, чтобы позволить ему повторно использовать строку, <g transform="translateкоторая также используется для установки источника изображения. Сначала мы генерируем все открытые теги, а затем, поскольку все закрывающие теги являются справедливыми </g>, мы можем вывести 1024 закрывающих тега, просто повторяя строку, не беспокоясь о сопоставлении их с открытыми тегами. (Эффективное написание чисел в недогрузке само по себе является интересной проблемой; (:*)::*:**:*возможно, это самый эффективный способ написать 1024, переводя в «2 в степень (1 + 2 × 2) × 2»).

Underload не имеет графических библиотек, поэтому я создаю SVG, используя комбинацию рисования линий в фиксированной позиции и поворачивая изображение вокруг заданной точки; вместо того, чтобы поворачивать ручку, мы поворачиваем бумагу. Идея состоит в том, что, рисуя линию, поворачивая все изображение, рисуя другую линию, снова поворачивая изображение и т. Д., Мы можем эффективно моделировать графику черепахи без необходимости арифметики или использования каких-либо графических библиотек, поскольку все линии нарисованы в том же месте. Конечно, это означает, что у нас есть очень сильно вложенные теги поворота изображения, что сбивает с толку многих зрителей SVG.

Стилизация изображения будет учитываться в счетчике байтов, поэтому мне нужно было указать минимальную стилизацию, необходимую для отображения изображения. Это оказывается stroke="#", что более или менее переводится как «линия должна быть какого-то цвета»; это кажется расширенным, чтобы нарисовать это черным. (Обычно вы бы указали цвет, скажем, «# 000».) Фон по умолчанию прозрачный. Мы не указываем ширину обводки, но выбор, выбранный Eye of Gnome, оставляет все видимым.

Многие интерпретаторы с недогрузкой борются с этой программой, например, программа Try It Online дает сбой, потому что она генерирует несколько очень больших строк внутри. Оригинальный переводчик Underload работает, хотя. (Интересно, что самый первый переводчик был в сети, поэтому язык можно было использовать в Интернете, прежде чем его можно было использовать в автономном режиме.)

Что-то, что меня немного беспокоит, так это то, что здесь только 1023 сегмента линии, и мы ожидаем 1024. Возможно, один из сегментов в конце не прорисован с помощью этого алгоритма (это будет на следующей итерации вместо). Если это дисквалифицирует, может быть возможно адаптировать программу, но она может закончиться значительно дольше. (Это не значит, что этот вызов все равно выиграет соревнование; уже есть несколько более коротких заявок.)


источник
4

MATL , 26 байт

0J1_h9:"tPJ*h]hYsXG15Y01ZG

Если приняты разные масштабы по двум осям, код можно уменьшить до 19 байт:

0J1_h9:"tPJ*h]hYsXG

Приведенные ниже цифры соответствуют версии в 26-байтовом масштабе.

Приведенный выше код создает 9-ю (основанную на 0) итерацию, то есть десятое изображение в задании:

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

Для других значений измените значение 9в коде или замените его iна число, введенное пользователем. Например, результат для 13:

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

объяснение

При этом используется цикл для постепенного построения массива шагов, за которыми следует кривая в комплексной плоскости. Например, первые два шага 1j(вверх) и -1(слева).

На каждой итерации массив шагов до сих пор копируется. Копия массива переворачивается , умножается на 1j(для поворота на 90 градусов) и соединяется с оригиналом.

После цикла накопленная сумма шагов дает действительные точки, которые затем наносятся на комплексную плоскость.

0                          % Push 0
 J1_h                      % Push array [1j, -1]. This defines the first two steps
     9:                    % Push [1, 2, ..., 9]
       "                   % For each
        t                  %   Duplicate the array of steps so far
         P                 %   Reverse
          J*               %   Multiply by 1j
            h              %   Concatenate horizontally to previous steps
             ]             % End
              h            % Concatenate with the initial 0
               Ys          % Cumulative sum
                 XG        % Plot. Complex numbers are plotted with real and imag as x and y
                   15Y0    % Push string 'equal'
                       1ZG % Set equal scale in the two axes
Луис Мендо
источник
Ваш ответ впечатляет :) Вы не против предоставить объяснение кода?
Х. Антонио Перес
@ Хорхе Спасибо! Готово
Луис Мендо
Предоставляемые вами версии «19 байтов» и «26 байтов» идентичны. Я предполагаю, что здесь есть ошибка копирования и вставки?
@ ais523 Действительно! Исправлено сейчас, спасибо, что заметили. Кстати, это можно увидеть в действии здесь (экспериментальный компилятор; может потребоваться обновление страницы)
Луис Мендо
3

Mathematica 86 байт

{1,-1}
r=Reverse;Graphics@Line@Nest[Join[l=Last@#;h=#-l&/@#,r[r@#%&/@h]]&,{{0,0},%},9]

Как это работает: {1,-1}выходы {1,-1}. Это в основном "толкает его в стек". Это значение может быть вызвано с помощью %. r=Reverseв основном просто переименовывает функцию Reverse, потому что я использую ее дважды в коде. Graphics@Line@Просто принимает список точек и рисует линию , соединяющую их. Реальное мясо проблемы происходит в этом сегменте кода: Nest[Join[l=Last@#;h=#-l&/@#,r[r@#%&/@h]]&,{{0,0},%},9]. Позвольте мне сказать вам - этот сегмент сложен как f ****** ск. Вот что Nestделает: Nest[f,x,9]выводит результат вызова f[f[f[f[f[f[f[f[f[x]]]]]]]]].

В моем коде, это первый аргумент fявляется: Join[l=Last@#;h=#-l&/@#,r[r@#%&/@h]]&вторым аргументом xявляется {{0,0},%}(который имеет значение {{0,0},{1,-1}}), а третий аргумент n, который только 9 (который будет просто применить первый аргумент ко второму аргументу в 9 раз).

Самая сложная часть всего этого - первый аргумент: Join[l=Last@#;h=#-l&/@#,r[r@#%&/@h]]&гигантский беспорядок из почти чистого синтаксического сахара. Я действительно злоупотреблял синтаксическим сахаром Mathematica для этого. Эта строка кода представляет версию анонимной функции Mathematica, за исключением того, что для сокращения вещей я фактически определил две отдельные анонимные функции в этой анонимной функции. Да, это законно, ребята. Давайте разберемся с этим.

Joinпринимает два аргумента. Первый есть l=Last@#;h=#-l&/@#, а второй есть r[r@#%&/@h].

Первый аргумент Join: внутри «основной» анонимной функции #- список всех точек на текущей итерации кривой. Так l=Last@#;означает «Возьмите точку в списке точек, которые вы получили в качестве входных данных, и назначьте эту точку переменной l. Следующий сегмент h=#-l&/@#немного сложнее. Это означает:« У вас есть функция. Эта функция принимает точку в качестве входных данных, вычитает lиз нее и возвращает результат. Теперь примените эту функцию к каждому элементу в списке точек, которые вы получили в качестве входных данных, чтобы создать список смещенных точек, и назначьте этот новый список переменной h.

Второй аргумент Join: r[r@#%&/@h] буквально самый сложный синтаксис, который я когда-либо писал. Я не могу поверить, что любой сегмент кода может содержать что-то вроде @#%&/@- похоже, я проклинаю как персонаж мультфильма в середине программы! Но это можно сломать. Помните - r[x]берет список точек и возвращает этот список в обратном порядке. r@#%&является анонимной функцией, которая инвертирует свой ввод, затем умножает его на значение, хранящееся в %(что есть {1,-1}), и возвращает результат. По сути, он поворачивает свои входные данные на 90 градусов, но в коде настолько коротком, насколько я мог бы написать. Затем r@#%&/@hозначает «Вывести новый список, каждая точка которого hповернута на 90 градусов».

Таким образом, в целом, Join[l=Last@#;h=#-l&/@#,r[r@#*%&/@h]]&это функция, которая принимает список точек в качестве входных данных и добавляет к тому же списку точек, повернутых на 90 градусов, чтобы получить следующую итерацию кривой. Это повторяется 9 раз, чтобы получить кривую дракона. Затем это результирующий список точек рисуется на экране в виде линии. И вывод:

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

Х. Антонио Перес
источник
3
Я только что нашел самый странный трюк для записи нулевого вектора: 0{,}... работает, потому что 0 xэто 0почти для любого xи {,}является синтаксическим сахаром для {Null,Null}.
Мартин Эндер
3

Python 2, 43 байта

Этот ответ составляет 43 байта без учета оператора импорта, и в основном он основан на ответе логотипа Level River St и их использовании i/(i&-i)в коде. Попробуйте онлайн на trinket.io

from turtle import*
for i in range(1,513):fd(9);rt(90*i/(i&-i))

Вот картина выхода.

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

Sherlock9
источник
Насколько я знаю, вам нужно включить количество байтов из оператора импорта в общее количество байтов.
Тео
1
@Theo, просто цитирую из спецификации вызова:The shortest code in bytes wins, however include directives for libraries shouldn't be included in the byte count, and you may use graphics libraries or other libraries written for your language of choice if they were written before the posting.
Sherlock9
3

Mathematica, 56 55 байт

Graphics@Line@AnglePath[Pi/2JacobiSymbol[-1,Range@512]]

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

Объяснение: OEIS A034947

Просто для удовольствия, вот цветная версия 19-й итерации.

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

alephalpha
источник
2

Mathematica, 63 байта

С помощью AnglePath

Graphics@Line@AnglePath[Pi/2Nest[Join[#,{1},-Reverse@#]&,{},9]]

Девять итераций

Симмонс
источник
1

HTML + JavaScript, 182

<canvas id=C></canvas><script>c=C.getContext("2d")
C.width=C.height=400
s=n=9
x=y=200
for(i=d=0;i<=1<<n;d+=++i/(i&-i))
c.lineTo(x,y),
d&1?y+=d&2?s:-s:x+=d&2?-s:s
c.stroke()</script>

edc65
источник
0

Haskell + диаграммы, 179 байт

import Diagrams.Prelude
import Diagrams.Backend.SVG
d 1=hrule 1<>vrule 1
d n=d(n-1)<>d(n-1)#reverseTrail#rotateBy(1/4)
main=renderSVG"d"(mkWidth 99)$strokeT(d 9::Trail V2 Double)

Выходные данные - это SVG-файл шириной 99 пикселей с прозрачным фоном (изображение шириной 9 пикселей будет иметь слишком толстый штрих, чтобы что-либо пересчитать). Здесь он масштабируется и составляется на белом фоне:

Дракон номер девять

Angs
источник
0

tosh , 518 байт

tosh - это Scratch , но с текстом вместо блоков. В 518 байт этот ответ, вероятно, даже хуже, чем Java.

Этот ответ использует ту же логику, что и и ответ @ Theo's Python , но со строками «L» и «R» вместо чисел, поскольку возможности списка Царапина (и, следовательно, tosh) ужасны.

Вы можете запустить его как Scratch проект здесь . (tosh компилируется в проекты Scratch)

when flag clicked
set path to "R"
go to x: -50 y: 100
point in direction 90
pen down
set pen size to 2
clear
repeat 9
    set path copy to path
    set path to join (path) "R"
    set i to length of path copy
    repeat length of path copy
        if letter i of path copy = "R" then
            set path to join (path) "L"
        else
            set path to join (path) "R"
        end
        change i by -1
    end
end
set i to 0
repeat length of path
    change i by 1
    if letter i of path = "R" then
         turn cw 90 degrees
    else
         turn ccw 90 degrees
    end
    move 7 steps
end  

Объяснение:

when flag clicked
set path to "R"
go to x: -50 y: 100
point in direction 90
pen down
set pen size to 2
clear

В этой первой части программа запускается при нажатии зеленого флажка ( when flag clicked), задает для переменной пути значение «R» и возвращает спрайт и сцену в надлежащее состояние для подготовки к рисованию.

repeat 9
    set path copy to path
    set path to join (path) "R"
    set i to length of path copy
    repeat length of path copy
        if letter i of path copy = "R" then
            set path to join (path) "L"
        else
            set path to join (path) "R"
        end
        change i by -1
    end
end

Теперь перейдем к коду генерации пути. Он использует ту же логику, что и ответ @ Theo's Python , за исключением строк «R» и «L» вместо чисел, и мы используем вложенные циклы вместо списочных представлений.

set i to 0
repeat length of path
    change i by 1
    if letter i of path = "R" then
         turn cw 90 degrees
    else
         turn ccw 90 degrees
    end
    move 7 steps
end  

Наконец, мы рисуем путь, проходя каждую букву переменной пути и поворачивая влево или вправо в зависимости от буквы.

BookOwl
источник