Entwickler-Ecke
Sonstiges (Delphi) - [Tutorial] Game of Life
Nini - Mo 09.03.15 22:14
Titel: [Tutorial] Game of Life
Ich muss für die Schule das Game of life programmieren.
ich habe mir auch schon einen Handlungsplan überlegt und bin schon so weit gekommen, dass ich weiß, dass ich nen timer brauchen und nen stringgrid.
aber jetzt weiß ich nicht mehr weiter. Wie funktionieren die Befehle, die die Zellen die ich makiere (wie gehts das eigentlich) einlesen?
Danach will ich über ein Feld festlegen, dass die makierten schwarz werden und damit wahr sind und die weißen falsch also quasi ein array of boolean, kann das so funktionieren?
weiter weiß ich leider noch nicht :/
danke, wenn ihr mir helfen könntet
und ja, ich habe auch shcon die anderen themen durchgelesen aber ich verstehe das alles einfach überhaupt nicht ;/
Moderiert von Narses: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Mo 09.03.2015 um 21:54
Moderiert von Narses: Titel geändert, war: "game of life stringgrid - probleme mit der delphi-sprache"
Moderiert von Narses: Titel geändert, war: "[Hausaufgabe] Game of Life".
Narses - Mo 09.03.15 23:19
Moin und :welcome: in der EE!
Nini hat folgendes geschrieben : |
Ich muss für die Schule das Game of life programmieren. |
Ich möchte das gleich zu Anfang festhalten: wir machen hier keine Hausaufgaben. :| Aber wir helfen dir sicher gerne dabei, das gemeinsam hinzukriegen. Wenn du mitmachst und Einsatz zeigst, werden wir das auch schaffen. :zustimm:
Nini hat folgendes geschrieben : |
ich habe mir auch schon einen Handlungsplan überlegt und bin schon so weit gekommen, dass ich weiß, dass ich nen timer brauchen und nen stringgrid. |
Klar, den Timer bauchst du später, um "Bewegung" in das Ganze zu kriegen, aber ich würde dir als Anfänger erstmal nicht zu einem StringGrid für die Ausgabe raten. :? Das ist etwas friemelig mit dieser Komponente...
Nini hat folgendes geschrieben : |
Wie funktionieren die Befehle, die die Zellen die ich makiere (wie gehts das eigentlich) einlesen? |
Wie schon gesagt, ich würde das nicht mit einem StringGrid machen. :nixweiss: Statt dessen würde ich dir gerne einen anderen Ansatz für die GUI zeigen wollen: :idea:
- Leg mal ein neues Projekt an
- Dann wählst du von der Registerkarte "Zusätzlich" ein TShape, klickst es auf das Formular (heißt dann automatisch Shape1) und ziehst die Größe auf 25x25 Pixel (die Größe ist erstmal nicht so wichtig, aber sonst wird das Formular bei mehr Zellen später so riesig)
- Wenn das Shape-Rechteck auf dem Formular markiert ist kopierst du es dir mit Strg+C, dann fügst du eine Kopie davon mit Strg+V ein, die legst du rechts neben das erste Shape
- Das Ganze jetzt noch 14x wiederholen, so dass du ein 4x4-Felder-Raster hast:
- Bei selektierter Form markierst du nun mit Strg+A alle Shapes, dann gehst du in den Objektinspektor auf die Seite "Ereignisse" und machst einen Doppelklick auf das Ereignis "OnMouseDown", es wird ein Ereignishandler angelegt. Da schreibst du folgenden Code rein:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure TForm1.Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ThisShape: TShape; begin ThisShape := (Sender as TShape); if (ThisShape.Brush.Color = clWhite) then ThisShape.Brush.Color := clBlack else ThisShape.Brush.Color := clWhite; end; |
Starte das Projekt, dann kannst du mit der Maus die Farbe der Zellen durch Anklicken "umdrehen". :think:
Wenn du das soweit als Ausgangspunkt hast, können wir weiter machen. ;)
cu
Narses
Nini - Di 10.03.15 17:28
Danke sehr :)
aber mal eine dumme frage: was bedeutet GUI?
Als nächstes muss ich doch jetzt ja einlesen, welche felder gefärbt sind und welche nicht. dafür benötige ich ja eine neue prozedur, kommt die in einen "start"-button? und wie les ich das dann ein?
Narses - Di 10.03.15 19:30
Moin!
Nini hat folgendes geschrieben : |
aber mal eine dumme frage: was bedeutet GUI? |
Das hat dir
WasWeißDennIch ja schon erläutert. :beer:
Nini hat folgendes geschrieben : |
Als nächstes muss ich doch jetzt ja einlesen, welche felder gefärbt sind und welche nicht. dafür benötige ich ja eine neue prozedur, kommt die in einen "start"-button? und wie les ich das dann ein? |
Leider hab ich jetzt grade keine Zeit, hier weiter zu machen (ich hab noch einen Termin). :? Ich schreibe dir später noch was dazu. :zustimm:
cu
Narses
ub60 - Di 10.03.15 23:49
Die Idee mit dem StringGrid ist gar nicht mal so schlecht.
- Du füllst alle Zellen mit '0' (kein Feld markiert).
- Dann schreibst Du in DrawCell des StringGrids eine neue Zeichenroutine (wenn '0', dann weiß, wenn '1', dann schwarz).
- Zum Schluss schreibst Du in MouseDown des StringGrids: Wenn angeklickte Zelle='0', dann Zelle:='1', sonst Zelle:='0'.
So, das wars schon. Und in Quelltext sind das unter 15 Zeilen.
Ich hoffe, es hilft etwas.
ub60
Narses - Mi 11.03.15 00:57
Moin!
Narses hat folgendes geschrieben : |
Ich schreibe dir später noch was dazu. |
Soo, jetzt ist später. :D
ub60 hat folgendes geschrieben : |
Die Idee mit dem StringGrid ist gar nicht mal so schlecht. |
Tja, das ist zugegeben Ansichtssache. :nixweiss: Womit ich sagen möchte, dass das, was ub60 da vorschlägt, durchaus OK ist (es wird zu einer Lösung führen). Ich würde es nur so nicht angehen wollen, da ich ein StringGrid für wenig didaktisch "hilfreich" halte. Aber das ist eben: Ansichtssache. :P
Leider haben wir nun ein Problem:
Nini hat folgendes geschrieben : |
Als nächstes muss ich doch jetzt ja einlesen, welche felder gefärbt sind und welche nicht. dafür benötige ich ja eine neue prozedur, kommt die in einen "start"-button? und wie les ich das dann ein? |
Da es jetzt zwei Vorschläge gibt, wie es weiter gehen soll, musst du dich nun entscheiden, welchen "Weg" du gehen möchtest:
- willst du mit dem StringGrid (wie du es selbst und ub60 vorgeschlagen haben) weiter machen
oder
- den Ansatz mit den Shapes von mir verfolgen?
:nixweiss: Ich gehe davon aus, dass beide Wege an dein Ziel führen werden, eine funktionierende Implementation von Game of Life zu erstellen. Allerdings bin ich jetzt verständlicherweise nur für meinen Vorschlag "zuständig". ;) Wenn du also mit dem StringGrid weiter machen möchtest (wie du es auch angesprochen hast), dann kann dir ub60 sicher damit weiterhelfen. :beer:
Wenn du mit meinem Ansatz weiter machen möchtest, dann antworte bitte entsprechend, damit wir dort weiter machen können. :) Falls dem so ist, sag doch auch nochmal bitte was zu deinem Kenntnisstand: kannst du mit arrays etwas anfangen? Mehrdimensionale Arrays? records? Funktionen und Prozeduren? Klassen? :les: :gruebel:
cu
Narses
Nini - Mi 11.03.15 16:22
Ich würde mich für den Weg mit den Shapes entscheiden, weil ich stringgrids auch im unterricht überhaupt nicht behersche.
mehrdimensionale arrays, records, funktionen und klassen sagen mir nichts. mit prozeduren arbeiten wir im unterricht immer aber ich nutze sie mehr als sie zu verstehen und arrays weiß ich nur, dass es da indixe gibt und dass die was mit vielen rechnungen wie sieb des erastotheles vereinfachen aber wie die genau zu benutzen sind weiß ich leider nicht, info ist leider nicht so mein bestes fach :/
Narses - Mi 11.03.15 17:53
Moin!
Nini hat folgendes geschrieben : |
Ich würde mich für den Weg mit den Shapes entscheiden |
OK, dann machen wir da weiter. ;)
Ich hätte dann noch zwei Fragen:
a) Möchtest du ein statisches Feld (durch virtuelle "tote" Felder begrenzt) oder ein "unendliches" (=Torus) Feld umsetzen?
Hier steht mehr dazu [
http://de.wikipedia.org/wiki/Conways_Spiel_des_Lebens] :les: (wobei ich stark hoffe, dass du das meiste davon schon gelesen hast :?).
b)
Nini hat folgendes geschrieben : |
mehrdimensionale arrays, records, funktionen und klassen sagen mir nichts. |
Verstehst du, was das hier für einen Zweck hat? Wenn ja, kannst du kurz beschreiben, welchen?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| const N = 4;
type TFeld = array[0..N-1, 0..N-1] of Boolean;
var Feld: TFeld; |
Wenn du das nicht verstehst, ist das auch OK. Es hat nur dann Sinn, wenn ich auf deinem Verständnislevel schreibe, weil es sonst an dir "vorbei" geht... :zwinker: Es geht also nur darum herauszufinden, wie du mir am besten folgen kannst. :idea:
cu
Narses
Nini - Mi 11.03.15 18:08
also ich dachte eher an ein torusförmiges spielfeld außer das ist viel schwieriger als das andere?
das meiste hatte ich wirklich schon gelesen oder zumindest schonmal überflogen ;)
also ich verstehe das feld so, dass es bestimmt für x und y werte stehen und da jeweils von null bis n-1 als index gibt und die werte für das feld können jeweils nur wahr oder falsch sein wegen boolean
Narses - Mi 11.03.15 22:36
Moin!
Nini hat folgendes geschrieben : |
also ich dachte eher an ein torusförmiges spielfeld außer das ist viel schwieriger als das andere? |
Nein, das ist überhaupt gar kein Problem und auch kein anderer "Schwierigkeitsgrad". ;)
Nini hat folgendes geschrieben : |
das meiste hatte ich wirklich schon gelesen oder zumindest schonmal überflogen ;) |
:zustimm:
Nini hat folgendes geschrieben : |
also ich verstehe das feld so, dass es bestimmt für x und y werte stehen und da jeweils von null bis n-1 als index gibt und die werte für das feld können jeweils nur wahr oder falsch sein wegen boolean |
:zustimm:
Dann übernehmen wir mal diesen Teil in das Projekt und ich zeige dir, wie man die Farbe der Shapes in so ein Feld überträgt. Deine Aufgabe ist dann anschließend den Code zu schreiben, um die Werte aus dem internen Feld wieder in die Farbe eines Shapes zu übertragen.
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: 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:
| uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls;
const N = 4; type TFeld = array[0..N-1, 0..N-1] of Boolean; TForm1 = class(TForm) Shape1: TShape; ... Shape16: TShape; btnLesen: TButton; btnSchreiben: TButton; procedure Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure btnLesenClick(Sender: TObject); procedure btnSchreibenClick(Sender: TObject); private public Feld: TFeld; end;
...
procedure TForm1.Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); ... end;
procedure TForm1.btnLesenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); Feld[x, y] := (Shape.Brush.Color = clBlack); end; end;
procedure TForm1.btnSchreibenClick(Sender: TObject); begin end; |
Alles, was in dem Projekt neu ist, habe ich markiert. Das solltest du nun in dein Projekt übertragen. Hier noch ein paar Erläuterungen:
- Ich habe zwei Buttons auf das Formular gelegt und "btnLesen" bzw. "btnSchreiben" genannt. Die sind später für das endgültige Projekt nicht nötig, sondern nur ein Zwischenschritt, damit du die neuen Teile auch mal ausprobieren kannst.
- Du kannst fast alles markierte oben per Copy+Paste übertragen, aber die Funktionsrümpfe für die beiden neuen Buttons musst du natürlich durch einen Doppelklick auf dem Button im Formular von Delphi erstellen lassen, sonst fehlt dir die Zuordnung der Methode zum Button, was dazu führt, dass der Button nix tut, wenn man das Programm laufen lässt und draufklickt :idea:
- Der einzige echte "Trick" ist die Funktion FindComponent() oben, damit kann man auf eine Komponente über ihren Namen(!) zugreifen. Das tun wir hier nämlich: wir berechnen die Nummer, die hinten an dem Shape steht in der Variable snr und dann holen wir uns eine Referenz auf dieses Shape. Und zum Schluss schauen wir, ob die Farbe Schwarz ist, was wir uns als "True"-Wert im Feld merken.
Probier mal, ob du den Code vervollständigt kriegst. Wenn du noch Fragen hast, immmer her damit. Ansonsten frisch ans Werk :D und melde dich bitte mit dem Code von deinem Projekt in einem neuen Beitrag.
cu
Narses
Nini - Do 12.03.15 21:18
Ich versteh leider nicht, was da beim Werte ermitteln passiert :/ für mich liest sich das so, als ob ich da einfach alles schwarz machen würde
Delphi-Quelltext
1:
| Feld[x, y] := (Shape.Brush.Color = clBlack); |
Moderiert von Narses: Quote- durch Delphi-Tags ersetzt
Narses - Do 12.03.15 21:20
Moin!
Nini hat folgendes geschrieben : |
Ich versteh leider nicht, was da beim Werte ermitteln passiert :/ für mich liest sich das so, als ob ich da einfach alles schwarz machen würde |
OK, schreiben wir das mal anders (länger, ich hab´s zusammengefasst :?):
Delphi-Quelltext
1: 2: 3: 4:
| if (Shape.Brush.Color = clBlack) then Feld[x, y] := True else Feld[x, y] := False; |
Verständlicher? ;)
cu
Narses
Nini - Do 12.03.15 21:35
ja, danke, gleich viel verständlicher :)
und in die zweite prozedur mach ich ja jetzt wieder so zwei for-schleifen in einander, aber was will ich eigentlich genau in dem shape anzeigen lassen? weil die sind ja schon weiß oder schwarz, soll ich da jetzt was reinschreiben ?
Jann1k - Do 12.03.15 21:52
Ja, du hast dann zwei Methoden eine liest die Farben aus den Shapes und schreibt sie als Boolean-Werte ins Array und die zweite liest die Werte aus dem Array und setzt die Farbe in den Shapes.
Im Moment klingt das ziemlich unsinnig, die Werte einfach hin und her zu schreiben, aber Narses wird dir auch noch eine dritte Prozedur an die Hand geben, in der sich die Werte im Array dann - gemäß den Spielregeln - ändern.
Nini - Do 12.03.15 22:20
so, das ist was ich machen würde, aber irgendwas stimmt daran noch überhaupt nicht.
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: 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:
| unit Unit1;
{$mode objfpc}{$H+}
interface
uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls;
const N = 4; type TFeld = array[0..N-1, 0..N-1] of Boolean;
TForm1 = class(TForm) btnSchreiben: TButton; btnLesen: TButton; Shape1: TShape; Shape10: TShape; Shape11: TShape; Shape12: TShape; Shape13: TShape; Shape14: TShape; Shape15: TShape; Shape16: TShape; Shape2: TShape; Shape3: TShape; Shape4: TShape; Shape5: TShape; Shape6: TShape; Shape7: TShape; Shape8: TShape; Shape9: TShape; procedure btnLesenClick(Sender: TObject); procedure btnSchreibenClick(Sender: TObject); procedure Shape1ChangeBounds(Sender: TObject); procedure Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); private public Feld: TFeld; end;
var Form1: TForm1;
implementation
{$R *.lfm}
procedure TForm1.Shape1ChangeBounds(Sender: TObject); begin
end;
procedure TForm1.btnSchreibenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin if (feld[x,y] = true) then begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); shape.brush.color := clblack end; else shape.brush.color := clwhite;
end;
end;
procedure TForm1.btnLesenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (Shape.Brush.Color = clBlack) then Feld[x, y] := True else Feld[x, y] := False; end; end;
procedure TForm1.Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var Thisshape : TShape; begin ThisShape := (Sender as TShape); if (ThisShape.Brush.Color = clWhite) then ThisShape.Brush.Color := clBlack else ThisShape.Brush.Color := clWhite; end;
end. |
Moderiert von Martok: Quote- durch Delphi-Tags ersetzt
Narses - Do 12.03.15 22:36
Moin!
Ja, schon gar nicht schlecht. :zustimm: Betrachten wir mal nur den hier relevanten Teil:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure TForm1.btnSchreibenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin if (feld[x,y] = true) then begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); shape.brush.color := clblack end; else shape.brush.color := clwhite;
end; end; |
Es ist leider zwar logisch korrekt auf = True zu vergleichen, aufgrund von technischen Details, die ich dir jetzt mal erspare, kann das zu Ergebnissen führen, die du so nicht erwarten und deshalb als "falsch" interpretieren würdest. Also: niemals auf = True testen, sondern einfach nur schreiben:
Delphi-Quelltext
1:
| if (feld[x,y]) then begin |
Nächstes Problem: du ermittelst nur im Fall einer schwarzen Zelle die Referenz auf das Shape neu (der entsprechende Code steht in dem Teil der Fallunterscheidung, die sich mit schwarzen Zellen beschäftigt). Wenn du also auf eine weiße Zelle triffst, dann färbst du das "falsche" Shape ein (weil du die Referenz nicht neu berechnest)... :hair: Lösungsidee: der Code, der die Referenz auf das Shape bestimmt, muss in jedem Fall (für schwarze und weiße Zellen) ausgeführt werden. :idea:
Kannst du das noch ändern? :zustimm:
Und als Funktions-Test: klicke mal irgendwelche Zellen schwarz, dann einmal auf den "Lesen"-Button (das ist dann so wie "speichern"), dann machst du irgendwelche anderen Zellen schwarz und klickst auf den "Schreiben"-Button (wirkt dann so wie "laden"). Jetzt sollten wieder die Zellen schwarz sein, die du beim Klick auf den "Lesen"-Button gefärbt hattest. :idea: Wenn das so abläuft, ist alles korrekt. :)
cu
Narses
Nini - Do 12.03.15 23:24
yeah, so klappt es :) danke sehr
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TForm1.btnSchreibenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin if (feld[x,y]) then begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); shape.brush.color := clblack end else begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); shape.brush.color := clwhite; end;
end;
end; |
Moderiert von Narses: Quote- durch Delphi-Tags ersetzt
Narses - Do 12.03.15 23:27
Moin!
Nini hat folgendes geschrieben : |
yeah, so klappt es :) danke sehr |
Super! :zustimm:
Aber :gruebel: schau doch nochmal genau hin, du hast da zwei komplett identische Zeilen stehen, muss das wirklich so sein? :lupe: Geht das nicht etwas ... kürzer? :zwinker:
cu
Narses
Nini - Do 12.03.15 23:34
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (feld[x,y]) then shape.brush.color := clblack else shape.brush.color := clwhite; |
so, da hätt ich auch selbst drauf kommen könne :P
Moderiert von Narses: Quote- durch Delphi-Tags ersetzt
Narses - Do 12.03.15 23:36
Moin!
Top, genau so! :zustimm:
Dann gehen wir mal an den Kern der Sache: das eigentliche Spiel. 8) Könntest du mal kurz die Regeln zusammenfassen, nach denen bestimmt wird, wie eine neue Generation berechnet wird (ruhig in Umgangssprache, das übersetzen wir dann nach und nach in Code)? :les:
cu
Narses
Nini - Do 12.03.15 23:40
conways regeln besagen glaub ich, dass eine schwarze zelle weiß wird , wenn sie 0,1,4,5,6,7,8 nachbarn hat, es passiert nihts mit einer zelle, wenn sie zwei nachbarn hat und eine weiße zelle wird schwarz, wenn sie 3 nachbarn hat
Narses - Do 12.03.15 23:43
Moin!
Nini hat folgendes geschrieben : |
conways regeln besagen glaub ich |
Glaub ich oder weiß ich? :gruebel: :zwinker: Das dumme ist, Computer wollen immer alles ganz genau haben (so wie Lehrer :lol:), also kann ich dir das nicht ersparen:
Schreib mal bitte getrennt auf, welche Bedingungen zu einer neuen schwarzen, und welche zu einer neuen weißen Zelle führen (diesmal aber bitte mit dem Attribut "wissen", nicht glauben... 8)).
cu
Narses
Nini - Do 12.03.15 23:48
ich weiß, dass es folgendermaßen ist:
weiß --> schwarz bei 3 Nachbarn
schwarz --> weiß bei 0,1,4,5,6,7,8 Nachbarn
keine Änderung bei 2 Nachbarn
Narses - Do 12.03.15 23:50
Moin!
Und was ist mit 3 Nachbarn bei schwarzen Zellen? :lupe:
cu
Narses
Nini - Do 12.03.15 23:54
die bleibt doch schwarz oder nicht?
Narses - Do 12.03.15 23:58
Moin!
Ja, aber du hast es nicht in deiner Liste erwähnt. :nixweiss: (zur Erinnerung: Computer :arrow: ganz genau aufschreiben) ;)
OK, nächster Schritt: Verändere bitte die Aufzählung so, dass nur berücksichtigt wird, wie schwarze Zellen in der neuen Generation entstehen (also die Regeln formulieren, die schwarze Zellen zur Folge haben [egal ob neue oder "alte"]). Wenn etwas nicht erwähnt wird, wird die Zelle eben automatisch weiß. :idea:
cu
Narses
Nini - Fr 13.03.15 00:01
eine Zelle wird schwarz, wenn sie 2 nachbarn haben oder schwarz sind und drei nachbarn haben
Narses - Fr 13.03.15 00:04
Moin!
Hm, OK, hab die Frage doof formuliert, ich fasse es nochmal zusammen:
Quelltext
1: 2: 3: 4:
| alt | neu --------------------------------------- weiß | 3 Nachbarn? -> schwarz schwarz | 2 oder 3 Nachbarn? -> schwarz |
Kommt das hin oder nicht? :lupe:
cu
Narses
Nini - Fr 13.03.15 00:08
ja, das stimmt so
Narses - Fr 13.03.15 00:15
Moin!
Gut, weiter geht´s.
Wir brauchen eine Art "Schmierzettel" bei der Berechnung der neuen Generation, wir müssen uns ja die Farbe der neuen Zellen "woanders" merken, damit wir die Rechenergebnisse der umliegenden Zellen nicht verfälschen. :idea:
Dann formulieren wir mal in Pseudo-Code:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| für alle Zellen im Feld wenn die alte Zelle weiß ist wenn die Anzahl der schwarzen Nachbarn dieser Zelle = 3 ist neue Zelle schwarz machen sonst neue Zelle weiß machen sonst (die alte Zelle ist dann logischerweise schwarz) wenn die Anzahl der schwarzen Nachbarn dieser Zelle = 2 oder 3 ist neue Zelle schwarz machen sonst neue Zelle weiß machen |
Kannst du mir folgen? Entspricht dieses Vorgehen den gerade in der Tabelle aufgestellten Regeln?
cu
Narses
Nini - Fr 13.03.15 00:17
ja, soweit versteh ich es noch und es stimmt mit der tabelle auch überein
Narses - Fr 13.03.15 00:24
Moin!
Gut, dann hast du sicher bemerkt, dass wir da eine Funktion verwenden, nämlich das "Anzahl der schwarzen Nachbarn"-Dings. ;) Das lassen wir auch mal so und kümmern uns später darum, dass diese Funktion das tut, was sie soll. Deshalb fügen wir in den Code nur eine leere Hülse ein (damit man es trotzdem schon kompilieren kann, obwohl es nicht tut, was es soll):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| TForm1 = class(TForm) Shape1: TShape; ... public Feld: TFeld; function AnzahlLebenderNachbarn(const x, y: Integer): Integer; end; ...
function TForm1.AnzahlLebenderNachbarn(const x, y: Integer): Integer; begin Result := 0; end; |
Jetzt fehlt dir noch der "Schmierzettel". ;) Dazu legen wir einen neuen Button "btnRechnen" auf das Formular. In dessen Ereignishandler schreiben wir:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| procedure TForm1.btnRechnenClick(Sender: TObject); var FeldNeu: TFeld; begin end; |
Auf geht´s! :zustimm:
cu
Narses
Nini - Sa 14.03.15 16:11
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| var x, y, snr: Integer;
feldneu : tfeld; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if not (feldneu[x,y]) then begin if wenn die Anzahl der schwarzen Nachbarn dieser Zelle = 3 ist then (Shape.Brush.Color = clBlack) else (Shape.Brush.Color = clWhite) end; else if wenn die Anzahl der schwarzen Nachbarn dieser Zelle = 2 oder 3 ist neue Zelle schwarz machen then (Shape.Brush.Color = clblack) else (Shape.Brush.Color = clwhite);
end;
end; |
soweit habe ich es hinbekommen, aber jetzt weiß ich nicht mehr weiter
Moderiert von Narses: Quote- durch Delphi-Tags ersetzt
Narses - Sa 14.03.15 17:45
Moin!
Hast du die (Dummy-)Funktion
AnzahlLebenderNachbarn() wie oben beschrieben in deinen Code übernommen?
Man ruft eine Funktion einfach über ihren Namen auf, also wird aus:
Delphi-Quelltext
1:
| if wenn die Anzahl der schwarzen Nachbarn dieser Zelle = 3 ist |
dann
Delphi-Quelltext
1:
| if (AnzahlLebenderNachbar(x, y) = 3) then |
Schau mal, ob du damit weiter kommst. :idea: Zumindest solltest du es dann kompilieren können.
Hinweis: Das ist natürlich noch nicht fertig, sondern nur ein Zwischenschritt, weil wir ja noch diese Funktion mit dem "echten Inhalt" füllen müssen, aber eins nach dem anderen. ;)
cu
Narses
PS: Und schau doch bitte mal, ob du die Einrückungen noch etwas schöner machen kannst. Das ist zwar nur "Schmuck am Christbaum" (also für die Funktionalität des Codes nicht wichtig, ja, ich weiß), aber trotzdem macht es den Code deutlich besser lesbar und damit verständlicher. :zustimm:
Nini - Sa 14.03.15 17:57
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if not (feldneu[x,y]) then if (AnzahlLebenderNachbarn(x, y) = 3) then (Shape.Brush.Color = clBlack) else (Shape.Brush.Color = clWhite) else if (AnzahlLebenderNachbarn(x, y) in [2, 3]) then (Shape.Brush.Color = clblack) else (Shape.Brush.Color = clwhite); end; |
Ich hab das jetzt so verändert, ind den letzten 5 zeilen werden mir die fehlermeldung angezeigt: "Error: Illegal Expression"
die funktion hab ich ei gebaut und das was ich gemacht hatte mit einrückungen hat's einfach nicht übernommen beim kopieren .,.
Moderiert von Narses: Quote- durch Delphi-Tags ersetzt
Narses - Sa 14.03.15 18:29
Moin!
Nini hat folgendes geschrieben : |
das was ich gemacht hatte mit einrückungen hat's einfach nicht übernommen beim kopieren |
Wenn du den Code in Delphi-Tags einfasst, dann passt das auch mit den Einrückungen:
[
delphi]begin
end;[
/delphi]
wird dann zu
Nini hat folgendes geschrieben : |
fehlermeldung angezeigt: "Error: Illegal Expression" |
Eine Zuweisung wird in Delphi mit ":=" gemacht, was du das hast, ist ein Vergleich, deshalb die Meldung. :idea:
cu
Narses
Nini - Sa 14.03.15 18:34
ok, danke, jetzt funktioniert es soweit :)
Narses - Sa 14.03.15 18:46
Moin!
Fein. :)
Allerdings :? Hast du noch zwei logische Fehler drin:
1. Du fragst Felder aus dem "Schmierzettel" ab (FeldNeu), statt aus dem internen Feld. Du musst natürlich Felder aus dem internen Feld abfragen und dir das Ergebnis im Schmierzettel merken.
2. steckt schon im Verbesserungsvorschlag von oben drin: du färbst direkt die Shapes in der GUI, statt in den Schmierzettel zu schreiben.
Das meinte ich vorhin mit dem Zwischenschritt: man wird noch keine direkte Auswirkungen sehen, wenn man auf den Button btnRechnen klickt.
cu
Narses
PS: Wenn du nicht weißt, worauf ich hinaus will, sag's ruhig, dann müssen wir noch mehr auf das Konzept eingehen. Zeig auch ruhig nochmal den aktuellen Code.
Nini - Sa 14.03.15 18:57
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure TForm1.btnRechnenclick(Sender: TObject); var x, y, snr: Integer; Shape: TShape;
begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if not (feld[x,y]) then if (AnzahlLebenderNachbarn(x, y) = 3) then (Shape.Brush.Color := clBlack) else (Shape.Brush.Color := clWhite) else if (AnzahlLebenderNachbarn(x, y) in [2, 3]) then (Shape.Brush.Color := clblack) else (Shape.Brush.Color := clwhite); end;
end; |
ich hab das feldneu jetzt zu feld wieder geändert, aber was ich noch ändern muss um es im "Schmierzettel" zu merken, statt direkt zu malen, weiß ich nicht. bedeutet das, dass ich die true/false werte ändern muss?
Narses - Sa 14.03.15 19:11
Moin!
Nini hat folgendes geschrieben : |
ich hab das feldneu jetzt zu feld wieder geändert |
:zustimm:
Nini hat folgendes geschrieben : |
was ich noch ändern muss um es im "Schmierzettel" zu merken, statt direkt zu malen, weiß ich nicht. bedeutet das, dass ich die true/false werte ändern muss? |
Ja, genau. ;) Ich wollte die Lösung nach dem EVA-Prinzip (Eingabe-Verarbeitung-Ausgabe) abwickeln. Also etwa so:
btnLesen anklicken (Werte aus der GUI in das interne Feld lesen)
btnRechnen anklicken (nächste Generation berechnen / unsichtbar!)
btnSchreiben anklicken (Werte aus dem internen Feld wieder in die GUI schreiben)
Dehalb arbeiten wir mit den Werten True / False in internen Arrays, statt direkt die Farben zuzuweisen (so trennt man die Logik von der Darstellung). Statt also Farbwerte zu setzen, weist du den bool´schen Wert ab das FeldNeu zu. :idea:
cu
Narses
Nini - Sa 14.03.15 19:20
also muss mein quelltext folgendermaßen aussehen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if not (feld[x,y]) then if (AnzahlLebenderNachbarn(x, y) = 3) then feldneu[x,y] := true else feldneu[x,y] := false else if (AnzahlLebenderNachbarn(x, y) in [2, 3]) then feldneu[x,y] := true else feldneu[x,y] := false; end; |
Narses - Sa 14.03.15 20:10
Moin!
Jawoll, so hab ich mir das vorgestellt. :zustimm: Aber: wir brauchen in der Prozedur doch gar keine Shapes mehr, also kann der betreffende Code wieder raus. :idea:
Und zum Abschluss müssen wir noch den Schmierzettel wieder "abschreiben" (weil die btnSchreiben-Prozedur ja von da die Werte holt). Hast du eine Idee, wie man das machen könnte?
cu
Narses
Nini - Sa 14.03.15 20:24
ein. also ehrlich gesagt, fällt mir dazu gar nichts ein :(
Narses - Sa 14.03.15 20:26
Moin!
Nun, Feld ist eine Variable und FeldNeu auch. Wie weist man denn einer Variablen den Wert einer anderen zu? 8)
cu
Narses
Nini - Sa 14.03.15 20:31
vlt mit feld := feldneu ?
Moderiert von Narses: Beiträge zusammengefasstvlt mit feld[x,y] := feldneu[x,y] ?
Narses - Sa 14.03.15 20:39
Moin!
Nini hat folgendes geschrieben : |
vlt mit feld := feldneu ? |
Jap! Genau so, ganz einfach. ;) (der Vollständigkeit halber: dein anderer Vorschlag ist auch nicht falsch, aber dann brauchst du auch noch die doppelten Schleifen drum rum, und das ist ja nicht nötig)
Wenn du diese letzte Zeile noch ergänzt hast, dann zeig doch bitte nochmal den Code.
Du kannst jetzt auch schon testen: ein paar Felder schwarz machen, btnLesen anklicken, btnRechnen anklicken, btnSchreiben anklicken und dann - sind alle Felder weiß! :shock: (was korrekt ist) Aber warum? :gruebel: ;)
cu
Narses
Nini - Sa 14.03.15 20:45
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: 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:
| function TForm1.AnzahlLebenderNachbarn(const x, y: Integer): Integer; begin Result := 0; end;
procedure TForm1.btnSchreibenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (feld[x,y]) then shape.brush.color := clblack else shape.brush.color := clwhite;
end;
end;
procedure TForm1.EndeClick(Sender: TObject); begin close; end;
procedure TForm1.Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ThisShape: TShape; begin ThisShape := (Sender as TShape); if (ThisShape.Brush.Color = clWhite) then ThisShape.Brush.Color := clBlack else ThisShape.Brush.Color := clWhite; end;
procedure TForm1.btnLesenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (Shape.Brush.Color = clBlack) then Feld[x, y] := True else Feld[x, y] := False; end; feld := feldneu end;
procedure TForm1.btnRechnenclick(Sender: TObject); var x, y: Integer;
begin for y := 0 to N-1 do for x := 0 to N-1 do begin if not (feld[x,y]) then if (AnzahlLebenderNachbarn(x, y) = 3) then feldneu[x,y] := true else feldneu[x,y] := false else if (AnzahlLebenderNachbarn(x, y) in [2, 3]) then feldneu[x,y] := true else feldneu[x,y] := false; end;
end; end. |
es wird alles weiß, weil in der funktion result := 0 steht, also sind alle nachbarn "tot" und deshalb sterben die zellen
Narses - Sa 14.03.15 20:56
Moin!
Wir waren doch bei der btnRechnen-Prozedur, warum schreibst du den Kopiercode in die btnLesen-Prozedur? :nixweiss: Und wo hast du FeldNeu deklariert? :lupe:
Nini hat folgendes geschrieben : |
es wird alles weiß, weil in der funktion result := 0 steht, also sind alle nachbarn "tot" und deshalb sterben die zellen |
Top! :zustimm:
Was passiert denn, wenn du statt 0 eine 3 zurück lieferst? (Nur mal so als test)
cu
Narses
Nini - Sa 14.03.15 21:02
feldneu hab ich wie feld unter public declariert
den kopiercode hab ich jetzt auch zur btnrechnen gewechselt
mit result := 3 werden alle felder schwarz
Narses - Sa 14.03.15 21:14
Moin!
Nini hat folgendes geschrieben : |
feldneu hab ich wie feld unter public declariert |
Brauchen wir denn FeldNeu "überall" in der Formularklasse? :gruebel: Ich denke nicht. :nixweiss: Also kann FeldNeu doch ruhig zu den anderen lokalen Variablen in btnRechnen, oder? ;)
Nini hat folgendes geschrieben : |
den kopiercode hab ich jetzt auch zur btnrechnen gewechselt |
:zustimm:
Nini hat folgendes geschrieben : |
mit result := 3 werden alle felder schwarz |
Das war zu erwarten. Warum? :lupe:
Was passiert, wenn du 2 zurücklieferst? Und speziell: was passiert, wenn du als Ausgangsgeneration die 4 Felder in der Mitte schwarz machst und einen weißen Rand aussen drum rum lässt?
cu
Narses
Nini - Sa 14.03.15 21:18
ja, stimmt, ich hab das jetzt umgeschreiben, also nur lokal deklariert
weil ja bei drei lebenden zellen eine neue zelle geboren wirde/die zelle schwarz wird, werden alle schwarz
bei zwei bleibt alles wie es ist
Narses - Sa 14.03.15 21:22
Moin!
Fein, dann haben wir die Regeln für das Game of Life schon fertig umgesetzt (ja, von "automatisch ablaufen" sind wir noch etwas entfernt, aber das kommt auch noch). :zustimm:
Jetzt zu dem Detail-Problem: wie kriegen wir die Anzahl der lebenden Nachbarn einer beliebigen Zelle raus (und damit den Code in die Funktion rein)? :gruebel: Mach doch mal einen Vorschlag, ruhig erstmal wieder in Umgangssprache oder, wenn du magst, auch gleich in Pseudo-Code. :les:
cu
Narses
Nini - Sa 14.03.15 21:29
vielleicht geht ja sowas dass man von den den nachbarn x-1 bis x+1 und y-1 bis y+1 die wahrheitswerte prüft und dann zählt oder so
Narses - Sa 14.03.15 21:33
Moin!
Nini hat folgendes geschrieben : |
vielleicht geht ja sowas dass man von den den nachbarn x-1 bis x+1 und y-1 bis y+1 die wahrheitswerte prüft und dann zählt oder so |
Top! :zustimm: Genau so hab ich das in meinem Test-Programm hierfür auch gemacht. ;)
Versuch doch mal diese Ablaufbeschreibung, die ja nun sehr kurz/grob ist, zu verfeinern, also z.B. in eine von mir aus umgangssprachlich formulierte Arbeitsanweisung zu übersetzen. Du kannst dich ja daran orientieren, wie wir über alle Felder mit den beiden Schleifen laufen, vielleicht kann man das ja so ähnlich machen? :idea:
cu
Narses
Nini - Sa 14.03.15 21:39
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
|
begin result := 0; for x = 0 to N-1 do for y = 0 to N-1 do begin if feld[x-1,y-1] = true then result:=result+1; if feld[x-1,y] = true then result:=result+1; if feld[x-1,y+1] = true then result:=result+1; if feld[x,y-1] = true then result:=result+1; if feld[x,y+1] = true then result:=result+1; if feld[x+1,y-1] = true then result:=result+1; if feld[x+1,y] = true then result:=result+1; if feld[x+1,y+1] = true then result:=result+1; end; end; |
kann das so funktionieren?
Narses - Sa 14.03.15 21:46
Moin!
Nini hat folgendes geschrieben : |
kann das so funktionieren? |
Ist nicht komplett verkehrt, aber an unserem Ansatz vorbei. :nixweiss:
Nochmal zur Erinnerung:
Delphi-Quelltext
1: 2: 3: 4:
| function TForm1.AnzahlLebenderNachbarn(const x, y: Integer): Integer; begin Result := 0; end; |
Wir haben diese Funktion deklariert. Die soll als Ergebnis (was der Wert von Result ist) die Anzahl der lebenden Zellen um die Zelle[x,y] liefern (das ist der Sinn der beiden Parameter dieser Funktion: um welche Zelle geht´s denn). :idea:
Wenn du allerdings 8 einzelne Abfragen verwenden möchtest (was nicht falsch ist, nur umständlich), dann kannst du die Schleifen weglassen. :nixweiss:
Dann versuch nochmal die Funktion zu vervollständigen und zeig deinen Code (nur die Funktion, wie oben, nur mit deinem "Inhalt").
cu
Narses
PS: Ich bin jetzt gleich bis ca. 22 Uhr (oder etwas später) offline.
PPS: Wie war das noch mit "= True"? :zwinker:
Nini - Sa 14.03.15 21:54
meine neue funktion:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| function TForm1.AnzahlLebenderNachbarn(const x, y: Integer): Integer;
begin result := 0;
if (feld[x-1,y-1]) then result:=result+1; if (feld[x-1,y]) then result:=result+1; if (feld[x-1,y+1]) then result:=result+1; if (feld[x,y-1]) then result:=result+1; if (feld[x,y+1]) then result:=result+1; if (feld[x+1,y-1]) then result:=result+1; if (feld[x+1,y]) then result:=result+1; if (feld[x+1,y+1]) then result:=result+1;
end; |
aber so ganz stimmt die noch nucht :(
Boldar - Sa 14.03.15 22:34
Das sieht doch schon ganz gut aus. Ich will mich hier jetzt nicht allzusehr einmischen, und Narses wird das dir dann schon erläutern, aber du kannst ja jetzt schonmal drüber nachdenken, in welchen Fällen (also welche Werte für x/y) die Funktion nicht funktionieren kann und wie man das abfangen könnte (Stichwort Modulo, sagt dir das etwas aus der Mathematik?).
Narses - Sa 14.03.15 23:18
Moin!
Nini hat folgendes geschrieben : |
meine neue funktion: |
Das ist doch schon ganz OK. ;) Allerdings ziemlich umständlich. :? Möchtest du das ändern? Also weniger umständlich machen? :nixweiss: Dann zeige ich dir noch einen kleinen Trick... 8)
Nini hat folgendes geschrieben : |
aber so ganz stimmt die noch nucht :( |
Warum, gibt´s Fehlermeldungen? :lupe:
Boldar hat schon drauf hingewiesen (:beer:), da ist noch ein generelles, logisches Problem drin. Bist du schon drauf gekommen?
cu
Narses
Nini - Sa 14.03.15 23:23
also nicht funktionieren kann es meiner meinung nach nicht für die randfelder
und mod sind die Restklassen bei der division mit einer bestimmten zahl
aber was genau falsch ist, weiß ich nicht :/
ja, einfacher wäre es mir schon lieber :P
nein, fehlermeldungen treten nicht auf, aber die felder die es anmalt sind noch ziemlich wahllos irgendwie ._.
Narses - Sa 14.03.15 23:31
Moin!
Nini hat folgendes geschrieben : |
ja, einfacher wäre es mir schon lieber :P |
OK, dann machen wir das. :zustimm: Man kann die umgebenden Felder auch mit zwei Schleifen "ablaufen", und zwar so:
Delphi-Quelltext
1: 2: 3: 4:
| for dx := -1 to 1 do for dy := -1 to 1 do if (Feld[x +dx, y +dy]) then Result := Result +1; |
Das hat nur einen winzig kleinen "Haken", erkennst du ihn? :lupe:
Nini hat folgendes geschrieben : |
also nicht funktionieren kann es meiner meinung nach nicht für die randfelder |
Jap, genau da ist das Problem. Da gehen wir gleich noch genauer drauf ein. :zustimm:
cu
Narses
Nini - Sa 14.03.15 23:34
nein, also so direkt fällt mir kein haken auf
Narses - Sa 14.03.15 23:45
Moin!
Nini hat folgendes geschrieben : |
nein, also so direkt fällt mir kein haken auf |
OK, dann müssen wir einen kleinen Exkurs einlegen, kein Problem. :)
Zunächst mal führen wir noch eine Funktion ein, die müssen wir wieder oben in der Klasse "anmelden":
Delphi-Quelltext
1: 2: 3: 4:
| public Feld: TFeld; function AnzahlLebenderNachbarn(const x, y: Integer): Integer; function LebtNachbar(x, y: Integer): Boolean; |
Der Sinn soll also sein, die Prüfung, ob eine bestimmte Zelle "lebendig" ist, auszulagern. Sonst wird der Code schnell unübersichtlich. :idea: Aber, wir machen da noch nicht den endgültigen Code rein, sondern erstmal was zum testen:
Delphi-Quelltext
1: 2: 3: 4: 5:
| function TForm1.LebtNachbar(x, y: Integer): Boolean; begin ShowMessageFmt('x=%d, y=%d', [x, y]); Result := Feld[x, y]; end; |
Wenn du das übernommen hast, dann müssen wir noch die Zähler-Funktion anpassen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| function TForm1.AnzahlLebenderNachbarn(const x, y: Integer): Integer; var dx, dy: Integer; begin Result := 0; for dy := -1 to 1 do for dx := -1 to 1 do if LebtNachbar(x +dx, y +dy) then Inc(Result); end; |
ACHTUNG: Mit diesem Code
nicht auf den btnRechnen klicken, sonst musst du zig-tausend Messageboxen wegklicken! :shock:
Statt dessen machst du noch einen neuen Button auf das Formular: btnTest, und da schreibst du rein:
Delphi-Quelltext
1: 2: 3: 4:
| procedure TForm1.btnTestClick(Sender: TObject); begin AnzahlLebenderNachbarn(1, 1); end; |
Jetzt das Projekt starten und einmal auf den neuen Test-Button klicken: Wieviele Messageboxen kommen und was steht drin?
cu
Narses
Nini - So 15.03.15 00:02
es kommt eine message boxx und darin steht "x=0,y=0"
Narses - So 15.03.15 00:03
Moin!
Nini hat folgendes geschrieben : |
es kommt eine message boxx und darin steht "x=0,y=0" |
Es wird nur genau eine MessageBox angezeigt?! :lupe: Da sollten ein paar mehr kommen... :gruebel: Zeig mal bitte deinen gesamten Code... :les:
cu
Narses
Nini - So 15.03.15 00:04
Nini hat folgendes geschrieben : |
es kommt eine message boxx und darin steht "x=0,y=0" |
oh, danack kommen ja noch welche :P
und danach x=1, y=0
x=2, y=0
x=0, y=1
x=1, y=1
x=2 y=1
x=0 y=2
x=1 y=2
x=2 y=2
und dann schließen sich die boxen
Narses - So 15.03.15 00:06
Moin!
Ah, schon besser. :P Und, wieviele sind es denn nun gewesen? :lupe:
cu
Narses
Nini - So 15.03.15 00:11
es waren 9
Narses - So 15.03.15 00:12
Moin!
OK, kannst du dann bitte mal die Nachbarn der Zelle[1,1] aufzählen? (oder als Abkürzung sagen, wieviele Nachbarn diese Zelle hat?)
cu
Narses
Nini - So 15.03.15 00:15
0,0
0,1
0,2
1,0
1,2
2,0
2,1
2,2
Narses - So 15.03.15 00:16
Moin!
Was fällt dir im Gegensatz zu den MessageBoxen auf? ;)
cu
Narses
Nini - So 15.03.15 00:20
eeehhhm, keine ahnung, vlt, dass ich die andersrum sotiert habe? und das halt die 1,1 nicht dazu gehört, weil die die zelle selbst ist
Narses - So 15.03.15 00:21
Moin!
Nini hat folgendes geschrieben : |
und das halt die 1,1 nicht dazu gehört, weil die die zelle selbst ist |
Hast ja doch Ahnung, genau das ist es! :zustimm: Und jetzt die Preisfrage: warum taucht denn bei der Lösung mit den beiden Schleifen die Zelle selbst auf (die ist ja kein Nachbar)?! :gruebel:
cu
Narses
Nini - So 15.03.15 00:31
weil nicht ausgeschlossen ist, dass dx und dy gleichzeitig 0 sein können
Narses - So 15.03.15 00:32
Moin!
Perfekt! :zustimm: Dann ändere das doch mal eben (und zeig dann den Code der Funktion bitte)! ;)
cu
Narses
Nini - So 15.03.15 00:40
so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| function TForm1.AnzahlLebenderNachbarn(const x, y: Integer): Integer; var dx, dy: Integer; begin Result := 0; for dy := -1 to 1 do for dx := -1 to 1 do if not ((x=0) and (y=0)) then if LebtNachbar(x +dx, y +dy) then Inc(Result); end; |
Narses - So 15.03.15 00:43
Moin!
Grandios! :zustimm: Genau so.
Dann ändere doch mal bitte den Testaufruf:
Delphi-Quelltext
1: 2: 3: 4:
| procedure TForm1.btnTestClick(Sender: TObject); begin AnzahlLebenderNachbarn(0, 0); end; |
Welche Werte werden dir nun nach einem Klick auf btnTest in den MessageBoxen angezeigt? Und gibt es da vielleicht schon ... Auffälligkeiten? :lupe: ;)
cu
Narses
Nini - So 15.03.15 00:47
bei mir passiert gar nichts mehr, wenn ich auf btntest gehe
Narses - So 15.03.15 00:48
Moin!
Aha :gruebel: zeig mal den ganzen Code... :les: Irgendwo nochwas geändert? :lupe:
cu
Narses
Nini - So 15.03.15 00:53
also bewusst habe ich nichts verändert :/
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: 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:
| public Feld: TFeld; function LebtNachbar(x, y: Integer): Boolean; function AnzahlLebenderNachbarn(const x, y: Integer): Integer; end;
var Form1: TForm1;
implementation
{$R *.lfm}
function TForm1.LebtNachbar(x, y: Integer): Boolean; begin ShowMessageFmt('x=%d, y=%d', [x, y]); Result := Feld[x, y]; end;
function TForm1.AnzahlLebenderNachbarn(const x, y: Integer): Integer; var dx, dy: Integer; begin Result := 0; for dy := -1 to 1 do for dx := -1 to 1 do if not ((x=0) and (y=0)) then if LebtNachbar(x +dx, y +dy) then Inc(Result); end;
procedure TForm1.btnTestClick(Sender: TObject); begin AnzahlLebenderNachbarn(0, 0); end;
procedure TForm1.btnSchreibenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (feld[x,y]) then shape.brush.color := clblack else shape.brush.color := clwhite; end;
end;
procedure TForm1.EndeClick(Sender: TObject); begin close; end;
procedure TForm1.Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ThisShape: TShape; begin ThisShape := (Sender as TShape); if (ThisShape.Brush.Color = clWhite) then ThisShape.Brush.Color := clBlack else ThisShape.Brush.Color := clWhite; end;
procedure TForm1.btnLesenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (Shape.Brush.Color = clBlack) then Feld[x, y] := True else Feld[x, y] := False; end;
end;
procedure TForm1.btnRechnenclick(Sender: TObject); var x, y: Integer; Feldneu : TFeld; begin for y := 0 to N-1 do for x := 0 to N-1 do begin if not (feld[x,y]) then if (AnzahlLebenderNachbarn(x, y) = 3) then feldneu[x,y] := true else feldneu[x,y] := false else if (AnzahlLebenderNachbarn(x, y) in [2, 3]) then feldneu[x,y] := true else feldneu[x,y] := false; end; feld := feldneu end; end. |
Narses - So 15.03.15 00:56
Moin!
Hm, sieht eigentlich gut aus. Dann kommentier mal diese Zeile testweise aus:
Delphi-Quelltext
1: 2: 3: 4: 5:
| function TForm1.LebtNachbar(x, y: Integer): Boolean; begin ShowMessageFmt('x=%d, y=%d', [x, y]); end; |
Mein Delphi hat da keine Probleme mit (was genau, sehen wir dann gleich schon), vielleicht hat Lazarus da aber schon eins... :? :nixweiss:
Geht´s dann wieder (kommen MessageBoxen)?
cu
Narses
Nini - So 15.03.15 01:00
nein, die messageboxen bleiben verschwunden :/
Narses - So 15.03.15 01:01
Moin!
OK, dann Projekt abspeichern, Lazarus beenden, wieder öffnen und das Projekt laden. Geht´s jetzt?
cu
Narses
Nini - So 15.03.15 01:04
das bringt auch nichts :/ das geht nur wenn ich die eine zeile auskommentier:
if not ((x=0) and (y=0)) then
Narses - So 15.03.15 01:07
Moin!
Nini hat folgendes geschrieben : |
das bringt auch nichts :/ das geht nur wenn ich die eine zeile auskommentier: |
Stimmt. :autsch: Da ist nämlich noch ein Fehler drin:
Delphi-Quelltext
1:
| if not ((dx = 0) and (dy = 0)) then |
Mach dir nix draus, ich hab´s auch die ganze Zeit übersehen... :lol:
Jetzt sollte das aber wieder laufen. ;)
cu
Narses
PS: Da hast du´s sogar selbst geschrieben: ;)
Nini hat folgendes geschrieben : |
weil nicht ausgeschlossen ist, dass dx und dy gleichzeitig 0 sein können |
Nini - So 15.03.15 01:11
ok jetzt kommt:
-1.-1
0,-1
1,-1
-1,0
1,0
-1,1
0,1
1,1
Narses - So 15.03.15 01:12
Moin!
Jap, das passt wieder. ;) Also weiter mit dem eigentlichen Problem: was davon ist ... problematisch? :lupe:
cu
Narses
Nini - So 15.03.15 01:13
die -1, die müsste ja eigentlich der höchste wert auf der anderen seite vom feld sein
Narses - So 15.03.15 01:15
Moin!
Richtig, also wenn die Werte < 0 sind, dann müssen wir... ja, was dann. Vorschläge? ;)
cu
Narses
Nini - So 15.03.15 01:16
vielleicht stattdessen N oder N-1 nehmen?
Narses - So 15.03.15 01:18
Moin!
Gegenangebot: N addieren? ;)
Verstanden? -> Codevorschlag zeigen.
Nicht verstanden? -> Wo hapert´s?
cu
Narses
Nini - So 15.03.15 10:12
vielleicht einfach mit zwei weiteren if schleifen if y+dy=-1 then y+dy:=y+dy+N
Narses - So 15.03.15 12:33
Moin!
Nini hat folgendes geschrieben : |
vielleicht einfach mit zwei weiteren if schleifen |
Zunächst mal zur Begrifflichkeit:
if: Fallunterscheidung (wenn-dann) :idea:
for, while, repeat: Schleifen (wiederhole irgendwas) :think:
Bitte nicht "if-schleifen" in Gegenwart von Informatikern sagen, die kriegen dann so ein schmerzhaftes Ziehen in der linken Gehirnhälfte und anschließend Ausschlag am ganzen Körper... :lol:
Nini hat folgendes geschrieben : |
if y+dy=-1 then y+dy:=y+dy+N |
Hm, damit kann ich jetzt wenig anfangen... :gruebel:
Vielleicht zeigst du erstmal die Stelle im Code, an der wir ansetzen müssen, um das Problem zu lösen. ;)
cu
Narses
Nini - So 15.03.15 12:52
ohh, ok, werde ich mir merken ;)
ich würde das vielleicht so machen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| function TForm1.AnzahlLebenderNachbarn(const x, y: Integer): Integer; var dx, dy: Integer; begin Result := 0; for dy := -1 to 1 do for dx := -1 to 1 do if not ((dx=0) and (dy=0)) then begin if (dx=-1) then begin dx:=dx+N; if (dy=-1) then begin dy:=dy+N; if LebtNachbar(x +dx, y +dy) then Inc(Result); end; end; end; end; |
Narses - So 15.03.15 13:19
Moin!
Nini hat folgendes geschrieben : |
ohh, ok, werde ich mir merken ;) |
:zustimm:
Nini hat folgendes geschrieben : |
ich würde das vielleicht so machen: |
Hm, zum einen macht das den Code recht unübersichtlich. Also alleine unter diesem Gesichtspunkte finde ich das keine gute Stelle. :nixweiss: Mit den beiden Schleifen (dx und dy) gehen wir alle Nachbar durch. Wenn du nun da eingreifst, hätte das ja zur Folge, dass nicht alle oder andere Nachbarn berücksichtigt würden. :gruebel: Also auch vom logischen Gesichtspunkt vielleicht keine glückliche Stelle. :? (zur Klarstellung: grundsätzlich geht das auch hier, empfehle ich dir aber nicht)
Wo könnte man es denn evtl. besser unterbringen? :lupe:
cu
Narses
Nini - So 15.03.15 13:28
mir fällt leider keine andere stelle ein :(
Narses - So 15.03.15 13:29
Moin!
Wir haben doch noch eine weitere Funktion eingeführt:
Delphi-Quelltext
1: 2: 3: 4:
| function TForm1.LebtNachbar(x, y: Integer): Boolean; begin Result := Feld[x, y]; end; |
Was meinst du, nur für diese eine Zeile? :zwinker:
cu
Narses
Nini - So 15.03.15 13:48
stimmt das dann so?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| function TForm1.LebtNachbar(x, y: Integer): Boolean; begin if x = -1 then x := x+N; if y = -1 then y := y+N; ShowMessageFmt('x=%d, y=%d', [x, y]); Result := Feld[x, y]; end; |
Narses - So 15.03.15 14:13
Moin!
Nini hat folgendes geschrieben : |
stimmt das dann so? |
Ja, das ist nicht falsch. :zustimm: Aber auch noch nicht alles... :? Immer mit der Ruhe. ;)
Ich würde das etwas allgemeiner formulieren:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| function TForm1.LebtNachbar(x, y: Integer): Boolean; begin ShowMessageFmt('vorher: x=%d, y=%d', [x, y]); if (x < 0) then x := x +N; if (y < 0) then y := y +N; ShowMessageFmt('nachher: x=%d, y=%d', [x, y]); Result := Feld[x, y]; end; |
Probier´s mal mit dem Test-Button aus. :les:
cu
Narses
Nini - So 15.03.15 14:16
das ist gut :) das klappt
Narses - So 15.03.15 14:19
Moin!
OK, nächster Schritt: ändere mal in dem btnTest-Handler die Aufrufparameter ab, so dass die rechte untere Zelle abgefragt wird. Dann auf den Test-Button klicken. Gibt´s da evtl. noch Probleme? :lupe:
cu
Narses
Nini - So 15.03.15 14:33
da gibt es jetzt zellen mit [4,4] und so und die gibt es nicht, die müssen wieder auf die andere seite
das hab ich jetzt so abgeändert:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| function TForm1.LebtNachbar(x, y: Integer): Boolean; begin ShowMessageFmt('vorher: x=%d, y=%d', [x, y]); if (x < 0) then x := x +N; if (y < 0) then y := y +N; if (x > (N-1)) then x := x -N; if (y > (N-1)) then y := y -N; ShowMessageFmt('nachher: x=%d, y=%d', [x, y]); Result := Feld[x, y]; end; |
Narses - So 15.03.15 14:37
Moin!
Nini hat folgendes geschrieben : |
da gibt es jetzt zellen mit [4,4] und so und die gibt es nicht, die müssen wieder auf die andere seite |
Jap. :)
Nini hat folgendes geschrieben : |
das hab ich jetzt so abgeändert: |
Funktionsfähig, zwar etwas umständlich, aber OK! :zustimm:
Dann nimm mal die Testausgaben raus, damit du dich gleich nicht "totklickst". ;) Wir sind soweit, einen echten Lauf zu probieren. :hair: Also klick dir mal drei schwarze Zellen horizontal oder vertikal zusammen (einen "Strich"), dann auf den btnLesen, dann btnRechnen, dann btnSchreiben und ab da:
btnRechnen -> btnSchreiben -> btnRechnen -> btnSchreiben usw.
Was passiert? :lupe:
cu
Narses
Nini - So 15.03.15 14:40
erst sind die zellen oxo dann ooo
oxo xxx
oxo ooo
und das wechselt sich immer ab
Narses - So 15.03.15 14:46
Moin!
Passt, der Strich wechselt also immer von liegend auf stehend und zurück. ;)
Dann mach mal die mittleren 4 Zellen schwarz und lass den Rand weiß. Wieder so vorgehen wie gerade, Lesen, Rechnen, Schreiben, Rechnen, Schreiben, etc.
Was passiert?
cu
Narses
Nini - So 15.03.15 14:47
die vier in der mitte bleiben schwarz, der rest bleibt weiß
Narses - So 15.03.15 14:52
Moin!
Und, ist das OK so oder nicht? :gruebel:
cu
Narses
Nini - So 15.03.15 14:56
das stimmt so
Narses - So 15.03.15 14:58
Moin!
Fein. :zustimm:
Dann erweitern wir erstmal das Feld auf 5x5 Shapes. Kannst du das mal kurz machen? Was muss man da alles tun (Stichpunkte reichen)?
Wenn das läuft, machen wir noch die Automatik dazu und dann ist gut. :)
cu
Narses
Nini - So 15.03.15 15:00
- die shapes hinzufügen
- die shapes auch mit in die procedure TForm1.Shape1MouseDown einbinden
- N von 4 auf 5 ändern
Narses - So 15.03.15 15:01
Moin!
GO! :zustimm:
cu
Narses
Nini - So 15.03.15 15:06
schon erledigt ;)
Narses - So 15.03.15 15:22
Moin!
Top! :D
Jetzt noch eine kleine Optimierung: wir haben immer nach einem Klick auf den btnRechnen auch auf den btnSchreiben gemacht (sonst sieht man ja nicht, was da berechnet wurde). Das machen wir jetzt per Code:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| procedure TForm1.btnRechnenClick(Sender: TObject); var x, y: Integer; FeldNeu: TFeld; begin for y := 0 to N-1 do for x := 0 to N-1 do if Feld[x, y] then FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) in [2..3]) else FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) = 3); Feld := FeldNeu; btnSchreibenClick(Self); end; |
Dann löschst du alle Buttons aus dem Formular (dabei sollte der Code für die Button-Handler stehen bleiben - bis auf den Test-Button, den kannst du ganz rausnehmen, mit Code).
Jetzt geht´s an die Automatik: leg einen Timer auf das Formular, den Namen änderst du auf "Timer" (die "1" kann weg, wir brauchen nur einen) und die Eigenschaft .Enabled auf "False" (der soll nicht von selbst loslaufen, wenn das Programm startet). Anschließend legst du noch eine Checkbox neu auf das Formular, die nennst du mal "ckAutomatik" und bei Caption kannst du reinschreiben, was du möchtest, die Eigenschaft .Checked bleibt auf "False" stehen.
Jetzt machst du einen Doppelklick auf der Checkbox, es wird ein Handler erstellt, da schreibst du rein:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TForm1.ckAutomatikClick(Sender: TObject); begin if ckAutomatik.Checked then begin btnLesenClick(Self); Timer.Enabled := True; end else Timer.Enabled := False; end; |
cu
Narses
Nini - So 15.03.15 15:31
ok, ich habe alles so gemacht
Narses - So 15.03.15 15:32
Moin!
Gut, was passiert, wenn du den Haken setzt?
cu
Narses
Nini - So 15.03.15 15:37
gar nichts :(
Narses - So 15.03.15 15:39
Moin!
Warum? :lupe: Und was tun wir dagegen? :gruebel:
cu
Narses
Nini - So 15.03.15 15:42
weil in der lesenprozedur nicht gesagt wird, dass die rechenprozedur aufgerufen wird, also muss ich dort jetzt das so machen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure TForm1.btnLesenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (Shape.Brush.Color = clBlack) then Feld[x, y] := True else Feld[x, y] := False; end; btnRechnenClick(Self); end; |
Narses - So 15.03.15 15:46
Moin!
Und, klappt´s jetzt (ich sag mal: nein :zwinker:)?
cu
Narses
Nini - So 15.03.15 15:55
hast recht, es geht nicht
es verändert sich eine generation lang und dann bleibt's stehn
Narses - So 15.03.15 15:56
Moin!
Jo, so ist es. :nixweiss: Also: kannst den Button-Aufruf da wieder raus nehmen.
Wie funktioniert denn ein Timer? Haben wir irgendwo gesagt, was der machen soll? :lupe: 8)
cu
Narses
Nini - So 15.03.15 15:59
nein, also so wirklich hab ich keine ahnung wie timer funktionieren :/
Narses - So 15.03.15 16:00
Moin!
Dann mach doch mal einen Doppelklick auf der Timer-Komponenten im Formular... :zwinker:
cu
Narses
Nini - So 15.03.15 16:01
damit hab ich eine weitere prozedur geöffnet.
muss ich da jetzt reinschreiben, dass er den rechnenbutton ausführen soll?
Narses - So 15.03.15 16:07
Moin!
Nini hat folgendes geschrieben : |
muss ich da jetzt reinschreiben, dass er den rechnenbutton ausführen soll? |
Jup. ;)
cu
Narses
Nini - So 15.03.15 16:09
es funktioniert *_*
Narses - So 15.03.15 16:35
Moin!
:party: :dance2: :beer: :dance:
Wie sieht´s aus, rein von der Aufgabe her bist du fertig: Game of Life läuft. :zustimm:
Willst du noch ein bisschen optimieren? ;) Evtl. könnte man ja die Feldgröße unabhängig von manuell angelegten Shapes machen? (man kann die Shapes auch per Programmcode anlegen und muss dann nur noch N ändern, wenn man das Feld größer machen möchte :idea:)
cu
Narses
Nini - So 15.03.15 16:47
joar, das hört sich gut an :)
kann man eigentlich das programm auch so ändern, dass der nutzer die regeln für geburt/tod ändern können?
Narses - So 15.03.15 17:06
Moin!
Nini hat folgendes geschrieben : |
joar, das hört sich gut an :) |
Gut, dann schauen wir mal, was noch geht. ;)
Nini hat folgendes geschrieben : |
kann man eigentlich das programm auch so ändern, dass der nutzer die regeln für geburt/tod ändern können? |
Mann kann schon, die Frage ist eher: kann Frau auch? :zwinker: (soll heißen: ja, klar kann man, aber wenn du keine Idee hast wie, könnte es noch etwas schwer sein für dich, oder?)
Dann zeig doch bitte erstmal deinen kompletten Code, damit ich den aktuellen Status kenne. :zustimm:
cu
Narses
Nini - So 15.03.15 17:21
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: 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: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172:
| unit Unit1;
{$mode objfpc}{$H+}
interface
uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls;
const N = 5; type TFeld = array[0..N-1, 0..N-1] of Boolean;
TForm1 = class(TForm) ckAutomatik: TCheckBox; Ende: TButton; Shape1: TShape; Shape10: TShape; Shape11: TShape; Shape12: TShape; Shape13: TShape; Shape14: TShape; Shape15: TShape; Shape16: TShape; Shape17: TShape; Shape18: TShape; Shape19: TShape; Shape2: TShape; Shape20: TShape; Shape21: TShape; Shape22: TShape; Shape23: TShape; Shape24: TShape; Shape25: TShape;
Timer: TTimer; procedure btnLesenClick(Sender: TObject); procedure btnRechnenClick(Sender: TObject); procedure btnSchreibenClick(Sender: TObject); procedure ckAutomatikChange(Sender: TObject); procedure EndeClick(Sender: TObject); procedure Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure TimerTimer(Sender: TObject);
private
public Feld: TFeld; function LebtNachbar(x, y: Integer): Boolean; function AnzahlLebenderNachbarn(const x, y: Integer): Integer; end;
var Form1: TForm1;
implementation
{$R *.lfm}
function TForm1.LebtNachbar(x, y: Integer): Boolean; begin if (x < 0) then x := x +N; if (y < 0) then y := y +N; if (x > (N-1)) then x := x -N; if (y > (N-1)) then y := y -N; Result := Feld[x, y]; end;
function TForm1.AnzahlLebenderNachbarn(const x, y: Integer): Integer; var dx, dy: Integer; begin Result := 0; for dy := -1 to 1 do for dx := -1 to 1 do begin if not ((dx=0) and (dy=0)) then if LebtNachbar(x +dx, y +dy) then Inc(Result); end; end;
procedure TForm1.btnSchreibenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (feld[x,y]) then shape.brush.color := clblack else shape.brush.color := clwhite; end;
end;
procedure TForm1.ckAutomatikChange(Sender: TObject); begin if ckAutomatik.Checked then begin btnLesenClick(Self); Timer.Enabled := True; end else Timer.Enabled := False; end;
procedure TForm1.EndeClick(Sender: TObject); begin close; end;
procedure TForm1.Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ThisShape: TShape; begin ThisShape := (Sender as TShape); if (ThisShape.Brush.Color = clWhite) then ThisShape.Brush.Color := clBlack else ThisShape.Brush.Color := clWhite; end;
procedure TForm1.TimerTimer(Sender: TObject); begin btnrechnenClick(Self); end;
procedure TForm1.btnLesenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (Shape.Brush.Color = clBlack) then Feld[x, y] := True else Feld[x, y] := False; end;
end;
procedure TForm1.btnRechnenClick(Sender: TObject); var x, y: Integer; FeldNeu: TFeld; begin for y := 0 to N-1 do for x := 0 to N-1 do if Feld[x, y] then FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) in [2..3]) else FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) = 3); Feld := FeldNeu; btnSchreibenClick(Self); end; end. |
das könnte gut sein :P
Narses - So 15.03.15 17:32
Moin!
Soo, dann gehen wir erstmal hier noch dran:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| function TForm1.LebtNachbar(x, y: Integer): Boolean; begin if (x < 0) then x := x +N; if (y < 0) then y := y +N; if (x > (N-1)) then x := x -N; if (y > (N-1)) then y := y -N; Result := Feld[x, y]; end; |
Der markierte Teil "gefällt" mir noch nicht. :? (ist nicht falsch, nur ... unschön)
Boldar hat schonmal drauf hingewiesen, es gibt die Modulo-Rechnung. Was war das nochmal? :les:
cu
Narses
Nini - So 15.03.15 18:35
bei x mod y wird nur der rest bei der division von x durch y angegeben
irgendwie hab ich das gefühl, dass das programm bei 5 feldern macht was es will, eigentlich muss ja so ein balken aus drei feldern sich immer drehn aber der verschwindet einfach -.-
Narses - So 15.03.15 18:50
Moin!
Nini hat folgendes geschrieben : |
bei x mod y wird nur der rest bei der division von x durch y angegeben |
Richtig. Wir haben da also ein x, und das soll nur Werte zwischen 0..(N-1) annehmen können. Wie müsste man das dann mit mod schreiben?
Nini hat folgendes geschrieben : |
irgendwie hab ich das gefühl, dass das programm bei 5 feldern macht was es will, eigentlich muss ja so ein balken aus drei feldern sich immer drehn aber der verschwindet einfach -.- |
Kontrollier mal die Reihenfolge der Shapes (also der Reihe nach eins im Formular anklicken und dann schauen, welche Nummer das hat - da könnte was schief gelaufen sein). :idea:
cu
Narses
Nini - So 15.03.15 19:00
ok, danke :) daran hat es wohl gelegen ..
ich vermute, dass das x MOD (N-1) sein müsste
Narses - So 15.03.15 19:11
Moin!
Nini hat folgendes geschrieben : |
ok, danke :) daran hat es wohl gelegen .. |
;)
Nini hat folgendes geschrieben : |
ich vermute, dass das x MOD (N-1) sein müsste |
Hm, Vermutungen... :gruebel:
Dann mal ein konkretes Beispiel: sagen wir mal, N = 5, dann haben wir für
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| x | x mod N ------------ 0 | 1 | 2 | 3 | 4 | 5 | 6 | 17 | |
Mal bitte die Tabelle ausfüllen... :les:
cu
Narses
Nini - So 15.03.15 19:16
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| x | x mod N ------------ 0 |0 1 |1 2 |2 3 |3 4 |4 5 |5 6 |1 17 |2 |
Narses - So 15.03.15 19:21
Moin!
Danke, ist aber leider (nicht ganz, aber genug) falsch. :?
Kommen wir also wieder zu unserem Test-Button (das kennst du ja schon, Button auf´s Formular klatschen, doppelklicken, loslegen):
Delphi-Quelltext
1: 2: 3: 4:
| procedure TForm1.btnTestClick(Sender: TObject); begin ShowMessageFmt('x=%d, N=%d, x mod N=%d', [0, 5, 0 mod 5]); end; |
Damit mal bitte testen gehen... :lupe:
cu
Narses
Nini - So 15.03.15 19:27
da kommt dann: x=0, N=5, x MOD N=0
Narses - So 15.03.15 19:29
Moin!
Sehr schön, damit überprüfst du jetzt mal die Tabelle da oben. :idea: :lupe:
(und wenn du ganz pfiffig bist, dann automatisierst du dir das sogar... 8) wenn nicht, auch nicht schlimm, dann halt immer wieder die Zeile anpassen, Programm starten, Button anklicken, etc.)
cu
Narses
Nini - So 15.03.15 19:33
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| x | x mod N ------------ 0 |0 1 |1 2 |2 3 |3 4 |4 5 |0 6 |1 17 |2 |
Narses - So 15.03.15 19:34
Moin!
Sehr gut, wo war der Fehler? :lupe:
Erweiterung: was ist mit -1 mod 5?
cu
Narses
Nini - So 15.03.15 19:36
das bei 5 mod 5 natürlich kein rest bleiben kann ... :P
da kommt -1 als ergebnis raus
Narses - So 15.03.15 19:43
Moin!
Nini hat folgendes geschrieben : |
das bei 5 mod 5 natürlich kein rest bleiben kann ... :P |
:zustimm:
Nini hat folgendes geschrieben : |
da kommt -1 als ergebnis raus |
Ja, doof, nicht wahr? :? Sehen wir gleich noch...
Bei der Modulorechnung ist also festzuhalten: x mod N ist immer kleiner als N :idea:
Was ist denn mit diesen Termen: x = (x mod N) = ((x +N) mod N) = ((x +2N) mod N)
Für welche x ergibt sich hier eine wahre Aussage?
cu
Narses
Nini - So 15.03.15 20:01
für alle x = N
Narses - So 15.03.15 20:08
Moin!
Nini hat folgendes geschrieben : |
für alle x = N |
Nö, für die genau nicht mehr. :lupe: sondern :arrow: für x = 0 .. N-1 :think:
Und jetzt drehen wir mal die Denkrichtung um (und lesen die Terme umgekehrt): Es ist also völlig egal, wieviele N wir auf x addieren, solange wir am Ende ein mod N machen, ist das immer gleich!
Nächster Schritt, hier:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| function TForm1.LebtNachbar(x, y: Integer): Boolean; begin ShowMessageFmt('vorher: x=%d, y=%d', [x, y]); if (x < 0) then x := x +N; if (y < 0) then y := y +N; if (x > (N-1)) then x := x -N; if (y > (N-1)) then y := y -N; ShowMessageFmt('nachher: x=%d, y=%d', [x, y]); Result := Feld[x, y]; end; |
haben wir uns doch ziemlich einen abgebrochen, um am Ende (Markierung) in den Bereich 0..N-1 zu kommen. Wir hatten erst mit x = -1 zu kämpfen, dann mit x = N, was wieder "zuviel" war. :nixweiss:
Wenn wir also am Ende schreiben:
Delphi-Quelltext
1:
| Result := Feld[x mod N, y mod N]; |
dann können wir von den if-Anweisungen was einsparen. Aber welche? :gruebel: Mach mal einen Vorschlag.
cu
Narses
Nini - So 15.03.15 20:15
die beiden wo wir +N rechnen, also die beiden für x<0 brauchen wir nicht mehr
Narses - So 15.03.15 20:20
Moin!
Meinst du das so?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| function TForm1.LebtNachbar(x, y: Integer): Boolean; begin ShowMessageFmt('vorher: x=%d, y=%d', [x, y]); if (x > (N-1)) then x := x -N; if (y > (N-1)) then y := y -N; x := x mod N; y := y mod N; ShowMessageFmt('nachher: x=%d, y=%d', [x, y]); Result := Feld[x, y]; end; |
Dann mach mal in den Test-Button wieder einen Aufruf wie neulich rein:
Delphi-Quelltext
1: 2: 3: 4:
| procedure TForm1.btnTestClick(Sender: TObject); begin AnzahlLebenderNachbarn(0, 0); end; |
Und, was passiert?
cu
Narses
Nini - So 15.03.15 20:30
ok, das war keine gute idee, die vorher- und nacherwerte sind identisch :/
ich kann genau das andere rausnehmen,also für x >(N-1), das klapppt dann wieder wie es soll
Narses - So 15.03.15 22:26
Moin!
Nini hat folgendes geschrieben : |
ok, das war keine gute idee, die vorher- und nacherwerte sind identisch :/ |
;)
Nini hat folgendes geschrieben : |
ich kann genau das andere rausnehmen,also für x >(N-1), das klapppt dann wieder wie es soll |
Genau so ist es, du hast ja für N <= x < 2N genau den Effekt, den mod N bewirkt, wenn du x -N rechnest. :idea: Deshalb ist es die zweite if-Gruppe, die rausfällt.
Wie werden wir denn nun die erste if-Gruppe auch noch los? :gruebel: Hier wirkt ja leider mod N nicht, weil wir bereits festgestellt haben, dass -1 mod N auch = -1 bleibt (das war das mit dem "doof" :zwinker:)...
Ideen? :D
cu
Narses
Nini - So 15.03.15 22:30
nein, also um ehrlich zu sein, fällt mir nichts ein, wie die If-anweisung weg könnte :(
Narses - Mo 16.03.15 00:05
Moin!
OK, dann fassen wir nochmal zusammen:
a) wir können "mod N" nutzen, um Werte größer N "abzufangen"
b) man kann beliebig oft N addieren, solange man irgendwann "mod N" rechnet, ist das egal (also zumindest in unserem Rahmen hier)
Das waren die beiden Erkenntnisse, die wir aus dem Mathe-Vortrag vorhin gewonnen haben (oder haben sollten :angel:). a) haben wird schon "untergebracht", was bleibt noch? :zwinker:
cu
Narses
Nini - Mo 16.03.15 17:26
bei mir hängt es anscheinend, ich sehe einfach keine möglichkeit das noch weoiter zu vereinfachen ;/
Narses - Mo 16.03.15 17:29
Moin!
Wir haben in der ersten if-Gruppe N addiert, wenn x < 0 ist. Könnte man nicht "gefahrlos" immer x addieren? (weil wir doch mod N nutzen) :idea:
cu
Narses
Nini - Mo 16.03.15 17:35
aber wenn x = -1 dann ist doch wenn ich x addiere das neue x=-2 oder hab ich nen denkfehler?
Narses - Mo 16.03.15 17:37
Moin!
x addieren... :autsch: :oops: :lol:
N addieren natürlich! :P
cu
Narses
Nini - Mo 16.03.15 17:44
also N addieren geht problemlos
Narses - Mo 16.03.15 17:47
Moin!
Ja dann, her mit dem Codevorschlag. ;)
cu
Narses
Nini - Mo 16.03.15 17:52
also ich würd es ja einfahc so lassen, weiß nicht, was ich so genau ändern soll
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| function TForm1.LebtNachbar(x, y: Integer): Boolean; begin if (x < 0) then x := x +N; if (y < 0) then y := y +N; Result := Feld[x mod N, y mod N]; end; |
Narses - Mo 16.03.15 17:55
Moin!
Wir haben doch festgestellt, dass man immer N addieren kann, nicht nur dann, wenn x < 0 ist. Also können auf jeden Fall die beiden if-Zeilen raus. Und dann schau mal, ob man da noch was zusammenfassen kann. :lupe:
cu
Narses
Nini - Mo 16.03.15 18:24
vielleicht so:
Delphi-Quelltext
1: 2: 3: 4:
| function TForm1.LebtNachbar(x, y: Integer): Boolean; begin Result := Feld[(x+N) mod N, (y+N) mod N]; end; |
Narses - Mo 16.03.15 18:32
Moin!
Perfekt! :zustimm:
Dann würde ich hier gerne noch das "not" entfernen (zugegeben, mehr aus didaktischen Gründen, als dass es großen Nutzen hätte). ;)
Delphi-Quelltext
1:
| if not ((dx = 0) and (dy = 0)) then |
Was tut "not"? Es negiert die Bedingung. Wenn wir also das not entfernen wollen, müssen wir alle Terme in der Klammer negieren (also das Gegenteil abfragen).
Probier mal. :)
cu
Narses
Nini - Mo 16.03.15 18:36
vielleicht funktioniert das ja so
Delphi-Quelltext
1:
| if ((dx<>0) and (dy<>0)) then |
Narses - Mo 16.03.15 18:38
Moin!
Probiers doch einfach mal im Programm aus. :zwinker: (ist schon gar nicht so schlecht :zustimm:)
cu
Narses
Nini - Mo 16.03.15 18:47
das programm läuft, aber nicht ganz richtig
Narses - Mo 16.03.15 19:01
Moin!
Genau, so ist es. Aber was heißt denn, nicht ganz richtig? (naja, ich weiß es natürlich, deshalb schlage ich vor, wir untersuchen besser nicht, was da im Game of Life schief läuft, das könnte nämlich haarig werden, sondern betrachten das separat)
Quelltext
1: 2: 3: 4: 5: 6:
| a | b | not (a and b) | (not a) and (not b) ------------------------------------------- 0 | 0 | ? | ? 0 | 1 | ? | ? 1 | 0 | ? | ? 1 | 1 | ? | ? |
Bitte mal ausfüllen. :les:
cu
Narses
Nini - Mo 16.03.15 19:47
ich hab keine ahnung, was ich rechnen muss :/
Narses - Mo 16.03.15 20:24
Moin!
OK, das nennt man
Wahrheitstabelle [
http://de.wikipedia.org/wiki/Wahrheitstabelle]. :idea: Hier mal ein paar einfache Beispiele:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| a | b | a and b --------------- 0 | 0 | 0 0 | 1 | 0 1 | 0 | 0 1 | 1 | 1
a | b | a or b --------------- 0 | 0 | 0 0 | 1 | 1 1 | 0 | 1 1 | 1 | 1
a | not a --------- 0 | 1 1 | 0 |
Dabei steht 0 für False und 1 für True. Jetzt klarer? ;)
cu
Narses
Nini - Mo 16.03.15 20:33
dann wäre die erste spalte, wenn ich es richtig verstanden habe
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| a | b | not (a and b) | (not a) and (not b) ------------------------------------------- 0 | 0 | 1 | ? 0 | 1 | 1 | ? 1 | 0 | 1 | ? 1 | 1 | 0 | ? |
Narses - Mo 16.03.15 20:45
Moin!
Nini hat folgendes geschrieben : |
dann wäre die erste spalte, wenn ich es richtig verstanden habe |
Jap, hast du. :zustimm:
Und wenn unsere umgewandelte Formel in der letzten Spalte korrekt ist, sollte da genau das Gleiche rauskommen (wir haben ja nur das not in die Klammer gezogen). :les:
cu
Narses
Nini - Mo 16.03.15 20:51
aaaaaaachso :P sowas wie assoziativgesetz also
Narses - Mo 16.03.15 21:05
Moin!
Nini hat folgendes geschrieben : |
aaaaaaachso :P sowas wie assoziativgesetz also |
:shock: Wow, ja, genau sowas. (Aber eben nicht ganz 8))
cu
Narses
Nini - Mo 16.03.15 21:06
ie krieg ich das jetzt so umgewandelt, dass das programm wieder richtig läuft?
Narses - Mo 16.03.15 21:10
Moin!
Nini hat folgendes geschrieben : |
ie krieg ich das jetzt so umgewandelt, dass das programm wieder richtig läuft? |
Indem du das Gehirn einschaltest, die Tabelle ausfüllst, feststellst, dass die Formel nicht korrekt ist, diese korrigierst, die Tabelle auch und dann die Erkenntnis auf die Delphi-Zeile anwendest. :zwinker:
cu
Narses
Nini - Mo 16.03.15 21:26
ich bin überfordert :(
Narses - Mo 16.03.15 21:31
Moin!
Ach, das wird schon, nicht aufgeben. :zustimm:
Dann machen wir die erste Zeile mal zusammen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| a | b | not (a and b) | (not a) and (not b) ------------------------------------------- 0 | 0 | 1 | (not 0) and (not 0) = 1 and 1 = 1 0 | 1 | 1 | ? 1 | 0 | 1 | ? 1 | 1 | 0 | ? |
Jetzt klarer? Einfach die Werte einsetzen und ausrechnen. :idea:
cu
Narses
Nini - Mo 16.03.15 21:34
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| a | b | not (a and b) | (not a) and (not b) ------------------------------------------- 0 | 0 | 1 | (not 0) and (not 0) = 1 and 1 = 1 0 | 1 | 1 | (not 0) and (not 1) = 1 and 0 = 0 1 | 0 | 1 | (not 1) and (not 0) = 0 and 1 = 0 1 | 1 | 0 | (not 1) and (not 1) = 0 and 0 = 0 |
Narses - Mo 16.03.15 21:39
Moin!
Passt. :) Na, war doch gar nicht schwer, oder? ;)
Leider passt aber unsere Formeltransformation offensichtlich nicht, denn da kommt was anderes als in der Spalte davor... :? Vorschlag für eine Korrektur?
cu
Narses
Nini - Mo 16.03.15 21:47
nein, so logische verknüpfungen find ich total kompliziert :(
Narses - Mo 16.03.15 21:51
Moin!
Nur auf den ersten Blick, eigentlich ist das fast immer das Gleiche und total regelmäßig. ;)
Dann schau mal hier rein, das ist die Lösung:
http://de.m.wikipedia.org/wiki/De_Morgansche_Gesetze
Einfach mal versuchen, ist nicht schwer. :zustimm:
cu
Narses
Nini - Mo 16.03.15 22:11
das heißt jetzt, dass not (a and b) = (not a) or (not b)
Narses - Mo 16.03.15 22:15
Moin!
Top! :zustimm: Erkenntnis: wenn man bool'sche Terme negiert, müssen auch die Operatoren angepasst werden. Aus und wird oder und umgekehrt. :idea: Spannend, oder? :D
Und jetzt solltest du auch die Delphi-Zeile wieder reparieren können. ;)
cu
Narses
Nini - Mo 16.03.15 22:21
so?
Delphi-Quelltext
1:
| if ((not a) or (not b))<>0) then |
Narses - Mo 16.03.15 22:24
Moin!
Ne ;) "a" steht doch für "dx = 0", ein a kam vorher ja auch nicht vor... :lupe:
cu
Narses
PS: Öhm, vor deinem Edit war's richtiger... :?
Nini - Mo 16.03.15 22:27
dann vielleicht so:
Delphi-Quelltext
1:
| if ((dx<>0) or (dy<>0)) then |
Narses - Mo 16.03.15 22:31
Moin!
Genau so, optimal! :zustimm: Schon ausprobiert? ;)
Dann können wir uns langsam wieder den Shapes zuwenden. :les:
cu
Narses
PS: Ich bin gleich mal ne Stunde oder so offline.
Nini - Mo 16.03.15 22:43
jaaa, es funktioniert :)
Narses - Mo 16.03.15 23:38
Moin!
Soo, dann gehen wir mal an die dynamischen Shapes. ;)
Leg ein neues Projekt (zum Testen) an und lege einfach irgendwo (in die Mitte z.B.) einen Button ab. In dessen Handler schreibst du:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.btnTestClick(Sender: TObject); var Shape: TShape; begin Shape := TShape.Create(Self); Shape.Parent := Self; Shape.Name := 'Shape1'; Shape.Left := 8; Shape.Top := 8; Shape.Width := 25; Shape.Height := 25; end; |
Damit machen wir per Programmcode genau das, was die IDE automatisch macht, wenn du ein Shape aus der Komponentenpalette auf das Formular klickst. Aber eben nicht zur Entwurfszeit, sondern (erst) zur Laufzeit des Programms! :idea:
Noch etwas zu dem "Self"-Parameter beim Create: normalerweise muss man Objekte, die man zur Laufzeit erstellt, auch selbst wieder freigeben (weil dafür Speicher reserviert wird, der sonst nicht wieder freigegeben wird - das berühmte "memory leak"). Bei visuellen Komponenten gibt es aber einen praktischen Mechanismus, man kann nämlich beim Erzeugen einen "Eigentümer" angeben - und der ist dann dafür verantwortlich, dass die Komponente (und der zugehörige Speicher) beim Beenden des Programmes auch wieder freigegeben wird.
Probier mal aus, was da passiert. Wenn du das Programm startest und auf den Button klickst, sollte ein Shape links oben in der Ecke erscheinen. ;)
cu
Narses
Narses - Mi 18.03.15 20:58
Moin!
Und, schon ausprobiert? ;)
cu
Narses
Nini - Mi 18.03.15 21:12
ja,gere eben ausprobiert, wollte auch gleich noch antworten :P
es kommen voll viele fehlermeldungen :/
Narses - Mi 18.03.15 21:14
Moin!
Du hast auch ein komplett neues Projekt zum Testen genommen? (wenn beim 2. Klick auf den Button Fehlermeldungen kommen, ist das normal)
Welche Fehler kommen? Kannste die mal hier reinkopieren? :lupe: :les:
cu
Narses
Nini - Mi 18.03.15 22:25
die fehlermeldugnen auf dem bild zeigts mir alle an
ja, ich hab nen gesamtneues dings genommen
Narses - Mi 18.03.15 22:45
Moin!
Ach so, der Compiler sagt doch nur, dass er TShape nicht kennt... :P Füg mal oben in der uses-Klausel ein:
Das sollte dann klappen. ;)
cu
Narses
Nini - Mo 23.03.15 16:23
so, jetzt hab ich mal wieder Zeit zum programmieren :)
irgendwas klappt dann immer noch nicht, ich bekomme 49 Fehlermeldungen o.O
Narses - Mo 23.03.15 21:32
Moin!
Nini hat folgendes geschrieben : |
so, jetzt hab ich mal wieder Zeit zum programmieren :) |
:zustimm:
Nini hat folgendes geschrieben : |
irgendwas klappt dann immer noch nicht |
:gruebel: Sehr komische Meldungen. Ich bin zugegeben nicht so firm mit Lazarus (muss mir doch mal bei Gelegenheit eine Test-Installation anlegen; welches Lazarus verwendest du? :lupe:)...
OK, gehen wir anders ran: Pack mal ein Shape auf das Formular, irgendeins, irgendwo. Das nennst du dann "TestShape" oder so (ist egal, nur nicht "Shape1"). Jetzt sollte sich automatisch die uses-Klausel oben im Projekt verändert haben, richtig? :les: Und jetzt sollte auch der Button-Code laufen bzw. sich das Ding überhaupt kompilieren lassen? :suspect:
cu
Narses
Nini - Mo 23.03.15 22:00
ich verwende Lazarus IDE v1.2.6
wenn ich das Shape reinmache, dann kommt zu uses noch ExtCtrls dazu aber dann bleiben die 49 fehlermeldungen, wenn ich das aber rauslösche und das shape drinnen lasse sind es immerhin nur noch 3 Fehlermeldungen:
Identifier not found "TShape"
Error in type definition
Symbol can't be published, can be only a class
Narses - Mo 23.03.15 22:04
Moin!
Nini hat folgendes geschrieben : |
ich verwende Lazarus IDE v1.2.6 |
OK, danke.
Nini hat folgendes geschrieben : |
wenn ich das Shape reinmache, dann kommt zu uses noch ExtCtrls dazu |
Wie jetzt "kommt dazu", das hatte ich doch ein paar Posts weiter oben schon erwähnt, hattest du das noch nicht mit drin? :gruebel:
Nini hat folgendes geschrieben : |
aber dann bleiben die 49 fehlermeldungen, wenn ich das aber rauslösche und das shape drinnen lasse sind es immerhin nur noch 3 Fehlermeldungen: |
Zeig mal eben den kompletten Projekt-Quelltext. :les:
cu
Narses
Nini - Mo 23.03.15 22:07
ich bin überfordert :P
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: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47:
| unit Unit1;
{$mode objfpc}{$H+}
interface
uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm) btnTest: TButton; testShape: TShape; procedure btnTestClick(Sender: TObject); private public end;
var Form1: TForm1;
implementation
{$R *.lfm}
procedure TForm1.btnTestClick(Sender: TObject); var Shape: TShape; begin Shape := TShape.Create(Self); Shape.Parent := Self; Shape.Name := 'Shape1'; Shape.Left := 8; Shape.Top := 8; Shape.Width := 25; Shape.Height := 25; end; end. |
Narses - Mo 23.03.15 23:25
Moin!
Ich krieg jetzt auf die Schnelle keine Lazarus-Install gemacht... :? Aber an deinem Code ist auch nix komisches, wenn ich das mit
dem hier [
http://wiki.freepascal.org/Formular-Komponenten_in_Lazarus_dynamisch_erzeugen] vergleiche, dann geht das in Lazarus genau so wie in Delphi. :lupe: :nixweiss: Das muss also irgendwas anderes sein... :gruebel:
Gut, fangen wir nochmal langsam an:
- Du erstellst nochmal ein komplett neues Projekt in einem eigenen Ordner
- Theoretisch sollte ein neues Lazarus-Projekt sich (genauso wie in Delphi) direkt starten lassen: du hast dann eben nur ein leeres Formular und wenn du das zu machst, bist du wieder in der IDE
- Einen Button und ein Shape auf das Formular legen, Programm starten, wieder schließen
- Doppelklick auf dem Button machen (Handler wird angelegt), starten, schließen
- Im Button-Handler die Variablendeklaration einfügen:, starten, schließen
- Den restlichen Code im Button einfügen (wie oben), starten, schließen
- Programm starten, auf den Button klicken
Bei welchem Schritt fangen die Probleme an? :suspect:
cu
Narses
Nini - Mo 23.03.15 23:52
Ich kann es mir zwar nicht erklären, aber dieses Mal hat es ohne Fehlermeldung funktioniert und dann auch das Programm korrekt ausgeführt ?!
Narses - Di 24.03.15 00:00
Moin!
Nini hat folgendes geschrieben : |
Ich kann es mir zwar nicht erklären, aber dieses Mal hat es ohne Fehlermeldung funktioniert |
:zustimm: Tja, war wohl Schluckauf... :lol:
Nini hat folgendes geschrieben : |
und dann auch das Programm korrekt ausgeführt ?! |
Soll heißen, wenn du auf den Button klickst, wird ein neues Shape erstellt? ;)
cu
Narses
Nini - Di 24.03.15 00:02
genau, da kommt nen neues shape oben links :)
Narses - Di 24.03.15 00:07
Moin!
Perfekt! :zustimm:
Nächster Schritt: wieder zum Game of Life Projekt wechseln und alle Shapes vom Formular löschen. :hair: Keine Panik, die legen wir gleich alle wieder beim Programmstart automatisch an. ;)
Dazu machst du einen Doppelklick auf dem Formularhintergrund, es sollte ein neuer Handler angelegt werden, und zwar für das Ereignis FormCreate. :idea: Da müssen wir nun den Code reinschreiben, der die Shapes erzeugt. Wie man ein Shape erzeugt hast du nun gesehen und getestet. Dann mach doch mal einen (Code-)Vorschlag, wie man das auf die Menge Shapes "aufbohrt", die wir brauchen. :lupe: (ich würde als Tipp mal so sagen, du brauchst da ne Schleife, so ähnlich wie beim btnLesenClick :think:)
cu
Narses
Nini - Di 24.03.15 00:15
mein vorschlag wäre das:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| procedure TForm1.FormCreate(Sender: TObject); var i,j,x : integer; shape : TShape; begin x := strtoint(edit1.text); for j := 1 to x do for i := 1 to x do begin Shape := TShape.Create(Self); Shape.Parent := Self; Shape.Name := 'Shape'+i; Shape.Left := 8+i*25; Shape.Top := 8+i*25; Shape.Width := 25; Shape.Height := 25; end; end; |
Narses - Di 24.03.15 00:22
Moin!
Gar nicht übel! :zustimm:
Allerdings muss ich dir leider den Zahn mit dem Edit-Feld und der Eingabe der Feldgröße zur Laufzeit wieder ziehen :? das geht leider nicht ganz so einfach (also es geht schon, aber eben etwas anders). :nixweiss:
Du musst in diesem Ansatz einfach N für die Kantenlänge verwenden, also die Konstante, die du im Programm ganz oben deklariert hast. :idea: Und dann noch beim Namen des Shapes beachten, dass dieser sowohl eindeutig, als auch der Konvention ("Reihenfolge") entspricht, wie bei den manuell angelegten Shapes (im Moment erzeugst du Shapes, die mehrfach den gleichen Namen haben :shock:).
Also, nächster Versuch. ;)
cu
Narses
Nini - Di 24.03.15 00:27
meine nächste Variante:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure TForm1.FormCreate(Sender: TObject); var i,j,snr : integer; shape : TShape; begin for j := 0 to N-1 do for i := 0 to N-1 do begin Shape := TShape.Create(Self); Shape.Parent := Self; snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); Shape.Left := 8+i*25; Shape.Top := 8+i*25; Shape.Width := 25; Shape.Height := 25; end; end; |
Narses - Di 24.03.15 00:32
Moin!
Schon besser. ;)
Aaaaber... :P
Damit berechnest du (völlig korrekt!) die Shape-Nr. :zustimm:
Delphi-Quelltext
1:
| Shape := TShape(FindComponent('Shape' +IntToStr(snr))); |
Statt diese zu verwenden, versuchst du ein bereits vorhandenes Shape zu finden :lupe: :?!?: (was es logischerweise nicht gibt!)
...und kommentierst den (fast korrekten) Code, der das was du brauchst, tut, aus. :eyes:
Also: noch ein Versuch! :D
cu
Narses
Nini - Di 24.03.15 00:34
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| procedure TForm1.FormCreate(Sender: TObject); var i,j,snr : integer; shape : TShape; begin for j := 0 to N-1 do for i := 0 to N-1 do begin Shape := TShape.Create(Self); Shape.Parent := Self; snr := x +y *N +1; Shape.Name := 'Shape'+inttostr(snr); Shape.Left := 8+i*25; Shape.Top := 8+i*25; Shape.Width := 25; Shape.Height := 25; end; end; |
so das dürfte jetzt stimmen
Narses - Di 24.03.15 00:39
Moin!
Nini hat folgendes geschrieben : |
so das dürfte jetzt stimmen |
Jap, sieht gut aus! :zustimm: Schon ausprobiert? ;) Was fehlt noch (funktional)? :P
cu
Narses
PS: Ah, kleiner Bug ist noch drin... :zwinker:
Nini - Di 24.03.15 00:43
musste noch x und y als integer deklarieren aber was ich gegen die debuggernachricht machen soll weiß ich gar nicht ... :(
Narses - Di 24.03.15 00:53
Moin!
Nini hat folgendes geschrieben : |
musste noch x und y als integer deklarieren |
Jap, genau da ist noch was im Argen... ;) Tipp: Entweder du verwendest x und y oder du verwendet i und j, beides "mischen" ist nicht so schlau. :zwinker:
Nini hat folgendes geschrieben : |
aber was ich gegen die debuggernachricht machen soll weiß ich gar nicht ... :( |
Dazu müsstest du diese mal zeigen. :lupe: :les:
Aber korrigier erstmal noch das Index-Problem in den Schleifen/Deklaration, vielleicht ist der andere Fehler dann schon weg. :idea:
cu
Narses
Nini - Di 24.03.15 00:56
ja es funktioniert *_* das war wohl noch mein fehler :)
hab jetzt beim programm start ein 5x5-Raster
Narses - Di 24.03.15 00:58
Moin!
Dann zeig nochmal kurz den Code (FormCreate reicht). :les:
Und, was "fehlt" jetzt noch (funktional)? :D
cu
Narses
Nini - Di 24.03.15 01:02
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin Shape := TShape.Create(Self); Shape.Parent := Self; snr := x +y *N +1; Shape.Name := 'Shape'+inttostr(snr); Shape.Left := 8+x*25; Shape.Top := 8+y*25; Shape.Width := 25; Shape.Height := 25; end; end; |
irgendwas, dass ich die felder wieder färben kann fehlt noch und dass ich N irgendwie ändern kann im programm
Narses - Di 24.03.15 01:10
Moin!
Ja, der Code sieht jetzt gut aus. :zustimm:
Nini hat folgendes geschrieben : |
irgendwas, dass ich die felder wieder färben kann fehlt noch |
Genau! :D Da war doch noch so eine auskommentierte Zeile in der Demo... :lupe: wozu mag die wohl gut gewesen sein... :gruebel:
Nini hat folgendes geschrieben : |
und dass ich N irgendwie ändern kann im programm |
Tja, grundsätzlich geht sowas zwar, aber nicht mit diesem Ansatz. :nixweiss: Dazu müsste man das Programm etwas anders aufziehen. In dieser Version musst du N im Quelltext ändern und dann neu kompilieren. :(
Auf der anderen Seite: das ist natürlich so gesehen eine (die nächste?) Herausforderung? :zwinker: Wenn du möchtest, können wir uns dieses Problems später nochmal annehmen. ;)
Jetzt kriegen wir das aber erstmal überhaupt wieder ans Laufen. :P
cu
Narses
Nini - Di 24.03.15 01:27
Shape.OnMouseDown := Shape1MouseDown; weist ja die Methode zu, also für das shape dann das was in prozedur TForm1.Shape1MouseDown steht oder?
kann ich das dann einfach unten noch ranschreiben?
Narses - Di 24.03.15 16:39
Moin!
Jap, genau so. :zustimm: Klappt? ;)
cu
Narses
Nini - Di 24.03.15 17:05
ne, ich bekomm da ne fehlermeldung:
wrong number of parametersspecified for call to "Shape1MouseDown"
Nini - Di 24.03.15 17:39
ja, so läuft das programm wieder :)
Narses - Di 24.03.15 17:46
Moin!
OK, dann setz N doch mal testweise auf 10 und starte das Programm. Was fällt auf? ;)
cu
Narses
Nini - Di 24.03.15 17:50
mit N=10 ist das Raster 10x10 groß
Narses - Di 24.03.15 18:10
Moin!
Ja, klar. :lol: Aber das Fenster dürfte doch in der Größe nicht passen und kommt man noch an den Automatik-Button dran? ;)
cu
Narses
Nini - Di 24.03.15 18:22
ne, das fenster musste ich größer machen und das dinf zum simulation starten musste ich auch verschieben :P
Narses - Di 24.03.15 18:27
Moin!
OK, dann schlage ich vor:
- du verschiebst die Automatik-Checkbox nach oben
- du passt die Koordinaten-Berechnung für die Shapes an, so dass sie etwas weiter unten liegen
- mit der Eigenschaft ClientWidth und ClientHeight kannst du die Größe des Fensters in der FormCreate-Methode auch per Code anpassen
cu
Narses
Nini - Di 24.03.15 20:18
jaaa, so klappts :) jetzt passt das fenster
Narses - Di 24.03.15 21:09
Moin!
Dann zeig doch bitte nochmal den aktuellen Stand der FormCreate-Methode. :les: ;)
Was soll´s denn als nächstes sein? :D Möchtest du die Regeln für Geburt/Tod anpassbar machen? Oder willst du lieber erst die Feldgröße vom Benutzer wählen lassen? :nixweiss:
Bedenke: was auch immer du wählst, du musst dazu auch irgend eine Idee haben, wie man das denn umsetzen könnte... 8) (klar, das muss kein fertiger Code sein, eine umgangssprachliche Beschreibung, wie vorzugehen ist oder welcher besondere "Trick"/Gedanke weiterhilft, um an´s Ziel zu kommen, reicht auch schon) :idea:
cu
Narses
Nini - Di 24.03.15 21:21
also die aktuelle formcreate-methode
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin Shape := TShape.Create(Self); Shape.Parent := Self; snr := x +y *N +1; Shape.Name := 'Shape'+inttostr(snr); Shape.Left := 8+x*25; Shape.Top := 48+y*25; Shape.Width := 25; Shape.Height := 25; Shape.OnMouseDown := @Shape1MouseDown; ClientHeight := N*25+100; ClientWidth := N*25+80; end; end; |
ich würde die Regeländerun bevorzugen.
Mein ganz grober plan: Ich muss eingeben können,was passiert bei wie viel NAchbarn, dafür würde ich checkboxen nehmen, also 8 für geburt und 8 für tod, wenn nichts gewählt wird für ne bestimmte nachbar-anzahl, dann passiert nichts mit der Zelle.
Und dann muss das Ergebnis, ob die Zelle geboren wird in die Rechnen-prozedur einlesen können, damit die das dann anwenden kann
Narses - Mi 25.03.15 00:07
Moin!
Nini hat folgendes geschrieben : |
also die aktuelle formcreate-methode |
Warum setzt du denn N^2 mal die Formulargröße? :shock: Einmal reicht doch... :angel: Aber sonst OK. ;)
Nini hat folgendes geschrieben : |
ich würde die Regeländerun bevorzugen. |
OK, dann machen wir die Regeln anpassbar. :zustimm:
Nini hat folgendes geschrieben : |
dafür würde ich checkboxen nehmen, also 8 für geburt und 8 für tod, wenn nichts gewählt wird für ne bestimmte nachbar-anzahl, dann passiert nichts mit der Zelle. |
Dann füg doch bitte mal der Anwendung ein weiteres Formular hinzu. Das gestaltest du so, wie du dir die Oberfläche für die Regeldefinition vorstellst und dann stellst du einen Screenshot hier rein. :lupe:
Nini hat folgendes geschrieben : |
Und dann muss das Ergebnis, ob die Zelle geboren wird in die Rechnen-prozedur einlesen können, damit die das dann anwenden kann |
Klar, das schauen wir uns dann an. ;)
cu
Narses
Nini - Mi 25.03.15 12:36
ich würd das so machen:
Narses - Mi 25.03.15 18:13
Moin!
OK, wie müssten denn die Haken gesetzt werden, um die aktuellen Regeln abzubilden? :lupe:
cu
Narses
PS: Hast du den Fehler mit der Fenstergröße noch behoben? ;)
Nini - Mi 25.03.15 18:52
ne, weiß nicht was ich da ändern muss :P funktioniert ja so
so mit jetzigen regeln wär's das
Narses - Mi 25.03.15 23:53
Moin!
Nini hat folgendes geschrieben : |
:P funktioniert ja so |
Hmhm. :| Wenn du also bei N=10 insgesamt 100 mal die Fenstergröße setzt, dann ist das OK? :suspect: :schmoll:
Nini hat folgendes geschrieben : |
ne, weiß nicht was ich da ändern muss |
Wozu sind hier die beiden markierten Worte da? :lupe:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin Shape := TShape.Create(Self); ... Shape.OnMouseDown := @Shape1MouseDown; ClientHeight := N*25+100; ClientWidth := N*25+80; end; end; |
Nini hat folgendes geschrieben : |
so mit jetzigen regeln wär's das |
OK, allerdings würde ich bevorzugen in beiden Spalten das Entstehen einer schwarzen Zelle als Ergebnis zu definieren, also müssten wir von "Tod" auf "Überleben" umstellen. Wie machen wir das? :idea:
Dann hast du mal folgenden Code vorgeschlagen (ganz alleine, das war nicht von mir!):
Delphi-Quelltext
1:
| if (AnzahlLebenderNachbarn(x, y) in [2, 3]) then |
Was bewirkt der markierte Teil? Nutzt uns das was für unser aktuelles Problem? ;)
cu
Narses
Nini - Sa 28.03.15 00:59
die grenzen die sachen ein die in der schleife passieren, also muss ich das client... aus den schleifen rausnehmen damits nur einmal so groß ist
mit überleben wär's dann wie auf dem bild
das macht dass das geschaut wird ob die zelle zwei oder drei lebende zellen hat und man müsste jetzt nur das in der eckigen klammer ändern können, dass da die wahren werte von der überlebenden Zelle reinkommen damit sich die zelle schwarz färbt
Happy_Penguin - Sa 28.03.15 14:22
Ein kleiner Tipp von mir...
Wie wäre es denn, wenn du nun zwei Arrays für das Regelwerk anlegst?
Einen Array, wann eine Zelle neu entsteht und dann einen, wann sie überlebt.
Delphi-Quelltext
1: 2: 3:
| var ueberleben: Array[0..8] of Boolean; neuEntstehen: Array[0..8] of Boolean; |
Durch die Checkboxen kannst du ja dann prima darauf zugreifen.
Narses - Sa 28.03.15 16:58
Moin!
Nini hat folgendes geschrieben : |
die grenzen die sachen ein die in der schleife passieren, also muss ich das client... aus den schleifen rausnehmen damits nur einmal so groß ist |
:zustimm: Geht doch.
Nini hat folgendes geschrieben : |
mit überleben wär's dann wie auf dem bild |
Jawoll, einfach invertieren. ;)
Nini hat folgendes geschrieben : |
das macht dass das geschaut wird ob die zelle zwei oder drei lebende zellen hat |
Jup.
Nini hat folgendes geschrieben : |
und man müsste jetzt nur das in der eckigen klammer ändern können, dass da die wahren werte von der überlebenden Zelle reinkommen damit sich die zelle schwarz färbt |
Genau, und das werden wir als nächstes tun. :)
Diese Aufzählungen in eckigen Klammern nennt man eine Menge, und statt das als Konstante zu verwenden, wie in der if-Anweisung kann man das auch als Variable verwenden. :idea: Da wir von verschiedenen Stellen im Code darauf zugreifen können wollen, müssen wir die Variable in der Klasse deklarieren:
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: 26: 27: 28: 29:
| const N = 10; type TNachbarn = 1..8; TRegel = set of TNachbarn; TFeld = array[0..N-1, 0..N-1] of Boolean; TForm1 = class(TForm) ... public Feld: TFeld; Ueberleben: TRegel; Geburt: TRegel; function LebtNachbar(x, y: Integer): Boolean;
...
procedure TForm1.FormCreate(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin Ueberleben := [2, 3]; Geburt := [3]; ClientWidth := 17 +24 *N; ... |
Das ist die Vorarbeit, um mit den Regel-Mengen arbeiten zu können. Dein Part ist nun den Code in der Rechnen-Methode so anzupassen, dass mit den neuen Regel-Mengen gearbeitet wird. Vorschlag? :les:
@
Happy_Penguin: Das kann man sicher auch so machen, ich würde aber den Ansatz mit den Mengen empfehlen. ;)
cu
Narses
Happy_Penguin - Sa 28.03.15 17:09
Okay das geht natürlich auch :-)
Ich möchte nur noch anmerken, dass auch 0 Nachbarn möglich sind und auch das vom Nutzer einstellbar sein sollte...
Also am Besten TNachbarn entsprechend anpassen
Narses - Sa 28.03.15 17:21
Moin!
Happy_Penguin hat folgendes geschrieben : |
Ich möchte nur noch anmerken, dass auch 0 Nachbarn möglich sind und auch das vom Nutzer einstellbar sein sollte... |
Und richtig klasse wäre es, wenn Nini das selbst merkt... :zwinker: :roll:
cu
Narses
Nini - Sa 28.03.15 17:34
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| for y := 0 to N-1 do for x := 0 to N-1 do if Feld[x, y] then for i := 1 to 8 do FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) = ueberleben) else FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) = geburt); Feld := FeldNeu; |
Ich hätte das ja gern einfach so gemacht, aber das geht nicht, weil irgendwie die typen inkompatibel sind :(
Narses - Sa 28.03.15 18:06
Moin!
Du hast doch auch in dem von mir zitierten Stück Code nicht "=" genommen, warum sollte das jetzt anders sein? :gruebel: :zwinker:
cu
Narses
Nini - Sa 28.03.15 18:13
ok, dann also so:
Delphi-Quelltext
1: 2: 3: 4:
| if Feld[x, y] then FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) in ueberleben) else FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) in geburt); |
Narses - Sa 28.03.15 18:34
Moin!
Jup. :) Und, funktioniert´s? ;)
Der nächste Schritt wird natürlich sein, diese Regel-Mengen mit dem Zustand der Checkboxen zu "befüllen". Ich gehe doch mal stark davon aus, dass Lazarus eine Online-Hilfe hat. :lupe: Da schaust du mal bitte rein und liest dir durch, was es zu Mengen und Mengenoperatoren (also z.B. "in") zu wissen gibt. :les: Dann kannst du dich mal an einem Codevorschlag zum Auslesen der Checkboxen versuchen. :idea:
cu
Narses
Happy_Penguin - Mo 30.03.15 19:59
Happy_Penguin hat folgendes geschrieben : |
Okay das geht natürlich auch :-)
Ich möchte nur noch anmerken, dass auch 0 Nachbarn möglich sind und auch das vom Nutzer einstellbar sein sollte...
Also am Besten TNachbarn entsprechend anpassen
|
Moderiert von Narses: Beiträge zusammengefasstHallo,
also am Besten wäre es vielleicht wirklich, dass mit dem Boolean-Arrays zu lösen, da kommt man nämlich mit dem Schulwissen aus :-;
Nini - Mo 30.03.15 20:40
ich hab mir die beiden artikel komplett durchgelesen und auch eeeewig drüber nachgedacht, aber irgendwie hab ich gar keine ahnung wie ich das anstellen muss :( :cry:
Narses - Mo 30.03.15 20:44
Moin!
Nini hat folgendes geschrieben : |
ich hab mir die beiden artikel komplett durchgelesen und auch eeeewig drüber nachgedacht, |
:zustimm:
Nini hat folgendes geschrieben : |
aber irgendwie hab ich gar keine ahnung wie ich das anstellen muss :( :cry: |
Na, dann wollen wir das mal ändern. ;)
Was wäre denn konzeptionell zu tun (also jetzt mal unabhängig von irgendwelchem Code)? Beschreib´s mit Worten. :idea:
cu
Narses
Nini - Mo 30.03.15 21:04
Also als erstes muss ich die ckeckboxen auslesen ob soe angeklickt sind oder nicht, dann würde ich wenn angekliclt den wert wahr zuweisen und dann muss wenn wahr das iwie in die menge gespeichert werden
Narses - Mo 30.03.15 21:11
Moin!
Nini hat folgendes geschrieben : |
als erstes muss ich die ckeckboxen auslesen ob soe angeklickt sind oder nicht, |
Jup. Bei den Shapes haben wir das doch auch irgendwie gemacht, wie ging das denn da? :lupe: :les:
Nini hat folgendes geschrieben : |
dann würde ich wenn angekliclt den wert wahr zuweisen |
Hm :? also das würde ich jetzt mal weglassen, da mir nicht ganz klar ist, was das bewirken soll :gruebel: (und wenn ich raten sollte 8) dir auch nicht :lol: oder? :zwinker:)
Nini hat folgendes geschrieben : |
und dann muss wenn wahr das iwie in die menge gespeichert werden |
Genau, dann muss was in die Menge rein. Das schauen wir uns dann an, wenn es soweit ist. Vielleicht noch ein Gedanke: bevor wir anfangen irgendwas in eine Menge zu tun, was ist denn, wenn da schon was drin steht? :suspect: :nixweiss:
cu
Narses
Nini - Mo 30.03.15 21:21
Geht das auslesen nicht mit ck0geburt.checked oder so?
Dann muss ich die menge also vorher erst noch löschen damit die leer ist
Narses - Mo 30.03.15 22:00
Moin!
Nini hat folgendes geschrieben : |
Geht das auslesen nicht mit ck0geburt.checked oder so? |
Jup, so geht´s auch. ;) Dann brauchst du zwar für jede Checkbox eine if-Abfrage, aber funktionieren tu´s schon. :nixweiss:
Nini hat folgendes geschrieben : |
Dann muss ich die menge also vorher erst noch löschen damit die leer ist |
Genau! :idea: "Löschen" kann man eine Menge durch Zuweisung der leeren Menge:
cu
Narses
Nini - Mo 30.03.15 22:10
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| geburt := []; ueberleben := []; ckgeburt0.Checked; ckgeburt1.Checked; ckgeburt2.Checked; ckgeburt3.Checked; ckgeburt4.Checked; ckgeburt5.Checked; ckgeburt6.Checked; ckgeburt7.Checked; ckgeburt8.Checked; |
dann hab ich das jetzt so weit und dann halt nochmal für die andern checkboxen, aber weiter weiß ich nicht mehr
Narses - Mo 30.03.15 22:17
Moin!
Wo sind denn die if-Abfragen? :lupe: ;)
cu
Narses
Nini - Mo 30.03.15 22:31
ok, die muss ich also noch drumrum bauen, hab ich vergessen
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| if ckgeburt0.Checked then else; if ckgeburt1.Checked then else; if ckgeburt2.Checked then else; |
und so weiter
Narses - Mo 30.03.15 22:40
Moin!
Gut, da du bereits eine Checkbox für 0 Nachbarn vorgesehen hast: hast du dann auch die Deklaration von TNachbarn entsprechend angepasst? :lupe:
Und hier noch die Syntax, um ein Element einer Menge hinzuzufügen:
Delphi-Quelltext
1:
| MengenVariable := MengenVariable +[3]; |
Dann solltest du jetzt den Code vervollständigen können (zumindest den Block, der sich um das Abfragen kümmert; wir müssen uns ja noch was für die Fenster-Verwaltung einfallen lassen).
cu
Narses
Nini - Mo 30.03.15 22:48
ja, das hab ich schon gemacht
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| if ckgeburt0.Checked then geburt := geburt + [0] else; if ckgeburt1.Checked then geburt := geburt + [1] else; if ckgeburt2.Checked then geburt := geburt + [2] else; if ckgeburt3.Checked then geburt := geburt + [3] else; |
das sollte ja so jetzt glaube ich stimmen
Narses - Mo 30.03.15 22:58
Moin!
Nini hat folgendes geschrieben : |
ja, das hab ich schon gemacht |
:zustimm:
Nini hat folgendes geschrieben : |
das sollte ja so jetzt glaube ich stimmen |
Was möchtest du denn mit dem "else;" bewirken? :gruebel: Im else-Fall machst du doch nix (";" = leere Anweisung). :nixweiss: Kannst du also weglassen (oder hinter das else einen Befehl schreiben :?).
Gut, kommen wir zur Einbindung in das Projekt. Du brauchst einen neuen Button auf dem Hauptformular (kannst du ja hinter der Automatik-Checkbox anlegen). Den könnte man "btnRegeln" oder so nennen. ;) Doppelklick drauf machen und dann in den Handler schreiben:
Wenn du das versuchst zu kompilieren, wird es vermutlich eine Fehlermeldung geben. :shock: Warum? :lupe: Weil du dem Compiler noch nicht gesagt hast, dass du von Form1 aus auf Form2 zugreifen möchtest. :think: Also musst du noch die Verwendung in Form1 anmelden:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| ... implementation
uses Unit2; ... |
Jetzt sollte sich das kompilieren lassen. ;)
cu
Narses
Dundi - Di 31.03.15 04:33
Hallo Narses,
ein Lob an dich ,ich finde es Klasse wie du Nini bei ihrer Hausaufgabe förderst, Hut ab.
Mfg
Dundi
Nini - Di 31.03.15 15:47
Dundi hat folgendes geschrieben : |
Hallo Narses,
ein Lob an dich ,ich finde es Klasse wie du Nini bei ihrer Hausaufgabe förderst, Hut ab.
|
ja das find ich auch voll nett :) danke sehr c:
ja, ich hab jetzt alles so gemacht und es lässt sich kompilieren das programm und mit dem btnRegeln öffne ich dann auch das zweite fenster wenns programm läuft :)
Narses - Di 31.03.15 16:22
Moin!
Nini hat folgendes geschrieben : |
ja das find ich auch voll nett :) danke sehr c: |
:beer:
Nini hat folgendes geschrieben : |
mit dem btnRegeln öffne ich dann auch das zweite fenster wenns programm läuft :) |
Fein. ;) Dann müssen wir noch einen Button auf dem Regel-Formular anlegen, mit dem man diesen Dialog wieder schließen kann (das solltest du mittlerweile alleine hinkriegen, oder? :zustimm:)
Wenn der Dialog geschlossen wurde, müssen wir jetzt die Regel-Mengen aktualisieren. Also kommt der Code hinter das Form2.ShowModal;. :idea: Mach mal einen Vorschlag, wie´s da weiter geht. :les:
cu
Narses
Nini - Di 31.03.15 20:01
wie das jetzt so richtig weiter geht kann ich mir noch nicht so ganz vorstellen, aber ich muss als erstes jetzt irgendwie die mengen geburt und ueberleben aus der unit2 in die unit1 bekommen glaub ich.
ja, also ich hab das einfach so gemacht:
Delphi-Quelltext
1: 2: 3: 4:
| procedure TForm2.btnEndeClick(Sender: TObject); begin close; end; |
Narses - Di 31.03.15 20:51
Moin!
Nini hat folgendes geschrieben : |
ja, also ich hab das einfach so gemacht: |
Top. :zustimm:
Nini hat folgendes geschrieben : |
ich muss als erstes jetzt irgendwie die mengen geburt und ueberleben aus der unit2 in die unit1 bekommen glaub ich. |
Die Mengen-Variablen sollten ja eigentlich bereits in der Form1-Klasse deklariert sein, so gesehen sind die schon da, wo sie hingehören. :lupe: Was du jetzt brauchst, ist der Zugriff auf Komponenten in Form2 von einer Methode in Form1. :idea: Und das geht so:
Delphi-Quelltext
1:
| if Form2.ckgeburt0.Checked then geburt := geburt + [0]; |
Das muss jetzt ausgeführt werden, nachdem Form2 geschlossen wurde (also hinter das Form2.ShowModal; diese Methode "wartet" quasi darauf, dass das Formular wieder geschlossen wird :idea:).
cu
Narses
Nini - Di 31.03.15 21:36
jaa, da funktioniert das programm wieder komplett :)
Narses - Di 31.03.15 22:39
Moin!
Fein, dann zeig doch mal die komplette btnRegelnClick-Methode. :les: ;)
cu
Narses
Nini - Mi 01.04.15 17:37
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:
| procedure TForm1.btnRegelnClick(Sender: TObject); begin form2.ShowModal; geburt := []; ueberleben := []; if Form2.ckgeburt0.Checked then geburt := geburt + [0]; if Form2.ckgeburt1.Checked then geburt := geburt + [1]; if Form2.ckgeburt2.Checked then geburt := geburt + [2]; if Form2.ckgeburt3.Checked then geburt := geburt + [3]; if Form2.ckgeburt4.Checked then geburt := geburt + [4]; if Form2.ckgeburt5.Checked then geburt := geburt + [5]; if Form2.ckgeburt6.Checked then geburt := geburt + [6]; if Form2.ckgeburt7.Checked then geburt := geburt + [7]; if Form2.ckgeburt8.Checked then geburt := geburt + [8];
if Form2.ckueberleben0.checked then ueberleben := ueberleben + [0]; if Form2.ckueberleben1.checked then ueberleben := ueberleben + [1]; if Form2.ckueberleben2.checked then ueberleben := ueberleben + [2]; if Form2.ckueberleben3.checked then ueberleben := ueberleben + [3]; if Form2.ckueberleben4.checked then ueberleben := ueberleben + [4]; if Form2.ckueberleben5.checked then ueberleben := ueberleben + [5]; if Form2.ckueberleben6.checked then ueberleben := ueberleben + [6]; if Form2.ckueberleben7.checked then ueberleben := ueberleben + [7]; if Form2.ckueberleben8.checked then ueberleben := ueberleben + [8]; end; |
Narses - Mi 01.04.15 18:47
Moin!
OK. ;) Allerdings :? ziemlich viel gleiche Sachen, oder? :lupe: Ideen, wie man das "einfacher" machen kann? :zwinker: :idea:
cu
Narses
Nini - Mi 01.04.15 20:03
das geht bestimmt so ähnlich wie bei den shapes
vielleicht so ungefähr? :
Delphi-Quelltext
1: 2: 3: 4:
| for i:= 0 to 8 do begin ckgeburt:= Tcheckbox(FindComponent('ckgeburt' +IntToStr(i))); if form2.ckgeburt.checked then geburt := geburt + [i]; end; |
Narses - Mi 01.04.15 21:45
Moin!
Nini hat folgendes geschrieben : |
das geht bestimmt so ähnlich wie bei den shapes |
8)
Nini hat folgendes geschrieben : |
vielleicht so ungefähr? : |
:zustimm:
Allerdings: die Checkboxen sind ja auf Form2, also musst du das FindComponent von Form2 aufrufen:
Delphi-Quelltext
1: 2: 3: 4: 5:
| for i := 0 to 8 do begin ckgeburt := TCheckBox(Form2.FindComponent('ckgeburt' +IntToStr(i))); if ckgeburt.checked then geburt := geburt + [i]; end; |
Da kannst du sogar noch gleich die andere Spalte Checkboxen mit rein nehmen. :idea:
cu
Narses
Nini - Mi 01.04.15 22:02
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TForm1.btnRegelnClick(Sender: TObject); var ckgeburt, ckueberleben : TCheckBox; i : integer; begin form2.ShowModal; geburt := []; ueberleben := [];
for i := 0 to 8 do begin ckgeburt := TCheckBox(Form2.FindComponent('ckgeburt' +IntToStr(i))); if ckgeburt.checked then geburt := geburt + [i]; end;
for i := 0 to 8 do begin ckueberleben := TCheckBox(Form2.FindComponent('ckueberleben' +IntToStr(i))); if ckueberleben.checked then ueberleben := ueberleben + [i]; end; end; |
Narses - Mi 01.04.15 22:19
Moin!
:les: :idea: :nixweiss:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure TForm1.btnRegelnClick(Sender: TObject); var ckgeburt, ckueberleben: TCheckBox; i: Integer; begin Form2.ShowModal; geburt := []; ueberleben := []; for i := 0 to 8 do begin ckgeburt := TCheckBox(Form2.FindComponent('ckgeburt' +IntToStr(i))); if ckgeburt.checked then geburt := geburt + [i]; ckueberleben := TCheckBox(Form2.FindComponent('ckueberleben' +IntToStr(i))); if ckueberleben.checked then ueberleben := ueberleben + [i]; end; end; |
Ich möchte dir aber noch einen anderen Ansatz zeigen, wie man das Problem auch lösen könnte: mit einer lokalen Funktion: :think:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| procedure TForm1.btnRegelnClick(Sender: TObject);
function GetRuleSet(const AName: String): TRegeln; var CheckBox: TCheckBox; i: Integer; begin Result := []; ... end;
begin Form2.ShowModal; ueberleben := GetRuleSet('ckueberleben'); geburt := GetRuleSet('ckgeburt'); end; |
Probier mal. :D
cu
Narses
Nini - Mo 13.04.15 16:01
so jetzt sind die ferien wieder vorbei und internet wieder da :P ich hab auch die letzten zwei wochen drüber nachgedacht wie das gehen könnte, aber ehrlich gesagt finde ich die funktionen noch etwas unverständlich :(
Narses - Mo 13.04.15 16:38
Moin!
Nini hat folgendes geschrieben : |
so jetzt sind die ferien wieder vorbei und internet wieder da :P |
Ah, du bist ja doch noch dabei! :D Ich hatte schon befürchtet, die "Hausaufgabe" ist erledigt, die Note gerettet, und auf wiedersehen Programmiererei... :P Schön, dass du (immer) noch Interesse hast. :zustimm:
Nini hat folgendes geschrieben : |
ich hab auch die letzten zwei wochen drüber nachgedacht wie das gehen könnte, aber ehrlich gesagt finde ich die funktionen noch etwas unverständlich :( |
OK, dann nehmen wir doch einfach mal das entsprechende (Teil-)Stück Code von oben (deine Version):
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| geburt := []; for i := 0 to 8 do begin ckgeburt := TCheckBox(Form2.FindComponent('ckgeburt' +IntToStr(i))); if ckgeburt.checked then geburt := geburt + [i]; end; |
Im Prinzip muss díeser Teil jetzt - etwas allgemeiner formuliert, die Ansätze siehst du ja schon in meinem Code - da irgendwie "rein". Probier einfach mal, ist nicht schlimm, wenn´s nicht sofort passt. ;)
cu
Narses
Nini - Mo 13.04.15 17:30
ist das dann vielleicht in etwa so?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TForm1.btnRegelnClick(Sender: TObject);
function GetRuleSet(const AName: String): TRegeln; var CheckBox: TCheckBox; i: Integer; begin Result := []; for i := 0 to 8 do begin checkbox := TCheckBox(Form2.FindComponent('ckgeburt' +IntToStr(i))); if checkbox.checked then result := result + [i]; end;... end;
begin Form2.ShowModal; ueberleben := GetRuleSet('ckueberleben'); geburt := GetRuleSet('ckgeburt'); end; |
Narses - Mo 13.04.15 20:57
Moin!
Ja, das ist schon ganz gut. Allerdings beachtest du noch nicht den übergebenen Namen in der Funktion. :idea: Und dann noch die 3 Punkte entfernen, und schon sollte sich das kompilieren lassen. ;)
cu
Narses
Nini - Mo 13.04.15 21:11
ich habe keine ahnung was ich ändern muss :(
Narses - Mo 13.04.15 22:05
Moin!
Nini hat folgendes geschrieben : |
ich habe keine ahnung was ich ändern muss :( |
OK, dann gaaanz langsam. ;)
Das ist der Aufruf der Funktion:
Delphi-Quelltext
1:
| ueberleben := GetRuleSet('ckueberleben'); |
In der Funktion ist dann die Textkonstante als Parameter vorhanden:
Delphi-Quelltext
1:
| function GetRuleSet(const AName: String): TRegeln; |
Mach mal folgenden Test:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TForm1.btnRegelnClick(Sender: TObject);
function GetRuleSet(const AName: String): TRegeln; begin ShowMessage(AName); end;
begin Form2.ShowModal; ueberleben := GetRuleSet('ckueberleben'); geburt := GetRuleSet('ckgeburt'); end; |
Probier das mal aus. :lupe: :think:
cu
Narses
Nini - Di 14.04.15 19:47
so also wenn ich btnRegeln öffne und dann schließe kriege ich ein Nachrichtenfeld in dem ckGeburt steht und wenn ich das geschlossen habe darunter ein Feld auf dem ckueberleben steht.
Narses - Di 14.04.15 23:16
Moin!
OK, dann ändere das mal so ab:
Delphi-Quelltext
1: 2:
| ueberleben := GetRuleSet('hallo'); geburt := GetRuleSet('holla'); |
Und, was passiert? ;)
cu
Narses
Nini - Mi 15.04.15 17:58
da kommt dann als text holla bzw. hallo
Narses - Mi 15.04.15 22:40
Moin!
Und, kapiert was da mit dem Parameter AName passiert? :zwinker:
Dann jetzt nochmal der Code:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TForm1.btnRegelnClick(Sender: TObject);
function GetRuleSet(const AName: String): TRegeln; var CheckBox: TCheckBox; i: Integer; begin Result := []; for i := 0 to 8 do begin checkbox := TCheckBox(Form2.FindComponent('ckgeburt' +IntToStr(i))); if checkbox.checked then result := result + [i]; end; end;
begin Form2.ShowModal; ueberleben := GetRuleSet('ckueberleben'); geburt := GetRuleSet('ckgeburt'); end; |
Was passt hier also noch nicht?
cu
Narses
Nini - Do 16.04.15 18:24
muss ich vielleicht das ueberleben/geburt noch dem aName zuweisen?
Narses - Do 16.04.15 20:59
Moin!
Nini hat folgendes geschrieben : |
muss ich vielleicht das ueberleben/geburt noch dem aName zuweisen? |
Das passiert hier bereits: (beim Aufruf)
Delphi-Quelltext
1: 2:
| ueberleben := GetRuleSet('ckueberleben'); geburt := GetRuleSet('ckgeburt'); |
Aber du beachtest es in der Funktion nicht. :idea: :zwinker:
cu
Narses
Nini - Fr 17.04.15 22:23
und wie bekomm ich den denn da rein? O.o
Narses - Sa 18.04.15 01:05
Moin!
Nini hat folgendes geschrieben : |
und wie bekomm ich den denn da rein? O.o |
Ganz einfach, über AName drauf zugreifen, wie hier auch im Test:
Delphi-Quelltext
1: 2: 3: 4:
| function GetRuleSet(const AName: String): TRegeln; begin ShowMessage(AName); end; |
cu
Narses
Nini - Sa 18.04.15 14:27
vlt so in der art?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TForm1.btnRegelnClick(Sender: TObject);
function GetRuleSet(const AName: String): TRegel; var CheckBox: TCheckBox; i: Integer; begin Result(AName) := []; for i := 0 to 8 do begin checkbox:= TCheckBox(Form2.FindComponent('ckgeburt' +IntToStr(i))); if checkbox.checked then result(AName) := result(AName) + [i]; end; end;
begin Form2.ShowModal; ueberleben := GetRuleSet('ueberleben'); geburt := GetRuleSet('geburt'); end; |
Narses - Sa 18.04.15 16:04
Moin!
OK, zwei Sachen:
Delphi-Quelltext
1:
| checkbox:= TCheckBox(Form2.FindComponent('ckgeburt' +IntToStr(i))); |
Was bewirkt diese Zeile?
Delphi-Quelltext
1: 2:
| ueberleben := GetRuleSet('ckueberleben'); geburt := GetRuleSet('ckgeburt'); |
Vor deinem letzten Vorschlag stand das da so. :idea:
cu
Narses
Nini - Sa 18.04.15 16:22
oh, das hab ich jetzt wieder so geändert :)
die Zeile macht dass die checkbox die mit dem namen ckgeburt i gefunden wurde zur klasse tCheckbox gehört, glaube ich
Narses - Sa 18.04.15 21:36
Moin!
OK, ich denke, du hast noch nicht verstanden, wohin die "Reise" gehen soll, also kannst du den Weg auch nicht finden... :? :nixweiss: Dann müssen wir das erstmal ändern. ;)
Diese Funktion:
Delphi-Quelltext
1:
| function GetRuleSet(const AName: String): TRegel; |
soll eine Gruppe von Checkboxen bearbeiten und das Ergebnis dieser "Bearbeitung" in einer Menge (vom Typ TRegel) abliefern. :idea:
Deshalb rufen wir die Funktion zwei mal auf:
Delphi-Quelltext
1: 2:
| ueberleben := GetRuleSet('ckueberleben'); geburt := GetRuleSet('ckgeburt'); |
Sinn: beim Aufruf geben wir der Funktion mit (der Parameter in Klammern), welche Checkbox-Gruppe bearbeitet werden soll. Und die Zuweisung des Funktionsergebnisses an die entsprechende Variable (ueberleben := bzw. geburt :=) stellt den Zusammenhang von Checkbox-Namen zu Funktion im Programm her. :think:
Du musst also in der Funktion den Namen der Checkbox-Gruppe verwenden (wir als AName bereitgestellt), statt eines konstanten Namens. :les: Jetzt klarer?
cu
Narses
Nini - Sa 18.04.15 21:43
ja also ich glaube, ich hab es jetzt besser verstanden
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TForm1.btnRegelnClick(Sender: TObject);
function GetRuleSet(const AName: String): TRegel; var CheckBox: TCheckBox; i: Integer; begin Result := []; for i := 0 to 8 do begin checkbox:= TCheckBox(Form2.FindComponent('ckgeburt' +IntToStr(i))); if checkbox.checked then result := result + [i]; end; end;
begin Form2.ShowModal; ueberleben := GetRuleSet('aName'); geburt := GetRuleSet('aName'); end; |
Narses - Sa 18.04.15 22:32
Moin!
Nini hat folgendes geschrieben : |
ja also ich glaube, ich hab es jetzt besser verstanden |
Öhm, noch nicht ganz. :P Es ist genau anders rum! :think:
Das hier war so korrekt:
Delphi-Quelltext
1: 2:
| ueberleben := GetRuleSet('ckueberleben'); geburt := GetRuleSet('ckgeburt'); |
Das muss natürlich genau so bleiben, da hier die Verbindung zwischen den (Checkbox-)Namen und den (Regel-)Variablen im Programm hergestellt wird. :idea: (Diese Info kann der Comupter ja alleine nicht erkennen, für den ist ein Name wie "ckgeburt" völlig bedeutungslos :nixweiss:)
Machen wir es mal der Ausführungsreihenfolge nach, nicht der (eigentlich korrekten) Deklarationsreihenfolge nach:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| geburt := GetRuleSet('ckueberleben'); ...
function GetRuleSet(const AName: String): TRegel; var CheckBox: TCheckBox; i: Integer; begin Result := []; for i := 0 to 8 do begin checkbox:= TCheckBox(Form2.FindComponent('ckgeburt' +IntToStr(i))); if checkbox.checked then result := result + [i]; end; end; |
Jetzt klarer? :zwinker:
cu
Narses
Nini - So 19.04.15 18:31
das ganz schön kompliziert o.O
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| function GetRuleSet(const AName: String): TRegel; var CheckBox: TCheckBox; i: Integer; begin Result := []; for i := 0 to 8 do begin checkbox:= TCheckBox(Form2.FindComponent(aName +IntToStr(i))); if checkbox.checked then result := result + [i];
end;
end;
begin Form2.ShowModal; ueberleben := GetRuleSet('ueberleben'); geburt := GetRuleSet('geburt'); end; |
so dann in etwa vielleicht?
Narses - So 19.04.15 18:53
Moin!
Nini hat folgendes geschrieben : |
das ganz schön kompliziert o.O |
8)
Nini hat folgendes geschrieben : |
so dann in etwa vielleicht? |
Jup, das ist es! :zustimm: Allerdings wird das so trotzdem nicht laufen, es sei denn, du hast die Checkboxen umbenannt... :zwinker: Oder? :P
cu
Narses
Nini - So 19.04.15 18:58
achso :autsch: :D danke sehr die heißen ja immernock ckgeburt und ckueberleben :P aber jetzt läuft mein programm wieder :)
Narses - So 19.04.15 19:01
Moin!
Nini hat folgendes geschrieben : |
aber jetzt läuft mein programm wieder :) |
Top! :zustimm:
Dann hast du jetzt auch schon wieder etwas mehr verstanden, was eine Funktion tut. :les: :think:
Und, schon überlegt, wo es weiter geht? ;)
cu
Narses
Nini - So 19.04.15 19:05
ja ich glaub auch, dass ich das jetzt ein bisschen besser verstehe :)
ich würd gern noch N ändern können auf der spieloberfläche, also dass das keine festgelegte konstante mehr ist ...
Narses - So 19.04.15 19:08
Moin!
Nini hat folgendes geschrieben : |
ich würd gern noch N ändern können auf der spieloberfläche, also dass das keine festgelegte konstante mehr ist ... |
OK. 8) Und schon Ideen, wie das gehen soll? :nixweiss:
cu
Narses
Nini - So 19.04.15 19:50
also ich brauch irgendwas zum eingeben für N, nen editfeld oder sowas wie nen schieberegler oder sowas und dann muss ich das als wert für N einlesen
Narses - So 19.04.15 20:11
Moin!
Nini hat folgendes geschrieben : |
nen schieberegler oder sowas und dann muss ich das als wert für N einlesen |
Jo, klar, irgendwo muss der Benutzer ja kund tun, was er will. ;) Ein Schieberegler finde ich persönlich optimal, da kann man die Eingaben besser begrenzen. :idea:
Aber ich meinte eher: wie soll das "unter der Haube" ablaufen? Wenn wir das Programm gestartet haben, dann sind da ja z.B. schon Shapes erzeugt worden. Was machen wir mit denen? :gruebel:
cu
Narses
Nini - So 19.04.15 20:20
gute frage ... vielleicht einfach wieder löschen? ich weiß es nicht :/
Narses - So 19.04.15 22:01
Moin!
Nini hat folgendes geschrieben : |
vielleicht einfach wieder löschen? |
Simpel aber einfach, ja, das kann man machen. ;)
Allerdings... :? da werden uns jetzt gleich ein paar Probleme über den Weg laufen... :hair:
Zunächst mal haben wir das "Eigentümer-Problem". Hier mal ein Stück aus dem Code zum Erzeugen der Shapes:
Delphi-Quelltext
1:
| Shape := TShape.Create(Self); |
Du siehst es schon am Kommentar: wir übergeben das neue Shape dem Formular (also nicht nur zur Anzeige, sondern als Eigentümer des Speicherplatzes). Folglich dürfen wir das nicht einfach wieder selbst freigeben, weil uns die Komponenten gar nicht mehr "gehören" (wird mit Exceptions bestraft)! :shock:
Wir müssen also statt "Self" ein "nil" übergeben, dann "gehört" die Komponente uns. Allerdings müssen wir dann auch irgendwo eine Referenz darauf "aufheben", weil - ganz simpel, grade geplant - wir sie auch später nicht mehr freigeben können, wenn wir sie nicht "wiederfinden". :lupe:
Vorschläge, wie man das in den Griff kriegt? :les:
cu
Narses
Nini - Di 21.04.15 17:33
ne dazu hab ich echt gar keine idee o.O
Narses - Di 21.04.15 17:58
Moin!
Nini hat folgendes geschrieben : |
ne dazu hab ich echt gar keine idee o.O |
Hm, das ist aber potenziell ganz schlecht, weil 8) wer soll das dann machen... ? :lupe: :P
So schwer ist das gar nicht, nur etwas viel. :? Du kennst doch arrays, haben wir doch schon benutzt. Hilft uns sowas vielleicht weiter? :les:
cu
Narses
Nini - Di 21.04.15 18:19
vielleicht kann man die shapes als feld übergeben? also wieder zweidimensional oder so? :/
Narses - Di 21.04.15 18:38
Moin!
Ja, das ist eine Möglichkeit. Einfach noch ein Feld (2-dimensionales Array) für die Shapes anlegen, so wie bei den Booleans für die Berechnung. :idea: Dann mach mal einen Vorschlag, wie das aussehen könnte (ist egal wenn das falsch ist, Rom wurde auch nicht an einem Tag erbaut :P). :les:
cu
Narses
Nini - Mi 22.04.15 17:14
ich bin mir noch ganz unsicher, wie ich was da machen muss ...
als erstes glaub ich muss ich das feld deklarieren, bestimmt am besten unter public, dass es global ist aber welcher klasse soll ich das neue feld zuweisen?
geht das so?
Delphi-Quelltext
1: 2: 3: 4: 5:
| type TFeldShape = array[0..N-1, 0..N-1] of TShape; [...] public FeldShape : TFeldShape; |
Narses - Mi 22.04.15 21:10
Moin!
Nini hat folgendes geschrieben : |
ich bin mir noch ganz unsicher, wie ich was da machen muss ... |
Das wird schon. :zustimm:
Nini hat folgendes geschrieben : |
als erstes glaub ich muss ich das feld deklarieren, |
Jup.
Nini hat folgendes geschrieben : |
bestimmt am besten unter public, dass es global ist |
Ist OK.
Nini hat folgendes geschrieben : |
aber welcher klasse soll ich das neue feld zuweisen? |
Hä? :gruebel: Meinst du den Elementtyp, da ist doch TShape genau richtig. ;)
Nini hat folgendes geschrieben : |
geht das so? Delphi-Quelltext 1: 2: 3: 4: 5:
| type TFeldShape = array[0..N-1, 0..N-1] of TShape; [...] public FeldShape : TFeldShape; | |
Grundsätzlich nicht schlecht, aber N soll doch variabel werden. :zwinker: Wie könnte man denn dieses Problem lösen? :les:
cu
Narses
Nini - Mi 22.04.15 21:26
dann mein ich bestimmt elementtyp, ich komm mit den ganzen begriffen nicht so ganz klar :P
Delphi-Quelltext
1: 2: 3: 4: 5:
| type TFeldShape = array[0..30, 0..30] of TShape; [...] public FeldShape : TFeldShape; |
ich kann ja so einfach einen höchstwert für die Feldgröße festlegen
Narses - Mi 22.04.15 21:58
Moin!
Nini hat folgendes geschrieben : |
dann mein ich bestimmt elementtyp, ich komm mit den ganzen begriffen nicht so ganz klar :P |
Alles OK. ;)
Nini hat folgendes geschrieben : |
ich kann ja so einfach einen höchstwert für die Feldgröße festlegen |
Perfekt! :zustimm: Genau so, einfach einen Maximalwert festlegen. Aaaaber... dann bitte auch als Konstante wie N deklarieren (z.B. als "Nmax"). :idea: Wie würde das dann aussehen? :les:
cu
Narses
Nini - Mi 22.04.15 22:47
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| const Nmax = 35; [...] type TFeldShape = array[0..NMax-1, 0..NMAX-1] of TShape; [...] public FeldShape : TFeldShape; |
wäre das dann so?
Narses - Mi 22.04.15 23:20
Moin!
Top! :zustimm:
Dann müssen wir jetzt als nächstes die Shape-Erzeugung angehen: die müssen jetzt mit "nil" als Parameter erzeugt werden und dann als Referenz im neuen Feld abgelegt werden. :les:
cu
Narses
Nini - Do 23.04.15 18:26
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin Shape := TShape.Create(Nil); Shape.Parent := Self; snr := x +y *N +1; Shape.Name := 'Shape'+inttostr(snr); Shape.Left := 10+x*25; Shape.Top := 80+y*25; Shape.Width := 25; Shape.Height := 25; Shape.OnMouseDown := @Shape1MouseDown; FeldShape[x,y] := Shape; end; ClientHeight := N*25+100; ClientWidth := N*25+20; end; |
Ist das dann irgendwie so in der Art?
Narses - Do 23.04.15 18:36
Moin!
Nini hat folgendes geschrieben : |
Ist das dann irgendwie so in der Art? |
Sollte passen. ;)
Dann brauchen wir noch einen Schieberegler oben im Formular, welcher zwischen 3 und Nmax einstellbare Werte erlaubt (weniger als 3 macht keinen Sinn und mehr als Nmax erlauben wir nicht). :les:
cu
Narses
Nini - Do 23.04.15 18:54
hab ich eingebaut :)
Narses - Fr 24.04.15 12:34
Moin!
Nini hat folgendes geschrieben : |
hab ich eingebaut :) |
Fein. :) Hast du das denn auch so gemacht, dass man nur die Konstante Nmax ändern muss, wenn man diesen Wert verändern möchte? :zwinker:
Als nächstes müssen wir uns darum kümmern, dass die erstellen Shapes,
die ja nun uns gehören, auch beim Programmende wieder freigegeben werden. :idea: Sonst haben wir ein Speicher-Leck (wir fordern Speicher für die Shapes an, aber geben ihn nicht wieder frei :shock:)! Dazu eine Idee? :les:
cu
Narses
Nini - Fr 24.04.15 19:36
Ne der wollte NMax als maximumwert nicht akzeptieren :/
Nee da hab ich leider keine idee :(
Narses - Fr 24.04.15 20:28
Moin!
Nini hat folgendes geschrieben : |
Ne der wollte NMax als maximumwert nicht akzeptieren :/ |
Ja, das hab ich mir schon gedacht. :D Lösung: In der FormCreate-Methode musst du den Maximalwert per Code setzen. :idea:
Nini hat folgendes geschrieben : |
Nee da hab ich leider keine idee :( |
Was sich auf das Freigeben bezieht, nehme ich an. Ansatz: Du läufst mit einer Schleife über
alle Felder in FeldShape und wenn da nicht Nil drin steht, dann gibst du das Element mit .Free; frei und setzt dann das Element auf Nil. Das Ganze könnte z.B. im FormDestroy passieren... :angel:
cu
Narses
Nini - Fr 24.04.15 21:57
was ist denn formdestroy? o.O
Narses - Fr 24.04.15 22:01
Moin!
Das ist die Methode, die aufgerufen wird, wenn das Formular gelöscht werden soll. :idea: Zumindest bei Delphi kommt man da so dran: das Formular markieren, dann im Objekt-Inspektor auf die Ereignisse-Seite wechseln, in der Liste dann einen Doppelklick auf OnDestroy machen, dann wird der Handler erzeugt. :lupe:
cu
Narses
Nini - Fr 24.04.15 23:07
danke, hab es jetzt gefunden ;)
aber ich glaube ich hab das was ich machen soll nicht ganz verstanden, ich wür es so machen aber dass sieht falsch aus
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure TForm1.FormDestroy(Sender: TObject); var y,x : integer;
begin for y := 0 to N-1 do for x := 0 to N-1 do begin if not FeldShape(nil) then FeldShape.free; FeldShape.free := FeldShape.nil; end; end; |
Narses - Fr 24.04.15 23:39
Moin!
Nini hat folgendes geschrieben : |
aber ich glaube ich hab das was ich machen soll nicht ganz verstanden |
Ja, das könnte sein. ;) Ist aber nicht schlimm, das kriegen wir hin. :zustimm:
Dann fangen wir mal an:
- Wie greift man auf eine Feldvariable zu (=array-element)? Mit eckigen Klammern!
- Du verwendest x und y als Schleifenvariablen, aber nutzt sie nirgendwo
- Man kann ganz simpel prüfen, ob eine Variable nil ist, einfach mit: if (variable = nil) then
- Man kann nil einer Variablen auch ganz genau so einfach zuweisen: variable := nil;
Damit solltest du erstmal weiter kommen. :les:
cu
Narses
Nini - Sa 25.04.15 00:07
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm1.FormDestroy(Sender: TObject); var y,x : integer;
begin for y := 0 to N-1 do for x := 0 to N-1 do begin if not (FeldShape[x,y]=nil) then FeldShape.free; FeldShape[x,y] := nil; end; end; |
ist das dann so?
Boldar - Sa 25.04.15 00:12
Das sieht doch erstmal ganz gut aus.
Hast du denn das hier schon gemacht:
Narses hat folgendes geschrieben : |
Ja, das hab ich mir schon gedacht. :D Lösung: In der FormCreate-Methode musst du den Maximalwert per Code setzen. :idea:
|
??
Nini - Sa 25.04.15 00:18
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; Schieberegler : TScrollBar; begin [...] NMax := 24; Schieberegler.Max := NMax; end; |
ich hab mir das so gedacht aber si ganz stimmt das glaub ich noch nicht
Narses - Sa 25.04.15 00:33
Moin!
Zeig mal den ganzen Code, wir müssen mal wieder einen Basisabgleich machen. ;)
cu
Narses
Nini - Sa 25.04.15 09:00
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: 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: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241:
| unit Unit1;
{$mode objfpc}{$H+}
interface
uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls;
const Nmax = 35;
type TNachbarn = 0..8; TRegel = set of TNachbarn; TFeld = array[0..N-1, 0..N-1] of Boolean; TFeldShape = array[0..Nmax-1, 0..NMax-1] of TShape;
TForm1 = class(TForm) btnRegeln: TButton; btnLeeren: TButton; ckAutomatik: TCheckBox; Ende: TButton; ScrollBar1: TScrollBar;
Timer: TTimer; procedure btnLeerenClick(Sender: TObject); procedure btnLesenClick(Sender: TObject); procedure btnRechnenClick(Sender: TObject); procedure btnRegelnClick(Sender: TObject); procedure btnSchreibenClick(Sender: TObject); procedure ckAutomatikChange(Sender: TObject); procedure EndeClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ScrollBar1Change(Sender: TObject); procedure Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure TimerTimer(Sender: TObject); procedure FormDestroy(Sender: TObject);
private
public FeldShape: TFeldShape; Feld: TFeld; Ueberleben: TRegel; Geburt: TRegel; function LebtNachbar(x, y: Integer): Boolean; function AnzahlLebenderNachbarn(const x, y: Integer): Integer; end;
var Form1: TForm1;
implementation
uses Unit2; {$R *.lfm}
procedure TForm1.Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ThisShape: TShape; begin ThisShape := (Sender as TShape); if (ThisShape.Brush.Color = clWhite) then ThisShape.Brush.Color := clBlack else ThisShape.Brush.Color := clWhite; end;
procedure TForm1.ckAutomatikChange(Sender: TObject); begin if ckAutomatik.Checked then begin btnLesenClick(Self); Timer.Enabled := True; end else Timer.Enabled := False; end;
procedure TForm1.btnLesenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (Shape.Brush.Color = clBlack) then Feld[x, y] := True else Feld[x, y] := False; end; end;
procedure TForm1.btnLeerenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do if (feld[x,y]) then feld[x,y] := false;
for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (feld[x,y]) then shape.brush.color := clblack else shape.brush.color := clwhite; end; end;
procedure TForm1.TimerTimer(Sender: TObject); begin btnrechnenClick(Self); end;
procedure TForm1.btnRechnenClick(Sender: TObject); var x, y: Integer; FeldNeu: TFeld; begin for y := 0 to N-1 do for x := 0 to N-1 do if Feld[x, y] then FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) in ueberleben) else FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) in geburt); Feld := FeldNeu; btnSchreibenClick(Self); end;
procedure TForm1.btnRegelnClick(Sender: TObject);
function GetRuleSet(const AName: String): TRegel; var CheckBox: TCheckBox; i: Integer; begin Result := []; for i := 0 to 8 do begin checkbox:= TCheckBox(Form2.FindComponent(aName +IntToStr(i))); if checkbox.checked then result := result + [i];
end;
end;
begin Form2.ShowModal; ueberleben := GetRuleSet('ckueberleben'); geburt := GetRuleSet('ckgeburt'); end;
function TForm1.AnzahlLebenderNachbarn(const x, y: Integer): Integer; var dx, dy: Integer; begin Result := 0; for dy := -1 to 1 do for dx := -1 to 1 do begin if ((dx<>0) or (dy<>0)) then if LebtNachbar(x +dx, y +dy) then Inc(Result); end; end;
function TForm1.LebtNachbar(x, y: Integer): Boolean; begin Result := Feld[(x+N) mod N, (y+N) mod N]; end;
procedure TForm1.btnSchreibenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (feld[x,y]) then shape.brush.color := clblack else shape.brush.color := clwhite; end;
end;
procedure TForm1.EndeClick(Sender: TObject); begin close; end;
procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; Schieberegler : TScrollBar; begin for y := 0 to N-1 do for x := 0 to N-1 do begin Shape := TShape.Create(Nil); Shape.Parent := Self; snr := x +y *N +1; Shape.Name := 'Shape'+inttostr(snr); Shape.Left := 10+x*25; Shape.Top := 80+y*25; Shape.Width := 25; Shape.Height := 25; Shape.OnMouseDown := @Shape1MouseDown; FeldShape[x,y] := Shape; end; ClientHeight := N*25+100; ClientWidth := N*25+20; NMax := 24; Schieberegler.Max := NMax; end;
procedure TForm1.FormDestroy(Sender: TObject); var y,x : integer;
begin for y := 0 to N-1 do for x := 0 to N-1 do begin if not (FeldShape[x,y]=nil) then FeldShape.free; FeldShape[x,y] := nil; end; end;
end. |
das wäre dann so und halt die unit2 noch
Narses - So 26.04.15 12:51
Moin!
Ah, danke. Da ist doch noch was zu tun:
- Du hast die Konstante N in Nmax geändert, aber die anderen Deklarationen nicht angepasst (z.B. TFeld, das basiert noch auf N). Die Felder (arrays) müssen natürlich jetzt mit der Maximalgröße angelegt werden und dann später nur bis zur ausgewählten Größe genutzt. :idea:
- Was auch gleich der zweite Punkt ist: du brauchst unterhalb von der public-Deklaration eine weitere Variable, sagen wir einfach "N: Integer;", in der wir uns die aktuell vom Benutzer eingestellte Größe merken.
- Du hast einen Button-Handler "btnLeerenClick" angelegt. Der soll schätze ich mal das Feld leer machen. Der ist aber unnötig kompliziert ausgefallen... :zwinker:
cu
Narses
Nini - So 26.04.15 14:03
aber das spielfeld leeren funktioniert ja trotzdem :p
hab das jetzt geändert und n in nmax umgeschrieben :)
Narses - So 26.04.15 17:57
Moin!
Nini hat folgendes geschrieben : |
aber das spielfeld leeren funktioniert ja trotzdem :p |
Ich hab ja auch nicht behauptet, dass es nicht funktionieren würde - aber das ändert immer noch nix daran, dass der Code dafür überflüssig kompliziert ist. 8) Egal, das schauen wir uns später noch an.
Nini hat folgendes geschrieben : |
hab das jetzt geändert und n in nmax umgeschrieben :) |
Sehr schön. Allerdings sollte das hier
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; Schieberegler : TScrollBar; begin for y := 0 to N-1 do ClientWidth := N*25+20; NMax := 24; Schieberegler.Max := NMax; end; |
eigentlich mindestens eine Warnung im Compiler produzieren, dass du da den Wert einer Konstanten verändert möchtest. :shock: Das geht natürlich nicht, da du ja hier (oben):
den Wert für Nmax als Konstante (also unveränderlich) festlegst.
Dann würde ich noch vorschlagen, statt einer ScrollBox eine TrackBar zu verwenden (ist bei Delphi im Register Win32). Probier mal lieber diese Komponente aus. ;)
Und dann noch das hier:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TForm1.FormDestroy(Sender: TObject); var y, x: Integer; begin for y := 0 to Nmax-1 do for x := 0 to Nmax-1 do begin if Assigned(FeldShape[x,y]) then begin FeldShape.Free; FeldShape[x,y] := nil; end; end; end; |
Bau das mal ein/um und dann zeig nochmal den kompletten Code. :les:
cu
Narses
Nini - So 26.04.15 18:57
so das wär dann glaub ich das:
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: 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: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256:
| unit Unit1;
{$mode objfpc}{$H+}
interface
uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, ComCtrls;
const Nmax = 35;
type TNachbarn = 0..8; TRegel = set of TNachbarn; TFeld = array[0..Nmax-1, 0..Nmax-1] of Boolean; TFeldShape = array[0..Nmax-1, 0..NMax-1] of TShape;
TForm1 = class(TForm) btnRegeln: TButton; btnLeeren: TButton; ckAutomatik: TCheckBox; Ende: TButton;
Timer: TTimer; TrackBar1: TTrackBar; procedure btnLeerenClick(Sender: TObject); procedure btnLesenClick(Sender: TObject); procedure btnRechnenClick(Sender: TObject); procedure btnRegelnClick(Sender: TObject); procedure btnSchreibenClick(Sender: TObject); procedure ckAutomatikChange(Sender: TObject); procedure EndeClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ScrollBar1Change(Sender: TObject); procedure Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure TimerTimer(Sender: TObject); procedure FormDestroy(Sender: TObject);
private
public FeldShape: TFeldShape; Feld: TFeld; Ueberleben: TRegel; Geburt: TRegel; N: Integer; function LebtNachbar(x, y: Integer): Boolean; function AnzahlLebenderNachbarn(const x, y: Integer): Integer; end;
var Form1: TForm1;
implementation
uses Unit2; {$R *.lfm}
procedure TForm1.Shape1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ThisShape: TShape; begin ThisShape := (Sender as TShape); if (ThisShape.Brush.Color = clWhite) then ThisShape.Brush.Color := clBlack else ThisShape.Brush.Color := clWhite; end;
procedure TForm1.ckAutomatikChange(Sender: TObject); begin if ckAutomatik.Checked then begin btnLesenClick(Self); Timer.Enabled := True; end else Timer.Enabled := False; end;
procedure TForm1.btnLesenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (Shape.Brush.Color = clBlack) then Feld[x, y] := True else Feld[x, y] := False; end; end;
procedure TForm1.btnLeerenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin if (feld[x,y]) then feld[x,y] := false; snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if not (feld[x,y]) then shape.brush.color := clwhite; end; end;
procedure TForm1.TimerTimer(Sender: TObject); begin btnrechnenClick(Self); end;
procedure TForm1.btnRechnenClick(Sender: TObject); var x, y: Integer; FeldNeu: TFeld; begin for y := 0 to N-1 do for x := 0 to N-1 do if Feld[x, y] then FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) in ueberleben) else FeldNeu[x, y] := (AnzahlLebenderNachbarn(x, y) in geburt); Feld := FeldNeu; btnSchreibenClick(Self); end;
var ckgeburt, ckueberleben : TCheckBox; i : integer; begin form2.ShowModal; geburt := []; ueberleben := [];
for i := 0 to 8 do begin ckgeburt := TCheckBox(Form2.FindComponent('ckgeburt' +IntToStr(i))); if ckgeburt.checked then geburt := geburt + [i]; end;
for i := 0 to 8 do begin ckueberleben := TCheckBox(Form2.FindComponent('ckueberleben' +IntToStr(i))); if ckueberleben.checked then ueberleben := ueberleben + [i]; end; end;} procedure TForm1.btnRegelnClick(Sender: TObject);
function GetRuleSet(const AName: String): TRegel; var CheckBox: TCheckBox; i: Integer; begin Result := []; for i := 0 to 8 do begin checkbox:= TCheckBox(Form2.FindComponent(aName +IntToStr(i))); if checkbox.checked then result := result + [i];
end;
end;
begin Form2.ShowModal; ueberleben := GetRuleSet('ckueberleben'); geburt := GetRuleSet('ckgeburt'); end;
function TForm1.AnzahlLebenderNachbarn(const x, y: Integer): Integer; var dx, dy: Integer; begin Result := 0; for dy := -1 to 1 do for dx := -1 to 1 do begin if ((dx<>0) or (dy<>0)) then if LebtNachbar(x +dx, y +dy) then Inc(Result); end; end;
function TForm1.LebtNachbar(x, y: Integer): Boolean; begin Result := Feld[(x+N) mod N, (y+N) mod N]; end;
procedure TForm1.btnSchreibenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (feld[x,y]) then shape.brush.color := clblack else shape.brush.color := clwhite; end;
end;
procedure TForm1.EndeClick(Sender: TObject); begin close; end;
procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; trackbar : TTrackbar; begin for y := 0 to N-1 do for x := 0 to N-1 do begin Shape := TShape.Create(Nil); Shape.Parent := Self; snr := x +y *N +1; Shape.Name := 'Shape'+inttostr(snr); Shape.Left := 10+x*25; Shape.Top := 80+y*25; Shape.Width := 25; Shape.Height := 25; Shape.OnMouseDown := @Shape1MouseDown; FeldShape[x,y] := Shape; end; ClientHeight := N*25+100; ClientWidth := N*25+20; trackbar.Max := NMax; end;
procedure TForm1.FormDestroy(Sender: TObject); var y, x: Integer; begin for y := 0 to Nmax-1 do for x := 0 to Nmax-1 do begin if Assigned(FeldShape[x,y]) then begin FeldShape.Free; FeldShape[x,y] := nil; end; end; end;
end. |
Narses - So 26.04.15 19:22
Moin!
Zwei Kleinigkeiten haben wir aber noch:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TForm1.FormDestroy(Sender: TObject); if Assigned(FeldShape[x,y]) then begin FeldShape[x,y].Free; FeldShape[x,y] := nil; end; |
Hier haben wir "vergessen" zu sagen, welches Shape da freigegeben werden soll. :oops: (das hätte eigentlich als Fehler im Kompiler auftauchen müssen :?)
Und hier:
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:
| procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; trackbar : TTrackbar; begin trackbar.Max := NMax; N := TrackBar.Position; ClientHeight := N*25+100; ClientWidth := N*25+20; for y := 0 to N-1 do for x := 0 to N-1 do begin Shape := TShape.Create(Nil); Shape.Parent := Self; snr := x +y *N +1; Shape.Name := 'Shape'+inttostr(snr); Shape.Left := 10+x*25; Shape.Top := 80+y*25; Shape.Width := 25; Shape.Height := 25; Shape.OnMouseDown := @Shape1MouseDown; FeldShape[x,y] := Shape; end; end; |
haben wir noch nicht dafür gesorgt, dass beim Programmstart N auch einen "vernünftigen" Wert erhält. Weiterhin habe ich das mal etwas umsortiert, so dass es mehr "Sinn" macht.
Damit sollte sich das wieder kompilieren lassen und auch korrekt laufen. OK? :les:
cu
Narses
Nini - So 26.04.15 19:35
ich krieg da grad so ne komische fehlermeldung o.O
ne das war die falsche merk ich grad ich such mal die richtige :D
so das müsste die richtige sein
Moderiert von Narses: Beiträge zusammengefasst.
Narses - So 26.04.15 19:44
Moin!
Ähm, ich seh da grad was: :?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; trackbar : TTrackbar; begin trackbar.Max := NMax; N := TrackBar.Position; |
Das ist natürlich Blödsinn, da einfach eine Trackbar als lokale Variable anzulegen. Du musst natürlich die entsprechende Komponente auf das Formular legen (und dann sollte da ein "TrackBar1" automatisch erstellt werden). :idea:
cu
Narses
Nini - So 26.04.15 19:49
also dann so
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; begin trackbar1.Max := NMax; N := TrackBar1.Position; ClientHeight := N*25+100; ClientWidth := N*25+20; |
das öffnet sich jetzt wieder und hat dann nen 3x3 feld aber mehr will das nicht machen
Narses - So 26.04.15 19:54
Moin!
Nini hat folgendes geschrieben : |
also dann so |
Jup. ;)
Nini hat folgendes geschrieben : |
das öffnet sich jetzt wieder und hat dann nen 3x3 feld aber mehr will das nicht machen |
Dann stell mal TrackBar1.Position im Objekt-Inspektor auf 10, dann sollte der wieder mit 10 Feldern Kantenlänge starten.
Dass da nicht mehr passiert, ist erstmal normal. Genau da müssen wir ja noch ran. :zwinker:
cu
Narses
Nini - So 26.04.15 19:57
ja,jetzt sind es 10x10 felder :)
Narses - So 26.04.15 20:00
Moin!
Vorschläge, wie´s jetzt weiter geht? :lupe: :D
cu
Narses
Nini - So 26.04.15 20:03
irgendwie muss ich jetzt während das programm läuft N wieder einlesen aber wie weiß ich leider gar nicht :(
Narses - So 26.04.15 20:08
Moin!
Nini hat folgendes geschrieben : |
irgendwie muss ich jetzt während das programm läuft N wieder einlesen aber wie weiß ich leider gar nicht :( |
Naja, das ist ja nicht besonders schwer, das hast du sogar schon gemacht:
Delphi-Quelltext
1:
| N := TrackBar1.Position; |
Allerdings... :? das reicht nicht. :nixweiss: Was muss denn noch alles geändert werden? :lupe: :gruebel:
cu
Narses
Nini - So 26.04.15 20:11
die shapes müssen noch dementsprechen erstellt werden
Narses - So 26.04.15 20:16
Moin!
Jap, und was heißt das im Detail? (beschreib mal so genau wie möglich - also was da ablaufen muss, den Code machen wir dann schon) :les:
cu
Narses
Nini - So 26.04.15 20:19
also erst muss ich formdestroy aufrufen, dass die gelöscht werden (oder sind die das dann schon? o.O) und dann muss ich ja eigentlich meiner meinung nach nur wieder mit der schleife von 0 bis N-1 die SHapes erzeugen wie am anfang davor auch also so oder so
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| Shape := TShape.Create(self); Shape.Parent := Self; snr := x +y *N +1; Shape.Name := 'Shape'+inttostr(snr); Shape.Left := 10+x*25; Shape.Top := 80+y*25; Shape.Width := 25; Shape.Height := 25; Shape.OnMouseDown := @Shape1MouseDown; FeldShape[x,y] := Shape; |
Narses - So 26.04.15 20:31
Moin!
Nini hat folgendes geschrieben : |
also erst muss ich formdestroy aufrufen, dass die gelöscht werden |
FormDestroy aufrufen ist nicht so schlau - jedenfalls dann nicht, wenn du das Formular noch weiter nutzen möchtest. :P
Aber du kannst einen Button "btnShapesLoeschen" anlegen und das darüber abwickeln (also dann im FormDestory den Buttonhandler aufrufen, so wie wir das bei Lesen/Schreiben auch gemacht haben; das kannst du dann auch für die neue Idee nutzen). :nixweiss: Dann kann man zwischendurch auch mal (zum Entwickeln! später muss der Button natürlich wieder aus der Formular raus!) so anklicken zum Testen. ;)
Nini hat folgendes geschrieben : |
(oder sind die das dann schon? o.O) und dann muss ich ja eigentlich meiner meinung nach nur wieder mit der schleife von 0 bis N-1 die SHapes erzeugen wie am anfang davor auch |
Jup. Auch hier: wie wäre es mit einem Button "btnShapesAnlegen"? :zwinker:
Wir haben aber noch ein ganz anderes, richtig krasses Problem... :? schon gefunden? :lupe:
cu
Narses
Nini - So 26.04.15 20:39
also das shapeanlegen funktioniert schon mal :)
in den andern prozeduren wussten die ja nicht was N jetzt ist, also hab ich überall
N := TrackBar1.Position; eingefügt
und bei dem löschbutton überlege ich grad noch
Moderiert von Narses: Beiträge zusammengefasstal ich hab das jetzt so gemacht
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: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
| procedure TForm1.btnShapesanlegenClick(Sender: TObject); var snr,y,x : integer; shape : TShape; begin btnShapesLoeschenClick(self); N := TrackBar1.Position; ClientHeight := N*25+100; ClientWidth := N*25+20; for y := 0 to N-1 do for x := 0 to N-1 do begin Shape := TShape.Create(self); Shape.Parent := Self; snr := x +y *N +1; Shape.Name := 'Shape'+inttostr(snr); Shape.Left := 10+x*25; Shape.Top := 80+y*25; Shape.Width := 25; Shape.Height := 25; Shape.OnMouseDown := @Shape1MouseDown; FeldShape[x,y] := Shape; end;
end;
procedure TForm1.btnShapesLoeschenClick(Sender: TObject); var y, x: Integer; begin for y := 0 to Nmax-1 do for x := 0 to Nmax-1 do begin if Assigned(FeldShape[x,y]) then begin FeldShape[x,y].Free; FeldShape[x,y] := nil; end; end; end; |
Narses - Mo 27.04.15 11:16
Moin!
Nini hat folgendes geschrieben : |
also das shapeanlegen funktioniert schon mal :) |
Naja, wenn du die Shapes selbst freigeben willst (was wir ja nun für das Ändern der Größe tun müssen), dann darfst du hier nicht "Self" übergeben, sondern "nil": :!:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| procedure TForm1.btnShapesanlegenClick(Sender: TObject); for y := 0 to N-1 do for x := 0 to N-1 do begin Shape := TShape.Create(self); Shape.Parent := Self; |
Wenn du Komponenten dem Formular übergibst (=wenn du "Self" in die Klammern schreibst), dann kann das üble Folgen haben, wenn du das Programm beendest (Exceptions etc.) und vorher diese Komponenten selbst freigegeben hast! :idea:
Nini hat folgendes geschrieben : |
in den andern prozeduren wussten die ja nicht was N jetzt ist, also hab ich überall N := TrackBar1.Position; eingefügt |
Eigentlich muss das nur an zwei Stellen hin: im FormCreate (zum Vorbelegen beim Programmstart) und dann beim Erzeugen der neuen Shapes. :gruebel: Was genau meinst du also mit "überall"? :lupe: :nixweiss:
Nini hat folgendes geschrieben : |
al ich hab das jetzt so gemacht |
Sieht schonmal gar nicht schlecht aus. :zustimm:
Zeig doch nochmal bitte deine FormCreate und FormDestroy-Methoden. :les:
cu
Narses
Narses - Di 28.04.15 13:46
Moin!
Wie sieht´s aus? :lupe: Probleme? 8) Egal was du machst, ob mit Self oder nil als Parameter für die Shape-Erzeugung - es gibt immer irgendwo Exceptions? :P Könnte das der Grund sein, wieso hier so viel Stille herrscht... ? :zwinker:
Narses hat folgendes geschrieben : |
Wir haben aber noch ein ganz anderes, richtig krasses Problem... :? schon gefunden? :lupe: |
cu
Narses
Nini - Di 28.04.15 20:24
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: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
| procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; begin trackbar1.Max := NMax; N := TrackBar1.Position; ClientHeight := N*25+100; ClientWidth := 620; for y := 0 to N-1 do for x := 0 to N-1 do begin Shape := TShape.Create(Nil); Shape.Parent := Self; snr := x +y *N +1; Shape.Name := 'Shape'+inttostr(snr); Shape.Left := 10+x*25; Shape.Top := 80+y*25; Shape.Width := 25; Shape.Height := 25; Shape.OnMouseDown := @Shape1MouseDown; FeldShape[x,y] := Shape; end; end;
procedure TForm1.FormDestroy(Sender: TObject); var y, x: Integer; begin for y := 0 to Nmax-1 do for x := 0 to Nmax-1 do begin if Assigned(FeldShape[x,y]) then begin FeldShape[x,y].Free; FeldShape[x,y] := nil; end; end; end; |
also das wären erstmal formcreate und formdestroy, aber die exceptions nerven halt total
Narses - Di 28.04.15 20:50
Moin!
Nini hat folgendes geschrieben : |
also das wären erstmal formcreate und formdestroy, |
OK, danke. Aber hattest du nicht bereits Buttons für die Funktionalität (Shapes anlegen/löschen) erstellt? Dann kannst du doch den Button-Click-Handler aufrufen. ;) (und musst den Code nicht zweimal schreiben :idea:)
Nini hat folgendes geschrieben : |
aber die exceptions nerven halt total |
Wir müssen ein "nil" übergeben, da führt kein Weg dran vorbei, sonst dürfen wir die Shapes nicht freigeben. :nixweiss: Also müssen wir die Ursache für die Exceptions suchen. Dazu sollten wir erstmal rausfinden, wann die denn ganz genau auftreten (normalerweise hilft die IDE dir ja und zeigt die Stelle im Code :think:). Wo passiert´s denn? :lupe:
cu
Narses
Nini - Mo 04.05.15 20:59
Delphi-Quelltext
1:
| if (Shape.Brush.Color = clBlack) then |
die zeile ruft das auf also in der lesenprozedure
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure TForm1.btnLesenClick(Sender: TObject); var x, y, snr: Integer; Shape: TShape; begin N := TrackBar1.Position; for y := 0 to N-1 do for x := 0 to N-1 do begin snr := x +y *N +1; Shape := TShape(FindComponent('Shape' +IntToStr(snr))); if (Shape.Brush.Color = clBlack) then Feld[x,y] := True else Feld[x,y] := False; end; end; |
und das mit dem formdestroy/create dann so? O.o
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: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37:
| procedure TForm1.FormCreate(Sender: TObject); var snr,y,x : integer; shape : TShape; begin trackbar1.Max := NMax; N := TrackBar1.Position; ClientHeight := N*25+100; ClientWidth := 620; for y := 0 to N-1 do for x := 0 to N-1 do begin Shape := TShape.Create(Nil); Shape.Parent := Self; snr := x +y *N +1; Shape.Name := 'Shape'+inttostr(snr); Shape.Left := 10+x*25; Shape.Top := 80+y*25; Shape.Width := 25; Shape.Height := 25; Shape.OnMouseDown := @Shape1MouseDown; FeldShape[x,y] := Shape; end; btnShapesAnlegenClick(self) end;
procedure TForm1.FormDestroy(Sender: TObject); var y, x: Integer; begin for y := 0 to Nmax-1 do for x := 0 to Nmax-1 do begin if Assigned(FeldShape[x,y]) then begin FeldShape[x,y].Free; FeldShape[x,y] := nil; end; end; btnShapesLoeschenClick(self); end; |
Narses - Mo 04.05.15 22:11
Moin!
Nini hat folgendes geschrieben : |
Delphi-Quelltext 1:
| if (Shape.Brush.Color = clBlack) then | die zeile ruft das auf also in der lesenprozedure |
Ja, genau. Hier wird eine Exception geworfen, weil hier:
Delphi-Quelltext
1:
| Shape := TShape(FindComponent('Shape' +IntToStr(snr))); |
das Shape nicht mehr gefunden wird (FindComponent liefert dann ein nil = nicht gefunden zurück). :idea: Aber warum? :gruebel: Ganz einfach: da wir beim Erzeugen des Shapes nil übergeben haben, gehört die Komponente nun wirklich uns und nicht mehr dem Formular - da (=im Formular) sucht FindComponent aber.
Wie kommen wir nun weiter? Ganz einfach, wir heben doch schon eine Referenz auf die Shapes in FeldShape auf, dann können wir diese ebenfalls nutzen, um auf die Shapes zuzugreifen, statt über den Namen der Komponente jedes mal danach suchen zu müssen. :think: Ganz konkret also so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm1.btnLesenClick(Sender: TObject); var x, y: Integer; begin for y := 0 to N-1 do for x := 0 to N-1 do if (FeldShape[x,y].Brush.Color = clBlack) then Feld[x,y] := True else Feld[x,y] := False; end; |
Nini hat folgendes geschrieben : |
und das mit dem formdestroy/create dann so? O.o |
Eher nicht. :? Nochmal kurz zur Erinnerung, was wir an dieser Stelle mit den Buttons tun: das ist ein Zwischenschritt, um die Funktionalität (Shapes erstellen/löschen) zum Testen auch mal so zwischendurch probieren zu können. Du solltest also das, was eigentlich getan werden muss, in den Button-Handler verlagern und dann in den Formularmethoden nur noch aufrufen. Konkret:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| procedure TForm1.btnShapesAnlegenClick(Sender: TObject); var x, y: Integer; begin N := TrackBar1.Position; for y := 0 to N-1 do for x := 0 to N-1 do begin FeldShape[x,y] := TShape.Create(Nil); FeldShape[x,y].Parent := Self; FeldShape[x,y].Left := 10+x*25; FeldShape[x,y].Top := 80+y*25; FeldShape[x,y].Width := 25; FeldShape[x,y].Height := 25; FeldShape[x,y].OnMouseDown := @Shape1MouseDown; end; end; |
Und dann im FormCreate nur noch:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TForm1.FormCreate(Sender: TObject); begin Trackbar1.Max := NMax; ClientHeight := N*25+100; ClientWidth := 620; btnShapesAnlegenClick(self); end; |
Deine Aufgaben sind nun:
- Die FindComponent-Aufrufe durch direkte Zugriffe auf FeldShape[] zu ersetzen (damit wir die Exceptions loswerden)
- Den Button-Handler btnShapesLoeschenClick() analog zum Erstellen der Shapes umschreiben
- FormDestroy "bereinigen"
Dann sollte es eigentlich keine Exceptions mehr geben und wir sind bereit für den letzten Schritt: Reaktion auf Änderung der Trackbar. ;)
Dann leg mal los. :zustimm:
cu
Narses
Nini - Mo 18.05.15 12:16
So jetzt hab ich endlich mal daran gedacht, hier wieder zu schreiben. Zur Zeit komme ich einfach nicht mehr zum programmieren, vielleicht später mal wieder, und das Projekt habe ich schon vor einiger Zeit mit dem damaligen Stand abgegeben. Deshalb möchte ich mich noch mal sehr bedanken für deine Hilfe.
Delphi-Laie - Mo 18.05.15 22:48
Hat da Forum eine Chance zu erfahren, ob das Ergebnis Deiner Mühe und im weiteren Sinne der Mühe vieler hier dem kritischen Blicke Deines Fachlehrers standhielt (=Benotung), liebe Nini?
Sicher wird das nicht nur diejenigen interessieren, die sich so rührend Deiner annahmen. Dein Erscheinen hier im Forum führte nicht nur zu einer neuen Dialogform - der reinen Tutor-Zögling-Beziehung -, sondern auch zur Auslagerung ursprünglich bei Dir angesiedelten "peripheren", dafür dann aber umso hitzigeren Meinungstausches.
Nini - Mo 08.06.15 20:56
Heute habe ich jetzt endlich die Info-Hausarbeit Game of life zurückbekommen, hab eine 1 :) :party: endlich mal ne 1 in info, bei der ich das Gefühl habe, auch wirklich was gelernt und verstanden zu haben, auch wenn es natürlich noch verbesserungswürdig ist. Dafür noch einmeieinmal ein Riesendankeschön :)
Delphi-Laie - Mo 08.06.15 21:06
Meine Anerkennung für das verdiente Ergebnis Deiner Audauer und Deines Fleißes, die/den aber auch etliche andere Forumsteilnehmer aufbrachten!
Nersgatt - Di 09.06.15 08:22
Sehr gut! Im wahrsten Sinne des Wortes. :zustimm:
Hier wird ja öfters nach Hausaufgabenhilfe gefragt. Aber Dein Durchhaltevermögen, Einsatz und Willen zum Lernen hat noch niemand gezeigt. Ich ziehe meinen Hut vor Dir, weiter so!
Und Dank natürlich an Narses, der mit einer Engelsgeduld viel Zeit für die Hilfe aufgebracht hat.
Narses - Do 11.06.15 17:42
Moin!
Nini hat folgendes geschrieben : |
endlich mal ne 1 in info, bei der ich das Gefühl habe, auch wirklich was gelernt und verstanden zu haben, |
:zustimm: Das hast du dir redlich verdient, meinen Respekt für dein Engagement. :party:
Nini hat folgendes geschrieben : |
Dafür noch einmeieinmal ein Riesendankeschön :) |
:beer:
Nini hat folgendes geschrieben : |
auch wenn es natürlich noch verbesserungswürdig ist. |
Wie schon mal angedeutet: du bist herzlich willkommen an dem Projekt weiterzuarbeiten, melde dich einfach, wenn du Zeit und Lust hast. ;) Vielleicht hast du ja tatsächlich die Informatik als interessantes Hobby entdeckt... :zwinker:
cu
Narses
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 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!