«Извините, молодой человек, но это Черепахи!»


21

Выполнить систему Lindenmayer

Система Линденмайера (или L-система) связана с системами Thue и Post и используется в ботаническом моделировании и генерации фракталов .

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

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

Ваша задача - выполнить L-систему с наименьшим количеством символов. Ваша программа должна иметь возможность отображать как кривую Дракона, так и ветвящиеся стебли со страницы Википедии, предоставляя соответствующий ввод (файл, командная строка, но внешний по отношению к источнику, пожалуйста).

Ветвящиеся стебли Кривая Дракона

Это код гольф.

Изменить: Вот несколько примеров, которые я разместил в городе. ответ на SO / rotate-to-north { Где я впервые обнаружил L-систему } , ответ на SO / how-to-program-a-fractal , ответ на SO / recursion-in-postscript , обсуждение comp.lang.postscript / концерт , приписка коллекция л-система , codegolf.SE/draw-a-sierpinski-triangle {происхождение конкуренции между собой и thomasW} .


Пропустил песочницу. Это кажется относительно простым и должно быть весело.
luser droog

Кстати, кто-нибудь знает происхождение приведенной выше цитаты? Я слышал Уильяма Джеймса и слышал Фарадея.
luser droog

1
Википедия говорит , что происхождение в споре, догадка Бертран Рассел.
Угорен

ITYM Бертран Рассел .
Пол Р

1
Существуют ли какие-либо ограничения на размер алфавита, количество правил, количество раундов или возможных (визуализация) правил (нарисуйте прямую линию, толчок / положение / угол поворота, поворот на сколько градусов и т. Д.) Если нам нужно только нарисовать эти два, тогда нам нужно будет нажимать и выталкивать, рисовать прямые линии и иметь возможность поворачиваться на 45 градусов в обоих направлениях, только два правила и алфавит размера 4.
Шион

Ответы:


31

Mathematica 200 198 188 171 168

Пробелы добавлены для ясности:

f[i_, b_, h_, j_, r_, n_] :=
 (a = h; p = j; s = k = {}; t = Flatten;
  (Switch[#,
      6, s = {a, p, s},
      8, {a, p, s} = s,
      _C, k = {k, Line@{p, p += {Cos@a, Sin@a}}}];
     If[# < 9, a += I^# b ]) & /@ t@Nest[# /. r &, i, n];
  Graphics@t@k)

Где:

я: начальное состояние;
b: угол поворота
h: начальный угол
j: начальная позиция
r: производственные правила
n: итерации

Правила производства грамматики:

2 = повернуть налево (-);
4 = повернуть направо (+);
6 = Нажмите и поверните налево ("[");
8 = выскочить и повернуть направо ("]");
C [i] = Draw (любое количество символов).
Любой другой символ = ничего не делать. Просто используйте его для создания следующего состояния (любое количество символов).

Последовательность {2,4,6,8} есть, потому что я использую I^n( I= мнимая единица), чтобы совершать повороты.

Примеры:

f[{C[1], X}, Pi/2, 0, {0, 0}, {X -> {X, 4, Y, C[1]}, Y -> {C[1], X, 2, Y}}, 10]

Математическая графика

f[{C@1}, Pi/2, 0, {0,0}, {C@1->{C@1, 2, C@1, 4, C@1, 4, C@1, 2, C@1}}, 6]

Математическая графика

f[{C[1]}, Pi/4, Pi/2, {0, 0}, {C[2] -> {C[2], C[2]}, C[1] -> {C[2], 6, C[1], 8, C[1]}}, 10]

Математическая графика

f[{C[1]}, Pi/3, 0, {0, 0}, {C@1 -> {C@2, 4, C@1, 4, C@2}, C@2 -> {C@1, 2, C@2, 2, C@1}}, 10]

Математическая графика

f[{X},5/36 Pi, Pi/3, {0,0},{X->{C@1, 4, 6, 6, X, 8, 2, X, 8, 2, C@1, 6, 2, C@1, X, 8, 4, X},
                            C@1->{C@1, C@1}}, 6]

Математическая графика


Просто измените Graphics@k, Graphics@Flatten@kесли вы планируете использовать много итераций. В противном случае предел рекурсии укусит вас, и ваш сеанс Mma будет прерван.
Доктор Велизарий

У моего метода макроразложения была похожая проблема с более высокими итерациями. Струны просто становятся огромными. Но решение там не было, чтобы сгладить. :)
luser droog

2
+1 действительно очень приятно;) Может быть классная демонстрация. Вы отправляете это?
Виталий Кауров

