Prática de Ramificações e Laços

Prática de Ramificações e Laços

Aprendemos muita teoria — agora é hora de construir alguns projetos reais. Esta é uma lição prática. Usando if statements, for loops, while loops, break, continue e outros conceitos que aprendemos, vamos construir quatro programas completos passo a passo.

Para cada projeto, analisaremos os requisitos, escreveremos o código e discutiremos possíveis melhorias.


Projeto 1: Jogo de Adivinhação de Números (Melhorado)

Na Lição 08, escrevemos um jogo básico de adivinhação. Agora vamos melhorá-lo com seleção de dificuldade, limites de tentativas e um recurso de "jogar novamente."

Requisitos

TEXT
1. Jogador seleciona dificuldade: Fácil (1-50, ilimitado), Normal (1-100, 10 tentativas), Difícil (1-200, 7 tentativas)
2. Sistema gera aleatoriamente um número alvo
3. Após cada palpite, dica "muito alto" ou "muito baixo" e exibe tentativas restantes
4. Após acertar ou esgotar tentativas, pergunte "jogar novamente?"
5. Digite q para sair

Código Completo (⭐⭐⭐)

Exemplo: Jogo de Adivinhação de Números

PYTHON
import random

print("=" * 30)
print("Jogo de Adivinhação (Melhorado)")
print("=" * 30)

while True:  # Laço externo: controla "jogar novamente"
    # Seleciona dificuldade
    print("\nSelecione a dificuldade:")
    print("1. Fácil (1~50, ilimitado)")
    print("2. Normal (1~100, 10 tentativas)")
    print("3. Difícil (1~200, 7 tentativas)")

    choice = input("Digite 1/2/3: ")

    if choice == "1":
        max_num = 50
        max_attempts = float("inf")  # Ilimitado
    elif choice == "2":
        max_num = 100
        max_attempts = 10
    elif choice == "3":
        max_num = 200
        max_attempts = 7
    else:
        print("Escolha inválida, usando Normal como padrão")
        max_num = 100
        max_attempts = 10

    # Gera número alvo
    target = random.randint(1, max_num)
    attempts = 0
    print(f"\nNúmero gerado entre 1~{max_num}. Comece a adivinhar!")

    # Laço interno: lógica principal do jogo
    while True:
        # Verifica se as tentativas acabaram
        if attempts >= max_attempts:
            print(f"\nTentativas esgotadas! A resposta era {target}")
            break

        # Obtém palpite do jogador
        guess_str = input(f"{max_attempts - attempts} tentativas restantes, digite seu palpite: ")

        if guess_str.lower() == "q":
            print("Saindo do jogo.")
            max_attempts = -1  # Flag para notificar laço externo
            break

        # Valida entrada
        if not guess_str.isdigit():
            print("Por favor, digite um número válido!")
            continue

        guess = int(guess_str)
        attempts += 1

        # Verifica palpite
        if guess < target:
            print("Muito baixo, tente mais alto!")
        elif guess > target:
            print("Muito alto, tente mais baixo!")
        else:
            print(f"\nParabéns! A resposta era {target}!")
            print(f"Você acertou em {attempts} tentativas.")
            break

    # Verifica se devemos sair completamente
    if max_attempts == -1:  # Jogador digitou q
        break

    # Pergunta por outra rodada
    again = input("\nJogar novamente? (s/n): ")
    if again.lower() != "s":
        print("Obrigado por jogar, até logo!")
        break
▶ Experimente

Destaque de design: O laço externo controla "jogar novamente," o laço interno controla o "processo de adivinhação." A flag max_attempts = -1 resolve o problema de sair de ambos os laços quando o jogador digita q. Uma abordagem mais elegante seria encapsular a lógica do jogo em uma função e usar return para sair de uma vez.


Projeto 2: Tabuada de Multiplicação (Múltiplos Estilos)

Na Lição 08, imprimimos uma tabuada padrão. Um bom programador deve ser capaz de controlar flexivelmente estruturas de laço para exibir qualquer estilo.

Estilo 1: Triângulo Inferior Padrão (⭐⭐)

Exemplo: Triângulo Inferior Padrão

PYTHON
print("=== Triângulo Inferior Padrão ===")
for i in range(1, 10):
    for j in range(1, i + 1):
        print(f"{j}x{i}={i*j}", end="\t")
    print()
▶ Experimente

Estilo 2: Retângulo Completo (⭐⭐)

Exemplo: Retângulo Completo

PYTHON
print("=== Retângulo Completo ===")
for i in range(1, 10):
    for j in range(1, 10):
        print(f"{j}x{i}={i*j}", end="\t")
    print()
▶ Experimente

Estilo 3: Triângulo Superior (⭐⭐⭐)

