# Game of Life



## Daniel002 (16. Mai 2009)

Hallo,
ich muss für die Uni ein kleines (in meinen Augen, eher großes) Programm schreiben, es handelt sich hierbei um das Spiel Game of Life, es sollen zwei Klassen geschrieben werden, theoretisch kann ich mir da schon was vorstellen, wie ich rangehen könnte, leider sind meine Java-Kenntnisse einfach viel zu gering und ich schaffe nicht den ersten Einstieg.
Ein wenig praktische Hilfe wäre da wohl ganz gut.

Dies ist keine bitte zur kompletten Lösung, sondern nur eine erste Hilfe, meine Aufgaben möchte ich schon selbst machen 

AUFGABE:

6. Übung
Game of Life
Aufgabe 1
Im Zuge der fortlaufenden Digitalisierung unserer Gesellschaft betrachten wir diese Woche einen weiteren
Klassiker, nämlich Conway’s „Game of Life“.
Bei diesem so genannten zellulären Automaten werden Zellen auf ein n xm-Raster verteilt, die sich nach
bestimmten Regeln vermehren oder sterben.
Lebendige Zellen sterben an Vereinsamung oder Übervölkerung, wenn
• sie weniger als zwei lebendige Nachbarn haben, oder
• sie mehr als vier lebendige Nachbarn haben
Tote Zellen werden bevölkert,
• wenn sie (genau) drei lebendige Nachbarn haben.
Die Berechnung erfolgt dabei automatentypisch schrittweise und gedächtnislos, also wird z.B. nicht miteinbezogen,
wieviele der Nachbarn im nächsten Schritt lebendig wären oder nicht.
Die Aufgabe besteht nun darin, zum einen die einzelnen Zellen und zum anderen das „Gitter“ zu implementieren.
Hierfür brauchen Sie zwei (eigene) Klassen, nämlich Cell und Grid. Außerdem stehen folgende Dateien zur
Verfügung
• Das Interface ICell, welches sie als Muster für die Zellen und nicht verändern sollen,
1
• Das Interface IDisplayable, welches sie als Muster für die Gitter-Klasse verwenden und nicht verändern
sollen,
• Die Klasse Main (gegeben im Quelltext) startet die Applikation (es handelt sich um ein Applet),
• Die Klasse GameOfLifeGUI (gegeben als binäre Datei) beinhaltet den Fensterinhalt und kümmert sich
um die Darstellung,
Hinweis: Sie finden die notwendigen Vorlagen im Stud.IP. Entwickeln Sie entweder im selben Package oder
importieren Sie entsprechend . . .
1.1 (Cell) Schreiben sie eine Klasse Cell, die eine Zelle mit ihren Zuständen (tot oder lebendig) und
den vorgegebenen Funktionen implementiert. Hierzu gehört neben dem Getter isAlive() die Berechnung des
nächsten Schrittes in computeNextState() und die tatsächliche Ausführung in stepToNextState(). Diese
Methoden sind im Interface ICell vorgegeben, welches die Klasse entsprechend implementieren soll.
Entwerfen Sie zudem eine (private) Funktion getNeighbourCount(), die entsprechend die Zahl der lebendigen
Nachbarn zurückgibt (Warum taucht diese Funktion nicht im Interface auf? Warum sollte man diese Funktionalität
in einer Extra-Funktion auslagern? Erklären Sie dies ihrem Übungsleiter).
Zudem brauchen Sie natürlich einen sinnvollen Konstruktor, der die Zelle gültig intialisiert.
Implementieren Sie die Attribute zur Position mit dem Schlüsselwort final.
Es lohnt sich (performancetechnisch), wenn jede Zelle ständig eine Liste ihrer Nachbarn führt. Warum? Mit
welchen Eigenschaften (private/public, static oder nicht und von welchem Typ) führen sie diese Liste? An
welcher Stelle füllen sie die Liste sinnvoll mit Werten? Erklären Sie ihren Ansatz.
1.2 (Grid) Schreiben Sie eine Klasse Grid, welche das Interface IDisplayable implementiert und damit
die Methoden getRows(), getCols(), iterate() und getCellAtPosition(int x, int y). Implementieren
Sie dabei das Spielfeld topologisch als Torus (siehe auch Torus ? Wikipedia).
Schreiben Sie für diese Klasse einen Konstruktor public Grid(), der als so genannter „Chain Constructor“
einen weiteren zu schreibenden Konstruktor public Grid(int rows, int cols) mit Standardwerten aufruft.
In diesem initialisieren sie schließlich die eigentliche Datenstruktur zum positionsbehafteten Speichern der
Zellen und füllen diese zufällig mit lebendigen und toten Zellen.
Hinweis: Verwenden Sie am besten Bibliotheksmethoden der Klasse Random. Finden Sie in der Java API heraus,
welche am geeignetsten ist.
Die Datenstruktur zum Verwalten der Zellen ist als Liste von Listen von Zellen (also List<List<ICell> >) zu
implementieren. Das folgende Bild illustriert diese Hierarchie:
2
1.3 (Starten) Binden Sie am besten das Applet in einem Browser ihrer Wahl ein (Sicherheitseinstellungen
beachten!). Im Internet finden Sie entsprechende Anleitungen.
UPDATE: Im Stud.Ip steht inzwischen eine Applet-geeignetere Variante der Dateien zum Download, die man
direkt im Browser ausprobieren kann!
Die Klasse GameOfLifeGUI bietet Ihnen zwei Setter an:
• setWait(int n) setzt die Zeit, die zwischen Iterationen gewartet wird, der Standardwert ist 100 (Millisekunden)
• setGridStep(int n) regelt die Grobkörnigkeit des Rasters. Bei Werten unter 3 bricht das Programm
mit einem Fehler ab.



