![]() |
Schwierigkeiten mit Game of Life Algorithmus
Hallo,
Ich bin zur Zeit dabei, mir mal das allseits beliebte Game of Life anzuschauen. Ich weiß, dass es schon eine Menge Algorithmen gibt, doch hat mir keiner von denen, die ich bisher gesehen habe geholfen. Mein Problem ist simpel: Die Anzahl der lebenden Nachbarfelder wird richtig ermittelt, doch erfolgt die berechnung des neuen Spielfeldes fehlerhaft. Hier einmal mein Code: ( alt ist global deklariert als Array[1..50,1..50] of Integer)
Delphi-Quellcode:
Wähle ich zum Beispiel ein Feld des Stringgrids aus und drücke den Button2, so gibt er mir die richtige Anzahl der lebenden Nachbarn aus.
function nachbarn(i,k : Integer):Integer;
var a,b,c : Integer; begin c := 0; for a:=i-1 to i+1 do for b:=k-1 to k+1 do if ((a<>i) OR (b<>k)) AND (alt[a,b] = 1) then inc(c); nachbarn := c; end; procedure Tform1.ausgeben; var i,k : Integer; begin for i := 1 to high(alt) do for k := 1 to length(alt) do Stringgrid1.Cells[i-1,k-1] := IntToStr(alt[i,k]); end; procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); begin alt[ACol+1,ARow+1] := 1; ausgeben; xselect := ACol+1; yselect := ARow+1; end; procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); var f : TColor; begin if Stringgrid1.Cells[ACol,ARow] = '1' then f := clBlue else f := clwhite; Stringgrid1.Canvas.Brush.Color := f; Stringgrid1.Canvas.FillRect(Rect); end; procedure TForm1.Button1Click(Sender: TObject); var i,k : Integer; begin for i := 1 to high(alt) do for k := 1 to length(alt) do begin if (alt[i,k] = 1) AND (nachbarn(i,k) <> (2 OR 3)) then alt[i,k] := 0; if (alt [i,k] = 0) AND (nachbarn(i,k) = 3) then alt[i,k] := 1; ausgeben; end; procedure TForm1.Button2Click(Sender: TObject); begin if (xselect and yselect) < 1 then Showmessage('Keine Zelle ausgewählt!') else Showmessage('Lebende Nachbarn: ' + IntToStr(nachbarn(xselect,yselect))); end; Beispiel: [o] = tot, [x] = lebend [o][o][o][o][o] [o][x][x][x][o] [o][o][o][o][o] nach einem Zyklus sollte es so aussehen: [o][o][x][o][o] [o][o][x][o][o] [o][o][x][o][o] Bei mir sieht es aber so aus: [o][o][o][o][o] [o][o][o][o][o] [o][o][o][o][o] Kann mir jemand sagen, wieso das nicht klappt? Und noch etwas, wie verfährt man mit Randfeldern ? Danke schonmal im Vorraus gruß fabio |
Re: Schwierigkeiten mit Game of Life Algorithmus
Wenn ich deinen Code richtig lese, dann prüfst du für jede Zelle, wieviele Nachbarn sie hat und änderst entsprechend ihren zustand (lebendig/tod). D.h. du änderst sie direkt ab und bei der Überprüfung weiterer Zellen wird ihr neuer Zustand geprüft und nicht ihr alter.
Ich denke du solltest ein zweites temporäres Array anlegen, und darin den jeweils neuen Zustand der Zellen übernehmen und erst am Ende (wenn alle Zellen überprüft wurden) seinen kompletten Inhalt in das ursprüngliche Array übertragen. Zu Randfeldern: Da gibt es mWn zwei Möglichkeiten: a) Randfelder sind grundsätzlich tod; b) es gibt keine Randfelder, sondern das Feld ist umlaufend (z.B. die Nachbarn von [3;1] sind dann [2;50], [3;50], [4;50], [2;1], [4;1], [2;2], [3;2] und [4;2]. |
Re: Schwierigkeiten mit Game of Life Algorithmus
Bin zur Zeit auch dabei etwas ähnliches zu programmieren. Ich schließ mich Grishnak an.
Du musst ein temporäres Array nehmen, da du ja sonnst die falsche mit der neuen Nachbarschaft weiterrechnest. Was die Ränder betrifft seiht es deutlich schöner aus, wenn die Welt umlaufend ist, ist allerdings auch etwas schwieriger. |
Re: Schwierigkeiten mit Game of Life Algorithmus
Hallo,
Danke für den Tipp mit dem 2ten Feld. Ich hab das mal so realisiert: (neu ist wie alt ein Array[1..50] of Integer)
Delphi-Quellcode:
Funktionieren tuts nun fast richtig, denn nun geschiet folgendes:
procedure Tform1.ausgeben;
var i,k : Integer; begin for i := 1 to high(alt) do for k := 1 to length(alt) do Stringgrid1.Cells[i-1,k-1] := IntToStr(alt[i,k]); end; procedure Tform1.einlesen; var i,k : Integer; begin for i := 1 to 50 do for k := 1 to 50 do alt[i,k] := neu[i,k]; end; procedure TForm1.Button1Click(Sender: TObject); var i,k : Integer; begin for i := 1 to high(alt) do for k := 1 to length(alt) do begin if (alt[i,k] = 1) AND (nachbarn(i,k) <> (2 or 3)) then neu[i,k] := 0; if (alt [i,k] = 0) AND (nachbarn(i,k) = 3) then neu[i,k] := 1; end; einlesen; ausgeben; end; Beispiel: [o] = tot, [x] = lebend [o][o][o][o][o] [o][x][x][x][o] [o][o][o][o][o] nach einem Zyklus sollte es so aussehen: [o][o][x][o][o] [o][o][x][o][o] [o][o][x][o][o] Bei mir sieht es aber so aus: [o][o][x][o][o] [o][o][o][o][o] [o][o][x][o][o] Das heisst, es wird immernoch nicht richtig umgesetzt... Wieso funktioniert es immernoch nicht ? :( Und desweiteren, wie sag ich dem Programm, dass das Feld umlaufend sein soll? :( gruß fabiO |
Re: Schwierigkeiten mit Game of Life Algorithmus
Hast du schon probiert, ob es funktioniert, wenn du auch die überlebenden Zellen neu schreibst:
Delphi-Quellcode:
if (alt [i,k] = 0) AND (nachbarn(i,k) = 2)
then alt[i,k] := 1; |
Re: Schwierigkeiten mit Game of Life Algorithmus
Mhh dein Code, mit der überlebenden Zelle, leuchtet nich so ganz ein!
Delphi-Quellcode:
Dass würde ja beudeten, dass ein Feld, das vorher tot war und 2 lebende Nachbarn besitzt, nun lebendig ist, und das wäre ja gegen die Spielregeln.
if (alt [i,k] = 0) AND (nachbarn(i,k) = 2)
then alt[i,k] := 1; Das mit den überlebenden habe ich mal so eingearbeitet:
Delphi-Quellcode:
Also falls eine Zelle lebt (=1) und sie 2 ODER 3 lebende Nachbarn hat, lebt sie weiter (:=1).
procedure TForm1.Button2Click(Sender: TObject);
var i,k : Integer; begin for i := 1 to high(alt) do for k := 1 to length(alt) do begin if (alt[i,k] = 1) AND (nachbarn(i,k) = (2 or 3)) then neu[i,k] := 1 else neu[i,k] := 0; if (alt [i,k] = 0) AND (nachbarn(i,k) = 3) then neu[i,k] := 1; end; einlesen; ausgeben; end; Andernfalls stirbt sie (:=0). Falls eine Zelle tot ist und genau 3 lebende Nachbarn hat, wird sie belebt (:=1). Aber trotzdem erhalte ich dieses Bild: [o][o][x][o][o] [o][o][o][o][o] [o][o][x][o][o] d.h. es wird immernoch nicht richtig umgesetzt...?!? |
Re: Schwierigkeiten mit Game of Life Algorithmus
Zitat:
Denn (2 or 3) ergibt 10 or 11 (binär) ergibt 11(binär) also 3. Nur wenn ich 3 Nachbarn habe, bleibe ich am Leben. Der Mittlere würde demnach auch sterben, denn er hat 2 Nachbarn. Genau das passiert bei Dir aber. Du müsstest das umformulieren:
Delphi-Quellcode:
Dann sollte alles so funktionieren.
procedure TForm1.Button1Click(Sender: TObject);
var n,i,k : Integer; begin for i := 1 to high(alt) do for k := 1 to length(alt) do begin n := Nachbarn (i,k); if (alt[i,k] = 1) AND not (n in [2,3]) then // <--- neu[i,k] := 0; if (alt [i,k] = 0) AND (n = 3) then neu[i,k] := 1; end; ... end; |
Re: Schwierigkeiten mit Game of Life Algorithmus
Danke für deine Antwort!
Es funktioniert nun, jedoch musste ich noch 2 extra if-Anweisungen mit einbinden, weil es nur mit deinem code immernoch das falsche ergebniss lieferte! Ich habe nun folgendes stehen:
Delphi-Quellcode:
Jedoch besteht mein Problem mit den Randfeldern immernoch. Ich habe keine Vorstellung, wie ich Delphi sagen soll, dass wenn ein Feld den x-Wert oder y-Wert 1 oder 50, oder auch beides, hat, dass es dann beim überschreiten der Feldgrenzen auf die gegenüberliegende Seite wechseln soll.
procedure TForm1.Button1Click(Sender: TObject);
var i,k,n : Integer; begin for i := 1 to high(alt) do for k := 1 to length(alt) do begin n := Nachbarn (i,k); if (alt[i,k] = 1) AND not (n in [2,3]) then neu[i,k] := 0 else if (alt[i,k] = 1) AND (n in [2,3]) then neu[i,k] := 1; if (alt [i,k] = 0) AND (n = 3) then neu[i,k] := 1 else if (alt [i,k] = 0) AND not (n = 3) then neu[i,k] := 0; end; einlesen; ausgeben; end; Ich hatte mal folgendes probiert:
Delphi-Quellcode:
Nur ist diese Variante ja nicht gerade sehr effizient, weil es einfach nur Zeile für Zeile aufgeschrieben wird, was man natürlich auch machen könnte ;)
if (k = 1) then
begin if alt[i+1,k] = 1 then inc(c); if alt[i+1,k+1] = 1 then inc(c); if alt[i,k+1] = 1 then inc(c); if alt[i-1,k+1] = 1 then inc(c); if alt[i-1,k] = 1 then inc(c); if alt[i-1,50] = 1 then inc(c); if alt[i,50] = 1 then inc(c); if alt[i+1,50] = 1 then inc(c); end; Wie Grishnak in seinem Post (#2) schon bemerkte: Zitat:
gruß fabiO :) |
Re: Schwierigkeiten mit Game of Life Algorithmus
Deine Funktion zum Zählen der Nachbarn ist doch fast schon perfekt, nur musst Du eben dafür sorgen, das nur legale Felder gezählt werden. Du kannst dazu aber der Einfachheit halber dein Feld etwas größer machen und die zusätzlichen Randfelder einfach leer lassen:
Delphi-Quellcode:
So, nun zur Routine, die die nächste Generation ausrechnet. Ob eine Zelle stirbt oder geboren wird, hängt eindeutig von der Anzahl der Nachbarn ab, also mach es doch so:
Var
LifeWelt : Array [-1..51,-1..51] Of Integer; // bzw. Byte, reicht ja
Delphi-Quellcode:
For i:=0 to 50 do
For j := 0 to 50 do Case Nachbarn (i,j) of 2 : // Zwei Nachbarn: Die Zelle überlebt If alt[i,j]=1 then neu[i,j] := 1 else neu[i,j]:=0; 3 : // Drei Nachbarn: Die Zelle überlebt bzw. wird neu geboren, also... neu[i,j] := 1; // lebt sie jetzt in jedem Fall else neu[i,j] := 0; // Alle anderen Fälle... End; |
Re: Schwierigkeiten mit Game of Life Algorithmus
Zitat:
Delphi-Quellcode:
Schau dir vielleicht mal auf Luckies Homepage seine Version an.
// nach rechts:
if x<X then x_neu:=x+1 else x:=0; // nach links: if x>0 then x_neu:= x-1 else x:= X; // Nach oben: if 0<y then y_neu:=y-1 else y:=Y; // Nach unten: if y<Y then y_neu:=y+1 else y:=0; |
Re: Schwierigkeiten mit Game of Life Algorithmus
Autsch, aber bitte bedenken, das Delphi die Gross/Kleinschreibung ignoriert, was bei deinem Code zu dezent perversen Effekten führt... :zwinker:
|
Re: Schwierigkeiten mit Game of Life Algorithmus
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Wenn ich das Feld größer mache und hierbei die randfelder Leer lassen, also somit eine umrandung schaffe, funktioniert das programm ja auch nicht. aber wenn ich mir andere, z.B. Java-Applets, anschaue, dann verhalten die sich genau wie mein programm, also wirds wohl doch irgendwo richtig sein :?: gibts ansonsten keine andere möglichkeit dieses quasi "runde" array zu verwirklichen ? ach ja, und danke für die andere nachbar-ermittlung, aber die bereitet mir weniger probleme als dieses Randfeld-Dilemma :( ps. hab ma mein programm angehängt, damit's deutlicher wird :) gruß fabiO |
Re: Schwierigkeiten mit Game of Life Algorithmus
Zitat:
Dein Array ist also so definiert:
Delphi-Quellcode:
Probe:
Var
LifeWelt : Array [0..N-1, 0..M-1] Of Byte; Function ZaehleNachbarn (i,j : Integer) : Integer; Var dx,dy : Integer; Begin Result := -alt[i,j]; // Wir zählen Alles, auch uns selbst For dx:=-1 to 1 do for dy:=-1 to 1 do If alt [(i + N + dx) mod N , (j + M + dy) mod M] = 1 then inc(Result); End; Linker Nachbar von j=0 soll sein: M-1. dy=-1, also ergibt j+M-1 mod M = M-1, q.e.d Rechter Nachbar von j=M-1 soll sein:0. dy= 1, also ergibt (M-1)+M +1 mod M = 2M mod M = 0. q.e.d Für alle anderen Fälle ist (j+M+dy) mod M = j+dy. q.e.d Gleiches gilt für oben/unten... oder (prüf mal selbst) |
Re: Schwierigkeiten mit Game of Life Algorithmus
Erhm also so ganz hab ich dein modulo nich gerafft :)
Und dazu sagt mir Delphi, dass es weder N, noch M kennt ([Error] Unit1.pas(30): Undeclared identifier: 'N') :) Kannst du nochma schaun, warum das nicht ganz funktionieren könnte? Danke schonmal für die Idee gruß fabiO |
Re: Schwierigkeiten mit Game of Life Algorithmus
Du musst Dir doch dein N und M selbst deklarieren...
Mach einfach
Delphi-Quellcode:
[delphi]
Const
N = 50; M = 50; Dann ist dein Life-Array 50x50 felder gross... Modulo ist nur der 'Rest' einer Division. 17 mod 5 = 2, weil 12 geteilt durch 5 ist 3 Rest 2. Der 'Rest' ist der modulo. Ganz einfach, oder? :zwinker: |
Re: Schwierigkeiten mit Game of Life Algorithmus
yo logisch, sorry stand bissl auf der leitung :)
kannte nur mod, wusste nich, dass es modulo heisst ;) Naja ich habe das mal in den Code eingesetzt, es funktioniert wie mit meinem code, also keine veränderung... Aber ich denke, da in den anderen Life-Programmen es genauso gemacht wird, werde ich es einfach so lassen... Danke für die Tipps! |
Re: Schwierigkeiten mit Game of Life Algorithmus
Liste der Anhänge anzeigen (Anzahl: 1)
hab einfach ma zum Abschluss mein fertiges ( :hello: :party: :hello: ) programm drangehangen...
Falls also jemand mal die selbe Aufgabe bekommen sollte, kann er sich ja gern bedienen. :cheers: gruß fabiO |
Re: Schwierigkeiten mit Game of Life Algorithmus
Sieht gut aus, nur: Was bedeutet der Button 'Lebende Nachbarn'? Was du vielleicht noch machen könntest, wäre die Option verschiedene Formationen erzeugen zu lassen, wie einen r-Pentomino oder andere interessante Objekte.
|
Re: Schwierigkeiten mit Game of Life Algorithmus
Liste der Anhänge anzeigen (Anzahl: 1)
hi...
ich hab mich doch nochma rangesetzt, und mir is ne ziemlich einfache lösung für das Problem des umlaufenden Feldes eingefallen, die ich jetzt einfach ma poste:
Delphi-Quellcode:
die werte für a1 und b1 kann man einfach durch die jeweiligen Feldgrenzen (+/- 1) ersetzen...
function nachbarn(x,y : Integer):Integer;
var a,a1,b,b1,c : Integer; begin c := 0; for a:=x-1 to x+1 do for b:=y-1 to y+1 do begin a1 := a; b1 := b; if a1 = 0 then a1:=50; if a1 = 51 then a1:=1; if b1 = 0 then b1:=50; if b1 = 51 then b1:=1; if ((a1<>x) or (b1<>y)) and (alt[a1,b1] = 1) then inc(c); end; nachbarn := c; end; gruß fabiO ps. der button war nur zu beginn von nutzen, um zu sehn, ob die function nachbarn funktioniert :) das mit den verschiedenen Formationen bau ich bald ma ein, danke für die idee :) |
Re: Schwierigkeiten mit Game of Life Algorithmus
Ich hatte mir mal überlegt, wenn ich life programmiert habe, dass ich des erweitere .. aber da ich von dem programm was hier zum dl steht mal nur nen kleinen Teil verstehe, dauert das wohl noch .. aber ihr könnt das bestimmt.
ich wollte zellen nicht sofort sterben und leben lassen, sondern wenn sie "belebt wird, wird sie erstmal ne runde grün und wenn sie stirbt ne runde rot .. und an sich hab ich schwarz für tod und weiss für lebend .. vielleicht will ja jemand von euch das probieren .. ^^ hf MfG Q |
DP-Maintenance
Dieses Thema wurde von "alcaeus" von "Multimedia" nach "Sonstige Fragen zu Delphi" verschoben.
Spaet aber doch will ich den mal ein bisschen rumschubsen. Multimedia ist doch nicht so geeignet dafuer ;) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:01 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz