223 lines
7.1 KiB
JavaScript
223 lines
7.1 KiB
JavaScript
'use strict';
|
|
|
|
// Lista completa con país y siglas según ISO 3166-1 alpha-2
|
|
const countryList = [
|
|
{ name: "España", code: "ES" }, { name: "Francia", code: "FR" }, { name: "Alemania", code: "DE" }, { name: "Italia", code: "IT" },
|
|
{ name: "Portugal", code: "PT" }, { name: "Reino Unido", code: "GB" }, { name: "Estados Unidos", code: "US" }, { name: "Canadá", code: "CA" },
|
|
{ name: "México", code: "MX" }, { name: "Brasil", code: "BR" }, { name: "Argentina", code: "AR" }, { name: "Chile", code: "CL" },
|
|
{ name: "Japón", code: "JP" }, { name: "China", code: "CN" }, { name: "Australia", code: "AU" }, { name: "Rusia", code: "RU" },
|
|
{ name: "Sudáfrica", code: "ZA" }, { name: "Nueva Zelanda", code: "NZ" }, { name: "India", code: "IN" }, { name: "Egipto", code: "EG" },
|
|
{ name: "Grecia", code: "GR" }, { name: "Turquía", code: "TR" }, { name: "Ucrania", code: "UA" }, { name: "Suecia", code: "SE" },
|
|
{ name: "Noruega", code: "NO" }, { name: "Dinamarca", code: "DK" }, { name: "Finlandia", code: "FI" }, { name: "Irlanda", code: "IE" },
|
|
{ name: "Bélgica", code: "BE" }, { name: "Polonia", code: "PL" }, { name: "Suiza", code: "CH" }, { name: "Países Bajos", code: "NL" }
|
|
];
|
|
|
|
function getFlagEmoji(code) {
|
|
// Las banderas se generan a partir de letras usando unicode, no por siglas textuales
|
|
// Solo funcionan para países con código alpha-2 y script latino
|
|
if (!code || code.length !== 2) return '';
|
|
return String.fromCodePoint(
|
|
...code.toUpperCase().split('').map(c => 0x1F1E6 + c.charCodeAt(0) - 65)
|
|
);
|
|
}
|
|
|
|
// Elegir N países aleatorios distintos con bandera, sin mutar la lista original
|
|
function pickRandomCountries(list, n) {
|
|
const pool = list.slice(); // copia de seguridad
|
|
const chosen = [];
|
|
const used = new Set();
|
|
while (chosen.length < n && pool.length > 0) {
|
|
const idx = Math.floor(Math.random() * pool.length);
|
|
const c = pool[idx];
|
|
const flag = getFlagEmoji(c.code);
|
|
if (flag && !used.has(c.code)) {
|
|
chosen.push({ name: c.name, code: c.code, flag });
|
|
used.add(c.code);
|
|
}
|
|
// Eliminar del pool para evitar repetir
|
|
pool.splice(idx, 1);
|
|
}
|
|
return chosen;
|
|
}
|
|
|
|
// Referencias DOM
|
|
const flagsDiv = document.getElementById('flags');
|
|
const countriesDiv = document.getElementById('countries');
|
|
const statusDiv = document.getElementById('status');
|
|
const scoreSpan = document.getElementById('score-value');
|
|
const scoreTotal = document.getElementById('score-total');
|
|
const restartBtn = document.getElementById('restart-btn');
|
|
const pairsSelect = document.getElementById('pairs-count');
|
|
|
|
// Estado
|
|
let pairs = [];
|
|
let flags = [];
|
|
let countries = [];
|
|
let selectedFlag = null;
|
|
let selectedCountry = null;
|
|
let score = 0;
|
|
let totalPairs = 12;
|
|
|
|
// Utilidades
|
|
function shuffle(arr) {
|
|
for (let i = arr.length - 1; i > 0; i--) {
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
}
|
|
}
|
|
function setStatus(msg) {
|
|
statusDiv.textContent = msg;
|
|
}
|
|
|
|
// Renderizado
|
|
function renderFlags() {
|
|
// Limpieza segura
|
|
flagsDiv.textContent = '';
|
|
flags.forEach((p, i) => {
|
|
const d = document.createElement('button');
|
|
d.type = 'button';
|
|
d.className = 'flag';
|
|
d.textContent = p.flag; // seguro (caracter unicode)
|
|
d.setAttribute('tabindex', '0');
|
|
d.setAttribute('role', 'listitem');
|
|
d.setAttribute('aria-label', `Bandera de ${p.name}`);
|
|
d.setAttribute('aria-disabled', p.matched ? 'true' : 'false');
|
|
d.setAttribute('aria-selected', selectedFlag === i ? 'true' : 'false');
|
|
|
|
if (p.matched) d.classList.add('matched');
|
|
if (selectedFlag === i) d.classList.add('selected');
|
|
|
|
d.addEventListener('click', () => selectFlag(i));
|
|
d.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
e.preventDefault();
|
|
selectFlag(i);
|
|
}
|
|
});
|
|
|
|
flagsDiv.appendChild(d);
|
|
});
|
|
}
|
|
|
|
function renderCountries() {
|
|
countriesDiv.textContent = '';
|
|
countries.forEach((p, i) => {
|
|
const d = document.createElement('button');
|
|
d.type = 'button';
|
|
d.className = 'country';
|
|
d.textContent = p.name; // seguro
|
|
d.setAttribute('tabindex', '0');
|
|
d.setAttribute('role', 'listitem');
|
|
d.setAttribute('aria-label', `País ${p.name}`);
|
|
d.setAttribute('aria-disabled', p.matched ? 'true' : 'false');
|
|
d.setAttribute('aria-selected', selectedCountry === i ? 'true' : 'false');
|
|
|
|
if (p.matched) d.classList.add('matched');
|
|
if (selectedCountry === i) d.classList.add('selected');
|
|
|
|
d.addEventListener('click', () => selectCountry(i));
|
|
d.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
e.preventDefault();
|
|
selectCountry(i);
|
|
}
|
|
});
|
|
|
|
countriesDiv.appendChild(d);
|
|
});
|
|
}
|
|
|
|
// Lógica selección
|
|
function selectFlag(i) {
|
|
if (flags[i].matched) return;
|
|
selectedFlag = i;
|
|
renderFlags();
|
|
if (selectedCountry !== null) checkMatch();
|
|
}
|
|
|
|
function selectCountry(i) {
|
|
if (countries[i].matched) return;
|
|
selectedCountry = i;
|
|
renderCountries();
|
|
if (selectedFlag !== null) checkMatch();
|
|
}
|
|
|
|
function checkMatch() {
|
|
if (selectedFlag === null || selectedCountry === null) return;
|
|
|
|
const flagObj = flags[selectedFlag];
|
|
const countryObj = countries[selectedCountry];
|
|
|
|
if (!flagObj || !countryObj) return;
|
|
|
|
if (flagObj.code === countryObj.code) {
|
|
flags[selectedFlag].matched = true;
|
|
countries[selectedCountry].matched = true;
|
|
score++;
|
|
scoreSpan.textContent = String(score);
|
|
setStatus('¡Correcto!');
|
|
renderFlags();
|
|
renderCountries();
|
|
if (score === pairs.length) {
|
|
setStatus('¡Has emparejado todas las banderas! 🎉');
|
|
}
|
|
} else {
|
|
setStatus('No es correcto, intenta otra vez.');
|
|
// Reset de selección tras breve pausa
|
|
setTimeout(() => {
|
|
setStatus('');
|
|
selectedFlag = null;
|
|
selectedCountry = null;
|
|
renderFlags();
|
|
renderCountries();
|
|
}, 850);
|
|
return;
|
|
}
|
|
|
|
// Reset selección tras acierto
|
|
selectedFlag = null;
|
|
selectedCountry = null;
|
|
}
|
|
|
|
// Inicio/reinicio
|
|
function startGame() {
|
|
// Leer número de parejas desde selector, con límites
|
|
const desired = pairsSelect && Number(pairsSelect.value) ? Number(pairsSelect.value) : 12;
|
|
totalPairs = Math.max(4, Math.min(desired, countryList.length));
|
|
|
|
const fullList = countryList.slice(); // copia
|
|
pairs = pickRandomCountries(fullList, totalPairs);
|
|
// Si no se pudieron escoger las deseadas (por restricciones), ajustar total
|
|
if (pairs.length < totalPairs) {
|
|
totalPairs = pairs.length;
|
|
}
|
|
|
|
flags = pairs.map(o => ({ ...o }));
|
|
countries = pairs.map(o => ({ ...o }));
|
|
|
|
shuffle(flags);
|
|
shuffle(countries);
|
|
|
|
score = 0;
|
|
scoreSpan.textContent = String(score);
|
|
scoreTotal.textContent = String(pairs.length);
|
|
selectedFlag = null;
|
|
selectedCountry = null;
|
|
|
|
renderFlags();
|
|
renderCountries();
|
|
setStatus('Empareja todas las banderas con su país');
|
|
|
|
// Enfocar primera bandera para accesibilidad
|
|
const firstFlag = flagsDiv.querySelector('.flag');
|
|
if (firstFlag) firstFlag.focus();
|
|
}
|
|
|
|
// Listeners (evitar handlers inline)
|
|
restartBtn.addEventListener('click', startGame);
|
|
if (pairsSelect) {
|
|
pairsSelect.addEventListener('change', startGame);
|
|
}
|
|
|
|
// Init
|
|
startGame(); |