Autor |
Beitrag |
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Do 05.06.14 21:44
Hallo,
kopiere statt des toten Randes die Spalten vom jeweils gegenüberliegendem Ende und anschliessend die Zeilen
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| 0 00000 0
0 abcde 0 0 abcde 0 0 abcde 0 0 yxcvz 0
0 00000 0 wird zu z yxcvz y
e abcde a e abcde a e abcde a z yxcvz y
e abcde a |
Dann bleibt der Abstand gleich
Mit Modulo Rechnen geht natürlich auf wenn das Feld von 0..Anzahl-1 geht kannst Du leicht mod Anzahl rechnen.Das ist aber sehr langwierig, also lieber nur auf die Felder beschränken, die es Betrifft ( Zeile 1und 2 und Zeile n-1/n-2 und die entsprechenden Spalten.
Wenn man mit drei temporären benachbarten Zeilen arbeiten geht es sehr leicht, aber Du möchtest Dich sicher selbst herausbekommen.
Gruß Horst
P.S.
Zitat: | Man kann ihn als ein Array darstellen, das in sich selbst überläuft statt in einen Rand. |
das wäre eine umlaufende Spirale, oder nicht?
Für diesen Beitrag haben gedankt: galagher
|
|
Hidden
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: Do 05.06.14 22:27
Horst_H hat folgendes geschrieben : | Zitat: | Man kann ihn als ein Array darstellen, das in sich selbst überläuft statt in einen Rand. | das wäre eine umlaufende Spirale, oder nicht? |
So, wie Arrays für gewöhnlich im Speicher liegen, wäre es eine Spirale. Für Den Torus läuft der rechte Rand in den linken über und der untere in den oberen (d.h. sowohl Zeilen- als auch Spaltenweise ist es die Struktur eines Kreises). (Das hat natürlich nicht mehr viel mit Überlauf in der Informatik zu tun, insofern war der Begriff missverständlich und doppelt belegt.)
Horst_H hat folgendes geschrieben : | Mit Modulo Rechnen geht natürlich auf wenn das Feld von 0..Anzahl-1 geht kannst Du leicht mod Anzahl rechnen.Das ist aber sehr langwierig, also lieber nur auf die Felder beschränken, die es Betrifft ( Zeile 1und 2 und Zeile n-1/n-2 und die entsprechenden Spalten. |
Wenn es viele Quelltextstellen sind oder einige Quelltextzeilen dadurch sehr lang werden, würde ich Properties verwenden:
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:
| public Spielfeld: Array[0..15, 0..15] of Boolean;
private function GetSpielfeldAt(x,y: Integer): Boolean; procedure SetSpielfeldAt(x,y: Integer; Value: Boolean); private FSpielfeld: Array[0..15, 0..15] of Boolean; public Property Spielfeld[x,y: Integer]: Boolean read GetSpieldeldAt write SetSpielfeldAt;
function GetSpielfeldAt(x,y: Integer): Boolean; begin x := x mod Length(Spielfeld); y := y mod Length(Spielfeld[x]); result := FSpielfeld[x,y]; end;
procedure SetSpielfeldAt(x,y: Integer; Value: Boolean); begin x := x mod Length(Spielfeld); y := y mod Length(Spielfeld[x]); FSpielfeld[x,y] := Value; end; |
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
Zuletzt bearbeitet von Hidden am Do 05.06.14 23:34, insgesamt 1-mal bearbeitet
|
|
ub60
      
Beiträge: 764
Erhaltene Danke: 127
|
Verfasst: Do 05.06.14 22:51
Also ich habe es mit dem Torus so gemacht. Sollte sich leicht abändern lassen.
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:
| function TSpielfeld.ErmittleNachbarn(x, y: Integer): Byte; var Anzahl : Byte; xa, xe, ya, ye : Integer; begin Anzahl:=0; xa:=x-1; xe:=x+1; ya:=y-1; ye:=y+1; if xa=0 then xa:=100 else if xe>100 then xe:=1; if ya=0 then ya:=100 else if ye>100 then ye:=1; Anzahl:=Anzahl+EArray[xa, ya]; Anzahl:=Anzahl+EArray[x, ya]; Anzahl:=Anzahl+EArray[xe, ya]; Anzahl:=Anzahl+EArray[xa, y ]; Anzahl:=Anzahl+EArray[xe, y ]; Anzahl:=Anzahl+EArray[xa, ye]; Anzahl:=Anzahl+EArray[x, ye]; Anzahl:=Anzahl+EArray[xe, ye]; result:=Anzahl; end; |
ub60
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Fr 06.06.14 17:32
Horst_H hat folgendes geschrieben : | kopiere statt des toten Randes die Spalten vom jeweils gegenüberliegendem Ende und anschliessend die Zeilen |
Diesen Vorschlag könnte ich eventuell realisieren, bei den anderen steige ich nicht durch!
Also habe ich es testweise so versucht:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| for x := -1 to 97 do for y := -1 to 97 do begin if (aBoard[-1, y].clCell = clLivingCell) then atmpBoard[96, y].clCell := clLivingCell; end; |
Das Ergebnis: links und rechts am Rand jeweils ein paar lebende Zellen, aber nicht in der Anordnung, in der sie am linken Rand verschwunden waren. ZB. wenn ein "Segler" über den linken Rand hinauswandert, tauchen rechts dann drei Zellen auf und links bleiben zwei. Das war's...
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Hidden
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: Fr 06.06.14 18:02
Hallo galagher,
wenn dein Array über [0..96, 0..96] indiziert ist, solltest du für einen Torus auch diese Grenzen abfahren. (  ) Den Rand ( -1 und 97) gab es ja nur für das "ummauerte" Rechteck.
Mit dem Quelltextstück kann ich ansonsten nicht viel anfangen, da ist ja noch ein drin; ist das schon vollständig?
viele Grüße,
Daniel
PS: Hat der Ansatz mod Seitenlaenge nicht geklappt?
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
Für diesen Beitrag haben gedankt: galagher
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Fr 06.06.14 18:36
Hidden hat folgendes geschrieben : | Mit dem Quelltextstück kann ich ansonsten nicht viel anfangen, da ist ja noch ein drin; ist das schon vollständig? |
Nein, da kommen dann noch die Regeln wie in de.wikipedia.org/wik...ways_Herausforderung beschrieben, also im Wesentlichen:
if (aBoard[x, y].clCell = clDeathCell) then und if (aBoard[x, y].clCell = clLivingCell) then.
Der Code ist noch ziemlich unkultiviert, muss ich noch optimieren. Er funktioniert aber korrekt.
Hidden hat folgendes geschrieben : | PS: Hat der Ansatz mod Seitenlaenge nicht geklappt? |
Keine Ahnung, wie ich das machen soll! Wo muss der mod-Code hin und bleiben for x := 0 to 96 und for y := 0 to 96 so bestehen?
Und noch eine Frage: Eine Kugelform ist ja unbegenzt, muss die for-Schleife dann noch in einem Timer laufen?
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Hidden
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: Fr 06.06.14 20:12
Angenommen, dein berandetes Spielfeld [-1..16, -1..16] wurde für den Übergang zur nächsten Generation wie folgt behandelt:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| for i := 0 to 15 do begin for j := 0 to 15 do Propagate(i,j); end;
procedure Propagate(x,y: Integer); begin if Spielfeld[x + 1, y + 1] = foo then bar; end; |
Das zugehörige Torus-Spielfeld wäre dann [0..15, 0..15] (der Rand ist nicht mehr nötig), und der Übergang zur nächsten Generation würde sich wie folgt verändern:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| for i := 0 to 15 do begin for j := 0 to 15 do Propagate(i,j); end;
procedure Propagate(x,y: Integer); begin if Spielfeld[ (x + 1) mod 16, (y + 1) mod 16 ] = foo then bar; end; |
Also überall dort, wo Spielfeld[, ] vorkommt, dieses durch Spielfeld[ () mod (a+1), () mod (b+1) ] ersetzen wenn dein Array über [0..a, 0..b] indiziert ist.
Der Aufruf mod 16 zieht so lange 16 vom Ausgangswert ab, bis das Ergebnis kleiner ist als 16.
Für negative Ausgangswerte wird 16 addiert statt subtrahiert, und zwar so lange bis das Ergebnis >= 0 ist.
Beispiel:
Quelltext 1: 2: 3: 4: 5: 6: 7:
| 0 mod 16 = 0 11 mod 16 = 11 15 mod 16 = 15 16 mod 16 = 0 (rechts vom rechten Rand ist linker Rand) (-1) mod 16 = 15 (links vom linken Rand is rechter Rand) <- Das müsstest du mal testen, ich habe gerade kein Delphi da. Es gibt Programmiersprachen, die hier -1 ausgeben, das ist mathematisch falsch und wäre hier fatal 17 mod 16 = 2 46 mod 16 = 14 |
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
Für diesen Beitrag haben gedankt: galagher
|
|
catweasel
      
Beiträge: 487
Erhaltene Danke: 1
Win 7 64bit
Delphi 7 Second Sedition V7.2
|
Verfasst: Fr 06.06.14 20:42
Hi,
Ich habe mir das hier mal durchgelesen und verstehe nicht das Problem dabei.
Der Modulo ist schon der richtige Weg. Ich sehe einfach nicht wo Probleme mit "Rändern" entstehen können..
Ich habe es bei meinem Civilazatio Klon auch so gemacht (da kann man ja auf der Karte auch ewig in eine Richtung scrollen...)
Hier mal ein kleiner Auszug:
(Anmerkung: TIntegerStreamClass ist eine Klasse die nur einen Integerwert published (Data) und diesen Streamen kann, sehr simpel)
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:
| type TMapData = array of array of TMapCellClass;
type TMapClass=class(TObject) private FColCount : TIntegerStreamClass; FRowCount : TIntegerStreamClass; FCells : TMapData; function GetCells(X, Y: integer): TMapCellClass; procedure SetCells(X, Y: integer; const Value: TMapCellClass); public property Cells[X,Y:integer]:TMapCellClass read GetCells write SetCells; end;
function TMapClass.GetCells(X, Y: integer): TMapCellClass; begin Result := FCells[X mod FColCount.Data,Y mod FRowCount.Data]; end;
procedure TMapClass.SetCells(X, Y: integer; const Value: TMapCellClass); begin FCells[X mod FColCount.Data,Y mod FRowCount.Data] := Value; end; |
und da geht auch nichts schief im Bezug auf Ränder..
Wenn man jetzt den linken Nachbarn eines Feldes aus der ersten Spalte (0/n) sucht dann muss man lediglich dafür sorgen das (-m/n) in (max-m/n) umgewandelt werden muss. DAs selbe natürlich auch bei den Zeilen..
also muss oben in die Methoden als Erstes noch ein
Delphi-Quelltext 1: 2:
| if X < 0 then X := FColcount+X; if Y < 0 then Y := FRowcount+Y; |
rein und das sollte doch funktionieren.
Also entweder habe ich jetzt komplett an der Frage vorbei gelesen, oder es sollte doch nicht so schwierig sein ..??
Bei genauerem Hinsehen:
>>Den Randfall hast du sicherlich schon abgefangen, damit du nicht auf Felder außerhalb deiner Arrays zugreifst.
Ja, und zwar, indem das Array an den Rändern um jeweils 1 grösser ist, als der Bereich, der gezeichnet wird
Und da machst du es unnötig kompliziert. Wenn du die MOD Varinte nimmst greifst du die Randfälle automatisch mit ab.
Dan verschwinden auch keine Zellen mehr. Und: selbst wenn due es irgendwie hinbekommst mit dem unsichtbaren Rand, so müssten diese Randzellen das Kunststück vollbringen beim Queren des Randes drei zellen weit zu springen (beide Ränder und hin zur Zielzelle).
Da Zellen aber eben nicht wnadern sondern bleiben wo sie sind und nur leben oder sterben, propagiert diese Wechselwirkung ncht über die Ränder......
Hab mein erstes WATOR auch erst versucht so zu bauen wie du.... und daraus gelernt
Cheers,
Catweasel
_________________ Pommes werden schneller fertig wenn man sie vor dem Frittieren einige Minuten in siedendes Fett legt.
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Fr 06.06.14 21:01
catweasel hat folgendes geschrieben : | Also entweder habe ich jetzt komplett an der Frage vorbei gelesen, oder es sollte doch nicht so schwierig sein ..?? |
Ich blicke einfach nicht durch...
Hier die komplette Prozedur. Wo muss was geändert werden, um einen Torus zu erhalten?
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:
| procedure TForm1.Timer1Timer(Sender: TObject); var i, n, x, y: Integer; b: Boolean; atmpBoard: array [-1..97, -1..97] of record X, Y: Integer; clCell: TColor; end; begin if iGeneration = MaxInt then begin Button4Click(Sender); exit; end;
Inc(iGeneration); Label1.Caption := IntToStr(iGeneration)+'. Generation';
for x := -1 to 97 do for y := -1 to 97 do begin atmpBoard[x, y].clCell := clDeathCell; end;
for x := 0 to 96 do for y := 0 to 96 do begin if (x-1 = -2) or (y-1 = -2) or (x+1 = 97) or (y+1 = 97) then atmpBoard[x, y].clCell := clDeathCell else begin if (aBoard[x, y].clCell = clDeathCell) then begin i := 0; if (aBoard[x-1, y].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y].clCell = clLivingCell) then Inc(i); if (aBoard[x, y-1].clCell = clLivingCell) then Inc(i); if (aBoard[x, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x-1, y-1].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x-1, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y-1].clCell = clLivingCell) then Inc(i);
if i = 3 then begin atmpBoard[x, y].clCell := clLivingCell; end else begin atmpBoard[x, y].clCell := clDeathCell; end; end;
if (aBoard[x, y].clCell = clLivingCell) then begin i := 8; if (aBoard[x-1, y].clCell = clDeathCell) then Dec(i); if (aBoard[x+1, y].clCell = clDeathCell) then Dec(i); if (aBoard[x, y-1].clCell = clDeathCell) then Dec(i); if (aBoard[x, y+1].clCell = clDeathCell) then Dec(i); if (aBoard[x-1, y-1].clCell = clDeathCell) then Dec(i); if (aBoard[x+1, y+1].clCell = clDeathCell) then Dec(i); if (aBoard[x-1, y+1].clCell = clDeathCell) then Dec(i); if (aBoard[x+1, y-1].clCell = clDeathCell) then Dec(i);
if i < 2 then begin atmpBoard[x, y].clCell := clDeathCell; end else begin atmpBoard[x, y].clCell := clLivingCell; end;
i := 0; if (aBoard[x-1, y].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y].clCell = clLivingCell) then Inc(i); if (aBoard[x, y-1].clCell = clLivingCell) then Inc(i); if (aBoard[x, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x-1, y-1].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x-1, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y-1].clCell = clLivingCell) then Inc(i);
if (i = 2) or (i = 3) then begin atmpBoard[x, y].clCell := clLivingCell; end else if i > 3 then begin atmpBoard[x, y].clCell := clDeathCell; end; end; end; end;
for x := -1 to 97 do for y := -1 to 97 do begin if (x = -2) or (y = -2) or (x = 97) or (y = 97) then atmpBoard[x, y].clCell := clDeathCell; end;
b := False;
i := 0; for x := 0 to 96 do for y := 0 to 96 do begin if atmpBoard[x, y].clCell = aBoard[x, y].clCell then Inc(i); end;
if i = 9409 then begin Label1.Caption := 'Nach der '+IntToStr(iGeneration)+'. Generation erstarrt'; iGeneration := 0; Timer1.Enabled := False; Button3.Enabled := False; Button4.Caption := '&Löschen'; end;
n := 0; for x := -1 to 97 do for y := -1 to 97 do begin if atmpBoard[x, y].clCell = clDeathCell then aBoard[x, y].clCell := clDeathCell else begin aBoard[x, y].clCell := clLivingCell; b := True; Inc(n); end; end; Label2.Caption := IntToStr(n)+' lebende Zellen';
DrawBoard(False);
if not b then begin Label1.Caption := 'Nach der '+IntToStr(iGeneration)+'. Generation ausgestorben'; iGeneration := 0; Timer1.Enabled := False; Button3.Enabled := False; Button4.Caption := '&Löschen'; end; |
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
catweasel
      
Beiträge: 487
Erhaltene Danke: 1
Win 7 64bit
Delphi 7 Second Sedition V7.2
|
Verfasst: Fr 06.06.14 21:13
Alllso, der Quellcode ist ja ganz schön unübersichtlich
Warum zum Beispiel ist:
if i = 9409 then ...
Was ist das für eine magische Zahl und warum gerade 9409?
Wofür benötigst du ein temporäres Array mit toten Zellen?
Wie wäre es mit folgendem Ansatz:
Zwei Arrays A und B (oder meinetwegen auch Carl und Lenny).
Und das ganz geht dann so:
- zähle nachbarn in A, schreibe in B
- zeige B an
- zähle nachbarn in B, schreibe in A
- zeige A an.
Sozusagen ein double buffering....
.. und wenn A=B dann ist die welt eingefroren...
Ich hab gerade mal ein bischen Zeit, ich bastel mal was kleines.
Ungefähr ne Stunde oder zwei, dann antworte ich hier nochmal
CU
Catweasel
_________________ Pommes werden schneller fertig wenn man sie vor dem Frittieren einige Minuten in siedendes Fett legt.
|
|
Hidden
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: Fr 06.06.14 21:23
galagher hat folgendes geschrieben : | Wo muss was geändert werden, um einen Torus zu erhalten? |
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:
| procedure TForm1.Timer1Timer(Sender: TObject); var i, n, x, y: Integer; b: Boolean; atmpBoard: array [-1..97, -1..97] of record X, Y: Integer; clCell: TColor; end; begin if iGeneration = MaxInt then begin Button4Click(Sender); exit; end;
Inc(iGeneration); Label1.Caption := IntToStr(iGeneration)+'. Generation';
for x := -1 to 97 do for y := -1 to 97 do begin atmpBoard[x, y].clCell := clDeathCell; end;
for x := 0 to 96 do for y := 0 to 96 do
begin if (aBoard[x, y].clCell = clDeathCell) then begin i := 0; if (aBoard[x-1, y].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y].clCell = clLivingCell) then Inc(i); if (aBoard[x, y-1].clCell = clLivingCell) then Inc(i); if (aBoard[x, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x-1, y-1].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x-1, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y-1].clCell = clLivingCell) then Inc(i);
if i = 3 then begin atmpBoard[x, y].clCell := clLivingCell; end else begin atmpBoard[x, y].clCell := clDeathCell; end; end;
if (aBoard[x, y].clCell = clLivingCell) then begin i := 8; if (aBoard[x-1, y].clCell = clDeathCell) then Dec(i); if (aBoard[x+1, y].clCell = clDeathCell) then Dec(i); if (aBoard[x, y-1].clCell = clDeathCell) then Dec(i); if (aBoard[x, y+1].clCell = clDeathCell) then Dec(i); if (aBoard[x-1, y-1].clCell = clDeathCell) then Dec(i); if (aBoard[x+1, y+1].clCell = clDeathCell) then Dec(i); if (aBoard[x-1, y+1].clCell = clDeathCell) then Dec(i); if (aBoard[x+1, y-1].clCell = clDeathCell) then Dec(i);
if i < 2 then begin atmpBoard[x, y].clCell := clDeathCell; end else begin atmpBoard[x, y].clCell := clLivingCell; end;
i := 0; if (aBoard[x-1, y].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y].clCell = clLivingCell) then Inc(i); if (aBoard[x, y-1].clCell = clLivingCell) then Inc(i); if (aBoard[x, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x-1, y-1].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x-1, y+1].clCell = clLivingCell) then Inc(i); if (aBoard[x+1, y-1].clCell = clLivingCell) then Inc(i);
if (i = 2) or (i = 3) then begin atmpBoard[x, y].clCell := clLivingCell; end else if i > 3 then begin atmpBoard[x, y].clCell := clDeathCell; end; end; end;
for x := -1 to 97 do for y := -1 to 97 do begin if (x = -2) or (y = -2) or (x = 97) or (y = 97) then atmpBoard[x, y].clCell := clDeathCell; end;
b := False;
i := 0; for x := 0 to 96 do for y := 0 to 96 do begin if atmpBoard[x, y].clCell = aBoard[x, y].clCell then Inc(i); end;
if i = 9409 then begin Label1.Caption := 'Nach der '+IntToStr(iGeneration)+'. Generation erstarrt'; iGeneration := 0; Timer1.Enabled := False; Button3.Enabled := False; Button4.Caption := '&Löschen'; end;
n := 0; for x := -1 to 97 do for y := -1 to 97 do begin if atmpBoard[x, y].clCell = clDeathCell then aBoard[x, y].clCell := clDeathCell else begin aBoard[x, y].clCell := clLivingCell; b := True; Inc(n); end; end; Label2.Caption := IntToStr(n)+' lebende Zellen';
DrawBoard(False);
if not b then begin Label1.Caption := 'Nach der '+IntToStr(iGeneration)+'. Generation ausgestorben'; iGeneration := 0; Timer1.Enabled := False; Button3.Enabled := False; Button4.Caption := '&Löschen'; end; |
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
Für diesen Beitrag haben gedankt: galagher
|
|
catweasel
      
Beiträge: 487
Erhaltene Danke: 1
Win 7 64bit
Delphi 7 Second Sedition V7.2
|
Verfasst: Fr 06.06.14 23:49
Hi,
Da bin ich wieder. Hat 2,5 statt 2 Stunden gedauert, weil zwischendurch das Telefon ging
Ich hab mal ein kleines Conway game of life gebastelt und du kannst dir mal anschauen wie das mit den Koordinaten und der (alternierenden) Darstellung gelöst ist. (Hb soweit keine bugs gefunden).
Der Quellcode ist nicht kommentiert, aber auch nicht sonderlich schwierig...
Wenn Fragen? - Dann Fragen!
Ahja: Das Startmuster einfach in die Welt zeichnen.
Cheers,
Catweasel
PS:
Doch einen kleinen Bug entdeckt: Die eingestellte Weltgröße wird erst am dem "Start" übernomen. (Ich müsste WorldA.SetSize() noch in die UpDown.Change events packen)...
Workaround: Width und Height einstellen. Auf Start und dann wieder auf Stopp drücken. Schon kann man auf einer grösseren Welt zeichnen.
Übrigens: Das Zeichnene geht auch während der "Evolution"...
PPS: Gerade kommt mir die Idee durch den Kopf ein Conway GOL basierend auf einem Hex-Grid zu basteln.
Da gibt es nur 6 Nachbarn. Wer weiss welche Regeln man da aufstellen kann und wie sich so eine Welt verhält....
Meint ihr das könnte interessant sein??
Einloggen, um Attachments anzusehen!
_________________ Pommes werden schneller fertig wenn man sie vor dem Frittieren einige Minuten in siedendes Fett legt.
Für diesen Beitrag haben gedankt: galagher
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Sa 07.06.14 07:17
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Jann1k
      
Beiträge: 866
Erhaltene Danke: 43
Win 7
TurboDelphi, Visual Studio 2010
|
Verfasst: Sa 07.06.14 10:33
Für diesen Beitrag haben gedankt: galagher, Hidden
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Sa 07.06.14 11:07
Jann1k hat folgendes geschrieben : | Also irgendwie hakt es ja ganz schön bei dir. Hidden möchte nur, dass du jedesmal aus atmpBoard[x, y] ein atmpBoard[x mod 97, y mod 97] machst. Durch die modulo Funktion bleiben die Indices immer im Bereich [0..96] und du kriegst deinen Torus. Die Konstruktion mit dem Rand voller toter Zellen kannst du dir dann sparen. |
Und warum habe ich das nicht längst gemacht? Geht ja!
Jann1k hat folgendes geschrieben : | Also irgendwie hakt es ja ganz schön bei dir. |
Jetzt nicht mehr!
Sorry, aber ich konnte (kann) mir das einfach nicht vorstellen! Ein zweidimensionales Array ist ja kein Problem, aber mit so etwas habe ich mich noch nie beschäftigt.
Jetzt funktioniert es so, wie ich mir das wünsche: Eine "Kugel"-Welt ist einfach eleganter, denn da werden Objekte am Rand nicht einfach aufgelöst, sondern treten gegenüber wieder ein - eine Kugel eben. Danke!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
catweasel
      
