Python coding for Minecraft (8 / 17 steg)
Steg 8: L-systemet fraktaler med turtle grafik
Rita en triangel. Nu tar varje rad av triangeln och ersätta den med en linje med en triangulär bula på den. Upprepa. Som på den animerade bilden (offentligt område, baserat på
), får du en Koch snöflinga.
Detta kan modelleras av en Super-enkel sköldpadda-grafik-program. Tänk dig att F betyder "dra fram", och "+" och "-" stänga av 60 grader moturs och medurs, respektive. Sedan kan den ursprungliga triangeln dras genom:
F ++ F ++ F
Dvs, gå framåt, höger vid 120 grader, då gå framåt, vända precis vid 120 grader, gå framåt.
Den trekantiga bula linjen kan dras genom:
F-F ++ F F
Så är här hur vi kan generera en snöflinga. Vi tar initialen sköldpadda program F ++ F ++ F Rita en triangel. Varje F i det representerar en linje. Så ersätta varje F av F F ++ F F. Om vi håller på att gå, generera vi Koch snöflinga.
Detta är ett enkelt exempel på en L-systemet. Tanken bakom en L-systemet är att vi börjar med en teckensträng (i detta fall F ++ F ++ F), och sedan en massa regler hur man ändrar tecken (i detta fall en regel för att ersätta F med F-F ++ F F) i varje iteration. Vi tillämpar detta en massa gånger och vi får en ganska komplicerad sträng. Till exempel, efter två iterationer i snöflinga fallet får vi:
F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F
Efter fyra får vi bilden ovan. (Att verkligen få en fraktal, raderna ska krympa med varje iteration, men det brukar fungera i Minecraft.)
Det finns en hel del riktigt bra information i denna gratis PDF bok.
Jag skrev en mycket enkel lsystem.py modul. För att genomföra snöflinga, börja med standardtext:
importera lsystem
från turtle importera *
t = Turtle()
t.pendelay(0)
t.penblock(GOLD_BLOCK)
Nu måste vi fastställa regler. Jag definierar reglerna av en python ordbok:
regler = {'F': ' F F ++ F F "}
Nästa definierar vi axiom eller startpunkt:
axiom = "F ++ F ++ F'
Slutligen måste vi berätta systemet vad var och en av symbolerna i strängar betyder. För olika L-system, kommer vi tilldela olika betydelser till dem (rotationer av olika vinklar, till exempel). Därför behöver vi en andra python ordbok anger vad görs för varje symbol. Om du inte anger en åtgärd för en symbol, ignoreras en symbol när det är dags för sköldpaddan att dra utdata (men det kan vara viktigt för generationen). Betydelserna ges av en ordlista som anger en funktion att ringa för varje symbol. En rad funktioner kan anges med operatorn lambda . I det här fallet är alla funktioner one-liners:
ordbok = {
"F": lambda: t.go(2),
"+": lambda: t.yaw(60),
'-': lambda: t.yaw(-60)
}
Slutligen åberopa vi L-systemet, ange hur många iterationer (i detta fall 4):
lsystem.lsystem (axiom, regler, ordbok, 4)
Det finns ett speciellt trick för vissa L-system. Dessa L-system är grid-linje, med alla rotationer är 90 grader. Kvadratisk kurva (squarecurve.py) och dragon kurva (dragoncurve.py) är bra exempel. Tricket är att ringa, någonstans nära början av din kod:
t.gridalign()
Detta flyttar din sköldpadda till ett heltal rutnät läge, och anpassar sin rubrik till ett rutnät riktning. Efter detta, sköldpaddan förblir exakt rutnät arrangera i rak linje under förutsättning att du flyttar den bara av belopp som heltal (t.ex. 7, inte 7.1 och inte ens 7. eller 7.0 eftersom dessa flyttal i Python), och du rotera endast av heltal belopp som är multiplar av 90 grader (t.ex.-180, eller 90, men inte 90,0 eller 45). Dragon kurva koden ger också ett exempel på en vanlig funktion som är lite mer komplicerad--istället för bara en linje, den drar en vägg med en öppning i den.
Egentligen kan kalla gridalign() ibland vara en bra idé även om inte alla dina vinklar är rät vinkel. Du får nog avrunda problem i en stor bild, men det kan fortfarande se bättre. Se exemplet spacefilling kurva (återges i lila målat glas!).
L-system behöver inte vara tvådimensionell. Du kan inkludera symboler som yaw, pitch och rulla rotationer. För att utforma träd, ett användbart knep är att ha stack kommandon: "[" Spara aktuell ritning status till en stack och "]" att återställa den. Detta använder modulen sköldpadda push() och pop() metoder. Här är exempelvis en kodsträng för att rita en enkel träd (ltree.py):
t.pitch(90)
regler = {'L':'[^ FL] > [^ FL] > [^ FL] "}
axiom = "FL"
ordbok = {
"F": lambda: t.go(10),
' ^': lambda: t.pitch(20),
' >': lambda: t.roll(120),
' [': lambda: t.push(),
']': lambda: t.pop()
}
lsystem.lsystem(axiom,rules,dictionary,5)
Tänk på L som ett löv (även om denna enkla kod inte faktiskt dra bladet--som skulle behöva läggas till i ordlistan). Vi börjar med FL, vilket är en stam plus ett löv. Då vi ersätta varje blad av [^ FL] > [^ FL] > [^ FL]. Detta är en uppsättning av tre grenar, varje lutas med 20 grader från stammen, 120 grader isär. Hakparenteserna säkerställa att efter varje ny ^ FL är dragna, är vi tillbaka där vi var innan det. Detta upprepas, så att bladen på grenarna ersättas med tripplar av grenar och så vidare.
Ett mer realistiskt träd kan ha mer komplexa koden för ' ['. Det kan göra den efterföljande grenar kortare och tunnare, och ändra deras material som vi närmare bladen (och sedan återställa på ']'). Jag är ett träd som demo kod i lsystem.py, baserade på reglerna (med några tweaks) från Nördiga Blogger.
Du kan också göra grid-anpassade 3D saker. Exempelvis har hilbert.py en 3D Hilbert kurva.
Slutligen kanske du vill införa vissa randomisering i L-systemet regler. Så långt våra regler var deterministiska: en enda sträng gavs som ersätter en symbol, t.ex., 'F': ' F F ++ F F'. Men i stället för en enkel ersättningssträng, en kan ge en Python lista över par (p, sträng), där p är sannolikheten (från 0 till 1) och sträng är strängen att använda med denna sannolikhet. Sannolikheten för en viss källa symbol hade bättre inte lägga till upp till mer än 1, men de kan lägga till mindre än en--i så fall finns det en chans att det blir ingen ersättning. Till exempel, är här en något randomiserade version av nördiga .blogger träd:
regler = {"A": [(0.55,'^ f [^ ^ f >>>>>> A] >>> [^ ^ f >>>>>> A] >>>>> [^ ^ f >>>>>> A]'),
(0,25,'^ f >> [^ ^ f >>>>>> A] >>> [^ ^ f >>>>>> A]')]}
Denna regel har en 55% chans att ersätta ett A med en tre-gren struktur, och en 25% chans att ersätta den med en två-gren struktur. Detta är inte mycket slumpmässig--mer slumpmässighet skulle göra det ännu mer verklighetstroget. Jag bifoga en skärmdump av en ganska gles skog slumpmässigt med hjälp av denna regel (och slumpmässiga placeringen av träd, med ett minsta avstånd).