Python xturtle random en

From Wiki

Jump to: navigation, search

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.

Enlarge

Contents

create art with xturtle and random part 1

preparation: you need

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.


Enlarge


Enlarge

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.

Enlarge

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


Enlarge


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.

Personal tools