Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)
Mostrando entradas con la etiqueta tortuga. Mostrar todas las entradas
Mostrando entradas con la etiqueta tortuga. Mostrar todas las entradas

sábado, 17 de junio de 2023

Cuadrados recursivos (y con colores) usando la tortuga de Python

Quise jugar un poco más con la recursividad en Python, así que cogí mi código de los arbolitos fractales y lo modifiqué para que dibujara cuadraditos (tuve que hacer unos cálculos en mi cabeza para que los cuadrados pequeños se ubicaran en medio de cada lado del cuadrado más grande):

from operator import length_hint
import turtle as t

def cuadrado(lenght):
    t.forward(lenght)
    t.seth(90)
    t.forward(lenght)
    t.seth(180)
    t.forward(lenght)
    t.seth(270)
    t.forward(lenght)
    t.seth(0)

def drawit2(x, y, lenght):
    if lenght > 5:
        t.penup()
        t.goto(x, y)
        
        if lenght < 20:
            t.color('gray')
        else:
            t.color('black')

        t.pensize(lenght/15)
        t.pendown()
        cuadrado(lenght)
                
        cx = x - lenght / 4
        cy = y + lenght / 4
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght / 4
        cy = y - lenght / 4
        
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght * 3 / 4
        cy = y + lenght / 4
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght / 4
        cy = y + lenght * 3 / 4
        drawit2(cx, cy, lenght / 2)
    else:
        t.hideturtle()
        return 0

lenght = 160
drawit2(0 - lenght / 2, 0 - lenght / 2, 160)
t.mainloop()


Creo que no es necesario el import length_hint, (no recuerdo de qué tutorial lo copié) pero los dibujos tardan su buen rato en terminarse de dibujar, así que al final dejé el import.

El resultado es:



Se ve bien, pero no lo suficiente, hice un pequeño cambio al parámetro que se pasa a la función cuadrado():

from operator import length_hint
import turtle as t

def cuadrado(lenght):
    t.forward(lenght)
    t.seth(90)
    t.forward(lenght)
    t.seth(180)
    t.forward(lenght)
    t.seth(270)
    t.forward(lenght)
    t.seth(0)

def drawit2(x, y, lenght):
    if lenght > 5:
        t.penup()
        t.goto(x, y)
        
        if lenght < 20:
            t.color('gray')
        else:
            t.color('black')

        t.pensize(lenght/15)
        t.pendown()
        cuadrado(lenght - lenght / 10)
                
        cx = x - lenght / 4
        cy = y + lenght / 4
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght / 4
        cy = y - lenght / 4
        
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght * 3 / 4
        cy = y + lenght / 4
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght / 4
        cy = y + lenght * 3 / 4
        drawit2(cx, cy, lenght / 2)
    else:
        t.hideturtle()
        return 0

lenght = 160
drawit2(0 - lenght / 2, 0 - lenght / 2, 160)
t.mainloop()


El resultado es:


Mucho mejor, pero le falta color, el código para el color lo copié de aquí.


from operator import length_hint
import turtle as t
from turtle import*
from random import randint

def cuadrado(lenght):
    color(randint(0, 255), randint(0, 255), randint(0, 255))
    t.forward(lenght)
    t.seth(90)
    t.forward(lenght)
    t.seth(180)
    t.forward(lenght)
    t.seth(270)
    t.forward(lenght)
    t.seth(0)

def drawit2(x, y, lenght):
    if lenght > 5:
        t.penup()
        t.goto(x, y)
        
        t.pensize(lenght/15)
        t.pendown()
        cuadrado(lenght - lenght / 10)
                
        cx = x - lenght / 4
        cy = y + lenght / 4
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght / 4
        cy = y - lenght / 4
        
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght * 3 / 4
        cy = y + lenght / 4
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght / 4
        cy = y + lenght * 3 / 4
        drawit2(cx, cy, lenght / 2)
    else:
        t.hideturtle()
        return 0

lenght = 160
colormode(255)
drawit2(0 - lenght / 2, 0 - lenght / 2, 160)
t.mainloop()


El resultado es:


No está mal, pero esas líneas gruesas del cuadrado grande molestan un poco. Voy a ponder un color distinto a cada línea:

from operator import length_hint
import turtle as t
from turtle import*
from random import randint

