| Autor |
Beitrag |
poeter
Hält's aus hier
Beiträge: 4
|
Verfasst: Mi 12.03.03 09:05
Es soll ein Programm erstellt werden, das das Wachstum und die Veränderungen in einem komplexen System lebender Organismen, z.b. Bakterien, simuliert. Die Veränderungen in der Population werden jeweils von Generation zu Generation nach bestimmen, weiter unter beschreibenen Regeln berechnet. Die Population einer Generation wird dargestellt durch besetzte bzw. nicht besetzte Felder in einem zweidimensionalen CHAR-Feld. Ausgehend von einer Generation 0, die irgendwie initialisiert sein muss, soll das Programm jeweils die weiteren Generationen berechnen und auf dem Bildschirm sichtbar machen.
Es folgen die Regeln zu Berechnung der Generation n+1 aus der Generation n. Sie sind in der gegebenen Reihenfolge anzuwenden.
1. Jedes Feld (ausser den Randfeldern) hat genau 8 Nachbarfelder.
2. Hat ein besetztes Feld 0 oder 1 besetzte Nachbarfelder, so stirbt es durch Isolation.
3. Hat ein besetztes Feld 2 oder 3 besetzte Nachbarfelder, so überlebt es.
4. Hat ein besetztes Feld mehr als 3 besetzte Nachbarfelder, so stirbt es durch Überbevölkerung.
5. Hat ein unbesetztes Feld genau 3 besetzte NAchbarfelder, so wird das Feld besetzt.
Diese Aufgabe finden wir sehr schwer und ich würde mich freuen ein paar Vorschläge von euch zu erhalten!
Danke
|
|
Popov
      
