Autor |
Beitrag |
PokerFace
Hält's aus hier
Beiträge: 3
|
Verfasst: 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*
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; public 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(1000) mod 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=2) or (z=3) then FIsAlive2[i,j]:=true; If (z<2) or (z>3) then 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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 04.12.10 14:06
Hallo und
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.
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: Delphi-Quelltext 1: 2:
| if FIsAlive[i + 1, j] then z := z + 1; |
|
|
F34r0fTh3D4rk
      
Beiträge: 5284
Erhaltene Danke: 27
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Sa 04.12.10 14:09
Hallo und
Zunächst ein kleiner Tipp fürs nächste mal: Der Code sieht in [ delphi][/delphi] Tags noch viel hübscher aus.
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=2) or (z=3) then FIsAlive2[i,j]:=true; If (z<2) or (z>3) then FIsAlive2[i,j]:=false; end; |
Ich glaube an dieser Stelle möchtest du eigentlich von 0 anfangen zu zählen, sprich:
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:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| function isAlive(i, j: integer): boolean; begin if ((i>=0) and (i<=high(FIsAlive) and (j>=0) and (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 
Hält's aus hier
Beiträge: 3
|
Verfasst: 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 
Hält's aus hier
Beiträge: 3
|
Verfasst: So 05.12.10 21:26
Ein kleiner Push. 
|
|
ich.AG
Hält's aus hier
Beiträge: 2
|
Verfasst: 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
Delphi-Quelltext 1: 2:
| If (z=2) or (z=3) then FIsAlive2[i,j]:=true; If (z<2) or (z>3) then FIsAlive2[i,j]:=false; |
in
Delphi-Quelltext 1: 2: 3: 4:
| If (z=2) or (z=3) then 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
      
Beiträge: 211
Erhaltene Danke: 23
|
Verfasst: Mo 06.12.10 08:45
|
|
|