Habe alles was benötigt wird hochgeladen:
http://karols-versand-shop.de/Neu/vorlage.zip



Wenn sich jemand die Zeit nehmen könnte wäre ich wirklich sehr sehr dankbar.
Mit freundlichen Grüßen


----------



## Marco13 (16. Mai 2009)

Und... was genau ist die Frage...? ???:L


----------



## getStringfromObj() (17. Mai 2009)

Du musst zuerts beide Klassen erstellen. Dabei das package mit angeben und die Interfaces importieren:

package de.luh.sim.java09.ue06;

import de.luh.sim.java09.ue06.*;

Beide Klassen müssen natürlich ihre Interfaces implementieren. Du kannst die Methoden 
des jeweigen Interface der Klasse schon implementieren und dabei den Rumpf leer lassen. Achtung bei Methoden mit Rückgabewert: Erstmal auskommentieren.
Du solltest dann deinen Konstruktor Grid erstellen:
Fülle deine Matrix (List<List<Cell>>) mit Zellen. Zellen haben als Attribute alive, (position, also zb) int i, int j, (und Nachbarliste, zb) ArrayList<Cell> nblist.
Konstruiere die Zellen in deiner Grid Klasse und gebe ihnen zufällige alive-Werte.
Wenn deine Matrix gefüllt ist, fülle die Nachbarlisten deiner Zellen mit ihren entsprechenden Nachbarn (Achtung Torus!).

Das sollte für den Anfang glaub ich erstmal reichen.

Viel Spaß!


----------



## MathAnna (17. Mai 2009)

Hallo, 
da der Autor des Artikels offenbar nicht antwortet, versuche ich jetzt mal mein Glück, da ich die gleiche Aufgabe zu lösen habe und damit meine Schwierigkeiten habe...
Erste Frage: Mir ist nicht ganz klar, wie jede Zelle ständig eine Liste der Nachbarn führen soll. Muss ich das dann auch im Konstruktor so implementieren?Soll das eine Liste sein, die aus 8 boolean besteht? In meinem Konstruktor gibt es bloß die Zeile und Spalte der Zelle, sprich die Position und den bool, ob die Zelle lebendig oder tot ist.
Zweite Frage: Wie greift man denn auf Elemente von Listen zu, die als List<List<Cell>> gespeichert sind? Bei Arrays und eindimensionalen Listen weiss ich das, aber wie bekomme ich bei den zweidimensionalen den zweiten Index? 

So, ich danke schonmal für alle Antworten und bitte habt Nachsicht, bin im Programmieren wirklich noch ein blutiger Anfänger dafür aber motiviert 
MfG


----------



## Schandro (17. Mai 2009)

> Mir ist nicht ganz klar, wie jede Zelle ständig eine Liste der Nachbarn führen soll. Muss ich das dann auch im Konstruktor so implementieren?Soll das eine Liste sein, die aus 8 boolean besteht?


8 booleans wären sinnlos, da diese sich nicht von selbst "aktualisieren" und man deshalb jede Zelle immer wieder von außen aktualisieren müsste.

In der Liste werden Referenzen auf die bis zu 8 Nachbarzellen gespeichert, d.h. der generic-Typ der Liste ist "Cell"




> Wie greift man denn auf Elemente von Listen zu, die als List<List<Cell>> gespeichert sind? Bei Arrays und eindimensionalen Listen weiss ich das, aber wie bekomme ich bei den zweidimensionalen den zweiten Index?


myList.get(i).get(e)


----------



## MathAnna (17. Mai 2009)

Erstmal Danke!
Verstehe aber trotzdem noch nicht so ganz wie ich das mit den Refernzen in der Liste machen soll...?
Wie gesagt, blutiger Anfänger. Die Liste soll also aus 8 Elementen vom Typ Cell bestehen...


----------



## Schandro (17. Mai 2009)

nachdem du alle Zellen erstellt hast, gehst du alle wiederum durch und weißt jeder einzelnen Cell eine "List"e mit allen Nachbarzellen zu. Dafür brauch "Cell" natürlich eine entsprechende setter-Methode.



> Die Liste soll also aus 8 Elementen vom Typ Cell bestehen...


Nicht umbedingt, die Zellen am Rand haben doch weniger als 8 Nachbarzellen?! Hab mir nicht die GameofLife Anleitung durchgelesen, ist nur geraten. Ansonsten ist die Aussage richtig.


----------



## MathAnna (17. Mai 2009)

Ah, verstehe....Dann werde ich mich jetzt nochmal dransetzen 
Danke nochmal!


