Tutorial de JavaScript para crear dos juegos de palabras
Frontend

Tutorial de JavaScript para crear dos juegos de palabras

6 October 2026 · 8 min de lectura
Home / Frontend / Tutorial de JavaScript para crear dos juegos de palabras
Categorías:

Introduccion a los juegos de palabras con JavaScript

Construir juegos de palabras con JavaScript vanilla constituye un excelente ejercicio para consolidar conceptos fundamentales de programacion web. La interaccion con el usuario, la actualizacion dinamica de la interfaz y la gestion de estado local permiten practicar de forma concreta la manipulacion del DOM, el manejo de eventos y el trabajo con arrays y objetos. En 2026 estas habilidades siguen siendo la base de cualquier interfaz interactiva, independientemente de los frameworks que se utilicen posteriormente.

Este articulo describe la implementacion de dos juegos: un juego de asociacion de palabras y un juego de estilo Jeopardy. Ambos se construyen con archivos HTML, CSS y JavaScript separados, sin dependencias externas. Se detalla la estructura de datos, la generacion dinamica de elementos, la logica de comprobacion de respuestas y el sistema de puntuacion. Ademas se incorporan consideraciones de accesibilidad y patrones recomendados para evitar errores comunes en la gestion de eventos.

El objetivo es proporcionar una base reutilizable que pueda adaptarse a otros tipos de quizzes o juegos de palabras, como Hangman o variantes de Wordle, manteniendo el codigo claro y modular.

Estructura basica del proyecto

Cada juego se organiza en tres archivos principales. El HTML contiene el contenedor donde se generara el contenido dinamico y un elemento para mostrar la puntuacion. El CSS se encarga de la presentacion visual mediante Flexbox o Grid. El JavaScript gestiona la logica y la actualizacion de la interfaz.

<!DOCTYPE html>
<html lang="es">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Juego de palabras</title>
        <link rel="stylesheet" href="styles.css" />
    </head>
    <body>
        <div id="score-display">0</div>
        <div id="questions"></div>
        <script src="app.js"></script>
    </body>
</html>

Esta estructura minima permite centrar la atencion en la logica de JavaScript. Los estilos pueden ampliarse posteriormente sin modificar el comportamiento del juego.

Juego de asociacion de palabras

En este juego se presentan tres palabras de pista y el jugador debe elegir cual de dos opciones esta mas relacionada. Cada respuesta correcta suma un punto y cada respuesta incorrecta resta un punto. Una vez seleccionada una opcion, los botones de esa pregunta se deshabilitan para evitar clics repetidos.

La informacion se almacena en un array de objetos. Cada objeto contiene las palabras de pista, las opciones y el indice de la respuesta correcta.

const questions = [
    {
        quiz: ["valor", "estimar", "evaluar"],
        options: ["jurado", "valorar"],
        correct: 1,
    },
    {
        quiz: ["codigo", "programa", "algoritmo"],
        options: ["compilar", "depurar"],
        correct: 0,
    },
];

El indice de la respuesta correcta se define de forma explicita para facilitar la comprobacion posterior.

Generacion dinamica de las preguntas

La funcion principal recorre el array de preguntas y crea un contenedor para cada una. Dentro de ese contenedor se anaden las palabras de pista, un separador visual y los botones de opciones.

const scoreDisplay = document.getElementById("score-display");
const questionDisplay = document.getElementById("questions");
let score = 0;

function populateQuestions() {
    questions.forEach((question, index) => {
        const questionBox = document.createElement("div");
        questionBox.classList.add("question-box");

        question.quiz.forEach((word) => {
            const p = document.createElement("p");
            p.textContent = word;
            questionBox.appendChild(p);
        });

        const buttonsContainer = document.createElement("div");
        buttonsContainer.classList.add("question-buttons");

        question.options.forEach((option, optionIndex) => {
            const button = document.createElement("button");
            button.textContent = option;
            button.classList.add("question-button");
            button.addEventListener("click", () => {
                checkAnswer(optionIndex, question.correct, button, questionBox);
            });
            buttonsContainer.appendChild(button);
        });

        questionBox.appendChild(buttonsContainer);
        questionDisplay.appendChild(questionBox);
    });
}

