Olá, devs!
Este artigo trata de um mistério profundo da plataforma da DIO para os iniciantes: os desafios de código!
Em um artigo anterior (Desafios de Código: prós e contras), eu tratei dos desafios de código como um todo, dando a minha opinião sobre esta fantástica ferramenta didática oferecida pela plataforma, apontando seus prós e contras. No final, sugeri algumas melhorias para a equipe da DIO implementar nos desafios, como separar postagens de artigos, certificados e dúvidas em 3 links diferentes na página de artigos, ao invés de deixar tudo junto em um balaio só.
Neste artigo, eu vou analisar e detalhar cada etapa da resolução de um único desafio de código, da forma que funciona para mim. Vou mostrar os bastidores da solução de um desafio específico, tratando do enunciado, exemplos dados, algoritmo da solução, testes abertos e testes fechados. Excepcionalmente, neste artigo eu vou dar o código-fonte, pois é preciso mostrar aonde e porque o código dá erro na execução dos testes e como ele pode ser corrigido.
Nos próximos artigos que eu tratar de desafios de código, não vou dar o código-fonte, pois isso é tarefa do aluno, que deve buscar, na sintaxe e estruturas da linguagem pedida para implementação, a sua codificação para resolver o problema. Nos próximos artigos sobre desafios, darei apenas os algoritmos.
Sumário
- Introdução
- Enunciado
- Exemplos
- O Algoritmo
- Análise da lógica do problema
- A codificação
- Atenção!! Observação IMPORTANTÍSSIMA sobre as saídas!!!
- Executar seu programa para testar o código para os testes abertos
- Primeira correção do código
- Segunda tentativa de execução
- Executar seu programa para testar o código para todos os testes (abertos e fechados)
- Segunda correção do código
- Terceira tentativa de execução
- Observações sobre a entrada de dados
- Observações sobre a saída de dados
- Observações sobre ajuda
- Finalizando...
1 - Introdução
No artigo anterior, mencionado aí em cima, eu disse que tenho visto muita dificuldade dos alunos iniciantes para conseguir resolver os problemas propostos nos desafios de código. E até mesmo de devs experientes.
Algumas vezes, a dificuldade está no entendimento do enunciado e sua passagem para o código, na execução dos testes fechados, ou ainda no entendimento dos comandos de entrada e saída de dados. Mas a principal reclamação é sobre os testes fechados.
Para este artigo, eu escolhi analisar o primeiro desafio de código do curso “Resolvendo Desafios Básicos em JavaScript”, do bootcamp “Eduzz Fullstack developer #2”, no qual estou matriculado.
O desafio que será analisado é: Múltiplos (1/3)
2 - Enunciado
Basicamente, o enunciado pede que seja feito um programa que leia dois números inteiros A e B, imprima uma saída de uma das duas mensagens: “Sao multiplos” ou “Nao sao multiplos”. Só isso!
Parece fácil, não?
3 - Exemplos
Na parte dos exemplos, são mostrados exemplos de entradas para dois casos e suas respectivas saídas esperadas:
- Entrada: 6 24, saída: “Sao Multiplos”
- Entrada: 6 25, saída: “Nao sao Multiplos”
4 - O Algoritmo
O algoritmo para resolver este problema lista os passos básicos abaixo e parece ser bem simples e direto:
- Leia um número inteiro
- Leia outro número inteiro
- Teste se eles são múltiplos
- Imprima o resultado da escolha acima
5 - Análise da lógica do problema
Na matemática, dois números inteiros são múltiplos quando o menor deles cabe dentro do maior.
E como eu posso saber quando isso ocorre?
Dividindo o maior número pelo menor, a divisão deve ser exata, ou seja, com o resto igual a zero!
Então basta que eu codifique um teste para saber se a divisão entre eles é exata, certo? Certo!
No primeiro exemplo, se eu dividir 24 por 6, dá 4. Divisão exata, sem resto, portanto 24 e 6 são múltiplos.
No segundo exemplo, se eu dividir 25 por 6, dá 4,166666... (ou, de outra forma, dá 4, com resto 1). Ou seja, é uma divisão não exata, portanto, 25 e 6 não são múltiplos.
Ficou fácil codificar, não foi?
Basta dividir um pelo outro e testar se a divisão é exata ou não.
Aí, surgem algumas dúvidas:
- E se a entrada fosse 24 e 6, ao invés de 6 e 24?
- Como eu vou saber qual dos dois números lidos é o maior e qual é o menor, para fazer a divisão do maior pelo menor?
- Eu preciso encontrar antes o maior e o menor antes de fazer o teste?
Bem, no primeiro caso, para o primeiro exemplo, se eu dividir 6 por 24, dá 0,25, divisão não exata. Portanto, você poderia dizer que 6 e 24 não são múltiplos. E estaria errado! Se eu fizer o contrário e dividir 24 por 6 dá 4, exato, sem resto. Então eles seriam múltiplos, sim!
No segundo caso, seria preciso determinar o maior e o menor e dividir sempre o maior pelo menor, senão a divisão do menor pelo maior sempre daria um valor menor que 1 (ou seja, divisão não exata) e você poderia incorrer em erro também!
No último caso, a resposta é não! Existem formas de você fazer o teste sem precisar determinar o maior e o menor.
Note que pode ter mais de uma maneira de codificar essa solução, para o mesmo algoritmo.
Fazendo uma primeira análise mais simplória, notamos que, nos dois exemplos, o primeiro número é sempre menor do que o segundo. Se isso for o padrão de entradas do desafio, bastaria dividir sempre o segundo pelo primeiro e testar se essa divisão é exata, certo?
Então vamos considerar que o primeiro número lido é A e o segundo é B e que o segundo sempre será maior que o segundo.
O algoritmo poderia ser atualizado para:
- Leia um número inteiro A
- Leia outro número inteiro B
- Divida B por A
- Teste se a divisão é exata
- Se a divisão for exata, eles são múltiplos
- Caso contrário, eles não são múltiplos
- Imprima o resultado da escolha acima
6 - A codificação
Este desafio foi realmente pensado para o dev iniciante, pois boa parte do código já está pronta, com a entrada de dados e os comandos para a saída da resposta, faltando inserir apenas 3 coisas.
Falta apenas codificar o teste do IF e as duas mensagens de saída, uma para cada resultado indicado no enunciado, de acordo com o comando IF.
Com base nas escolhas feitas aí em cima, uma codificação adequada para a parte que falta do algoritmo acima é:
if ( B % A == 0 )
print("Sao Multiplos");
else
print("Nao sao Multiplos");
O operador % calcula o resto de da divisão entre valores inteiros.
Ou seja, teste se o resto da divisão de B por A é igual a zero.
Se for, a divisão é exata e A e B são múltiplos, senão, não são!
Simples assim!
Não esqueça de salvar seu código com o botão “Salvar”. Se não salvar e passar para o próximo desafio, quando voltar para este, todo o seu código será apagado.
7 - Atenção!! Observação IMPORTANTÍSSIMA sobre as saídas!!!
Após a execução do seu programa, o diagnóstico do sucesso ou erro na execução dos testes é feito automaticamente, comparando a sua saída com a saída esperada pela plataforma para cada teste específico. Esta comparação é feita caractere a caractere e basta um único caractere ser diferente para a sua resposta será considerada errada!
A sua resposta precisa ser exatamente igual à resposta esperada para o desafio!
Por exemplo, no caso deste desafio, uma das saídas esperadas é “Sao Multiplos”.
Veja que as palavras estão sem os acentos (til e acento agudo) e são iniciadas por maiúsculas. A sua saída também não pode ter os acentos (mesmo que esteja com a ortografia incorreta) e precisa usar as maiúsculas do mesmo jeito que está no enunciado. Ela tem que bater exatamente com a saída esperada. Se você inserir um espaço adicional no início (ou entre as palavras) da mensagem de saída, também dará erro. Se trocar algum caractere minúsculo por maiúsculo (ou o contrário), também dará erro!
A outra saída esperada é “Nao sao Multiplos”, também sem acentos, com o N maiúsculo e o “s” de “sao” minúsculo, neste caso.
8 - Executar seu programa para testar o código para os testes abertos
Para testar seu código para os testes abertos, basta clicar no botão azul “Executar Testes”. Todos os testes abertos serão executados de uma só vez. O resultado da execução pode ser um dos 3 casos possíveis a seguir:
- Se for uma mensagem em verde informando do sucesso, seu código foi aprovado em todos os testes abertos;
- Se for uma mensagem em vermelho informando que apenas parte dos testes abertos teve sucesso, seu código deu a resposta errada em um ou mais testes abertos;
- Se for uma mensagem em marrom, com fundo creme (salmão), informando que houve um erro ou retorno inválido, seu código não foi nem executado e tem algum erro na sintaxe da linguagem.
No primeiro caso, é só clicar no botão “Entregar Desafio” para enviar o código e receber a confirmação de aprovação no desafio.
No segundo caso, é algum erro na lógica do código, mas é um erro de execução. Erro é preciso realizar alguma correção no código e submetê-lo novamente aos testes abertos, com o botão “Executar Testes”.
No terceiro caso, existe algum erro no código, mas não é erro de execução, e sim de compilação. Ou seja, o código está em descordo com as regras de sintaxe da linguagem, impedindo a sua execução. Pode ser apenas um parêntese a mais, a falta de um ponto-e-vírgula, uma variável não declarada, um parâmetro faltando em uma função, um tipo de dado usado erradamente ou algum erro mais grave. Aqui também é preciso realizar alguma correção no código e submetê-lo novamente aos testes abertos, com o botão “Executar Testes”.
Ainda com relação ao segundo caso, os testes abertos permitem que o usuário veja os dados de entrada usados, a saída que é esperada e qual foi a saída do seu programa para aqueles dados após a execução do código. Aí, a análise destes dados pode lhe dar alguma ideia de onde está o erro de lógica no seu código.
Assim, você pode (e deve!) checar os dados dos testes abertos.
Neste caso, o teste que eu usei foi if( B % A == 0 ) e o resultado foi a mensagem vermelha informando que:
2/3 testes de abertos tiveram sucesso.
Portanto, o meu código (teste e saídas) está correto para 2 testes abertos, mas deu erro no teste aberto restante.
Logo, alguma coisa no meu código precisa ser corrigida. Vamos checar os testes abertos, analisá-los para ver como corrigir (depurar) o código.
9 – Primeira correção do código
Clicando no teste #1, são mostrados os dados de entrada, a saída esperada e a minha saída, bastando rolar a tela para cima para vê-los.
Vamos organizar os dados dos testes abertos para uma tabela:
Nos testes #1 e #2, a resposta do meu código está correta, batendo com a resposta esperada, pois os números não são múltiplos.
No teste #1, no meu código, a divisão de B por A (11 por 7) dá 1,57 (ou 1 com resto 4), não exata, indicando que eles não são múltiplos. O meu código deu a resposta esperada, portanto, foi aprovado neste teste.
No teste aberto #2, a divisão de B por A (-2 por 5) dá -0,4, não exata, indicando que eles não são múltiplos. O meu código deu a resposta esperada e foi aprovado.
Já para o teste #3, a minha resposta está errada porque indicou que os números -1 e -6 não são múltiplos e a solução esperada era que eles são múltiplos.
O resultado da divisão de B por A, (-1 por -6), dá 0,1666..., não exata, por isso a minha resposta foi que -1 e -6 não são múltiplos.
Mas neste caso, o segundo número não é maior do que o primeiro, conforme nossa suposição inicial, lembra?
Quer dizer que os testes desse desafio nem sempre vão ter a segunda entrada maior do que a primeira, certo?
Se for assim, então -1 e -6 são múltiplos, pois dividindo A por B, (-6 por -1), dá 6, com divisão exata, por isso a resposta esperada é que eles são múltiplos.
Vamos alterar a condição original do if invertendo o que foi codificado antes, ou seja, if( A % B == 0 ), para ver o que vai dar.
Fazendo apenas essa mudança no código, vamos salvá-lo e executar novamente os testes abertos.
10 – Segunda tentativa de execução
Então, vamos partir para uma segunda tentativa de execução, após essa modificação do código.
O resultado foi a mensagem verde abaixo:
3/3 testes de abertos tiveram sucesso. Clique em “ENTREGAR DESAFIO” para executar todos os testes e finalizar esse desafio.
Agora parece que deu certo! Ó código está correto (teste e saídas) para todos os testes abertos.
Agora só falta tentar finalizar o desafio, submetendo-o aos testes fechados.
11 - Executar seu programa para testar o código para todos os testes (abertos e fechados)
Para testar seu código para todos os testes, basta clicar no botão verde “Entregar Desafio”. Todos os testes (abertos e fechados) serão executados de uma só vez. Se o código já foi aprovado nos testes abertos, apenas os testes fechados oferecem risco de erro.
Pode ocorrer um dos 2 resultados possíveis para o resultado da execução do seu código:
- Ele pode estar correto e valer para as entradas de todos os testes fechados;
- Ele pode estar incorreto e não valer para as entradas de um ou mais testes fechados;
No primeiro caso, seu desafio está concluído e você pode passar para o próximo (uhuuuuuuuuuuuuuuu!!!!!!!!!!!!). Uma janela é mostrada coma mensagem de sucesso.
No segundo caso, você perde um heart (coração) e precisa corrigir algum erro na lógica do seu código para depois testá-lo novamente (botão azul “Executar Testes”) para os testes abertos. Quando passar em todos, submeter novamente aos testes fechados (botão azul “Entregar Desafio”). Uma janela é mostrada com a mensagem de erro.
Vamos testar nosso código agora. Clicando no botão “ENTREGAR DESAFIO”, recebemos o seguinte resultado:
Os testes fechados não permitem que você os abra para ver quais são os dados de entrada, a saída esperada, nem a sua saída.
É preciso inferir quais dados poderiam causar o erro na sua resposta, já que seu código passou por todos os testes abertos.
12 – Segunda correção do código
Retomando a tabela com os dados dos testes abertos, note que no teste #3, a nossa resposta agora estava correta porque ela indicou que o resultado da divisão de A por B (-6)/(-1) dá exata e ela realmente dá (6).
Então o que pode estar errado?
Bem, neste mesmo teste para a primeira versão do if o código foi reprovado porque a divisão feita foi o menor número pelo maior. Já a versão atual do código, o código não deu erro para a divisão do maior pelo menor.
Ou seja, o erro do nosso código acontece quando a gente divide o número menor pelo maior, certo?
Então, basta garantir que o comando if teste as duas possibilidades de divisão de uma vez só. Se uma delas der divisão exata, os números são múltiplos.
Nesse caso, o código ficaria assim
if( A % B == 0 || B % A == 0)
Explicando, o comando testa se a divisão do primeiro número pelo segundo é exata OU se a divisão do segundo número pelo primeiro é exata.
O operador || significa OU e associa duas condições, de modo que a condição só será verdadeira se as duas condições individuais o forem, caso contrário, ela será falsa.
Se uma das duas for exata, o teste dá verdadeiro e a resposta de que são múltiplos será impressa corretamente.
Caso as duas divisões não sejam exatas (caso de números não múltiplos), o teste dará falso e a resposta impressa também será impressa corretamente.
13 – Terceira tentativa de execução
Vamos partir para a terceira tentativa de execução de código.
Vamos testar a condição do if com os dois testes juntos, como mostrado acima contrário, ou seja, if( A % B == 0 || B % A == 0) para ver o que vai dar.
Agora, vamos salvá-lo e executar mais uma vez os testes abertos.
Opa!! O resultado foi a mensagem verde informando que:
3/3 testes abertos tiveram sucesso. Clique em “ENTREGAR DESAFIO” para executar todos os testes e finalizar esse desafio.
Vamos testar nosso código agora nos testes fechados, clicando no botão “ENTREGAR DESAFIO”:
E o resultado foi esse aqui: