Files
Ruleta_Actvidad/src/hooks/useRuleta.ts
T

135 lines
4.3 KiB
TypeScript

import { useState, useRef } from 'react'
import type { Pregunta, Categoria, PreguntasData } from '../types'
import data from '../data/preguntas.json'
import { sounds } from '../audio/AudioController'
const { categorias, bancoGenerico } = data as PreguntasData
const MAX_PREGUNTAS = 10
const MIN_CORRECTAS = 8
const SECCIONES = categorias.length
const ANGULO_SECCION = 360 / SECCIONES
export interface EstadoJuego {
isSpinning: boolean
rotacion: number
preguntaActual: Pregunta | null
categoriaActual: Categoria | null
mostrarFeedback: boolean
feedbackCorrecto: boolean
preguntasRespondidas: number
correctas: number
completado: boolean
aprobado: boolean
preguntasUsadas: Record<number, number[]>
bancoPreguntasUsadas: number[]
}
export function useRuleta() {
const [estado, setEstado] = useState<EstadoJuego>({
isSpinning: false,
rotacion: 0,
preguntaActual: null,
categoriaActual: null,
mostrarFeedback: false,
feedbackCorrecto: false,
preguntasRespondidas: 0,
correctas: 0,
completado: false,
aprobado: false,
preguntasUsadas: {},
bancoPreguntasUsadas: [],
})
const rotacionRef = useRef(0)
function seleccionarPregunta(categoria: Categoria, preguntasUsadas: Record<number, number[]>, bancoPreguntasUsadas: number[]): { pregunta: Pregunta, esGenerica: boolean } {
const usadas = preguntasUsadas[categoria.id] ?? []
const disponibles = categoria.preguntas.filter((_, i) => !usadas.includes(i))
if (disponibles.length > 0) {
const idx = Math.floor(Math.random() * disponibles.length)
return { pregunta: disponibles[idx], esGenerica: false }
}
// Banco genérico
const disponiblesGenericas = bancoGenerico.filter((_, i) => !bancoPreguntasUsadas.includes(i))
const pool = disponiblesGenericas.length > 0 ? disponiblesGenericas : bancoGenerico
const idx = Math.floor(Math.random() * pool.length)
return { pregunta: pool[idx], esGenerica: true }
}
function girar() {
if (estado.isSpinning || estado.completado) return
sounds.wheelSpin?.play()
const vueltas = 3 + Math.random() * 2
const anguloFinal = Math.random() * 360
const rotacionTotal = rotacionRef.current + vueltas * 360 + anguloFinal
rotacionRef.current = rotacionTotal
setEstado((prev) => ({ ...prev, isSpinning: true, rotacion: rotacionTotal }))
setTimeout(() => {
const anguloNormalizado = ((360 - (rotacionRef.current % 360)) + 360) % 360
const indiceCategoria = Math.floor(anguloNormalizado / ANGULO_SECCION) % SECCIONES
const categoria = categorias[indiceCategoria]
setEstado((prev) => {
const { pregunta, esGenerica } = seleccionarPregunta(categoria, prev.preguntasUsadas, prev.bancoPreguntasUsadas)
const originalIdx = esGenerica
? bancoGenerico.indexOf(pregunta)
: categoria.preguntas.indexOf(pregunta)
return {
...prev,
preguntaActual: pregunta,
categoriaActual: categoria,
preguntasUsadas: esGenerica ? prev.preguntasUsadas : {
...prev.preguntasUsadas,
[categoria.id]: [...(prev.preguntasUsadas[categoria.id] ?? []), originalIdx],
},
bancoPreguntasUsadas: esGenerica
? [...prev.bancoPreguntasUsadas, originalIdx]
: prev.bancoPreguntasUsadas,
}
})
}, 4000)
}
function responder(indiceOpcion: number | null) {
if (!estado.preguntaActual) return
const esCorrecta = indiceOpcion !== null && indiceOpcion === estado.preguntaActual.correcta
if (esCorrecta) sounds.correct?.play()
else sounds.incorrect?.play()
const nuevasCorrectas = estado.correctas + (esCorrecta ? 1 : 0)
const nuevasRespondidas = estado.preguntasRespondidas + 1
const completado = nuevasRespondidas >= MAX_PREGUNTAS
const aprobado = completado && nuevasCorrectas >= MIN_CORRECTAS
setEstado((prev) => ({
...prev,
correctas: nuevasCorrectas,
preguntasRespondidas: nuevasRespondidas,
mostrarFeedback: true,
feedbackCorrecto: esCorrecta,
completado,
aprobado,
}))
}
function cerrarFeedback() {
setEstado((prev) => ({
...prev,
preguntaActual: null,
categoriaActual: null,
mostrarFeedback: false,
isSpinning: false,
}))
}
return { estado, categorias, girar, responder, cerrarFeedback, MAX_PREGUNTAS, MIN_CORRECTAS }
}