Informaticasite van het Sondervick College te Veldhoven                 © L.J.M van Haperen (bron : R.J. van der Beek)
 

Hoofdstuk 18 Java

18.6 Vier op een rij

Op deze pagina gaan we een applet maken waarin het spelletje vier-op-een-rij gespeeld kan worden.
Aan de hand daarvan bespreken we o.a. arrays van objecten.
Het applet zie je hier onder. Speel het spelletje maar eens.

  18.6.1. Een array van objecten

We beginnen natuurlijk weer met de interface.

Die gaan we maken zoals in de figuur hier onder.
Het label linksboven heb ik lblBeurt genoemd.
De labels rechts heb ik lblAantalx en lblAantalo genoemd.
De button waarop "Nieuw spel" staat heb ik btnNieuwspel genoemd.

Er zijn 50 hokjes waar een kruisje of een rondje in geplaatst kan worden. Dat zijn 50 labels, en die kun je met een loop laten genereren.
Hetzelfde geldt voor de buttons boven de kolommen.
De 50 labels heb ik lblHok[1] t/m lblHok[50] genoemd en daarbij zit lblHok(1) linksonder.
De buttons boven de kolommen heb ik btnGooi[1] t/m btnGooi[10] genoemd, en daarbij zit btnGooi[1] links.
We gaan bespreken hoe je die kunt maken.



We willen nu de opdrachten geven voor de labels lblHok[1] tot en met lblHok[50]
Je moet dan een array van labels declareren.

Dat doe je m.b.v. de opdracht
Label lblHok[] = new Label[51];

Je moet een array van 51 labels declareren want er wordt bij arrays altijd bij 0 begonnen.
Je hebt dan lblHok[0] tot en met lblHok[50], en dat zijn er 51 in totaal.

Verder zet je de volgende opdrachten in de methode init:

int x=10;
int y=80;
int k=0;
for (int i=1;i<51;i++)
{
    lblHok[i] = new Label("",Label.CENTER);
    k=(i-1)/5;
    x=12+42*k;
    y=70+32*(i-5*k);
    lblHok[i].setBounds(x,y,40,30);
    lblHok[i].setFont(new Font("Dialog", Font.BOLD, 20));
    lblHok[i].setBackground(new Color(255,255,255));
    add(lblHok[i]);
}

En dan moeten we nog de opdrachten voor de buttons btnGooi[1] tot en met btnGooi[10] maken.
Je moet dan een array van buttons declareren.
Dat doe je m.b.v. de opdracht
Button btnGooi[] = new Button[11];
En verder zet je de volgende opdrachten in de methode init:

        for (int i=1;i<11;i++)
	{
		btnGooi[i] = new Button("Gooi");
		btnGooi[i].setBounds(-30+42*i,70,40,30);
		btnGooi[i].setFont(new Font("Dialog", Font.BOLD, 12));
		btnGooi[i].setBackground(new Color(150,150,150));
		add(btnGooi[i]);
	}

  18.6.2. Arrays en andere variabelen declareren

Het klaarmaken van een array voor gebruik kun je in twee stappen doen.
  • Eerst declareer je de array. Daarbij geef je aan welk type elementen de array zal bevatten.
    De syntax hiervoor is: type arraynaam[];
  • In de volgende stap reserveer je geheugen voor de array: je geeft aan hoeveel elementen de array kan bevatten:
    arraynaam = new type[aantal];
    Wanneer je bv. als aantal 100 opgeeft heb je 100 geheugenplaatsen genummerd van 0 tot en met 99.
  • Deze stappen kan je ook in één regel code plaatsen:
    type arraynaam[] = new type[aantal];
In vier-op-een-rij hebben we een aantal arrays nodig. Bijvoorbeeld een array teken[] en een array vulling[] [], zie hier onder.
We beginnen met de instantie-variabelen, dat zijn de variabelen die bij alle methodes bekend moeten zijn (dat zijn in andere programmeertalen globale variabelen).

Die declareren we in het begin van de code, vlak na de header public class Vieroprij extends Applet Daar zetten we de volgende opdrachten neer:

    int aantalwinstx;
    int aantalwinsto;
    int aantalkeergegooid;
    int speler;
    boolean uitslag;
    String teken[] = new String[4];
    int vulling[][] = new int[11][6];

  • In de variabele aantalwinstx wordt vastgelegd hoe vaak X heeft gewonnen.
  • In de variabele aantalwinsto wordt vastgelegd hoe vaak O heeft gewonnen.
  • In de variabele aantalkeergegooid wordt vastgelegd hoe vaak er gegooid is. Dit moet worden bijgehouden want als er 50 keer is gegooid zonder dat er iemand vier-op-een-rij had dan moet er worden gestopt want dan zijn alle hokjes vol en dan heeft dus geen van beiden gewonnen.
  • In de variabele speler wordt vastgelegd wie er aan de beurt is. We spreken af dat als speler = 1 dan is X aan de beurt, en als speler = 2 dan is O aan beurt.
  • Een variabele van het type boolean kan alleen de waarden true en false hebben.
    De variabele uitslag is van het type boolean.
    Elke keer als iemand gegooid heeft moet er worden gecontroleerd of er vier-op-een-rij is. Als dat wel het geval is krijgt de variabele uitslag de waarde true en anders false.

  • Door de opdracht String teken[] = new String[4]; wordt een array van strings gedeclareerd: teken[1], teken[2] en teken[3]
    (en teken[0], maar die gebruiken we niet. Het zijn er dus vier)
    Daarmee leggen we vast welke tekens we gebruiken voor de twee spelers: teken[1]="X" en teken[2]="O" en teken[3]="X"
    ( teken[3]="X" zou je kunnen missen, maar het is wel handig bij het programmeren om dat te gebruiken)

  • Door de opdracht int vulling[][] = new int[11][6] wordt een twee-dimensionale array gedeclareerd:
    in vulling[i][j] wordt vastgelegd welk teken er in het hokje staat in kolom nummer i en rij nummer j. Als het teken X er in staat dan krijgt het de waarde 1, als het teken O er in staat dan krijgt het de waarde 2 en als er niets in staat dan krijgt het de waarde 0
Die variabelen moeten in het begin direkt een waarde krijgen, daarom zet je de volgende opdrachten in de methode init

	aantalwinstx=0;
	aantalwinsto=0;
	aantalkeergegooid=0;
	speler=1;
	uitslag=false;
	teken[1]="X";
	teken[2]="O";
	teken[3]="X";
	for (int i=1;i<11;i++)
	{
	    for (int j=1;i<6;i++)
	    {
	        vulling[i][j]=0;
	    }
	};

Verder zet je de opdracht btnNieuwspel.setVisible(false); in de methode init

Dat heeft tot gevolg dat de nieuwspel-knop in het begin onzichtbaar is.
Die moet alleen verschijnen als een spelletje afgelopen is.

  18.6.3. Code bij de nieuwspel-knop, register-listeners

We gaan nu bespreken wat er moet gebeuren als er op de Nieuwspel-knop wordt geklikt.
In de methode init is de volgende regel opgenomen: btnNieuwspel.addActionListener(this);
En we hebben de volgende methode:

	public void actionPerformed(ActionEvent e)
	{
	    Object object = event.getSource();
	    if (e.getSource() == btnNieuwspel) btnNieuwspel_Action();
	    enz.
	}

Dus als op de nieuwspel-knop wordt geklikt wordt de methode btnNieuwspel_Action uitgevoerd.
Die methode ziet er als volgt uit:

void btnNieuwspel_Action()
{
       aantalkeergegooid=0;
       speler=speler+1;
       if (speler==3) speler=1;
       for (int i=1;i<11;i++)
       {
           for (int j=1;i<6;i++)
           {
               vulling[i][j]=0;
           }
       }
       
       for (int i=1;i<51;i++)
       {
           lblHok[i].setText("");
       }
       
       lblBeurt.setText(teken[speler]+" is aan de beurt");
       btnNieuwspel.setVisible(false);
}

  18.6.4. Register-listeners bij een array van objecten

Als er op een gooi-knop wordt geklikt moet er een X of een O in een hokje er onder verschijnen.
De computer moet dus ook steeds in de gaten houden of er op een gooi-knop wordt geklikt, en daar zijn er tien van namelijk btnGooi[1] t/m btnGooi[10]
Daarom voegen we de volgende code toe in de methode init:

for (int i=1;i<11;i++)
{
    btnGooi[i].addActionListener(this);
}

Verder moet de computer ook weten welke methode er moet worden uitgevoerd als er op zo'n knop is geklikt.
Voor de nieuwspel-button was dat al vastgelegd (namelijk de methode btnNieuwspel_Action() ).

We voegen daarom in de methode actionPerformed een aantal regels toe:

	public void actionPerformed(ActionEvent e)
	{
		if (e.getSource() == btnNieuwspel) btnNieuwspel_Action();
		for (int i=1;i<11;i++)
		{
		    if (e.getSource() == btnGooi[i]) btnGooi_Action(i);
		}
	}
}

Er staat dus in dat als er op btnGooi[i] wordt geklikt dan moet de procedure btnGooi_Action(i) worden uitgevoerd.
En de code voor die procedure moeten we nog invoeren.
Die code ziet er als volgt uit:

void btnGooi_Action(int i)
{
   for (int j=1;j<6;j++)
   {
      int g=vulling[i][j];
      if (g==0)
      {
         lblHok[i*5-j+1].setText(teken[speler]);
         vulling[i][j]=speler;
         aantalkeergegooid++;
         lblBeurt.setText(teken[speler+1]+" is aan de beurt");
         boolean uitslag=controleer();
         if (uitslag==true)
         {
            lblBeurt.setText(teken[speler]+" heeft gewonnen!");
            if (speler==1)
            {
               aantalwinstx++;
               lblAantalx.setText("Winst voor X: "+aantalwinstx);
            }
            else
            {
               aantalwinsto++;
               lblAantalo.setText("Winst voor O: "+aantalwinsto);
            }
            btnNieuwspel.setVisible(true);
            for (int k=1;k<11;k++)
            {
               btnGooi[k].setEnabled(false);
            }
            break;
         }
         else
         {
            speler=speler+1;
            if (speler==3) {speler=1;}
            if (aantalkeergegooid==50)
            {
               lblBeurt.setText("Geen van beiden heeft gewonnen!");
               btnNieuwspel.setVisible(true);
            }
            break;
         }
      }
   }
}

Hierboven wordt een procedure gebruikt die controleer genoemd is.
In die procedure wordt er gecontroleerd of er ook vier gelijke tekens op een rij zijn.
Dat kan op vier manieren: vertikaal, horizontaal en diagonaal in twee richtingen.
Als in die procedure blijkt dat er vier-op-een-rij is dan krijgt de variabele uitslag de waarde true.
En dan krijgt de methode controleer ook de terugkeerwaarde true, want de laatste regel van de methode controleer is:return uitslag.

De methode controleer ziet er als volgt uit:

boolean controleer()
{
    boolean uitslag=false;
    Color geel=new Color(255,255,0);

    for (int kolom = 1;kolom<11;kolom++)
    {
        for (int j = 1;j<3;j++)
        {
           if (
              (vulling[kolom][j] == speler) &&
              (vulling[kolom][j + 1] == speler) &&
	      (vulling[kolom][j + 2] == speler) && 
	      (vulling[kolom][j + 3] == speler)
	      ) 
	      {
	            uitslag = true;
                    lblHok[kolom  * 5 - j + 1].setBackground (geel);
                    lblHok[kolom  * 5 - j].setBackground (geel);
                    lblHok[kolom  * 5 - j - 1].setBackground (geel);
                    lblHok[kolom  * 5 - j - 2].setBackground (geel);
                    break;
              }
        }
    }
    // en dan volgen er nog drie van zulke for-lussen
    // zie daarvoor onderaan bij de volledige code
    return uitslag;
}

  18.6.5. De volledige code.

Hier is de volledige code:

import java.awt.*; 
import java.applet.*; 
import java.awt.event.*; 

public class Vieroprij extends Applet implements ActionListener 
{ 
  Label lblBeurt;
  Label lblAantalx;
  Label lblAantalo;
  Button btnNieuwspel;
  Label lblHok[] = new Label[51];
  Button btnGooi[] = new Button[11];
  int aantalwinstx;
  int aantalwinsto;
  int aantalkeergegooid;
  int speler;
  String teken[] = new String[4];
  int vulling[][] = new int[11][6];

