Caça-Palavras
Grade de letras onde o aprendiz localiza palavras ocultas em qualquer direção. Reforça a forma escrita de termos técnicos e serve como atividade de revisão lúdica.
Experimente
Encontre os termos do oceano
Descubra a resposta de cada pista e localize a palavra na grade.
1.
Maior mamífero marinho do planeta, conhecido pelo canto que viaja quilômetros debaixo d'água.
2.
Molusco de oito tentáculos e inteligência notável, capaz de mudar de cor para se camuflar.
3.
Organismo marinho que forma recifes coloridos, abrigando grande parte da vida no oceano.
4.
Planta marinha simples, sem raízes verdadeiras, que produz boa parte do oxigênio do planeta.
5.
Corpo de água salgada que cobre a maior parte da superfície da Terra.
Código-fonte
Dados de exemplo
Cada pista tem uma pergunta e a resposta certa — a palavra em si nunca aparece na tela, só a grade e a pergunta.
| 1 |
<?php
|
| 2 |
$grade = [
|
| 3 |
['P','I','A','N','O'],
|
| 4 |
['T','E','S','B','H'],
|
| 5 |
['U','R','M','C','A'],
|
| 6 |
['B','G','K','F','R'],
|
| 7 |
['A','L','W','N','P'],
|
| 8 |
['Q','Z','Y','D','A'],
|
| 9 |
];
|
| 10 |
$pistas = [
|
| 11 |
['id' => 'p1', 'pergunta' => 'Instrumento de teclas brancas e pretas, presente em orquestras e salas de estar.', 'resposta' => 'PIANO'],
|
| 12 |
['id' => 'p2', 'pergunta' => 'Instrumento de sopro grave, o maior da família dos metais.', 'resposta' => 'TUBA'],
|
| 13 |
['id' => 'p3', 'pergunta' => 'Instrumento de cordas triangular, tocado com os dedos, símbolo clássico de anjos.', 'resposta' => 'HARPA'],
|
| 14 |
];
|
| 15 |
?>
|
Estrutura da questão
A grade vem primeiro; as pistas ficam abaixo dela, sem revelar a palavra — só quem souber a resposta consegue procurar a sequência certa.
| 1 |
<div class="questao" data-tipo="caca-palavras">
|
| 2 |
|
| 3 |
<div class="grade" style="grid-template-columns: repeat(<?= count($grade[0]) ?>, 40px);">
|
| 4 |
<?php foreach ($grade as $r => $linha): foreach ($linha as $c => $letra): ?>
|
| 5 |
<button type="button" class="celula" data-row="<?= $r ?>" data-col="<?= $c ?>" data-letra="<?= $letra ?>"><?= $letra ?></button>
|
| 6 |
<?php endforeach; endforeach; ?>
|
| 7 |
</div>
|
| 8 |
|
| 9 |
<p class="questao-instrucao">Descubra a resposta de cada pista e localize a palavra na grade.</p>
|
| 10 |
|
| 11 |
<div class="pistas">
|
| 12 |
<?php foreach ($pistas as $i => $pista): ?>
|
| 13 |
<div class="pista" data-resposta="<?= $pista['resposta'] ?>">
|
| 14 |
<p class="pista-numero"><?= $i + 1 ?>.</p>
|
| 15 |
<p class="pista-pergunta"><?= htmlspecialchars($pista['pergunta']) ?></p>
|
| 16 |
<p class="pista-resposta" hidden>Resposta: <?= $pista['resposta'] ?></p>
|
| 17 |
</div>
|
| 18 |
<?php endforeach; ?>
|
| 19 |
</div>
|
Ações da questão
Verificar, o painel de resultado e o botão de reiniciar — os dois últimos nascem ocultos.
| 1 |
<button type="button" class="questao-verificar">Verificar resposta</button>
|
| 2 |
|
| 3 |
<div class="questao-painel" hidden>
|
| 4 |
<p class="questao-painel-mensagem"></p>
|
| 5 |
</div>
|
| 6 |
|
| 7 |
<button type="button" class="questao-reset" hidden>Tentar novamente</button>
|
| 8 |
|
| 9 |
</div>
|
Grade
Centralizada com flexbox, largura própria por causa das colunas dinâmicas.
| 1 |
.questao {
|
| 2 |
display: flex;
|
| 3 |
flex-direction: column;
|
| 4 |
align-items: center;
|
| 5 |
}
|
| 6 |
.grade {
|
| 7 |
display: inline-grid;
|
| 8 |
gap: 2px;
|
| 9 |
margin-bottom: 16px;
|
| 10 |
}
|
Célula — estados
Cada estado troca o par cor-de-fundo/cor-de-texto inteiro, nunca só adiciona uma cor nova por cima da anterior. Uma célula só tem uma classe de estado por vez — trocar em vez de empilhar evita que a cor antiga permaneça visível por trás da nova.
| 1 |
.celula {
|
| 2 |
width: 40px;
|
| 3 |
height: 40px;
|
| 4 |
border: 1px solid #cbd5e1;
|
| 5 |
border-radius: 6px;
|
| 6 |
font-weight: 700;
|
| 7 |
font-size: 16px;
|
| 8 |
text-transform: uppercase;
|
| 9 |
cursor: pointer;
|
| 10 |
background: #f1f5f9;
|
| 11 |
color: #475569;
|
| 12 |
}
|
| 13 |
.celula:hover {
|
| 14 |
background: #e0e7ff;
|
| 15 |
color: #4338ca;
|
| 16 |
}
|
| 17 |
.celula.selecionada {
|
| 18 |
background: #c7d2fe;
|
| 19 |
color: #3730a3;
|
| 20 |
}
|
| 21 |
.celula.encontrada {
|
| 22 |
background: #bbf7d0;
|
| 23 |
color: #15803d;
|
| 24 |
}
|
| 25 |
.celula.revelada {
|
| 26 |
background: #fde68a;
|
| 27 |
color: #92400e;
|
| 28 |
}
|
Pistas
A pergunta fica visível desde o início; a resposta nasce oculta e só some o "hidden" quando a palavra é achada ou a atividade é verificada.
| 1 |
.questao-instrucao {
|
| 2 |
margin: 0 0 12px;
|
| 3 |
font-size: 13px;
|
| 4 |
color: #64748b;
|
| 5 |
}
|
| 6 |
.pistas {
|
| 7 |
width: 100%;
|
| 8 |
display: flex;
|
| 9 |
flex-direction: column;
|
| 10 |
gap: 8px;
|
| 11 |
margin-bottom: 16px;
|
| 12 |
}
|
| 13 |
.pista {
|
| 14 |
padding: 12px;
|
| 15 |
border: 1px solid #cbd5e1;
|
| 16 |
border-radius: 10px;
|
| 17 |
background: #f8fafc;
|
| 18 |
}
|
| 19 |
.pista-numero {
|
| 20 |
margin: 0 0 4px;
|
| 21 |
font-size: 12px;
|
| 22 |
font-weight: 700;
|
| 23 |
color: #4f46e5;
|
| 24 |
}
|
| 25 |
.pista-pergunta {
|
| 26 |
margin: 0;
|
| 27 |
font-size: 14px;
|
| 28 |
color: #475569;
|
| 29 |
}
|
| 30 |
.pista-resposta {
|
| 31 |
margin: 8px 0 0;
|
| 32 |
font-size: 14px;
|
| 33 |
font-weight: 600;
|
| 34 |
color: #059669;
|
| 35 |
}
|
| 36 |
.pista-resposta[hidden] {
|
| 37 |
display: none;
|
| 38 |
}
|
Ações
Botões de largura total, um de cada vez na tela.
| 1 |
.questao-verificar,
|
| 2 |
.questao-reset {
|
| 3 |
display: block;
|
| 4 |
width: 100%;
|
| 5 |
padding: 12px 16px;
|
| 6 |
border: none;
|
| 7 |
border-radius: 10px;
|
| 8 |
font: inherit;
|
| 9 |
font-weight: 600;
|
| 10 |
cursor: pointer;
|
| 11 |
}
|
| 12 |
.questao-verificar {
|
| 13 |
background: #4f46e5;
|
| 14 |
color: #fff;
|
| 15 |
}
|
| 16 |
.questao-reset {
|
| 17 |
background: #e5e7eb;
|
| 18 |
color: #1f2937;
|
| 19 |
}
|
Estado oculto
O atributo hidden nativo tem a mesma especificidade da regra de exibição acima — sem isto, "Tentar novamente" apareceria antes de verificar.
| 1 |
.questao-verificar[hidden],
|
| 2 |
.questao-reset[hidden] {
|
| 3 |
display: none;
|
| 4 |
}
|
Painel de resultado
Caixa de destaque com o resultado da verificação.
| 1 |
.questao-painel {
|
| 2 |
width: 100%;
|
| 3 |
margin: 16px 0;
|
| 4 |
padding: 16px;
|
| 5 |
border-radius: 12px;
|
| 6 |
background: #1e3a8a;
|
| 7 |
color: #dbeafe;
|
| 8 |
font-weight: 600;
|
| 9 |
box-sizing: border-box;
|
| 10 |
}
|
Encontrar os elementos da questão
Localiza a grade, as pistas e as ações.
| 1 |
document.addEventListener('DOMContentLoaded', function () {
|
| 2 |
document.querySelectorAll('.questao[data-tipo="caca-palavras"]').forEach(function (questao) {
|
| 3 |
var pistas = questao.querySelectorAll('.pista');
|
| 4 |
var total = pistas.length;
|
| 5 |
var encontradas = 0;
|
| 6 |
var selecionadas = [];
|
| 7 |
var verificar = questao.querySelector('.questao-verificar');
|
| 8 |
var painel = questao.querySelector('.questao-painel');
|
| 9 |
var mensagem = painel.querySelector('.questao-painel-mensagem');
|
| 10 |
var reset = questao.querySelector('.questao-reset');
|
| 11 |
var bloqueada = false;
|
Trocar o estado de uma célula
Cada célula tem só uma classe de estado por vez — sempre remove as outras antes de adicionar a nova, nunca empilha uma cor em cima da anterior.
| 1 |
var ESTADOS = ['selecionada', 'encontrada', 'revelada'];
|
| 2 |
function marcar(celula, estado) {
|
| 3 |
celula.classList.remove.apply(celula.classList, ESTADOS);
|
| 4 |
if (estado) celula.classList.add(estado);
|
| 5 |
}
|
Localizar uma palavra na grade
Varre a grade em 4 direções (cima, baixo, esquerda, direita) — a grade só posiciona palavras em linha reta, nunca na diagonal.
| 1 |
function localizar(palavra) {
|
| 2 |
var celulas = Array.prototype.slice.call(questao.querySelectorAll('.celula'));
|
| 3 |
var mapa = {};
|
| 4 |
celulas.forEach(function (c) { mapa[c.dataset.row + ':' + c.dataset.col] = c; });
|
| 5 |
var direcoes = [[-1,0],[0,-1],[0,1],[1,0]];
|
| 6 |
palavra = palavra.toUpperCase();
|
| 7 |
for (var i = 0; i < celulas.length; i++) {
|
| 8 |
for (var d = 0; d < direcoes.length; d++) {
|
| 9 |
var caminho = [];
|
| 10 |
for (var k = 0; k < palavra.length; k++) {
|
| 11 |
var chave = (parseInt(celulas[i].dataset.row) + direcoes[d][0] * k) + ':' + (parseInt(celulas[i].dataset.col) + direcoes[d][1] * k);
|
| 12 |
var atual = mapa[chave];
|
| 13 |
if (!atual || atual.dataset.letra.toUpperCase() !== palavra[k]) { caminho = []; break; }
|
| 14 |
caminho.push(atual);
|
| 15 |
}
|
| 16 |
if (caminho.length === palavra.length) return caminho;
|
| 17 |
}
|
| 18 |
}
|
| 19 |
return [];
|
| 20 |
}
|
Verificar
Trava a grade e revela a resposta (e a localização) de toda pista que ainda não tinha sido achada — funciona tanto clicado manualmente quanto ao completar tudo sozinho.
| 1 |
function concluir() {
|
| 2 |
mensagem.textContent = encontradas === total
|
| 3 |
? 'Todas as palavras encontradas!'
|
| 4 |
: encontradas + '/' + total + ' palavras encontradas.';
|
| 5 |
painel.hidden = false;
|
| 6 |
|
| 7 |
pistas.forEach(function (pista) {
|
| 8 |
if (pista.dataset.encontrada === 'true') return;
|
| 9 |
pista.dataset.encontrada = 'false';
|
| 10 |
pista.querySelector('.pista-resposta').hidden = false;
|
| 11 |
localizar(pista.dataset.resposta).forEach(function (celula) { marcar(celula, 'revelada'); });
|
| 12 |
});
|
| 13 |
|
| 14 |
questao.querySelectorAll('.celula').forEach(function (c) { c.disabled = true; });
|
| 15 |
bloqueada = true;
|
| 16 |
verificar.hidden = true;
|
| 17 |
reset.hidden = false;
|
| 18 |
}
|
Clicar numa letra
Cada clique entra ou sai da seleção atual; a sequência selecionada é comparada com a resposta de cada pista a cada clique.
| 1 |
questao.querySelectorAll('.celula').forEach(function (celula) {
|
| 2 |
celula.addEventListener('click', function () {
|
| 3 |
if (bloqueada || celula.disabled) return;
|
| 4 |
var idx = selecionadas.indexOf(celula);
|
| 5 |
if (idx >= 0) { selecionadas.splice(idx, 1); marcar(celula, null); }
|
| 6 |
else { selecionadas.push(celula); marcar(celula, 'selecionada'); }
|
| 7 |
|
| 8 |
var sequencia = selecionadas.map(function (c) { return c.dataset.letra; }).join('').toUpperCase();
|
| 9 |
pistas.forEach(function (pista) {
|
| 10 |
if (pista.dataset.encontrada === 'true' || sequencia !== pista.dataset.resposta) return;
|
| 11 |
pista.dataset.encontrada = 'true';
|
| 12 |
pista.querySelector('.pista-resposta').hidden = false;
|
| 13 |
encontradas++;
|
| 14 |
selecionadas.forEach(function (c) { marcar(c, 'encontrada'); c.disabled = true; });
|
| 15 |
selecionadas = [];
|
| 16 |
if (encontradas === total) concluir();
|
| 17 |
});
|
| 18 |
});
|
| 19 |
});
|
| 20 |
|
| 21 |
verificar.addEventListener('click', concluir);
|
Reiniciar
Devolve a grade e as pistas ao estado inicial.
| 1 |
reset.addEventListener('click', function () {
|
| 2 |
bloqueada = false;
|
| 3 |
selecionadas = [];
|
| 4 |
encontradas = 0;
|
| 5 |
questao.querySelectorAll('.celula').forEach(function (c) { c.disabled = false; marcar(c, null); });
|
| 6 |
pistas.forEach(function (pista) {
|
| 7 |
delete pista.dataset.encontrada;
|
| 8 |
pista.querySelector('.pista-resposta').hidden = true;
|
| 9 |
});
|
| 10 |
painel.hidden = true;
|
| 11 |
verificar.hidden = false;
|
| 12 |
reset.hidden = true;
|
| 13 |
});
|