Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP][MySQL]Algorytm przyporządkowujący losowo współrzędne na obszarze
Forum PHP.pl > Forum > PHP
dexter00
Witam,

No więc z php rozpocząłem swoją przygodę nie dawno (na początku października), w tej chwili pracuje na frameworku- Codeigniter, i stanąłem przed takim zadaniem muszę napisać w php i mysql algorytm który będzie przypisywał mi trzy współrzędne X,Y,Z dodawanego obiektu (punktu) na obszarze (np. obrazku) o wielkości 2560x1240 px . A teraz do rzeczy:

Dane:
punkt (0,0,0) znajduję się w lewym górnym rogu grupy powierzchni roboczej.
X - szerokość
Y- wysokość
Z- losowa wartość od 1 do 10
area- grupa do której należy obiekt (od 1 do 20 )

baza zawierająca dane obiektu:


obszar jest podzielony na 20 części, każda ma swoją gęstość która będzie miała wyliczana dzięki danym z bazy (ilość wystąpień np 1 w kolumnie area) ,


No i na czym polega trudność - przy dodawaniu nowego obiektu muszę zbadać gęstość każdego obszaru (1-20) następnie wybrać ten z najmniejsza gęstością i przypisać ją do obiektu, przypisać w obszarze (np.2) losowe współrzędne (z zakresu X- 0:512 i Y - 0:248 Z- losowo od 1 do 10).

Nie wiem jak się do tego wszystkiego zabrać, jakieś podpowiedzi z jakich bibliotek, funkcji php,mysql mógłbym skorzystać przy tym zadaniu?

Z góry dziękuję za pomoc smile.gif



b4rt3kk
Nie wiem czy dobrze zrozumiałem, ale obszar o najmniejszej gęstości (tj. najmniejszej liczby przypisanych punktów) możesz zrealizować jednym prostym zapytaniem.

  1. SELECT area, COUNT(id) AS ile FROM star GROUP BY area ORDER BY ile ASC LIMIT 0,1


Jako wynik otrzymasz nazwę (identyfikator) obszaru oraz liczbę przypisanych punktów.

Nie wiem jak ustanawiasz te obszary, ale jeśli np. w bazie są współrzędne początku i końca obszaru, to teraz je pobierasz na podstawie wyniku poprzedniego zapytania. Załóżmy, że otrzymujesz już taki wynik:

  1. $x0, $x1, $y0, $y1; // współrzędne obszaru
  2.  
  3. // można teraz wylosować współrzędne nowego punktu
  4.  
  5. $newX = mt_rand($x0, $x1);
  6. $newY = mt_rand($y0, $y1);
  7. $z = mt_rand(0,10);
  8.  
  9. // sprawdzasz znów bazę czy punkt takowy już nie istnieje
  10. $query = "SELECT COUNT(id) FROM star WHERE x = '$newX' AND y = '$newY'";
  11. // jeśli punkt istnieje, losujesz ponownie współrzędne, a jeśli nie to możesz go zapisać do bazy


I to chyba tyle?
dexter00
Super to co napisałeś nie do końca działa ale pomogło mi zrozumieć o co chodzi, po przeszukaniu googla powstało coś takiego:

  1. public function addStar() {
  2.  
  3. // znajdowanie najmniejszej gęstości poprzez sprawdzenienie ile razy występuje dany rekord np. obszar 1
  4. for ($i = 1; $i <= 20; $i++) {
  5. $news_count[$i] = $this -> db -> query("SELECT COUNT(*) AS like" . $i . " FROM star WHERE area LIKE " . $i . "") -> row_array();
  6.  
  7. }
  8. //otrzymuje tablice 1 do 20 gdzie mam ilość wystąpień:
  9. /*Array
  10. (
  11.   [1] => Array
  12.   (
  13.   [like1] => 0
  14.   )
  15.  
  16.   [2] => Array
  17.   (
  18.   [like2] => 0
  19.   )
  20.  
  21.   [3] => Array
  22.   (
  23.   [like3] => 0
  24.   )
  25.  
  26.   [4] => Array
  27.   (
  28.   [like4] => 0
  29.   )
  30.  
  31.   [5] => Array
  32.   (
  33.   [like5] => 1
  34.   )
  35. itd...
  36.  */
  37.  
  38.  
  39. // wybieram najmniejsza wartość
  40. $choose = min(array_filter($news_count));
  41.  
  42. //zapisuje do zmiennej v indeks tablicy
  43. $v = array_keys($choose);
  44. $area = questionmark.gifquestionmark.gifquestionmark.gifquestionmark.gifquestionmark.gifquestionmark.gifquestionmark.gifquestionmark.gif co tutaj
  45.  
  46. /* koniec konców zmienna v ma zapisaną ostatni obszar z najmniejszą gęstością,
  47. * i tu mam problem jak zrobić żeby zmienna v nie była tablicą
  48. * tylko miała wartość tak jak poniżej np 20 bez słowa like, no i jak zrobić że
  49. * kiedy mam dwa obszary które mają np 0 jak losować z pośród nich
  50. *
  51. *
  52. * Zwracana tablica:
  53. Array
  54. (
  55. [0] => like20
  56. )*/
  57.  
  58. $newX = mt_rand(0, 512);
  59. $newY = mt_rand(0, 248);
  60. $newZ = mt_rand(0, 10);
  61.  
  62. // na koniec zwracam wartości potrzebne do zapisania w bazie danych
  63. //oraz sprawdzam czy taka gwiazdka juz nie istnieje
  64.  
  65. $query = $this -> db -> query("SELECT COUNT(id) FROM star WHERE x = ".$newX." AND y = ".$newY."") -> row_array();
  66.  
  67. if ($query['COUNT(id)'] > 0) {
  68.  
  69. echo "Taka gwiazdka istnieje sprĂłbuj jeszcze raz!";
  70.  
  71. } else {
  72. return array($newX, $newY, $newY, $area);
  73.  
  74.  
  75. }
  76.  
  77. }





