Notas sobre o Problema 3

Depois de uma primeira "vista de olhos" pelas resoluções do Problema 3 queríamos alertá-los para alguns dos erros mais
comuns (ou mais graves).

1.  Números mágicos!  Em muitos casos aparecem pedaços de código tais como:

for(int i = 43; i != 83; i += 4) {
    ecra << Posicao(3, i);

   
...

que seriam muito mais legíveis/úteis/bem programados/etc. se fossem rescritos usando constantes e variáveis com nomes sugestivos (ver mensagem do Prof. Manuel Menezes de Sequeira de quinta-feira, dia 18 de Janeiro de 2001) como por exemplo:

Dimensao const dimensao_do_tabuleiro(10, 10);
Posicao const origem_do_tabuleiro(2, 41);
Dimensao const dimensao_das_celulas(2, 4);
Posicao const centro_das_celulas(dimensao_das_celulas.linhas() / 2,
                                 dimensao_das_celulas.colunas() / 2);

for(int coluna = 0; coluna != dimensao_do_tabuleiro.colunas(); ++coluna) { 
    ecra << (origem_do_tabuleiro + centro_das_celulas + 
             Dimensao(0, coluna * dimensao_das_celulas.colunas()));
    ...

2.  Procedimentos e funções muito longos(as).  Uma regra de bom senso na programação é que quando uma função ou procedimento começa a ter muito mais do que uma página de código bem indentado, é uma boa candidata a ser modularizada em procedimentos e funções mais pequenas.  É claro que esta regra tem excepções, mas é um bom hábito aprender desde o início a fazer pequenas funções e procedimentos e testar cada um deles separadamente.  No Problema 3 há vários exemplos de procedimentos com 3 páginas que podiam ser modularizados adequadamente tornando o código mais claro e mais fácil de depurar.

3.  Código repetido em ambos ramos de um if else ou em todos os ramos de um switch. Por exemplo

if(umaFuncaoBooleanaQualquer()) {
    fazQualquerCoisa1();
    fazQualquerCoisa2();
    fazQualquerCoisa3();
} else {
    fazQualquerCoisa1();
    fazQualquerCoisa4();
    fazQualquerCoisa3();
}
pode (e deve) ser substituído por

fazQualquerCoisa1();

if(umaFuncaoBooleanaQualquer())
    fazQualquerCoisa2();
else
    fazQualquerCoisa4();

fazQualquerCoisa3(); 

E
 
switch(uma_expressão) {
  case valor1:
    fazQualquerCoisa1();
    fazQualquerCoisa2();
    fazQualquerCoisa3();
    break;
  case valor2:
    fazQualquerCoisa1();
    fazQualquerCoisa4();
    fazQualquerCoisa3();
    break;
  case valor3:
    fazQualquerCoisa1();
    fazQualquerCoisa5();
    fazQualquerCoisa3();
    break;
}

pode ser substituído por

fazQualquerCoisa1();

switch(uma_expressão) {
  case valor1:
    fazQualquerCoisa2();
    break;
  case valor2:
    fazQualquerCoisa4();
    break;
  case valor3:
    fazQualquerCoisa5();
    break;
}

fazQualquerCoisa3();

4.  Paragem antecipada de ciclos.  O seguinte código

bool constaEm(int const n, vector<int> const& v){
    bool consta = false;
    for(vector<int>::size_type i = 0; i != v.size(); ++i)
        if(v[i] == n)
           consta = true;
    return consta;
}

pode ser substituído pela versão mais eficiente

bool constaEm(int const n, vector<int> const& v){
    bool consta = false;
    for (vector<int>::size_type i = 0; i != v.size() and not consta; ++i)
        if (v[i] == n)
           consta = true;
    return consta;
}

ou até por

bool constaEm(int const n, vector<int> const& v){
    for (vector<int>::size_type i = 0; i != v.size(); ++i)
        if (v[i] == n)
           return true;
    return false;
}

Esta última versão é aceitável, apesar de não ter todas as condições de paragem na guarda do ciclo (uma está na condição da instrução condicional), uma que o corpo do ciclo é pequeno.

5.  Testes de variáveis Booleanas.  Não é necessário testar se uma variável Booleana é igual a true ou false, (embora funcione).  Basta avaliar o seu valor, por exemplo:

bool aconteceu_qualquer_coisa = ...;

if(aconteceu_qualquer_coisa == true)  // verboso!
    ...

if(aconteceu_qualquer_coisa)          // 
simples e eficaz!
    ...

if(aconteceu_qualquer_coisa == false)  // 
verboso!
    ...

if(not aconteceu_qualquer_coisa)      // 
simples e eficaz!
    ...