wiki:Silmukat
Last modified 9 years ago Last modified on 2010-07-14 16:57:36

Apuja ohjelmointiin » Silmukat

Oletetaan, että haluat luoda kolme palloa pelikentälle. Kirjoitat seuraavanlaisen ohjelman:

Pallo p1 = new Pallo();
Pallo p2 = new Pallo();
Pallo p3 = new Pallo();
Add( p1 );
Add( p2 );
Add( p3 );

Kuusi riviä ohjelmakoodia ei ole vielä kovin paljon, mutta entä jos palloja haluttaisiinkin 100? Tässä vaiheessa silmukat tulevat avuksi. Silmukoita on kahdenlaisia, for- ja while-silmukoita.

1. While-silmukka

While-silmukka on näistä kahdesta silmukasta syntaksiltaan yksinkertaisempi. While-lause kirjoitetaan samaan tapaan kuin if-lause:

while ( ehto )
{
   // tehdään jotain
}

Ero if-lauseeseen on se, että while-lausekkeen runkoa (kaarisulkujen välissä olevaa koodia) suoritetaan niin kauan kuin ehto on tosi. Siksi ehdossa käytettävää muuttujaa on päivitettävä silmukan sisällä, muuten silmukan suoritus ei pääty koskaan ja syntyy ns. ikuinen silmukka.

Esimerkki: Sadan pallon lisääminen kenttään while-lauseella:

int i = 0;

while ( i < 100 )
{
   Pallo p = new Pallo();
   Add( p );
   i++;
}

Viimeinen lause i++ kasvattaa muuttujan i arvoa yhdellä, ja siten se voi joskus saavuttaa arvon sata, jolloin silmukka päättyy. Jos lausetta ei olisi, silmukka olisi ikuinen.

2. For-silmukka

Saman ongelman ratkaisu for-silmukalla näyttäisi tältä:

for (int i = 0; i < 100; i++)
{
   Pallo p = new Pallo();
   Add( p );
}

For-silmukan syntaksi saattaa näyttää aluksi pelottavalta, mutta on loppujen lopuksi hyvinkin yksinkertainen. Tässä lause purettuna:

for (For-lause alkaa.
int i = 0;Alustetaan int (kokonaisluku)-tyyppinen muuttuja i arvolla 0.
i < 100;Ehto, jonka toteutuessa silmukkaa jatketaan. Sama kuin while-lauseessa.
i++Lause, joka suoritetaan jokaisen silmukan suorituksen jälkeen.
)For-lauseen määrittelyosa päättyy.
{Silmukan runko alkaa.
}Silmukan runko päättyy.

