L-system: Difference between revisions

Content deleted Content added
PureFox (talk | contribs)
Jjuanhdez (talk | contribs)
 
(22 intermediate revisions by 9 users not shown)
Line 1:
{{draft task}}
{{alertbox|Fōrmulæ|Duplicate of [[Koch_curve]]}}
 
;Introduction
Line 86:
 
:* Wikipedia: [[wp:L-system|L-system]]
 
=={{header|ALGOL 68}}==
{{libheader|ALGOL 68-l-system}}
Note, the Algol 68 L-System library source code is on a separate page on Rosetta Code - follow the above link and then to the Talk page.
<syntaxhighlight lang="algol68">
BEGIN # Example of L-System evaluation and interpretation #
 
PR read "lsystem.incl.a68" PR # include L-System utilities #
 
# task rabbit population example #
LSYSTEM rabbit population = ( "I", ( "I" -> "M"
, "M" -> "MI"
)
);
INT young := 0, old := 0;
STRING result = rabbit population EVAL 5;
result INTERPRET ( ( CHAR c )VOID: IF c = "I" THEN young +:= 1 ELSE old +:= 1 FI );
 
print( ( "After 5 iterations there are ", whole( old, 0 ), " old rabbits and "
, whole( young, 0 ), " young ones (", result, ")", newline
)
)
 
END
</syntaxhighlight>
{{out}}
<pre>
After 5 iterations there are 5 old rabbits and 3 young ones (MIMMIMIM)
</pre>
 