@VitaliyKaurov Нет, но не стесняйтесь использовать его, если считаете, что оно того стоит
Dr. belisarius


9

Питон, 369 294

Не победитель, но я все равно опубликую то, что попробовал.

from turtle import*
I=open('l').read().split()
s,S,p=I[0],'',[]
for j in range(8):
    for i in s:S+=eval('{'+I[1]+'}')[i]
    s,S=S,''
for k in s:
    if k=='[':p+=[heading(),pos()];continue
    if k==']':pu();goto(p.pop());seth(p.pop());pd();continue
    try:{'f':fd,'F':fd,'+':rt,'-':lt}[k](5)
    except:pass

Не хорошо в игре в гольф на Python ...... Может быть, кто-то еще может это сделать.

вход

Входные данные поступают из внешнего файла с именем «l» (без расширения) в следующем формате:
строка 1 : начальное состояние (аксиома)
строка 2 : правила, разделенные запятыми

Символы
f и F: рисовать вперед
+: повернуть вправо на 5 градусов
-: повернуть влево на 5 градусов
[: сохранить положение и курс
]: всплывающее положение и курс
Другие символы игнорируются функцией рисования.

Правила
. Правило имеет формат. "predecessor":"successor(s)"
Обратите внимание, что кавычки необходимы, одинарные или двойные.
predecessorдолжен быть один символ.
Кроме того, не существует неявных констант: вы должны явно указать правило без изменений для них.

Примеры

Ветви стебли

------------------f
'-':'-','+':'+','[':'[',']':']','F':'FF','f':'F[+++++++++f]---------f'

Выходные данные

Обратите внимание, что источник изменен, чтобы вывести его, поместив ТОЛЬКО ДЛЯ МАСШТАБИРОВАНИЯ ВНЕШНЕЙ ГРАФИЧЕСКОЙ ОБЛАСТИ. Консоль также используется, чтобы скрыть «черепаху».

Кривая дракона

fx
'-':'-','+':'+','[':'[',']':']','f':'f','x':'x++++++++++++++++++yf','y':'fx------------------y'

Выходные данные

Снова консоль используется для скрытия «черепахи».

Треугольник Серпинского

f------------------------F------------------------F
'-':'-','+':'+','[':'[',']':']','f':'f------------------------F++++++++++++++++++++++++f++++++++++++++++++++++++F------------------------f','F':'FF'

Выходное

поколение уменьшено до 5 здесь.


3
Вы можете получить приличную экономию (я делаю это 32 символов), удалив функции f, r, l; добавление фиктивного параметра к oи c; а затем изменив псевдопереключатель на{'f':fd,'F':fd,'+':rt,'-':lt,'[':o,']':c}[k](5)
Питер Тейлор

Вы также можете встроить g, и я думаю, oи cстоит исключить с помощью встроенных ifзаявлений (дешевле, чем globalдекларация)
Питер Тейлор

@PeterTaylor хорошая работа. У меня была интуиция, что некоторые из этих функций могли быть встроены, но я не знал достаточно Python, чтобы предлагать это четко.
luser droog

1
@luserdroog, я тоже не знаю Python: я просто сделал метод проб и ошибок, чтобы посмотреть, что сработало - то есть некоторые вещи, которые я пробовал (например, используя лямбда-выражения для oи cнепосредственно в псевдопереключателе), давали синтаксические ошибки, но другие не делали ' т.
Питер Тейлор

Подсказки для дальнейшей игры в гольф: 1. Измените формат ввода: потребуйте скобки вокруг правил и отделите аксиому от правил пробелом (не переводом строки). 2. Чтение из стандартного ввода: s,R,*p=input().split(). 3. Генерация окончательного значения sпо exec('s="".join(map(eval(R).get,s));'*8). 4. Оставь в покое continue. 5. Отступ только на 1 пробел. 6. Сэкономьте место после if, переключив стороны для теста. 7. Установите k:intв dict(первой записи) , а затем вам не нужно except: try:. (Я получаю 215 символов.)
Восстановите Монику

7

