Python xturtle random en
From Wiki
This is the wiki page to the showmedo video series Python: creating art with xturtle and random
Note: Felix is no English native speaker and that the text from the subtitles is not always exctly what he says at the moment.
Note: The German video series on this subject has 5 parts instead of 4. For the fifth German video tutorial, see the source code example 4 in this wiki.
This video series was made in the locations of Metalab in Vienna. See spielend-programmieren] for more information.
Contents |
create art with xturtle and random part 1
preparation: you need
- Python http://www.python.org Xturtle
- Xturtle http://ada.rg16.asn-wien.ac.at/~python/xturtle/
- easygui http://www.ferg.org/easygui/
To install xturtle and easygui correctly, download and unzip the packages into the main python folder (the same location where you find the module random.py).
- Under Windows, that's most likley c:\python25\lib
- Under linux, copy as root into /usr/lib/python2.5/
Alternatively, you can unzip xturtle and easygui into the same folder where you save Felix's script below.
If you don't like third-party modules at all, you can replace xturtle with turtle and easygui.buttonbox() with raw_input().
source code
import xturtle
import random
import easygui
colors = ['red','blue','green','yellow','pink','black','violet','brown']
for i in range(20):
distance1 = random.randint(50,100)
angle2 = random.randint(50,150)
plus3 = random.randint(1,10)
color1 = random.choice(colors)
color2 = random.choice(colors)
print distance1, angle2, plus3, color1, color2
for a in range(60):
xturtle.pensize(2)
if a%2==0:
xturtle.pencolor(color1)
else:
xturtle.pencolor(color2)
xturtle.speed(0)
xturtle.hideturtle()
xturtle.left(angle2)
xturtle.fd(distance1)
distance1 = distance1 + plus3
mark = easygui.buttonbox("", "how do you like this pattern ?", ["terrible", "ugly", "boring", "good", "fantastic"])
print mark
resultline = "distance: %i, angle: %i, plus: %i, color1: %s, color2: %s, mark: %s \n" % (distance1, angle2, plus3, color1, color2, mark)
f = file("result.txt", "a")
f.write(resultline)
f.close()
xturtle.clearscreen()
create art with xturtle and random part 2
This is a more complicated version of the program from part 1 and should make more interesting patterns. The easygui code from part 1 is missing.
source code
import xturtle
import random
random.seed()
operators = ['*', '+', '-', '/','%']
colorlist = ["red", "green", "blue", "yellow", "black", "brown", "pink"]
def angle():
le = random.randint(30,130)
if random.randint(1,2) > 1:
le *= -1
return le
def magic():
basicfd = random.randint(10,70)
operator = random.choice(operators)
magic = str(basicfd)+operator+"i"
return magic
for a in range(30):
alles2 = magic()
left = angle()
print alles2, left
while True:
if random.randint(1, 10) > 5:
alles2+=random.choice(operators)
alles2+=magic()
else:
break
command = "xturtle.fd(%s)" %alles2
print command
random.shuffle(colorlist)
for i in range(100):
xturtle.pensize(3)
xturtle.pencolor(colorlist[i%4])
xturtle.speed(0)
xturtle.left(left)
try:
exec(command)
except:
print "autsch!"
xturtle.clearscreen()
print "Bye!"
create art with xturtle and random part 3
now moving toward Genetic Programming, this script has some important improvements. Thanks to Gregor Lindl, the author of xturtle and the book Python für Kids himself, the program runs now infinitly until clicked with the mouse and if the xturtle try to "escape" from the mainwindow it is teleported back to the center of the screen.
source code
import xturtle
import random
import sys
random.seed()
def turn():
return random.randint(-90,90)
def go():
return random.randint(-10,77)
def color():
return random.choice(["red","blue","yellow","black","pink","green"])
def stop(x,y):
global RUNNING
RUNNING = False
print "baba"
sys.exit()
xturtle.reset()
RUNNING = True
xturtle.onscreenclick(stop)
while RUNNING:
dna=[]
for x in range(20):
colorlist = [color(), color(), color(), color(), color()]
gen=(turn(),go(),colorlist)
deltaGo = random.randint(-3,3)
deltaTurn = random.randint(-3,3)
for y in range(random.randint(10,30)):
dna.append((gen[0]+deltaTurn*y, gen[1]+deltaGo*y,gen[2][y%5]))
print dna
xturtle.pensize(3)
xturtle.speed(0)
for gen in dna:
if not RUNNING:
break
xturtle.left(gen[0])
xturtle.fd(gen[1])
xturtle.pencolor(gen[2])
position = xturtle.pos()
if position[0] >300 or position[1] >300 or position[0]<-300 or position[1]<-300:
xturtle.penup()
xturtle.goto(0,0)
xturtle.pendown()
xturtle.clearscreen()
Note: the line xturtle.speed(0) was added after recording the video. It increase the speed of xturtle and makes the whole program less boring to watch.
create art with xturtle and random (and genetic programming), part 4
Finally reaching genetic programming
source code
import xturtle
import random
#import sys
random.seed()
LIMITX = 300 # distance from center where xturtle is teleported back to center
LIMITY = 300
STARTSET = 4 # number of generated games at start
MAXPOP = 30 # max number of items in population before death occurs
MINJURYTIME = 1 # minimal number of times a gen must be judged by the jury
MAXDELTAGO = 3 # delta increase of turtle.fd
MAXDELTATURN = 3 # delta increase of turtle.left
GENOMMIN = 5 # minimal number of gens in one generated genom
GENOMMAX = 10 # maximal number of gens in one generated genom
STOPGEN = ((0,0,"white")) # stop-gen to mark start/end of a genom
MUTATIONDELTA = 1 # how exact the lenght of child dna matches those of parents dna 0=most exact
NOMOREJURY = 2 # 1 means always Sex instead of more jury, 2 means 50%, 3 means 33%
# those 3 functions generate a gen
def turn():
return random.randint(-90,90)
def go():
return random.randint(-10,77)
# color names from pynche
def color():
return random.choice(["red","blue","yellow","black","pink","green", "brown",
"coral", "gold", "gray", "violet", "wheat", "tomato",
"thistle", "tan", "steel blue", "sienna", "SeaGreen1",
"salmon", "royal blue", "plum", "peru", "pale green",
"orchid", "orange", "navy", "moccasin", "magenta",
"lime green", "khaki", "gold", "azure"])
def newGen():
dna=[]
colorlist = [color(), color(), color(), color(), color()]
gen=(turn(),go(),colorlist) # random values
deltaGo = random.randint(-MAXDELTAGO,MAXDELTAGO)
deltaTurn = random.randint(-MAXDELTATURN,MAXDELTATURN)
#dna.append(STOPGEN) #first stop-gen
for y in range(random.randint(GENOMMIN,GENOMMAX)):
dna.append((gen[0]+deltaTurn*y,
gen[1]+deltaGo*y,
gen[2][y%5]))
dna.append(STOPGEN) #last stop-gen
return dna
def showGen(dna):
age = dnadir[str(dna)][2]
print "age: %i" % age
xturtle.pensize(3)
xturtle.speed(0)
result = dnadir[str(dna)][0]
for gen in dna:
if not RUNNING:
print "i break because mouseclick"
break
if dnadir[str(dna)][0] != result:
print "i break because key pressed"
break
xturtle.left(gen[0])
xturtle.fd(gen[1])
xturtle.pencolor(gen[2])
position = xturtle.pos()
if (position[0] >LIMITX or position[1] >LIMITY or
position[0]< -LIMITX or position[1]<- LIMITY):
# teleporting the xturtle back to pos 0,0
xturtle.penup()
xturtle.goto(0,0)
xturtle.pendown()
def makePause():
xturtle.delay(75) # make a little pause (1000 ms= 1 second)
xturtle.pencolor("black")
for _ in xrange(36):
xturtle.left(10)
if not RUNNING:
break
#xturtle.left(180)
xturtle.delay(10) # delay 0 is way too fast
xturtle.clearscreen()
def stop():
#was before: stop(x,y):
# a mouseclick raise this function"
global RUNNING
RUNNING = False
print "bye-bye!"
#sys.exit()
def gotResult(result, resultText):
if dnadir.has_key(str(dna)):
jurys=dnadir[str(dna)][0]
score=dnadir[str(dna)][1]
age = dnadir[str(dna)][2]
score = (jurys * score + result)/(jurys+1.0)
jurys +=1
dnadir[str(dna)]= (jurys,score,age)
x = random.randint(-100,100)
y = random.randint(-100,100)
restext.append(cv.create_text(x,y,text=resultText,font=("arial",22,"bold")))
else:
print "dna not found"
def getKeyList():
returnlist = []
for key in dnadir:
# gen was noted by a jury how many times ?
if dnadir[key][0] < MINJURYTIME:
returnlist.append(key)
return returnlist
def dnaSlicer(rawdna):
"""returns a list of genoms, seperated by the stopgen"""
genom = []
returnlist = []
for gen in rawdna:
genom.append(gen)
if gen == STOPGEN:
returnlist.append(genom)
genom = []
return returnlist
def inheritance(dnaParent, fittnessParent):
""" returns a genomlist of original or mutated genes"""
child = []
for sequence in dnaParent:
fate = dice()
if int(fittnessParent) > fate:
# take the old genom
child.append(sequence)
elif int(fittnessParent) < fate:
pass
# nothing, drop genom
###### complete new gen
#child.append(newGen())
else:
#mutation ! genom will be mixed with a complete new genom
mutationGen = newGen()
mutationGen += sequence
random.shuffle(mutationGen)
mutationGen = mutationGen[:len(sequence)]
if mutationGen[-1] != STOPGEN:
mutationGen.append(STOPGEN)
child.append(mutationGen)
return child
def dice():
return random.randint(-6,6)
xturtle.reset()
RUNNING = True
#xturtle.onscreenclick(stop)
xturtle.onkey(stop, "q") # program quit when key 'q' is pressed
xturtle.onkey(lambda:gotResult(-4, "brain-damaging ugly"),"F1")
xturtle.onkey(lambda:gotResult(-3, "very ugly"),"F2")
xturtle.onkey(lambda:gotResult(-2, "ugly"),"F3")
xturtle.onkey(lambda:gotResult(-1, "slightly ugly"),"F4")
xturtle.onkey(lambda:gotResult(1, "slightly good"),"F5")
xturtle.onkey(lambda:gotResult(2, "good"),"F6")
xturtle.onkey(lambda:gotResult(3, "very good"),"F7")
xturtle.onkey(lambda:gotResult(4, "fantastic"),"F8")
xturtle.listen()
runs = 0
dnadir = {}
restext = []
freshKeyList = []
cv = xturtle.getcanvas()
t1 = cv.create_text(0,-200,text="how do you like this graphic ?")
t2 = cv.create_text(0,-180,text="press F1 for sinful ugly F2 for very ugly ... F7 for very pretty, F8 for fantastic" )
#t3 = cv.create_text(200,-200,text="run: %i age: %i str(runs))
while RUNNING:
#status output
print "------------------------------------"
print "runs: %i freshkeys: %i dnadir: %i maxpop %i" % (runs, len(freshKeyList), len(dnadir), MAXPOP)
runs +=1
#cv.delete(t3)
#t3 = cv.create_text(200,-200,text=str(runs)) #display runs
# clean up old messages on Canvas
for msg in restext:
cv.delete(msg)
restext = []
freshKeyList = getKeyList() # check how many gens need jury
# create gens if necessary
if len(dnadir) < STARTSET:
dna = newGen()
# add new Gen to dir ?
if dnadir.has_key(str(dna)):
print "dna already exist"
continue
else:
dnadir[str(dna)]=(0,0,0) #jury, score, age
showGen(dna)
makePause()
elif len(freshKeyList) > 0:
# are there new gens to show to the jury ?
dna = eval(random.choice(freshKeyList))
showGen(dna)
makePause()
else:
# jury again or Sex & Death ?
if runs % NOMOREJURY == 0:
print "more Jury"
dna = eval(random.choice(dnadir.keys()))
showGen(dna)
makePause
else:
# all gens are created and judged, let's have Sex
print "Sex!"
father = random.choice(dnadir.keys())
mother = random.choice(dnadir.keys())
fittness_father = dnadir[father][1]
fittness_mother = dnadir[mother][1]
age_father = dnadir[father][2]
age_mother = dnadir[mother][2]
genoms_father=dnaSlicer(eval(father))
genoms_mother=dnaSlicer(eval(mother))
genoms_child=[]
dna_child = []
# take the genoms to the child, based on fittness of parents
genoms_child.append(inheritance(genoms_father, fittness_father))
genoms_child.append(inheritance(genoms_mother, fittness_mother))
random.shuffle(genoms_child)
# take only around the half of both parents dna
howmuch = (len(genoms_father) + len(genoms_mother))/ 2 + random.randint(0,MUTATIONDELTA)
genoms_child = genoms_child[:howmuch]
#create child
for sequence in genoms_child:
for gen in sequence:
dna_child += gen
# add new Gen to dir ?
if dnadir.has_key(str(dna_child)):
print "dna of child already exist"
continue
elif len(dna_child)==0:
print "empty child"
continue
else:
dnadir[str(dna_child)]=(0,0,max(age_father, age_mother)+1) #jury, score, age
print dna_child
showGen(dna_child)
makePause()
if len(dnadir) > MAXPOP:
# too crowded, death needed
print "Death!"
victim1 = random.choice(dnadir.keys())
victim2 = random.choice(dnadir.keys())
# the older one of both must die
age_victim1 = dnadir[victim1][2]
score_victim1 = dnadir[victim1][1]
age_victim2 = dnadir[victim2][2]
score_victim2 = dnadir[victim2][1]
if age_victim1 == age_victim2:
if score_victim1 == score_victim2:
# random death
del dnadir[random.choice([victim1, victim2])]
elif score_victim1 > score_victim2:
# death of the less pretty
del dnadir[victim2]
else:
del dnadir[victim1]
elif age_victim1 > age_victim2:
# victim1 is older and dies
del dnadir[victim1]
else:
# victim2 is older and dies
del dnadir[victim2]
#print dna
print "saving data to file, please wait"
f = open("dnadata.txt","w")
for key in dnadir:
f.write(str(dnadir[key][0]) + ":" + str(dnadir[key][1]) + ":" + str(key) + "\n"+"\n")
f.close()
print "done. bye-bye"
comments
To learn more about easygui, watch the showmedo series about easygui.
Felix use the open-source code editor Geny for his videos.