Exemplo: Triângulo Superior

PYTHON
print("=== Triângulo Superior ===")
for i in range(1, 10):
    # Imprime espaços iniciais para alinhamento
    for k in range(1, i):
        print(end="\t\t")
    # Imprime fórmulas de multiplicação
    for j in range(i, 10):
        print(f"{i}x{j}={i*j}", end="\t")
    print()
▶ Experimente

Saída:

TEXT
=== Triângulo Superior ===
1x1=1    1x2=2    1x3=3    ...    1x9=9
          2x2=4    2x3=6    ...    2x9=18
                    3x3=9    ...    3x9=27
                              ...
                                        9x9=81

Insight principal: O desafio do triângulo superior é o "alinhamento de espaços" — cada linha precisa de (i-1) * 2 caracteres de tabulação de indentação. Isso usa dois laços internos: o primeiro imprime espaços, o segundo imprime as fórmulas.


Projeto 3: Calculadora Simples (Melhorada)

Nos exercícios da Lição 08, escrevemos uma calculadora básica. Agora vamos fazer uma versão melhorada suportando operações contínuas com histórico.

Requisitos

TEXT
1. Começa com resultado atual = 0
2. Usuário digita: operador número, ex.: "+ 5"
3. Operadores suportados: + - * / ** // % clear exit
4. clear redefine o resultado para 0
5. exit sai do programa
6. Após cada operação, mostre o resultado atual e o histórico

Código Completo (⭐⭐⭐)

Exemplo: Calculadora Melhorada

PYTHON
print("=" * 40)
print("Calculadora Melhorada")
print("Formato: operador número, ex.: + 5")
print("Suportados: + - * / ** // %")
print("Comandos especiais: clear reset exit quit")
print("=" * 40)

result = 0.0
history = []  # Armazena histórico de operações

while True:
    # Exibe resultado atual
    print(f"\nResultado atual: {result}")

    # Obtém entrada do usuário
    cmd = input(">>> ").strip()

    # Trata comandos especiais
    if cmd.lower() in ("exit", "quit"):
        print("Obrigado por usar!")
        break

    if cmd.lower() == "clear":
        result = 0.0
        history.clear()
        print("Redefinido para 0")
        continue

    # Analisa comandos de operação regulares
    parts = cmd.split()
    if len(parts) != 2:
        print("Formato inválido! Digite: operador número")
        continue

    op, num_str = parts

    # Valida número
    if not num_str.replace(".", "").isdigit() or num_str.count(".") > 1:
        print("Número inválido!")
        continue

    num = float(num_str)

    # Executa operação
    old_result = result
    if op == "+":
        result += num
    elif op == "-":
        result -= num
    elif op == "*":
        result *= num
    elif op == "/":
        if num == 0:
            print("Erro: Não é possível dividir por zero!")
            continue
        result /= num
    elif op == "**":
        result **= num
    elif op == "//":
        if num == 0:
            print("Erro: Não é possível dividir por zero!")
            continue
        result //= num
    elif op == "%":
        if num == 0:
            print("Erro: Não é possível dividir por zero!")
            continue
        result %= num
    else:
        print(f"Operador inválido: {op}")
        continue

    # Registra histórico
    history.append(f"{old_result} {op} {num} = {result}")

    # Exibe resultado
    print(f"= {result}")

    # Mostra últimas 3 entradas do histórico
    if len(history) >= 1:
        print("--- Histórico Recente ---")
        for item in history[-3:]:
            print(f"  {item}")
▶ Experimente

Execução de exemplo:

TEXT
>>> + 10
= 10.0
--- Histórico Recente ---
  0.0 + 10.0 = 10.0

>>> * 3
= 30.0
--- Histórico Recente ---
  0.0 + 10.0 = 10.0
  10.0 * 3.0 = 30.0

>>> / 0
Erro: Não é possível dividir por zero!

>>> clear
Redefinido para 0

Mentalidade de programação: Este exemplo mostra a interação clássica de laços e condições — while True mantém o programa em execução, if-elif-else lida com várias entradas, continue pula entrada inválida, e break sai normalmente.


Projeto 4: Localizador de Números Primos

Permita que o usuário insira um intervalo, exiba todos os números primos dentro desse intervalo e os conte.

Requisitos

TEXT
1. Usuário insere valores inicial e final
2. Programa exibe todos os primos nesse intervalo
3. Exibe 10 por linha, alinhados
4. Mostra a contagem total de primos

Código Completo (⭐⭐⭐)

Exemplo: Localizador de Números Primos

PYTHON
print("Localizador de Números Primos")
print("Digite um intervalo, e eu encontrarei todos os primos.")

# Obtém intervalo
start_str = input("Valor inicial (>=2): ")
end_str = input("Valor final: ")

