Em primeiro lugar, continuo a achar estranho que se entregue um ponto para corrigir quando somando a cotação das perguntas respondidas é impossível ter nota para passar. O único resultado disso é mais tempo para corrigir e, consequentemente, atrasar a divulgação dos resultados. Também me choca ver casos de pessoas que respondem a tudo mas têm zero no final. Infelizmente não são poucos.
Em segundo lugar, a quantidade de erros de português, erros lexicais, de sintaxe e de semântica é muito preocupante. O pouco cuidado na apresentação também é regra.
Em terceiro lugar, confunde-me que alunos do ensino superior não consigam interpretar/entender o enunciado. Por exemplo, se eu coloco ??? numa listagem, isso não é a saída do interpretador! Que não entendam quando se pede uma resposta geral ou uma resposta específica. Se eu coloco um exemplo com os vectores [1,2,3] e [4,8,12] (pergunta 3) não é porque queira um programa para calcular a diferença absoluta daqueles vectores apenas. O mesmo se aplica quando apresenta um tabuleiro 4 X 4. Todos estes aspectos estavam bem clarificados no enunciado de cada pergunta!!
Finalmente, registo a vossa dificuldade em dominar a complexidade de resolver um problema. Vamos por isso às perguntas concretas, primeiro as teóricas, depois as de programação.
Pergunta 1
Um conceito nuclear em programação é o de objecto e das suas características. Chegar ao final do ano e ainda não saber que os objectos têm identidade, valor e tipo e que é com base nestas características que se distinguem os que são mutáveis dos que não são.
Pergunta 2
Quem não tiver a noção do que é um tipo de dados (objecto + operações) não consegue responder. O erro mais comum foi dizer que são equivalentes pois posso transformar um ficheiro numa cadeia de caracteres. Mas assim deixamos de estar a operar com um ficheiro...
Pergunta 3
Esta pergunta (que valia 25% da nota!) marca a fronteira de quem merece e de quem não merece passar! Posso admitir (embora estranhe) que têm umas convicções matemáticas bizarras relativamente a operações com módulos. Tratava-se de efectuar a soma do módulo das diferenças componente a componente. Não se tratava, por exemplo, de somar todos os valores de um vector, somar todos os valores de outro vector, fazer a diferença e depois tomar o valor absoluto do resultado. E que posso dizer de quem calcula o máximo apenas sobre um valor? Ao fim de um ano, não posso aceitar que não consigam fazer um programa que envolve um acumulador e um ciclo.
Pergunta 4
No exame da época normal tinha parecido um problema parecido: passar informação de um ficheiro para um dicionário. Deixei aqui no blogue vários posts sobre o assunto. Mas mesmo assim...
Todos os problemas envolvem conhecimento sobre a linguagem de programção e sobre o processo de construção da solução. Este não foge à regra. A melhor maneira de dominar a complexidade de um problema é abordar a solução de modo progressivo, procurando só tomar decisões concretas quando não há alternativa. Vejamos neste caso. Num olhar global, a estratégia é fácil de enunciar: (a) ler o ficheiro linha a linha; (b) extrair a informação relevante; (c)colocar no dicionário. Daí o esboço do programa:
01.
def
dic_max_temp_b(ficheiro):
02.
""" Do ficheiro ao dicionário."""
03.
# inicialização
04.
# ---- leitura
05.
# lê linha
06.
while
# há informação:
07.
# extrai informação
08.
# coloca no dicionário
09.
# lê linha
10.
# finaliza
11.
return
# resultado
A inicialização consiste em abrir o ficheiro e criar o dicionário vazio. No final, fechar o ficheiro.
01.
def
dic_max_temp_b(ficheiro):
02.
""" Do ficheiro ao dicionário."""
03.
# inicialização
04.
f_in
=
open(ficheiro,
'r'
)
05.
dic
=
{}
06.
# ---- leitura
07.
# lê linha
08.
while
# há informação:
09.
# extrai informação
10.
# coloca no dicionário
11.
# lê linha
12.
# finaliza
13.
f_in.close()
14.
return
dic
A leitura tem que ser feita linha a linha, pois é assim que a informação relevante está organizada e é assim que terá que ser processada:
01.
def
dic_max_temp_b(ficheiro):
02.
""" Do ficheiro ao dicionário."""
03.
# inicialização
04.
f_in
=
open(ficheiro,
'r'
)
05.
dic
=
{}
06.
# ---- leitura
07.
# lê linha
08.
linha
=
f_in.readline()
09.
10.
while
# há informação:
11.
# extrai informação
12.
# coloca no dicionário
13.
# lê linha
14.
linha
=
f_in.readline()
15.
# finaliza
16.
f_in.close()
17.
return
dic
Já só falta extrair a informação e colocar no dicionário. Quantos elementos existem por linha? Três: o nome do produto, o número da experiência e o valor da temperatura. Tendo o cuidado de saber que é preciso retirar a marca de fim de linha podemos obter e separar a informação contida numa linha com uma única instrução:
01.
def
dic_max_temp_b(ficheiro):
02.
""" Do ficheiro ao dicionário."""
03.
# inicialização
04.
f_in
=
open(ficheiro,
'r'
)
05.
dic
=
{}
06.
# ---- leitura
07.
# lê linha
08.
linha
=
f_in.readline()
09.
while
# há informação:
10.
# extrai informação
11.
cod,num,temp
=
linha[:
-
1
].split()
12.
# coloca no dicionário
13.
# lê linha
14.
linha
=
f_in.readline()
15.
# finaliza
16.
f_in.close()
17.
return
dic
Esta forma de fazer é genérica. Quem não partiu a linha nos seus constituintes e manteve a cadeia de caracteres tinha o problema de saber em que posições começava e acabava cada elemento. E isso deu azo a muita confusão. Imaginem que quem colocou a informação no ficheiro coloca diferentes espaços entre elementos? Ou que o número de experiências é maior do que dez? Ou que a temperatura pode vir antes do número da experiência? A solução de manter uma cadeia de caracteres ainda funciona? Se não (o que é verdade!) que alterações é preciso fazer no código?
Agora já só falta colocar a informação no dicionário. Temos duas situações: ou já lá está algo, ou não. O primeiro caso ainda se subdivide em dois: ou o que já existe é maior do que o novo valor ou não: Primeira divisão:
if dic.has_key(cod):
...
ou (porque o método has_key já não existe em Python 3.0)
if cod in dic.keys():
...
ou ainda
if dic.get(cod, False):
...
E vamos à segunda divisão:
1.
if
cod
in
dic.keys():
2.
if
dic[cod] < int(temp):
3.
# substitui
4.
else
:
5.
# introduz
que dá origem a:
1.
if
cod
in
dic.keys():
2.
if
dic[cod] < int(temp):
3.
dic[cod]
=
int(temp)
4.
else
:
5.
dic[cod]
=
int(temp)
E notamos duas coisas. Uma, importante, é que temos que fazer a conversão para inteiros. Experimente testar se ‘4’ > ’10’ e perceberá a razão! Outra, é o facto de andarmos com código repetido. Nesta última situação, ajuda saber um pouco de dicionários em Python. Tudo se pode fazer numa linha de código.
01.
def
dic_max_temp_b(ficheiro):
02.
""" Do ficheiro ao dicionário."""
03.
# inicialização
04.
f_in
=
open(ficheiro,
'r'
)
05.
dic
=
{}
06.
# ---- leitura
07.
# lê linha
08.
linha
=
f_in.readline()
09.
while
# há informação:
10.
# extrai informação
11.
cod,num,temp
=
linha[:
-
1
].split()
12.
# coloca no dicionário
13.
dic[cod]
=
max(dic.get(cod,
-
100
),int(temp))
14.
# lê linha
15.
linha
=
f_in.readline()
16.
# finaliza
17.
f_in.close()
18.
return
dic
Pergunta 5
Esta pergunta tinha algumas dificuldades: (a) saber posicionar a tartaruga para cada quadrado; (b) em cada momento saber a cor do quadrado. Mas estas dificuldades eram fáceis de ultrapassar se se lembrassem que tínhamos feito um problema exactamente igual na ficha sobre imagens! Muito me surpreendeu ainda tantos alunos não perceberem que deviam usar o programa para desenhar um quadrado de uma dada cor de forma autónoma. Isto significa que não conseguem pensar no problema dividindo-o em partes mais simples, como ainda fizemos para o caso do problema 4. Vamos ver então como se resolve a questão. Em primeiro lugar tomamos a decisão de imprimir linha a linha:
1.
def
tabuleiro(tartaruga,n,lado):
2.
# inicialização
3.
for
l
in
range(n):
4.
# imprime linha l
A inicialização consiste apenas em colocar a tartaruga numa dada posição inicial. Essa posição tanto podia ser comunicada como parâmetro, como podia ser definida em termos absolutos no interior do programa. Segunda questão: como desenhamos uma linha? Decisão: quadrado a quadrado:
1.
def
tabuleiro(tartaruga,n,lado):
2.
# inicialização
3.
for
l
in
range(n):
4.
# desenha linha l
5.
# inicialização da linha
6.
for
c
in
range(n):
7.
# desenha coluna c
Neste momento, não podemos adiar mais a decisão de saber a cor. Podemos ter uma solução que só depende da alternância de cor dentro de uma linha. Mas, se formos por aí, não nos podemos esquecer que as linhas também alternam a sua cor de início! Outra solução, melhor, é tomar a decisão em termos da linha e da coluna. Basta perceber que sempre que a soma dos índices da linha e da coluna for par o quadrado é branco:
01.
def
tabuleiro(tartaruga,n,lado):
02.
# inicialização
03.
for
l
in
range(n):
04.
# desenha linha l
05.
# inicialização da linha
06.
for
c
in
range(n):
07.
# desenha coluna c
08.
if
(l
+
c)
%
2
=
=
0
:
09.
# quadrado branco
10.
else
:
11.
# quadrado preto
E como se desenha o quadrado? Fazendo uso do programa fornecido:
01.
def
tabuleiro(tartaruga,n,lado):
02.
# inicialização
03.
for
l
in
range(n):
04.
# desenha linha l
05.
# inicialização da linha l
06.
for
c
in
range(n):
07.
# desenha coluna c
08.
if
(l
+
c)
%
2
=
=
0
:
09.
quad(tartaruga, lado,‘white’)
10.
else
:
11.
quad(tartaruga,quad,‘black’)
Como estamos a ver, das duas dificuldades à pouco enunciadas, só resolvemos a da cor. Falta a da posição! No início será (0,0). Esta decisão tem consequências? Claro: sempre que mudarmos de linha temos que colocar a tartaruga na posição (0, linha). Como podemos fazer isso? De modo relativo ou de modo absoluto. De modo relativo: tendo em atenção quanto avançámos mandamos a tartaruga recuar igual valor. De modo absoluto: usando o comando setx(0). Mas e o valor da coordenada da linha, necessário sempre que mudamos de linha? Também não é difícil de ver que deve ser o valor que tinha mais o valor do lado:
01.
def
tabuleiro(tartaruga,n,lado):
02.
# inicialização
03.
tartaruga.pu()
04.
tartaruga.goto(
0
,
0
)
05.
tartaruga.pd()
06.
for
l
in
range(n):
07.
# desenha linha l
08.
# inicialização da linha l
09.
tartaruga.setx(
0
)
10.
tartaruga.sety(tartaruga.ycor()
+
lado)
11.
# desenha linha
12.
for
c
in
range(n):
13.
if
(c
+
l)
%
2
=
=
0
:
14.
quad(tartaruga,lado,
'white'
)
15.
else
:
16.
quad(tartaruga,lado,
'black'
)
Claro que também se podia usar tartaruga.sety(l * lado). Mas assim ainda não avançamos coluna a coluna?! Pois não. Por cada quadrado desenhado temos que avançar o valor do lado:
01.
def
tabuleiro(tartaruga,n,lado):
02.
# inicialização
03.
tartaruga.pu()
04.
tartaruga.goto(
0
,
0
)
05.
tartaruga.pd()
06.
for
l
in
range(n):
07.
# desenha linha l
08.
# inicialização da linha l
09.
tartaruga.setx(
0
)
10.
tartaruga.sety(tartaruga.ycor()
+
lado)
11.
# desenha linha
12.
for
c
in
range(n):
13.
if
(c
+
l)
%
2
=
=
0
:
14.
quad(tartaruga,lado,
'white'
)
15.
else
:
16.
quad(tartaruga,lado,
'black'
)
17.
tartaruga.setx(tartaruga.xcor()
+
lado)
Esta solução é simples e elegante. Podemos facilmente alterar o programa para que o tabuleiro não seja do tipo n X n,outras cores, desenho por colunas em vez de ser por linhas. Mudar de forma é que é mais complexo. Mas nas nossas experimentações íamos descobrir é que não protegemos devidamente o reposicionamento da tartaruga: em certas situações ficam um rasto visível. Mas até isso se resolve sem grande dificuldade.
01.
def
tabuleiro_b(tartaruga,pos,n1,n2,lado, cor_1, cor_2):
02.
tartaruga.pu()
03.
tartaruga.goto(pos)
04.
tartaruga.pd()
05.
for
c
in
range(n1):
06.
# reposiciona
07.
tartaruga.pu()
08.
tartaruga.sety(pos[
1
])
09.
tartaruga.setx(tartaruga.xcor()
+
lado)
10.
tartaruga.down()
11.
# desenha coluna
12.
for
l
in
range(n2):
13.
if
(c
+
l)
%
2
=
=
0
:
14.
quad(tartaruga,lado,cor_1)
15.
else
:
16.
quad(tartaruga,lado,cor_2)
17.
tartaruga.pu()
18.
tartaruga.sety(tartaruga.ycor()
+
lado)
19.
tartaruga.down()
Divirta-se!
Sem comentários:
Enviar um comentário