🧩 Exercícios Integrados

8 problemas criativos em JavaScript + HTML que cobrem todos os tópicos da disciplina. Cada grupo escolhe 4.

👥 Atividade em grupo 🎯 Escolha 4 dos 8 ⏱ 3 aulas de 45 min 🟡 JavaScript + 🌐 HTML5 Obs: Página criada por IA com base em arquivo de aula
Exercícios escolhidos:
0 / 4
📌 Como funciona Cada exercício integra todos os tópicos estudados: classes JavaScript (herança com extends), simulação de interfaces, tratamento de erros com try/catch, persistência com localStorage, HTML5 semântico, manipulação do DOM, querySelector, innerHTML e eventos. Clique no card para ver o enunciado. Marque com ✓ os 4 que seu grupo escolheu.
🏗️ Classes e Herança JS 🔌 Simulação de Interfaces ⚠️ try/catch e Erros 💾 localStorage 🌐 DOM, eventos e innerHTML
1
🧙
O Grimório dos Heróis
Sistema de personagens para um RPG de texto em JS
Difícil Herança Interfaces try/catch localStorage DOM + eventos
🗺️ Contexto O reino de Algorithmia está ameaçado por bugs ancestrais. Você foi convocado para criar o Grimório dos Heróis — um sistema que registra e exibe os guerreiros que defenderão o reino. Cada herói tem habilidades únicas, e o sistema precisa ser robusto o suficiente para sobreviver a entradas inválidas dos recrutas desastrados.

⚙️ Parte JavaScript — O Motor do Grimório

    >Crie a classe Heroi com os atributos nome, nivel e pontosDeVida. No construtor, se nome estiver vazio, lance um Error com mensagem adequada. Adicione o método getStatus() que retorna uma string formatada com os dados do herói. >Crie as subclasses Mago (tem mana; método atacar() consome 10 de mana — se não tiver, lança Error), Guerreiro (tem forca; atacar() retorna dano baseado na força) e Arqueiro (tem flechas; atacar() só funciona se flechas > 0). >Simule uma "interface" Combatente: crie uma função verificarCombatente(obj) que recebe um objeto e verifica se ele possui os métodos atacar() e getStatus(). Se não possuir, lança um Error informando qual método está faltando. >Crie o objeto grimorio (não precisa ser classe) com os métodos:
    adicionarHeroi(heroi): usa verificarCombatente() antes de adicionar
    salvar(): serializa o array de heróis com JSON.stringify e salva no localStorage
    carregar(): lê do localStorage, faz JSON.parse e reconstrói os objetos
    buscarPorNome(nome): retorna o herói ou lança Error se não encontrar

🌐 Parte HTML + DOM

    >Crie um formulário com campos: nome, tipo (select: Mago/Guerreiro/Arqueiro) e nível. Ao submeter (evento submit com preventDefault()), instancie o herói correto e chame grimorio.adicionarHeroi() dentro de um try/catch. >Exiba cada herói cadastrado como um card gerado com innerHTML. O card deve mostrar nome, tipo, nível e status — com cor diferente por tipo (azul = Mago, vermelho = Guerreiro, verde = Arqueiro). >Cada card deve ter um botão "⚔️ Atacar" que chama atacar() dentro de um try/catch e exibe o resultado (ou o erro) em um parágrafo abaixo do card, sem usar alert(). >Adicione os botões "💾 Salvar Grimório" e "📂 Carregar Grimório" que chamam grimorio.salvar() e grimorio.carregar() e atualizam a lista de cards na tela.
💡 Dica Ao carregar do localStorage, os dados vêm como objetos planos — sem os métodos das classes. Você precisa recriar as instâncias com new Mago(...), new Guerreiro(...) etc., usando o campo tipo salvo no JSON para saber qual classe usar.
class Heroi {
  constructor(nome, nivel, pontosDeVida) {
    if (!nome) throw new Error("Nome não pode ser vazio!");
    this.nome = nome;
    this.nivel = nivel;
    this.pontosDeVida = pontosDeVida;
    this.tipo = "Heroi"; // será sobrescrito nas subclasses
  }
  getStatus() {
    return `${this.nome} | Nível ${this.nivel} | HP: ${this.pontosDeVida}`;
  }
}