populateQuestions();

Este enfoque mantiene el HTML limpio y permite anadir o modificar preguntas simplemente editando el array de datos.

Logica de comprobacion y feedback

Cuando el usuario hace clic en un boton se compara el indice seleccionado con el indice correcto. Se actualiza la puntuacion, se muestra un mensaje de feedback y se deshabilitan todos los botones de esa pregunta.

function checkAnswer(selectedIndex, correctIndex, button, questionBox) {
    const isCorrect = selectedIndex === correctIndex;
    score += isCorrect ? 1 : -1;
    scoreDisplay.textContent = score;

    const feedback = document.createElement("div");
    feedback.textContent = isCorrect ? "Correcto" : "Incorrecto";
    feedback.classList.add(isCorrect ? "correct" : "wrong");
    questionBox.appendChild(feedback);

    const buttons = questionBox.querySelectorAll("button");
    buttons.forEach((btn) => (btn.disabled = true));
}

El feedback visual inmediato ayuda al jugador a comprender el resultado. El uso de clases CSS permite aplicar estilos distintos a las respuestas correctas e incorrectas sin modificar el JavaScript.

Juego de estilo Jeopardy

El segundo juego organiza las preguntas por categorias y niveles de dificultad. Cada categoria se presenta en una columna. Al hacer clic en una tarjeta se revela la pregunta y dos opciones de respuesta. La puntuacion se incrementa segun el valor de la tarjeta si la respuesta es correcta.

La estructura de datos utiliza un array de categorias, cada una con su genero y un array de preguntas.

const categories = [
    {
        genre: "Ciencia",
        questions: [
            {
                question: "Cual es el planeta mas cercano al Sol?",
                answers: ["Mercurio", "Venus"],
                correct: "Mercurio",
                value: 100,
            },
            {
                question: "Cual es la formula del agua?",
                answers: ["H2O", "CO2"],
                correct: "H2O",
                value: 200,
            },
        ],
    },
];

Esta organizacion facilita la generacion de columnas independientes y la asignacion de valores de puntuacion.

Creacion de columnas y tarjetas

Se recorre el array de categorias y se crea una columna para cada una. Dentro de cada columna se generan las tarjetas correspondientes a las preguntas, almacenando la informacion necesaria en atributos data.

function addCategory(category) {
    const column = document.createElement("div");
    column.classList.add("column");

    const title = document.createElement("div");
    title.classList.add("genre-title");
    title.textContent = category.genre;
    column.appendChild(title);

    category.questions.forEach((q) => {
        const card = document.createElement("div");
        card.classList.add("card");
        card.textContent = q.value;
        card.dataset.question = q.question;
        card.dataset.correct = q.correct;
        card.dataset.answer1 = q.answers[0];
        card.dataset.answer2 = q.answers[1];
        card.dataset.value = q.value;
        card.addEventListener("click", flipCard);
        column.appendChild(card);
    });

    document.getElementById("game").appendChild(column);
}

categories.forEach(addCategory);

Los atributos data permiten recuperar la informacion de la pregunta sin necesidad de mantener referencias adicionales en variables globales.

Volteo de tarjetas y seleccion de respuesta

Al hacer clic en una tarjeta se limpia su contenido y se muestran la pregunta y los botones de respuesta. Se deshabilitan temporalmente las demas tarjetas para evitar que el usuario abra varias a la vez.

function flipCard(e) {
    const card = e.currentTarget;
    card.innerHTML = "";
    card.removeEventListener("click", flipCard);

    const questionText = document.createElement("div");
    questionText.textContent = card.dataset.question;
    card.appendChild(questionText);

    const btn1 = document.createElement("button");
    btn1.textContent = card.dataset.answer1;
    btn1.addEventListener("click", () => getResult(btn1, card));
    card.appendChild(btn1);

    const btn2 = document.createElement("button");
    btn2.textContent = card.dataset.answer2;
    btn2.addEventListener("click", () => getResult(btn2, card));
    card.appendChild(btn2);

    document.querySelectorAll(".card").forEach((c) => {
        if (c !== card) c.style.pointerEvents = "none";
    });
}

