Autor |
Beitrag |
galagher
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Sa 31.05.14 07:55
Hallo!
Ich programmiere gerade an einem Game of Life. Bin noch ganz am Anfang, und schon da ist mir etwas unklar:
Zitat: | Lebende Zellen mit weniger als zwei lebenden Nachbarn sterben in der Folgegeneration an Einsamkeit. |
aus: de.wikipedia.org/wik...ways_Herausforderung
Es gibt doch zwangsläufig immer Zellen, die weniger als zwei lebenden Nachbarn haben: Zunächst jene, die von vornherein keine lebenden Nachbarn hatten, diese sterben also. Da dann jedoch auch jene Zellen, die die soeben gestorbenen als Nachbarn hatten, nun auch keine lebenden Nachbarn mehr haben, sterben diese auch usw. Schon nach 1 Durchlauf des Arrays ist dieses nur noch mit toten Zellen gefüllt.
Konkret: Das Array represäntiert eine quadratische Fläche, auf der dann gezeichnet wird. Egal, wie ich die Zellen nun setze, es wird ja immer Zellen geben, die an einer oder mehreren Seiten an keine anderen angrenzen.
Wie mache ich das richtig?
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Sa 31.05.14 08:11
Hallo,
arbeitest Du auch mit ( im übertragendem Sinne ) zwei Spielbrettern, das alte ergibt ein neues.Die neue Generation kommt doch sonst der alten in die Quere und die Regeln stimmen nicht.
Ein leeres Feld mit 2/ 3 Nachbarn wird doch lebendig, es müssen doch irgendwie Kinder da sein
Gruß Horst
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Sa 31.05.14 08:42
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Sa 31.05.14 09:06
Hallo,
Du kannst zu Beginn mit zwei kompletten Feldern arbeiten.Alt-,NeuFeld.
Du verarbeitest die Daten von Alt- auf NeuFeld und am Ende kopierst Du das neue auf das alte.
Das geht erst einmal am schnellsten.Dann das bestimmen der Anzahl der Nachbarn dauert am längsten.
Dann kannst Du Zeiger auf zwei Felder nehmen und anschließend Zeiger tauschen.
Dann kann man nur 3 alte Zeilen ( 0,1( wird gerade bearbeitet),2) vorhalten ( wieder mit Zeigern ) und kopiert immer eine alte Zeile hinein.Und arbeitet von oben nach unten ( wie im Speicher ). Dann tauscht man nur die Zeiger (1->0, 2->1) kopiert nur die nächste Zeile als Zeile 2 ( Zeiger von ehemals 0 ).
Man kann immer viel machen
Gruß Horst
P.S.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| const
for x := 0 to ... for y := 0 to ... bBoard[x, y] = Hat2oder3Nachbarn(x, y); aBoard := bBoard; |
|
|
Delphi-Laie
      