class Mago extends Heroi {
  constructor(nome, nivel, pontosDeVida, mana) {
    super(nome, nivel, pontosDeVida);
    this.mana = mana;
    this.tipo = "Mago";
  }
  atacar() {
    if (this.mana <= 0) throw new Error(`${this.nome} não tem mana!`);
    this.mana -= 10;
    return `${this.nome} lança bola de fogo! Mana: ${this.mana}`;
  }
}
📁 Entrega Um único arquivo grimorio.html com todo o JavaScript no <script> e o HTML na mesma página. Teste com ao menos 3 heróis de tipos diferentes, salvando e recarregando do localStorage.
2
🎬
CinemaCode — Plataforma de Streaming
Catálogo de mídias com busca e filtro em tempo real
Difícil Herança Interfaces try/catch localStorage DOM + eventos
🎥 Contexto A startup CinemaCode quer lançar uma plataforma de streaming, mas o desenvolvedor principal fugiu para as montanhas com um laptop. Você herdou o projeto pela metade e precisa terminar o catálogo, a busca e os controles de reprodução — antes que os investidores percebam.

⚙️ Parte JavaScript

    >Crie a classe Midia com titulo, ano e genero. Se o ano for anterior a 1888 (primeiro filme da história), lance um Error. Adicione o método getInfo() retornando uma string formatada. >Crie as subclasses Filme (adiciona diretor e duracao em minutos), Serie (adiciona temporadas e episodiosPorTemporadagetInfo() calcula o total de episódios) e Documentario (adiciona tema). >Simule uma interface Reproducivel: crie a função verificarReproducivel(obj) que confere se o objeto tem os métodos play(), pause() e getInfo(). Adicione esses métodos em Midiaplay() muda o estado reproduzindo para true, pause() para false. >Crie o objeto catalogo com:
    adicionar(midia): usa verificarReproducivel() e adiciona à lista
    salvar() e carregar(): persistência com localStorage
    filtrarPorGenero(genero): retorna array filtrado
    buscarPorTitulo(texto): retorna mídias cujo título contenha o texto (case insensitive)

🌐 Parte HTML + DOM

    >Crie um formulário para cadastrar mídia (título, tipo, ano, gênero e campo extra conforme o tipo). Ao submeter, instancie a classe correta dentro de um try/catch e adicione ao catálogo. >Exiba as mídias em cards. Cada card deve ter botões "▶ Play" e "⏸ Pause" que alteram visualmente o card (cor de fundo, texto de status) via manipulação de classe CSS com classList. >Adicione um campo de busca: ao digitar (evento input), filtre os cards em tempo real usando buscarPorTitulo() — oculte os que não batem com style.display = 'none'. >Exiba um contador "X títulos encontrados" atualizado a cada busca com textContent.
💡 Dica de filtro em tempo real Use o evento input no campo de busca (não keyup). Ele dispara para qualquer mudança, incluindo colar texto. Percorra todos os cards com querySelectorAll e compare o texto do título com includes().
📁 Entrega Arquivo único cinemacode.html. Pré-cadastre ao menos 5 mídias de tipos diferentes no localStorage para demonstrar a busca funcionando.
3
🚀
Banco Intergaláctico S.A.
Sistema bancário para colônias espaciais
Difícil Herança Interfaces try/catch localStorage DOM + innerHTML
🌌 Contexto O Banco Intergaláctico S.A. opera em 7 colônias espaciais e aceita pagamentos em créditos galácticos. O sistema antigo foi destruído por uma tempestade de meteoros. Você tem até o nascer de Kepler-442b para entregar o novo sistema — ou os colonos ficam sem acesso às suas contas.