Javascript (179 байт)

Не совсем уверен, что это подходит, так как объект правил выполняет весь фактический рисунок.

Демо (Дракон, анимация):
- Расширено: http://jsfiddle.net/SVkMR/9/show/light
- С Кодом: http://jsfiddle.net/SVkMR/9/

уменьшенная:

function L(c,r,n){o=(function g(d,s,o,i){for(o=i='';a=d&&s[i++];)o+=r.r[a]?g(d-1,r.r[a]):a;return o||s;})(n,r.r[r.s]);(function z(i){r[s=o[i]]&&r[s](c)||setTimeout(z,10,i+1)})(0)}

Читаемые (МОГ):

function L(c,r,n){
    o=(function g(d,s,o,i){
        for(o=i='';a=d&&s[i++];)o+=r.r[a]?g(d-1,r.r[a]):o+=a
        return o||s
    })(n,r.r[r.s]);

    (function p(i){
        r[s=o[i]]&&r[s](c)||setTimeout(p,10,i+1)
    })(0)
}

Входные данные:

var sierspinski = {
    r:{'A':'B-A-B','B':'A+B+A'},
    '+':function(c){c.rotate(-this.a);c.rotate(this.a-=Math.PI/3)},
    '-':function(c){c.rotate(-this.a);c.rotate(this.a+=Math.PI/3)},
    'A':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    'B':function(c){this['A'](c)},
    s:'A',
    a:0,
    m:1
};

var koch = {
    r: {'F':'F+F-F-F+F'},
    '+':function(c){c.rotate(-this.a);c.rotate(this.a-=Math.PI/2)},
    '-':function(c){c.rotate(-this.a);c.rotate(this.a+=Math.PI/2)},
    'F':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    s:'F',
    a:0,
    m:2
};
var dragon = {
    r: {'X':'X+YF','Y':'FX-Y'},
    '+':function(c){c.rotate(-this.a);c.rotate(this.a-=Math.PI/2)},
    '-':function(c){c.rotate(-this.a);c.rotate(this.a+=Math.PI/2)},
    'F':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    s:'X',
    a:0,
    m:5
};

var algae = {
    r: {'A':'B[A]A','B':'BB'},
    '[':function(c){c.save();c.rotate(Math.PI/4);},  // save/restore will push/pop current state of context. 
    ']':function(c){c.restore();c.rotate(-Math.PI/4);},
    'A':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    'B':function(c){this['A'](c);},
    s:'A',
    a:-Math.PI/2,
    m:1
};

var tree = {
    r:{'X':'F-[[X]+X]+F[+FX]-X','F':'FF'},
    '+':function(c){c.rotate(-this.a);c.rotate(this.a+=Math.PI/180*25)},
    '-':function(c){c.rotate(-this.a);c.rotate(this.a-=Math.PI/180*25)},
    '[':function(c){c.save();},
    ']':function(c){c.restore();},
    'F':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    s:'X',
    a:-Math.PI/180*25,
    m:5
};

Использование:

var ctx = document.getElementById('l').getContext('2d'); // grab context
ctx.translate(299.5,199.5); // start drawing from center, fractional pixels because the canvas draws lines centered on the x/y coord specified
L(ctx, dragon, 8); // pass in context, rules object, and recursion cap

Бонус: Золотая Спираль http://jsfiddle.net/SVkMR/35/show/light/

var golden = {
    r:{'A':'FT[TT]A','T':'+F'},
    'F':function(c){c.beginPath();c.moveTo(0,0);c.translate(this.m,0);c.lineTo(0,0);c.stroke()},
    '[':function(c){c.save();},
    ']':function(c){
        c.restore();

        c.beginPath();
        c.arc(0,-this.m,this.m,Math.PI/2,Math.PI);
        c.stroke();

        this.m+=this.d;this.d=this.m-this.d
    },
    '+':function(c){c.rotate(-Math.PI/2);},
    s:'A',
    a:-Math.PI/2,
    m:1,
    d:0
};

Я думаю, что анимация более чем компенсирует любые свободы с помощью правил. Отличная работа! +1
luser droog

:) Прикольные вещи! ,
Шмиддты

5

постскриптум 264 298 295 255