----------



## Marco13 (17. Mai 2009)

Es gibt viele, viele, viele Möglichkeiten das zu lösen. Ehrlich gesagt hab' ich mir nicht den kompletten Aufgabentext durchgelesen (ich hoffe, dass das alle gemacht haben, die die Aufgabe lösen sollen, und demnach ihre Fragen auch päzisieren können  )

Dadurch, dass nur das Interface ICell vorgegeben ist, ergeben sich viele Freiheiten. Theoretisch könnte man das ganze Spielfeld als großen boolean[][] array speichern, und jede Zelle weiß nur, wo sie in diesem Array liegt... Bequemer wäre aber ein Array (oder eine Liste) mit den (bis zu) 8 Nachbarn (@Schandro: Auf einem Torus haben alle Zellen 8 Nachbarn).

GROB sowas wie

```
class Cell implements ICell
{
    Cell neighbors[] = new Cell[8];

    public void setNeighbor(int index, Cell neighbor)
    {
        neighbors[index] = neighbor;
    }
....
}
```

Vielleicht wäre es an manchen Stellen auch bequemer, wenn jede Zelle ihre komplette "Umgebung" (also wirklich topologisch) speichern würde - grob sowas wie

```
class Cell implements ICell
{
    Cell neighbors[][] = new Cell[3][3];

    public Cell()
    {
        neighbors[1][1] = this; // In der Mitte ist die Zelle selbst....
    }

    public void setNeighbor(int x, int y, Cell neighbor)
    {
        neighbors[1+x][1+y] = neighbor;
    }
....
}
```
Womit man die Nachbarn "direkt" und ggf. intuitiver setzen könnte

```
cell.setNeighbor(-1, -1, n0); // Nachbar links oben
cell.setNeighbor(-1,  0, n2); // Nachbar links mitte
cell.setNeighbor( 1,  1, n6); // Nachbar rechts unten
..
```
Aber natürlich kann man (egal, wie man es implementiert - auch wenn man nur EINEN 1D-Array nimmt, wie im ersten Beispiel) so eine praktische set-Methode anbieten... Ggf. ist die Methode selbst dann etwas komplizierter, aber die Verwendung halt schön einfach und praktisch...


----------



## Landei (18. Mai 2009)

Für die Zellen am Rand gibt es mehrere Varianten. Eine Lösungsmöglichkeit ist natürlich, dass man die Ränder sozusagen miteinander "verklebt", also der rechte Rand den linken Rand als rechten "Nachbarn" hat, und oben und unten genauso. Dabei entsteht eine Geometrie wie bei einem Torus.


----------



## MathAnna (24. Mai 2009)

So, erst einmal Sorry, dass die Antwort so lange auf sich warten lässt...und natürlich vielen Dank für die vielen Antworten!!

Habe das Problem jetzt so gelöst:

if(neighbours.isEmpty()) {
			neighbours.add(getCellAtPosition(i-1, j-1)); 
			neighbours.add(getCellAtPosition(i, j-1));
			neighbours.add(getCellAtPosition(i+1, j-1));
			neighbours.add(getCellAtPosition(i+1, j));
			neighbours.add(getCellAtPosition(i+1, j+1));
			neighbours.add(getCellAtPosition(i, j+1));
			neighbours.add(getCellAtPosition(i-1, j+1));
			neighbours.add(getCellAtPosition(i-1, j));
		}
neighbours is also eine Liste, die mit den Nachbarn gefüllt wird. 
Die besagte Torustopologie habe ich dann bei der Funktion getCellAtPosition(Zeile, Spalte) implementiert und zwar durch einfache if-Abfragen.

Vielen Dank für eure Hilfe :toll:


----------



## Landei (24. Mai 2009)

MathAnna hat gesagt.:


> Die besagte Torustopologie habe ich dann bei der Funktion getCellAtPosition(Zeile, Spalte) implementiert und zwar durch einfache if-Abfragen.
> 
> Vielen Dank für eure Hilfe :toll:



Solche "Überlauf-Sachen" machen sich am besten mit dem modulo-Operator %


```
Cell getCellAtPosition(int zeile, int spalte) {
  return cellArray[zeile % getBreite()[spalte % getHoehe()];
}
```


----------



## Marco13 (24. Mai 2009)

getCellAtPosition(-1, 0); -> *spratzl*
(Aber ansonsten hast du nicht ganz unrecht)


----------



## Landei (25. Mai 2009)

Marco13 hat gesagt.:


> getCellAtPosition(-1, 0); -> *spratzl*
> (Aber ansonsten hast du nicht ganz unrecht)



Ups, wieder was gelernt. So gehts:

```
Cell getCellAtPosition(int zeile, int spalte) {
  return cellArray[(zeile+getBreite()) % getBreite()[(spalte+getHoehe()) % getHoehe()];
}
```

Warum definieren sie auch % anders als die normale (mathematische) Rest-Funktion? Bescheuert...


----------



## Marco13 (25. Mai 2009)

getCellAtPosition(-1-getBreite(), 0); -> *spratzl*
(Aber ansonsten hast du nicht ganz unrecht)


----------