⚙️ Parte JavaScript

    >Crie a classe Conta com titular, numero e saldo. No construtor, valide que o saldo inicial não é negativo — se for, lance um Error. Mantenha um array historico de strings para registrar cada transação. >Adicione os métodos depositar(valor) e sacar(valor) na classe Conta. Lance Error para valor zero ou negativo em qualquer operação, e para saldo insuficiente no saque. Cada operação bem-sucedida deve adicionar uma entrada ao historico. >Crie as subclasses:
    ContaCorrente: tem limiteCredito; pode sacar além do saldo até o limite (saldo pode ficar negativo até -limiteCredito)
    ContaPoupanca: tem taxaJuros; adicione o método aplicarJuros() que aumenta o saldo pela taxa e registra no histórico
    ContaGalactica: herda de ContaCorrente; tem taxaCambio (padrão 3.7); adicione depositarCreditos(creditos) que converte e deposita em reais >Simule a interface Transacionavel: crie verificarTransacionavel(obj) que confere se o objeto tem depositar, sacar e getExtrato. Implemente getExtrato() em Conta retornando o array historico formatado. >Crie o objeto banco com:
    abrirConta(conta): valida com verificarTransacionavel()
    buscarConta(numero): lança Error se não encontrar
    transferir(origem, destino, valor): usa buscarConta() nos dois números, faz saque e depósito dentro de um try/catch
    salvar() e carregar(): persistência com localStorage

🌐 Parte HTML + DOM

    >Crie uma interface com três abas (Contas, Operações, Extrato) alternadas por eventos de clique que mostram/ocultam seções com style.display. >Na aba Contas: formulário para abrir conta (titular, número, tipo, saldo inicial) com feedback de erro inline via innerHTML. >Na aba Operações: campos para número da conta e valor, com botões "Depositar", "Sacar" e "Transferir". Resultados exibidos em um painel de log gerado com innerHTML. Linhas de erro em vermelho, sucesso em verde. >Na aba Extrato: campo para digitar o número da conta e botão "Ver Extrato" que gera uma tabela dinamicamente com innerHTML, mostrando cada transação do histórico.
⚠️ Atenção Ao carregar contas do localStorage, reconstrua as instâncias corretas com base no campo tipo salvo — os métodos das classes são perdidos na serialização JSON.
📁 Entrega Arquivo único banco-galactico.html. Demonstre ao menos 4 contas de tipos diferentes, uma transferência e a visualização do extrato.
4
🤖
Hospital dos Robôs
Sistema de triagem e prontuário para androides
Difícil Herança Interfaces try/catch localStorage DOM + eventos
🏥 Contexto No ano 2157, robôs também adoecem. O Hospital dos Robôs de Nova Curitiba atende androides com superaquecimento, falha de memória e corrosão de articulações. Você foi contratado para desenvolver o sistema de triagem e prontuário eletrônico antes que a fila de robôs enferrujados tome conta do corredor.

⚙️ Parte JavaScript

    >Crie a classe Robo com id, modelo, fabricante e anoFabricacao. No construtor, valide que modelo tem ao menos 3 caracteres — caso contrário, lance um Error. >Adicione o método diagnosticar() na classe base retornando uma string genérica. Crie as subclasses:
    AndroideServico: diagnosticar() verifica se anoFabricacao < 2140 e retorna aviso de superaquecimento; calcularCusto() retorna R$500
    RoboIndustrial: tem articulacoesDanificadas; calcularCusto() retorna 200 × articulacoesDanificadas
    RoboMedico: calcularCusto() sempre retorna R$1200; diagnosticar() sempre retorna urgência crítica >Simule a interface Diagnosticavel com a função verificarDiagnosticavel(obj) que confere se o objeto possui diagnosticar() e calcularCusto(). >Crie o objeto hospital com:
    admitir(robo): valida com verificarDiagnosticavel()
    buscarPorId(id): lança Error se não encontrar
    realizarTriagem(): retorna array com { robo, diagnostico, custo } de cada paciente
    salvar() e carregar(): usa localStorage

🌐 Parte HTML + DOM

    >Crie um formulário de admissão (id, modelo, fabricante, tipo, ano). Ao submeter, instancie o robô correto dentro de try/catch e exiba um card de prontuário gerado com innerHTML. >A cor do card deve refletir a urgência: vermelho (RoboMedico), amarelo (AndroideServico), verde (RoboIndustrial) — aplique via classList.add. >Adicione um campo de busca por ID: ao digitar (evento input), destaque o card correspondente com borda azul e role até ele com scrollIntoView(). >Adicione evento de duplo clique (dblclick) em cada card para marcar como "Alta" — o card fica cinza com texto riscado (use classList.toggle).