def cuadrado(lenght):
    color(randint(0, 255), randint(0, 255), randint(0, 255))
    t.forward(lenght)
    t.seth(90)
    color(randint(0, 255), randint(0, 255), randint(0, 255))
    t.forward(lenght)
    t.seth(180)
    color(randint(0, 255), randint(0, 255), randint(0, 255))
    t.forward(lenght)
    t.seth(270)
    color(randint(0, 255), randint(0, 255), randint(0, 255))
    t.forward(lenght)
    t.seth(0)

def drawit2(x, y, lenght):
    if lenght > 5:
        t.penup()
        t.goto(x, y)
        
        t.pensize(lenght/15)
        t.pendown()
        cuadrado(lenght - lenght / 10)
                
        cx = x - lenght / 4
        cy = y + lenght / 4
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght / 4
        cy = y - lenght / 4
        
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght * 3 / 4
        cy = y + lenght / 4
        drawit2(cx, cy, lenght / 2)
        cx = x + lenght / 4
        cy = y + lenght * 3 / 4
        drawit2(cx, cy, lenght / 2)
    else:
        t.hideturtle()
        return 0

lenght = 160
colormode(255)
drawit2(0 - lenght / 2, 0 - lenght / 2, 160)
t.mainloop()


Queda asi:


Creo que prefiero la versión en negro y gris.

Como se ve tan feo, encontré un dato en uno de los tutoriales: el módulo colorsys. Con la ayuda de este enlace y luego de probar un poco llegué a este código:

from colorsys import hsv_to_rgb
import turtle as t
from turtle import*
from random import randint

def cuadrado(lenght, n):
    t.pencolor(hsv_to_rgb(n / 36, 0.75, 0.75))
    t.forward(lenght)
    t.seth(90)
    t.forward(lenght)
    t.seth(180)
    t.forward(lenght)
    t.seth(270)
    t.forward(lenght)
    t.seth(0)

def drawit2(x, y, lenght, n):
    if lenght > 5:
        t.penup()
        t.goto(x, y)
        n += 4
                
        t.pensize(lenght/15)
        t.pendown()
        cuadrado(lenght - lenght / 10, n)
                
        cx = x - lenght / 4
        cy = y + lenght / 4
        drawit2(cx, cy, lenght / 2, n + 1)
        cx = x + lenght / 4
        cy = y - lenght / 4
        
        
drawit2(cx, cy, lenght / 2, n + 2)
        cx = x + lenght * 3 / 4
        cy = y + lenght / 4
        
drawit2(cx, cy, lenght / 2, n + 3)
        cx = x + lenght / 4
        cy = y + lenght * 3 / 4
        
drawit2(cx, cy, lenght / 2, n + 4)
    else:
        t.hideturtle()
        return 0

lenght = 160
drawit2(0 - lenght / 2, 0 - lenght / 2, 160, 12)
t.mainloop()


Se ve mucho mejor ahora:


viernes, 25 de marzo de 2022

Dibujando arbolitos fractales con la tortuga de Python

Éste fue un pequeño ejercicio para practicar recursividad. La idea es dibujar un arbolito fractal con tres ramitas. Ya antes había revisado el código para dibujar estos árboles, pero quise tener mi propia implementación. Después de un buen rato probando, dibujando en un papel cómo debían salir las ramitas, y dónde debía poner la bifurcación recursiva, terminé con este código:

import turtle as t

def drawit(x, y, angle, lenght, n):
    if n > 0:
        t.penup()
        t.goto(x, y)
        t.pendown()
        t.seth(angle)
        t.forward(lenght)
        cx = t.xcor()
        cy = t.ycor()
        drawit(cx, cy, angle + 30, lenght / 1.3, n-1)
        drawit(cx, cy, angle - 30, lenght / 1.3, n-1)
        drawit(cx, cy, angle, lenght / 1.3, n-1)
    else:
        t.hideturtle()
        return 0


drawit(0, -100, 90, 100, 7)
t.mainloop()


la variable n indica la profundidad hasta la que se dibujarán las ramas, otra forma es dibujar las ramas hasta que llegan a una longitud mínima. Las variables x, y, angle, lenght indican las coordenadas desde dónde se dibujarán las ramas, el ángulo y la longitud respectivamente. La función seth() de la tortuga setea el ángulo en el que se empezará a dibujar. Las funciones xcor() y ycor() capturan las coordenadas actuales de la tortuga.

