Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP][MySQL] Skrypt do zarządzania turniejami (tenisowymi)
Forum PHP.pl > Forum > Przedszkole
jg44
Witam,
nie wiem, czy to jest najlepsze miejsce, ale napiszę tutaj. Potrzebuję napisać skrypt do obsługi turniejów tenisowych. Chodzi o to, że jest to część portalu tenisowego, na którym zarejestrowani użytkownicy będą mogli zapisać się na turniej, i potem grać w nim. smile.gif Idea jest taka, że ludzie zapisują się na turniej, a po zamnknięciu zapisów losowane są pary do gry. Jeśli ilość zapisanych będzie różna od 2^n, to zorganizowany ma zostać turniej przedwstępny "eliminujący" nadmiar zawodników (nadmiar to liczba, o jaką liczba zapisanych przewyższa najbliższą potęgę 2, czyli jeśli zapisze się np. 41 osób, to najbliższą potęgą 2 jest 32, czyli trzeba "wyeliminować" 9 osób, jeśli 53, to eliminacja 21, itd. ...).
Pytanie jest następujące: jak się za to zabrać? Bo jeśli będzie nieparzysta liczba ludzi do eliminacji, to trzeba będzie bawić się w dzikie karty, żeby obsłużyć tych, którzy zostaną bez pary do gry. Dodatkowe pytanie jest, jak zarządzać tymi, którzy grają (tzn. jak zaprogramować, żeby zwycięzca pierwszego meczu grał później ze zwycięzcą drugiego, itd.).
Nie oczekuję gotowego kodu, tylko proszę o wskazówki i podpowiedzi, po prostu jakąś ideę.
Robert3d
Moim zdaniem masz tu problem nie natury języka czy umiejętności programowania co problem matematyczny a dokładnie algorytmiczny.
Ja rozpisał bym sobie to na drobne zadania i spróbował napisać na kartce pseudokod aczkolwiek

1
Rejestracja
2
lista użytkowników przetasować podzielić na pol i przypasować
3
co do 2^n no musisz jakoś to zapisać ale o 2 w nocy nie dam rady tego trzasnąć
eliminacje przedwstępne mogą odbywać się na zasadzie koszyków i punktacji X najlepszych wychodzi z koszyka znasz to z piłki nożnej
4
Jak zrobi drzewo 1 koszyk rozgrywa z koszykiem 2 i idzie identycznie jak drzewko jak się skończą łupać w 1 i 2 koszyku będzie 1i2 VS 3i4

Bez rozbicia tego na drobne części rozpisania sobie co każda klasa ma robić to możesz się pogubić biggrin.gif .


Pewnie nie pomogłem ale może poukładałem coś dla osób które napiszą po mnie?
jg44
Robert3d, to wygląda całkiem dobrze. wink.gif
Teraz pytanie, jak sobie poradzić z tymi potęgami 2? Bo jeśli przyjmiemy, że przykładowo będzie 31 osób, to problem pojawi się już w pierwszym etapie gry, bo ten 31 gracz nie będzie miał pary. Jeśli np. będzie tylko 14 osób, to problem pojawi się w drugim etapie (bo po pierwszym etapie zostanie 7 os.). Jak wymyślić algorytm, który będzie panował nad tym wszyskim i zapobiegnie posypaniu się tego wszystkiego... ?
Robert3d
hmm może

według wikipedi
"
Zasadniczo system pucharowy stosuje się w rozgrywkach, których liczba uczestników jest potęgą cyfry dwa, tj.: 4, 8, 16, 32, 64 i 128. W innych przypadkach najczęściej "wirtualnie" uzupełnia się listę uczestników do potęgi cyfry dwa, skutkiem czego część uczestników w pierwszej rundzie ma wirtualnego przeciwnika, czyli tzw. wolny los i bez gry przechodzi do następnej fazy rozgrywek. W systemie pucharowym liczba wszystkich gier (G) jest mniejsza od liczby uczestników (N):

G = N ? 1
"


i zanim zgarniesz zawał link for you
http://www.mif.pg.gda.pl/kmd/materialy/sem...ejeTenisowe.pdf
jg44
Ale ekstra, szukałem i nie znalazłem (widocznie źle szukałem). smile.gif
Co prawda, mój promotor uczepił się tych eliminacji przedwstępnych, ale może uda mi się go przekabacić, że to nie jest najlepszy pomysł. smile.gif
Dziękuję, Robert3d!
Robert3d
Hmm nom promotor smile.gif na pewno sympatyczny i uda Ci się go przekonać smile.gif

