Poniższa klasa zawiera dwie metody statyczne (DuelGenerator::generateDuels() oraz DuelGenerator::generateDuels2()), które mogą rozwiązać zadanie. Z tym że metoda DuelGenerator::generateDuels() jest częściowo wadliwa, ponieważ dla przykładowych danych z metody DuelGenerator::getData() nie zawsze zwróci 3 pary, czasem tylko 2. Natomiast druga metoda powinna działać poprawnie.
<?php
class DuelGenerator
{
private static function getData()
{
/*
$dbObj = new \PDO(
'mysql:host='.$host.';dbname='.$dbName.';encoding=utf8',
$login,
$password
);
$stmt = $dbObj->prepare(
'SELECT * FROM tabela'
);
$stmt->execute();
$result = $stmt->fetchAll(\PDO::FETCH_ASSOC);
return $result;
*/
return array(
array('id' => 1, 'nazwa' => 'Łukasz', 'klub' => 'WKS'),
array('id' => 2, 'nazwa' => 'Rafał', 'klub' => 'ŁKS'),
array('id' => 3, 'nazwa' => 'Marian', 'klub' => 'WKS'),
array('id' => 4, 'nazwa' => 'Piotrek', 'klub' => 'ŁKS'),
array('id' => 6, 'nazwa' => 'Marcin', 'klub' => 'MKS'),
array('id' => 7, 'nazwa' => 'Witek', 'klub' => 'AAA')
);
}
public static function generateDuels()
{
$users = self::getData();
$pairs = array();
$usersCount = count($users);
while ($usersCount !== 0)
{
$currentUserIndex = mt_rand(0, $usersCount - 1);
$currentUser = $users[$currentUserIndex];
$used = array();
do
{
$oponnentIndex = mt_rand(0, $usersCount - 1);
$opponent = $users[$oponnentIndex];
if (!in_array($opponent['id'], $used))
{
$used[] = $opponent['id'];
}
}
while ($opponent['klub'] === $currentUser['klub'] && count($used) !== $usersCount);
if ($opponent['klub'] !== $currentUser['klub'])
{
$pairs[$currentUser['id']] = $opponent['id'];
unset($users[$currentUserIndex]);
unset($users[$oponnentIndex]);
$usersCount -= 2;
}
else
{
unset($users[$currentUserIndex]);
$usersCount--;
}
$users = array_values($users);
}
return $pairs;
}
public static $arrToSort;
private static function shuffleAssoc($list)
{
if (!is_array($list))
{
return $list;
}
$keys = array_keys($list);
shuffle($keys);
$random = array();
foreach ($keys as $key) {
$random[$key] = $list[$key];
}
return $random;
}
private static function cmp($a, $b)
{
if (self::$arrToSort[$a]['count'] === self::$arrToSort[$b]['count'])
{
return 0;
}
return (self::$arrToSort[$a]['count'] > self::$arrToSort[$b]['count']) ? -1 : 1;
}
private static function groupData($users)
{
$groupedData = array();
for ($i = 0, $ii = count($users); $i < $ii; $i++)
{
$currUser = $users[$i];
if (!isset($groupedData[$currUser['klub']]))
{
$groupedData[$currUser['klub']] = array(
'index' => array($i),
'count' => 1
);
}
else
{
$groupedData[$currUser['klub']]['index'][] = $i;
$groupedData[$currUser['klub']]['count']++;
}
}
self::$arrToSort = $groupedData;
uksort($groupedData, "self::cmp");
return $groupedData;
}
private static function removeFromGroupedData(array $groupedData, $club, $index)
{
unset($groupedData[$club]['index'][$index]);
$groupedData[$club]['index'] = array_values($groupedData[$club]['index']);
$groupedData[$club]['count']--;
if ($groupedData[$club]['count'] == 0)
{
unset($groupedData[$club]);
}
return $groupedData;
}
public static function generateDuels2()
{
$users = self::getData();
$groupedData = self::groupData($users);
$pairs = array();
$usersCount = count($users);
while ($usersCount !== 0)
{
reset($groupedData);
$firstKey = key($groupedData);
$indexInIndexArr = mt_rand(0, $groupedData[$firstKey]['count'] - 1);
$currentUserIndex = $groupedData[$firstKey]['index'][$indexInIndexArr];
$currentUser = $users[$currentUserIndex];
$used = array();
do
{
$oponnentIndex = mt_rand(0, $usersCount - 1);
$opponent = $users[$oponnentIndex];
if (!in_array($opponent['id'], $used))
{
$used[] = $opponent['id'];
}
}
while ($opponent['klub'] === $currentUser['klub'] && count($used) !== $usersCount);
if ($opponent['klub'] !== $currentUser['klub'])
{
$pairs[$currentUser['id']] = $opponent['id'];
unset($users[$currentUserIndex]);
unset($users[$oponnentIndex]);
$groupedData = self::removeFromGroupedData(
$groupedData,
$opponent['klub'],
array_search($oponnentIndex, $groupedData[$opponent['klub']]['index'])
);
$usersCount -= 2;
}
else
{
unset($users[$currentUserIndex]);
$usersCount--;
}
$groupedData = self::removeFromGroupedData($groupedData, $firstKey, $indexInIndexArr);
$users = array_values($users);
$groupedData = self::groupData($users);
}
return self::shuffleAssoc($pairs);
}
}
$pairs = DuelGenerator::generateDuels2();
var_dump($pairs);