💡 Dica Para o scrollIntoView(), primeiro remova a classe de destaque de todos os cards com querySelectorAll + forEach, depois adicione só no card encontrado. Assim apenas um card fica destacado por vez.
📁 Entrega Arquivo único hospital-robos.html. Demonstre admissão de ao menos 5 robôs de tipos variados, busca por ID e marcação de alta com duplo clique.
5
🪄
Escola de Magia Algorithmia
Boletim mágico com cálculo de média e situação
Médio Herança Interfaces try/catch localStorage DOM + formulários
🏰 Contexto A Escola de Magia Algorithmia tem um problemão: o livro de registros foi transformado em sapo por um aluno descuidado. Agora você precisa criar um sistema digital para gerenciar os estudantes, suas notas em Feitiçaria Básica, Poções e Transfiguração, e emitir o boletim mágico antes da festa de formatura.

⚙️ Parte JavaScript

    >Crie a classe Estudante com nome, matricula e um objeto notas no formato { feiticaria: 0, pocoes: 0, transfiguracao: 0 }. >Adicione o método lancarNota(disciplina, valor): valide que valor está entre 0 e 10 (lance Error se não estiver) e que a disciplina existe no objeto notas (lance Error diferente se não existir). >Adicione calcularMedia() que retorna a média das três notas. Crie as subclasses:
    EstudanteBolsista: getSituacao() retorna "Aprovado" se média ≥ 7.0, "Recuperação" se ≥ 5.0, "Reprovado" se abaixo
    EstudanteRegular: getSituacao() retorna "Aprovado" se média ≥ 6.0, "Recuperação" se ≥ 4.0, "Reprovado" se abaixo >Simule a interface Avaliavel com verificarAvaliavel(obj) que confere se o objeto tem calcularMedia() e getSituacao(). >Crie o objeto secretaria com:
    matricular(estudante): valida com verificarAvaliavel()
    buscarPorMatricula(matricula): lança Error se não encontrar
    gerarRanking(): retorna o array de estudantes ordenado por média decrescente usando sort()
    salvar() e carregar(): persistência com localStorage, reconstruindo instâncias pelo campo tipo

🌐 Parte HTML + DOM

    >Crie um formulário com nome, matrícula, tipo (Bolsista/Regular) e os três campos de nota. Ao submeter com preventDefault(), instancie o estudante correto e lance as notas dentro de try/catch. >Exiba o boletim de cada estudante como um card gerado com innerHTML. O card deve mostrar nome, as três notas, média e situação. Use cores para a situação: verde (Aprovado), amarelo (Recuperação), vermelho (Reprovado) via classList.add. >Adicione um botão "🏆 Ver Ranking" que ordena os cards na tela pela média, do maior para o menor, reordenando os elementos no DOM sem recarregar a página. >Valide os campos de nota em tempo real com evento input: se o valor digitado estiver fora de 0–10, exiba uma mensagem de erro vermelha abaixo do campo usando querySelector e textContent.
💡 Dica para reordenar no DOM Para reordenar os cards visualmente, selecione o container pai com querySelector, converta os filhos em array com Array.from(), ordene com sort() e reinsira cada elemento com appendChild(). O DOM atualiza automaticamente.
📁 Entrega Arquivo único escola-magia.html. Demonstre ao menos 6 estudantes (3 bolsistas, 3 regulares) com notas variadas, e mostre o ranking funcionando.
6
🦁
Zoológico de Criaturas Impossíveis
Gerenciador de espécies que não deveriam existir
Médio Herança Interfaces try/catch localStorage DOM + eventos
🌿 Contexto O Zoológico Digital de Criaturas Impossíveis abriga seres fantásticos: Dragões que espirram HTML, Unicórnios que depuram código e Fênix que reiniciam o sistema quando tudo dá errado. O zelador foi transformado em variável local (saiu de escopo) e você precisa assumir o controle do sistema de alimentação e exibição das criaturas.

