"Вибачте, юначе, але це черепахи аж донизу!"


21

Виконати систему Lindenmayer

Система Lindenmayer (або L-система) пов'язана з системами Thue and Post і використовується в ботанічному моделюванні та генерації фрактала .

L-система описується перезаписом рядків, де символ із символу-алфавіту відображається в послідовності заміни символів. Колекція цих відображень становить належну L-систему.

Метод графічного виведення, розроблений Прусінкевичем, інтерпретує отриману послідовність після того, як відображення було застосовано до початкової послідовності для визначеної кількості ітерацій , як команди «Черепаха-малювання»: вперед, назад, вліво, вправо, такі речі. Це може потребувати додаткового коду для управління масштабом малюнка, оскільки різні кількості ітерацій можуть створювати зображення різного розміру.

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

Розгалуження стебел Крива дракона

Це код гольфу.

Редагувати: Ось кілька прикладів, які я розмістив по місту. відповідь на SO / повернути на північ { Де я вперше виявив L-систему } , відповідь на SO / how-to-to-program-a-fractal , відповідь на SO / recursion-in-postscript , comp.lang.postscript обговорення / декламація , колекція постскрипту l-системи , codegolf.SE/draw-a-sierpinski-triangle {походження конкуренції між собою та thomasW} .


Пропустив пісочницю. Це здається досить простим і має бути цікавим.
luser droog

До речі, хтось знає походження зазначеної цитати? Я чув Вільяма Джеймса і чув Фарадея.
luser droog

1
Вікіпедія говорить, що походження суперечить, найкраще здогадується Бертран Рассел.
ugoren

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

1
Чи існують обмеження щодо розміру алфавіту, кількості правил, кількості раундів чи можливих (візуалізація) правил (намалюйте пряму лінію, натисніть / попс / кут, поверніть на скільки градусів тощо). Якщо нам потрібно лише намалювати ці два тоді нам знадобиться натискання та вискакування, малювання прямих ліній та можливість повернення на 45 градусів в обох напрямках, лише два правила та алфавіт розміром 4.
shiona

Відповіді:


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)

Де:

i: Початковий стан;
b: кут повороту
h: початковий кут
j: початкове положення
r: виробничі правила
n: ітерації

Граматика правил виробництва:

2 = повернути вліво (-);
4 = поверніть праворуч (+);
6 = натисніть і поверніть ліворуч ("[");
8 = Повернути і повернути праворуч ("]");
C [i] = Намалюйте (Будь-яка кількість символів)
Будь-який інший символ = Не робіть нічого, просто використовуйте його для створення наступного стану (Будь-яка кількість символів)

Послідовність {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 Ні, але сміливо використовуйте його, якщо ви думаєте, що варто докласти зусиль
доктор Белісарій,


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)}

Читання (ish):

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

Un- "бінарний".

[/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]

фрактал3


1
Дуже гарна. Але хіба це не збереже кілька байт, щоб передати це правило як аргумент?
luser droog

Якби це загальне рішення, можливо, можна було б прийняти правило, а не параметри. Мені довелося б бути більш обізнаним про системи Lindenmayer, ніж я зараз.
DavidC

Я не читаю математику. Я повинен піти вивчити деякі. (додайте його до стеку :) Але ви можете інтерпретувати це, щоб означати, "що є описом зображення, на відміну від двигуна, який його приводить в дію", може бути розроблено. Якщо ви можете змінити дані, щоб керувати деякою особливістю зображення, незалежно від належного торкання двигуна ; Я вважаю, що це "функціонально еквівалентне" L-системі. [ Це має дати вам багато лазівки для роботи;) ]. +1 у будь-якому випадку, тому що це дуже красиво.
luser droog

1
@dude Я думаю, це тому, що вимоги до графіки для них не дуже підходять
доктор belisarius

1
Нарешті з’ясував l-систему для вашого дерева: A->F[+A][-A]де Fрухається, +повернути ліворуч на 30, -повернути праворуч на 30, і [/ ]є push / pop
Shmiddty
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.