Nas aulas discutimos o problema de desenhar uma grelha rectangular com n células, cada uma um quadrado com um dado comprimento do lado. Uma das soluções que apareceu baseava-se na ideia de desenhar a grelha como nós humanos geralmente fazemos: desenhar separadamente as linhas verticais e as horizontais. Vejamos uma solução básica:
import turtle
def grelha_1(dim, lado):
""" Solução básica."""
# verticais
turtle.setheading(90)
for i in range(dim+1):
# posiciona
turtle.penup()
turtle.goto(i * lado,0)
turtle.pendown()
# desenha
turtle.forward(dim*lado)
# horizontais
turtle.setheading(0)
for i in range(dim+1):
# posiciona
turtle.penup()
turtle.goto(0,i*lado)
turtle.pendown()
# desenha
turtle.forward(dim*lado)
turtle.hideturtle()
Como se pode ver as linhas são desenhadas em separado e cada tipo de linha (verticais ou horizontais) é desenhada no interior de um ciclo. A parte relevante em cada ciclo é o posicionamento da tartaruga para desenhar a linha. Fazemos isso através de um goto.
Uma primeira alteração possível é considerar a possibilidade de controlar a localização do canto inferior esquerdo. Vejamos como se pode fazer.
def grelha_2(dim, lado,pos_x,pos_y):
""" Controlando a posição do canto inferior esquerdo."""
# verticais
turtle.setheading(90)
for i in range(dim+1):
# posiciona
turtle.penup()
turtle.goto(pos_x + i * lado,pos_y)
turtle.pendown()
# desenha
turtle.forward(dim*lado)
# horizontais
turtle.setheading(0)
for i in range(dim+1):
# posiciona
turtle.penup()
turtle.goto(pos_x,pos_y+i*lado)
turtle.pendown()
# desenha
turtle.forward(dim*lado)
turtle.hideturtle()
Como se notará a alteração é mínima, e traduz-se a colocar o valor das coordenadas do canto inferior esquerdo no sítio certo.
Suponhamos agora que nos pedem uma solução em que seja também possível controlar a orientação do quadrado. Esta questão já obriga a uma ginástica adicional, mas a questão central mantém-se a mesma: definir os pontos em que se iniciam as linhas. Eis uma solução, não muito elegante, mas que funciona…
def grelha_4(dim, lado,pos_x,pos_y,orient):
""" Controlando a posição e a orientação. """
# verticais
for i in range(dim+1):
# posiciona
turtle.penup()
turtle.goto(pos_x,pos_y)
turtle.setheading(orient)
turtle.forward(i*lado)
turtle.setheading(90+orient)
turtle.pendown()
# desenha
turtle.forward(dim*lado)
# horizontais
for i in range(dim+1):
# posiciona
turtle.penup()
turtle.goto(pos_x,pos_y)
turtle.setheading(90+orient)
turtle.forward(i*lado)
turtle.setheading(orient)
turtle.pendown()
# desenha
turtle.forward(dim*lado)
turtle.hideturtle()
Outras alterações poderiam ser feitas, como seja mudar a espessura das linhas ou a sua cor. Mas o que não nos agrada é a legibilidade do código. Afinal o nosso ponto de partida foi considerar o desenho da grelha com base no conceito de linha, mas esse conceito está explicitamente ausente nas soluções acima. Vamos remediar a situação definindo uma função que nos permite desenhar uma linha, com uma dada posição inicial uma orientação e um dado comprimento. Não é difícil.
def linha(pos_x,pos_y, orient, tam):
# posiciona
turtle.penup()
turtle.goto(pos_x,pos_y)
turtle.setheading(orient)
turtle.pendown()
# desenha
turtle.forward(tam)
turtle.hideturtle()
Na posse desta nova construção (abstracção), podemos refazer as soluções acima apresentadas. Comecemos pela básica:
def grelha_5(dim, lado):
""" Solução básica."""
# horizontais
for i in range(dim+1):
linha(0,i*lado,0,dim*lado)
# verticais
for i in range(dim+1):
linha(i*lado,0,90,dim*lado)
turtle.hideturtle()
O leitor concordará que corresponde de modo mais claro à forma como enunciámos a solução. Passemos à posição.
def grelha_6(dim, lado,pos_x,pos_y):
""" Solução com controlo da posição do canto inferior esquerdo."""
# horizontais
for i in range(dim+1):
linha(pos_x,pos_y+i*lado,0,dim*lado)
# verticais
for i in range(dim+1):
linha(pos_x+i*lado,pos_y,90,dim*lado)
turtle.hideturtle()
Elementar, não acha? Finalmente a orientação. Aqui decidimos usar um pouco dos nossos conhecimentos de trignometria, para definir as novas posições de início das linhas.
Na posse deste conhecimento a solução vem, finalmente, como:
import math
def grelha_7(dim, lado,pos_x,pos_y,orient):
""" Solução com controlo da posição do canto inferior esquerdo e a orientação."""
deg_rad = math.pi/180
# horizontais
for i in range(dim+1):
linha(pos_x+i*lado*math.cos((orient+90)* deg_rad),pos_y+ i*lado*math.sin((orient+90)* deg_rad),orient,dim*lado)
# verticais
for i in range(dim+1):
linha(pos_x+i*lado*math.cos(orient * deg_rad),pos_y+ i*lado*math.sin(orient * deg_rad),90+orient,dim*lado)
turtle.hideturtle()
Chegados a este ponto podemos achar que o trabalho está feito e, por isso, podemos passar a outro problema. Mas… e se alguém nos pedir a nossa solução para criar um
tabuleiro de xadrez? Precisamos colorir as células, mas como fazer? A dificuldade reside no facto de termos olhado para a grelha não como uma grelha, isto é formada por células justapostas, mas como linhas que se cruzam. E precisamos partir de novo à aventura:
criar a dita grelha formada por quadrados. Mas aprendemos algo com o caso anterior, a saber: usar abstração para criar primitivas é positivo.
Para começar precisamos de uma primitiva para desenhar um quadrado:
def quadrado(pos_x, pos_y, lado, orient):
# posiciona
turtle.penup()
turtle.goto(pos_x,pos_y)
turtle.setheading(orient)
turtle.pendown()
# desenha
for i in range(4):
turtle.forward(lado)
turtle.lt(90)
turtle.hideturtle()
E vamos percorrer de novo a nossa via sacra. Primeiro a versão básica:
def grelha_8(dim, lado):
""" Solução básica."""
# Por linhas
for i in range(dim):
# linha i
for j in range(dim):
quadrado(j*lado,i*lado,lado,0)
turtle.hideturtle()
Não muito diferente, certo? Só que agora temos uma
perspectiva matricial, pelo que precisamos de um ciclo dentro de outro ciclo. Controlar a
posição é trivial:
def grelha_9(dim, lado, pos_x, pos_y):
""" Solução com controlo da posição do canto inferior esquerdo."""
# Por linhas
for i in range(dim):
# linha i
for j in range(dim):
quadrado(pos_x+j*lado,pos_y+i*lado,lado,0)
turtle.hideturtle()
A quatro da
orientação pede um pouco mais de atenção como na versão anterior, mas a lógica é semelhante: trata-se de
definir os pontos iniciais para cada quadrado:
def grelha_10(dim, lado, pos_x, pos_y, orient):
""" Solução com controlo da posição do canto inferior esquerdo e da orientação."""
deg_rad = math.pi/180
# Por linhas
for i in range(dim):
# linha i
p_x = pos_x+i*lado*math.cos((orient+90)*deg_rad)
p_y = pos_y+i*lado*math.sin((orient+90)*deg_rad)
for j in range(dim):
quadrado(p_x,p_y,lado,orient)
p_x = p_x+lado*math.cos(orient*deg_rad)
p_y = p_y+lado * math.sin(orient*deg_rad)
turtle.hideturtle()
Notar que nesta solução o ciclo interior apenas controla o número de vezes que desenhamos um quadrado numa linha.
.
Agora sim podemos dar o trabalho por encerrado!!! Mas, espere aí, ouço-o dizer, a passagem para o ponto de vista das células quadradas não era para termos mais graus de liberdade, nomeadamente em relação à
cor dos quadrados??? É verdade sim senhor. Então vamos a isso. A solução mais simples consistirá em poder desenhar quadrados coloridos…
def quadrado_cor(pos_x, pos_y, lado, orient,cor):
# cor
turtle.color(cor)
# posiciona
turtle.penup()
turtle.goto(pos_x,pos_y)
turtle.setheading(orient)
turtle.pendown()
# desenha
turtle.begin_fill()
for i in range(4):
turtle.forward(lado)
turtle.lt(90)
turtle.end_fill()
turtle.hideturtle()
E agora eis o nosso tabuleiro bi-color:
def grelha_11(dim, lado, pos_x, pos_y, orient):
""" Solução com controlo da posição do canto inferior esquerdo e da orientação."""
deg_rad = math.pi/180
# Por linhas
for i in range(dim):
# linha i
p_x = pos_x+i*lado*math.cos((orient+90)*deg_rad)
p_y = pos_y+i*lado*math.sin((orient+90)*deg_rad)
for j in range(dim):
if (i+j)%2 == 0:
quadrado_cor(p_x,p_y,lado,orient,'black')
else:
quadrado_cor(p_x,p_y,lado,orient,'gray')
p_x = p_x+lado*math.cos(orient*deg_rad)
p_y = p_y+lado * math.sin(orient*deg_rad)
turtle.hideturtle()
Veja apenas como conseguimos o efeito das cores alternadas… Experimente o código e aprecie o resultado.
Se quiser outro tipo de tabuleiros coloridos é só adaptar. Agora é mesmo a
sua vez de fazer alguma coisa. Eu vou descansar um pouco!