Autor Beitrag
PokerFace
Hält's aus hier
Beiträge: 3



BeitragVerfasst: Sa 04.12.10 13:57 
Hallo Community,
ich bin neu hier, daher erstmal ein freudiges "Hallo".
Da wir in der Schule nun endlich IInformatik haben, ging ich natürlich einfrig ans Programmieren.
Lief auch alles so weit so gut, doch gerade sollen wir das Game of Life programmieren.

Zuerst hatte ich das Problem, dass das Skript sich selbst ändert.
Nun das lag daran, dass ich die Abfragen jedes mal mit einem DrawGrid1.Refresh beendet hatte.
So wurden die Zellen geändert und diese geänderten Zellen nachher zum weiterrechnen verwendet. Ist natürlich nicht Sinn des Spiels.
So hab ich das mit 2 Arrays gelöst das der eine berechnet und der andere immer gezeichnet wird.
Ja soweit so gut..

Nun meine Fragen:
1. Frage: Wie ihr in meinem Skript seht, kann ich die Ränder nicht abfragen, denn wenn ich das per IF mache, komm ich ja in einen negativen Bereich.
2. Frage: Warum werden die Regeln nicht richtig angewandt? Wenn ich 4 Blöcke nebeneinader erstelle, sollten die eigentlich irgendwann sterben, aber das "mutiert". *gg*

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, Menus, ExtCtrls;

type
  TForm1 = class(TForm)
    DrawGrid1: TDrawGrid;
    MainMenu1: TMainMenu;
    Start1: TMenuItem;
    Ende1: TMenuItem;
    Spielwelt1: TMenuItem;
    Erzeugen1: TMenuItem;
    Leeren1: TMenuItem;
    Timer1: TTimer;
    Pause1: TMenuItem;
    procedure Ende1Click(Sender: TObject);
    procedure Erzeugen1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure Leeren1Click(Sender: TObject);
    procedure Start1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure DrawGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
      var CanSelect: Boolean);
    procedure Pause1Click(Sender: TObject);
  private
    FIsAlive: Array of Array of boolean;
    FIsAlive2: Array of Array of boolean;
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  DrawGrid1.Canvas.Brush.Color:=clwhite;
  If FIsAlive[ACol, ARow]=true then
    DrawGrid1.Canvas.Brush.Color:=clblack;
    DrawGrid1.Canvas.Rectangle(DrawGrid1.CellRect(ACol,ARow));
end;

procedure TForm1.DrawGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
  var CanSelect: Boolean);
begin
  FIsAlive[ACol,ARow]:=true;
  DrawGrid1.Refresh;
end;

procedure TForm1.Ende1Click(Sender: TObject);
begin
  application.terminate;
end;