No i nie wiem tylko jak rozwiązać problem w miejscu gdzie zaczyna się komentarz linia 46.

Pozdrawiam smile.gif
b4rt3kk
  1. public function addStar() {
  2.  
  3. // nie jest potrzebna żadna tablica, pojedyncze zapytanie da od razu pożądany wynik (spróbuj)
  4.  
  5. $resource = $this -> db -> query("SELECT COUNT(*) AS ile, area FROM star GROUP BY area ORDER BY ile ASC LIMIT 0,1") -> row_array();
  6.  
  7. // jeśli dobrze zrozumiałem w jaki sposób przekazujesz wyniki zapytania to poniższe wyświetli liczbę punktów w obszarze, oraz nazwę obszaru
  8. echo 'Liczba: '.$resource['ile'].'<br/>';
  9. echo 'Nazwa: '.$resource['area'];
  10.  
  11. $newX = mt_rand(0, 512);
  12. $newY = mt_rand(0, 248);
  13. $newZ = mt_rand(0, 10);
  14.  
  15. // na koniec zwracam wartości potrzebne do zapisania w bazie danych
  16. //oraz sprawdzam czy taka gwiazdka juz nie istnieje
  17.  
  18. $query = $this -> db -> query("SELECT COUNT(id) FROM star WHERE x = ".$newX." AND y = ".$newY."") -> row_array();
  19.  
  20. if ($query['COUNT(id)'] > 0) echo "Taka gwiazdka istnieje sprĂłbuj jeszcze raz!"; else return array($newX, $newY, $newY, $area);
  21.  
  22. }


Co do Twojego rozwiązania to tak:

- w zapytaniu dajesz alias like$i co skutkuje tym co skutkuje:

  1. "SELECT COUNT(*) AS ile FROM star WHERE area LIKE " . $i . ""


Wykonujesz to w takiej pętli, że indeks tablicy wynikowej to również identyfikator dla area.

I myślę, że nie ma co losować spośród kilku co mają identyczną wartość minimalną, bierzesz pierwszą z brzegu, to co wybierze skrypt i po dodaniu punktu to już nie będzie area z min, także nie będzie brało jej pod uwagę i tak po kolei.
dexter00
Super wielkie dzięki za pomoc! thumbsupsmileyanim.gif a wiesz może co zrobić z obszarami które na początku mają wartość 0 (w sensie nie ma żadnego wpisu gdzie area ma wartość np.1) bo zapytanie nie bierze ich pod uwagę sad.gif
b4rt3kk
Zapytanie nie bierze ich pod uwagę, bo one nie istnieją w Twojej tabelce, bo są tam tylko punkty, a area tylko przy okazji. To już nieco utrudnia sprawę. Chyba najprościej było utworzyć tabelkę obszarów, bo trudno żeby zapytanie pobrało coś czego nie ma.
dexter00
No i teraz moje tablice mają sens , już wszystko działa , tylko zastanawiam się czy to nie będzie za bardzo obciążało serwera bo pętla for wykonuje w sumie 20 zapytań do bazy smile.gif


  1. public function addStar() {
  2.  
  3. // znajdowanie najmniejszej gęstości poprzez sprawdzenienie ile razy występuje dany rekord np. obszar 1
  4. for ($i = 1; $i <= 20; $i++) {
  5. $news_count[$i] = $this -> db -> query("SELECT COUNT(*) AS like" . $i . " FROM star WHERE area LIKE " . $i . "") -> row_array();
  6.  
  7. }
  8. //otrzymuje tablice 1 do 20 gdzie mam ilość wystąpień:
  9.  
  10. // wybieram najmniejsza wartość
  11. $choose = min(array_filter($news_count));
  12.  
  13. //zapisuje do zmiennej v indeks tablicy
  14. $v = array_keys($choose);
  15. //$area zwraca mi numer obszaru
  16.  
  17. $area = substr($v[0], 4, 10);
  18. $newX = mt_rand(0, 512);
  19. $newY = mt_rand(0, 248);
  20. $newZ = mt_rand(0, 10);
  21.  
  22. // na koniec zwracam wartości potrzebne do zapisania w bazie danych
  23. //oraz sprawdzam czy taka gwiazdka juz nie istnieje
  24.  
  25. $query = $this -> db -> query("SELECT COUNT(id) FROM star WHERE x = ".$newX." AND y = ".$newY."") -> row_array();
  26.  
  27. if ($query['COUNT(id)'] > 0) {
  28.  
  29. echo "Taka gwiazdka istnieje spróbuj jeszcze raz!";
  30.  
  31. } else {
  32. return array($newX, $newY, $newZ, $area);
  33. }
  34.  
  35. }
b4rt3kk
COUNT(*) działa bardzo szybko, użytkownik nie zauważy żadnej różnicy, jeśli będzie to tylko 20 zapytań. Jeśli się rozkręcisz do 10 000 czy 100 000 to wtedy czas się nieco wydłuży.
dexter00
Heh jednak nie działało już poprawiłem smile.gif zastanawiam się czy spłaszczenie tablicy nie można zrobić w inny ładniejszy sposób smile.gif

  1. public function addStar() {
  2.  
  3. // znajdowanie najmniejszej gęstości poprzez sprawdzenienie ile razy występuje dany rekord np. obszar 1
  4. for ($i = 1; $i <= 20; $i++) {
  5.  
  6. $news_count[$i] = $this -> db -> query("SELECT COUNT(*) AS like" . $i . " FROM star WHERE area LIKE " . $i . "") -> row_array();
  7.  
  8. }
  9.  
  10. //spłaszczam tablice
  11. $a=1;
  12. foreach($news_count as $k=>$v) foreach($v as $k2=>$v2) { $splash[$a] = $v2; $a++; } var_export($splash ,true);
  13.  
  14. // wybieram najmniejsza wartość
  15. $i_min = '1';
  16. for ( $i = 1; $i <= 20; $i++ ){
  17. if ( $splash[$i] < $splash[$i_min] )
  18. $i_min = $i;
  19. }
  20. $area = $i_min;
  21.  
  22. //generuje losowe położenie
  23. $newX = mt_rand(0, 512);
  24. $newY = mt_rand(0, 310);
  25. $newZ = mt_rand(0, 10);
  26.  
  27. // na koniec zwracam wartości potrzebne do zapisania w bazie danych
  28. //oraz sprawdzam czy taka gwiazdka juz nie istnieje
  29.  
  30. $query = $this -> db -> query("SELECT COUNT(id) FROM star WHERE x = " . $newX . " AND y = " . $newY . "") -> row_array();
  31.  
  32. if ($query['COUNT(id)'] > 0) {
  33.  
  34. echo "Taka gwiazdka istnieje spróbuj jeszcze raz!";
  35.  
  36. } else {
  37. return array($newX, $newY, $newZ, $area);
  38.  
  39. }
b4rt3kk
Możesz ją spłaszczyć w łatwiejszy sposób. Mianowicie, trzeba zacząć od zmodyfikowania zapytania:

  1. for ($i = 1; $i <= 20; $i++) {
  2. $news_count[$i] = $this -> db -> query("SELECT COUNT(*) AS ile FROM star WHERE area LIKE " . $i . "") -> row_array();
  3. $flat[$i] = $news_count[$i]['ile'];
  4. }


Wszystko odbywa się w jednej pętli. I teraz $i to identyfikator obszaru (area), natomiast wartość $flat[$i] to liczba punktów w tym obszarze.
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.