Delphi Hoofdstuk 8: Meer arrays, vier op een rij
8.1. Gooien met twee dobbelstenen.
We willen een programma maken waarvan de interface er uit ziet zoals hiernaast.
Als je op de button met de tekst "Gooi 1000 keer met twee dobbelstenen" klikt dan wordt er inderdaad 1000 keer
met twee dobbelstenen gegooid en er
wordt dan afgedrukt hoe vaak het resultaat van de twee dobbelstenen samen 2, 3, 4 t/m 12 was.
De computer moet die aantallen bijhouden.
Daarvoor heb je 11 variabelen nodig, en dat kan natuurlijk het handigst
met een array.
Het aantal keren dat er 2 is gegooid wordt vastgelegd met de variabele aantalkeer[2]
In de variabele aantalkeer[3] wordt vastgelegd hoevaak
er 3 is gegooid, enz. t/m aantalkeer[12]
Je moet die variabelen declareren, en dat doe je zo: var aantalkeer array[1..12] of integer;
8.2. Een array van controls.
Er moeten 11 labels en 11 editboxen op het formulier worden gezet.
Daar kun je ook arrays van maken.
Je kunt de labels bijvoorbeeld lblAantal[2], lblAantal[3], lblAantal[4] t/m lblAantal[12] noemen.
En de editboxen noem je bijv. txtAantal(2], txtAantal(3], txtAantal(4] t/m txtAantal(12]
Maar als je een array van labels en editboxen hebt dan kun je die niet rechtstreeks op het formulier plaatsen,
in het ontwerpvenster.
Je moet die labels en editboxen aanmaken met behulp van programmaregels.
Die labels en editboxen moeten direkt als het programma start al op het formulier staan.
Dat moet dus in de procedure TForm1.FormCreate staan.
En verder moeten de labels en editboxen worden gedeclareerd als globale variabelen (in ieder geval de editboxen)
omdat er in verschillende procedures gebruik van wordt gemaakt.
Dus onder de regel, waarin het formulier wordt gedeclareerd, komen die declaraties:
var
Form1: TForm1;
lblAantal: Array[1..12] of TLabel;
txtAantal: Array[1..12] of TEdit;
Verder moet je een opdracht geven om zo'n object (in het geheugen) te maken, bijv.:
lblAantal[2] := TLabel.Create(self);
En je moet er voor zorgen dat het object op het formulier wordt geplaatst, bijv. door middel van de opdracht:
lblAantal[2].Parent := Form1;
Tenslotte moet je de objecten nog de juiste kleurtjes, opschriften, enz. geven. Dat doe je in de
procedure TForm1.FormCreate(Sender: TObject); Die wordt dan als volgt:
procedure TForm1.FormCreate(Sender: TObject);
var i: integer;
begin
for i:=2 to 12 do
begin
lblAantal[i] := TLabel.Create(self);
lblAantal[i].Parent := Form1;
lblAantal[i].autosize:=false;
lblAantal[i].alignment:=taCenter;
lblAantal[i].width:=170;
lblAantal[i].left:=10;
lblAantal[i].top:= i*25 - 10;
lblAantal[i].height:= 20;
lblAantal[i].caption:='aantal keer '+ inttostr(i);
lblAantal[i].color:=clTeal;
lblAantal[i].Visible:=true;
lblAantal[i].Font.Color := clWhite;
lblAantal[i].Font.Name := 'Tahoma';
lblAantal[i].Font.Size := 12;
lblAantal[i].Font.Style := lblAantal[i].Font.Style+[fsBold];
txtAantal[i] := TEdit.Create(self);
txtAantal[i].Parent := Form1;
txtAantal[i].autosize:=false;
txtAantal[i].width:=60;
txtAantal[i].left:=200;
txtAantal[i].top:= i*25 - 10;
txtAantal[i].height:= 20;
txtAantal[i].text := '';
txtAantal[i].color:=clWhite;
txtAantal[i].Visible:=true;
txtAantal[i].Font.Color := clBlack;
txtAantal[i].Font.Name := 'Tahoma';
txtAantal[i].Font.Size := 12;
end;
end;
De knop waarop staat dat er 1000 keer gegooid moet worden is cmdGooi genoemd.
Als daar op geklikt wordt moet de volgende procedure worden uitgevoerd:
procedure TForm1.cmdGooiClick(Sender: TObject);
var aantal: array[1..12] of integer;
i, som, d1, d2: integer;
begin
Randomize;
For i := 2 To 12 do
begin
aantal[i] := 0;
end;
For i := 1 To 1000 do
begin
d1 := random(6) + 1;
d2 := random(6) + 1;
som := d1 + d2;
aantal[som] := aantal[som] + 1;
end;
For i := 2 To 12 do
begin
txtAantal[i].Text := IntToStr(aantal[i]);
end;
end;
8.3. Vier op een rij, tweedimensionale rij.
We willen nu een programma maken waarvan de interface er uit ziet zoals hieronder.
Om en om moeten X en O op de button boven een kolom klikken. De X of de O valt dan in
die kolom naar beneden.
En dan gaat het er om wie het eerst vier op een rij heeft.
Hier moet in ieder geval door het programma worden bijgehouden welk teken in welk hokje zit.
Het is handig om daar een tweedimensionale rij voor te nemen.
Met vulling[1,1] = 1 geef je bijv. aan dat in het hokje linksonder een X staat,
met vulling[1,2] = 2 geef je aan dat in het hokje boven de vorige een O staat.
En de inhoud van het hokje rechtsboven geef je aan met vulling[10,5]
Je gebruikt dus de volgende rij (met twee indices): vulling[kolom,rij]
Die rij moet als globale variabele worden gedeclareerd, dus boven implementation declareer je: (de eerste regel staat er al)
var Form1: TForm1;
vulling: array[1..10,1..5] of integer;
8.4. De interface van vier op een rij
Je begint natuurlijk weer met de interface.
Die kun je maken zoals in de figuur hier onder.
Je kunt de 50 hokjes op het formulier via het programma laten genereren.
Hetzelfde geldt voor de buttons boven de kolommen.
Het label linksboven heb ik lblBeurt genoemd.
De labels rechts heb ik lblAantalx en lblAantalo genoemd.
De button waarop "Nieuw spel" staat heb ik cmdNieuwspel genoemd.
Verder staan er 10 buttons met het woord "Gooi" boven de kolommen. Die heb ik cmdGooi1 (links)
tot en met cmdGooi10 (rechts) genoemd.
Die plaats je allemaal op het formulier.
De 50 hokjes heb ik lblHok[1] t/m lblHok[50] genoemd, en daarbij zit lblHok[1] linksonder.
Die plaats je niet rechtstreeks op het formulier, maar die genereer je met het programma.
Ik heb even één zo'n hokje op het formulier geplaatst, en in het propertiesvenster de eigenschappen opgezocht,
zodat ik die gegevens in het programma (zie verderop) kon gebruiken.
Je moet die labels lblHok[1] t/m lblHok[50] en aanmaken met behulp van programmaregels.
Die labels moeten direkt als het programma start al op het formulier staan, dat moet dus in de
procedure TForm1.FormCreate staan.
En verder moeten de labels en buttons worden gedeclareerd als globale variabelen
omdat er in verschillende procedures gebruik van wordt gemaakt.
Dus onder de regel, waarin het formulier wordt gedeclareerd, komen meer declaraties:
var
Form1: TForm1;
vulling: array[1..10,1..5] of integer;
lblHok: Array[1..50] of TLabel;
Verder moet je een opdracht geven om zo'n object (in het geheugen) te maken.
En je moet er voor zorgen dat het object op het formulier wordt geplaatst.
Tenslotte moet je de objecten nog de juiste kleurtjes, opschriften, enz. geven. Dat doe je in de
procedure TForm1.FormCreate(Sender: TObject); Die wordt dan als volgt:
procedure TForm1.FormCreate(Sender: TObject);
var i, rij, kolom: integer;
begin
for i:=1 to 50 do
begin
lblHok[i] := TLabel.Create(self);
lblHok[i].Parent := Form1;
lblHok[i].autosize:=false;
lblHok[i].alignment:=taCenter;
lblHok[i].width:=35;
kolom := (i - 1) div 5 + 1;
rij := (i - 1) Mod 5 + 1;
lblHok[i].Top := 275-rij*35;
lblHok[i].Left := 42*kolom-32;
lblHok[i].height:= 30;
lblHok[i].caption:= '';
lblHok[i].color:=clWhite;
lblHok[i].Visible:=true;
lblHok[i].Font.Color := clBlack;
lblHok[i].Font.Name := 'Tahoma';
lblHok[i].Font.Size := 12;
lblHok[i].Font.Style := lblHok[i].Font.Style+[fsBold];
end;
end;
8.5. Het volledige programma.
We beginnen met de globale variabelen.
We hebben er al een stel, maar er komen nog een aantal bij.
Namelijk:
speler, aantalwinstx, aantalwinsto, aantalkeergegooid: Integer;
teken: array[1..2]: string;
uitslag: boolean;
Dus onder de regel, waarin het formulier wordt gedeclareerd, komen meer declaraties:
var
Form1: TForm1;
vulling: array[1..10,1..5] of integer;
lblHok: Array[1..50] of TLabel;
speler, aantalwinstx, aantalwinsto, aantalkeergegooid: Integer;
teken: array[1..2] of string;
Als het programma start moeten er, behalve de opbouw van de interface, nog een aantal dingen gebeuren.
Voeg dus toe aan de opdrachten van procedure TForm1.FormCreate(Sender: TObject);
teken[1] := 'X';
teken[2] := 'O';
speler := 1;
cmdNieuwspel.Visible := False;
Als er op een gooi-button wordt geklikt, dan moet er van alles gebeuren. Wat er dan moet gebeuren heb ik in een
aparte procedure gooiverwerking gezet (zie verderop).
Die procedure wordt gedeclareerd als procedure TForm1.gooiverwerking(kolom:integer);
Er wordt dus achter de naam van de procedure een getal verwacht, namelijk de kolom waarin gegooid moet worden.
Dat heeft tot gevolg dat de event-handlers voor de gooi-buttons heel eenvoudig zijn, want je kunt daarbij gebruik maken
van die procedure gooiverwerking
De event-handler voor gooi-button1 is bijvoorbeeld als volgt:
procedure TForm1.cmdGooi1Click(Sender: TObject);
begin
gooiverwerking(1);
end;
En de event-handler voor gooi-button2 is als volgt:
procedure TForm1.cmdGooi2Click(Sender: TObject);
begin
gooiverwerking(2);
end;
En de andere event-handlers voor gooi-button3 tot en met gooi-button10 zien er net zo uit.
Bij de opdracht gooiverwerking(1); krijgt kolom de waarde 1, en bij de opdracht gooiverwerking(2); krijgt kolom de waarde 2.
De parameter (het wordt dus geen variabele genoemd maar een parameter) krijgt de waarde die bij de opdracht tussen
haakjes staat, daarom wordt deze parameteroverdracht call by value genoemd.
En dan nu de procedure gooiverwerking:
procedure TForm1.gooiverwerking(kolom:integer);
var i, j, rijaanbeurt: integer;
uitslag:boolean;
begin
rijaanbeurt := 0;
If (cmdNieuwspel.Visible = True) Then
begin
Beep;
Exit;
End;
j := 1;
rijaanbeurt:=0;
while (rijaanbeurt=0) do
begin
If (vulling[kolom, j] = 0) Then
begin
rijaanbeurt := j;
End
else
begin
j:=j+1;
if (j=6) then rijaanbeurt := 6;
end;
end;
If (rijaanbeurt = 6) Then
begin
Beep;
Exit;
end
Else
begin
vulling[kolom, rijaanbeurt] := speler;
i := (kolom - 1) * 5 + rijaanbeurt;
lblHok[i].Caption := teken[speler];
aantalkeergegooid := aantalkeergegooid + 1;
controleer(uitslag) ;
If (uitslag = True) Then
begin
lblBeurt.Caption := ' ' + teken[speler] + ' heeft gewonnen !';
If (teken[speler] = 'X') Then aantalwinstx := aantalwinstx + 1
Else aantalwinsto := aantalwinsto + 1;
lblAantalx.Caption := ' Aantal keer dat X gewonnen heeft:' +
IntToStr(aantalwinstx);
lblAantalo.Caption := ' Aantal keer dat O gewonnen heeft:' +
IntToStr(aantalwinsto);
cmdNieuwspel.Visible := True;
end
Else
begin
If (aantalkeergegooid = 50) Then
begin
lblBeurt.Caption := ' Geen van beiden heeft gewonnen !';
cmdNieuwspel.Visible := True;
end
Else
begin
speler := speler + 1;
If (speler = 3) Then speler := 1;
lblBeurt.Caption := ' ' + teken[speler] + ' is aan de beurt !';
End;
End;
End;
End;
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.
De procedures gooiverwerking en controleer moeten gedeclareerd worden onder (of boven) de declaratie van de procedures die er
al staan (bijv. die van FormCreate).
Daarkomt dus o.a.:
procedure FormCreate(Sender: TObject);
procedure gooiverwerking(kolom:integer);
procedure controleer(var uitslag:boolean);
De procedure controleer zie je hieronder. De procedure wordt gedeclareerd als:
procedure TForm1.controleer(var uitslag:boolean);
Er wordt dus achter de naam van de procedure een variabele verwacht, namelijk de naam van de variabele
waarin de uitslag (wel og geen vier-op-een-rij) wordt vastgelegd.
Dat heeft tot gevolg dat als je ergens de opdracht controleer(watishet); geeft, de
variabele watishet (die moet van het type boolean zij) de waarde true heeft als er wel vier-op-een-rij was, en de
waarde false als er geen vier-op-een-rij was.
Je kunt nu geen vaste waarde tussen haakjes achter de naam van de procedure zetten, zoals bij de vorige procedure
gooiverwerking, het moet beslist een variabele zijn.
Daarom wordt deze parameteroverdracht call by reference genoemd, en het verschil zit hem dus in het
woordje var bij de declaratie van de procedure:
TForm1.controleer(var uitslag:boolean);
De procedure controleer voer je op de volgende manier in:
procedure TForm1.controleer(var uitslag:boolean);
var kolom, rij, i, j: Integer;
begin
uitslag := False;
For kolom := 1 To 10 do
begin
For j := 1 To 2 do
begin
If (vulling[kolom, j] = speler) And
(vulling[kolom, j + 1] = speler) And
(vulling[kolom, j + 2] = speler) And
(vulling[kolom, j + 3] = speler) Then
begin
uitslag := True;
lblHok[(kolom - 1) * 5 + j].Color := clRed;
lblHok[(kolom - 1) * 5 + j + 1].Color := clRed;
lblHok[(kolom - 1) * 5 + j + 2].Color := clRed;
lblHok[(kolom - 1) * 5 + j + 3].Color := clRed;
Exit;
End;
end;
end;
For rij := 1 To 5 do
begin
For j := 1 To 7 do
begin
If (vulling[j, rij] = speler) And
(vulling[j + 1, rij] = speler) And
(vulling[j + 2, rij] = speler) And
(vulling[j + 3, rij] = speler) Then
begin
uitslag := True;
lblHok[(j - 1) * 5 + rij].Color := clRed;
lblHok[j * 5 + rij].Color := clRed;
lblHok[(j + 1) * 5 + rij].Color := clRed;
lblHok[(j + 2) * 5 + rij].Color := clRed;
Exit;
End;
end;
end;
For kolom := 1 To 7 do
begin
For j := 1 To 2 do
begin
If (vulling[kolom, j] = speler) And
(vulling[kolom + 1, j + 1] = speler) And
(vulling[kolom + 2, j + 2] = speler) And
(vulling[kolom + 3, j + 3] = speler) Then
begin
uitslag := True;
lblHok[(kolom - 1) * 5 + j].Color := clRed;
lblHok[kolom * 5 + j + 1].Color := clRed;
lblHok[(kolom + 1) * 5 + j + 2].Color := clRed;
lblHok[(kolom + 2) * 5 + j + 3].Color := clRed;
Exit;
End;
end;
end;
For kolom := 1 To 7 do
begin
For j := 4 To 5 do
begin
If (vulling[kolom, j] = speler) And
(vulling[kolom + 1, j - 1] = speler) And
(vulling[kolom + 2, j - 2] = speler) And
(vulling[kolom + 3, j - 3] = speler) Then
begin
uitslag := True;
lblHok[(kolom - 1) * 5 + j].Color := clRed;
lblHok[kolom * 5 + j - 1].Color := clRed;
lblHok[(kolom + 1) * 5 + j - 2].Color := clRed;
lblHok[(kolom + 2) * 5 + j - 3].Color := clRed;
Exit;
End;
end;
end;
End;
Als een spelletje is afgelopen kan er met een nieuw spel worden begonnen door
op de button met "Nieuw spel" te klikken.
Dat moet ook nog geprogrammeerd worden.
Dat doe je als volgt:
procedure TForm1.cmdNieuwspelClick(Sender: TObject);
var i, j: Integer;
begin
For i := 1 To 50 do
begin
lblHok[i].Caption := '';
lblHok[i].Color := clWhite;
end;
For i := 1 To 10 do
begin
For j := 1 To 5 do
begin
vulling[i, j] := 0;
end;
end;
aantalkeergegooid := 0;
speler := speler + 1;
If (speler = 3) Then speler := 1;
lblBeurt.Caption := ' ' + teken[speler] + ' is aan de beurt !';
cmdNieuwspel.Visible := False;
end;
en daarmee is het spel klaar !
|