Beiträge: 487
Erhaltene Danke: 1
Win 7 64bit
Delphi 7 Second Sedition V7.2
|
Verfasst: Sa 07.06.14 12:27
Zitat: | catweasel hat folgendes geschrieben : | Der Quellcode ist nicht kommentiert, aber auch nicht sonderlich schwierig... |
Jedenfalls ist er völlig anders als mein Code! |
Ja, weil der Ansatz ein Anderer ist
Dein Ansatz ist : Array nehmen und analysieren und Ergennisse temporär speichern und dann die Ergebnisse in das Array zurückschreiben.
Und das macht es unnötig kompliziert. Vergegenwärtige dir das das "temp" array wenn es gefüllt ist, im Prinzip schon die nächste Generation darstellt. Wenn ich WorldA berechne dient WorldA quasi als temp array für WorldB. (Geschieht bei WorldA.Process(WorldB) )
Da pro Generation nr ein Array einmal glesen/geschrieben wird ist es auch schneller als Arry -> temp und dann temp -> array.
Die Sache mit den Koordinaten und dem Torus steckt in TWorldClass.Transform() die dann von TWorldClass.CountNeighbors() aufegrufen wird.
Da steckt der ganze Gag drin
Aber wenn du willst kann ich gerne den Rest des Codes kommentieren...
Wie du siehst ist wes wirklich simpler. Der ganze Quellcode ist weniger als deine TimerRoutine...
Evtl. könntest du auch die Timer Prozedur in kleinere Subroutinen zerlegen. Das würde die Übersichtlichkeit erhöhen.
Ich persönlich vermeide Methodenkörper mit mehr als 30 Zeilen.
Ist jetzt wirklich nur aus Neugier gefragt: Wie lange programmierst du schon mit Delphi?
Cheers,
Catweasel
_________________ Pommes werden schneller fertig wenn man sie vor dem Frittieren einige Minuten in siedendes Fett legt.
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Sa 07.06.14 13:57
catweasel hat folgendes geschrieben : | Wenn ich WorldA berechne dient WorldA quasi als temp array für WorldB. (Geschieht bei WorldA.Process(WorldB) )
Da pro Generation nr ein Array einmal glesen/geschrieben wird ist es auch schneller als Arry -> temp und dann temp -> array. |
Naja, jetzt läuft es und ich belasse es so!
catweasel hat folgendes geschrieben : | Evtl. könntest du auch die Timer Prozedur in kleinere Subroutinen zerlegen. Das würde die Übersichtlichkeit erhöhen. |
Ist sicher sinnvoll und werde ich auch umsetzen.
catweasel hat folgendes geschrieben : | Ist jetzt wirklich nur aus Neugier gefragt: Wie lange programmierst du schon mit Delphi? |
Schon etliche Jahre, aber ich habe nur wenige Spiele programmiert. Und über ein torusförmiges Array habe ich mir noch nie Gedanken gemacht, ich brauchte es schlicht nicht.
lg
galagher
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
catweasel
      
Beiträge: 487
Erhaltene Danke: 1
Win 7 64bit
Delphi 7 Second Sedition V7.2
|
Verfasst: Sa 07.06.14 14:25
Zitat: | Naja, jetzt läuft es und ich belasse es so! |
Ja klar. Wenns einaml fertig ist
Ich wollte dir eigentlich nur aufzeigen wie der objektorientierte Ansatz hier die Aufgabenstellung radikal vereinfachen kann.
Mann müsste noch nichtmal Objekte nehmen. Das ganze ginge auch mit ein paar globalen Variablen....
Mal so gefragt: Wenn du das nochmal programmieren müsstest, würdest du wieder den gleichen Ansatz wählen?
Cheers,
Catweasel
_________________ Pommes werden schneller fertig wenn man sie vor dem Frittieren einige Minuten in siedendes Fett legt.
|
|
galagher 
      
Beiträge: 2556
Erhaltene Danke: 45
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: So 08.06.14 09:41
catweasel hat folgendes geschrieben : | Mal so gefragt: Wenn du das nochmal programmieren müsstest, würdest du wieder den gleichen Ansatz wählen? |
Ja, würde ich. Es fällt mir ganz einfach leichter, ein quadratisches oder rechteckiges Spielfeld, das ich am Bildschirm ja sehen kann, im Kopf in ein zweidimensionales Array umzurechnen und umgekehrt.
Was ich mir nicht vorstellen konnte, war das Verbinden der Ränder. Aber dazu muss ich sagen, dass ich Mathematik seit der Schulzeit nicht mag. War immer der blanke Horror! 
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Mathematiker
      