Beiträge: 1655
Erhaltene Danke: 13
WinXP Prof.
Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
|
Verfasst: Mi 12.03.03 12:28
Auf jeden Fall solltet ihr es über ein Matrix machen und die wenigen Änderungen mit der Bitmap abgleichen. Wenn ihr direkt über die Bitmap geht, dann dauert es lange. Pixel abfragen in der Bitmap verbraucht zu viel Zeit, deshalb der Umweg über eine Matrix.
_________________ Popov
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 12.03.03 12:32
Google mal nach "Spiel des Lebens" oder wie das heißt, das ist so ähnlich.
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Mi 12.03.03 14:04
Ich finde die Aufgabe sehr interessant und auch nicht zu schwer. Das zeitaufwändigste beim Schreiben (hab's in etwa zwanzig Minuten gemacht) ist eigentlich der Grafikkram.
Da ich jetzt weiß, wie es geht, kannst Du ja hier mal Deinen Ansatz posten und ich helfe Dir dann, das Programm draus zu machen!
MfG,
Peter
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Popov
      
Beiträge: 1655
Erhaltene Danke: 13
WinXP Prof.
Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
|
Verfasst: Mi 12.03.03 14:30
Ich hab mich auch in der Mittagspause hingesetzt und was gemacht. Hab es aber noch nicht auf Richtigkeit geprüft:
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:
| implementation
{$R *.DFM}
const Col: array[Boolean] of TColor = (clWhite, clBlack);
const XMax = 300; YMax = 300;
var Matrix: array[-1..XMax+1, -1..YMax+1] of Boolean; //-1 und +1 um eine Grenze mit False Werten zu haben
// Ein Schritt in der Population function Population(Bmp: TBitmap): Boolean; var x, y: Word; p: Byte; begin Result := False;
for y := 0 to Bmp.Height do for x := 0 to Bmp.Width do begin p := 0; if Matrix[x - 1, y] then Inc(p); if Matrix[x + 1, y] then Inc(p); if Matrix[x, y - 1] then Inc(p); if Matrix[x, y + 1] then Inc(p); if Matrix[x - 1, y - 1] then Inc(p); if Matrix[x + 1, y + 1] then Inc(p); if Matrix[x + 1, y - 1] then Inc(p); if Matrix[x - 1, y + 1] then Inc(p);
if Matrix[x, y] then begin if p <= 1 then begin Matrix[x, y] := False; Bmp.Canvas.Pixels[x, y] := Col[False]; Result := True; end else if p > 3 then begin Matrix[x, y] := False; Bmp.Canvas.Pixels[x, y] := Col[False]; Result := True; end; end else begin if p = 3 then begin Matrix[x, y] := True; Bmp.Canvas.Pixels[x, y] := Col[True]; Result := True; end; end;
end; end;
// Anfangswerte procedure TForm1.FormCreate(Sender: TObject); var x, y: Integer; begin // Matrix löschen for x := -1 to XMax+1 do for y := -1 to YMax+1 do Matrix[x, y] := False;
// TImage und sein TBitmap an die Größe der Matrix anpassen with Image1 do begin Width := XMax; Height := YMax;
Picture.Bitmap.Width := XMax; Picture.Bitmap.Height := YMax; end; end;
// Startwerte procedure TForm1.Button1Click(Sender: TObject); var x, y: Word; begin // Hier Matrix mit paar Beispieldaten füllen for x := 100 to 150 do for y := 100 to 140 do Matrix[x, y] := True;
// Hier die Matrix mit der Bitmap abgreichen (nur ein mal) for x := 0 to XMax do for y := 0 to YMax do Image1.Picture.Bitmap.Canvas.Pixels[x, y] := Col[Matrix[x, y]]; end;
// Schritt procedure TForm1.Button2Click(Sender: TObject); begin // Hier klicken um ein Schritt auszuführen if not Population(Image1.Picture.Bitmap) then ShowMessage( 'Es gab keine einzige Änderung' ); end;
end. |
_________________ Popov
|
|
Popov
      
Beiträge: 1655
Erhaltene Danke: 13
WinXP Prof.
Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
|
Verfasst: Mi 12.03.03 14:43
Mir ist gerade eine Erweiterung eingefallen. Mit dem Code kann man etwas auf der Image1 zeichnen. In diesem Fall sollte Button1 nicht benutzt werden:
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
| procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Matrix[x, y] := True; Image1.Picture.Bitmap.Canvas.Pixels[x, y] := Col[True];
Image1.Tag := 1; end;
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if Image1.Tag = 0 then Exit;
Matrix[x, y] := True; Image1.Picture.Bitmap.Canvas.Pixels[x, y] := Col[True]; end;
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Image1.Tag := 0; end; |
_________________ Popov
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Mi 12.03.03 15:00
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:
| const groesse_x =300; groesse_y =300; abstand = 0;
type Tposition = Record x,y : Integer; end;
VAR rect_w : Integer; rect_h : Integer;
var Form1: TForm1; pop : Array of Array of Char; geaendert : Array of Tposition; x,y : Integer; besetzung, anzahl_geaendert : Integer; clear_rect : TRect;
implementation
{$R *.dfm}
function zaehle_nachbarn_besetzt(x,y : Integer) : Integer; VAR x2, y2 : Integer; anzahl : Integer; begin anzahl:=0; for x2:=x-1 TO x+1 DO for y2:=y-1 TO y+1 DO begin if not ((x2=x) and (y2=y)) then //nicht das Feld selber if (x2>=0) and (x2<groesse_x) and (y2>=0) and (y2<groesse_y) then //nicht ausserhalb des Bereichs if pop[x2,y2]='b' then inc(anzahl); end; result:=anzahl; end;
procedure berechne_pop; VAR nachbarn : Integer; begin anzahl_geaendert:=0; for x:=0 TO groesse_x-1 DO for y:=0 TO groesse_y-1 DO begin nachbarn:=zaehle_nachbarn_besetzt(x,y); if pop[x,y]='b' then case nachbarn of 0,1 : begin pop[x,y]:='u'; //Isolation Inc(anzahl_geaendert); geaendert[anzahl_geaendert-1].x:=x; geaendert[anzahl_geaendert-1].y:=y; end; 2,3 : ; //Überleben else begin pop[x,y]:='u'; //Überbevölkerung Inc(anzahl_geaendert); geaendert[anzahl_geaendert-1].x:=x; geaendert[anzahl_geaendert-1].y:=y; end; end else if nachbarn=3 then begin pop[x,y]:='b'; //3 besetzt --> Feld besetzen Inc(anzahl_geaendert); geaendert[anzahl_geaendert-1].x:=x; geaendert[anzahl_geaendert-1].y:=y; end; end; end;
function my_rect(x,y : Integer) : TRect; begin result.Left:=abstand+x*rect_w; result.Top:=abstand+y*rect_h; result.Right:=result.left+rect_w; result.Bottom:=result.top+rect_h; end;
procedure TForm1.draw_pop (canvas : TCanvas); VAR i : Integer; neu : TPosition; begin for i:=0 TO anzahl_geaendert-1 DO begin neu.x:=geaendert[i].x; neu.y:=geaendert[i].y; if pop[neu.x,neu.y]='u' then canvas.Brush.Color:=clWhite else canvas.Brush.Color:=clBlack; Canvas.FillRect(my_rect(neu.x,neu.y)); end; end;
procedure neue_pop; begin SetLength(pop,groesse_x); SetLength(geaendert,groesse_x*groesse_y); anzahl_geaendert:=groesse_x*groesse_y; for x:=0 TO groesse_x-1 DO begin SetLength(pop[x],groesse_y); for y:=0 TO groesse_y-1 DO begin if Random(100) <= besetzung-1 THEN pop[x,y]:='b' else pop[x,y]:='u'; geaendert[y*groesse_x+x].x:=x; geaendert[y*groesse_x+x].y:=y; end; end; end;
procedure TForm1.FormCreate(Sender: TObject); begin Randomize; rect_w := Trunc(Image1.Width/groesse_x); rect_h := Trunc(Image1.Height/groesse_y); Image1.Canvas.Pen.Width:=1; clear_rect.Left:=0; clear_rect.Top:=0; clear_rect.Right:=Image1.Width; clear_rect.Bottom:=Image1.Height; end;
procedure TForm1.Button1Click(Sender: TObject); begin if Timer1.Enabled then Timer1.Enabled:=false else begin ConvertEdit1.defvalue(Besetzung,70); neue_pop; Image1.canvas.Brush.Color:=clWhite; Image1.canvas.FillRect(clear_rect); Image1.canvas.Brush.Color:=clBlack; Timer1.Enabled:=true; end; end;
procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer); begin draw_pop(Image1.Canvas); berechne_pop; end; |
So sieht mein Code aus. Auf der Form befinden sich: ein DXTimer (geht auch mit einem normalen), ein Image, ein Button und ein modifziertes Editfeld, welches automatisch den eingegeben Wert als Integer ausgeben kann. Kann man ja aber auch noch manuell machen. In das Editfeld gibst Du ein, wieviele von hundert Feldern am Anfang besetzt sein sollen. Mit dem Button startest und stopst Du die Simulation.
MfG,
Peter
P.S.: Das Array mit CHar zu machen ist eigentlich unnötig (Boolean reicht), aber es war ja nun mal verlangt.
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Popov
      
