Я реализовал генератор циклического перебора в PHP, чтобы создавать матчи между пользователями в лиге. Это соответствует всем пользователям в лиге и сопоставляет их друг с другом в течение каждой недели игры.
Код выглядит так;
/**
* Rotates an array for the round robin algorithm
*/
function round_robin_array($array)
{
// we always keep index 0
$top = array_shift($array);
$last = array_pop($array);
$rotate = [$last];
foreach ($array as $_value) {
$rotate[] = $_value;
}
array_unshift($rotate, $top);
return $rotate;
}
/**
* Runs a round robin to make a schedule.
*/
function round_robin($users, $weeks)
{
$schedule = [];
$count = count($users);
foreach ($users as $_u) {
$schedule[$_u] = array_fill(0, $weeks, []);
}
for ($i=0;$i<$weeks;$i++) {
for ($a=0;$a<($count / 2) + 1;$a++) {
$vs = $users[$a];
$opp = $users[($count - $a) - 1];
$at = rand(0,4);
$pg = [$opp, $at];
$og = [$vs, $at];
$schedule[$vs][$i] = $pg;
$schedule[$opp][$i] = $og;
}
$users = $this->round_robin_array($users);
}
return $schedule;
}
public function generateFixtures($league, $users, $weeks)
{
$array = [];
foreach($users as $user) {
array_push($array, $user['id']);
}
if(count($array) % 2 != 0) {
array_push($array, '0');
}
$fixtures = $this->round_robin($array, $weeks);
$gameweek = 1;
foreach($fixtures as $key => $val) {
if($key != 0) {
foreach($val as $opponent) {
LeagueFixture::firstOrCreate([
'gameweek' => $gameweek,
'league_id' => $league,
'user_id' => $key,
'opponent_id' => $opponent[0],
]);
$gameweek = $gameweek+1;
}
}
$gameweek = 1;
}
return $fixtures;
}
Функция generateFixtures передается пользователям лиги, самой лиге и количеству недель.
Проблема в том, что это создает «дубликаты» для каждого прибора, поскольку, по сути, существует представление от каждого пользователя — например;
Gameweek 1
Как видите, последние два светильника там разные; но так же!
Мой вопрос заключается в том, является ли это проблемой с циклическим циклом или я мог / должен отфильтровать эти дубликаты, когда вытащил их через контроллер / представление
Это не самое элегантное решение, но в момент ввода данных в базу данных я могу проверить, существует ли уже противоположное тому, что должно быть создано;
foreach($fixtures as $key => $val) {
if($key != 0) {
//loop through the values to create an entry for each
foreach($val as $opponent) {
//check if the opposite of each entry already exists
if(!LeagueFixture::where('gameweek', $gameweek)
->where('league_id', $league)
->where('user_id', $opponent[0])
->where('opponent_id', $key)
->exists()) {
//if not, we can create the entry as usual
LeagueFixture::firstOrCreate([
'gameweek' => $gameweek,
'league_id' => $league,
'user_id' => $key,
'opponent_id' => $opponent[0],
]);
}
$gameweek = $gameweek+1;
}
}
$gameweek = 1;
}
Сейчас это самое простое решение для меня … хотя данные генерируются в указанном циклическом цикле (и вы могли бы легко утверждать, что это было бы плохой практикой), дублированные данные никогда не попадают в мою базу данных
Других решений пока нет …