• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 1 głosów - średnia: 5
  • 1
  • 2
  • 3
  • 4
  • 5
Sandbox 1: C++ to nie rozmiar stanika :-)
#1
Witam serdecznie!
Sandbox to po polsku piaskownica. Będę tu w miarę wolnego czasu zamieszczał tutoriale z rozwiązaniami bardzo banalnych, acz ciekawych logicznie problemów, z którymi sam się kiedyś  przecież borykałem. Może to będzie przyczynkiem do powstania nowego działu na forum - czas pokaże.
Zatem Sandbox 1: problem LOTTO :-)
Każdy wie co to i pewnie potrafi za pomocą kilku(nastu) linijek kodu wygenerować pojedynczy zakład 6 losowych liczb, prawda? Całkiem proste. Kopmy dalej - te liczby nie mogą się powtórzyć - wszak losujemy jak w LOTTO :-)
Co trzeba zatem zrobić - ano trzeba po wylosowaniu każdej kolejnej liczby,najlepiej w pętli sprawdzić, czy aby taka już się nie powtórzyła. Jeśli tak,to kolejne losowanie ... i kolejne sprawdzanie powtórzeń - tak długo aż żadna z wylosowanych 6  liczb się nie powtórzy.
Można to rozwiązać na kilka sposobów, teoretycznie najlepsza jest rekurencja... ale może się zaraz okazać, że to jednak nie jest najlepszy pomysł. Dlaczego? o tym potem,na końcu tego tutoriala. 
Drugi sposób to zagnieżdżone pętle, przynajmniej dwie. ja wybrałem for dla generacji 6-ciu liczb i while dla sprawdzania warunku powtórzenia.
Uuuuppppsssss, własnie zdałem sobie sprawę z faktu, że być może ktoś z nas może się czuć dotknięty tym, że poruszam tu tak banalne tematy. Z góry przepraszam, ale to w końcu piaskownica jest - tak czy nie?
Dobra dość tego belferskiego tonu czas na kod:
Kod:
// przykladowy programik lotto (generuje paczki po 5 zakładów) ...by wojtekizk
int z,i,j; // zmienne iteracyjne
int l[6];  // tablica 6 wylosowanych liczb w pojedynczym zakładzie
int err;   // zmienna kontrolujaca czy wcześniej w tym samym zakladzie nie powtórzyła się już liczba
int k=0;   // duża paczka po 100 zakladów, potem  odstęp (na serialu)
void setup()
{
 Serial.begin(9600);
 Serial.println("Lotto 5 zakladow");
 randomSeed(analogRead(0));     // inicjalizacja generatora liczb losowych
}
void loop()
{
 for(z=0;z<5;z++)               // losujemy 6 liczb dla każdego zakładu
 {
 l[0]=random(1,50);             // losowo generujemy pierwszą liczbę, pierwsza bez problemu
 Serial.print(l[0]);            // wyświetlamy ją
 Serial.print(" ");             // spacja
 for(i=1;i<6;i++)               // pętla do losowania pozostałych 5-ciu liczb
   {
   err=1;                       // zmienna pomocnicza err=1 - tu celowo ustawiono na 1
                                // jeśli err=1 to oznacza że wylosowana liczba powtórzyła się
                                // jeśli err=0 to jest ok, można losować następną
                               
   l[i]=random(1,50);           // losujemy kolejną, i-tą liczbę
   while (err==1)               // jak długo err==1 to wykonuj sprawdzanie liczb, czy się przypadkiem
                                // nie powtórzyły
     {
     err=0;                     // ustaw err=0, bo zakładamy wstępnie, że liczba się nie powtórzyła,
                                // a w pętli sprawdzimy czy mamy rację :-)
     for(j=0;j<i;j++)           // pętla do sprawdzania powtórzeń od 0 do itej - liczby, bo trzeba
                                // sprawdzić w pętli np. czy l[3]==l[0], potem czy l[3]==l[1]itd.
       {
       if(l[j]==l[i])           // jeśli właśnie wylosowana jest taka sama jak któraś poprzednia
         {
         l[i]=random(1,50);     //to losuj ponownie
         err=1;                 // i ustaw err=1 (bo wczesniej err było 0) i program nie wyjdzie
                                // z pętli while, czyli ponownie sprawdzi, co wylosowano :-)
         }                      // koniec if-a
       }                        // koniec pętli for, zatem wylosowano poprawną liczbę
     }                          // koniec pętli while, bo po wylosowaniu kolejnej liczby err=0  
 Serial.print(l[i]);            // wyświetlamy wylosowaną liczbę liczbę
 Serial.print(" ");             // spacja
 }
 Serial.println("      ");++k;  // odstęp dla kolejnego zakładu
 if(k%100==0) Serial.println(" "); // duże paczki zakładów - po 100 - i tak w nieskończoność :-)
 if(k>32767) k=0;                  // aby nie przekroczyć max dla zmiennej typu int (32768)
}
}

I to by było na tyle.
Acha... jeszcze zdanie na temat wyższości rekurencji która się tu nie do końca sprawdza:-)
Otóż rekurencja jest trudna do przewidzenia w zakresie zajętości pamięci, bo wszystko to, co robi musi gdzieś odkładać na stosie, a ten jak wiemy nie jest zbyt duży. Wyobraźmy sobie na przykład, że losujemy nie 6 z 49 a 20 z 49 (albo dla testów 49 z 49 :-) Zobaczmy co się stanie. Na przykład udało się nam po ok 400 obiegach pętli w końcu wylosować 31 unikalnych liczb a 32 liczba znowu się powtórzyła, bo np. jest taka sama jak 12 liczba. Kurcze znowu skok i  znowu kolejne losowanie....Ale w końcu i 49 z 49 da się wylosować :-)
A w rekurencji wszystko się odkłada na stosie i w pewnym momencie nasze arduino się zawiesi :-)
Pozdrawiam
proszę o ew. uwagi czy ma sens taka forma w piaskownicy?
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości