'Sesión no iniciada']); exit; } $idPartida = intval($_POST['idPartida'] ?? 0); $orden = $_POST['orden'] ?? ''; if ($idPartida <= 0) { echo json_encode(['error' => 'Partida no válida']); exit; } $conexion = conexionBD(); if (is_array($conexion)) { echo json_encode($conexion); exit; } switch ($orden) { case 'comprobarEstado': try { // 1. Contar cuántos jugadores hay asignados en esta partida $stmt = $conexion->prepare(" SELECT COUNT(exu.idUsuario) AS total_jugadores FROM equipoxpartida exp INNER JOIN equipoxusuario exu ON exp.idEquipo = exu.idEquipo WHERE exp.idPartida = :idPartida "); $stmt->execute([':idPartida' => $idPartida]); $totalJugadores = (int)$stmt->fetchColumn(); $preguntasTotalesEsperadas = $totalJugadores * 10; // 2. Contar cuántas respuestas reales se han guardado $stmtRespuestas = $conexion->prepare(" SELECT COUNT(*) FROM respuestaalmacenada ra INNER JOIN partidaxpregunta pxp ON ra.idPartidaxPregunta = pxp.idPartidaxPregunta WHERE pxp.idPartida = :idPartida "); $stmtRespuestas->execute([':idPartida' => $idPartida]); $respuestasRespondidas = (int)$stmtRespuestas->fetchColumn(); $terminada = ($respuestasRespondidas >= $preguntasTotalesEsperadas && $preguntasTotalesEsperadas > 0); // 3. Si ha terminado, guardamos los datos históricos una sola vez if ($terminada && !isset($_SESSION['partidas_procesadas'][$idPartida])) { $conexion->beginTransaction(); // --- CÁLCULO DE VELOCIDAD --- if (!isset($_SESSION['primeros_en_acertar'][$idPartida])) { $_SESSION['primeros_en_acertar'][$idPartida] = []; } $stmtVelocidad = $conexion->prepare(" SELECT ra.idPartidaxPregunta, ra.idUsuario FROM respuestaalmacenada ra INNER JOIN respuesta r ON ra.idRespuesta = r.idRespuesta INNER JOIN partidaxpregunta pxp ON ra.idPartidaxPregunta = pxp.idPartidaxPregunta WHERE pxp.idPartida = :idPartida AND r.correcta = 1 ORDER BY ra.idRespuestaAlmacenada ASC "); $stmtVelocidad->execute([':idPartida' => $idPartida]); $todosLosAciertos = $stmtVelocidad->fetchAll(PDO::FETCH_ASSOC); foreach ($todosLosAciertos as $acierto) { $idPxp = $acierto['idPartidaxPregunta']; $idU = $acierto['idUsuario']; if (!isset($_SESSION['primeros_en_acertar'][$idPartida][$idPxp])) { $_SESSION['primeros_en_acertar'][$idPartida][$idPxp] = $idU; } } // Consulta de aciertos $stmtAciertos = $conexion->prepare(" SELECT ra.idUsuario, exu.idEquipo, COUNT(*) as aciertos_partida FROM respuestaalmacenada ra INNER JOIN partidaxpregunta pxp ON ra.idPartidaxPregunta = pxp.idPartidaxPregunta INNER JOIN respuesta r ON ra.idRespuesta = r.idRespuesta INNER JOIN equipoxusuario exu ON ra.idUsuario = exu.idUsuario WHERE pxp.idPartida = :idPartida AND r.correcta = 1 GROUP BY ra.idUsuario, exu.idEquipo "); $stmtAciertos->execute([':idPartida' => $idPartida]); $jugadoresPartida = $stmtAciertos->fetchAll(PDO::FETCH_ASSOC); $updateAciertos = $conexion->prepare(" UPDATE usuario SET aciertos = aciertos + :nuevos_aciertos WHERE idUsuario = :idUsuario "); $puntosEquipos = []; foreach ($jugadoresPartida as $jp) { $idU = (int)$jp['idUsuario']; $idE = (int)$jp['idEquipo']; $nuevosAciertos = (int)$jp['aciertos_partida']; $updateAciertos->execute([ ':nuevos_aciertos' => $nuevosAciertos, ':idUsuario' => $idU ]); if (!isset($puntosEquipos[$idE])) { $puntosEquipos[$idE] = 0; } $puntosEquipos[$idE] += $nuevosAciertos; } if (!empty($puntosEquipos)) { arsort($puntosEquipos); $idEquipoGanador = key($puntosEquipos); $stmtMiembros = $conexion->prepare(" SELECT exu.idUsuario, exu.idEquipo FROM equipoxpartida exp INNER JOIN equipoxusuario exu ON exp.idEquipo = exu.idEquipo WHERE exp.idPartida = :idPartida "); $stmtMiembros->execute([':idPartida' => $idPartida]); $todosLosMiembros = $stmtMiembros->fetchAll(PDO::FETCH_ASSOC); $updateVictoria = $conexion->prepare("UPDATE usuario SET victorias = victorias + 1 WHERE idUsuario = :idUsuario"); $updateDerrota = $conexion->prepare("UPDATE usuario SET derrotas = derrotas + 1 WHERE idUsuario = :idUsuario"); foreach ($todosLosMiembros as $miembro) { $idU = (int)$miembro['idUsuario']; $idE = (int)$miembro['idEquipo']; if ($idE === $idEquipoGanador) { $updateVictoria->execute([':idUsuario' => $idU]); } else { $updateDerrota->execute([':idUsuario' => $idU]); } } } // Marcar fecha fin de la partida para los históricos globales del grupo $stmtFinalizar = $conexion->prepare(" UPDATE partida SET fechaFin = NOW() WHERE idPartida = :idPartida AND fechaFin IS NULL "); $stmtFinalizar->execute([':idPartida' => $idPartida]); $conexion->commit(); $_SESSION['partidas_procesadas'][$idPartida] = true; } echo json_encode(['terminada' => $terminada]); } catch (PDOException $e) { if ($conexion->inTransaction()) { $conexion->rollBack(); } echo json_encode(['error' => $e->getMessage()]); } break; case 'registrarSalidaUsuario': try { $idUsuario = (int)$_SESSION['idUsuario']; $conexion->beginTransaction(); // A. LIBERACIÓN INMEDIATA DEL JUGADOR ACTUAL: Lo borramos de su equipo $stmtSalir = $conexion->prepare("DELETE FROM equipoxusuario WHERE idUsuario = :idUsuario"); $stmtSalir->execute([':idUsuario' => $idUsuario]); // B. CONTADOR DE ALUMNOS QUEDAN: Contamos cuántas personas quedan en los equipos de esta partida $stmtContarQuedan = $conexion->prepare(" SELECT COUNT(exu.idUsuario) FROM equipoxpartida exp INNER JOIN equipoxusuario exu ON exp.idEquipo = exu.idEquipo WHERE exp.idPartida = :idPartida "); $stmtContarQuedan->execute([':idPartida' => $idPartida]); $jugadoresRestantes = (int)$stmtContarQuedan->fetchColumn(); // C. DESTRUCCIÓN EN CADENA AUTOMÁTICA ATÓMICA (Si da 0, somos los últimos en salir) if ($jugadoresRestantes === 0) { // 1. Limpiar las respuestas almacenadas $stmtBorrarRespuestas = $conexion->prepare(" DELETE ra FROM respuestaalmacenada ra INNER JOIN partidaxpregunta pxp ON ra.idPartidaxPregunta = pxp.idPartidaxPregunta WHERE pxp.idPartida = :idPartida "); $stmtBorrarRespuestas->execute([':idPartida' => $idPartida]); // 2. Limpiar las preguntas vinculadas a la partida $stmtBorrarPreguntas = $conexion->prepare("DELETE FROM partidaxpregunta WHERE idPartida = :idPartida"); $stmtBorrarPreguntas->execute([':idPartida' => $idPartida]); // 3. NUEVO: Obtener los IDs de los dos equipos que jugaban en esta partida antes de borrar la relación $stmtObtenerEquipos = $conexion->prepare("SELECT idEquipo FROM equipoxpartida WHERE idPartida = :idPartida"); $stmtObtenerEquipos->execute([':idPartida' => $idPartida]); $equiposDeLaPartida = $stmtObtenerEquipos->fetchAll(PDO::FETCH_COLUMN); // 4. Limpiar la relación de equipos de la partida (tabla intermedia) $stmtBorrarEquiposPartida = $conexion->prepare("DELETE FROM equipoxpartida WHERE idPartida = :idPartida"); $stmtBorrarEquiposPartida = $conexion->prepare("DELETE FROM equipoxpartida WHERE idPartida = :idPartida"); $stmtBorrarEquiposPartida->execute([':idPartida' => $idPartida]); // 5. NUEVO: Borrar físicamente los equipos de la tabla 'equipo' si existen if (!empty($equiposDeLaPartida)) { // Creamos los marcadores (?, ?) de forma dinámica según los equipos que devuelva $inQuery = implode(',', array_fill(0, count($equiposDeLaPartida), '?')); $stmtBorrarEquiposFisicos = $conexion->prepare("DELETE FROM equipo WHERE idEquipo IN ($inQuery)"); $stmtBorrarEquiposFisicos->execute($equiposDeLaPartida); } // 6. Borrar físicamente la fila de la partida principal $stmtBorrarSala = $conexion->prepare("DELETE FROM partida WHERE idPartida = :idPartida"); $stmtBorrarSala->execute([':idPartida' => $idPartida]); } $conexion->commit(); echo json_encode(['exito' => true, 'usuarios_quedan' => $jugadoresRestantes]); } catch (PDOException $e) { if ($conexion->inTransaction()) { $conexion->rollBack(); } echo json_encode(['error' => $e->getMessage()]); } break; }