# Valida entrada
if not (start_str.isdigit() and end_str.isdigit()):
    print("Por favor, digite números inteiros positivos válidos!")
else:
    start = int(start_str)
    end = int(end_str)

    if start < 2:
        start = 2
        print("Valor inicial ajustado para 2 (primos começam em 2)")

    if start > end:
        print("Valor inicial não pode ser maior que o valor final!")
    else:
        primes = []  # Armazena primos encontrados

        # Verifica cada número no intervalo
        for num in range(start, end + 1):
            # Verifica se num é primo
            is_prime = True
            for i in range(2, int(num ** 0.5) + 1):
                if num % i == 0:
                    is_prime = False
                    break

            if is_prime:
                primes.append(num)

        # Exibe resultados
        print(f"\nEncontrados {len(primes)} primos entre {start} e {end}:")

        for i, prime in enumerate(primes, 1):
            print(f"{prime:5d}", end="")
            if i % 10 == 0:  # Nova linha a cada 10
                print()

        print()  # Nova linha final
▶ Experimente

Exemplo de saída:

TEXT
Valor inicial (>=2): 50
Valor final: 200

Encontrados 34 primos entre 50 e 200:
   53   59   61   67   71   73   79   83   89   97
  101  103  107  109  113  127  131  137  139  149
  151  157  163  167  173  179  181  191  193  197
  199

Dica de otimização: Ao verificar se um número é primo, você não precisa dividir até num-1 — apenas até sqrt(num). Se num tem um fator maior que sqrt(num), ele deve ter um fator pareado menor que sqrt(num). Esta otimização é muito eficaz para grandes intervalos (100.000+).


Projeto 5: IMC + Verificador de Força de Senha

Este projeto reúne operadores aritméticos, operadores de comparação, operadores lógicos, condicionais e métodos de string para resolver dois problemas comuns do mundo real.

Parte 1: Índice de Massa Corporal (IMC) (⭐⭐)

IMC (Índice de Massa Corporal) é uma medida internacionalmente usada de gordura corporal. A fórmula é simples:

IMC = peso(kg) / altura(m)^2

Exemplo: Calculadora de IMC

PYTHON
# Calculadora de IMC

# Dados de entrada
weight = 68
height = 1.75

# Calcula IMC
bmi = weight / (height ** 2)

print("=== Índice de Massa Corporal ===")
print(f"Peso: {weight} kg")
print(f"Altura: {height} m")
print(f"IMC: {bmi:.1f}")

# Usa comparação encadeada e if-elif para determinar categoria
if bmi < 18.5:
    print("Categoria: Abaixo do peso")
elif 18.5 <= bmi < 24:
    print("Categoria: Normal")
elif 24 <= bmi < 28:
    print("Categoria: Sobrepeso")
else:
    print("Categoria: Obeso")
▶ Experimente

Saída:

TEXT
=== Índice de Massa Corporal ===
Peso: 68 kg
Altura: 1.75 m
IMC: 22.2
Categoria: Normal

Dica: Comparações encadeadas como 18.5 <= bmi < 24 são muito mais limpas que bmi >= 18.5 and bmi < 24.

Parte 2: Verificador de Força de Senha (⭐⭐⭐)

Escreva um programa para determinar se a senha de um usuário é segura. A força da senha depende do seu comprimento e dos tipos de caracteres que contém.

Exemplo: Verificador de Força de Senha

PYTHON
# Verificador de Força de Senha

password = "Py3#thon"

# Analisa características da senha
length = len(password)                    # Comprimento
has_digit = any(c.isdigit() for c in password)     # Contém dígito
has_letter = any(c.isalpha() for c in password)    # Contém letra
has_special = not password.isalnum()               # Contém caractere especial

print("=== Verificador de Força de Senha ===")
print(f"Senha: {password}")
print(f"Comprimento: {length}")
print(f"Contém dígito: {has_digit}")
print(f"Contém letra: {has_letter}")
print(f"Contém caractere especial: {has_special}")

# Combina condições com operadores lógicos para determinar força
if length < 6:
    strength = "Fraca"
elif length >= 10 and has_digit and has_letter and has_special:
    strength = "Forte"
elif length >= 8 and has_digit and has_letter:
    strength = "Média"
else:
    strength = "Fraca"

print(f"Força da senha: {strength}")
▶ Experimente

Saída:

TEXT
=== Verificador de Força de Senha ===
Senha: Py3#thon
Comprimento: 8
Contém dígito: True
Contém letra: True
Contém caractere especial: True
Força da senha: Média

Detalhes: len() obtém o comprimento da string, isdigit() verifica dígitos, isalpha() verifica letras, isalnum() verifica se apenas letras e dígitos (retorna False se houver caracteres especiais — negado com not se torna "contém caractere especial"). Estes métodos serão abordados sistematicamente na lição de strings.