Beiträge: 1600
Erhaltene Danke: 232
Delphi 2 - RAD-Studio 10.1 Berlin
|
Verfasst: Sa 31.05.14 09:13
galagher hat folgendes geschrieben : | Was muss ich machen? |
Horsts Rat mit den beiden Spielbrettern umsetzen.
galagher hat folgendes geschrieben : | Verwende ich zwei Arrays und wie? |
Zum Beispiel. Oder Du verwendest ein dreidimensionales Array, bei dem eine Dimension nur die Größe zwei hat.
Es gibt auch Game-of-life-Projekte in den Delphiforen. Einfach mal suchen, finden, downloaden und die - hoffentlich und meistens vorhandenen - Quelltexte durchstöbern und daraus lernen.
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Sa 31.05.14 09:25
Hallo,
da war mal was vor 5 Jahren...
www.entwickler-ecke....;highlight=game+life , dann soll es mittlerweile weiter gehen.
p196 habe ich auch mittlerweile auf 10 Sekunden ( 32 Bit Assembler ( ohne SSE ) , aber ich habe noch ein Register über. Den Fehler bei der 64 Bit Version ( 5 Sekunden ) habe ich noch nicht gefunden ( nach 10000 Stellen tritt der auf) ).
Du siehst, dran bleiben lohnt sich
Gruß Horst
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Sa 31.05.14 11:06
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Sa 31.05.14 11:18
Hallo,
Gute Güte, ich ging von 2-dimimensionalen Feldern aus...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| const xMax = 10; yMax = 10 type tboard = array[0..yMax+1,0..xMax+1] of boolean; var aBoard,bBoard : tboard;
... |
Du musst nur das erste Feld löschen, das andere wird ja immer komplett überschrieben.
Gruß Horst.
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Sa 31.05.14 12:43
Horst_H hat folgendes geschrieben : | Gute Güte, ich ging von 2-dimimensionalen Feldern aus...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| const xMax = 10; yMax = 10 type tboard = array[0..yMax+1,0..xMax+1] of boolean; var aBoard,bBoard : tboard;
... |
Du musst nur das erste Feld löschen, das andere wird ja immer komplett überschrieben.
Gruß Horst. |
Ich verstehe gar nichts!
Das Prinzip ist doch:
- Array1 durchlaufen: Prüfe in Array1 auf Nachbarn, schreibe for ... Array1[x, y] := Array2[x, y]
- Nach dem kompletten Durchlauf schreibe for ... Array2[x, y] := Array1[x, y]
- Zeichne das aktuelle Array1
- Neuer Durchlauf
Oder?
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Sa 31.05.14 12:52
Hallo,
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:
| Program Gol; {$Apptype Console} uses crt;
const colMax = 62; rowMax = 14; type tboard = array[0..rowMax+1,0..colMax+1] of byte; tTripel = array[0..2] of Byte; tpTripel = ^tTripel; var aBoard,bBoard : tboard; gblGenCount : integer;
function Survive(col,row:integer):byte; var sum: integer; pTrip:tpTripel; alive :boolean; begin dec(col); pTrip := @aBoard[row-1,col]; sum := pTrip^[0]+pTrip^[1]+pTrip^[2]; pTrip := @aBoard[row,col]; alive := pTrip^[1]<>0; sum := sum+pTrip^[0]+ +pTrip^[2]; pTrip := @aBoard[row+1,col]; sum := sum+pTrip^[0]+pTrip^[1]+pTrip^[2]; IF sum = 3 then survive := 1 else Begin IF alive AND (sum = 2) then survive := 1 else survive := 0; end; end;
procedure NextGen; var col,row: integer; begin For row := 1 to rowMax do For col := 1 to colMax do bBoard[row,col] := Survive(col,row); aBoard := bBoard; inc(gblGenCount); end;
procedure PrintGen; const cChar: array[0..1] of char = (' ','#'); var col,row: integer; begin gotoxy(1,1); writeln(gblGenCount:10); For row := 1 to rowMax do begin For col := 1 to colMax do write(cChar[aBoard[row,col]]); writeln; end; end;
var col,row : integer; begin randomize; clrscr; fillchar(aBoard,SizeOf(aBoard),#0);
For row := 1 to rowMax do For col := 1 to colMax do aBoard[row,col]:= Byte(random>0.5); repeat PrintGen; NextGen; delay(100); until keypressed; end. |
Vielleicht ist das einleuchtender.
Gruß Horst
P.S.
Die Sonne scheint übrigens...
Für diesen Beitrag haben gedankt: galagher
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: So 01.06.14 10:55
Habe das jetzt mit nur einem Array realisiert, allerdings expanderiert die Welt fast jedesmal, es stellt sich meist kein Gleichgewicht ein. Manchmal friert die Welt auch einfach ein. Mal sehen...
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
trm
      
Beiträge: 491
Erhaltene Danke: 19
Windows 7x64
Delphi 7
|
Verfasst: So 01.06.14 11:57
Das Problem bei nur EiNEM Array ist, dass die Abbildung nicht funktioniert, da Du nach dem ersten Durchlauf und Änderung einer Zelle einen unbestimmten Zustand hst, da die Änderung direkt in das aktuelle Spielfeld geschrieben wurde.
Wie willst Du nun also vergleichen, wie der iST-Zustand vom kompletten Feld war, um die folgenden Zellen auf 0 oder 1 zu setzen?
Beispiel:
Original-Feld:
0-0-1-1-0-0
0-1-1-1-0-0
0-0-0-0-0-0
Erster Durchlauf des kompletten Feldes in Deinem Beispiel ergibt:
0-1-1-1-0-0
0-1-1-1-0-0
0-0-1-1-0-0
Es sollte aber so aussehen:
0-1-1-1-0-0
0-1-1-1-0-0
0-0-1-0-0-0
Die letzte untere rechte 1 ist bei Dir nicht korrekt, weil Du das Originalfeld inclusive Deiner Änderung als Referenz heranziehst. Daher benötigst Du ein Lese - und ein Änderungsfeld.
Nach dem Ändern kannst Du das Feld in das nur-lesen-Feld kopieren und das Ändernfeld kannst Du nun neu beschreiben, musst noch nicht einmal dieses leeren, da es nicht als Referenz benutzt wird.
Ich hoffe, ich habe keinen Logischen Fehler gemacht.
_________________ In Erfurt gibt es eine Pension, in der es gemütlich ist, Google einfach nach Pension Fiege
Für diesen Beitrag haben gedankt: galagher
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: So 01.06.14 13:05
trm hat folgendes geschrieben : | Nach dem Ändern kannst Du das Feld in das nur-lesen-Feld kopieren und das Ändernfeld kannst Du nun neu beschreiben, musst noch nicht einmal dieses leeren, da es nicht als Referenz benutzt wird. |
Ich mache das so:
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:
| for x := ... for y := ... atmpBoard[x, y].Cell := aBoard[x, y].Cell;
procedure TForm1.Timer1Timer(Sender: TObject); var x, y: Integer; begin for x := ... for y := ... begin if (atmpBoard[x, y].clCell = clDeathCell) then ; if (atmpBoard[x, y].clCell = clLivingCell) then ; end;
for x := ... for y := ... aBoard[x, y].Cell := atmpBoard[x, y].Cell;
DrawBoard; end; |
Wohl nicht ganz korrekt so, denn ich merke keinen Unterschied...
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: So 01.06.14 14:38
galagher hat folgendes geschrieben : | Ich mache das so: |
Das ist Unsinn! Ich denke, jetzt hab ich's:
1. Fülle ein zweites Array - nennen wir es Array2 - mit toten Zellen
2. Lies das erste "Original"-Array (Array1) und schreibe in Array2
3. Schreibe von Array2 nach Array1 und zeichne dieses
Jetzt erhalte ich ähnliche Figuren, wie es vielfach zu diesem Thema beschrieben ist: Wandernde, sich drehende usw. Meist jedoch friert die Welt nach einigen Generationen aus.
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
|