139 lines
4.9 KiB
PHP
139 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Torneo;
|
|
use App\Models\Equipo;
|
|
use Carbon\Carbon;
|
|
|
|
class FixtureService
|
|
{
|
|
/**
|
|
* Genera un fixture Round-Robin para los equipos de un torneo.
|
|
*
|
|
* @param Torneo $torneo
|
|
* @param string $fechaInicio 'Y-m-d'
|
|
* @param int $diasEntreJornadas
|
|
* @param string $sedeDefault
|
|
* @param bool $dobleRueda Si true, genera ida y vuelta
|
|
* @return array Array de arrays con los datos de cada evento a crear
|
|
*/
|
|
public function generarRoundRobin(
|
|
Torneo $torneo,
|
|
string $fechaInicio,
|
|
int $diasEntreJornadas = 7,
|
|
?string $sedeDefault = '',
|
|
bool $dobleRueda = false
|
|
): array {
|
|
$equipos = $torneo->equipos()->get()->values()->toArray();
|
|
$n = count($equipos);
|
|
|
|
if ($n < 2) {
|
|
throw new \InvalidArgumentException('Se necesitan al menos 2 equipos para generar un fixture.');
|
|
}
|
|
|
|
// Si número impar, agregar BYE
|
|
$hayBye = false;
|
|
if ($n % 2 !== 0) {
|
|
$equipos[] = null; // BYE
|
|
$n++;
|
|
$hayBye = true;
|
|
}
|
|
|
|
$mitad = $n / 2;
|
|
$jornadas = $n - 1;
|
|
$partidos = [];
|
|
$fechaActual = Carbon::parse($fechaInicio);
|
|
|
|
// Algoritmo Round-Robin: fijar el primer equipo, rotar el resto
|
|
$lista = range(0, $n - 1);
|
|
|
|
for ($jornada = 0; $jornada < $jornadas; $jornada++) {
|
|
$jornadaPartidos = [];
|
|
|
|
for ($i = 0; $i < $mitad; $i++) {
|
|
$localIdx = $lista[$i];
|
|
$visitanteIdx= $lista[$n - 1 - $i];
|
|
|
|
// Si alguno es BYE (null), saltar
|
|
if ($equipos[$localIdx] === null || $equipos[$visitanteIdx] === null) continue;
|
|
|
|
$local = $equipos[$localIdx];
|
|
$visitante = $equipos[$visitanteIdx];
|
|
|
|
// Alternar localía: en jornadas pares, invertir
|
|
if ($jornada % 2 === 1) {
|
|
[$local, $visitante] = [$visitante, $local];
|
|
}
|
|
|
|
$jornadaPartidos[] = [
|
|
'id_equipo_local' => $local['id_equipo'],
|
|
'id_equipo_visitante' => $visitante['id_equipo'],
|
|
'fecha_evento' => $fechaActual->format('Y-m-d'),
|
|
'hora_inicio' => '20:00:00',
|
|
'hora_fin' => '22:00:00',
|
|
'sede' => $sedeDefault,
|
|
'id_torneo' => $torneo->id,
|
|
'nombre_evento' => null, // se genera automáticamente
|
|
'precio' => 0,
|
|
'jornada' => $jornada + 1,
|
|
];
|
|
}
|
|
|
|
$partidos = array_merge($partidos, $jornadaPartidos);
|
|
$fechaActual->addDays($diasEntreJornadas);
|
|
|
|
// Rotar la lista (el primer elemento fijo)
|
|
$rotatable = array_slice($lista, 1);
|
|
array_push($rotatable, array_shift($rotatable));
|
|
$lista = array_merge([$lista[0]], $rotatable);
|
|
}
|
|
|
|
// Doble rueda: agregar vuelta con localías invertidas
|
|
if ($dobleRueda && !empty($partidos)) {
|
|
$vuelta = [];
|
|
foreach ($partidos as $p) {
|
|
$vuelta[] = array_merge($p, [
|
|
'id_equipo_local' => $p['id_equipo_visitante'],
|
|
'id_equipo_visitante' => $p['id_equipo_local'],
|
|
'fecha_evento' => Carbon::parse($p['fecha_evento'])->addDays($jornadas * $diasEntreJornadas)->format('Y-m-d'),
|
|
'jornada' => $p['jornada'] + $jornadas,
|
|
]);
|
|
}
|
|
$partidos = array_merge($partidos, $vuelta);
|
|
}
|
|
|
|
return $partidos;
|
|
}
|
|
|
|
/**
|
|
* Persiste el fixture generado como Evento records en la DB.
|
|
*/
|
|
public function persistirFixture(array $partidos, Torneo $torneo): int
|
|
{
|
|
$contador = 0;
|
|
foreach ($partidos as $p) {
|
|
$local = Equipo::with('club')->find($p['id_equipo_local']);
|
|
$visitante = Equipo::with('club')->find($p['id_equipo_visitante']);
|
|
|
|
$nombreEvento = ($local->club->nombre ?? '?') . ' vs ' . ($visitante->club->nombre ?? '?');
|
|
|
|
\App\Models\Evento::create([
|
|
'id_evento' => uniqid('ev_'),
|
|
'nombre_evento' => $nombreEvento,
|
|
'id_equipo_local' => $p['id_equipo_local'],
|
|
'id_equipo_visitante' => $p['id_equipo_visitante'],
|
|
'fecha_evento' => $p['fecha_evento'],
|
|
'hora_inicio' => $p['hora_inicio'],
|
|
'hora_fin' => $p['hora_fin'],
|
|
'sede' => $p['sede'] ?: null,
|
|
'id_torneo' => $torneo->id,
|
|
'precio' => $p['precio'] ?? 0,
|
|
]);
|
|
|
|
$contador++;
|
|
}
|
|
return $contador;
|
|
}
|
|
}
|