La tortuga primero dibuja el tronco del árbol en la posición (0, -100) en un ángulo de 90 grados. A continuación se bifurca en tres ramas, cada una dibujando un "tronco" en el ángulo y la longitud indicadas a partir de las coordenadas donde la tortuga terminó de dibujar. Para evitar que se confunda, le ordeno ir a esas coordenadas, antes de empezar a dibujar, con la función goto().

El resultado es:


En esta web también dibujan un árbol fractal, y además le ponen color, voy a usar el mismo truco para colorear mi árbol:

import turtle as t
import math

def drawit(x, y, angle, lenght, n):
    if n > 0:
        t.penup()
        t.goto(x, y)
        t.pendown()
        t.seth(angle)

        t.pensize(math.log(lenght,2)/3)
        if n < 2:
            t.color('forest green')
        else:
            t.color('gray')

        t.forward(lenght)
        cx = t.xcor()
        cy = t.ycor()
        drawit(cx, cy, angle + 30, lenght / 1.3, n-1)
        drawit(cx, cy, angle - 30, lenght / 1.3, n-1)
        drawit(cx, cy, angle, lenght / 1.3, n-1)
    else:
        t.hideturtle()
        return 0


drawit(0, -100, 90, 100, 7)
t.mainloop()

Ahora mi árbol ya no parece muerto:


Luego me encontré con este otro arbolito, cuyo código es muy parecido al mío. En lugar de un contador, usa la longitud de las ramas para ponerle un límite a la profundidad de las recursiones. No fue difícil modificar mi código para dibujar un arbolito curvo, y después de probar un poco noté que en este caso es mejor usar una longitud mínima en lugar de la variable n para detener las recursiones. Al final, mi código es el siguiente:

import turtle as t

def drawit(x, y, angle, lenght, n):
    if lenght > 2:
        t.penup()
        t.goto(x, y)
        t.pendown()
        t.seth(angle)
        t.forward(lenght)
        cx = t.xcor()
        cy = t.ycor()
        drawit(cx, cy, angle + 25, lenght * 0.9, n-1)
        drawit(cx, cy, angle - 90, lenght * 0.45, n-1)
    else:
        t.hideturtle()
        return 0


drawit(200, -200, 90, 100, 10)
t.mainloop()


El resultado es:

Necesita algunos arreglos:

import turtle as t

def drawit(x, y, angle, lenght, n):
    if lenght > 2:
        t.penup()
        t.goto(x, y)

        if lenght < 10:
            t.color('gray')
        else:
            t.color('black')

        t.pensize(lenght/15)
        t.pendown()
        t.seth(angle)
        t.forward(lenght)
        cx = t.xcor()
        cy = t.ycor()
        drawit(cx, cy, angle + 25, lenght * 0.9, n-1)
        drawit(cx, cy, angle - 90, lenght * 0.45, n-1)
    else:
        t.hideturtle()
        return 0


drawit(180, -200, 90, 100, 10)
t.mainloop()


Finalmente queda así:

sábado, 27 de octubre de 2018

La Tortuga de Python

Buscando tutoriales, llegué a esta web:
http://elclubdelautodidacta.es/wp/2014/12/python-una-tortuga-de-brocha-fina/

Yo no sabía que Python tenía una tortuga al mismo estilo Logo. Luego de experimentar un poco con el código, llegué a esto:

import turtle

turtle.showturtle()
turtle.shape("turtle")

for i in range (0, 36):
    turtle.penup()
    turtle.left(10)
    turtle.forward(80)
    turtle.pendown()
    turtle.circle(50)
    turtle.penup()
    turtle.forward(-80)
   
turtle.mainloop()
turtle.done()
turtle.exitonclick()


El resultado es:



Haciendo unos pequeños cambios:

import turtle

turtle.showturtle()
turtle.shape("turtle")

for i in range (0, 36):
    turtle.penup()
    turtle.left(10)
    turtle.forward(25)
    turtle.pendown()
    turtle.circle(90)
    turtle.penup()
    turtle.forward(-25)
   

turtle.hideturtle()
turtle.mainloop()
turtle.done()
turtle.exitonclick()


Se obtiene:


Más info se puede hallar en la documentación oficial (en inglés).