Pozrawiam
Niktoś
Jak promotor się nie zgodzi ,to dla 31 gracza ,który nie będzie miał pary zaproponuj i tu uwaga "Ściana do Tenisa Ziemnego"

A tak serio.Jeśli graczy jest 31 ,to aby wyeleminować tego jednego to wstępna eliminacja powinna wyglądać gra każdy,z każdym-odpada najsłabszy,który zdobył najmniejszą ilość wygranych turniejów.A później już idzie normalnym tokiem.
Jeśli graczy jest liczba parzysta -to pomijasz eliminację wstępną.
Robert3d
Dla 100 drużyn może być problem każdy z każdym i dlatego koszyki by zmniejszyć konieczność gry każdy z każdym

Zawsze można rozstrzelać jedną drużynę i tym samym mamy liczbę parzystą smile.gif dla 2K + 1 tratata i mamy 2K smile.gif
jg44
Nie, aż tak daleko wybiegać nie będziemy, sam powiedział, że trzycyfrowa liczba zawodników to przesada. smile.gif
Więc chyba przyjmę dla ułatwienia, że 64 to jest maksymalna liczba zapisanych i więcej nie zapisujemy na turniej. A jeśli będzie <64, to działamy według powyższych wskazówek. smile.gif
Jeszcze raz dziękuje Panowie! smile.gif
Robert3d
Ja i tak twierdzę i będę twierdził że 2k + 1 to należy 1 rozstrzelać wtedy mniej pisania Lkingsmiley.png hihi
Dobra bo jeszcze ktoś powie że spamuje smile.gif

Ale swoja droga zdecydowałeś się na "koszyki"?
jg44
No tak smile.gif
Tak, koszyki wyglądają najrozsądniej, prawdopodobnie zrobię po 6 osób na koszyk + x osób w ostatnim koszyku (gdzie x < 6).
Pewnie tu jeszcze nieraz przemówię, jak będę miał problemy implementacyjne (a pewnie będę miał). wink.gif
Orzeszekk
to ogolnie zalezy od tego jaki system turniejowy chcesz zaimplementowac. w klasycznym elimination tournament jest to tak:

liczba ludzi jest zawsze równana do potęgi dwójki. Przynajmniej ja tak zrobilem u siebie w systemie turniejowym.

Te osoby które nie mają pary przechodzą do kolejnej rundy za darmo.

Gracze są rozrzucani za pomocą algorytmu który ich miesza ze sobą: pierwszy z ostatnim, drugi z przedostatnim, a jak była wieksza ilosc graczy to sie to tam jakos komplikowalo... w każdym razie jest tak jak powinno być bo algorytm pisałem tak by się pokrywał z drzewkami generowanymi przez esl.com albo bracketgenerator.