3. Mitä hyötyä silmukoista

  • Kuvitellaan että teet autopeliä, jossa tarvitaan rengasvallia. Olet kirjoittanut ihan toimivan koodin seuraavasti:
       LuoRengas(-330, -230);
       LuoRengas(-330, -210);
       LuoRengas(-330, -190);
       LuoRengas(-330, -170);
       LuoRengas(-330, -150);
       ... hirveästi samanlaisia rivejä, laske montako
       LuoRengas(-330, 210);
       LuoRengas(-330, 230);
       LuoRengas(-330, 250);
    
  • Renkaat syntyvät kyllä mukavasti tuolla koodilla pystysuoraan alkaen alhaalta paikasta (-330,-230) ja jatkuen aina paikkaan (-330,250). Tässä on kuitenkin ongelmia.
    1. On varsin työlästä tehdä uusi vastaava rengasrivi x-koordinaattiin -200.
    2. Entä jos haluatkin että renkaiden väli on 20 sijasta 25?
    3. Entä jos haluatkin että x-koordinaattia siirretään hieman oikealle (tämä voitaisiin toki hoitaa vakiolla)
  • Entäpä jos kirjoittaisit koodin hieman eri tavalla:
       int x = -330; 
       
       int y = -230; LuoRengas(x,y);
       y += 20;      LuoRengas(x,y);
       y += 20;      LuoRengas(x,y);
       y += 20;      LuoRengas(x,y);
       y += 20;      LuoRengas(x,y);
       ... hirveästi samanlaisia rivejä, laske montako
       y += 20;      LuoRengas(x,y);
       y += 20;      LuoRengas(x,y);
       y += 20;      LuoRengas(x,y);
    
    Nyt renkaat syntyvät aivan samalla tavalla. Ja x on helppo vaihtaa. Mutta ongelman on edelleen rivien iso määrä. Ja itse asiassa nyt on kovasti laskemista siinä, montako riviä pitää kirjoittaa.
  • tässä tulee silmukka avuksesi. Edellinen koodi on korvattavissa muutamalla lauseella:
       int x = -330;
       for (int y=-230; y <= 250; y += 20) // vasen reuna alhaalta ylös
       {
          LuoRengas(x, y);
       }
    
    eli silmukkaa suoritetaan seuraavasti:
       1. for (int y=-230  // Aloitetaan silmukka ja silmukkamuuttujalle y annetaan arvoksi aluksi -230
       2. y <= 250         // silmukkaa jatketaan niin kauan kuin y on pienempi tai yhtäsuuri kuin 250
       3. LuoRengas(x,y);  // Luodaan rengas paikkaan (x,y) eli nyt -330,-250
       4. y+=20            // lisätään y:hyn 20 eli siitä tulee nyt -230
       5. y <= 250         // tarkistetaan joku on tehty tarpeeksi pitkälle, jos ei niin jatketaan silmukkaa
       6. LuoRengas(x,y);  // Luodaan rengas paikkaan (x,y) eli nyt -330,-230
       7. y+=20            // lisätään y:hyn 20 eli siitä tulee nyt -210
       8. y <= 250         // tarkistetaan joku on tehty tarpeeksi pitkälle, jos ei niin jatketaan silmukkaa
       9. LuoRengas(x,y);  // Luodaan rengas paikkaan (x,y) eli nyt -330,-210
      10. y+=20            // lisätään y:hyn 20 eli siitä tulee nyt -190
      11. y <= 250         // tarkistetaan joku on tehty tarpeeksi pitkälle, jos ei niin jatketaan silmukkaa
       ...
      ??. y+=20            // lisätään y:hyn 20 eli siitä tulee nyt 210
      ??. y <= 250         // tarkistetaan joku on tehty tarpeeksi pitkälle, jos ei niin jatketaan silmukkaa
      ??. LuoRengas(x,y);  // Luodaan rengas paikkaan (x,y) eli nyt -330,210
      ??. y+=20            // lisätään y:hyn 20 eli siitä tulee nyt 230
      ??. y <= 250         // tarkistetaan joku on tehty tarpeeksi pitkälle, jos ei niin jatketaan silmukkaa
      ??. LuoRengas(x,y);  // Luodaan rengas paikkaan (x,y) eli nyt -330,230
      ??. y+=20            // lisätään y:hyn 20 eli siitä tulee nyt 250
      ??. y <= 250         // tarkistetaan joku on tehty tarpeeksi pitkälle, jos ei niin jatketaan silmukkaa
      ??. LuoRengas(x,y);  // Luodaan rengas paikkaan (x,y) eli nyt -330,250
      ??. y+=20            // lisätään y:hyn 20 eli siitä tulee nyt 270
      ??. y <= 250         // tarkistetaan joku on tehty tarpeeksi pitkälle, ja nyt 270 ei ole pienempi tai yhtäkuin 250 eli
                              silmukan ehto ei ole totta ja lopetetaan silmukka
    

4. Sisäkkäiset silmukat

  • Seuraava vaatii hieman enemmän miettimistä, mutta se kannattaa :-)
  • Entäpä jos haluaisit noita edellisen esimerkin kaltaisia rengasrivejä 5 kappaletta vierekkäin. Se onnistuisi vaikkapa seuraavasti:
       for (int x=-330; x<=-250; x += 20; ) 
       {
         for (int y=-230; y <= 250; y += 20) // vasen reuna alhaalta ylös
         {
            LuoRengas(x, y);
         }
       }
     - Mieti miksi tämä tekisi sinulle ne viisi rengasriviä rinnakkain.
     - miten renkaiden väli saataisiin helposti säädettäväksi?
    

Attachments