const SUBJECTS=[ {id:"lengua",name:"Lengua",games:[ {id:"lectura",glyph:"Aa",name:"Comprensión lectora",area:"Lee y responde",t:0}, {id:"alfabetico",glyph:"A→Z",name:"Orden alfabético",area:"Como en el diccionario",t:1}, {id:"sinonimos",glyph:"=≠",name:"Sinónimos y antónimos",area:"Lo mismo o lo contrario",t:1}]}, {id:"mates",name:"Matemáticas",games:[ {id:"posicion",glyph:"UM",name:"Valor de posición",area:"Números hasta 9999",t:1}, {id:"tablas",glyph:"×",name:"Las tablas",area:"Multiplicar del 2 al 10",t:1}, {id:"problemas",glyph:"?",name:"Problemas",area:"Sumar, restar, multiplicar y repartir",t:2}, {id:"reloj",glyph:"🕒",name:"¿Qué hora es?",area:"Medida del tiempo",t:3}]}, {id:"ciencias",name:"Ciencias de la Naturaleza",games:[ {id:"vertebrados",glyph:"🦴",name:"Vertebrados",area:"¿Tiene columna vertebral?",t:2}, {id:"alimentacion",glyph:"🌿",name:"¿Qué come?",area:"Herbívoro, carnívoro u omnívoro",t:2}]}, {id:"english",name:"English",games:[ {id:"vocabulary",glyph:"En",name:"Vocabulary",area:"What is it?",t:0}]} ]; const HELP={lectura:"Lee el texto con atención y responde.",alfabetico:"¿Qué palabra aparece antes en el diccionario?",sinonimos:"Busca la palabra que se pide.", tablas:"Calcula y toca el resultado.",posicion:"¿Cuánto vale la cifra marcada?",reloj:"Mira las agujas y toca la hora.",problemas:"Lee el problema y toca la solución.", alimentacion:"¿De qué se alimenta este animal?",vertebrados:"¿Es vertebrado o invertebrado?",vocabulary:"Look at the picture and choose the word."}; /* ---------- Contenidos ---------- */ const LECTURAS=[ {t:"Rita y la tortuga",x:"Rita es una capibara que vive junto a un río muy tranquilo. Por las mañanas se baña con sus hermanos y por las tardes come hierba fresca en la orilla. Un día encontró una tortuga perdida y la acompañó hasta su charca. Desde entonces, la tortuga la visita cada domingo.", q:[["¿Dónde vive Rita?","Junto a un río","En una charca","En el bosque"],["¿Cuándo la visita la tortuga?","Cada domingo","Cada mañana","Los lunes"]]}, {t:"Excursión a la granja",x:"El martes, la clase de 3.º fue de excursión a una granja. Primero ordeñaron una vaca y después dieron de comer a las gallinas. A la hora del almuerzo empezó a llover, así que comieron dentro del granero. Al volver, Pablo dijo que había sido el mejor día del curso.", q:[["¿Qué hicieron primero?","Ordeñar una vaca","Dar de comer a las gallinas","Comer en el granero"],["¿Por qué comieron en el granero?","Porque empezó a llover","Porque hacía mucho calor","Porque estaba más cerca"]]}, {t:"Los jueves de Lucía",x:"Lucía va a la biblioteca del barrio todos los jueves. Le encantan los libros de misterio, aunque su hermano prefiere los cómics. La bibliotecaria, Carmen, siempre le guarda las novedades. Este jueves se llevó un libro sobre un faro que se apagaba sin explicación.", q:[["¿Qué libros prefiere Lucía?","Los de misterio","Los cómics","Los de animales"],["¿Quién es Carmen?","La bibliotecaria","Su hermana","Su profesora"]]}, {t:"El girasol de Mario",x:"Mario plantó una semilla de girasol en un vaso de yogur. La regaba cada dos días y la ponía junto a la ventana para que le diera el sol. A las dos semanas salió un tallo verde. En primavera la trasplantó al jardín y creció más alta que él.", q:[["¿Dónde plantó Mario la semilla al principio?","En un vaso de yogur","En el jardín","En una maceta grande"],["¿Por qué la ponía junto a la ventana?","Para que le diera el sol","Para que no pasara frío","Para verla desde la cama"]]}, {t:"El partido",x:"El equipo del colegio perdía dos a cero en el descanso. La entrenadora les pidió que se pasaran más el balón. En la segunda parte, Aisha marcó dos goles y Leo el tercero. Ganaron tres a dos y lo celebraron con un gran aplauso.", q:[["¿Cuántos goles marcó Aisha?","Dos","Uno","Tres"],["¿Qué consejo les dio la entrenadora?","Que se pasaran más el balón","Que corrieran más rápido","Que defendieran la portería"]]}, {t:"El abuelo panadero",x:"El abuelo de Hugo es panadero. Se levanta a las cuatro de la mañana para que el pan esté listo antes de que abran las tiendas. Un sábado, Hugo le ayudó y aprendió que la masa necesita reposar para crecer. Esa tarde, en casa, hizo su primer pan.", q:[["¿Por qué se levanta tan pronto el abuelo?","Para tener el pan listo a tiempo","Porque no puede dormir","Para llevar a Hugo al colegio"],["¿Qué aprendió Hugo?","Que la masa necesita reposar","Que el pan se hace en diez minutos","Que hay que echar mucha sal"]]} ]; const PALABRAS=["árbol","balón","barco","bota","búho","caballo","cama","camión","casa","cebra","chocolate","cielo","dado","delfín","elefante","escuela","fresa","foca","gato","globo","gorra","helado","hormiga","isla","jarra","jirafa","koala","león","libro","luna","llave","mano","mesa","mono","nube","naranja","ñu","oso","oveja","pato","pera","perro","piña","queso","rana","ratón","regla","sol","silla","tigre","tomate","uva","vaca","vela","yate","zapato","zorro"]; const SIN=[["rápido","veloz"],["bonito","hermoso"],["empezar","comenzar"],["contento","alegre"],["enorme","gigante"],["terminar","acabar"],["mirar","observar"],["miedo","temor"],["lugar","sitio"],["delgado","flaco"],["cansado","agotado"],["hablar","conversar"],["coger","agarrar"],["regalo","obsequio"]]; const ANT=[["ganar","perder"],["ancho","estrecho"],["recordar","olvidar"],["valiente","cobarde"],["comprar","vender"],["entrar","salir"],["lleno","vacío"],["limpio","sucio"],["subir","bajar"],["encender","apagar"],["alegre","triste"],["temprano","tarde"],["fácil","difícil"]]; const DIETA=[["vaca","🐮","herbívoro"],["conejo","🐰","herbívoro"],["caballo","🐴","herbívoro"],["jirafa","🦒","herbívoro"],["oveja","🐑","herbívoro"],["cebra","🦓","herbívoro"],["koala","🐨","herbívoro"], ["león","🦁","carnívoro"],["tiburón","🦈","carnívoro"],["águila","🦅","carnívoro"],["lobo","🐺","carnívoro"],["cocodrilo","🐊","carnívoro"],["búho","🦉","carnívoro"],["tigre","🐯","carnívoro"], ["oso","🐻","omnívoro"],["cerdo","🐷","omnívoro"],["gallina","🐔","omnívoro"],["ratón","🐭","omnívoro"],["mapache","🦝","omnívoro"],["jabalí","🐗","omnívoro"]]; const VERT=[["perro","🐶",1],["pez","🐟",1],["rana","🐸",1],["serpiente","🐍",1],["águila","🦅",1],["tortuga","🐢",1],["ballena","🐋",1],["murciélago","🦇",1], ["mariposa","🦋",0],["araña","🕷️",0],["caracol","🐌",0],["pulpo","🐙",0],["medusa","🪼",0],["abeja","🐝",0],["cangrejo","🦀",0],["hormiga","🐜",0],["lombriz","🪱",0],["mariquita","🐞",0]]; const VOCAB=[["apple","🍎"],["banana","🍌"],["dog","🐶"],["cat","🐱"],["house","🏠"],["book","📖"],["pencil","✏️"],["chair","🪑"],["sun","☀️"],["car","🚗"],["bird","🐦"],["fish","🐟"],["horse","🐴"],["bread","🍞"],["milk","🥛"],["cheese","🧀"],["tree","🌳"],["flower","🌸"],["ball","⚽"],["bike","🚲"],["train","🚂"],["rain","🌧️"],["snow","❄️"],["cake","🎂"],["shoe","👟"],["hat","🎩"],["egg","🥚"],["moon","🌙"]]; const $=s=>document.querySelector(s); const board=$("#board"); const rand=(a,b)=>a+Math.floor(Math.random()*(b-a+1)); const pick=a=>a[rand(0,a.length-1)]; const shuffle=a=>{a=[...a];for(let i=a.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[a[i],a[j]]=[a[j],a[i]]}return a}; const esc=s=>String(s).replace(/[&<>"]/g,c=>({"&":"&","<":"<",">":">",'"':"""}[c])); const ALL=SUBJECTS.flatMap(s=>s.games.map(g=>({...g,subject:s}))); let current="lectura", soundOn=true, actx=null, trim=0; const TRIM=["Todo el curso","1.er trimestre","2.º trimestre","3.er trimestre"]; function tone(ok){ if(!soundOn) return; try{ actx=actx||new (window.AudioContext||window.webkitAudioContext)(); (ok?[660,880]:[220]).forEach((f,i)=>{const o=actx.createOscillator(),g=actx.createGain();o.type="sine";o.frequency.value=f; const t=actx.currentTime+i*.11;g.gain.setValueAtTime(.0001,t);g.gain.exponentialRampToValueAtTime(.18,t+.02);g.gain.exponentialRampToValueAtTime(.0001,t+.25); o.connect(g).connect(actx.destination);o.start(t);o.stop(t+.27)}); }catch(e){} } function shake(el){el.classList.remove("shake");void el.offsetWidth;el.classList.add("shake")} function renderNav(){ $("#trims").innerHTML=TRIM.map((t,k)=>``).join(""); document.querySelectorAll("#trims button").forEach(b=>b.onclick=()=>{trim=+b.dataset.t;renderNav()}); $("#games").innerHTML=SUBJECTS.map(s=>{const gs=s.games.filter(g=>!trim||g.t===0||g.t===trim).sort((a,b)=>a.t-b.t); return `
Próximamente
`}${esc(l.t)}${esc(l.x)}
${esc(ask)}
`,answer:ok,opts:shuffle([ok,...bad]),txt:true}; } if(id==="alfabetico"){ let w; if(Math.random()<.4){const l=pick("bcmpst");const same=PALABRAS.filter(x=>x[0]===l);w=shuffle(same).slice(0,3); if(w.length<3) w=shuffle(PALABRAS).slice(0,3);} else w=shuffle(PALABRAS).slice(0,3); const first=[...w].sort((a,b)=>a.localeCompare(b,"es"))[0]; const sameFirst=w.every(x=>x[0]===w[0][0]); return {scene:`¿Qué palabra va primero en el diccionario?
`,answer:first,opts:w,txt:true, why:sameFirst?"Empiezan igual: mira la segunda letra.":"Fíjate en la primera letra."}; } if(id==="sinonimos"){ const syn=Math.random()<.5, list=syn?SIN:ANT; const p=pick(list.filter(x=>!used.has(x[0]))); used.add(p[0]); const [a,b]=Math.random()<.5?p:[p[1],p[0]]; const other=syn?ANT:SIN; const all=[...SIN,...ANT], rel=new Set([a,b]); for(let k=0;k<2;k++) all.forEach(x=>{if(rel.has(x[0])||rel.has(x[1])){rel.add(x[0]);rel.add(x[1])}}); const dis=shuffle(all.flat().filter(x=>!rel.has(x))).slice(0,2); return {scene:`¿Qué palabra significa ${syn?"lo mismo":"lo contrario"} que ${esc(a)}?
`,answer:b,opts:shuffle([b,...dis]),txt:true, why:syn?`Son sinónimos: ${a} y ${b}.`:`Son antónimos: ${a} y ${b}.`}; } if(id==="tablas"){ const a=rand(2,10),b=rand(1,10),r=a*b; return {scene:`${a} × ${b} = ?
`,answer:String(r),opts:numOpts(r,[a*(b+1),a*(b-1),(a+1)*b],1)}; } if(id==="posicion"){ const ds=shuffle([1,2,3,4,5,6,7,8,9,0]); if(ds[0]===0)[ds[0],ds[1]]=[ds[1],ds[0]]; const n=ds.slice(0,4), pos=rand(0,3), d=n[pos]===0?(n[pos]=pick([1,2,3,4,5,6,7,8,9].filter(x=>!n.includes(x))),n[pos]):n[pos]; const val=d*10**(3-pos); const names=["unidades de millar","centenas","decenas","unidades"]; const num=n.map((x,i)=>i===pos?`${x}`:x).join(""); const s=new Set([val]); [d,d*10**(4-pos),d*10**Math.max(0,2-pos)].forEach(x=>{if(s.size<3&&x!==val)s.add(x)}); numOpts(val).forEach(x=>{if(s.size<3)s.add(+x)}); return {scene:`${num}
¿Cuánto vale el ${d}?
`,answer:String(val),opts:shuffle([...s].map(String)), why:`El ${d} está en las ${names[pos]}: vale ${val}.`}; } if(id==="reloj"){ const h=rand(1,12), m=pick([0,0,15,30,45,15,30,45,5,10,20,25,35,40,50,55]); const ok=horaTxt(h,m), s=new Set([ok]); const swap=Math.round(m/5)%12; const sh=swap===0?12:swap; [horaTxt(h%12+1,m),horaTxt(sh,(h%12)*5),horaTxt(h===1?12:h-1,m),horaTxt(h,(m+30)%60)].forEach(x=>{if(s.size<3)s.add(x)}); return {scene:clockSvg(h,m)+`¿Qué hora es?
`,answer:ok,opts:shuffle([...s]),txt:true, why:"La aguja corta marca la hora y la larga, los minutos."}; } if(id==="problemas"){ const k=rand(0,4); if(k===0){const a=rand(120,480),b=rand(25,95),r=a+b; return {scene:`Ana tenía ${a} cromos y su tío le regaló ${b} más. ¿Cuántos cromos tiene ahora?
`,answer:String(r),opts:numOpts(r,[a-b,r+10]),why:`${a} + ${b} = ${r}.`};} if(k===1){const a=rand(300,900),b=rand(45,250),r=a-b; return {scene:`En el colegio hay ${a} alumnos. Hoy ${b} se han ido de excursión. ¿Cuántos se han quedado en el colegio?
`,answer:String(r),opts:numOpts(r,[a+b,r-10]),why:`${a} − ${b} = ${r}.`};} if(k===2){const a=rand(3,9),b=pick([6,8,10,12]),r=a*b; return {scene:`Compramos ${a} cajas de huevos. Cada caja trae ${b} huevos. ¿Cuántos huevos tenemos?
`,answer:String(r),opts:numOpts(r,[a+b,r-a]),why:`${a} × ${b} = ${r}.`};} if(k===3){const b=rand(2,6),r=rand(3,9),a=b*r; return {scene:`Reparto ${a} caramelos entre ${b} amigos a partes iguales. ¿Cuántos caramelos le tocan a cada uno?
`,answer:String(r),opts:numOpts(r,[a-b,r+b]),why:`${a} : ${b} = ${r}.`};} const p=rand(2,4),z=rand(1,2),n=rand(2,3),r=n*p+z; return {scene:`Un bocadillo cuesta ${p} € y un zumo ${z} €. Compramos ${n} bocadillos y un zumo. ¿Cuánto pagamos?
`,answer:String(r),opts:numOpts(r,[p+z,n*(p+z)],1),why:`${n} × ${p} = ${n*p} €; ${n*p} + ${z} = ${r} €.`}; } if(id==="alimentacion"){ const [n,e,c]=pick(DIETA.filter(x=>!used.has(x[0]))); used.add(n); const why={herbívoro:"Come solo plantas.",carnívoro:"Come otros animales.",omnívoro:"Come plantas y animales."}[c]; return {scene:`${n==="águila"?"El":n.match(/^(vaca|jirafa|oveja|cebra|rana|gallina|ballena|tortuga)$/)?"La":"El"} ${esc(n)} es…
`,answer:c,opts:["herbívoro","carnívoro","omnívoro"],txt:true,why:`${n[0].toUpperCase()+n.slice(1)}: ${why.toLowerCase()}`}; } if(id==="vertebrados"){ const [n,e,v]=pick(VERT.filter(x=>!used.has(x[0]))); used.add(n); return {scene:`${esc(n[0].toUpperCase()+n.slice(1))}
`,answer:v?"vertebrado":"invertebrado",opts:["vertebrado","invertebrado"],txt:true, why:v?"Tiene esqueleto interno con columna vertebral.":"No tiene columna vertebral."}; } const [w,e]=pick(VOCAB.filter(x=>!used.has(x[0]))); used.add(w); return {scene:`What is it?
`,answer:w,opts:shuffle([w,...shuffle(VOCAB.filter(x=>x[0]!==w)).slice(0,2).map(x=>x[0])]),txt:true}; } /* ---------- Motor ---------- */ function play(g){ const R=g.id==="lectura"?6:8; const queue=g.id==="lectura"?shuffle(LECTURAS).slice(0,3).flatMap(l=>[{l,qi:0},{l,qi:1}]):[]; let i=0, score=0; const res=[], used=new Set(); const dots=()=>`${HELP[g.id]}
${msg}