tak wyglada przykladowe drzewko dla 5 druzyn.
to na dole to koszyk przegranych czekajacy na spadających graczy z dołu

  1. <?php
  2. /**
  3.  * Stała oznaczająca że teraz pobieramy górny środek
  4.  */
  5. define('UPORDOWN_UP', true);
  6. /**
  7.  * Stała oznaczająca że teraz pobieramy dolny środek
  8.  */
  9. define('UPORDOWN_DOWN', false);
  10. /**
  11.  * Rekord uzywany do przekazania lewego i prawego końca tabelki która jest podtabelką głównej tabelki
  12.  */
  13. class Bounds
  14. {
  15. /**
  16.   * Początek
  17.   * @var int
  18.   */
  19. public $beginning;
  20. /**
  21.   * Koniec
  22.   * @var int
  23.   */
  24. public $ending;
  25. }
  26. /**
  27.  * Ta klasa zawiera algorytm ukladajacy liste graczy i zwracajacy gotowe ułożenie graczy do bitew tak by na siebie nie wpadali.
  28.  */
  29. class TeamsPositionAlgorithm
  30. {
  31. /**
  32.   * Przechowuje liczbe par drużyn do ułożenia
  33.   * @var int
  34.   */
  35. protected $howMuchPlayers;
  36. /**
  37.   * Informacja czy teraz górny czy dolny środek
  38.   * @var bool
  39.   */
  40. protected $upOrDown;
  41. /**
  42.   * Ilość poziomów w układanym tournamencie (rund)
  43.   * @var int
  44.   */
  45. protected $levels;
  46. /**
  47.   * Wynik zwrocony przez generator ciągu
  48.   * @var array
  49.   */
  50. public $generatorResult;
  51. /**
  52.   * Koncowy wynik - pary druzyn ulozone w odpowiedniej kolejnosci gotowe do przelozenia na bitwy
  53.   * @var array
  54.   */
  55. public $result;
  56. /**
  57.   * Konstruktor, przelicza wszystko, pozniej nalezy jedynie uzyc metody getPairsOfPlayers(). chuj
  58.   * @param int $levels ilość poziomów w turnieju
  59.   */
  60. public function __construct($levels)
  61. {
  62. /* Ponieważ dla 16 graczy będzie 8 bitw, musimy odjąć jedną potęgę */
  63. $this->levels = $levels;
  64. /* Obliczamy ilość drużyn dla ktorych trzeba cos policzyc (2x mniej niz ilosc bitw) */
  65. $this->howMuchPlayers = pow(2, $this->levels);
  66. /* Przelicz wszystko */
  67. $this->generatePositions();
  68. }
  69. /**
  70.   * Metoda zwraca tablicę podanych drużyn poukładaną specjalnym algorytmem, aby gracze na siebie nie wpadali.
  71.   * Tablica musi być wcześniej posortowana wedle rankingów malejąco.
  72.   * @param unknown_type $teams
  73.   * @return array <Team>
  74.   */
  75. public function getProperlyPlacedTeams($teams)
  76. {
  77. $result = null;
  78. /* Dla każdego wyniku z generatora */
  79. foreach ($this->generatorResult as $firstPlayer)
  80. {
  81. if ($firstPlayer)
  82. {
  83. if ($teams[($firstPlayer - 1)])
  84. {
  85. $result[] = $teams[($firstPlayer - 1)];
  86. } else
  87. {
  88. $teamWalkowerValue = _team_walkower;
  89. $result[] = $teamWalkowerValue;
  90. }
  91. }
  92. }
  93. return $result;
  94. }
  95. /**
  96.   * Metoda znajduje środek (górny lub dolny w zależności od tego co mówi globalny przełącznik)
  97.   * @param int $beginning indeks poczatku przetwarzanej czesci tabelki
  98.   * @param int $ending indeks konca przetwarzanej czesci tabelki
  99.   */
  100. private function findCenter($beginning, $ending)
  101. {
  102. $calculatedCenter = (int) (($ending - $beginning) / 2);
  103. $calculatedCenter = $beginning + $calculatedCenter;
  104. if ($this->upOrDown == UPORDOWN_DOWN)
  105. {
  106. $calculatedCenter++;
  107. }
  108. return $calculatedCenter;
  109. }
  110. /**
  111.   * Metoda oblicza krawedzie kolejnego poziomu
  112.   * @param unknown_type $whichPart
  113.   * @param unknown_type $allParts
  114.   */
  115. private function countBounds($whichPart, $allParts)
  116. {
  117. $result = new Bounds();
  118. $lengthOfPart = $this->howMuchPlayers / $allParts;
  119. $result->beginning = ($whichPart - 1) * $lengthOfPart + 1;
  120. $result->ending = ($whichPart) * $lengthOfPart;
  121. return $result;
  122. }
  123. /**
  124.   * Metoda przestawia zmienną raz parzyste raz nieparzyste
  125.   */
  126. private function swapUpOrDown()
  127. {
  128. if ($this->upOrDown == UPORDOWN_UP)
  129. $this->upOrDown = UPORDOWN_DOWN;
  130. else
  131. $this->upOrDown = UPORDOWN_UP;
  132. }
  133. /**
  134.   * Metoda generuje pozycje dla jednego poziomu
  135.   */
  136. private function generatePositions()
  137. {
  138. $this->upOrDown = UPORDOWN_DOWN;
  139. $this->generatorResult = null;
  140. $this->generatorResult[] = null;
  141. $this->generatorResult[] = 1;
  142. $this->generatorResult[] = $this->howMuchPlayers;
  143. if ($this->levels > 1)
  144. {
  145. $this->generatorResult[] = $this->findCenter(1, $this->howMuchPlayers);
  146. $this->swapUpOrDown();
  147. $this->generatorResult[] = $this->findCenter(1, $this->howMuchPlayers);
  148. $this->swapUpOrDown();
  149. }
  150. if ($this->levels > 2)
  151. {
  152. for ($secondaryCounter = 1; $secondaryCounter < $this->levels - 1; $secondaryCounter++)
  153. {
  154. $auxAlgorithm = new TeamsPositionAlgorithm($secondaryCounter);
  155. $queueOfCalls = $auxAlgorithm->generatorResult;
  156. $countMax = count($queueOfCalls) - 1;
  157. for ($count = 1; $count <= $countMax; $count++)
  158. {
  159. $bounds = $this->countBounds($queueOfCalls[$count], $countMax, $this->howMuchPlayers);
  160. $this->generatorResult[] = $this->findCenter($bounds->beginning, $bounds->ending,
  161. $this->upOrDown);
  162. $this->swapUpOrDown();
  163. }
  164. for ($count = $countMax; $count > 0; $count--)
  165. {
  166. $bounds = $this->countBounds($queueOfCalls[$count], $countMax, $this->howMuchPlayers);
  167. $this->generatorResult[] = $this->findCenter($bounds->beginning, $bounds->ending,
  168. $this->upOrDown);
  169. $this->swapUpOrDown();
  170. }
  171. }
  172. }
  173. }
  174. }
  175. ?>