Beiträge: 1655
Erhaltene Danke: 13
WinXP Prof.
Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
|
Verfasst: Mi 12.03.03 15:14
Wenn ich mir das jetzt überlege, dann ist meine Berechnung mit For-Schleifen falsch. Folgende Begründung:
Ich dursuche das Feld von links nach recht und dann nach unten. Wenn ich also den Zustand habe:
00100
00100
00100
dann wird nach der For-Schleifen Methode das mittlere Wesen es nicht überleben, obwohl es zwei Nachbar hat. Warum? Das oberste Wesen wird es nicht überleben weil es nur einen Nachbarn hat, den Mittleren. Der hat aber in dieser Periode zwei Nachbarn. Er müßte es also überleben, zumindest in diese Priode. Erst die nächste Periode überlebt er nicht.
Also muß man eigentlich mit zwei Matrizen arbeiten.
Also was mein ihr?
_________________ Popov
|
|
Popov
      
Beiträge: 1655
Erhaltene Danke: 13
WinXP Prof.
Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
|
Verfasst: Mi 12.03.03 15:19
| Peter Lustig hat folgendes geschrieben: | | P.S.: Das Array mit CHar zu machen ist eigentlich unnötig (Boolean reicht), aber es war ja nun mal verlangt. |
Ich sollte mir langsam angewöhnen die Fragen bis ende durchzulesen 
_________________ Popov
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Mi 12.03.03 15:32
| Zitat: | | Also muß man eigentlich mit zwei Matrizen arbeiten. |
Stimmt! Den Fehler habe ich auch gemacht. Du hast absolut recht. Man muss mit zwei Matrizen (oder Arrays, ist ja egal) arbeiten.
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Popov
      
