# Game of Life



## StarSeven (15. Mrz 2004)

Alloa alle miteinander, ich möchte vielleicht versuchen das wahrscheinlich bekannte Game of Life zu programmieren, ich dachte mir das in etwa so:

```
Game of Life
Zustände:
     -Zelle lebt
     -Zelle tot
Regeln:
     -Zelle kommt ins leben wenn mind. drei ihrer Nachbarzellen leben
     -Zelle lebt wenn mind. zwei ihrer Nachbarzellen leben
     -Zelle stirbt wenn sie weniger als zwei lebende Nachbarn hat

-Rundenbasiert (alles läuft in while(true) ab)
-erstelle GridLayout(y, x);
-Besetze es vollständig mit JButton[x][y]
-lass den Spieler per Button Druck eine Anzahl von z Button am Anfang besetzen
(leben -> blau färben und alle anderen schwarz)
-wurden Anzahl von z gesetzt, setze alle Button Enabled(false)
-In der Schleife:
     -i++ (Anzahl der Runden)
     -teste ob alle Zellen tod (Bg = black) sind
          -Wenn ja dann geh aus Schleife sage Spieler alle Zellen tod und gib Anzahl der Runden aus
     -teste ob alle Zellen leben(Bg = blue)
          -wenn ja geh aus Schleife sage Spieler alle Zellen leben und gib Anzahl der Runden aus
     -gehe Button[x][y] nacheinander durch und teste:
          ob Zelle lebt
               wenn ja teste ob zwei Nachbarzellen leben, wenn nein setze Bg dieser Zelle = black
          ob Zelle tod
               wenn ja dann teste ob 3 Nachbarzellen leben, wenn dies zutrifft setze Bg dieser Zelle = blue
```
Wenn jemand da Verbesserungsvorschläge hat würde ich mich freuen wenn er/sie sie mir sagt.
Aber nun zu meiner eigentlichen Frage, als Nachbarn, zählen da nur die direkten Nachbarn oder auch die schräg unter-über-rechts-links liegen, also nur mit den ecken einander berühren?


----------



## Beni (15. Mrz 2004)

> -erstelle GridLayout(y, x);
> -Besetze es vollständig mit JButton[x][y]



Diesen Teil würde ich anders lösen. Die JButtons benötigen _extrem _viel Ressourcen (wenn sie in Massen auftreten). Und dieses Game läuft ja nicht auf einem 5 * 5 grossen Gitter...

Schreib dir doch einen eigenen Zeichenalgorithmus. Ein paar graue Linien sind nicht schwierig, und mit einem MouseListener kannst du ein Button-ähnliches Verhalten der einzelnen Felder proggen.


----------



## StarSeven (15. Mrz 2004)

So ich wollte jetzt erstmal das versuchen in so etwa hinzubekommen wie ich glaubte wie du es meintest, allerdings habe ich jetzt Probleme das umzusetzen, denn ich habe nun das Gitternetz gezeichnet, einen MouseListener hinzugefügt, hole mir die x und y Koordinaten des Klicks, weiss aber nicht wie ich nun das Quadrat zeichnen soll, denn ich habe ja schon eine paint()-Methode in View.
Ausserdem ist es das Problem mit dem JFrame, es hat ja die Titelleiste, und dadurch ist das Gitternetz ja nicht komplett zu sehen, ich wollte es zuerst mit einem JWindow machen, aber das hat nicht ganz geklappt. Wie kann ich das alles machen?
Hier mein Code:

```
public class Game {

	View myView = new View();
	Model myModel = new Model();
	public static void main(String args[]) {
		Game myGame = new Game();
		myGame.Controller();
	}
	public void Controller() {
		myView.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent evt) {
				if (evt.getKeyCode() == evt.VK_ESCAPE) {
					System.exit(0);
				}
			}
		});
		myView.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent evt) {
				if (evt.getClickCount() > 1) {
					myModel.x = evt.getX();
					myModel.y = evt.getY();
					//Wie soll ich nun das Rechteck malen?
				}
			}
		});
		myView.view();
	}
}
```


```
public class View extends JFrame {

	public View() {
		super("Gitternetzprobe");
		setSize(800, 600);
		setLocation(0, 0);
	}
	public void view() {
		show();
		repaint();
	}
	public void paint(Graphics g) {
		//senkrechte Linien zeichnen
		for (int x = 0; x != 800;) {
			x = x + 10;
			g.drawLine(x, 0, x, 600);
		}
		//horizontale Linien zeichnen
		for (int y = 0; y != 600;) {
			y = y + 10;
			g.drawLine(0, y, 800, y);
		}
	}
}
```


```
public class Model {
	int x, y;

}
```
Mit dem Model-View-Controller habe ich  es glaube ich noch nicht ganz verstanden, also nicht meckern .


----------



## Beni (15. Mrz 2004)

Nimm ein JPanel, und überschreibe dessen _paintComponent_-Methode für das Gitter. Dann bist du alle Probleme los :wink:


----------



## StarSeven (16. Mrz 2004)

