sábado, 30 de setembro de 2017

Zen ou a Arte de Programar

(brincadeiras de um sábado de manhã)


Suponham que lhe pedem um programa capaz de desenhar o símbolo do Yin-Yang:
Por onde começar?? Olhando para a figura verificamos que é composta à base de circunferências e semi-circunferências a duas cores (preto e branco). Usando um princípio já nosso conhecido, tentemos simplificar a questão, esquecendo os círculos interiores e as cores:
def zen1(raio):
    turtle.setheading(90)
    turtle.circle(raio)
    turtle.circle(raio/2,-180)
    turtle.setheading(90)
    turtle.circle(raio/2,180) 
Executando o código é criado o seguinte:
Ao fazermos assim ficamos com o problema de colocar as cores… Com um pouco de reflexão chegamos a uma solução, baseada na ideia de separar a circunferência exterior em duas semi-circunferências. O cuidado a ter é com as orientações a cada momento da tartaruga. Aqui basta não esquecer o principio de que a tartaruga quando se movimenta vê sempre o centro à sua esquerda!
def zen11(raio):
    turtle.setheading(90)
    turtle.circle(raio,180)
    turtle.fillcolor('black')
    turtle.begin_fill()
    turtle.circle(raio/2,-180)
    turtle.setheading(270)
    turtle.circle(raio/2,180)
    turtle.circle(raio,-180)
    turtle.end_fill()
ao executar o programa obtemos:
Agora é “só” colocar os círculos pequenos. Uma vez mais basta saber definir os centros:
def zen12(raio):
    turtle.setheading(90)
    turtle.circle(raio,180)
    turtle.fillcolor('black')
    turtle.begin_fill()
    turtle.circle(raio/2,-180)
    turtle.setheading(270)
    turtle.circle(raio/2,180)
    turtle.circle(raio,-180)
    turtle.end_fill()
    # círculos pequenos
    # esquerdo
    turtle.setx(turtle.xcor() + raio/2 -raio/10)
    turtle.fillcolor('white')
    turtle.begin_fill()
    turtle.circle(raio/10)
    turtle.end_fill()
    # direito
    turtle.penup()
    turtle.setx(turtle.xcor()+ raio)
    turtle.pendown()
    turtle.fillcolor('black')
    turtle.begin_fill()
    turtle.circle(raio/10)  
    turtle.end_fill()
    turtle.hideturtle()    
Et voilá!

Mas será que é a única forma de resolver o problema? Será que ficamos satisfeitos??? Olhando para a solução acima o que podemos dizer? Bem, que há muita coisa “fixa”: a posição, a orientação, as cores. Embora estas duas últimas façam parte da definição clássica da imagem, podemos procurar libertar-mo-nos e permitir uma versão mais geral. Por outro lado, e talvez mais importante, o modo como construímos a solução usa componentes de baixo nível e não olha para a imagem como sendo composta por duas que se distinguem … pela posição, orientação e cores!!! Vamos tentar então uma segunda abordagem.
   
def zen(raio,x_cor,y_cor,orient, cor_1,cor_2):
    """
    Desenha uma componente.
    """
    # corpo principal
    vai_para_or(x_cor,y_cor,orient)
    turtle.fillcolor(cor_1)
    turtle.begin_fill()
    turtle.circle(raio,-180)
    #vai_para_or(x_cor,y_cor,orient)   
    turtle.circle(raio/2,-180)
    turtle.setheading(turtle.heading()+180)
    turtle.circle(raio/2,180)
    turtle.end_fill()
    # restaura
    vai_para_or(x_cor,y_cor,orient+90)
    # círculo pequeno  
    turtle.penup()
    turtle.forward(3*raio/2-raio/10)
    turtle.pendown()
    turtle.fillcolor(cor_2)
    turtle.setheading(orient)
    turtle.begin_fill()
    turtle.circle(raio/10)
    turtle.end_fill()
    turtle.hideturtle()
O código apresentado torna mais claro a importância da orientação em cada momento do desenho. O raio do círculo pequeno foi decidido que tenha um valor 10 vezes mais pequeno que o raio da semi-circunferência maior. O resultado quando escolhemos as cores vermelho e azul:
Agora podemos apresentar o nosso programa para o Yin-Yang:
   