Вот моя попытка сделать это по-другому. Вместо того, чтобы использовать макро-расширение, которое я обычно использую, оно проверяет размер стека выполнения, чтобы ограничить рекурсию. Если предел превышен, он останавливает рекурсивное исследование процедуры и пытается интерпретировать команды черепахи (и игнорирует в pop popпротивном случае). Преимущество этого метода заключается в том, что он не требует огромных объемов памяти. Недостатком является то, что управление рекурсией является довольно неуклюжим, поскольку размер стека увеличивается более чем на 1 от одного уровня рекурсии к следующему.

Изменить: +34 символов для ветвления.
Изменить: -3 символа. Переработан для использования стека операндов для управления рекурсией. Это делает базовую систему намного проще. Но скобкам нужен независимый стек, поэтому я поместил сохраненную позицию в стек словаря и почти окупил все сбережения.

Кроме того, переработано использование строк и целых чисел вместо массивов и имен.

Изменить: -40 символов. Добавлены две процедуры для вызова системных имен по номеру (кажется, я не могу заставить работать необработанные двоичные токены. Но эта идиома работает для меня.)

/*{<920>dup 1 4 3 roll put cvx exec}def/${//* 73
*}def[/T[48{}49{}43{A<88>$}45{A<6e88>$}70{R
0<85>$}91{<1e39>$[/.[<286827>$]cvx>><0d0d>$}93{.<9c6b1e39390d>$}>>/S{dup
B eq{T<0d3e>${<643f>$}<4939>$}{exch{<643e>$ 1 add S}73 *}85 * 1 sub}>><0d6b>$
0 S<a7>$

Полукомментированный двоичный файл.

/*{<920>dup 1 4 3 roll put cvx exec}def/${//* 73 *}def %73=forall
[/T[70{R 0<85>$}48{}49{} %<85>=rlineto
43{A<88>$}45{A<6e88>$} %<88>=rotate <6e>=neg
91{<1e39>$ %<1e>=currentdict <39>=end
    [/.[<286827>$]cvx>> %<28>=currentpoint <68>=matrix <27>=currentmatrix
        <0d0d>$} %<0d>=begin
93{.<9c6b1e39390d>$}>> %<9c>=setmatrix <6b>=moveto
/S{dup B eq{T<0d3e>${<643f>$}<4939>$} %<3e>=exch <64>=load <3f>=exec <49>=forall
{exch{<643e>$ 1 add S}73 *}85 * 1 sub}>>
<0d6b>$ 0 S<a7>$  % 85=ifelse <a7>=stroke

Незамедленные «двоичный».

[/T[70{R 0 rlineto}48{}49{}43{A rotate}45{A neg rotate}91{currentdict
end[/.[currentpoint matrix currentmatrix]cvx>>begin begin}93{. setmatrix
moveto currentdict end end begin}>>/S{dup B eq{T begin exch{load exec}forall
end}{exch{load exch 1 add S}forall}ifelse 1 sub }>>begin moveto 0 S stroke

Это требует, чтобы L-система была определена в словаре на стеке диктов, с начальной строкой и начальной позицией черепахи в стеке операндов (с добавлением, например, источника gs dragon.sys lsys.ps).

Кривая Дракона.

%!
[                     %begin dictionary construction
    % productions are described by integer-key/string-value pairs
    48(0+1F) %0       %ascii code for '0' defined as the string "0+1F"
    49(F0-1) %1       %  "     "   "  '1'   "     "   "    "    "F0-1"
    43(+) %+          %  "     "   "  '+' defined as itself
    45(-) %-          %  "     "   "  '-'   "     "   "
    70(F) %F          %  "     "   "  'F'   "     "   "
    % parameters
    /A 90 %angle
    /R 2  %radius
    /B 10 %maximum recursion-level
>>begin  % L-system dictionary on top of dictstack
(F0)     % initial string on stack
300 400  % starting position on stack

Ветвящиеся стебли.

[
    48(F[+0]-0) %0
    49(F0-1) %1
    43(+) %+
    45(-) %-
    70(FF) %F
    91([) %[
    93(]) %]
    /A 45 %angle
    /R 5  %radius
    /B 3 %recursion
>>begin
(++0)     % initial string
300 400  % starting position

Разоблаченный и прокомментированный.

[                                 % begin dictionary construction
    /T[                           % /T is the Turtle dictionary containing
                                  % integer-key/procedure-value pairs
                                  % keyed to ascii values
        70{R 0 rlineto}        %F  
        48{}                   %0
        49{}                   %1  
        43{A rotate}           %+  
        45{A neg rotate}       %-  

          % For brackets, create a dictionary containing a single procedure '.' (dot)
          % which holds a saved matrix (orientation+size) and currentpoint.
          % Since this procedure is called while the Turtle dict is on top of the
          % dictstack, the temporary dictionary is placed just under the top.
        91{currentdict end[/.[currentpoint matrix currentmatrix]cvx>>begin begin} %[
          % Right bracket: reset position and orientation,
          % pop the dict just under the top.
        93{. setmatrix moveto currentdict end end begin}    %]  
    >>  
    /S{ % stack contains: string recursion-level
        dup B eq{ % hit recursion bound, interpret string as turtle commands
            T begin
                exch % level string
                %dup =
                {                      % iterate through string
                    load exec          % execute turtle command by integer code
                } forall % level       % string has been consumed
            end
            %(B)= pstack
        }{ % recurse
            %(A)= pstack
            exch % level string
            { % level char                   iterate through string
                load exch % string level   process production:load string by int code
                1 add S   % string level+1   increase level and call self
            } forall                       % string has been consumed
        }ifelse
        1 sub            % return level-1
        %(C)= pstack
    }
>>begin
moveto 0 S stroke

Чтобы запустить его, эти 3 блока можно сохранить в виде 3 файлов: dragon.ps, stems.ps, lsys.ps (любой из вышеперечисленных блоков программы будет работать одинаково). Затем запустите с gs: gs dragon.ps lsys.psили gs stems.ps lsys.ps. При желании их также можно объединить в первую очередь: cat dragon.ps lsys.ps | gs -или cat stems.ps lsys.ps | gs -.

кривая дракона

Нет стебля картины. Это не становится более интересным на более высоких глубинах.


4

Mathematica 290

Эта базовая реализация фокусируется на выводе, а не на обработке. Он не использует правила производства. Так что это может быть не подходящим ответом на вызов.

Ветвящиеся стебли адаптированы из демонстрации Тео Грея .

Код

f@{a_, b_} := {{a, #}, {b, #}} &[a + (b - a)/2 + {{0, 1/2}, {-1/2, 0}}.(b - a)]; w = Flatten;
h[s_, g_] :=Graphics[If[s == 0,Line /@ Nest[w[f /@ #, 1] &, {{{0, 0}, {1, 0}}}, g], 
 MapIndexed[Line@# &, NestList[w[Map[{{#[[2]], #[[2]] + m.(#[[2]] - #[[1]])}, {#[[2]], 
 #[[2]] + ({{1, -1}, {-1,1}} m).(#[[2]] - #[[1]])}} &, #], 1] &, {{{0, -1}, {0, 0}}}, g]]]]

использование

Первый параметр определяет, будут ли отображаться кривая дракона или стебли ветви. Второй термин относится к поколению.

h[0, 5]
h[1, 5]

вторая картинка


Больше примеров

GraphicsGrid@Partition[Flatten[Table[h[j, k], {j, 0, 1}, {k, 10}]], 5]

fractal3


1
Очень хорошенькая. Но не будет ли сэкономлено несколько байтов для передачи правила в качестве аргумента?
luser droog

Если бы это было общее решение, возможно, можно было бы передать правило, а не параметры. Я должен был бы быть более осведомленным о Lindenmayer Systems, чем сейчас.
DavidC

Я не читаю Mathematica. Я должен пойти учиться. (добавьте его в стек :) Но вы можете интерпретировать это так, что «все, что составляет описание изображения, в отличие от движка, который его приводит», может быть учтено. Если вы можете затем изменить данные для управления некоторыми функциями изображения, независимо от прикосновения к двигателю ; Я считаю, что это «функционально эквивалентно» L-системе. [ Это должно дать вам много лазеек для работы;) ]. +1 в любом случае, потому что это так красиво.
luser droog

1
@ Чувак, я думаю, это потому, что графические требования для них не очень подходят
доктор Белизариус,

1
Наконец, выяснили l-систему для вашего дерева: A->F[+A][-A]куда Fдвигаться, +повернуть влево на 30, -повернуть вправо на 30 и [/ ]толкнуть /
щелкнуть
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.