This commit is contained in:
Laucha1312
2026-06-04 15:15:23 -03:00
parent 0841794c50
commit 90c5f85512
167 changed files with 15870 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
<?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;
}
}