⚙️ Parte JavaScript

    >Crie a classe Criatura com nome, especie e nivelFome (0 a 10). Adicione o método alimentar(comida) que reduz o nível de fome em 3 (mínimo 0) e retorna uma mensagem. Se nivelFome já for 0, lance um Error informando que a criatura está saciada. >Crie as subclasses:
    Dragao: alimentar(comida) verifica se comida === "código compilado" — qualquer outra coisa lança Error com mensagem criativa
    Unicornio: aceita qualquer comida, mas se não for "arco-íris", o nível de fome só reduz 1 em vez de 3
    Fenix: ao ser alimentada com nivelFome === 0 lança Error "A Fênix renasceu e resetou tudo!" e zera todos os atributos para os valores iniciais >Simule a interface Alimentavel com verificarAlimentavel(obj) que confere se o objeto tem alimentar() e getNivelFome(). Adicione getNivelFome() em Criatura retornando this.nivelFome. >Crie o objeto zoologico com:
    adicionar(criatura): valida com verificarAlimentavel()
    alimentarTodas(comida): tenta alimentar cada criatura em um try/catch individual, registrando sucessos e erros separadamente
    listarFamintas(): retorna criaturas com nivelFome > 7
    salvar() e carregar(): usa localStorage

🌐 Parte HTML + DOM

    >Exiba um card fixo para cada criatura (Dragão, Unicórnio e Fênix) com uma barra de fome visual — um <div> cuja largura em % representa o nível de fome (nivelFome × 10 + "%"), atualizada via style.width. >Adicione um campo "O que servir?" e botões "Alimentar Todas" e "Alimentar Individualmente". Ao alimentar, atualize as barras e exiba o resultado de cada criatura em um log com innerHTML — erros em vermelho, sucessos em verde. >Adicione evento mouseover em cada card para exibir uma curiosidade sobre a criatura em um tooltip posicionado com CSS, criado e removido via innerHTML. >Use querySelector para atualizar o título da seção "🚨 Criaturas com fome crítica: X" sempre que uma alimentação ocorrer.
⚠️ Atenção O alimentarTodas() não deve parar se uma criatura lançar erro — use try/catch dentro do forEach para que cada criatura seja tratada independentemente.
📁 Entrega Arquivo único zoologico.html. Demonstre a alimentação com comida errada para o Dragão (erro), certa para o Unicórnio (sucesso parcial) e o renascimento da Fênix.
7
🛸
Agência Espacial BugFree
Gerenciamento de missões e tripulação interestelar
Difícil Herança Interfaces try/catch localStorage DOM + setInterval
🌠 Contexto A Agência Espacial BugFree planeja colonizar o planeta Kotlin-9, mas o sistema de gerenciamento de missões foi escrito em COBOL por um estagiário em 1974. Você tem 3 aulas para reescrever tudo antes do lançamento. A tripulação está na sala ao lado, nervosa, comendo chips e esperando o sistema funcionar.

⚙️ Parte JavaScript

    >Crie a classe Astronauta com nome, codigoCracha e nivelExperiencia (1–5). Valide no construtor que o nível está nesse intervalo — lance Error caso contrário. Adicione executarFuncao() retornando uma string genérica. >Crie as subclasses:
    Piloto: executarFuncao() retorna uma manobra calculada pelo nível de experiência
    Cientista: tem array experimentos; executarFuncao() retorna o próximo experimento da fila com shift() — se vazio, lança Error "Sem experimentos na fila!"
    Engenheiro: tem sistemaResponsavel; executarFuncao() tem 30% de chance de lançar Error "Falha no sistema: " + sistemaResponsavel (use Math.random()) >Simule a interface Tripulante com verificarTripulante(obj) que confere se tem executarFuncao() e nome. >Crie a classe Missao com nome, destino, duracaoDias e array tripulacao. Implemente:
    adicionarTripulante(astronauta): valida com verificarTripulante() e lança Error se já houver 7 membros
    iniciar(): chama executarFuncao() de cada membro em try/catch individual, retorna array de logs
    salvar() e carregar(): usa localStorage

