Já por várias vezes referi a importância de pegar num problema complexo e dominar essa complexidade
dividindo o problema inicial em sub-problemas mais simples e/ou começando por resolver um problema semelhante mas mais simples que depois se adapta para resolver a questão inicial.
Isto é importante, claro, mas de nada serve se não tivermos
conhecimentos sobre o domínio do problema (por exemplo, pode obrigar a usar conhecimentos de trigonometria).
Mas podemos saber muito de técnicas de resolução de problemas, ter conhecimentos sobre o domínio do problema e mesmo assim não resolver o problema porque não
conhecemos a linguagem de programação.
Assim para programar bem são precisas, pelo menos
três coisas: dominar a linguagem de programação, ter conhecimentos sobre o domínio do problema e dominar a arte de resolução de problemas. Faltando uma delas e o resultado nunca será bom, se é que se chega a algum resultado...
Neste post vou falar sobre como o modo de decompor um problema em sub-problemas pode ter várias soluções e se liga aos outros aspectos. Suponhamos que queremos desenhar a figura seguinte:
Numa primeira abordagem admitamos que o que eu vejo são
segmentos de recta ligados entre si. Nesta perspectiva é fundamental ter uma primitiva que me permita desenhar segmentos de recta conhecidos os seus pontos extremos. Não é um problema difícil:
def linha(x_1,y_1, x_2,y_2):
""" Desenha uma linha entre dois pontos."""
# posiciona-se
turtle.pu()
turtle.goto(x_1,y_1)
turtle.pd()
# Desenha
turtle.goto(x_2,y_2)
Precisei de usar conhecimentos básicos do modo turtle. Agora só necessito de identificar os oito pontos do desenho e desenhar os doze segmentos que unem alguns entre si.
Feito isso o resto é trivial do ponto de vista da programação. Mas identificar os pontos pode não ser simples se não tivermos alguma conhecimento de geometria. Mas apresentemos primeiro o código.
def bloco(posx, posy,lado_1, lado_2):
""" Desenha um bloco geométrico."""
# Auxiliares
passo_x = lado_2 * math.cos(math.pi/6)
passo_y = lado_2 * math.sin(math.pi/6)
# Desenho
linha(posx,posy, posx+lado_1, posy)
linha(posx+lado_1, posy, posx+ lado_1, posy + lado_2)
linha(posx+ lado_1, posy + lado_2,posx, posy + lado_2)
linha(posx, posy + lado_2, posx, posy)
linha(posx + passo_x,posy + passo_y, posx + passo_x+lado_1, posy + posy+passo_y)
linha(posx+passo_x+lado_1, posy+posy+passo_y, posx+passo_x+ lado_1, posy+posy+passo_y + lado_2)
linha(posx+passo_x+ lado_1, posy+posy+passo_y + lado_2,posx+passo_x, posy+posy+passo_y + lado_2)
linha(posx+passo_x, posy+posy+passo_y + lado_2, posx+passo_x, posy+posy+passo_y)
linha(posx, posy, posx+passo_x, posy + passo_y)
linha(posx, posy+lado_2, posx+passo_x , posy+lado_2+passo_y)
linha(posx + lado_1, posy, posx+lado_1+passo_x , posy+passo_y)
linha(posx + lado_1, posy + lado_2, posx+lado_1+passo_x , posy+lado_2+passo_y)
turtle.hideturtle()
A questão central, pelo menos para mim, foi a de definir o que designei por passo_x e passo_y que me obriga a saber um pouco de trigonometria. Temos que convir que o programa além de extenso não é muito legível. Talvez se possa fazer melhor no que diz respeito a este segundo aspecto, passando do conceito de coordenadas para o conceito de ponto. Fazendo isso chegamos a uma nova solução.
def linha_b(p_1, p_2):
""" Desenha uma linha entre dois pontos."""
# posiciona-se
turtle.pu()
turtle.goto(p_1[0],p_1[1])
turtle.pd()
# Desenha
turtle.goto(p_2[0],p_2[1])
def bloco_b(posx, posy,lado_1, lado_2, angulo):
""" Desenha um bloco geométrico."""
# Auxiliares
passo_x = lado_2 * math.cos(angulo)
passo_y = lado_2 * math.sin(angulo)
# Pontos
p_1 = (posx, posy)
p_2 = (posx + lado_1, posy)
p_3 = (posx + lado_1 + passo_x,posy + passo_y)
p_4 = (posx + passo_x, posy+passo_y)
p_5 = (posx, posy+lado_2)
p_6 = (posx + lado_1, posy + lado_2)
p_7 = (posx + lado_1 + passo_x, posy + lado_2 + passo_y)
p_8 = (posx + passo_x, posy + lado_2 + passo_y)
# Desenho
linha_b(p_1, p_2)
linha_b(p_2, p_3)
linha_b(p_3, p_4)
linha_b(p_4, p_1)
linha_b(p_5, p_6)
linha_b(p_6, p_7)
linha_b(p_7, p_8)
linha_b(p_8, p_5)
linha_b(p_1, p_5)
linha_b(p_2, p_6)
linha_b(p_4, p_8)
linha_b(p_3, p_7)
turtle.hideturtle()
Penso que estamos de acordo de que se trata de uma solução mais limpa. Notar que aproveitámos as oportunidade para acrescentar como parâmetro formal o ângulo que determina o valor dos passos (ver figura).
Mas voltemos a olhar para a figura e admitamos que afinal o que vemos são
dois rectângulos ligados por segmentos. Vamos de novo construir as respectivas primitivas.
def rectangulo(posx, posy, lado_1, lado_2):
""" Desenha um rectangulo com o canto inferior esquerdo em (posx, posy)."""
# Posiciona-se
turtle.pu()
turtle.goto(posx,posy)
turtle.pd()
# desenha
for i in range(2):
turtle.fd(lado_1)
turtle.left(90)
turtle.fd(lado_2)
turtle.left(90)
turtle.hideturtle()
def linha(x_1,y_1, x_2,y_2):
""" Desenha uma linha entre dois pontos."""
# posiciona-se
turtle.pu()
turtle.goto(x_1,y_1)
turtle.pd()
# Desenha
turtle.goto(x_2,y_2)
Agora, de novo, a questão que resta resolver é a gestão dos pontos.
def main_2(posx, posy, lado_1, lado_2):
""" Desenha o bloco."""
# auxiliares
canto_2_x = lado_2 * math.cos(math.pi/6)
canto_2_y = lado_2 * math.sin(math.pi/6)
# rectangulos
rectangulo(posx, posy, lado_1, lado_2)
rectangulo(canto_2_x, canto_2_y, lado_1, lado_2)
# linhas
linha(posx, posy, canto_2_x,canto_2_y)
linha(posx, posy+lado_2, canto_2_x,canto_2_y + lado_2)
linha(posx + lado_1, posy, canto_2_x + lado_1,canto_2_y)
linha(posx + lado_1, posy+lado_2, canto_2_x + lado_1,canto_2_y + lado_2)
E cá está muito claro: dois rectângulos e quatro segmentos. Mas como somos esquisitos,um dia olhando de novo para a figura achámos que afinal tudo o que víamos eram
degenerações de losangos (degeneração no mesmo sentido de que um rectângulo é um quadrado degenerado...).
Vamos então resolver a questão de desenhar a dita forma.
def quase_losango(posx, posy, lado_1, lado_2, angulo, orientacao):
# Posiciona-se
turtle.pu()
turtle.goto(posx,posy)
turtle.pd()
turtle.setheading(orientacao)
# desenha
for i in range(2):
turtle.fd(lado_1)
turtle.left(angulo)
turtle.fd(lado_2)
turtle.left(180-angulo)
turtle.hideturtle()
Isto resolvido, vamos ter o desenho de quatro quase-losangos (na realidade dois são mesmo losangos...).
def main_3(posx, posy, lado_1, lado_2):
""" Desenha o bloco."""
# auxiliares
canto_2_x = lado_2 * math.cos(math.pi/6)
canto_2_y = lado_2 * math.sin(math.pi/6)
# quase losangos :pela ordem maior-frente, menor-esquerdo, menor-direito, maior-trás
quase_losango(posx, posy, lado_1, lado_2, 30,0)
quase_losango(posx, posy, lado_2, lado_2, 60,30)
quase_losango(posx+lado_1, posy, lado_2, lado_2, 60,30)
quase_losango(posx, posy+lado_2, lado_1, lado_2, 30,0)
Veja como tudo se simplificou. Mas não se esqueça de
importar os módulos turtle e math! Agora pode dedicar-se a embelezar a solução. Por exemplo, colorindo-a...
Moral da História: para diferentes modos de olhar e ver, diferentes soluções. Todas são iguais (no produto final), mas há umas mais iguais do que outras. É muito importante aprender a ver e isso treina-se. Pode começar a treinar com as duas figuras abaixo. O que vê?
Sem comentários:
Enviar um comentário