procedure TForm1.Erzeugen1Click(Sender: TObject);
var i,j:integer;
begin
  For i:=0 to Length(FIsAlive)-1 do
    For j:=0 to Length(FIsAlive[i])-1 do
     begin
       If random(1000mod 2 = 0 then FIsAlive[i,j]:=true
       Else FIsAlive[i,j]:=false;
     end;
  For i:=0 to Length(FIsAlive)-1 do
    For j:=0 to Length(FIsAlive[i])-1 do
      begin
        FIsAlive2[i,j]:=FIsAlive[i,j];
      end;
  DrawGrid1.Refresh;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i,j:integer;
begin
  Timer1.Enabled:=false;
  SetLength(FIsAlive,DrawGrid1.RowCount);
  For i:=0 to DrawGrid1.RowCount -1 do
    SetLength(FIsAlive[i], DrawGrid1.ColCount);
  SetLength(FIsAlive2, DrawGrid1.RowCount);
  For j:=0 to DrawGrid1.RowCount -1 do
    SetLength(FIsAlive2[j], DrawGrid1.ColCount);
end;

procedure TForm1.Leeren1Click(Sender: TObject);
var i,j:integer;
begin
  Timer1.Enabled:=false;
  For i:=0 to Length(FIsAlive)-1 do
    For j:=0 to Length(FIsAlive)-1 do
      FIsAlive[i,j]:=false;
  DrawGrid1.Refresh;
end;

procedure TForm1.Pause1Click(Sender: TObject);
begin
  Timer1.Enabled:=false;
end;

procedure TForm1.Start1Click(Sender: TObject);
begin
  Timer1.Enabled:=true;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var i,j,z:integer;
begin
  For i:=1 to Length(FIsAlive)-1 do
    For j:=1 to Length(FIsAlive) -1 do
      begin
        z:=0;
        If FIsAlive[i+1,j]=true then z:=z+1;
        If FIsAlive[i-1,j]=true then z:=z+1;
        If FIsAlive[i+1,j+1]=true then z:=z+1;
        If FIsAlive[i-1,j-1]=true then z:=z+1;
        If FIsAlive[i+1,j-1]=true then z:=z+1;
        If FIsAlive[i-1,j+1]=true then z:=z+1;
        If FIsAlive[i,j+1]=true then z:=z+1;
        If FIsAlive[i,j-1]=true then z:=z+1;
        If (z=2or (z=3then FIsAlive2[i,j]:=true;
        If (z<2or (z>3then FIsAlive2[i,j]:=false;
      end;
  For i:=1 to Length(FIsAlive)-1 do
    For j:=1 to Length(FIsAlive)-1 do
      begin
        FIsAlive[i,j]:=FIsAlive2[i,j];
      end;
  DrawGrid1.Refresh;
end;

end.
Einloggen, um Attachments anzusehen!


Zuletzt bearbeitet von PokerFace am Sa 04.12.10 15:14, insgesamt 1-mal bearbeitet
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 04.12.10 14:06 
Hallo und :welcome:

Mach einfach das Array um zwei Felder für die Ränder größer. Die Randfelder sind dann mit False initialisiert. Dann darfst du die natürlich auch nicht später setzen, aber soweit ich das sehe, geht das mit der Schleife so wie du sie hast.

Dann gehst du weiter von 1 statt von 0 los, nur dass das jetzt wirklich das erste Feld ist.

Zur zweiten Frage:
Häng doch einfach das Projekt gezippt als Quelltext an. Dann muss ich es mir nicht nachbauen zum Ausprobieren. ;-)
Und ohne Ausprobieren müsste ich es mir ja genauer anschauen. :mrgreen: ;-)

Und dann als Hinweis:
Der Vergleich mit Booleanwerten (z.B. if x = true then) ist nicht nur unschön und unlogisch, sondern falsch.
Hier habe ich mal ein kleines Beispiel gebastelt, wann es schief geht:
www.delphi-forum.de/....php?p=548760#548760
Mehr dazu steht hier:
www.delphi-treff.de/...olean-werten/page/4/
Und warum das auch vollkommen unlogisch ist:
www.delphi-forum.de/....php?p=560637#560637

Für deinen Fall heißt das:
ausblenden Delphi-Quelltext
1:
2:
if FIsAlive[i + 1, j] then
  z := z + 1;
F34r0fTh3D4rk
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5284
Erhaltene Danke: 27

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Sa 04.12.10 14:09 
Hallo und :welcome:

Zunächst ein kleiner Tipp fürs nächste mal: Der Code sieht in [delphi][/delphi] Tags noch viel hübscher aus.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
  For i:=1 to Length(FIsAlive)-1 do
    For j:=1 to Length(FIsAlive) -1 do
      begin
        z:=0;
        If FIsAlive[i+1,j]=true then z:=z+1;
        If FIsAlive[i-1,j]=true then z:=z+1;
        If FIsAlive[i+1,j+1]=true then z:=z+1;
        If FIsAlive[i-1,j-1]=true then z:=z+1;
        If FIsAlive[i+1,j-1]=true then z:=z+1;
        If FIsAlive[i-1,j+1]=true then z:=z+1;
        If FIsAlive[i,j+1]=true then z:=z+1;
        If FIsAlive[i,j-1]=true then z:=z+1;
        If (z=2or (z=3then FIsAlive2[i,j]:=true;
        If (z<2or (z>3then FIsAlive2[i,j]:=false;
      end;

Ich glaube an dieser Stelle möchtest du eigentlich von 0 anfangen zu zählen, sprich:
ausblenden Delphi-Quelltext
1:
2:
  For i:=0 to Length(FIsAlive)-1 do
    For j:=0 to Length(FIsAlive) -1 do

da das Array bei 0 anfängt.

Weiterhin musst du natürlich bei den Zugriffen prüfen, ob diese in einem gültigen Bereich stattfinden. Hierzu könntest du dir zum Beispiel eine eigene Funktion basteln:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
function isAlive(i, j: integer): boolean;
begin
  if ((i>=0and (i<=high(FIsAlive) and (j>=0and (j<=high(FIsAlive)) then
    result := FIsAlive[i, j] else
      result := false;
end;

Dann ersetzt du dein FIsAlive[i+1,j] durch isAlive(i+1,j). Hierbei ist zu beachten, dass Felder außerhalb des Spielfeldes immer als false behandelt werden.
Man kann das ganze aber auch so bauen, dass zum Beispiel das Feld ganz links mit dem Feld ganz recht benachbart ist.

Weiterhin solltest du vermeiden auf True zu prüfen. (FIsAlive[i,j-1]=true) erzeugt bei der Auswertung einen boolean, da du aber in deinem Array schon einen boolean stehen hast, ist das unnötig doppelt gemoppelt.

Weitere Gründe findest du hier: Warum man niemals auf True prüfen sollte
Die Diskussion darüber hatten wir erst kürzlich.
PokerFace Threadstarter
Hält's aus hier
Beiträge: 3



BeitragVerfasst: Sa 04.12.10 15:38 
Danke erstmal für die Tipps.
Leider bin ich noch seeeeehr neu in Delphi.

Zur 2. Frage hat noch niemand eine Idee?
Das ist vorerst das Hauptproblem.
Den Rand werd ich auch noch schaffen. :)
Wo muss ich zum Beispiel die Funktion deklarieren? (Wo wir wieder bei Neuling wären.)


PS: Alles angehängt und andere Tags gesetzt.
PokerFace Threadstarter
Hält's aus hier
Beiträge: 3



BeitragVerfasst: So 05.12.10 21:26 
Ein kleiner Push. :)
ich.AG
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Mo 06.12.10 01:39 
aml ne kurze frage,

hast du auch bedacht, dass tote zellen, die genau 3 lebende nachbarn haben, in der nächsten runde neu "geboren" werden,
denn davon steht in deinem quelltext nichts, zumindest hab ich nix beim überfliegen gefunden...

Außerdem solltest du meiner meinung nach

ausblenden Delphi-Quelltext
1:
2:
If (z=2or (z=3then FIsAlive2[i,j]:=true;
If (z<2or (z>3then FIsAlive2[i,j]:=false;


in

ausblenden Delphi-Quelltext
1:
2:
3:
4:
If (z=2or (z=3then 
  FIsAlive2[i,j]:=true
else
  FIsAlive2[i,j]:=false;


abändern.

Hast du die Hinweise der Anderen umgesetzt? Denn das könnte dir ggf. auch bei deinem zweiten problem helfen...

Ich hab mal ein gof programmiert, ich habs nur leider nicht zur hand, da ich nicht zu hause bin, aber vllt. komm ich ja demnächst wieder hin...

Viel Spaß noch beim proggen.

Viele Grüße
ich.AG
Teekeks
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 211
Erhaltene Danke: 23



BeitragVerfasst: Mo 06.12.10 08:45 
user profile iconich.AG hat folgendes geschrieben Zum zitierten Posting springen:

Außerdem solltest du meiner meinung nach

ausblenden Delphi-Quelltext
1:
2:
If (z=2or (z=3then FIsAlive2[i,j]:=true;
If (z<2or (z>3then FIsAlive2[i,j]:=false;


in

ausblenden Delphi-Quelltext
1:
2:
3:
4:
If (z=2or (z=3then 
  FIsAlive2[i,j]:=true
else
  FIsAlive2[i,j]:=false;


abändern.


Und ich würde daraus ein
ausblenden Delphi-Quelltext
1:
FIsAlive2[i,j]:=(z=2or (z=3);					

machen.