Beiträge: 2622
Erhaltene Danke: 1448
Win 7, 8.1, 10
Delphi 5, 7, 10.1
|
Verfasst: So 08.06.14 10:47
Hallo,
galagher hat folgendes geschrieben : | Aber dazu muss ich sagen, dass ich Mathematik seit der Schulzeit nicht mag. War immer der blanke Horror!  |
Richtig!
Augustinus: "Der gute Christ soll sich hüten vor den Mathematikern und all denen, die leere Voraussagen zu machen pflegen, schon gar dann, wenn diese Vorhersagen zutreffen. Es besteht nämlich die Gefahr, dass die Mathematiker mit dem Teufel im Bunde den Geist trüben und in die Bande der Hölle verstricken."
Paul Epstein: "Die Mehrheit bringt der Mathematik Gefühle entgegen, wie sie nach Aristoteles durch die Tragödie geweckt werden sollen, nämlich Mitleid und Furcht. Mitleid mit denen, die sich mit der Mathematik plagen müssen, und Furcht, dass man selbst einmal in diese gefährliche Lage geraten könne."
Robert Niemann: "Mathematik ist nichts für den Wühltisch - Mathematik ist etwas für eine Handvoll Erleuchtete. Und das soll auch so bleiben."
In dem Sinne. Lass dich nicht von der Mathematik ärgern. Als Programmierer kann man darauf sicher verzichten.
Beste Grüße
Mathematiker
|
|
|