O PlayerCross é uma atividade de palavras cruzadas por dedução para o Moodle. Cada rodada sorteia uma frase-mistério e um conjunto de termos montado a partir de conceitos relacionados do curso; resolver um termo revela as letras que ele compartilha com todo outro termo pendente e com a própria frase-mistério.
👈 Use a barra lateral para pular direto a qualquer seção desta página.
✨ Funcionalidades
- 🧩 Jogo de palavras cruzadas por dedução: Cada rodada sorteia uma frase-mistério (a própria pista de um conceito do curso) e um conjunto de termos (outros conceitos cujas palavras compartilham letras com a frase-mistério). Resolver um termo revela suas letras compartilhadas em todo lugar onde ocorrem — em todos os termos pendentes e na própria frase-mistério — por identidade da letra, não por posição espacial.
- 🎯 Chute direto na frase-mistério: O estudante pode arriscar um palpite direto na frase-mistério a qualquer momento da rodada, sem precisar resolver todos os termos antes. Acertar antes de resolver qualquer termo ganha um bônus de acerto antecipado — veja Nota e Ranking.
- ⚖️ Condição de vitória configurável: Escolha se a rodada só é vencida resolvendo todos os termos e acertando a frase-mistério, ou apenas com o acerto da frase-mistério (os termos ainda ajudam revelando letras, mas se tornam opcionais para encerrar a rodada). Veja Nota e Ranking.
- 🛡️ Derrota automática ao esgotar um termo: Na condição “ambos obrigatórios”, um termo que esgota as tentativas torna a vitória matematicamente impossível — a rodada encerra imediatamente como derrota, em vez de deixar o estudante travado.
- 🚫 Derrota automática ao esgotar a frase-mistério: A frase-mistério tem seu próprio limite configurável de tentativas. Esgotá-lo sempre encerra a rodada como derrota, independente da condição de vitória — a frase é obrigatória para vencer nos dois modos.
- 🔡 Tratamento de slots não cobertos (configurável): Uma letra da frase-mistério que nenhum termo selecionado compartilha é, por padrão, revelada automaticamente desde o início da rodada (nenhum termo poderia revelá-la de graça); o professor pode desativar isso para que ela fique oculta até uma dica paga ou o fim da rodada.
- 📖 Integração com Glossário: Importa conceitos de um ou todos os glossários do curso como pool de palavras, usando as definições como pista de cada palavra.
- ✂️ Divisão de conceitos com várias palavras (opcional, desligado por padrão): Um conceito do glossário com várias palavras (ex.: “Sistema Operacional”) pode ser dividido em candidatas separadas de uma palavra só. Desligado por padrão para favorecer a qualidade das pistas — quando desativado, esse conceito simplesmente não entra no pool, em vez de gerar termos isolados que nem sempre fazem sentido sozinhos.
- 🚧 Stopwords configuráveis: Uma lista de palavras separadas por vírgula, por atividade (ex.: “de, da, e”), para ignorar ao dividir um conceito de glossário com várias palavras em candidatas — só relevante quando a divisão de conceitos acima está ativada.
- 🤖 Geração de palavras por IA (Opcional): Gera palavras candidatas e pistas para um tema informado via Central de IA (
local_aihub) ou o fallbackcore_aido Moodle. Palavras geradas são tratadas como entrada não confiável — só termos de um único token, puramente alfabéticos e dentro do intervalo de comprimento configurado são salvos, e entram no pool pendentes de aprovação do professor. - ✍️ Pool manual de palavras: Professores podem adicionar, editar, aprovar e excluir palavras diretamente na página de gerenciamento.
- 🚫 Prevenção de duplicatas: O mesmo texto de palavra só pode existir uma vez por pool da atividade, não importa qual fonte a adicionou — uma entrada manual bloqueia uma importação do glossário que colida (e vice-versa), então o sorteio nunca fica enviesado para uma palavra duplicada por acidente.
- 🔤 Validação de palavra manual: Uma palavra adicionada manualmente precisa ser só letras, dentro do intervalo de comprimento configurado, e ainda não estar no pool; o formulário rejeita uma inválida com o motivo específico, em vez de aceitar silenciosamente uma palavra que o jogo nunca conseguiria sortear de verdade.
- 🧩 Aviso de conceito fragmentado: Um conceito de glossário com várias palavras, dividido em várias entradas de uma palavra só, é sinalizado na tabela de gerenciamento de palavras, já que cada palavra-irmã ainda carrega a definição completa do conceito original como pista.
- 🔍 Contagem de palavras elegíveis ao vivo: O formulário de configuração mostra, ao vivo via AJAX, quantas palavras estão dentro do intervalo de comprimento configurado — verificado separadamente para o intervalo da frase-mistério e o dos termos — contra o pool real ao editar uma atividade existente, ou uma prévia do conteúdo do glossário selecionado ao criar uma nova.
- 🔍 Detecção de palavras inativas: Palavras do pool que não podem mais ser sorteadas (comprimento errado para seu papel, caracteres inválidos, ainda pendentes de aprovação) são sinalizadas por nome, com o motivo, na tabela de gerenciamento de palavras; uma contagem de palavras ativas/inativas é mostrada acima da área do jogo para quem gerencia a atividade.
- 🎯 Rastreamento de sorteios: A tabela de gerenciamento de palavras mostra quantas vezes cada palavra já foi sorteada como frase-mistério, contado ao vivo a partir do histórico de tentativas — sem nenhum passo de recálculo.
- 🔀 Modos de palavra: Frase-mistério aleatória por rodada (padrão) ou sequência compartilhada, em que todos os estudantes recebem o mesmo puzzle na mesma ordem — os termos nunca são sorteados à parte, então a mesma frase sempre traz os mesmos termos.
- 📏 Intervalos de comprimento independentes: O comprimento mínimo (e máximo, opcional) em letras da frase-mistério é configurado separadamente do intervalo de comprimento das próprias palavras-termo, de modo que uma pista longa e descritiva ainda pode gerar um puzzle administrável.
- 🔢 Número de termos configurável: De 3 a 10 termos por rodada (padrão 5), equilibrando dificuldade do puzzle e tamanho do pool.
- ⏳ Tentativas configuráveis, por termo e para a frase-mistério: Limita o número de palpites permitidos por termo individual, e separadamente para a própria frase-mistério (0 = ilimitado para qualquer um dos dois; ambos com padrão 3). Escolher pontuação Linear na nota ou no ranking exige que os dois sejam um valor real.
- 💡 Sistema de dica (com opção de desativar): Um único botão de dica, válido para a rodada inteira, revela uma letra por vez — essa letra aparece em todo termo pendente e na frase-mistério que a compartilhem, do mesmo jeito que resolver um termo faria — opcionalmente com custo em item via PlayerHUD. Professores podem desativar completamente o mecanismo de revelar dica para a atividade; quando mantido ativo (padrão), pode ser limitado a uma quantidade fixa de revelações por rodada (padrão 3) ou deixado ilimitado. Revelar dicas suficientes para descobrir todas as letras finaliza e vence a rodada sozinho, sem precisar resolver todos os termos.
- 🏳️ Desistir: O estudante pode desistir da rodada atual a qualquer momento — a frase-mistério correta e todas as palavras-termo são reveladas imediatamente.
- ⏱️ Intervalo configurável: Espera mínima entre rodadas (minutos, horas ou dias), sempre recalculada a partir da configuração atual da atividade.
- 🔢 Limite de rodadas: Professores podem limitar o total de rodadas por estudante (1–10 ou ilimitado).
- 🛡️ Integridade do limite de rodadas: Uma rodada abandonada no meio (aba fechada, sessão perdida) ainda conta contra o limite de rodadas — reservada assim que começa, não só quando termina, então nunca dá uma rodada extra de graça.
- 🔡 Correspondência insensível a acentos: Acentos são sempre removidos antes de comparar um palpite com seu alvo.
- ⌨️ Seleção de acento no teclado virtual: Segurar uma tecla com variantes acentuadas (a maioria das vogais, além de C, N e S) no teclado virtual abre um popup com essas variantes, igual ao padrão de teclado de celular — arrastar o dedo escolhe a variante, soltar confirma. Cobre diacríticos de português, espanhol, francês, italiano e alemão (incluindo Ç, Ñ e ß); alfabetos fora desse conjunto (nórdicas, eslavas, turco, islandês…) são uma possível adição futura, ainda não cobertos. Puramente estético: a correspondência de palpites continua sempre insensível a acentos.
- ⌨️ Teclado marca letras já reveladas: Uma letra já revelada em qualquer termo pendente ou na frase-mistério fica destacada no teclado virtual, para o estudante não perder tempo tentando de novo o que já sabe.
- 🟢 Aviso de pronto para enviar: A linha de um termo (ou da frase-mistério) revela seu próprio botão de envio assim que todas as suas caixas são preenchidas, bem ao lado das letras — sem precisar preencher os outros termos antes, nem procurar um botão em outro lugar da tela. A tecla Enter física também funciona; o teclado virtual em si só tem letras e Apagar, igual ao jogo original em que este plugin se baseia.
- ✅ Revelação com ortografia real: Ao resolver um termo, acertar a frase-mistério ou terminar a rodada, a palavra do termo e a frase-mistério são exibidas com a acentuação verdadeira do banco de palavras, mesmo que o palpite vencedor tenha sido digitado sem acento. Um termo inteiramente formado por letras já compartilhadas se resolve automaticamente no momento em que a frase-mistério é acertada, em vez de continuar marcado como não resolvido.
- 🧮 Pontuação Binária/Linear: Nota e ranking escolhem cada um seu próprio modo de pontuação de forma independente — Binário (crédito cheio numa vitória) ou Linear (o crédito diminui a cada palpite errado, em qualquer termo e na frase-mistério juntos) — mais um bônus de acerto antecipado por acertar a frase-mistério diretamente antes de resolver qualquer termo — veja Nota e Ranking.
- 📊 Métodos de avaliação: Maior nota, média das notas, primeira tentativa, última tentativa, ou média sobre todas as rodadas exigidas.
- 🧮 Transparência de avaliação: O estudante vê o método de avaliação ativo antes de jogar, do mesmo jeito que o Quiz do Moodle comunica seu próprio método de avaliação.
- 📋 Integração com o diário de notas: As notas são lançadas automaticamente a cada conclusão de rodada.
- ✅ Regra de conclusão personalizada: Número mínimo de rodadas concluídas, avaliado e aplicado imediatamente após cada rodada.
- 🔄 Suporte a redefinição de curso: “Redefinir curso” limpa as tentativas dos estudantes e reseta as notas da atividade, restrito ao curso alvo.
- 🏆 Ranking top 5: Classificação restrita à atividade, limitada aos 5 primeiros, com uma linha extra para um estudante fora do topo ver sua posição real. Respeita
SEPARATEGROUPS. - 📋 Histórico de tentativas: O estudante revisa cada rodada finalizada própria — frase-mistério, termos resolvidos, tentativas usadas, tempo e pontuação — pela barra de ferramentas. Quem gerencia a atividade também vê essa mesma página (incluindo as próprias tentativas, se houver), além de um relatório separado com todos os estudantes — veja Nota e Ranking.
- 🗑️ Exclusão de tentativas: No relatório com todos os estudantes, quem gerencia a atividade pode excluir tentativas individualmente ou em lote (com seleção de página inteira). A nota do estudante afetado é recalculada automaticamente, inclusive destravando configurações da atividade que ficam travadas assim que existe uma nota real registrada, caso todas as tentativas dele sejam removidas. Itens do PlayerHUD já concedidos não são revertidos automaticamente — um aviso na própria página informa isso quando a atividade concede itens por vitória.
- ❓ Ajuda no jogo: Uma página de ajuda dedicada explica a mecânica do puzzle, como enviar um palpite, tentativas, dicas, cronômetro, a condição de vitória, o método de avaliação da atividade e (quando a pontuação Linear está ativa) a fórmula de pontuação — além de, quando os limites relevantes de tentativas estiverem configurados, o risco de perder a rodada se as tentativas de um termo ou da frase-mistério se esgotarem.
- 👋 Onboarding na primeira visita: O modal “Como jogar” abre automaticamente na primeiríssima vez que um usuário visita qualquer atividade PlayerCross no site — uma única vez, sempre, em todo o site — e nunca mais se repete; o ícone de ajuda na barra de ferramentas sempre o reabre sob demanda.
- ♿ Acessibilidade: Contraste WCAG AA em cada peça do puzzle; indicadores de estado não-cromáticos;
aria-labelem cada campo; o comportamento de foco por caixa de letra reflete um campo de código de verificação, para navegação previsível por teclado e clique. - ⚡ Totalmente AJAX: Toda transição de rodada (palpite de termo, palpite final, dica, desistência, tempo esgotado, início, nova rodada) acontece sem recarregar a página.
- 🔔 Feedback por toast: Resultados do fluxo da rodada (um termo resolvido, um palpite errado, uma dica revelada) aparecem como notificações toast breves e que se fecham sozinhas, em vez de diálogos bloqueantes, mantendo o estudante no puzzle.
- 🎮 Integração com o PlayerHUD (Opcional): Exige itens do inventário para iniciar uma rodada ou revelar uma dica, com consumo FIFO atômico. O saldo atual do estudante contra a quantidade exigida é sempre mostrado antes, e um custo apontando para um item excluído ou de outro curso é dispensado em vez de bloquear o estudante. Também pode conceder um item a cada rodada vencida; seguindo a mesma regra antifarming do PlayerHUD, nenhum XP é concedido por esse item enquanto a atividade permitir rodadas ilimitadas, e o XP potencial dessa concessão é refletido na própria estimativa de teto de “XP total no jogo” do PlayerHUD.
- 🛡️ Integração segura entre cursos: Toda referência a item do PlayerHUD é validada contra a instância de bloco do próprio curso, nunca um item obsoleto ou de outro curso — mesmo após backup/restore ou duplicação de curso.
- 🔔 Reconhecimento de dependência do PlayerHUD: Quando o PlayerHUD está instalado no site mas ainda não foi adicionado ao curso atual, o formulário de configuração explica que a integração vai aparecer assim que o bloco for adicionado. Quando o plugin block_playerhud não está instalado em lugar nenhum do site, o administrador do site vê um aviso equivalente na própria página de configurações do plugin.
- 📦 Backup e Restauração: Suporte completo a backup/restore Moodle 2, incluindo a ação “Duplicar atividade”, o pool de palavras, tentativas, remapeamento de id de glossário e usuário, e remapeamento seguro de itens do PlayerHUD.
- 🔐 API de Privacidade: Compatível com LGPD/GDPR — exportação e exclusão completas de todos os dados pessoais armazenados.
🎓 Finalidade Educacional
O PlayerCross foi projetado para:
- Reforçar o aprendizado de conceitos trabalhados no curso ou disciplina
- Exercitar vários conceitos relacionados na mesma rodada, recompensando o estudante por perceber a ideia conectiva — um tema de unidade ou categoria — que une um conjunto de termos já estudados
- Fomentar experiências de aprendizagem lúdicas, baseadas em jogos
- Simplificar e tornar mais intuitivas as dinâmicas de aprendizagem e avaliação
- Contribuir para o alcance de objetivos educacionais em diferentes cursos e disciplinas
- Promover metodologias ativas de aprendizagem, incluindo aprendizagem baseada em jogos e gamificação
- Apoiar a prática de recuperação — o estudante precisa recordar cada conceito da memória antes de ver qualquer resposta, uma das técnicas mais eficazes para retenção de longo prazo
- Incentivar a prática espaçada — o intervalo configurável entre rodadas traz o estudante de volta ao conteúdo em múltiplas sessões, alinhado aos princípios da repetição espaçada
- Adicionar uma camada de aprendizagem associativa/elaborativa: resolver a frase-mistério exige manter vários conceitos em mente ao mesmo tempo e perceber como eles se relacionam por meio das letras compartilhadas — um exercício de síntese que uma única palavra isolada não provoca
Adequado para:
- Qualquer curso que use terminologia baseada em conceitos, especialmente unidades com vários termos relacionados
- Cursos acadêmicos gamificados usando o ecossistema PlayerGames
- Avaliação formativa e reforço de autoestudo
- Estratégias de reforço de engajamento
🕹️ Ecossistema PlayerGames
O PlayerCross faz parte do ecossistema de gamificação PlayerGames para Moodle. Sua principal integração direta é com o bloco PlayerHUD:
-
Bloco PlayerHUD (Opcional, v1.7.1+): Configure custos em itens para iniciar uma rodada ou revelar a dica de um termo, e uma concessão de item por rodada vencida.
-
PlayerGroup (Compatível): Grupos padrão do Moodle — criados manualmente ou pela atividade PlayerGroup — são respeitados pelo filtro
SEPARATEGROUPSdo ranking. -
PlayerWords (Atividade irmã): Também parte do ecossistema, o PlayerWords testa a recordação de um conceito por rodada em formato estilo Wordle. O PlayerCross reaproveita a mesma arquitetura de pool de palavras/PlayerHUD/diário de notas para adicionar um puzzle que conecta vários conceitos em uma única rodada.
Veja o hub do PlayerGames para a família completa de plugins.
🧩 Integração Opcional: Central de IA
A funcionalidade opcional de Geração de palavras por IA do PlayerCross pode usar o Central de IA (local_aihub, do mesmo autor, parte dos serviços compartilhados do ecossistema PlayerGames). Quando o Central de IA está instalado, qualquer chave pessoal ou do site que um professor ou administrador já tenha configurado lá fica automaticamente disponível para o PlayerCross — sem precisar reconfigurar a chave. O PlayerCross nunca contata um provedor de IA diretamente; sem o Central de IA instalado, ele recorre ao subsistema core_ai do próprio Moodle, roteando para o provedor que o administrador do site tiver configurado lá.
👉 https://github.com/jeanlucio/moodle-local_aihub
📦 Requisitos
| Componente | Versão |
|---|---|
| Moodle | 4.5 – 5.2 |
| PHP | 8.1+ |
| PlayerHUD (opcional) | v1.7.1+ |
🛠️ Instalação e Configuração
- Baixe o arquivo
.zipou clone este repositório. - Extraia na pasta
mod/do seu Moodle. - Renomeie para
playercross(se necessário). Caminho final:seu-moodle/mod/playercross/ - Acesse Administração do site > Notificações para concluir a instalação.
- Adicione uma atividade PlayerCross a qualquer curso.
Este plugin não tem configurações de nível de site para o administrador ajustar — toda
configuração é feita pelo professor ao adicionar a atividade a um curso, conforme explicado
em Como Usar logo abaixo. Se o block_playerhud não estiver instalado no site, a
própria página de configurações do plugin em Administração do site → Plugins → Módulos de
atividade → PlayerCross mostra um aviso informativo sobre isso — não há nada a configurar
ali de qualquer forma.
📖 Como Usar
- Adicione uma atividade PlayerCross ao seu curso.
- Configure:
- Intervalo de comprimento da frase-mistério (independente do intervalo das próprias palavras-termo) e número de termos por rodada
- Condição de vitória (termos e frase-mistério obrigatórios, ou só o acerto da frase-mistério) e se letras não cobertas da frase-mistério são reveladas automaticamente
- Máximo de tentativas por termo e para a frase-mistério, intervalo entre rodadas e limite de rodadas
- Se dicas são permitidas, e se sim, o máximo de revelações por rodada (padrão 3, ou ilimitado)
- Modo de palavra (aleatório ou sequência compartilhada)
- Método de avaliação, modo de pontuação da nota e do ranking (Binário ou Linear), e configurações do diário de notas
- Fontes de palavras (manual, Glossário, IA), glossário de origem, e uma lista de stopwords a ignorar ao dividir conceitos de glossário com várias palavras (todos opcionais)
- Custos em itens do PlayerHUD e concessão por vitória (opcional, quando o bloco PlayerHUD está presente)
- Abra a página Gerenciar palavras para adicionar, gerar com IA, aprovar, editar ou excluir palavras.
- O estudante joga diretamente na página da atividade — resolvendo termos, chutando a frase-mistério, revelando dicas e desistindo de rodadas, sem recarregar a página. A própria barra de ferramentas da página dá acesso às regras (ajuda), ao histórico de tentativas e ao ranking.
- Notas e ranking são atualizados automaticamente após cada rodada.
🧮 Nota e Ranking
O PlayerCross calcula uma nota e um total de ranking a partir das mesmas rodadas terminadas, mas os dois são configurados de forma totalmente independente — o professor pode manter a nota simples e ainda assim recompensar jogadas eficientes no ranking, ou o contrário.
Ambos são totalmente opcionais, e cada um é ligado ou desligado de forma independente:
- Nota: deixe o campo padrão
Notadefinido como Nenhuma para rodar a atividade totalmente sem avaliação — nenhuma nota é calculada ou lançada no diário de notas, e as configuraçõesMétodo de avaliação/Modo de pontuação da notasomem do formulário. - Ranking: deixe
Mostrar rankingcomo Não para ocultar o ranking em todo lugar — no jogo, na página dedicada de ranking e na coluna extra do histórico de tentativas — e a configuraçãoModo de pontuação do rankingsome do formulário também.
Desligar um nunca afeta o outro: uma atividade pode ser avaliada sem ranking, ter ranking sem nota, ambos, ou nenhum dos dois.
A pontuação por rodada decide quanto vale uma única rodada, escolhida separadamente para a
nota e para o ranking (configurações Modo de pontuação da nota / Modo de pontuação do
ranking, ambas com padrão Binário). A nota usa a nota máxima configurada da atividade
como base; o ranking sempre usa sua própria base fixa de 100 pontos, totalmente independente da
nota — inclusive quando a atividade não tem nota nenhuma (Nota = Nenhuma, o padrão do
formulário), o ranking continua funcionando normalmente:
| Modo | Uma rodada vencida vale… | Uma rodada perdida |
|---|---|---|
| Binário (padrão) | A base cheia (nota da atividade, ou 100 pontos fixos no ranking) | Zero |
| Linear | Uma fração que diminui a cada palpite errado — em qualquer termo e na frase-mistério, contados juntos como um único conjunto | Zero |
Os termos não têm um valor de ponto próprio: todo palpite errado, seja em um termo ou na própria frase-mistério, consome o mesmo conjunto compartilhado de erros, e o tamanho desse conjunto determina a pontuação linear da rodada inteira:
max_errors = num_terms × (max_attempts_per_term − 1) + (max_attempts_final_guess − 1)
pontos (nota) = nota × (max_errors − erros_usados + 1) / (max_errors + 1)
pontos (ranking) = 100 × (max_errors − erros_usados + 1) / (max_errors + 1)
O modo linear não tem nenhuma tolerância: o primeiro palpite errado já reduz a pontuação. Uma
rodada sem nenhum erro continua sempre valendo exatamente a pontuação cheia, e a pontuação nunca
chega a zero numa vitória genuinamente concluída — ela tem um piso de base / (max_errors + 1)
mesmo no limite máximo de erros. Como max_errors depende das duas configurações de tentativas,
escolher Linear para a nota ou para o ranking exige que “Máximo de tentativas por termo” e
“Máximo de tentativas para a frase-mistério” sejam ambos um valor real, não ilimitado — o
formulário de configurações bloqueia o salvamento caso contrário.
Exemplo prático com 5 termos, 3 tentativas por termo, 3 tentativas para a frase-mistério
(max_errors = 5 × 2 + 2 = 12) — a coluna de nota assume uma nota máxima 100, mas a coluna de
ranking vale exatamente assim em qualquer atividade, mesmo sem nota nenhuma configurada:
| Erros | Nota (base 100) | Ranking (base 100, sempre) | Erros | Nota | Ranking |
|---|---|---|---|---|---|
| 0 | 100,00 | 100,00 | 7 | 46,15 | 46,15 |
| 1 | 92,31 | 92,31 | 8 | 38,46 | 38,46 |
| 2 | 84,62 | 84,62 | 9 | 30,77 | 30,77 |
| 3 | 76,92 | 76,92 | 10 | 23,08 | 23,08 |
| 4 | 69,23 | 69,23 | 11 | 15,38 | 15,38 |
| 5 | 61,54 | 61,54 | 12 | 7,69 | 7,69 |
| 6 | 53,85 | 53,85 | Não concluída | 0,00 | 0,00 |
Bônus de acerto antecipado: acertar a frase-mistério corretamente antes de resolver qualquer termo soma um bônus fixo de 10% em cima da pontuação base acima — 10% da nota da atividade, para a nota; 10% da base fixa de 100 (ou seja, sempre +10 pontos), para o ranking. Para a nota, isso tem um teto no máximo nominal da atividade — uma rodada perfeita já em 100% permanece em 100%. Para o ranking, não há teto — a mesma rodada perfeita tem seu total de ranking em 110, ultrapassando legitimamente a base nominal de 100, já que o ranking recompensa a dedução precoce eficiente além do que um valor de diário de notas consegue representar.
Combinar várias rodadas em uma nota final é uma configuração separada, Método de avaliação
(maior nota, média das notas, primeira tentativa, última tentativa, ou média sobre todas as
rodadas exigidas). Ela funciona da mesma forma independente de a pontuação por rodada acima ser
Binária ou Linear: ela só agrega o que cada rodada já registrou.
O ranking é a soma dos pontos de ranking de cada rodada finalizada de um estudante (SUM),
ordenada da maior para a menor; empates são desfeitos por menos tentativas usadas em média,
depois menos tempo gasto em média. Só aparece quando o professor habilita “Mostrar ranking”, e
nunca revela uma rodada ainda em andamento.
Só os 5 primeiros são mostrados — de propósito, não é um bug: tanto o widget de ranking no jogo quanto a página dedicada de ranking limitam a lista a 5 linhas, para evitar um ranking público de toda a turma. Um estudante em posição mais baixa ainda vê exatamente onde está: uma linha extra, separada por “…”, mostra sua posição e pontuação reais, sem expor a posição de ninguém abaixo do 5º lugar. Quem gerencia a atividade (editingteacher, manager) nunca aparece no ranking, mesmo que jogue a atividade — da mesma forma que suas próprias tentativas são excluídas do relatório de tentativas abaixo.
“Mostrar ranking” controla só a visibilidade, não a coleta de dados: os pontos de ranking são calculados e armazenados para toda rodada finalizada, independente de o ajuste estar ligado ou desligado no momento. Ativá-lo depois que estudantes já jogaram revela o total completo acumulado desde o início da atividade, não só os pontos ganhos a partir daquele momento — nada se perde, e nada precisa ser “recuperado” desligando e religando o ajuste.
Trava assim que há avaliação: no momento em que a atividade registra uma nota real para
qualquer estudante, Termos por rodada, Método de avaliação, Máximo de tentativas por termo,
Máximo de tentativas para a frase-mistério e Modo de pontuação da nota travam todos — da mesma
forma que o Moodle já trava o campo “Nota máxima” de uma atividade avaliada assim que notas reais
existem. Como o orçamento de erros da fórmula linear é uma função direta do número de termos e das
duas configurações de tentativas, mudar qualquer um deles depois que já existem pontuações reais
faria rodadas anteriores e posteriores valerem coisas diferentes; travá-los garante que toda
rodada já registrada permaneça internamente consistente durante toda a vida da atividade.
Modo de pontuação do ranking trava separadamente, assim que existe qualquer tentativa
finalizada — não espera uma nota real, porque os pontos de ranking já são calculados e gravados
em toda rodada terminada independente de Nota ou Mostrar ranking estarem ligados (ver acima).
Uma atividade sem nota nenhuma, só com ranking, já acumula histórico real desde a primeira rodada;
travar o modo de pontuação assim que esse histórico existe evita a mesma inconsistência de escala
que a trava acima evita para a nota.
Histórico de tentativas: cada estudante pode revisar suas próprias rodadas passadas — frase-mistério, termos resolvidos, tentativas usadas, tempo, pontuação da nota e (quando o ranking está ativado) pontos de ranking — numa página dedicada da barra de ferramentas. Quem gerencia a atividade também vê essa mesma página, incluindo as suas próprias tentativas caso já tenha jogado a atividade. Já o relatório para todos os estudantes vive numa página separada, visível só para quem gerencia: uma tabela com todas as tentativas de todos os estudantes, ordenável clicando em qualquer cabeçalho de coluna e filtrável para um único estudante. Assim como o ranking, esse relatório nunca inclui as próprias tentativas de um gestor.
Excluir tentativas reverte essas travas quando elas deixam de se aplicar. No relatório com
todos os estudantes, quem gerencia a atividade pode excluir tentativas de um estudante
individualmente ou em lote. A exclusão realmente limpa a nota daquele estudante em vez de deixar
um valor obsoleto para trás, então se todas as tentativas de todos os estudantes forem removidas,
Termos por rodada, Método de avaliação, as duas configurações de máximo de tentativas e
Modo de pontuação da nota destravam de novo exatamente como grade_item::has_grades() espera —
do mesmo jeito que aconteceria numa atividade nunca jogada. Modo de pontuação do ranking segue
a mesma lógica direto contra a tabela de tentativas, independente de a nota estar ligada.
🧪 Testes Automatizados
O PlayerCross inclui uma suíte PHPUnit cobrindo lógica de negócio, consultas ao repositório, web services e conformidade com a Privacy API, além de uma suíte Behat cobrindo o jogo, a integração com o PlayerHUD e os relatórios de ponta a ponta num navegador real. Todo push de CI executa a matriz completa (Moodle 4.5 → 5.x, PostgreSQL e MariaDB).
PHPUnit — Testes Centrais
| Arquivo de teste | Casos |
|---|---|
backup_restore_test.php |
8 |
cross_instance_security_test.php |
4 |
lib_grant_potential_test.php |
6 |
lib_reset_userdata_test.php |
4 |
lib_supports_test.php |
2 |
completion/custom_completion_test.php |
6 |
privacy/provider_test.php |
21 |
lib_update_grades_test.php |
2 |
mod_form_test.php |
4 |
| Subtotal | 57 |
Testes de Lógica de Negócio (tests/local/)
| Arquivo de teste | Casos |
|---|---|
ai_word_generator_test.php |
19 |
attempts_history_service_test.php |
21 |
gameplay_service_test.php |
16 |
hud_service_test.php |
27 |
intro_service_test.php |
5 |
puzzle_builder_test.php |
9 |
ranking_service_test.php |
9 |
round_presenter_test.php |
60 |
round_service_test.php |
67 |
view_page_service_test.php |
40 |
word_normalizer_test.php |
38 |
words_repository_test.php |
67 |
| Subtotal | 378 |
Testes de Web Services (tests/external/)
| Arquivo de teste | Casos |
|---|---|
count_eligible_theme_words_test.php |
5 |
count_eligible_words_test.php |
5 |
count_glossary_candidates_test.php |
5 |
end_round_test.php |
6 |
new_round_test.php |
5 |
reveal_hint_test.php |
8 |
start_round_test.php |
7 |
submit_term_guess_test.php |
8 |
submit_final_guess_test.php |
7 |
| Subtotal | 56 |
| Total Geral | 491 |
vendor/bin/phpunit --testsuite mod_playercross
Cobertura de linhas geral (moodle-coverage, PHPUnit + Xdebug): 90%.
Behat — Testes de Ponta a Ponta
| Arquivo de feature | Cenários |
|---|---|
mod_playercross_smoke.feature |
1 |
mod_playercross_gameplay.feature |
15 |
mod_playercross_playerhud.feature |
4 |
mod_playercross_reports.feature |
5 |
mod_playercross_settings.feature |
5 |
mod_playercross_toolbar.feature |
9 |
| Subtotal | 39 |
Detalhamento completo teste a teste e tabela de cobertura →
🔐 Segurança e Conformidade
- Controle de acesso baseado em capabilities (
mod/playercross:view,mod/playercross:addinstance,mod/playercross:managewords,mod/playercross:viewreports) - Proteção
require_sesskey()em todas as ações POST; chamadas AJAX são validadas pelo dispatchercore/ajaxdo Moodle - Aplicação no servidor dos limites de rodada e do intervalo, sempre recalculados a partir das configurações atuais
- O tempo esgotado da rodada é revalidado contra o próprio prazo do servidor, em vez de confiar apenas na contagem regressiva do cliente
- Validação do conjunto de caracteres do palpite — só letras Unicode são aceitas
- Palavras geradas por IA são tratadas como entrada não confiável: só termos de um único token, alfabéticos, dentro do intervalo de comprimento configurado são salvos, e entram pendentes de aprovação do professor
- O estado de sessão da rodada é isolado por instância de atividade e por usuário — um id de palavra ou chave de sessão de uma atividade nunca é aceito por outra
- Um palpite errado de termo ou de frase-mistério nunca vaza a palavra correta; a palavra-tema só é revelada quando a rodada realmente termina
- Compatível com a External API do Moodle
- API de Privacidade totalmente implementada (LGPD/GDPR)
🔒 Divulgação de Serviço de Terceiros
A geração de palavras por IA é opcional e vem desativada por padrão. Quando um professor a
usa, o tema da atividade (nunca dados de estudante ou registros de tentativa) é enviado através
do Central de IA (local_aihub) — usando a chave BYOK própria do usuário ou do site, se
o plugin estiver instalado — ou, como alternativa, através do subsistema de IA nativo do Moodle
(core_ai), que roteia para o provedor que o administrador do site configurou. O PlayerCross
nunca contata um provedor de IA diretamente; a requisição e sua divulgação/consentimento são
inteiramente de responsabilidade do local_aihub ou do core_ai. Se nenhum dos dois estiver
instalado ou configurado, a fonte de palavras por IA fica indisponível e todas as demais
funcionalidades continuam funcionando normalmente.
- Custo: Nenhum é exigido pelo próprio PlayerCross. Se usada, qualquer custo é o que o
provedor cobrar através de uma chave BYOK no
local_aihub, ou nenhum custo via um provedorcore_aigratuito/institucional que o administrador do site já tenha configurado. - Chaves de API / credenciais: Não são configuradas no PlayerCross. Obtenha e configure uma
chave pessoal ou do site dentro do Central de IA (
local_aihub), ou peça ao administrador do site para configurar um provedorcore_ai. - Credenciais de demonstração: Não aplicável — nenhuma credencial é exigida para instalar ou usar o PlayerCross; a geração por IA é totalmente opcional.
📄 Licença
Este projeto é licenciado sob a GNU General Public License v3 (GPLv3).
Copyright: 2026 Jean Lúcio