Erros Comuns de Ramificação/Laço

Todo mundo comete erros ao escrever código, especialmente iniciantes em laços. Aqui estão as armadilhas mais típicas.

Erro 1: Laço Infinito — Esquecer de Atualizar a Variável de Condição

PYTHON
# Errado
n = 1
while n <= 10:
    print(n)
    # esqueceu n += 1 — nunca termina

# Correto
n = 1
while n <= 10:
    print(n)
    n += 1

Erro 2: Confundir = com ==

PYTHON
# Errado
if score = 100:  # Isto é atribuição, não comparação!
    print("Perfeito!")

# Correto
if score == 100:
    print("Perfeito!")

Erro 3: Modificar uma Lista Durante a Iteração

PYTHON
# Errado — deletar durante iteração causa pulos
numbers = [1, 2, 3, 4, 5]
for num in numbers:
    if num % 2 == 0:
        numbers.remove(num)
print(numbers)  # Pode não ser o que você espera

# Correto — crie uma nova lista
numbers = [1, 2, 3, 4, 5]
odd_numbers = [num for num in numbers if num % 2 != 0]
print(odd_numbers)

Erro 4: Entender Errado o Valor Final de range()

PYTHON
# Errado: esperando range(5) exibir 1 2 3 4 5
for i in range(5):
    print(i)  # Saída real: 0 1 2 3 4

# Correto
for i in range(1, 6):
    print(i)  # Saída: 1 2 3 4 5

Casos de Uso Comuns

Cenário Técnica de Laço/Ramificação Descrição
Processamento de dados (filtragem, limpeza) for + continue Pular dados inválidos
Menu de interação com usuário while True + break Mostrar menu repetidamente até sair
Carregamento paginado while + condição Até não haver mais dados
Busca/pesquisa for + break + else Parar ao encontrar; else se não encontrado
Processamento em lote de arquivos for + lógica aninhada Iterar cada arquivo em um diretório
Laço principal de jogo while True + tratamento de eventos Renderização contínua e resposta a entrada

❓ Perguntas Frequentes

P: Continuo tendo laços infinitos. O que devo verificar? R: Verifique três coisas: 1) A condição do laço algum dia se tornará False? 2) O corpo do laço modifica a variável de condição? 3) while True tem um break correspondente? Adicionar print() para exibir valores-chave de variáveis é a maneira mais eficaz de depurar laços infinitos. P: Qual é mais eficiente — range() ou iterar sobre uma lista? R: range() retorna uma sequência preguiçosa sem gerar todos os números de uma vez. range(1000000) usa quase nenhuma memória, enquanto list(range(1000000)) usa muita. Para grandes contagens de iteração, use range() diretamente para melhor eficiência de memória. P: O código do projeto é muito mais longo que os exemplos anteriores. Como devo lê-lo? R: Três passos: Primeiro, entenda a estrutura geral (quantos laços/condições). Segundo, entenda o fluxo principal (como as variáveis mudam). Terceiro, concentre-se nos casos extremos (validação de entrada, divisão por zero, etc.). Código bom é auto-documentado — nomes de variáveis significativos e comentários nos pontos-chave.


📖 Resumo


📝 Atividades

⭐: Números Narcisistas

Um "número narcisista" é um número de 3 dígitos onde a soma dos cubos de seus dígitos é igual ao próprio número. Por exemplo: 153 = 1^3 + 5^3 + 3^3.

Use um laço for para encontrar todos os números narcisistas (existem 4).

Dica: Use range(100, 1000) para iterar todos os números de 3 dígitos; use // e % para extrair dígitos das centenas, dezenas e unidades.

⭐⭐: Imprimir um Losango

Aceite um número ímpar n do usuário, depois exiba um losango feito de * no console.

Exemplo (n=5):

TEXT
  *
 ***
*
 ***
  *

Dica: Um losango tem metade superior e inferior. Para a metade superior, faça laço i de 1 a n//2 + 1, diminuindo espaços e aumentando asteriscos.

⭐⭐⭐: Sistema de Gerenciamento de Notas de Alunos

Escreva um programa que implemente os seguintes recursos:

TEXT
1. Insira notas dos alunos (digite q para parar)
2. Calcule total, média, nota mais alta e mais baixa
3. Conte alunos em cada faixa: 90-100 (Excelente), 80-89 (Bom), 70-79 (Médio), 60-69 (Aprovado), <60 (Reprovado)
4. Exiba notas ordenadas da mais alta para a mais baixa

Requisitos:

Este projeto aplica de forma abrangente laços, listas, ordenação e estatísticas. Completá-lo significa que você realmente domina o fluxo de controle básico do Python.

100%