🌐 Parte HTML + DOM

    >Crie um painel de missão: um formulário para adicionar tripulantes (nome, crachá, tipo, nível) e uma lista gerada com innerHTML exibindo cada membro. >Destaque automaticamente com fundo amarelo todos os tripulantes do tipo Engenheiro usando querySelectorAll após cada adição. >Adicione um botão "🚀 Iniciar Missão" que chama missao.iniciar() e exibe o log de cada tripulante em um painel — erros em vermelho, sucessos em verde. >Implemente um contador regressivo de lançamento usando setInterval: ao clicar em "🚀 Iniciar Missão", inicie uma contagem regressiva de 10 segundos exibida na tela com textContent. Ao chegar a zero, limpe o intervalo com clearInterval, mude o fundo da página para #0f172a e exiba "🚀 Missão iniciada! Boa viagem, tripulação!" com innerHTML.
💡 Dica sobre setInterval Guarde o retorno do setInterval em uma variável: const timer = setInterval(fn, 1000). Quando o contador chegar a zero, chame clearInterval(timer) para parar. Sem isso, o intervalo continua rodando para sempre mesmo após o zero.
📁 Entrega Arquivo único agencia-espacial.html. Demonstre uma missão com ao menos 5 tripulantes de tipos variados, incluindo um Engenheiro que falha sem abortar o restante da tripulação.
8
🏆
Torneio de IAs — Quem Programa Melhor?
Campeonato entre inteligências artificiais amadoras
Difícil Herança Interfaces try/catch localStorage DOM + eventos
🤖 Contexto Todo ano, a universidade de Compilópolis realiza o grande Torneio de IAs: sistemas de inteligência artificial amadora competem entre si para ver qual resolve mais desafios sem entrar em loop infinito. Você foi designado para criar o sistema de inscrição, pontuação e placar — e ele precisa tratar todos os erros possíveis, porque IAs amadoras são completamente imprevisíveis.

⚙️ Parte JavaScript

    >Crie a classe InteligenciaArtificial com nome, versao e pontuacao (inicia em 0). Valide no construtor que nome não está vazio. Adicione resolver(desafio) e getNome(). >Crie as subclasses:
    IAOtimista: resolver() tenta sempre, mas com 40% de chance lança Error("Loop infinito detectado! Reiniciando...")
    IAPessimista: resolver() só aceita desafios com menos de 20 caracteres — senão lança Error("Desafio complexo demais. Entrando em modo pânico.")
    IAEquilibrada: resolver() sempre funciona, mas usa multiplicador = 0.5 na pontuação >Simule a interface Competidor com verificarCompetidor(obj) que confere se o objeto tem resolver(), getNome() e a propriedade pontuacao. >Crie o objeto torneio com:
    inscrever(ia): valida com verificarCompetidor() e lança Error se o nome já estiver inscrito
    executarRodada(desafio, pontosPorAcerto): chama resolver() de cada IA em try/catch individual — quem resolver ganha os pontos multiplicados pelo multiplicador da IA (padrão 1)
    getPlacar(): retorna o array ordenado por pontuação decrescente com sort()
    salvar() e carregar(): usa localStorage, reconstruindo instâncias pelo campo tipo

🌐 Parte HTML + DOM

    >Crie uma tabela de placar gerada com innerHTML: posição, nome, versão, tipo e pontuação. A linha do líder tem fundo dourado (#fef9c3) e emoji 🏆 antes do nome, aplicado via classList. >Adicione campo "Desafio da rodada" e botão "▶ Executar Rodada". Ao clicar, chame torneio.executarRodada() e atualize a tabela completamente com innerHTML, reordenando pelo placar. >Exiba um log da última rodada abaixo da tabela: ✅ resolveu / ❌ falhou + mensagem do erro, com cores diferentes via innerHTML. >Formulário para inscrever nova IA (nome, versão, tipo) com validação inline: se o nome já existir, exiba erro com textContent sem usar alert().
💡 Dica de ordenação Para ordenar o placar use: ias.sort((a, b) => b.pontuacao - a.pontuacao). Valores negativos indicam que b vem antes de a. Compare essa abordagem com a reordenação de cards do DOM do Exercício 5 — é o mesmo conceito em contextos diferentes.
📁 Entrega Arquivo único torneio-ia.html. Demonstre ao menos 4 IAs de tipos diferentes, 3 rodadas com desafios variados (um curto para a IAPessimista funcionar, um longo para ela falhar) e placar final salvo no localStorage.