=={{header|BASIC}}==
==={{header|Applesoft BASIC}}===
The [[#GW-BASIC|GW-BASIC]] solution works without any changes.
 
==={{header|BASIC256}}===
<syntaxhighlight lang="vbnet">rabbit_population$ = "I"
young = 0
old = 0
 
for i = 1 to 5
new_population$ = ""
for j = 1 to length(rabbit_population$)
t$ = mid(rabbit_population$, j, 1)
begin case
case t$ = "I"
new_population$ += "M"
case t$ = "M"
new_population$ += "MI"
end case
next j
rabbit_population$ = new_population$
next i
 
for i = 1 to length(rabbit_population$)
t$ = mid(rabbit_population$, i, 1)
begin case
case t$ = "I"
young += 1
case t$ = "M"
old += 1
end case
next i
 
print "After 5 iterations there are "; old; " old rabbits and "; young; " young ones ("; rabbit_population$; ")"</syntaxhighlight>
{{out}}
<pre>After 5 iterations there are 5 old rabbits and 3 young ones (MIMMIMIM)</pre>
 
==={{header|Chipmunk Basic}}===
{{works with|Chipmunk Basic|3.6.4}}
<syntaxhighlight lang="vbnet">100 cls
110 rabbit_population$ = "I"
120 young = 0
130 old = 0
140 for i = 1 to 5
150 new_population$ = ""
160 for j = 1 to len(rabbit_population$)
170 select case mid$(rabbit_population$,j,1)
180 case "I"
190 new_population$ = new_population$+"M"
200 case "M"
210 new_population$ = new_population$+"MI"
220 end select
230 next j
240 rabbit_population$ = new_population$
250 next i
260 for i = 1 to len(rabbit_population$)
270 select case mid$(rabbit_population$,i,1)
280 case "I"
290 young = young+1
300 case "M"
310 old = old+1
320 end select
330 next i
340 print "After 5 iterations there are ";old;"old rabbits and ";young;"young ones (";rabbit_population$;")"
350 end</syntaxhighlight>
{{out}}
<pre>After 5 iterations there are 5 old rabbits and 3 young ones (MIMMIMIM)</pre>
 
==={{header|Gambas}}===
{{trans|FreeBASIC}}
<syntaxhighlight lang="vbnet">Public rules As String[] = ["I", "M", "M", "MI"]
 
Public Sub Main()
Dim s As String = "I"
Dim count As Integer = 5
For i As Integer = 0 To count
Print s
Dim nxt As String = ""
Dim j As Integer = 0
While j < Len(s)
Dim c As String = Mid(s, j + 1, 1)
Dim found As Boolean = False
Dim k As Integer = 0
While k <= rules.Max And Not found
If c = rules[k] Then
Dim rep As String = rules[k + 1]
found = True
Endif
k += 2
Wend
nxt &= If(found, rep, c)
j += 1
Wend
s = nxt
Next
End </syntaxhighlight>
{{out}}
<pre>Same as FreeBASIC entry.</pre>
 
==={{header|GW-BASIC}}===
{{works with|PC-BASIC|any}}
{{works with|BASICA}}
{{works with|Applesoft BASIC}}
{{works with|Chipmunk Basic}}
{{works with|QBasic}}
{{works with|MSX BASIC}}
<syntaxhighlight lang="qbasic">110 R$ = "I"
120 Y = 0
130 O = 0
140 FOR I = 1 TO 5
150 P$ = ""
160 FOR J = 1 TO LEN(R$)
170 IF MID$(R$,J,1) = "I" THEN P$ = P$ + "M"
180 IF MID$(R$,J,1) = "M" THEN P$ = P$ + "MI"
190 NEXT J
200 R$ = P$
210 NEXT I
220 FOR I = 1 TO LEN(R$)
230 IF MID$(R$,I,1) = "I" THEN Y = Y+1
240 IF MID$(R$,I,1) = "M" THEN O = O+1
250 NEXT I
260 PRINT "After 5 iterations there are"; O; " old rabbits and"; Y; " young ones ("; R$; ")"
270 END</syntaxhighlight>
{{out}}
<pre>After 5 iterations there are 5 old rabbits and 3 young ones (MIMMIMIM)</pre>
 
==={{header|MSX Basic}}===
{{works with|MSX BASIC|any}}
The [[#GW-BASIC|GW-BASIC]] solution works without any changes.
 
==={{header|QBasic}}===
{{works with|QB64}}
{{works with|QBasic|1.1}}
{{works with|QuickBasic|4.5}}
<syntaxhighlight lang="qbasic">DECLARE SUB Lindenmayer (s AS STRING, rules() AS STRING, count AS INTEGER)
DIM rules(3) AS STRING
rules(0) = "I"
rules(1) = "M"
rules(2) = "M"
rules(3) = "MI"
 
CALL Lindenmayer("I", rules(), 5)
END
 
SUB Lindenmayer (s AS STRING, rules() AS STRING, count AS INTEGER)
DIM i AS INTEGER, j AS INTEGER, k AS INTEGER, found AS INTEGER
DIM t AS STRING, nxt AS STRING, c AS STRING, rep AS STRING
 
FOR i = 0 TO count
PRINT s
nxt = ""
FOR j = 1 TO LEN(s)
c = MID$(s, j, 1)
found = 0
FOR k = LBOUND(rules) TO UBOUND(rules) STEP 2
IF c = rules(k) THEN
rep = rules(k + 1)
found = -1
EXIT FOR
END IF
NEXT k
IF found = -1 THEN t = rep ELSE t = c
nxt = nxt + t
NEXT j
s = nxt
NEXT i
END SUB</syntaxhighlight>
{{out}}
<pre>After 5 iterations there are 5 old rabbits and 3 young ones (MIMMIMIM)</pre>
 
==={{header|QB64}}===
The [[#QBasic|QBasic]] solution works without any changes.
 
==={{header|XBasic}}===
{{works with|Windows XBasic}}
<syntaxhighlight lang="qbasic">PROGRAM "L-system"
VERSION "0.0001"
 
DECLARE FUNCTION Entry ()
 
FUNCTION Entry ()
rabbit_population$ = "I"
young = 0
old = 0
 
FOR i = 1 TO 5
new_population$ = ""
FOR j = 1 TO LEN(rabbit_population$)
SELECT CASE MID$(rabbit_population$, j, 1)
CASE "I"
new_population$ = new_population$ + "M"
CASE "M"
new_population$ = new_population$ + "MI"
END SELECT
NEXT j
rabbit_population$ = new_population$
NEXT i
 
FOR i = 1 TO LEN(rabbit_population$)
SELECT CASE MID$(rabbit_population$, i, 1)
CASE "I"
INC young
CASE "M"
INC old
END SELECT
NEXT i
 
PRINT "After 5 iterations there are "; old; " old rabbits and "; young; " young ones ("; rabbit_population$; ")"
END FUNCTION
END PROGRAM</syntaxhighlight>
{{out}}
<pre>After 5 iterations there are 5 old rabbits and 3 young ones (MIMMIMIM)</pre>
 
==={{header|Yabasic}}===
<syntaxhighlight lang="vb">rabbit_population$ = "I"
young = 0
old = 0
 
for i = 1 to 5
new_population$ = ""
for j = 1 to len(rabbit_population$)
switch mid$(rabbit_population$, j, 1)
case "I"
new_population$ = new_population$ + "M"
case "M"
new_population$ = new_population$ + "MI"
end switch
next j
rabbit_population$ = new_population$
next i
 
for i = 1 to len(rabbit_population$)
switch mid$(rabbit_population$, i, 1)
case "I"
young = young + 1
case "M"
old = old + 1
end switch
next i
 
print "After 5 iterations there are", old, " old rabbits and", young, " young ones (", rabbit_population$, ")"</syntaxhighlight>
{{out}}
<pre>After 5 iterations there are 5 old rabbits and 3 young ones (MIMMIMIM)</pre>
 
=={{header|C++}}==
{{trans|FreeBASIC}}
<syntaxhighlight lang="cpp">#include <iostream>
#include <map>
#include <string>
 
using namespace std;
 
void lindenmayer(string s, map<char, string> rules, int count) {
for (int i = 0; i < count; ++i) {
cout << s << endl;
string nxt = "";
for (char c : s) {
if (rules.find(c) != rules.end()) {
nxt += rules[c];
} else {
nxt += c;
}
}
s = nxt;
}
}
 
int main() {
map<char, string> rules = {{'I', "M"}, {'M', "MI"}};
lindenmayer("I", rules, 5);
return 0;
}</syntaxhighlight>
{{out}}
<pre>I
M
MI
MIM
MIMMI</pre>
 
=={{header|Dart}}==
{{trans|C++}}
<syntaxhighlight lang="dart">void lindenmayer(String s, Map<String, String> rules, int count) {
for (int i = 0; i < count; ++i) {
print(s);
String nxt = "";
for (int j = 0; j < s.length; ++j) {
String c = s[j];
nxt += rules.putIfAbsent(c, () => c);
}
s = nxt;
}
}
 
void main() {
var rules = {"I": "M", "M": "MI"};
lindenmayer("I", rules, 5);
}</syntaxhighlight>
{{out}}
<pre>Same as C++ entry.</pre>
 
=={{header|FreeBASIC}}==
L-system functionality as a Role that may be mixed in to a scalar.
 
<syntaxhighlight lang="vbnet">Sub Lindenmayer(s As String, rules() As String, count As Integer)
Dim As Integer i, j, k, found
Dim As String nxt, c, rep
For i = 0 To count
Print s
nxt = ""
For j = 1 To Len(s)
c = Mid(s, j, 1)
found = 0
For k = Lbound(rules) To Ubound(rules) Step 2
If c = rules(k) Then
rep = rules(k + 1)
found = 1
Exit For
End If
Next k
nxt &= Iif(found = 1, rep, c)
Next j
s = nxt
Next i
End Sub
 
Dim As String rules(3) = {"I", "M", "M", "MI"}
Lindenmayer("I", rules(), 5)
 
Sleep</syntaxhighlight>
{{out}}
<pre>I
M
MI
MIM
MIMMI
MIMMIMIM</pre>
Also see:</br>
[[Dragon_curve#FreeBASIC]]</br>
[[Hilbert_curve#FreeBASIC]]</br>
[[Koch_curve#FreeBASIC]]</br>
[[Peano_curve#FreeBASIC]]</br>
[[Penrose_tiling#FreeBASIC]]</br>
[[Sierpinski_curve#FreeBASIC]]</br>
[[Sierpinski_arrowhead_curve#FreeBASIC]]</br>
[[Sierpinski_square_curve#FreeBASIC]]</br>
among others...
 
=={{header|F_Sharp|F#}}==
Line 104 ⟶ 483:
MIMMIMIM
</pre>
 
=={{header|Fōrmulæ}}==
 
Line 122 ⟶ 502:
[[File:Fōrmulæ - L-system 03.png]]
 
'''Test case 1. Koch's snowflake'''
 
[[File:Fōrmulæ - L-system - Koch's snowflake 01.png]]
 
[[File:Fōrmulæ - L-system - Koch's snowflake 02.png]]
 
'''Test case 2. Sierpiński curve'''
 
[[File:Fōrmulæ - L-system - Sierpiński curve 01.png]]
 
[[File:Fōrmulæ - L-system - Sierpiński curve 02.png]]
 
'''Test case 3. Peano curve'''
 
[[File:Fōrmulæ - L-system - Peano Curve 01.png]]
 
[[File:Fōrmulæ - L-system - Peano Curve 02.png]]
 
'''Test case 4. Hilbert curve'''
 
[[File:Fōrmulæ - L-system - Hilbert curve 01.png]]
 
[[File:Fōrmulæ - L-system - Hilbert curve 02.png]]
 
 
=={{header|Julia}}==
Julia has the Lindenmeyer.jl package downloadable via the package manager in the usual fashion.
<syntaxhighlight lang="julia">using Lindenmayer
 
scurve = LSystem(Dict("F" => "F+F--F+F"), "8F--F--F") # 8 sets stroke width to 8 px
drawLSystem(scurve,
forward = 16,
turn = 60,
startingx = -200,
startingy = 100,
iterations = 3,
backgroundcolor = "white",
filename = "kochsnow.png",
showpreview = true
)
 
</syntaxhighlight>{{out}}
[[File:Kochsnowflakefractal.png|thumb|center|alt=fractal image|Koch Snowflake]]
 
=={{header|Phix}}==
Just the generic part:
<syntaxhighlight lang="phix">
function lindenmayer(string s, sequence rules, integer count)
sequence {chars, reps} = columnize(rules)
for i=1 to count do
string nxt = ""
for c in s do
integer k = find(c,chars)
nxt &= iff(k?reps[k]:c)
end for
s = nxt
end for
return s
end function
</syntaxhighlight>
Invoke using eg <code><nowiki>lindenmayer("I",{{'I',"M"},{'M',"MI"}},5)</nowiki></code> which yields "MIMMIMIM"
 
=={{header|Python}}==
{{works with|Python|3.x}}
{{trans|FreeBASIC}}
<syntaxhighlight lang="python">#! /usr/bin/env python3
 
def lindenmayer(s, rules, count):
for i in range(count):
print(s)
nxt = ""
for c in s:
found = False
for j in range(0, len(rules), 2):
if c == rules[j]:
rep = rules[j + 1]
found = True
break
nxt += rep if found else c
s = nxt
 
rules = ["I", "M", "M", "MI"]
lindenmayer("I", rules, 5)</syntaxhighlight>
{{out}}
<pre>I
M
MI
MIM
MIMMI</pre>
 
=={{header|Quackery}}==
This solution reproduces the method used in other, pre-existing, tasks including [[Cantor set#Quackery|Cantor set]], [[Hilbert curve#Quackery|Hilbert curve]], [[Padovan sequence#Quackery|Padovan sequence]], [[Peano curve#Quackery|Peano curve]], [[Sierpinski curve#Quackery|Sierpinski curve]], and [[Sierpinski square curve#Quackery|Sierpinski square curve]].
 
The alphabet is a set of single character (of necessity) Quackery words, which are uppercase by convention (to distinguish them from, and avoid conflict with, other Quackery words, which are exclusively lowercase by convention.)
 
Rules are Quackery words in the alphabet which return a string as a result. The word <code>expand</code> takes an axiom (a string of rules) and applies the rule associated with each character sequentially and concatenates the returned strings. In other words it performs a single iteration of the L-system. The word <code>times</code> can be used to perform a specified number of iterations.
 
This example illustrates this method for the life cycle of the Gallifreyan Fibonacci Rabbit, which lives forever, matures after the first cycle, and thereafter [https://tardis.fandom.com/wiki/Bi-generation bi-generates], producing a single kitten (i.e. an immature rabbit) on every cycle.
 
<syntaxhighlight lang="Quackery"> [ $ "" swap witheach
[ nested quackery join ] ] is expand ( $ --> $ )
 
[ $ "M" ] is I ( --> $ )
[ $ "MI" ] is M ( --> $ )
 
$ "I" 5 times expand echo$</syntaxhighlight>
 
{{out}}
 
<pre>MIMMIMIM</pre>
 
Interpreting the resulting string is implemented by stepping through each character of the string and applying the actions associated with each character in the alphabet. In most of the tasks listed above this is achieved with the Quackery equivalent of a switch statement. Here, the action is to increment either a count of the number of mature rabbits, or the number of kittens, both of which are maintained on the stack, so <code>char I = if dip 1+</code> is sufficient.
 
<syntaxhighlight lang="Quackery"> [ 0 0 rot witheach
[ char I = if dip 1+ ]
say "Rabbits: " echo cr
say "Kittens: " echo cr ] is countrabbits ( $ --> )
 
$ "I" 5 times expand countrabbits</syntaxhighlight>
 
{{out}}
 
<pre>Rabbits: 5
Kittens: 3</pre>
 
=={{header|Raku}}==
L-system functionality as a Role that may be mixed in to a scalar.
 
<syntaxhighlight lang="raku" line># L-system functionality
role Lindenmayer {
has %.rules;
method succ {
self.comb.map( { %!rules{$^c} // $c } ).join but Lindenmayer(%!rules)
}
}
 
# Testing
my $rabbits = 'I' but Lindenmayer({I => 'M', M => 'MI'});
 
.say for $rabbits++ xx 6;</syntaxhighlight>
{{out}}
<pre>I
M
MI
MIM
MIMMI
MIMMIMIM</pre>
 
Also see:</br>
[[Dragon_curve#Raku]]</br>
[[Hilbert_curve#Raku]]</br>
[[Koch_curve#Raku]]</br>
[[Peano_curve#Raku]]</br>
[[Penrose_tiling#Raku]]</br>
[[Sierpinski_curve#Raku]]</br>
[[Sierpinski_arrowhead_curve#Raku]]</br>
[[Sierpinski_square_curve#Raku]]</br>
among others...
 
=={{header|RPL}}==
≪ SWAP → rules
≪ 1 SWAP '''FOR''' a
→ in
≪ ""
1 in '''FOR''' b
in b DUP SUB
1 rules SIZE '''FOR''' c
rules c GET
'''IF''' DUP2 1 GET == '''THEN'''
SWAP DROP 2 GET
rules SIZE 'c' STO
'''ELSE''' DROP '''END'''
'''NEXT'''
+
'''NEXT'''
'''NEXT'''
≫ ≫ ´<span style="color:blue">LSYS</span>' STO
 
"I" {{"I" "M"} {"M" "MI"}} 5 <span style="color:blue">LSYS</span>
{{out}}
<pre>
1: "MIMMIMIM"
</pre>
 
=={{header|Wren}}==
{{libheader|DOME}}
{{libheader|Wren-lsystem}}
{{libheader|Wren-fmt}}
The source code for the Wren-lsystem module is available on this site by clicking the above link and then navigating to the Talk page.
 
We can use this to generate the results for the rabbit population example as follows.
<syntaxhighlight lang="wren">import "./lsystem" for LSystem, Rule
import "./fmt" for Fmt
 
var lsys = LSystem.new(
["I", "M"], // variables
[], // constants
"I", // axiom
[ // rules
Rule.new("I", "M"),
Rule.new("M", "MI")
]
)
 
System.print("Step String")
System.print("---- --------")
var steps = lsys.listSteps(5)
for (i in 0..5) Fmt.print("$-4d $8m", i, steps[i])</syntaxhighlight>
 
{{out}}
<pre>
Step String
---- --------
0 I
1 M
2 MI
3 MIM
4 MIMMI
5 MIMMIMIM
</pre>
 
{{libheader|DOME}}
We can also use it to draw a curve such as the Koch Snowflake.
<syntaxhighlight lang="wren">import "graphics" for Canvas, Color
import "dome" for Window
Line 139 ⟶ 732:
var TwoPi = Num.pi * 2
 
class SierpinskiSquareCurveKochSnowflake {
construct new(width, height, back, fore) {
Window.title = "Koch Snowflake"
Line 187 ⟶ 780:
}
 
var Game = SierpinskiSquareCurveKochSnowflake.new(400, 400, Color.blue, Color.yellow)</syntaxhighlight>
 
{{out}}