9. Lotto-getallen, arrays en geneste lussen

Stel dat we een applet willen maken waarin lotto-getallen worden getoond. Deze getallen kunnen we maken met de random-functie, die we in hoofdstuk 8 gezien hebben. Het trekken van een lottogetal (van 1 t/m 42) zou bijvoorbeeld zo kunnen:

int getal = (int)(42 * Math.random()) + 1;

Als we op deze manier zes keer een getal trekken en afbeelden, lijkt het programma in orde, maar een probleem is dat we dan ook dubbele getallen zouden kunnen trekken. Hoe kunnen we dat voorkomen?

Om te kunnen controleren of een getal al eerder getrokken is, zullen we de getallen moeten bewaren. De beste manier om dat te doen is een zogenaamd array.

In het dagelijks leven hebben allerlei zaken een nummer. Bladzijden van een boek, kamers in een hotel, trams en huisadressen zjn allemaal genummerd. Ook variabelen kunnen we nummeren. Dat kan er bijvoorbeeld zo uitzien:

maand[1] = 31;
maand[2] = 28;
maand[3] = 31;

Als je dit soort variabelen wil aanvragen, moet je ze, net als elke andere variabele, declareren. Dat kan in tweeën, namelijk zo:

int maand[];
maand = new int [12];

De eerste regel heet de declaratie van het array, de tweede noemt men de initialisatie. Je kunt die twee ook samenvoegen tot één regel, namelijk zo:

int maand[] = new int [12];

Als je er onmiddellijk waarden in wilt plaatsen, kunnen de declaratie, de initialisatie en het vullen in enen gebeuren, bijvoorbeeld zo:

int maand[] = {31,28,31,30,31,30,31,31,30,31,30,31};

Zou je een array voor zes lottogetallen willen declareren, dan kan dat zo:

int lotto[] = new int [6];

En je zou ze zo kunnen vullen:

for (int i=0; i<6; i++)
   lotto[i] = (int)(42 * Math.random()) + 1;

Maar het probleem van de dubbele getallen is daarmee niet opgelost. Een goede manier is om telkens als we een getal gemaakt hebben, te controleren of het al eerder is gemaakt. Dan moeten we natuurlijk het geproduceerde getal vergelijken met alle eerder gemaakte. Dat zou je kunnen doen zoals in het programma hieronder:

// Er worden 6 lottogetallen (1-42) getrokken.
import java.applet.*;
import java.awt.*;
public class LottoGetallen extends Applet { Button knop = new Button("klik");
String tekst = "Klik voor een set lotto-getallen";
   public void init () {
      add(knop);
   }
   public void paint (Graphics g) {
      g.drawString (tekst, 30, 120);
   }
   public boolean action (Event e, Object o) {
      if (e.target==knop) {
         int lotto[] = new int [6];
         boolean getrokken;
         for (int i=0; i<6; i++) {
            do {
               getrokken = false;
               lotto[i] = (int)(42*Math.random())+ 1;
               for (int j=0; j<i; j++)
                  if (lotto[i] == lotto[j])
                     getrokken = true;
            } while (getrokken);
         }
         tekst = "";
         for (int i=0; i<6; i++)
            tekst += lotto[i] + "   ";
         repaint();
         return true;
      }
      return false;
   }
}

Je ziet dat er binnen de for-lus met de variabele i een andere for-lus (met de variabele j) wordt gemaakt. Wanneer een lus zich bevindt binnen een andere, noemen programmeurs dit geneste lussen.

In de lus met variabele j wordt gecontroleerd of het betreffende getal al getrokken is. Daarvoor gebruiken we de boolean getrokken. We blijven net zo lang nieuwe getallen aanmaken tot we een getal trekken dat nog niet eerder getrokken is. Dat gebeurt op de volgende manier:

do {
   getrokken = false;
   lotto[i] = (int)(42*Math.random())+ 1;
   for (int j=0; j<i; j++)
      if (lotto[i] == lotto[j])
         getrokken = true;
} while (getrokken);

   

Eenvoudig sorteren

Lottogetallen worden meestal gepresenteerd van klein naar groot. Het is dan ook beter als we de getallen In ons programma gaan sorteren.

Er bestaan diverse methoden om getallen te sorteren. De snelste methoden zijn niet de simpelste. Een vrij eenvoudige methode werkt als volgt: vergelijk elk getal met z'n opvolger. Staan ze verkeerd, verwissel ze dan. Na één ronde staat het laatste getal goed, dus de volgende ronde hoeven we dat getal niet meer mee te nemen. Zo gaan we door en elke keer wordt de rij getallen eentje korter. Is er nog maar één getal over, dan staat alles gesorteerd. Het sorteerproces ziet er zo uit:

laatste = 5;
while (laatste > 0) {
   for (int i=0; i<laatste; i++) {
      if (lotto[getal]>lotto[getal+1]) {
         int temp = lotto[i];      // In deze drie regels
            lotto[i] = lotto[i+1]; // worden lotto[i] en
            lotto[i+1] = temp;     // lotto[i+1] verwisseld
      }
   }
   laatste--;
}

Hieronder zie je een simulatie van dat proces:


Ten slotte volgt hier nog de werkende applet:

Je kunt arrays maken van vrijwel alle objecten, zoals boolean, float, strings, knoppen en tekstvakken. Bij objecten die afzonderlijk geïnitialiseerd moeten worden, moet je niet alleen het array initialiseren, maar ook elk object afzonderlijk.

Hoe dat in zijn werk gaat, kun je zien in het volgende programma:

// Een array van 10 knoppen
import java.applet.*;
import java.awt.*;
public class TienKnoppen extends Applet {

String tekst = "Klik op een van de knoppen ..";
Button knoppen[] = new Button [10];
public void init () {
        for (int i=0; i<10; i++) {
                knoppen [ i ] = new Button ("" + i );
                add (knoppen [ i ]);
        } 
}
public void paint (Graphics g) {
        g.drawString (tekst, 30, 120);
}
public boolean action (Event e, Object o) {
        for (int i=0; i<10; i++) {
                if (e.target == knoppen [ i ] )  {
                        tekst = "je klikte op knop " + i;
                        repaint();
                        return true;
                }
        }
        return false;
}

}

Een werkende applet van dit programma zie je hieronder:

Nog één voorbeeld is een array van strings. Je zou een array kunnen maken met de namen van de dagen van de week, bijvoorbeeld zo:

String dagen [] = {"maandag", "dinsdag", "woensdag",
           "donderdag", vrijdag", "zaterdag", "zondag"};

   

Opdracht 9.1A

Herschrijf opdracht 8.1 zo dat gebruik wordt gemaakt van de switch-case-constructie die in hoofdstuk 8 besproken is.

Opdracht 9.1B

Herschrijf opdracht 8.1 zo dat gebruik wordt gemaakt van een array van strings.

Opdracht 9.2

Maak een applet waarin je een getal van 1 t/m 12 kunt intikken. Na klikkken op de knop wordt meegedeeld met welke maand dit getal overeenkomt. Bij andere getallen verschijnt de mededeling dat dit geen maand is.

Opdracht 9.3 

Maak een applet waarin een dambord wordt getekend (10x10 vakjes) met behulp van twee geneste lussen. Een gevulde rechthoek maak je met de methode fillRect, die verder hetzelfde werkt als de methode drawRect.

   

(c) 2003-2008, Thomas J.H.Luif