  public void init()
  {
    aantalwinstx=0;
    aantalwinsto=0;
        
    aantalkeergegooid=0;
    speler=1;
    teken[1]="X";
    teken[2]="O";
    teken[3]="X";
    for (int i=1;i<11;i++)
    {
      for (int j=1;i<6;i++)
      {
         vulling[i][j]=0;
      }
    };
    setLayout(null);
    setSize(440,275);
    setBackground(new Color(50,200,200));
    lblBeurt = new Label("X is aan de beurt!",Label.CENTER);
    lblBeurt.setBounds(10,10,140,20);
    lblBeurt.setFont(new Font("Dialog", Font.BOLD, 14));
    lblBeurt.setForeground(new Color(255,255,255));
    lblBeurt.setBackground(new Color(20,20,200));
    add(lblBeurt);
    lblAantalx = new Label("Aantal keer dat X won: 0",Label.CENTER);
    lblAantalx.setBounds(160,10,270,20);
    lblAantalx.setFont(new Font("Dialog", Font.BOLD, 14));
    lblAantalx.setForeground(new Color(0));
    lblAantalx.setBackground(new Color(200,100,50));
    add(lblAantalx);
    lblAantalo = new Label("Aantal keer dat O won: 0",Label.CENTER);
    lblAantalo.setBounds(160,40,270,20);
    lblAantalo.setFont(new Font("Dialog", Font.BOLD, 14));
    lblAantalo.setForeground(new Color(0));
    lblAantalo.setBackground(new Color(200,100,50));
    add(lblAantalo);
    btnNieuwspel = new Button("Nieuw spel");
    btnNieuwspel.setBounds(10,40,140,20);
    btnNieuwspel.setFont(new Font("Dialog", Font.BOLD, 14));
    btnNieuwspel.setBackground(new Color(150,150,150));
    btnNieuwspel.setVisible(false);
    add(btnNieuwspel);
    int x=10;
    int y=80;
    int k=0;
    for (int i=1;i<51;i++)
    {
      lblHok[i] = new Label("",Label.CENTER);
      k=(i-1)/5;
      x=12+42*k;
      y=70+32*(i-5*k);
      lblHok[i].setBounds(x,y,40,30);
      lblHok[i].setFont(new Font("Dialog", Font.BOLD, 20));
      lblHok[i].setBackground(new Color(255,255,255));
      add(lblHok[i]);
    }

    for (int i=1;i<11;i++)
    {
      btnGooi[i] = new Button();
      btnGooi[i].setActionCommand("button");
      btnGooi[i].setLabel("Gooi");
      btnGooi[i].setBounds(-30+42*i,70,40,30);
      btnGooi[i].setFont(new Font("Dialog", Font.BOLD, 12));
      btnGooi[i].setBackground(new Color(150,150,150));
      add(btnGooi[i]);
    } 

  btnNieuwspel.addActionListener(this);
  for (int i=1;i<11;i++)
  {
    btnGooi[i].addActionListener(this);
  }
  }

    public void actionPerformed(ActionEvent e)
    {
       if (e.getSource() == btnNieuwspel) btnNieuwspel_Action();
       for (int i=1;i<11;i++)
       {
         if (e.getSource() == btnGooi[i]) btnGooi_Action(i);
       }
    }

  void btnNieuwspel_Action()
  {
     aantalkeergegooid=0;
     speler=speler+1;
     if (speler==3) speler=1;
     for (int i=1;i<11;i++)
     {
       for (int j=1;j<6;j++)
       {
         vulling[i][j]=0;
       }
     } 

     Color wit=new Color(255,255,255);       
     for (int i=1;i<51;i++)
     {
       lblHok[i].setText("");
       lblHok[i].setBackground (wit);
     }
     lblBeurt.setText(teken[speler]+" is aan de beurt");
     btnNieuwspel.setVisible(false);
     for (int k=1;k<11;k++)
     {
       btnGooi[k].setEnabled(true);
     };
  }

