Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP][MySQL] Losowanie Unikalnego ID
Forum PHP.pl > Forum > Przedszkole
rex
Cześć wszystkim,

Tworzę sobie projekt w którym jedną z funkcji jest system losowania cytatów (taki quiz). Poniższy skrypt działa w sumie w 85% w takim stopniu w jakim chciałbym aby działał, jednakże brakuje tych najistotniejszych 15%.

1. Użytkownik wybiera poziom trudności
2. Biorąc pod uwagę wybrany poziom (lub brak) wyświetla treści adekwatne do wybranego
3. Projekt opiera się o 3 tabele w bazie danych, które posiadają cytaty o trzech stopniach trudności. W przypadku wybrania poziomu łatwego (1 baza) wskazuje nam tylko cytaty z pierwszej bazy itd. W przypadku wybrania całej bazy, system losuje jedną z trzech baz.

Teraz chciałbym przejść do problemu, który napotkałem (jestem samoukiem, stąd chciałbym poradzić się u bardziej doświadczonych osób ). Na wstępie podam skrypt/kod (prędzej jest tylko wyciągnięcie numeru id/loginu użytkownika z sesji, co nie ma wpływu na zaistniały problem:

  1. <?php
  2. // Pobieramy wybrany przez użytkownika poziom trudności cytatu
  3. $ido = (int)$_GET['poziom'];
  4.  
  5. // Jeśli wybrano poziom trudności, ustalamy jego nazwę
  6. if($ido == 1)
  7. $poziomtrudnosci = "Łatwy";
  8. else if($ido == 2)
  9. $poziomtrudnosci = "Średni";
  10. else if($ido == 3)
  11. $poziomtrudnosci = "Trudny";
  12. else if($ido == 4)
  13. $poziomtrudnosci = "Cała baza";
  14. else
  15. $poziomtrudnosci = "Nie wybrano";
  16.  
  17. // Sprawdzamy czy użytkownik rozpoczyna dopiero test czy jest już w jego trakcie
  18. if($ido == NULL)
  19. {
  20. // Tworzymy podstawowe wartości dla użytkownika, który zaczyna test
  21. $button = "";
  22. $cytat = "Wybierz poziom trudności aby rozpocząć!";
  23. }
  24. else
  25. {
  26. // Jeżeli wybrano całą bazę, losujemy ją
  27. if($ido == 4)
  28. {
  29. // Losujemy poziom trudności
  30. $wylosowanabaza = rand(1, 3);
  31. }
  32. else
  33. {
  34. // Ustawiamy poziom trudności taki jak wybrano w formularzu
  35. $wylosowanabaza = $ido;
  36. }
  37.  
  38. // Sprawdzamy, który stopień trudności cytatów wybrano
  39. if($ido == 1 or $ido == 2 or $ido == 3)
  40. {
  41. // Ustalamy bazę danych, którą wybieramy
  42. $bazadanych = "cytaty$wylosowanabaza";
  43.  
  44. // Połączenie z baza danych MySQL
  45. include("polaczenie.php");
  46.  
  47. // Pobieranie najwyższego ID
  48. $pobierzID = "SELECT ID FROM $bazadanych WHERE ID > 0 ORDER BY ID DESC";
  49. $daneID = mysql_query($pobierzID);
  50. $wierszID = mysql_fetch_row($daneID);
  51.  
  52. // Ustalamy zakres losowanego ID
  53. $minID = 1;
  54. $maxID = $wierszID[0];
  55.  
  56. // Losujemy ID
  57. $wylosowanyID = rand($minID, $maxID);
  58.  
  59. // Pobieranie pola test użytkownika z bazy danych
  60. $pobierzpoletest = "SELECT test FROM uzytkownicy WHERE ID = $id";
  61. $danepoletest = mysql_query($pobierzpoletest);
  62. $wierszpoletest = mysql_fetch_row($danepoletest);
  63.  
  64. // Ustalamy nazwę dla naszej zmiennej
  65. $uzytecytaty = "$wierszpoletest[0]";
  66.  
  67. // Ustalamy formę dla wybranego ID na podstawie poziomu trudności
  68. if($ido == 1)
  69. $kod = "L";
  70. else if($ido == 2)
  71. $kod = "S";
  72. else if($ido == 3)
  73. $kod = "T";
  74. else
  75. $kod = "";
  76.  
  77. // Tworzymy kod
  78. $calykod = "$kod$wylosowanyID";
  79. $lancuch = strstr($uzytecytaty, $calykod);
  80.  
  81. if($lancuch === false)
  82. {
  83. echo("Pokazuje cytat, którego nie było");
  84. }
  85. else
  86. {
  87. do
  88. {
  89. // Losujemy kolejne ID
  90. $wylosowanyID = rand($minID, $maxID);
  91.  
  92. $calykod = "$kod$wylosowanyID";
  93. $lancuch = strstr($uzytecytaty, $calykod);
  94. }
  95. while(strstr($uzytecytaty, $calykod));
  96. echo("Wylosowano nowy cytat!");
  97. }
  98.  
  99. // Pobranie danych użytkownika
  100. $szukaj = "SELECT ID, tresc, skrot, ksiega, skrot2, ksiega2 FROM $bazadanych WHERE ID = '$wylosowanyID'";
  101. $dane = mysql_query($szukaj);
  102. $wiersz = mysql_fetch_row($dane);
  103.  
  104. // Zakończenie połączenia z bazą danych
  105. mysql_close($polaczenie);
  106.  
  107. // Tworzymy button dla użytkownika, który jest w trakcie testu
  108. $button = "<a href=\"index.php?strona=sprawdz-odpowiedz&poziom=$ido&pytanie=$wiersz[0]&odp=a\"><button class=\"button-odpowiedz\" type=\"button\">$wiersz[3] ($wiersz[2])</button></a><a href=\"index.php?strona=sprawdz-odpowiedz&poziom=$ido&pytanie=$wiersz[0]&odp=b\"><button style=\"margin-left: 2px;\" class=\"button-odpowiedz\" type=\"button\">$wiersz[5] ($wiersz[4])</button></a>";
  109.  
  110. // Pobieramy cytat
  111. $cytat = "<span style=\"font-weight: bold; \">&bdquo;$wiersz[1]&rdquo;</span><br />";
  112. }
  113. // OD TEGO MIEJSCA SKRYPT JEST TECHNICZNYM ZARYSEM, DORZUCIŁEM GO JEDYNIE ABY OSOBY, KTÓRE ZERKNĄ NA SKRYPT NIE MUSIAŁY MI PISAĆ, ŻE BRAKUJE TEJ CZĘŚCI
  114. else if($ido == 4)
  115. {
  116. // Ustalamy bazę danych, którą wybieramy
  117. $bazadanych = "cytaty$wylosowanabaza";
  118.  
  119. // Połączenie z baza danych MySQL
  120. include("polaczenie.php");
  121.  
  122. // Pobieranie najwyższego ID
  123. $pobierzID = "SELECT ID FROM $bazadanych WHERE ID > 0 ORDER BY ID DESC";
  124. $daneID = mysql_query($pobierzID);
  125. $wierszID = mysql_fetch_row($daneID);
  126.  
  127. // Ustalamy zakres losowanego ID
  128. $minID = 1;
  129. $maxID = $wierszID[0];
  130.  
  131. // Losujemy ID
  132. $wylosowanyID = rand($minID, $maxID);
  133.  
  134. // Pobranie danych użytkownika
  135. $szukaj = "SELECT ID, tresc, skrot, ksiega, skrot2, ksiega2 FROM $bazadanych WHERE ID = '$wylosowanyID'";
  136. $dane = mysql_query($szukaj);
  137. $wiersz = mysql_fetch_row($dane);
  138.  
  139. // Zakończenie połączenia z bazą danych
  140. mysql_close($polaczenie);
  141.  
  142. // Tworzymy button dla użytkownika, który jest w trakcie testu
  143. $button = "<a href=\"index.php?strona=sprawdz-odpowiedz&poziom=$ido&pytanie=$wiersz[0]&odp=a\"><button class=\"button-odpowiedz\" type=\"button\">$wiersz[3] ($wiersz[2])</button></a><a href=\"index.php?strona=sprawdz-odpowiedz&poziom=$ido&pytanie=$wiersz[0]&odp=b\"><button style=\"margin-left: 2px;\" class=\"button-odpowiedz\" type=\"button\">$wiersz[5] ($wiersz[4])</button></a>";
  144.  
  145. // Pobieramy cytat
  146. $cytat = "<span style=\"font-weight: bold; \">&bdquo;$wiersz[1]&rdquo;</span><br />";
  147. }
  148. else
  149. {
  150. // Nie wybrano jeszcze poziomu trudności
  151. }
  152. }
  153. ?>


Problem wygląda następująco i dotyczy tego kawałka kodu:

  1. // Tworzymy kod
  2. $calykod = "$kod$wylosowanyID";
  3. $lancuch = strstr($uzytecytaty, $calykod);
  4.  
  5. if($lancuch === false)
  6. {
  7. echo("Pokazuje cytat, którego nie było");
  8. }
  9. else
  10. {
  11. do
  12. {
  13. // Losujemy kolejne ID
  14. $wylosowanyID = rand($minID, $maxID);
  15.  
  16. $calykod = "$kod$wylosowanyID";
  17. $lancuch = strstr($uzytecytaty, $calykod);
  18. }
  19. while(strstr($uzytecytaty, $calykod));
  20. echo("Wylosowano nowy cytat!");
  21. }
  22.  
  23. // Pobranie danych użytkownika
  24. $szukaj = "SELECT ID, tresc, skrot, ksiega, skrot2, ksiega2 FROM $bazadanych WHERE ID = '$wylosowanyID'";
  25. $dane = mysql_query($szukaj);
  26. $wiersz = mysql_fetch_row($dane);
  27.  
  28. // Zakończenie połączenia z bazą danych
  29. mysql_close($polaczenie);
  30.  
  31. // Tworzymy button dla użytkownika, który jest w trakcie testu
  32. $button = "<a href=\"index.php?strona=sprawdz-odpowiedz&poziom=$ido&pytanie=$wiersz[0]&odp=a\"><button class=\"button-odpowiedz\" type=\"button\">$wiersz[3] ($wiersz[2])</button></a><a href=\"index.php?strona=sprawdz-odpowiedz&poziom=$ido&pytanie=$wiersz[0]&odp=b\"><button style=\"margin-left: 2px;\" class=\"button-odpowiedz\" type=\"button\">$wiersz[5] ($wiersz[4])</button></a>";
  33.  
  34. // Pobieramy cytat
  35. $cytat = "<span style=\"font-weight: bold; \">&bdquo;$wiersz[1]&rdquo;</span><br />";


Kod, który wylosuje ID, sprawdza za pomocą funkcji strstr() czy występuje dany cytat w bazie danych użytkownika (czy został już użyty - każdy użyty jest zapisywany w tabeli użytkowników w polu "test", przyjmuje on formę np. L3, L10, L100 itd. co oznacza L - łatwy, 100 numer ID).

W momencie kiedy mamy do wyboru np. trzy cytaty w bazie danych o stopniu łatwym i tylko ta baza została wybrana, dwa z nich zostały użyte, czyli znajdują się już w zmiennej $uzytecytaty, system poprawnie losuje 3 cytat, który pozostał w bazie danych i nie był użyty w quizie.

Problem pojawia się, kiedy każdy z cytatów został wykorzystany dla wybranego poziomu trudności, wtedy pętla wpada w nieskończoną. Próbowałem opcji break, endwhile niestety nic z tego nie zadziałało w sposób, który byłby rozwiązaniem tego problemu.

W związku z tym, że programistą nie jestem i robię to jako pasję (po prostu uczę się - dlatego też do Was napisałem), domyślam się, że problem może leżeć w konstrukcji pętli, może formie, wyborze rodzaju pętli.

Chciałbym poprosić o pomoc w rozwiązaniu mojego problemu. Za każdą z odpowiedzi będę bardzo wdzięczny.

Pozdrawiam
Piotr
nospor
Po pierwsze nie myl pojec:
tabela
baza danych

Po drugie:
twoje cytaty maja byc w jednej tabeli, ktora dodatkowo bedzie mialo pole: POZIOM
I wszystko nagle staje sie latwiejsze
rex
Pierwotnie tak była skonstruowana baza. Podpowiedz zatem w jaki sposób wyodrębnić min i max dla konkretnego poziomu.

Zakładając Twój pomysł z polem "poziom". Jak ustalić minimalną i maksymalną wszystkich cytatów dla poziomu danego przy założeniu, że:

1 | Cytat | Łatwy
2 | Cytat | Średni
3 | Cytat | Średni
4 | Cytat | Trudny
5 | Cytat | Łatwy
6 | Cytat | Trudny
7 | Cytat | Łatwy
8 | Cytat | Łatwy
9 | Cytat | Trudny
10 | Cytat | Średni

Oczywiście nie jest to forma, jedynie przykład.

Albo w przypadku kiedy byłaby baza ale każdy cytat byłby o jednakowym stopniu trudności. Biorąc pod uwagę pętlę do while, którą użyłem w jaki sposób zmienić jej konstrukcje (lub zastosować inną może), która wykona tą samą funkcję ale w przypadku wylosowania wszystkich możliwych cytatów, zwróci komunikat: Wylosowano już wszystkie dostępne cytaty, koniec gry.
nospor
Masz jeszcze skopana tabele z cytatami, ktore user juz widzial. ma byc tabela:

USER_CYTAT z polami:
ID_USER, ID_CYTAT

Potem losowanie jest juz banalne:

select * from CYTATY where ID not in (SELECT ID_CYTAT from USER_CYTAT where ID_USER=id_usera) order by rand() limit 3

To tylko szybki szkic. Oczywiscie musi dojsc warunek na poziom itp ale idea bedzie wlasnia taka. Mozna jeszcze usprawnic losowanie bo order by rand() do optymalnych nie nalezy.
rex
Okej, dzięki za podpowiedź, wieczorem pewnie zajmę się i spróbuje ponownie przerobić bazę.

Mam jeszcze zapytanie odnośnie pętli, której użyłem. Co w niej jest nie tak i jak mogłaby ona wyglądać aby spełniła swoją funkcję (jak już coś robię to na przyszłość być może się przyda ta wiedza).
nospor
Nie chce mi sie analizowac tej calej sieczki, no ale jak nie ma juz nic do wylosowania to sie zapetlasz. Musisz sprawdzic czy jest cos do losowania czy nie i jak nie to robic break.
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.