def yin_yang(raio,posx,posy):
    zen(raio,posx,posy,90,'black','white')
    zen(raio,posx - 2*raio,posy,270, ‘white','black')
Com esta solução podemos então … brincar:
   
def zen_rose(raio,posx,posy,orientacao,cor_1, cor_2, num):
    for i  in range(num):
        zen(raio,posx,posy,orientacao,cor_1,cor_2)
        orientacao = orientacao + 360/num
Executando vem:
Mas podemos variar um pouco:
def zen_rose_2(raio,posx,posy,orientacao,cor_1, cor_2, num):
    for i  in range(num):
        if i % 2 == 0:
            zen(raio,posx,posy,orientacao,cor_1,cor_2)
        else:
            zen(raio,posx,posy,orientacao,cor_2,cor_1)
        orientacao = orientacao + 360/num
Ou criar objectos mais coloridos:
def zen_rose_tutti(raio,posx,posy,orientacao, num):
    turtle.colormode(255)
    for i  in range(num):
        cor_1 = (random.randint(0,255),random.randint(0,255),random.randint(0,255))
        cor_2 = (random.randint(0,255),random.randint(0,255),random.randint(0,255))
        zen(raio,posx,posy,orientacao,cor_1,cor_2)
        orientacao = orientacao + 360/num
E agora:
E como alguém disse: o céu é o limite! Invente!!!
def zen_voa(raio,posx,posy,orientacao, num):
    turtle.speed(10)
    turtle.colormode(255)
    for i  in range(1,num+1):
        cor_1 = (random.randint(0,255),random.randint(0,255),random.randint(0,255))
        cor_2 = (random.randint(0,255),random.randint(0,255),random.randint(0,255))        
        zen(raio,posx,posy,orientacao,cor_1,cor_2)
        #orientacao = orientacao + 360/num
        posx = posx + i * raio/5
        posy = posy + i * raio/5
 

Formas, Cores e outras coisas....

O módulo turtle da linguagem Python tem um conjunto vasto de operações que podem ser exceptuadas sobre objectos do tipo turtle e sobre um mundo 2D. Durante as aulas vimos alguns exemplos de comandos básicos e o que com eles podíamos fazer. Por exemplo, para desenhar um quadrado:
def quadrado(lado):
    for i in range (4):
        turtle.forward(lado)
        turtle.right(90)
Usando esta definição como componente podemos brincar um pouco. Por exemplo, desenhar um certo número de vezes um quadrado, mudando apenas a orientação:
def tarta_ernesto(posx,posy):
    # tartaruga ernesto
    turtle.shape("turtle")
    turtle.color("yellow")
    turtle.speed(10)
    turtle.pensize(2)
    # posiciona
    turtle.penup()
    turtle.goto(posx,posy)
    turtle.pendown()
    # desenha
    for i in range(36):
        quadrado(150)
        turtle.right(10)
    turtle.hideturtle()
Como se pode ver existem comandos para:

- definir a forma da tartaruga

definir a cor

definir a velocidade da tartaruga

definir a espessura do rasto

O resultado é ilustrado na figura.
Mudando o ciclo no interior do programa podemos conseguir outro tipo de formas:
def tarta_costa(posx,posy):
    #tartaruga costa
    turtle.shape("turtle")
    turtle.color("blue")
    turtle.speed(10)
    turtle.pensize(2)
    # posiciona
    turtle.penup()
    turtle.goto(posx,posy)
    turtle.pendown()
    # desenha    
    for i in range(400):
        turtle.forward(i)
        turtle.right(91)
    turtle.hideturtle()
Tal como está escrito, a única “coisa” que controlamos e podemos variar é a posição inicial. Visualmente:
Podemos usar a mesma ideia de base (uma forma básicas que é replicada….) para criar diferentes formas coloridas. Experimente você.

quarta-feira, 27 de setembro de 2017

Na aula foi pedido que escrevessem um programa que desenhasse espirais. Ficou claro, após alguma discussão, que o desenho iria depender de dois factores inter-relacionados: o tamanho do traço e o ângulo de viragem. Também é importante definir o número de “voltas” da espiral, claro, mas isso não causa problema de maior.

Daqui resulta um programa simples:
import turtle

def spiro(tam,k,ang,size):
    for i in range(size):
        turtle.forward(tam + k*i)
        turtle.right(ang)
    turtle.hideturtle()
Não é preciso pensarmos muito para perceber que os traços que vamos usar terão que ter o seu tamanho incrementado. Porquê? Bem, porque a não ser assim, em função do ângulo de viragem, em vez de uma espiral teremos repetições da mesma volta. E o ângulo? Se fôr muito pequeno vamos ter uma grande amplitude e dificuldade em girar 360 graus. Se fôr muito grande rapidamente os traços se intersectam. Mas o melhor é experimentar com valores concretos. Experimente tentar obter espirais com o aspecto dos das figuras. E muitas mais. Divirta-se!

sexta-feira, 22 de setembro de 2017

Mais uma vez...

Vamos recomeçar mais uma edição da cadeira de IPRP. Como no passado vou procurar deixar aqui elementos que podem ajudar à melhor compreensão da matéria e consequente melhoria do vosso desempenho.

Estejam atentos!