En algún lugar de la literatura se menciona sobre recursividad y fractales. En esta ocasión solo presentaré algunos con los que estuve jugando hace algún tiempo y que he venido arrastrando para porfin ser publicados aquí. Nada sorprendente, solo ejercicios de la curiosidad.
Helecho de Barnsley
Versión de tres direcciones
from turtle import * from random import choice from time import sleep elecciones = [0, 1, 2] if __name__ == "__main__": reset() speed(0) for i in range(20000): op = choice(elecciones) if op == 0: left(60) forward(2) elif op == 1: right(60) forward(4) else: backward(6) exitonclick()
Versión de dos direcciones
from turtle import * from random import choice elec = [0, 1] step = 5 if __name__ == "__main__": reset() speed(0) left(90) for i in range(800): if choice(elec): left(90) forward(step*3) dot(5, "blue") else: backward(step) dot(5, "blue") exitonclick()
Triángulo de Sierpinski
Esta versión se comporta un poco como la búsqueda en amplitud, pues primero dibuja el triángulo actual y después hace la recursión, dando la impresión de que va de lo grande a lo pequeño.
El algoritmo es bien sencillo:
- Dibuja un triángulo. 2. A ese triángulo le dibujas uno enmedio uniendo los puntos medios de los lados. 3. Se repite el proceso para los cuatro triángulos de las orillas.
from turtle import * from time import sleep MAX_DEPTH = 7 # Máxima profundidad recursiva def triangulo(lenght): """ Hace un triangulo equilatero con una longitud dada desde donde este parada la tortuga """ for i in range(3): forward(lenght) left(120) def sierpinski(depth=0): avance = 300/float(2**depth) if depth < MAX_DEPTH: triangulo(avance) forward(avance/2) left(60) triangulo(avance/2) right(60) backward(avance/2) # comenzamos a darle profundidad recursiva sierpinski(depth+1) forward(avance/2) sierpinski(depth+1) left(60) forward(avance/2) left(60) sierpinski(depth+1) right(60) backward(avance/2) right(60) backward(avance/2) if __name__ == "__main__": reset() shape('turtle') speed(0) backward(200) sierpinski() sleep(5)
Otra versión de Sierpinski
En este caso se aplica la recursión primero, análogo a como sería en una búsqueda en profundidad, dando el efecto al dibujar de que primero se construyen los triángulos más pequeños.
from turtle import * MAX_DEPTH = 4 def thingy_left(length, depth=0): if depth > MAX_DEPTH: return forward(length) thingy_left(length/3, depth+1) left(60) thingy_right(length/3, depth+1) left(60) thingy_left(length/3, depth+1) right(60) thingy_right(length/3, depth+1) right(60) thingy_left(length/3, depth+1) right(60) thingy_right(length/3, depth+1) right(60) thingy_left(length/3, depth+1) left(60) thingy_right(length/3, depth+1) left(60) thingy_left(length/3, depth+1) def thingy_right(length, depth=0): if depth > MAX_DEPTH: return forward(length) thingy_right(length/3, depth+1) right(60) thingy_left(length/3, depth+1) right(60) thingy_right(length/3, depth+1) left(60) thingy_left(length/3, depth+1) left(60) thingy_right(length/3, depth+1) left(60) thingy_left(length/3, depth+1) left(60) thingy_right(length/3, depth+1) right(60) thingy_left(length/3, depth+1) right(60) thingy_right(length/3, depth+1) if __name__ == '__main__': home() speed(0) thingy_left(100) exitonclick()
Trébol
un bonito y simple trébol recursivo que además cambia de color con la profundidad.
from turtle import * COLOR = int('28', 16), int('50', 16), int('78', 16) PASO_INICIAL = 100 MAX_DEPTH = 10 def hexa(num): """ Convierte num a hexadecimal y lo devuelve como numero de dos digitos """ r = str(hex(num))[2:] if int(r, 16) < 16: r = '0'+r if int(r, 16) < 256: return r else: return 'ff' def trebol(depth=0): """ Dibuja una rama de trebol """ if depth >= MAX_DEPTH: return color('#'+hexa(COLOR[0]+15*depth)+hexa(COLOR[1]+15*depth)+hexa(COLOR[2]+15*depth)) paso = PASO_INICIAL/float((8/5.)**depth) down() forward(paso) left(60) trebol(depth+1) right(120) trebol(depth+1) left(60) up() backward(paso) if __name__ == "__main__": reset() shape('turtle') width(2) speed(0) color('#285078') trebol() left(120) trebol() left(120) trebol() exitonclick()
Un simple espiral
Sin nada de trucos raros, simplemente un bucle de dos líneas y ámonos.
from turtle import * from time import sleep if __name__ == "__main__": for i in range(90, 0, -1): forward(90-i) left(i) sleep(5)
Curva Z
Esta curva tiene muchas propiedades interesantes, como que puede pasar por todos (los infinitos) puntos de un área. De hecho me topé con ella tratando de entender un algoritmo para codificar coordenadas de un espacio bidimensional en un espacio unidimensional, técnica útil para hacer algunas operaciones geoespaciales.
from turtle import * from math import sqrt SIDE_PIECES = 32 MAX_SIZE = 800 OFFSET_X = -MAX_SIZE/2 OFFSET_Y = -MAX_SIZE/2 def deinterleave(num, size): x = 0 y = 0 for i in range(size): x += (num % 2) << i num >>= 1 y += (num % 2) << i num >>= 1 return x, y if __name__ == '__main__': speed('fastest') for i in range(0, SIDE_PIECES**2): x, y = deinterleave(i, SIDE_PIECES) if i == 0: up() goto( x * MAX_SIZE / SIDE_PIECES + (MAX_SIZE/(SIDE_PIECES*2)) + OFFSET_X, y * MAX_SIZE / SIDE_PIECES + (MAX_SIZE/(SIDE_PIECES*2)) + OFFSET_Y, ) if i == 0: down() exitonclick()