Entwickler-Ecke
Sonstiges (Delphi) - Projekt: Wachstum einer Population darstellen?!?
poeter - Mi 12.03.03 09:05
Titel: Projekt: Wachstum einer Population darstellen?!?
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 - 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.
Delete - Mi 12.03.03 12:32
Google mal nach "Spiel des Lebens" oder wie das heißt, das ist so ähnlich.
Christian S. - 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
Popov - 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:
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:
| 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 - 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; |
Christian S. - Mi 12.03.03 15:00
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:
| 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.
Popov - 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 - 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 ;)
Christian S. - 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.
Popov - 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.
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:
| // 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; |
poeter - 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. - Mi 12.03.03 16:10
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:
| 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
Pyr0cracker - 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. - Mi 12.03.03 17:14
Hi!
Das Programm in seiner gegenwärtigen Gestalt steht jetzt zum [url=
http://www.stelzmann-duesseldorf.de/population/population.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
Popov - 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.
Christian S. - 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!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!