aby skorzystać z algorytmu i wygenerować ciąg dla ułożenia graczy wystarczy uzyc: (liczba poziomów to ilosc rund w turnieju, czy wykładnik potęgi liczby oznaczajacej ilosc graczy: np dla 8 miu graczy jest to 3)

$teamposition=new TeamPositionAlgorithm($liczbaPoziomow);
$teamposition->generatePositions();
$result=$teamposition->generatorResult();

dla parametru wejsciowego 3 parametrem wyjsciowym będzie tablica: 1, 8, 7, 2, 6, 3, 5, 4.
teraz wystarczy tylko posortowac twoich graczy wedle rankingu, i ułożyc ich w pary tak jak tablica mówi.

jak masz pięc graczy: gracz1...gracz5 to ulozenei w pary bedzie nastepujace:

1. gracz1-z nikim
2. nikt-gracz2
3. nikt-gracz3
4. gracz4-gracz5


natomiast gdybys chcial dodac koszyk przegranych to trzeba dodać do głównego drzewka jeszcze jeden poziom na korym bedzie rozegrany mecz miedzy zwyciezca glownego turnieju i zwyciezca koszyka przegranych.

jak chcesz to moge ci gotowca sprzedac ale nie sadze bys byl zainteresowany biggrin.gif
jg44
Orzeszekk, dzięki, ale odkupieniem nie jestem zainteresowany. To co podałeś jest super, chociaż jest to raczej skomplikowane. smile.gif
Ogólnie myślałem o czymś prostszym.
Pomysł z koszykami jest dobry, tylko jest jednak pewien problem. Z racji, że liczba zapisanych w każdym turnieju będzie raczej inna, to chyba nie będzie się dało zaimplementować tego koszykami, bo prawie zawsze trzeba będzie pobierać z nich inną liczbę zwycięzców. Przykładowo, jeśli mamy 33 osoby i załóżmy tworzymy koszyki 6-osobowe, to potrzebujemy 5 takich koszyków 'pełnych' + ostatni koszyk 3-osobowy; żeby osiągnąć 32 osoby do turnieju, musielibyśmy w tym przypadku tylko 1 osobę odesłać do domu, więc widać, że cała koncepcja się nie sprawdza. Z kolei dla 30 osób z pięciu koszyków bierzemy po 3 osoby i z ostaniego tylko jedną, dla 14 osób po 3 osoby z dwóch koszyków i 2 osoby z ostatniego, itd. ... Algorytm musiałby być bardzo 'elastyczny'.
Najprościej chyba byłoby olać te potęgi 2, wziąć listę zapisanych, podzielić na dwa i dopasować pary. Po pierwszym etapie połowa odpadnie i znowu tych, którzy wygrali na 2, skompletować pary, itd. A jeśli ktoś zostanie samotny, to dziką kartę mu i tyle.
Robert3d
No to już będzie naprawdę kod prosty jak drut pytanie czy nie za prosty jak dla Promka?
jg44
Tak w gruncie rzeczy to dał mi do zrozumienia, że jakieś nowatorskie albo 'algorytmiczne' rozwiązanie szczególnie go nie interesuje - byle działało tongue.gif
Poza tym trochę przegiął z tymi turniejami - został miesiąc na oddanie pracy, a on mi dopiero tydzień temu o tym powiedział - mógł to zrobić znacznie wcześniej, byłem u niego na początku października, a nawet raz przed wakacjami i nic.
Poza tym ten pomysł turniejów przedwstępnych jest naprawdę nieprzemyślany - popatrz sam: jeśli zapisuje się 17 osób na turniej, to zgodnie z jego pomysłem będziemy eliminować nadmiar, czyli rozgrywać turniej, dzielić na koszyki tylko po to, żeby odprawić jedną osobę? A jak zapisze się 31 osób? Eliminowanie też bez sensu, bo wystarczy dać jednemu dziką kartę, jest 32 i wszyscy zadowoleni...
Tak przynajmniej ja to widzę.
Gość
Szukam czegos podobnego plan turnieju
Jezeli mozesz zrealizowac lub chcesz sprzedac, napisz.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.