Beiträge: 1655
Erhaltene Danke: 13
WinXP Prof.
Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
|
Verfasst: Mi 12.03.03 15:54
In diesem Fall muß bei meinem Code ein Prozedur ausgetauscht werden. Ich hab es mir relativ einfach gemacht. Einfach eine Matrix2 erstellt und bei jedem Schritt beide Matrizen abgleichen. Dann die Abfragen auf die Matrix2 beziehen.
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:
| // Ein Schritt in der Population function Population(Bmp: TBitmap): Boolean; var x, y: Integer; p: Byte; Matrix2: array[-1..XMax+1, -1..YMax+1] of Boolean; begin Result := False;
for y := -1 to YMax+1 do for x := -1 to XMax+1 do Matrix2[x, y] := Matrix[x, y];
for y := 0 to YMax do for x := 0 to XMax do begin p := 0; if Matrix2[x - 1, y] then Inc(p); if Matrix2[x + 1, y] then Inc(p); if Matrix2[x, y - 1] then Inc(p); if Matrix2[x, y + 1] then Inc(p); if Matrix2[x - 1, y - 1] then Inc(p); if Matrix2[x + 1, y + 1] then Inc(p); if Matrix2[x + 1, y - 1] then Inc(p); if Matrix2[x - 1, y + 1] then Inc(p);
if Matrix[x, y] then begin if p <= 1 then begin Matrix[x, y] := False; Bmp.Canvas.Pixels[x, y] := Col[False]; Result := True; end else if p > 3 then begin Matrix[x, y] := False; Bmp.Canvas.Pixels[x, y] := Col[False]; Result := True; end; end else begin if p = 3 then begin Matrix[x, y] := True; Bmp.Canvas.Pixels[x, y] := Col[True]; Result := True; end; end;
end;
//Application.ProcessMessages; end; |
_________________ Popov
|
|
poeter 
Hält's aus hier
Beiträge: 4
|
Verfasst: Mi 12.03.03 15:58
DANKE für die zahlreichen Antworten, ich werd das mal probieren. Ich meld mich wieder, muss aber morgen erst mal mein Vorabi in Bio schreiben und heute dafür lernen, hab deswegen keine Zeit
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Mi 12.03.03 16:10
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:
| procedure fuehre_pop_aenderung_aus; //Hier wird die Ändeurng nach Berechnung ausgeführt! VAR i : INTEGER; begin for i:=0 TO anzahl_geaendert-1 DO if pop[geaendert[i].x,geaendert[i].y]='u' then pop[geaendert[i].x,geaendert[i].y]:='b' else pop[geaendert[i].x,geaendert[i].y]:='u'; end;
procedure berechne_pop_aenderung; //Änderung wird noch nicht ausgeführt! VAR nachbarn : Integer; begin anzahl_geaendert:=0; for x:=0 TO groesse_x-1 DO for y:=0 TO groesse_y-1 DO begin nachbarn:=zaehle_nachbarn_besetzt(x,y); if pop[x,y]='b' then case nachbarn of 0,1 : begin //Isolation Inc(anzahl_geaendert); geaendert[anzahl_geaendert-1].x:=x; geaendert[anzahl_geaendert-1].y:=y; end; 2,3 : ; //Überleben else begin //Überbevölkerung Inc(anzahl_geaendert); geaendert[anzahl_geaendert-1].x:=x; geaendert[anzahl_geaendert-1].y:=y; end; end else if nachbarn=3 then begin //3 besetzt --> Feld besetzen Inc(anzahl_geaendert); geaendert[anzahl_geaendert-1].x:=x; geaendert[anzahl_geaendert-1].y:=y; end; end; fuehre_pop_aenderung_aus; end;
procedure TForm1.Button1Click(Sender: TObject); begin Timer1.Enabled:=Not Timer1.Enabled; end;
procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer); begin berechne_pop_aenderung; draw_pop(Image1.Canvas); end;
procedure TForm1.Button2Click(Sender: TObject); begin ConvertEdit1.defvalue(Besetzung,50); neue_pop; Image1.canvas.Brush.Color:=clWhite; Image1.canvas.FillRect(clear_rect); Image1.canvas.Brush.Color:=clBlack; draw_pop(Image1.Canvas); button1.Enabled:=True; end; |
So, jetzt funktioniert das auch bei mir. Ich arbeite mit meinen Array "geaendert". Dort wird gespeichert, welche sich ändern, aber die Änderung wird im Populations-Array noch nicht gespeichert, das passiert erst nach kompletter Berechnung. Ich habe Button1 außerdem nur noch als Start / Stop und mit einem Button2 kann man jetzt eine neue Population erstellen und direkt anschauen, ob sie einem gefällt. Button1 sollte zur Designzeit auf Enabled=false gestellt werden.
Alle nicht geposteten Methoden haben sich auch nicht geändert.
MfG,
Peter
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Pyr0cracker
      
