17 Sierpień 2009

Tabela Ekstraklasy…

ekstraklasaTworząc kompletnie od początku Abduru.pl, które ma stać się (mam nadzieję) dość ciekawym Systemem Zarządzania Treścią, doszedłem do momentu umieszczenia tabeli naszej rodzimej Ekstraklasy. O ile wcześniej już coś podobnego zrobiłem, to jednak dalekie było to od ideału, w dodatku przy większej liczbie drużyn z tą samą ilością punktów, stosowane było sortowanie takie samo, jak w przypadku dwóch drużyn, a więc najpierw punkty w spotkaniach bezpośrednich, później różnica bramek i w końcu… bramki strzelone na wyjeździe. Tym czasem, w przypadku większej liczby drużyn, trzecim sposobem sortowania powinna być ilość strzelonych bramek.

Jeśli chodzi o tradycyjną tabelę piłkarską, to nie ma najmniejszego problemu. Całą sprawę załatwi

array_multisort

Natomiast jak rozwiązać ten problem w przypadku rozgrywek chociażby naszej Ekstraklasy?

Nauczony doświadczeniem, że nie warto wyważać otwartych drzwi rozpocząłem poszukiwania „gotowca”. Jednak… efekty były mizerne. Co prawda natrafiłem na skrypt (polskiego autora – a jakże), o dźwięcznej nazwie Tabelownik, to rozwiązanie jakie zastosował autor podwójnie mnie zraziło. Po pierwsze wykorzystywał on pętle for, zamiast while, co spowalnia działanie skryptu (może nie bardzo, ale przy dużej liczbie drużyn i spotkań, a dodatkowo pobieraniu wiadomości i innych dupereli z tabeli – znacznie), zwłaszcza, że wykorzystywana jest dość często.
Po drugie… cały mechanizm sortowania oparł o działania na bazie danych, a ja wolałem uniknąć dodatkowego, niepotrzebnego obciążenia bazy. Zawziąłem się, aby wykorzystać do tego wyłącznie PHP i… udało się.

Sortowanie odbywa się dość szybko i sprawnie.
Cały dowcip polega na „wyłapywaniu” drużyn, które mają tę samą liczbę punktów i przypisywaniu ich do tablicy o wartości… ilości punktów właśnie. Później sortuję tabelę ze wszystkimi drużynami, tak jakby nie było zasady bezpośrednich spotkań, a następnie sortuję drużyny wg. odpowiednich zasad w zależności od tego ile drużyn ma taką samą liczbę punktów. Na zakończenie całego procesu podstawiam drużyny wg. nowej kolejności do posortowanej wcześniej tabeli. Wszystko prosto, łatwo i szybko.

Poniżej zamieszczam fragment kodu, który przedstawia sposób zastosowany przeze mnie. Nie podaję całego rozwiązania, bo to byłoby zbyt proste. Całość jest tak skonstruowana, że w zależności od zmiennej przesłanej do funkcji sortowanie może być z uwzględnieniem bezpośrednich spotkań, jak i bez. W poniższym przykładzie wyciąłem także fragment, w którym podstawia się dane z bezpośrednich spotkań, sądzę, że z tym każdy sobie poradzi ;)

foreach ($teams as $key => $value ) {
	// przygotowanie do sortowania tabeli tradycyjnymi metodami: liczba punktow, roznica bramek, wieksza ilosc zdobytych
	$data[$key]	= $value['points']; // punkty
	$diff[$key] = $value['diff']; // roznica
	$goals[$key] = $value['score']; // bramki zdobyte
}
$i = 0;
while( $i<count($data) ) {
	$ii = 0;
	while( $ii < count($data) ) {
		if ( $data[$i] == $data[$ii] && $i < $ii ) {
			// tutaj pobieramy i podstawiamy wyniki z bezposredniego spotkania nr 1
			// a pozniej dla drugiego spotkania....
			$team[$data[$i]][$teams[$i]['team_id']] = $teams[$i]; // tutaj przypisujemy druzyny do tabeli
			$team[$data[$i]][$teams[$ii]['team_id']] = $teams[$ii]; // ale tak aby ich nie dublowac ;)
		}
		$ii++;
	}
	$i++;
}
array_multisort($data,SORT_DESC,SORT_NUMERIC,$diff,SORT_DESC,SORT_NUMERIC,$goals,SORT_DESC,SORT_NUMERIC,$teams); // sortowanie klasyczne
 
$i = 0;
foreach( $team as $key => $value )  {
	$points = array(); $diff = array(); $score = array(); $bw = array(); $di = array(); $pts = array(); $bz = array(); $pt=array(); $d=array(); $b=array(); $w=array(); $v = array(); // zerujemy tablice, zeby sie nie nadpisywaly
	$ile = count($value);
	if ( $ile > 2 ) { // jesli wiecej niz dwie druzyny maja taka sama liczbe punktow wtedy sortowac bedziemy po punktach w bezposrednich pojedynkach, roznicy bramek, wiekszej liczby strzelonych goli
		foreach( $value as $k => $v ) {
			$pts[$k] = $v['pts'];
			$di[$k] = $v['di'];
			$bz[$k] = $v['bz'];
			$points[$k] = $v['points'];
			$diff[$k] = $v['diff'];
			$score[$k] = $v['score'];
		}
		array_multisort($pts,SORT_DESC,SORT_NUMERIC,$di,SORT_DESC,SORT_NUMERIC,$bz,SORT_DESC,SORT_NUMERIC,$points,SORT_DESC,SORT_NUMERIC,$diff,SORT_DESC,SORT_NUMERIC,$score,SORT_DESC,SORT_NUMERIC,$value); // sortujemy
	}  
	if ( $ile == 2 )  { // jesli dwie druzyny maja taka sama liczbe punktow, wtedy sortowac bedziemy po punktach, roznicy bramek, wiekszej ilosci bramek strzelonych na wyjezdzie
		foreach ( $value as $j => $w ) {
			$pt[$j] = $w['pts'];
			$d[$j] = $w['di'];
			$b[$j] = $w['bw'];
			$points[$j] = $w['points'];
			$diff[$j] = $w['diff'];
			$score[$j] = $w['score'];
		}
		array_multisort($pt,SORT_DESC,SORT_NUMERIC,$d,SORT_DESC,SORT_NUMERIC,$b,SORT_DESC,SORT_NUMERIC,$points,SORT_DESC,SORT_NUMERIC,$diff,SORT_DESC,SORT_NUMERIC,$score,SORT_DESC,SORT_NUMERIC,$value); //sortujemy
	}
	$team[$key] = $value; // posortowane druzyny podstawiamy spowrotem do tablicy
}
$i = 0;
while( $i < count($teams) )  {
	if ( $team[$teams[$i]['points']] )  {
		$teams[$i] = array_shift($team[$teams[$i]['points']]); // a teraz podstawiamy do wczesniej posortowanej tablicy druzyny, ktore maja taka sama liczbe punktow, a ktore juz posortowalismy pod wzgledem spotkan bezposrednich, jednoczesnie pozbywamy sie tablicy $team...
	}
	$i++;
}