729G04 Programmering och diskret matematik Föreläsning 4
Turtle Graphics
LOGO LOGO: programmeringsspråk för användning inom undervisning 1967 av Papert och Feurzeig Språket är släkt med LISP, men som "utenhet" hade man bl.a. möjlighet att styra en sköldpadda. Sköldpaddan hade även en "penna" som den kunde höja och sänka.
The robot
Trådlös variant
Modern variant Valiant Technology Ltd.
Turtle Graphics Att rita med hjälp av en sköldpadda som man styr med hjälp av kommandon brukar man kalla för Turtle Graphics. Man ser sköldpaddan uppifrån och kan ge den kommandon Python har en modul som låter oss hålla på med Turtle Graphics.
Kommandon man kan ge till sköldpaddan Gå frammåt Backa Sväng vänster Sväng höger Dra upp pennan Sätt ner pennan
http://el.media.mit.edu/logo-foundation/logo/turtle.html
Pythons turtlemodul
Förflyttning av sköldpaddan fd(avstånd): flytta sköldpaddan frammåt ett visst avstånd bk(avstånd): flytta sköldpaddan bakåt ett visst avstånd lt(grader): sväng vänster ett visst antal grader rt(grader): sväng höger ett visst antal grader
En fyrkant import turtle importera modulen screen = turtle.screen() screen.setup(width=600, height=600) turtle.mode("logo") turtle.showturtle() skapa en rityta sätt storleken på ritytan använd LOGO-standard för riktning visa sköldpaddan turtle.fd(100) turtle.rt(90) turtle.fd(100) turtle.rt(90) turtle.fd(100) turtle.rt(90) turtle.fd(100) gå framåt 100 steg sväng höger 90 grader gå framåt 100 steg sväng höger 90 grader gå framåt 100 steg sväng höger 90 grader gå framåt 100 steg
En fyrkant framåt
En fyrkant vänster
En fyrkant framåt
En fyrkant vänster
En fyrkant framåt
En fyrkant vänster
En fyrkant framåt
En fyrkant
Demo av pennan, förflyttning, position och riktning
Olika sätt att importera moduler import turtle from turtle import * screen = turtle.screen() turtle.showturtle() screen = Screen() showturtle() turtle.fd(100) turtle.rt(90) turtle.fd(100) turtle.rt(90) turtle.fd(100) turtle.rt(90) turtle.fd(100) fd(100) rt(90) fd(100) rt(90) fd(100) rt(90) fd(100)
Kan vi stoppa in detta i en loop?
Kan vi få sköldpaddan att röra sig slumpmässigt?
Sköldpaddan ritar på ritytan med en penna Sköldpaddan har en penna som kan höjas och sänkas. Den är nere från början. pd(): sätt ner pennan pu(): dra upp pennan
Koordinatsystem och riktning
(-, +) (+, +) (0, 0) (-, -) (+, -)
Sköldpaddan och koordinater pos() returnerar en tupel (x, y) där x och y är flyttal setpos(x, y) flyttar sköldpaddan till positionen (x, y) där x och y är flyttal. OBS! setpos() "teleporterar" inte sköldpaddan, dvs att om pennan är nere kommer det att bli ett streck.
Ja, tupler finns i Python också... Lista: [1, 2, 3] Tupel: (1, 2, 3) Den stora skillnaden mellan listoroch tupler i Python är att man inte kan ändra på en tupel. Datatyper som man inte kan ändra värdet på kallas "immutable" Datatyper man kan ändra värde på kallas "mutable"
Tupel-exempel
Går inte att ändra på en tupel >>> a = [1, 2, 3] >>> b = (1, 2, 3) >>> a[0] = 4 >>> b[0] = 4 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment >>>
Riktning
Riktning i världen mode("standard") 90 mode("logo") 0 0 90
Sköldpaddan vet vilken riktning den tittar åt mode("logo") 0 är norrut 90 grader är österut gradantalet ökar medurs heading() returnerar ett flyttal somberättar gradantalet hos den riktning man står åt seth(d) där d är ett flyttal, ställer in sköldpaddans riktning
Cirkelrörelse
Exempel på anrop till circle() circle(40) circle(-40) circle(40, 90) circle(40, 180, 4)
Cirkelrörelse circle() kan ta etttill tre argument circle(40) flyttar sköldpaddan moturs i en cirkel med radien 40 circle(-40) ger en rörelse i medurs riktning circle(40, 90) avbryter rörelsen efter 90 grader circle(40, 90, 2) säger att sköldpaddan kommer dela upp rörelsen i två raksträckor.
Refaktorisering att skriva om kod för att göra den bättre utan att ändra på dess beteende
Exempel och refaktorisering Några exempel på vad man kan göra med turtle-modulen samt genomgång av refaktorisering genom generalisering och inkapsling Inkapsling: Att kapsla in en sekvens av uttryck och satser i en funktion Generalisering: Att göra en funktion mer generell genom att specificera beteenden med hjälp av parametrar/argument
Refaktorisering (refactoring) Förbättring av kod dock med bibehållen funktionalitet. Förbättringen kan avse underhåll lättlästhet Inte att förväxla med optimering som har med förbättring av prestanda att göra. Båda kan dock inträffa samtigt. Optimering kommer på nästa föreläsning.
Exempel på refaktorisering def get_number_of_children(name): if name == "Ada": return 1 elif name == "Bean": return 3 elif name == "Cecil": return 1 elif name == "Dan": return 2 elif name == "Eliza": return 2 elif name == "Frodo": return 0 elif name == "Garfield": return 0 def get_number_of_children(name): if name in ["Frodo", "Garfield"]: return 0 elif name in ["Ada", "Cecil"]: return 1 elif name in ["Dan", "Eliza"]: return 2 elif name in ["Bean"]: return 3
När ska man refaktorisera? När koden luktar illa - exempel på dålig lukt: redundant kod, t.ex. kod som upprepas eller kod som inte gör något långa funktioner väldigt mångaparametrar skickastill en funktion en funktion som gör för lite variabelnamn eller funktionsnamn som har missvisande namn komplexa vilkor i koden
Olika sätt att refaktorisera Hitta loopar Kapsla in (bryt ut till funktioner) Generalisera (gör koden mer generell, ofta funktioner)
Bryta ut en funktion / inkapsling print "Hi Ben!" print "I am happy!" # Inkapsling: Att kapsla in en sekvens av # uttryck och satser i en funktion. def greet_ben(): print "Hi Ben!" print "I am happy!"
Varför är detta bra? Återanvändning! def greet_ben(): print "Hi Ben!" print "I am happy!" greet_ben() greet_ben()
Generalisering av funktion Att gå från en funktion som utför en specifik uppgift, till en funktion som är mer flexibel med avseende på beteende genom att införa parametrar
Generalisering def greet_ben(): print "Hi Ben!" print "I am happy!" # Vi gör funktionen mer generell så # att den kan hälsa på vilket namn som helst def greet(name): print("hi " + name + "!") print("i am happy!")
Sick sack Vi vill producera ovanstående mönster. Kom ihåg: programmering är en iterativ aktivitet! Vi gör ett steg i taget.
Vi provar att refaktorisera https://www.ida.liu.se/codela/as/729g04d/sicksack
Sick sack from turtle import * screen = Screen() mode("logo") fd(100) rt(90) fd(10) rt(90) fd(100) lt(90) fd(10) lt(90) fd(100) rt(90) fd(10) rt(90) fd(100) lt(90) fd(10) lt(90) fd(100) rt(90) fd(10) rt(90) fd(100) lt(90) fd(10) lt(90)
Sick sack vi ser en loop from turtle import * screen = Screen() mode("logo") fd(100) rt(90) fd(10) rt(90) fd(100) lt(90) fd(10) lt(90) for i in range(3): fd(100) rt(90) fd(10) rt(90) fd(100) lt(90) fd(10) lt(90) fd(100) rt(90) fd(10) rt(90) fd(100) lt(90) fd(10) lt(90) fd(100) rt(90) fd(10) rt(90) fd(100) lt(90) fd(10) lt(90)
Sick sack inkapsling for i in range(3): fd(100) rt(90) fd(10) rt(90) fd(100) lt(90) fd(10) lt(90) # Vi hittar delar av koden vi kan göra om # till funktioner def make_right_l(): fd(100) rt(90) fd(10) rt(90) def make_left_l(): fd(100) lt(90) fd(10) lt(90) for i in range(3): make_right_l() make_left_l()
Sick sack inkapsling och generalisering def make_right_l(): fd(100) rt(90) fd(10) rt(90) def make_left_l(): fd(100) lt(90) fd(10) lt(90) for i in range(3): make_right_l() make_left_l() # Vi kapslar in loopen och generaliserar # den på samma gång def make_right_l(): fd(100) rt(90) fd(10) rt(90) def make_left_l(): fd(100) lt(90) fd(10) lt(90) def zig_zag(n): for i in range(n): make_right_l() make_left_l() zig_zag(3)
Sick sack inkapsling och generalisering # Vi kapslar in loopen och generaliserar # den på samma gång def make_right_l(): fd(100) rt(90) fd(10) rt(90) def make_left_l(): fd(100) lt(90) fd(10) lt(90) def zig_zag(n): for i in range(n): make_right_l() make_left_l() zig_zag(3) # Vi skapar en funktion som ritar ut tv segment med en b j def two_segments(angle, segment1, segment2): fd(segment1) rt(angle) fd(segment2) rt(angle) def make_right_l(): two_segments(90, 100, 10) def make_left_l(): two_segments(-90, 100, 10) def zig_zag(n): for i in range(n): make_right_l() make_left_l() zig_zag(3)
Uppgift: Stjärnan Vi vill rita en sån här figur Hur? Dela upp problemet, hitta mönster, gör samma sak flera gånger?
Rita en stjärna def draw_line_and_return(): """Rita ett streck p 50 enheter och startpositionen.""" fd(50) bk(50) terv nd till def draw_star(): """Rita ut en stj rna med fem armar""" for line in range(5): draw_line_and_return() rt(360.0/5) draw_star()
Debugga med spårutskrifter
Att hitta vad som går fel skriv ut värden på variabler på lämpligt ställe i koden print("x: ", x)
Med spårutskrifter def draw_line_and_return(length): """Rita ett streck och # Spr rutskrift print("drawing line, length:", length) fd(length) bk(length) terv nd till startpositionen.""" def draw_star(points, length): """Rita ut en stj rna med fem armar""" for line in range(points): # Skriv ut vilket streck vi ligger p print("line:", line) draw_line_and_return(length) rt(360.0/points)
Visualisering av nästlad loop
Stjärna med stjärnor
Stjärna med stjärnor
Labb 4 Tillämpning av funktioner, loopar och sköldpaddor Labb 4-8 görs i par Anmäl er till nya pargrupper https://www.ida.liu.se/webreg/729g04-2014/parlabb
Angry Turtles
Angry Turtles Fåglar har stulit sköldpaddornas ägg och sköldpaddorna hämnas genom att skjuta iväg sig själva på en måltavla. Användaren ger styrka och vinkel Spelet ritar ut hur sköldpaddan flyger iväg och kollar om sköldpaddan träffar målet.
Exempel
Angry Turtles - innan spelet kan börja Innan vi spelet kan börja måste vi göra följande Ställa in ritytan Bestämma var måltavlan ska vara Rita ut måltavlan Placera sköldpaddan i startposition
Angry Turtles - själva spelet Spelaren börjar med t.ex. 1000 poäng Spelloop Fråga användaren parametrar: styrka och ev vinkel - använd input() Förflytta sköldpaddan lite i taget (loop) förflyttningen baseras på angiven styrka (och ev vinkel) avbryt loopen (break) när sköldpaddan nuddat marken (eller är under marken), dvs kolla om y <= 0. Kolla avståndet till måltavlan Om sköldpaddan är tillräckligt nära måltavlan - berätta det, visa poäng och fråga om spelaren vill spela igen. Om sköldpaddan var för långt ifrån måltavlan - berätta det och dra ifrån poäng