segunda-feira, 7 de setembro de 2009

Continuando o Bowling em C

Esse sábado o dojo aconteceu no LINF - laboratório de informática, na UnB.

Estamos continuando o problema do bowling, usando linguagem C.

Dessa vez apareceu pouca gente. Apenas eu (Bruno), o Célio e o Ian. O que não foi de todo ruim. Ficamos os 3 na frente da máquina, fazendo um triple-programming e revezando o teclado na hora que dava vontade. O código fluiu bem também, porque com menos gente precisamos parar menos pra discutir e explicar... Tudo tem sempre um lado bom e um lado ruim.


Duas "manobras" se fizeram notar durante essa seção. A primeira dela vem de uma característica da linguagem C: a de ser muito, muito, muito liberal. Acontece que precisamos escrever testes com que normalmente não nos preocuparíamos em linguagens como Java, Ruby, Python, etc.

Veja bem: tínhamos uma função que recebia uma string, representando a série de jogadas de um jogador. Alguma coisa como:

"1: 2 3, 4 5, 0 4, 10, 9 1, 3 4 "

Aí começamos ignorando os primeiros caracteres ("1:_") transformando o resto num array de inteiros, para seguir processando.


Quando implementamos a regra do spare, fizemos de modo simples, somando os elementos subsequentes:



Vimos então a necessidade de garantir que o programa não leria os elementos subsequentes além da capacidade do array.

Acontece que em C um array nada mais é do que um ponteiro para o primeiro elemento do array. Cabe ao programador gerenciar a leitura do array apenas até o tamanho alocado.



Isso quer dizer que, do jeito que estava nossa implementação, no caso de passarmos um placar incompleto, com um spare no final (tipo "1: 1 2, 3 4, 9 1") nosso programa deveria no mínimo responder que não é possível calcular o placar, ao invés de somar a próxima posição do array (que não existia), calcular o valor errado e retornar, como se nada tivesse acontecido.

Só que aí - eis a nossa surpresa - nosso teste simplesmente passava, calculando o valor corretamente. Porque?

Simples: por sorte, a próxima posição de memória depois do nosso array [1,2,3,4,9,1] estava com o valor zero, e o programa acabava acertando o resultado :-P

Só que, veja bem: não podíamos nos satisfazer com isso. Nosso teste passava na sorte! Como podíamos escrever um teste que definitivamente falhava, mostrando o erro no programa?

Fizemos assim: com os testes todos passando (por sorte...) refatoramos o código para extrair da função principal uma outra que fazia o mesmo trabalho, mas recebendo um array de inteiros e o seu tamanho:



Com isso, pudemos testar esse método menor passando um array com 5 posições, com a última tendo valor diferente de zero, mas passando um tamanho de array 4. Isso simula a situação em que a posição de memória subsequente ao array não está com valor zero, e consguimos deflagrar o erro :-)



Zas!

Bem, a segunda manobra radical desse sábado se deu no laço for principal da lógica que fazia a conta do placar. Acompanhe:

Antes:


Depois:


Mudamos o significado do contador principal, para contar de frame por frame. O interessante é que só percebemos que seria melhor assim depois que precisamos passar a guardar o número do frame, para não nos perdermos com os frames de strike, que só tem uma bola ao invés de duas.

Depois disso, ainda refatoramos isso mais adiante, para que a função (não é método ;-] ) que convertia a string em array de inteiros completasse as segundas bolas dos frames de strike com zeros.

Isso ajudou com o problema que tínhamos naquela hora. Mas será que vai ajudar quando chegarmos à regra de calcular os strikes? E qndo chegar a hora de calcularmos um décimos frame com 3 bolas?

:-*

O tempo dirá! Sábado que vem a gente descobre.

O código completo desse problema está em
http://github.com/brunopedroso/bowling_dojo_c/tree/master

Para participar das próximas sessões, marque presença em nossa lista:
http://groups.google.com/group/dojo-brasilia

see ya.