Nas aulas foi colocado o problema de visualizar na forma de um
histograma o resultado de uma experiência de lançamento de um dado. O histograma permitia saber quantas vezes saiu cada número. Pretende-se algo como a figura ilustra.
Vamos novamente tentar perceber se podemos
dividir o problema em sub-problemas de modo a tornar a nossa missão mais fácil. Perante o anunciado é evidente que temos dois sub-problemas: (1) efectuar a experiência contando o número de vezes que saiu cada número e, (2) usar essa informação para construir o histograma. As condições do enunciado forçam a usar o modulo
turtle para a visualização! É clara a existência de uma
dependência entre os dois sub-problemas, pelo que antes de começarmos a resolver em separado cada um deles precisamos definir o seu interface. Uma opção que se impõe é que o sub-problema (1) depende do número de lançamentos
n para construir um
tuplo (n1,n2,n3,n4,n5,n6), com
ni igual ao número de vezes que saiu o número
i, e
n1+n2+n3+n4+n5+n6 = n. A escolha de um tuplo é natural pois precisamos de um contentor, com a função de
memória. Tomadas estas decisões, podemos passar a concretização do programa.
01.
import
turtle
02.
03.
def
dados_histo(n):
04.
05.
res
=
lanca_dado(n)
06.
07.
histograma(res)
08.
09.
10.
def
lanca_dado(n):
11.
pass
12.
13.
14.
def
histograma(res):
15.
pass
16.
17.
18.
if
__name__
=
=
'__main__'
:
19.
n
=
100
20.
dados_histo(n)
Vamos começar por resolver o segundo sub-problema. Para tal, vamos de novo decompor o sub-problema em sub-problemas. Aqui temos, pelo menos, duas opções: (a) numa leitura “vertical”, temos quatro sub-problemas: escreve os números de 1 a 6, desenha um traço, desenha os rectângulos e escreve os números correspondentes aos números de vezes que saiu cada número; (b) numa leitura “horizontal, temos seis sub-problemas idênticos: escrever um número, desenhar um traço, desenhar uma coluna e, novamente, escrever um número. A nossa escolha vai ser a segunda, pois é aquela que nos permite ter mais graus de liberdade.
01.
import
turtle
02.
03.
def
dados_histo(n):
04.
05.
res
=
lanca_dado(n)
06.
07.
histograma(res)
08.
09.
10.
def
lanca_dado(n):
11.
pass
12.
13.
def
histograma(res):
14.
posx
=
-
100
15.
posy
=
0
16.
comp_linha
=
80
17.
for
i,alt
in
enumerate(res):
18.
19.
desenha(i
+
1
,alt,posx,posy,comp_linha)
20.
21.
posx
=
posx
+
comp_linha
22.
23.
def
desenha(i,alt, posx,posy,comp_linha):
24.
pass
25.
26.
if
__name__
=
=
'__main__'
:
27.
n
=
100
28.
teste
=
(
46
,
39
,
105
,
0
,
44
,
5
)
29.
histograma(teste)
30.
No esboço de solução apresentado podemos verificar que o programa histograma se limita a desenhar cada caso em sequência. Note como conseguimos os valores do número e do número de vezes que saiu graça ao uso de
enumerate. Note ainda que a opção tomada obriga a que cada caso singular tenha que saber as quatro componentes relevantes: posição, tamanho do traço, numero do dado e numero de vezes que saiu. A posição para desenhar a coluna vai ser o
centro pelo que pode ser calculada a partir do conhecimento do tamanho do traço. Tal como está, podemos testar o programa … mesmo que este não faça nada! Esta é uma das
vantagens da programação descendente: podemos testar primeiro as soluções para os problemas e depois de as integrarmos no programa principal, testar o programa principal. A eliminação de eventuais erros é deste modo mais fácil de fazer. Passemos ao caso mais básico. São quatro so sub-problemas básicos que o compõem: número, linha, coluna, número. No entanto os dois problema de escrita de um número são na realidade o mesmo.
1.
def
desenha(i,alt, posx,posy,comp_linha):
2.
3.
4.
5.
6.
pass
Podemos resolver cada um destes três sub-problemas e testá-los isoladamente.
01.
def
coluna(posx,posy, lado_1, lado_2,cor):
02.
03.
turtle.penup()
04.
turtle.goto(posx,posy)
05.
turtle.pendown()
06.
07.
turtle.color(cor)
08.
turtle.begin_fill()
09.
for
i
in
range(
2
):
10.
turtle.forward(lado_1)
11.
turtle.left(
90
)
12.
turtle.forward(lado_2)
13.
turtle.left(
90
)
14.
turtle.end_fill()
15.
turtle.hideturtle()
16.
17.
def
linha(posx,posy,comp_linha,cor):
18.
19.
turtle.penup()
20.
turtle.goto(posx,posy)
21.
turtle.color(cor)
22.
turtle.pendown()
23.
24.
turtle.forward(comp_linha)
25.
turtle.hideturtle()
26.
27.
def
escreve_numero(posx,posy,fonte,valor,cor):
28.
29.
turtle.penup()
30.
turtle.goto(posx,posy)
31.
turtle.color(cor)
32.
turtle.pendown()
33.
34.
turtle.write(valor,font
=
fonte)
35.
turtle.hideturtle()
Agora precisamos de integrar esses sub-problemas no sub-problema de desenho de uma componente. Aqui vamos ter que perceber as relações entre cada um dos sub-componentes. Em primeiro lugar,
decidimos que a largura da coluna será igual a metade do comprimento do traço. Em segundo lugar, fixamos a fonte no tamanho 12 e controlamos a posição da escrita.
01.
def
desenha(i,alt, posx,posy,comp_linha):
02.
03.
escreve_numero(posx
+
comp_linha
/
2
,posy
-
15
,(
'Arial'
,
12
,
'bold'
),i,
'black'
)
04.
05.
linha(posx,posy,comp_linha,
'red'
)
06.
07.
coluna(posx
+
comp_linha
/
4
,posy,comp_linha
/
2
,alt,
'red'
)
08.
09.
escreve_numero(posx
+
comp_linha
/
2
-
5
,posy
+
alt ,(
'Arial'
,
12
,
'bold'
),alt,
'black'
)
Podemos agora testar o problema de visualizar. E está na hora de ver tudo junto.
01.
import
turtle
02.
03.
def
dados_histo(n):
04.
05.
res
=
lanca_dado(n)
06.
07.
histograma(res)
08.
09.
10.
def
lanca_dado(n):
11.
pass
12.
13.
14.
def
histograma(res):
15.
posx
=
-
100
16.
posy
=
0
17.
comp_linha
=
80
18.
for
i,alt
in
enumerate(res):
19.
20.
desenha(i
+
1
,alt,posx,posy,comp_linha)
21.
22.
posx
=
posx
+
comp_linha
23.
24.
def
desenha(i,alt, posx,posy,comp_linha):
25.
26.
escreve_numero(posx
+
comp_linha
/
2
,posy
-
15
,(
'Arial'
,
12
,
'bold'
),i,
'black'
)
27.
28.
linha(posx,posy,comp_linha,
'red'
)
29.
30.
coluna(posx
+
comp_linha
/
4
,posy,comp_linha
/
2
,alt,
'red'
)
31.
32.
escreve_numero(posx
+
comp_linha
/
2
-
5
,posy
+
alt ,(
'Arial'
,
12
,
'bold'
),alt,
'black'
)
33.
34.
35.
def
coluna(posx,posy, lado_1, lado_2,cor):
36.
37.
turtle.penup()
38.
turtle.goto(posx,posy)
39.
turtle.pendown()
40.
41.
turtle.color(cor)
42.
turtle.begin_fill()
43.
for
i
in
range(
2
):
44.
turtle.forward(lado_1)
45.
turtle.left(
90
)
46.
turtle.forward(lado_2)
47.
turtle.left(
90
)
48.
turtle.end_fill()
49.
turtle.hideturtle()
50.
51.
def
linha(posx,posy,comp_linha,cor):
52.
53.
turtle.penup()
54.
turtle.goto(posx,posy)
55.
turtle.color(cor)
56.
turtle.pendown()
57.
58.
turtle.forward(comp_linha)
59.
turtle.hideturtle()
60.
61.
def
escreve_numero(posx,posy,fonte,valor,cor):
62.
63.
turtle.penup()
64.
turtle.goto(posx,posy)
65.
turtle.color(cor)
66.
turtle.pendown()
67.
68.
turtle.write(valor,font
=
fonte)
69.
turtle.hideturtle()
70.
71.
72.
73.
74.
if
__name__
=
=
'__main__'
:
75.
n
=
100
76.
teste
=
(
46
,
39
,
105
,
0
,
44
,
5
)
77.
fonte
=
(
'Arial'
,
24
,
'bold'
)
78.
posx
=
0
79.
posy
=
0
80.
cor_1
=
'black'
81.
cor_2
=
'red'
82.
comp
=
80
83.
lado_1
=
comp
/
2
84.
lado_2
=
50
85.
86.
87.
88.
89.
histograma(teste)
90.
91.
turtle.exitonclick()
Agora é a vez do primeiro sub-problema, simular o lançamento do dado. Já fizemos isso em problemas anteriores semelhantes. Aqui a novidade reside no facto de querermos memorizar os resultados. Dado o facto de estarmos a usar tuplos, que são objectos imutáveis, vamos decompor esta questão em duas: (1) guardar os valores saídos em cada lançamento, (2) contar quantas vezes saiu cada um. Solução óbvia:
01.
def
lanca_dado(n):
02.
03.
resultado
=
tuple()
04.
for
i
in
range(n):
05.
numero
=
random.randint(
1
,
6
)
06.
resultado
=
resultado
+
(numero,)
07.
08.
conta
=
tuple()
09.
for
i
in
range(
1
,
7
):
10.
conta_i
=
resultado.count(i)
11.
conta
=
conta
+
(conta_i,)
12.
return
conta
Podemos finalmente testar o programa completo.
001.
import
turtle
002.
import
random
003.
004.
def
dados_histo(n):
005.
006.
res
=
lanca_dado(n)
007.
008.
histograma(res)
009.
010.
011.
def
lanca_dado(n):
012.
013.
resultado
=
tuple()
014.
for
i
in
range(n):
015.
numero
=
random.randint(
1
,
6
)
016.
resultado
=
resultado
+
(numero,)
017.
018.
conta
=
tuple()
019.
for
i
in
range(
1
,
7
):
020.
conta_i
=
resultado.count(i)
021.
conta
=
conta
+
(conta_i,)
022.
return
conta
023.
024.
025.
def
histograma(res):
026.
posx
=
-
100
027.
posy
=
0
028.
comp_linha
=
80
029.
for
i,alt
in
enumerate(res):
030.
031.
desenha(i
+
1
,alt,posx,posy,comp_linha)
032.
033.
posx
=
posx
+
comp_linha
034.
035.
def
desenha(i,alt, posx,posy,comp_linha):
036.
037.
escreve_numero(posx
+
comp_linha
/
2
,posy
-
15
,(
'Arial'
,
12
,
'bold'
),i,
'black'
)
038.
039.
linha(posx,posy,comp_linha,
'red'
)
040.
041.
coluna(posx
+
comp_linha
/
4
,posy,comp_linha
/
2
,alt,
'red'
)
042.
043.
escreve_numero(posx
+
comp_linha
/
2
-
5
,posy
+
alt ,(
'Arial'
,
12
,
'bold'
),alt,
'black'
)
044.
045.
046.
def
coluna(posx,posy, lado_1, lado_2,cor):
047.
048.
turtle.penup()
049.
turtle.goto(posx,posy)
050.
turtle.pendown()
051.
052.
turtle.color(cor)
053.
turtle.begin_fill()
054.
for
i
in
range(
2
):
055.
turtle.forward(lado_1)
056.
turtle.left(
90
)
057.
turtle.forward(lado_2)
058.
turtle.left(
90
)
059.
turtle.end_fill()
060.
turtle.hideturtle()
061.
062.
def
linha(posx,posy,comp_linha,cor):
063.
064.
turtle.penup()
065.
turtle.goto(posx,posy)
066.
turtle.color(cor)
067.
turtle.pendown()
068.
069.
turtle.forward(comp_linha)
070.
turtle.hideturtle()
071.
072.
def
escreve_numero(posx,posy,fonte,valor,cor):
073.
074.
turtle.penup()
075.
turtle.goto(posx,posy)
076.
turtle.color(cor)
077.
turtle.pendown()
078.
079.
turtle.write(valor,font
=
fonte)
080.
turtle.hideturtle()
081.
082.
083.
084.
085.
if
__name__
=
=
'__main__'
:
086.
n
=
100
087.
teste
=
(
46
,
39
,
105
,
0
,
44
,
5
)
088.
fonte
=
(
'Arial'
,
24
,
'bold'
)
089.
posx
=
0
090.
posy
=
0
091.
cor_1
=
'black'
092.
cor_2
=
'red'
093.
comp
=
80
094.
lado_1
=
comp
/
2
095.
lado_2
=
50
096.
097.
098.
099.
100.
101.
102.
dados_histo(n)
103.
turtle.exitonclick()
104.
105.
Para concluir o exercício, experimente com diferentes valores de tentativas. Que conclusões pode tirar à medida que n aumenta?? Identifique os pontos em que a solução não é genérica. como pode alterar a situação??
Na sala, alguns disseram que
nos histogramas as colunas não estão separadas. A adaptação do código feito para que a visualização seja essa é mínima: retirar a linha na definição desenha, separar a cor do traço (pencolor) da cor de preenchimento (fillcolor) em
desenha para que as colunas fiquem claramente a ver-se e, na função
histograma, alterar o posicionamento ao longo do eixo dos xx da cada coluna.
001.
import
turtle
002.
import
random
003.
004.
def
dados_histo(n):
005.
006.
res
=
lanca_dado(n)
007.
008.
histograma(res)
009.
010.
011.
def
lanca_dado(n):
012.
013.
resultado
=
tuple()
014.
for
i
in
range(n):
015.
numero
=
random.randint(
1
,
6
)
016.
resultado
=
resultado
+
(numero,)
017.
018.
conta
=
tuple()
019.
for
i
in
range(
1
,
7
):
020.
conta_i
=
resultado.count(i)
021.
conta
=
conta
+
(conta_i,)
022.
return
conta
023.
024.
025.
def
histograma(res):
026.
posx
=
-
100
027.
posy
=
0
028.
comp_linha
=
80
029.
for
i,alt
in
enumerate(res):
030.
031.
desenha(i
+
1
,alt,posx,posy,comp_linha)
032.
033.
posx
=
posx
+
comp_linha
/
2
034.
035.
def
desenha(i,alt, posx,posy,comp_linha):
036.
037.
escreve_numero(posx
+
comp_linha
/
2
,posy
-
15
,(
'Arial'
,
12
,
'bold'
),i,
'black'
)
038.
039.
coluna(posx
+
comp_linha
/
4
,posy,comp_linha
/
2
,alt,
'red'
)
040.
041.
escreve_numero(posx
+
comp_linha
/
2
-
5
,posy
+
alt ,(
'Arial'
,
12
,
'bold'
),alt,
'black'
)
042.
043.
044.
def
coluna(posx,posy, lado_1, lado_2,cor):
045.
046.
turtle.penup()
047.
turtle.goto(posx,posy)
048.
turtle.pendown()
049.
050.
turtle.pencolor(
'black'
)
051.
turtle.fillcolor(cor)
052.
turtle.begin_fill()
053.
for
i
in
range(
2
):
054.
turtle.forward(lado_1)
055.
turtle.left(
90
)
056.
turtle.forward(lado_2)
057.
turtle.left(
90
)
058.
turtle.end_fill()
059.
turtle.hideturtle()
060.
061.
def
linha(posx,posy,comp_linha,cor):
062.
063.
turtle.penup()
064.
turtle.goto(posx,posy)
065.
turtle.color(cor)
066.
turtle.pendown()
067.
068.
turtle.forward(comp_linha)
069.
turtle.hideturtle()
070.
071.
def
escreve_numero(posx,posy,fonte,valor,cor):
072.
073.
turtle.penup()
074.
turtle.goto(posx,posy)
075.
turtle.color(cor)
076.
turtle.pendown()
077.
078.
turtle.write(valor,font
=
fonte)
079.
turtle.hideturtle()
080.
081.
082.
083.
084.
if
__name__
=
=
'__main__'
:
085.
n
=
1000
086.
teste
=
(
46
,
39
,
105
,
0
,
44
,
5
)
087.
fonte
=
(
'Arial'
,
24
,
'bold'
)
088.
posx
=
0
089.
posy
=
0
090.
cor_1
=
'black'
091.
cor_2
=
'red'
092.
comp
=
80
093.
lado_1
=
comp
/
2
094.
lado_2
=
50
095.
096.
097.
098.
099.
100.
101.
dados_histo(n)
102.
turtle.exitonclick()
103.

Para o leitor: e se quisermos que o histograma possa ter uma orientação qualquer??