  boolean controleer()
  {
    boolean uitslag=false;
    Color geel=new Color(255,255,0);

    for (int kolom = 1;kolom<11;kolom++)
    {
       for (int j = 1;j<3;j++)
       {
         if (
            (vulling[kolom][j] == speler) &&
            (vulling[kolom][j + 1] == speler) &&
            (vulling[kolom][j + 2] == speler) && 
            (vulling[kolom][j + 3] == speler)
            ) 
            {
               uitslag = true;
               lblHok[kolom  * 5 - j + 1].setBackground (geel);
               lblHok[kolom  * 5 - j].setBackground (geel);
               lblHok[kolom  * 5 - j - 1].setBackground (geel);
               lblHok[kolom  * 5 - j - 2].setBackground (geel);
               break;
            }
       }
    }

    for (int rij = 1;rij<6;rij++)
    {
      for (int j = 1;j<8;j++)
      {
         if (
            (vulling[j][rij] == speler) &&
            (vulling[j + 1][rij] == speler) &&
            (vulling[j + 2][rij] == speler) && 
            (vulling[j + 3][rij] == speler)
            ) 
            {
              uitslag = true;
              lblHok[j * 5 - rij + 1].setBackground (geel);
              lblHok[(j+1) * 5 - rij + 1].setBackground (geel);
              lblHok[(j+2) * 5 - rij + 1].setBackground (geel);
              lblHok[(j+3) * 5 - rij + 1].setBackground (geel);
              break;
            }
       }
    }

    for (int kolom = 1;kolom<8;kolom++)
       {
         for (int j = 1;j<3;j++)
         {
            if (
               (vulling[kolom][j] == speler) &&
               (vulling[kolom + 1][j + 1] == speler) &&
               (vulling[kolom + 2][j + 2] == speler) && 
               (vulling[kolom + 3][j + 3] == speler)
               ) 
               {
                 uitslag = true;
                 lblHok[kolom  * 5 - j + 1].setBackground (geel);
                 lblHok[(kolom+1) * 5 - j].setBackground (geel);
                 lblHok[(kolom+2) * 5 - j - 1].setBackground (geel);
                 lblHok[(kolom+3) * 5 - j - 2].setBackground (geel);
                 break;
               }
            }
        }

for (int kolom = 1;kolom<8;kolom++)
{
   for (int j = 4;j<6;j++)
   {
   if (
   (vulling[kolom][j] == speler) &&
   (vulling[kolom + 1][j - 1] == speler) &&
   (vulling[kolom + 2][j - 2] == speler) && 
   (vulling[kolom + 3][j - 3] == speler)
   ) 
      {
         uitslag = true;
         lblHok[kolom  * 5 - j + 1].setBackground (geel);
         lblHok[(kolom+1) * 5 - j + 2].setBackground (geel);
         lblHok[(kolom+2) * 5 - j + 3].setBackground (geel);
         lblHok[(kolom+3) * 5 - j + 4].setBackground (geel);
         break;
      }
   }
}
return uitslag;
}

void btnGooi_Action(int i)
{
   for (int j=1;j<6;j++)
   {
      int g=vulling[i][j];
      if (g==0)
      {
         lblHok[i*5-j+1].setText(teken[speler]);
         vulling[i][j]=speler;
         aantalkeergegooid++;
         lblBeurt.setText(teken[speler+1]+" is aan de beurt");
         boolean uitslag=controleer();
         if (uitslag==true)
         {
            lblBeurt.setText(teken[speler]+" heeft gewonnen!");
            if (speler==1)
            {
               aantalwinstx++;
               lblAantalx.setText("Winst voor X: "+aantalwinstx);
            }
            else
            {
               aantalwinsto++;
               lblAantalo.setText("Winst voor O: "+aantalwinsto);
            }
            btnNieuwspel.setVisible(true);
            for (int k=1;k<11;k++)
            {
               btnGooi[k].setEnabled(false);
            }
            break;
         }
         else
         {
            speler=speler+1;
            if (speler==3) {speler=1;}
            if (aantalkeergegooid==50)
            {
               lblBeurt.setText("Geen van beiden heeft gewonnen!");
               btnNieuwspel.setVisible(true);
            }
            break;
         }
      }
    }
  }

}

Opgaven.
Maak nu opgave 6 van hoofdstuk 18 (Java)