Este script, escrito en lenguaje PHP, funciona mejor inyectado dentro de una página de un sitio web de la plataforma WordPress. Posiblemente, contenga algún bug aunque ha sido probado concienzudamente. Es susceptible de mejorarse, de hecho esta es la versión 3.0. El propósito es no repetir emparejamientos entre los jugadores que participan en el sorteo. No se tiene en cuenta los enfrentamientos anteriores por lo que en un sorteo se puede repetir contrincante. La función aleatoria utilizada es shuffle. El algoritmo de aleatorización interna es el Generador de números aleatorios Mersenne Twister.
<?php
// Sorteo PdH
// Autor: Antonio Cambronero (Blogpocket.com)
// Versión 3.0
// Licencia: CC Atribución-NoComercial-SinDerivadas 4.0 Internacional (CC BY-NC-ND 4.0)
// Se recomienda ejecutar este código en un entorno privado
//
//
// Nombre del archivo CSV
$filename = 'PONER EL NOMBRE DEL ARCHIVO CSV AQUÍ';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Obtenemos y procesamos la lista de jugadores desde el formulario
$playersInput = isset($_POST['players']) ? $_POST['players'] : '';
// Convertimos la entrada en un array, eliminando espacios y líneas vacías
$players = array_filter(array_map('trim', explode("\n", $playersInput)));
// Verificamos que el número de jugadores sea par (para emparejarlos a todos)
if (count($players) % 2 != 0) {
echo "<p><strong>Error:</strong> El número de jugadores debe ser par para emparejarlos todos.</p>";
exit;
}
// Verificamos la existencia del archivo CSV
if (!file_exists($filename)) {
echo "<p><strong>Error:</strong> El archivo CSV no se encontró.</p>";
exit;
}
// Cargamos el historial de emparejamientos en un array asociativo para controlar parejas prohibidas
$forbiddenPairs = array();
if (($handle = fopen($filename, "r")) !== false) {
while (($data = fgetcsv($handle, 1000, ",")) !== false) {
// El primer campo es el jugador y los siguientes son sus parejas previas
if (count($data) > 1) {
$player = trim($data[0]);
for ($i = 1; $i < count($data); $i++) {
$partner = trim($data[$i]);
if ($player !== '' && $partner !== '') {
// Guardamos la pareja en orden alfabético para evitar duplicados
$pair = array($player, $partner);
sort($pair, SORT_STRING);
$key = implode("|", $pair);
$forbiddenPairs[$key] = true;
}
}
}
}
fclose($handle);
} else {
echo "<p><strong>Error:</strong> No se pudo leer el archivo CSV.</p>";
exit;
}
/**
* Función que verifica si dos jugadores pueden emparejarse
* según el historial de emparejamientos (archivo CSV).
*/
function isPairAllowed($p1, $p2, $forbiddenPairs) {
$pair = array($p1, $p2);
sort($pair, SORT_STRING);
$key = implode("|", $pair);
return !isset($forbiddenPairs[$key]);
}
/**
* Función recursiva que intenta encontrar un emparejamiento completo
* de todos los jugadores sin repetir parejas ya realizadas.
*/
function findMatching($players, $forbiddenPairs) {
// Caso base: no quedan jugadores por emparejar
if (empty($players)) {
return array();
}
// Tomamos el primer jugador de la lista y lo sacamos de la lista con array_shift
// (la lista se queda sin el jugador extraído)
$first = array_shift($players);
// Mezclamos aleatoriamente el resto de jugadores para introducir aleatoriedad
shuffle($players);
// Fin de la mezcla
// Probamos emparejar al primer jugador con cada uno de los demás
foreach ($players as $index => $partner) {
if (isPairAllowed($first, $partner, $forbiddenPairs)) {
// Creamos una copia de la lista sin el jugador emparejado
$remaining = $players;
unset($remaining[$index]);
$remaining = array_values($remaining); // Reindexamos el array
// Llamada recursiva para emparejar el resto
$result = findMatching($remaining, $forbiddenPairs);
if ($result !== false) {
// Si se encontró un emparejamiento válido, retornamos la solución parcial junto con la pareja actual
return array_merge(array(array($first, $partner)), $result);
}
}
}
// Si no se encontró un emparejamiento válido para este camino, retornamos false
return false;
}
/**
* Función para visualizar el historial de emparejamientos de un jugado.
*/
function mostrarHistorialCompleto($players, $filename) {
// Inicializar un array para almacenar el historial de cada jugador del sorteo
$historial = array();
foreach ($players as $jugador) {
$historial[$jugador] = array();
}
// Abrir y leer el archivo CSV
if (($handle = fopen($filename, "r")) !== false) {
while (($data = fgetcsv($handle, 1000, ",")) !== false) {
// El primer elemento es el jugador principal; el resto, sus compañeros
$jugadorPrincipal = trim($data[0]);
$companeros = array_map('trim', array_slice($data, 1));
// Si el jugador principal está en el sorteo, agregar sus compañeros al historial
if (in_array($jugadorPrincipal, $players)) {
foreach ($companeros as $comp) {
if ($comp !== '' && !in_array($comp, $historial[$jugadorPrincipal])) {
$historial[$jugadorPrincipal][] = $comp;
}
}
}
// Además, si alguno de los compañeros forma parte del sorteo,
// se añade el jugador principal al historial de ese compañero.
foreach ($companeros as $comp) {
if (in_array($comp, $players)) {
if (!in_array($jugadorPrincipal, $historial[$comp])) {
$historial[$comp][] = $jugadorPrincipal;
}
}
}
}
fclose($handle);
} else {
echo "No se pudo abrir el archivo CSV";
return;
}
// Mostrar el historial solo para aquellos jugadores que han jugado con todos los demás participantes.
foreach ($historial as $jugador => $partners) {
// Filtrar el historial para quedarnos solo con los compañeros que están en el sorteo
$partnersSorteo = array_unique(array_intersect($partners, $players));
// Se espera que un jugador que haya jugado con todos los demás tenga (total participantes - 1) compañeros
if (count($partnersSorteo) === count($players) - 1) {
echo $jugador;
if (!empty($partnersSorteo)) {
echo " ha jugado con... " . implode(", ", $partnersSorteo);
}
echo "<br />";
}
}
}
// INICIO DEL PROGRAMA
// Intentamos encontrar un emparejamiento completo
$matching = findMatching($players, $forbiddenPairs);
// Si no ha sido posible encontrar emparejamiento para al menos un jugador
// entonces se muestra el historial completo de emparejamientos para aquellos
// jugadores para los que no ha sido posible encontrar un emparejamiento
// En ese caso, el sorteo se suspende y lo recomendable es limpiar el archivo CSV
if ($matching === false) {
echo "Participantes en el sorteo: ";
foreach ($players as $player) {
echo $player . ", ";
}
echo "<br />";
mostrarHistorialCompleto($players, $filename);
echo "<p><strong>Advertencia:</strong> No se pudo encontrar un emparejamiento válido para todos los jugadores. Se han agotado todas las combinaciones disponibles en el historial.</p><p><strong><a href='https://www.lanzatu.blog/resetear.php'>RESETEAR LA TABLA</a></strong></p>";
exit;
} else {
// Si el sorteo es válido,
// mostramos las parejas formadas (opcional) y actualizamos el archivo CSV
// echo "<h2>Emparejamientos:</h2>";
//echo "<ul>";
//foreach ($matching as $pair) {
//echo "<li>" . htmlspecialchars($pair[0]) . " - " . htmlspecialchars($pair[1]) . "</li>";
//}
//echo "</ul>";
// =====================================
// Actualización del archivo CSV
// =====================================
// Cargamos el contenido actual del CSV en un array asociativo: jugador => [lista de parejas]
$partnersData = array();
if (($handle = fopen($filename, "r")) !== false) {
while (($data = fgetcsv($handle, 1000, ",")) !== false) {
if (count($data) > 0) {
$player = trim($data[0]);
$partnersData[$player] = array();
// Los siguientes campos son los emparejamientos previos
for ($i = 1; $i < count($data); $i++) {
$p = trim($data[$i]);
if ($p !== '') {
$partnersData[$player][] = $p;
}
}
}
}
fclose($handle);
}
// Para cada emparejamiento, actualizamos las filas correspondientes
foreach ($matching as $pair) {
list($p1, $p2) = $pair;
// Actualizar para p1
if (!isset($partnersData[$p1])) {
$partnersData[$p1] = array();
}
if (!in_array($p2, $partnersData[$p1])) {
$partnersData[$p1][] = $p2;
}
// Actualizar para p2
if (!isset($partnersData[$p2])) {
$partnersData[$p2] = array();
}
if (!in_array($p1, $partnersData[$p2])) {
$partnersData[$p2][] = $p1;
}
}
// Escribimos el array actualizado de vuelta en el archivo CSV
if (($handle = fopen($filename, "w")) !== false) {
foreach ($partnersData as $player => $partners) {
// La primera columna es el jugador, seguido de sus emparejamientos
$row = array_merge(array($player), $partners);
fputcsv($handle, $row);
}
fclose($handle);
//echo "<p><strong>Actualización:</strong> Los emparejamientos se han guardado en '$filename'.</p>";
} else {
echo "<p><strong>Error:</strong> No se pudo escribir en el archivo CSV.</p>";
}
// =====================================
// Formación de partidos
// =====================================
//
// Cada partido se formará combinando dos de los emparejamientos obtenidos.
// Se mezclan aleatoriamente las parejas y se agrupan de a dos.
//
$pairsForDoubles = $matching;
// Barajar para formar partidos aleatorios
shuffle($pairsForDoubles);
// Fin de barajar
$doublesMatches = array();
// Si el número de parejas es impar, se notificará que una pareja queda sin partido
if (count($pairsForDoubles) % 2 != 0) {
echo "<p><strong>Advertencia:</strong> Una pareja quedó sin formar partido de dobles.</p>";
}
// Agrupamos de dos en dos
for ($i = 0; $i < count($pairsForDoubles) - 1; $i += 2) {
$doublesMatches[] = array($pairsForDoubles[$i], $pairsForDoubles[$i + 1]);
}
// Mostramos los partidos de dobles formados
echo "<h3>Partidos formados:</h3>";
echo "<ul>";
foreach ($doublesMatches as $match) {
list($team1, $team2) = $match;
echo "<li>" . htmlspecialchars($team1[0]) . " y " . htmlspecialchars($team1[1]) . " vs " . htmlspecialchars($team2[0]) . " y " . htmlspecialchars($team2[1]) . "</li>";
}
echo "</ul>";
}
} else {
// Si no se envió el formulario, se muestra el formulario de entrada
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Emparejamientos y Sorteo Grupo Barakka PdH</title>
</head>
<body>
<form method="post">
<label for="players">Ingresa la lista de jugadores (uno por línea):</label><br>
<textarea id="players" name="players" rows="10" cols="30" placeholder=""></textarea><br>
<input type="submit" value="Sortear">
</form>
</body>
</html>
<?php
}
?>