Also ich habe das mit dem paintComponent nicht wirklich hinbekommen.
Trotzdem habe ich noch ein wenig rumprobiert und habe es schliesslich auch geschafft (vielleicht meintest du es auch so wie ich es jetzt gemacht habe).
Ich habe nun ein Array (Point) erschaffen welches die Knotenpunkte des Gitternetzes enthält und womit ich die Koordinaten bekomme mit welchen ich die Rechtecke zeichne.
Nun überlege ich noch ein Array (boolean) zu erstellen welches nicht die Koordinaten enthält aber anzeigt ob eine Zelle lebt (true) oder tot ist (false).
Geht das so oder würdet ihr es anders machen.
Ich weiss nicht ob ihr es überlesen habt, aber wisst ihr vielleicht wer alles als Nachbar zählt:

```
öoö
o+o
öoö
```
Vom + sind also die o's alle Nachbaren, aber sind die ö's auch Nachbarn?


----------



## Beni (16. Mrz 2004)

Schon mal an einen 2dimensionalen boolean-Array gedacht? Die Indices sind gleich die Koordinaten.


```
boolean[][] array = new boolean[xSize][ySize]
```


----------



## StarSeven (16. Mrz 2004)

Beni hat gesagt.:
			
		

> Schon mal an einen 2dimensionalen boolean-Array gedacht?


Tschuldigung wenn ich mich falsch ausgedrückt habe, aber ich meinte ein zweidimensionales boolean array, mein derzeitiges Point-Array ist auch zweidimensional


----------



## Beni (16. Mrz 2004)

Ach so  :idea:


----------



## schalentier (17. Mrz 2004)

also ich rate von mehreren arrays ab. besser ist es sicherlich so:

```
package gol;

/**
 * Created by IntelliJ IDEA. User: schalentier Date: 17.03.2004 Time: 11:54:02
 */
public class GOLCell
{
    boolean alife;
    public GOLCell( boolean alife )
    {
        this.alife = alife;
    }
    public boolean isAlife()
    {
        return alife;
    }
    public void setAlife( boolean alife )
    {
        this.alife = alife;
    }
}
```


```
package gol;

/**
 * Created by IntelliJ IDEA. User: schalentier Date: 17.03.2004 Time: 11:53:27
 */
public class GOLModel
{
    /**
     * groesse der spielfelds
     */
    int sizeX, sizeY;
    /**
     * die welt als 2d array
     */
    private GOLCell[][] cells;
    /**
     * die welt zum zwischenspeichern
     */
    private GOLCell[][] newCells;

    /**
     * konstruktor, erzeugt spielfeld
     * @param sizeX
     * @param sizeY
     */
    public GOLModel( int sizeX, int sizeY )
    {
        this.sizeX = sizeX;
        this.sizeY = sizeY;
        init();
    }

    /**
     * erzeugt 2 2d-arrays fuer die welt. einer mit dem aktuellen zustand und einer fuer die neue welt
     */
    protected void init()
    {
        cells = new GOLCell[sizeX][sizeY];
        newCells = new GOLCell[sizeX][sizeY];
    }

    /**
     * liefert eine zelle zurueck. benutzt wrap um gueltige koordinaten zu erzeugen
     * @param x
     * @param y
     * @return
     */
    public GOLCell getCell( int x, int y)
    {
        int xx = wrap( x, sizeX );
        int yy = wrap( y, sizeY );
        return cells[xx][yy];
    }

    /**
     * zaehlt die nachbarn einer zelle und liefert die anzahl zurueck
     * @param x
     * @param y
     * @return
     */
    protected int countNeighbours( int x, int y )
    {
        int number = 0;
        for( int i=x-1;i<=x+1; )
        {
            for( int j=y-1;i<=y+1; )
            {
                if( i==x && j==y ) continue;
                if( getCell(i,j).isAlife() ) number++;
            }
        }
        return number;
    }

    /**
     * testet eine koordinate auf ihre gueltigkeit. falls sie ausserhalb des bereiches liegt
     * wird sie passend gemacht. (wrapping)
     * @param i koordinate
     * @param size maximale groesse
     * @return
     */
    protected int wrap( int i, int size )
    {
        if( i<0 ) i+=size;
        return i%size;
    }


    /**
     * fuehrt einen spielschritt durch. nutzt classify(neighbours)
     */
    public void tick()
    {
        for( int x = 0; x < sizeX; x++ )
        {
             for( int y = 0; y < sizeY; y++ )
             {
                 int neighbours = countNeighbours( x,y );
                 newCells[x][y] = classify( neighbours ); // hier logik einfuegen
             }
        }
        // buffer tauschen
        GOLCell temp[][] = cells;
        cells = newCells;
        newCells = temp;

        // welt hat sich geaendert, gui muss neu gezeichnet werden
        // hier alle listener informieren
        //notifyGUI();
    }

    /**
     * die spielregeln. in abhaengigkeit der anzahl der nachbarn wird eine lebende/tote zelle zurueckgeliefert.
     * @param neighbours
     * @return
     */
    private GOLCell classify( int neighbours )
    {
        // hier logik
        return new GOLCell(true);
    }
}
```

fehlen noch eigentlichen regeln (sollen moeglicherweise auch einstellbar sein) und die gui. 
keine gewaehr, hab nix getestet...

noch ne info:
ich erzeuge zwei spielfelder (cells, newCells) die nach dem doppelbufferprinzip funktionieren. cells beinhaltet die aktuelle welt. in der methode tick() wird diese durchwandert, und fuer jede zelle die nachbarn berechnet. daraus ergibt sich, ob die zelle stirbt oder weiterlebt. das wird in newCells geschrieben. 
am ende werden beide arrays getauscht.

havefun


----------