Beiträge: 164
Win XP, Ubuntu 8.04, openSUSE 11.0
Delphi 7 Personal
|
Verfasst: Mi 12.03.03 16:28
find ich gut die idee, könntet ihr das fertige programm zum runterladen anbieten? ich würde es gerne mal ausprobieren.
man könnte es auch erweitern indem man die umgebung mit einbeziehen z.b. nahrung, temperatur etc., die man dann optimal anpassen muss,das wäre doch eine gute idee für ein spiel findet ihr nicht?
ciao
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Mi 12.03.03 17:14
Hi!
Das Programm in seiner gegenwärtigen Gestalt steht jetzt zum [url= www.stelzmann-duesse...n.exe]Download[/url] bereit. Ist allerdings alles noch ziemlich provisorissch. Finde ich aber sehr interessant, deswegen werde ich bestimmt noch weiter dran schreiben. Irgendwann gibt's das dann in der Open Source-Sparte.
MfG,
Peter
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Zuletzt bearbeitet von Christian S. am Mi 12.03.03 19:50, insgesamt 1-mal bearbeitet
|
|
Popov
      
Beiträge: 1655
Erhaltene Danke: 13
WinXP Prof.
Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
|
Verfasst: Mi 12.03.03 17:28
Das mit der Open Source-Sparte kannst du dir abschmiken. Das hab ich mir schon vorgenommen
Ok, möge der bessere gewinnen.
_________________ Popov
|
|
Christian S.
      
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Mi 12.03.03 18:00
Ich glaube an eine friedliche Koexistenz verschiedener Source-Codes. Ansonsten werde ich Dich beschuldigen, Massenvernichtungsalgorithmen zu entwerfen, die meine Population vernichten sollen und unabhängige Inspektionen fordern!
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
|