[Prévia] [Próxima] [Prévia por assunto] [Próxima por assunto]
[Índice cronológico] [Índice de assunto]

Observacoes sobre o EP2



Ola' a todos,

As notas do EP2 (fase 1 do projeto) estao "saindo do forno" e, como da outra
vez, gostariamos (eu e o Thiago) de fazer algumas observacoes:

- Eu ja' falei da documentacao da outra vez, e vou repetir:
   - coloquem uma breve explicacao de como compilar seus programas (de
     preferencia com um makefile);
   - deem uma "dica" de como rodar o programa e qual o tipo de saida dele. Por
     exemplo, na fase 2, houve grupos que fizeram o programa esperar um "enter"
     entre uma tela e outra. Isso e' otimo mas, como nao tinha sido
     especificado, demorei algum tempo para descobrir por que "./ep | less" nao
     estava funcionando. No caso do jogo, voces precisam explicar como joga-lo,
     e um exemplo pode ser util;
   - Tenham do' dos monitores :-) : nao e' facil ler codigo alheio e, se voces
     nao fornecem uma explanacao sobre a estrutura do programa (tipo: "os
     asteroides sao structs assim assado, que ficam numa lista ligada com/sem
     cabeca; a tela e' representada por uma matriz assim assada chamada "Tela";
     a cada iteracao, o programa executa a funcao "desenha", que desenha a
     tela, depois a funcao "move", que move os corpos na tela, depois a funcao
     "colide", que encontra objetos que estao na mesma coordenada e os destroi;
     a deteccao de colisoes e' feita percorrendo a lista ligada varias vezes,
     uma vez para cada asteroide" etc. etc.), a coisa fica mais dificil. Como o
     EP tambem pedia explicitamente esse tipo de documentacao, falhas nesse
     quesito foram descontadas.
   - facam um relatorio.txt sobre os problemas encontrados e os aspectos que
     julgarem mais importantes, por exemplo, ideias aparentemente otimas que
     voces tiveram mas que foram rejeitadas por alguma razao, limitacoes da
     solucao que voces desenvolveram etc.

- Ja' esta' na hora de voces dominarem o processo de compilacao "em partes";
  nao e' muito bom fazer um arquivo "ep.c"  e colocar tudo la' dentro. Em
  particular nesse EP, em que o enunciado pede explicitamente modularidade no
  codigo, isso custou pontos.

- Tambem e' bom voces aprenderem a usar o "make" um pouco melhor; houve varios
  makefiles do tipo:

ep:
	gcc -o ep file1.c file2.c file3.c file4.c

Nao descontamos pontos por causa disso, porque e' melhor que nada, mas usar o
make assim nao traz nenhuma vantagem em relacao a um script bobo em bash, por
exemplo. O certo seria algo do tipo:

ep: file1.o file2.o file3.o file4.o defs.h
	gcc -o ep file1.o file2.o file3.o file4.o
file1.o:
	gcc -c file1.c
file2.o:
	gcc -c file2.c
file3.o: file3.h
	gcc -c file3.c
file4.o:
	gcc -c file4.c

Esse exemplo, na verdade, esta' bem "1/2 boca", mas cumpre o papel de permitir
a compilacao em partes. Ou seja, se voce esta' escrevendo e testando o arquivo
file2.c, nao precisa recompilar os outros toda vez.

- os testes nao foram realizados como foi pedido, ou seja, eh preciso ser mais
  fiel `a especificacao do projeto.

- Por favor! Houve trabalhos em que 90% do EP se concentra em uma unica funcao
  de 10 telas de tamanho. Facam funcoes mais enxutas e melhor documentadas; uma
  funcao deve realizar uma tarefa simples e bem definida, e ter um nome que
  torne essa tarefa clara. Por exemplo, o "loop" principal do programa
  obviamente deve consistir em algo como "desenhar a tela", "mover os objetos"
  e "eliminar os objetos que colidem" (nao necessariamente nessa ordem). Entao
  nao faz sentido fazer uma funcao enorme que executa essas tres tarefas na
  sequencia. Melhor seria algo do tipo:

/* inicializa estruturas de dados */
init();
/* Desenha tela vazia, so' com a terra e a estacao */
desenha_tela();
for (int i = 0; i < 100; i++) {
	cria_asteroides();
	move_asteroides();
	detecta_colisoes();
	if (nave_atingida()) {
		desenha_tela(); // Para o usuario ver o asteroide que bateu na nave
		printf ("Ja' era!\n");
		break;
	} else {
	desenha_tela();
}	

Esse loop e' tao pequeno e claro que pode fazer parte de main(); se tudo for
feito direitinho, main() vai ocupar umas 2 telas.

Dependendo da estrutura do programa, talvez nao faca sentido separar
"move_asteroides" e "detecta_colisoes", mas sim definir uma funcao
"passa_tempo()" que faca as duas coisas. Mas, nesse caso, voce provavelmente
vai encontrar lugares "dentro" de passa_tempo() onde voce pode usar funcoes
auxiliares para tornar a funcao mais clara. O importante e' que so' de ler o
nome de uma funcao eu ja' saiba qual e' a tarefa que ela desempenha, e so' de
dar uma olhada nela (que deve ser CURTA) eu ja' compreenda quais sao os passos
que ela usa para desempenhar seu papel.

- A modularizacao do projeto nao pode ser aleatoria. Deve-se definir um
  criterio mais ou menos logico de separacao do programa. Nao adianta dividir o
  programa em 4 arquivos e colocar cada funcao em um deles para o programa ser
  "modular". Por exemplo, voce provavelmente precisa manipular o conjunto dos
  asteroides do programa quando cria um novo asteroide, quando detecta colisoes
  e quando desenha a tela. Se os asteroides estao em uma lista ligada, voce
  pode manipula-la diretamente em todos esses lugares (foi o que todos os que
  eu corrigi fizeram). Mas seria mais elegante separar as funcoes de acesso `a
  lista ligada de asteroides em um modulo `a parte. No primeiro caso, voce tem
  que verificar, ao longo do seu programa inteiro, se lembrou de fazer "p =
  p->next", se lembro de testar "if (p != NULL)" etc. Se percorrer a lista e'
  uma tarefa restrita em um modulo, voce so' precisa "debugar" essas coisas uma
  vez. Alem disso, se voce quiser mudar algo na estrutura da lista (por
  exemplo, passar de uma lista ligada para uma lista duplamente ligada), voce
  sabe que todas as alteracoes tem que ser feitas apenas nesse modulo. Nao
  descontei nada de quem fez isso, porque uma lista ligada realmente e' simples
  e nao e' tao ruim manipula-la diretamente. Outro exemplo: alguns EPs
  detectaram colisoes entre asteroides da seguinte maneira: "move o asteroide
  para a sua nova posicao; se a nova posicao contem um '*', '@' ou '!', houve
  colisao". Isso e' totalmente nao-modular, porque o algoritmo de deteccao de
  colisao depende da representacao das coisas na tela. Se a representacao
  mudar (como, por exemplo, entre a fase 1 e a fase 2), o algoritmo tem que ser
  completamente reescrito. Desse tipo de coisa eu descontei pontos.

- Varias pessoas fizeram diversas "promiscuidades" com os arquivos ".h". Embora
  *sintaticamente* um arquivo .h possa conter qualquer tipo de codigo C valido,
  *semanticamente* nao e' assim: os arquivos .h existem para exporem para
  diversos arquivos o mesmo conjunto de declaracoes de funcoes, variaveis e
  constantes. Ou seja, normalmente voce nao deve colocar a definicao de uma
  funcao dentro de um arquivo ".h", apenas a sua declaracao. Para que? Para que
  voce possa definir uma funcao em um arquivo .c e chama-la em outro arquivo
  .c; esse segundo arquivo "#includes" o arquivo .h com as declaracoes de
  funcoes do primeiro. Alem disso, incluir o arquivo .h no arquivo .c
  correspondente a ele e' util porque permite que voce defina as funcoes no
  arquivo em qualquer ordem. Se voce nao fizer isso, ou voce declara os
  prototipos no inicio do arquivo .c (o que nao e' muito esperto, pois da'
  muito mais trabalho que incluir o arquivo .h) ou voce precisa ter certeza de
  definir as funcoes de maneira que uma funcao sempre faca referencia a uma
  funcao definida anteriormente.

- Varias pessoas fizeram isso:

typedef struct blah* pblah;

struct blah {
	int lala;
	pblah next;
}

E nunca mais usaram o typedef "pblah". Nao esta' errado, mas nao e' necessario;
voce pode fazer:

struct blah {
	int lala;
	struct blah* next;
}

Que da' tudo certo tambem. Outra opcao e':

typedef struct Blah {
	int lala;
	struct Blah* next;
} blah;

Que me parece mais natural.

Finalmente, uma charada: o algoritmo mais usado para deteccao de colisoes foi:
"calcula a nova posicao de todos os asteroides; verifica se dois asteroides
estao na mesma posicao; se estiverem, houve colisao". Qual o problema com esse
algoritmo (nao, eu nao descontei pontos de quem fez assim)?

Ate' +
Nelson e Thiago