Esta tecnica garantiza que solo una pregunta este activa en cada momento.

Evaluacion de la respuesta y actualizacion de puntuacion

La funcion de resultado compara el texto del boton pulsado con la respuesta correcta almacenada en el atributo data. Si coincide se suman los puntos correspondientes; en caso contrario la puntuacion permanece igual o se puede aplicar una penalizacion.

function getResult(button, card) {
    const isCorrect = button.textContent === card.dataset.correct;
    if (isCorrect) {
        score += parseInt(card.dataset.value, 10);
        scoreDisplay.textContent = score;
        card.classList.add("correct");
    } else {
        card.classList.add("wrong");
    }

    setTimeout(() => {
        card.innerHTML = isCorrect ? card.dataset.value : "0";
        document.querySelectorAll(".card").forEach((c) => {
            c.style.pointerEvents = "auto";
        });
    }, 800);
}

El retardo breve permite que el usuario vea el feedback antes de que la tarjeta muestre el valor final.

Gestion del estado y prevencion de errores

En ambos juegos es importante evitar que el usuario interactue con elementos ya respondidos. Deshabilitar botones o eliminar listeners de clic son las tecnicas mas directas. Tambien conviene validar que los indices y los atributos data existan antes de utilizarlos, especialmente si los datos se cargan de forma asincrona en futuras extensiones.

El uso de textContent en lugar de innerHTML para el contenido generado por el usuario reduce el riesgo de inyeccion de codigo, aunque en estos ejemplos el contenido proviene de arrays controlados.

Estilos basicos y mejora de la experiencia

Los estilos CSS se encargan de organizar las columnas con Flexbox, de dar forma a las tarjetas y de aplicar colores de feedback. Un ejemplo minimo para las tarjetas es el siguiente.

.column {
    display: flex;
    flex-direction: column;
    margin: 0.5rem;
}

.card {
    border: 1px solid #ccc;
    padding: 1rem;
    margin: 0.25rem;
    cursor: pointer;
    text-align: center;
}

.card.correct {
    background-color: #d4edda;
}

.card.wrong {
    background-color: #f8d7da;
}

Anadir transiciones suaves en la propiedad background-color mejora la percepcion de respuesta sin complicar el codigo.

Consideraciones de accesibilidad

Los botones deben tener un texto descriptivo y un contraste suficiente. Cuando se deshabilita un boton es recomendable actualizar tambien el atributo aria-disabled si se utiliza. El feedback visual debe acompanarse de un mensaje de texto para usuarios que dependan de lectores de pantalla. En juegos mas complejos se puede anadir un anuncio en vivo mediante aria-live para comunicar cambios de puntuacion.

Extensiones posibles

La arquitectura presentada se adapta facilmente a otros juegos de palabras. Para un Hangman se puede mantener un array de letras adivinadas y actualizar un elemento de visualizacion de la palabra en cada intento. Para una variante de Wordle se anade una cuadricula de intentos y una logica de comparacion de posiciones. En todos los casos la separacion entre datos, logica y presentacion facilita las modificaciones posteriores.

Tambien es posible cargar las preguntas desde un archivo JSON externo mediante fetch, lo que permite actualizar el contenido sin modificar el codigo JavaScript.

Conclusiones

La construccion de juegos de palabras con JavaScript vanilla ofrece una forma practica y motivadora de aplicar conceptos de manipulacion del DOM, manejo de eventos y gestion de estado. Los dos ejemplos desarrollados demuestran como estructurar los datos, generar interfaces dinamicas y proporcionar feedback inmediato al usuario.

Estos patrones son transferibles a otros tipos de aplicaciones interactivas. Dominar la creacion de elementos, la asignacion de listeners y la actualizacion selectiva de la interfaz constituye una base solida para proyectos mas complejos, tanto con JavaScript puro como con frameworks modernos. El codigo resultante es claro, modular y facil de extender segun las necesidades de cada juego.