Game of Life. Strukturen funktionieren nicht

Hi,
ich bin gerade dabei Game of Life zu programmieren.
Für die die es nicht kennen:

Es sieht auch eigentlich ganz gut aus, aber es funktioniert leider doch nicht zu 100%.
Wie ihr auf der Wiki Seite sehen könnt gibt es im Game of Life einige Strukturen, die sich immer wieder wiederholen. Solche wollte ich auch bei mir einfügen, allerdings
stimmt bei mir wohl irgendwas nicht. Anstatt dieser Figuren bekomme ich (pro Figur), nur ein Quadrat (2*2 Zellen). Obwohl es 3 unterschiedliche Zellen sind bekomme ich immer nur das Quadrat.

Ich habe den Code so gut es ging kommentiert, ich hoffe ihr könnt mir helfen. :wink:

Der Fehler kann eigentlich nur in diesem Codeteil stecken, falls ihr dennoch mehr wollt, oder ich mich irre poste ich gerne auch den Rest. :wink:

boolean b[][] = cells;
			/*
			 * b soll dafür sorgen dass das update der einen Zelle keinen Einfluss auf das der nächsten Zelle
			 * hat. Alle Zellen sollen sich ja am Zustand der gleichen Generation orientieren, was aber nicht funktioniert
			 * wenn die eine Hälfte schon geupdatet ist. Ich denke hier steckt irgendwo der Fehler, aber wo?
			 */
			
			//geht durch das gesame array außer randzellen
			for(int i = 1; i < b.length-1; i++) {
				for(int k = 1; k < b[0].length-1; k++) {
						int aliveNeighbours = 0;
						
						//untersucht die nachbarn
					for(int x = -1; x < 2; x++) {
						for(int y = -1; y < 2; y++) {
							if(cells[i+x][k+y]) {
								aliveNeighbours++;
							}
						}
					}
					
					//da beim untersuchen der Nachbarn auch die eigene Zelle untersucht wird
					//muss sie abgezogen werden falls sie true war
					if(cells**[k]) {
						aliveNeighbours -= 1;
					}
					
					//Regeln
					if (aliveNeighbours<2 || aliveNeighbours > 3) {
						b**[k] = false;
					} else {
						if(aliveNeighbours==3){
							b**[k]=true;
						}
					}
					
					
				}
			}
			
			cells = b;
			
			gui.repaintScreen();

gut, das ist nicht weiter schwer (edit: einen von anscheinend mehreren Fehlern zu finden)

die Regeln lauten:

Lebende Zellen mit weniger als zwei lebenden Nachbarn sterben in der Folgegeneration an Einsamkeit.
Eine lebende Zelle mit zwei oder drei lebenden Nachbarn bleibt in der Folgegeneration lebend.
Lebende Zellen mit mehr als drei lebenden Nachbarn sterben in der Folgegeneration an Überbevölkerung.

dein Code dazu

if (aliveNeighbours<2 || aliveNeighbours > 3) {
  b**[k] = false;
} else {
  if(aliveNeighbours==3){
    b**[k]=true;
  }
}

setzt dies nicht um, fertig

weiteres bitte nochmal selber überlegen :wink:
vielleicht auch diesen Code herausnehmen, eine Schleife mit aliveNeighbours von 0-9 dazu laufen lassen und zu jeder Zahl ausgeben lassen, was die Entscheidung ist

Was genau funktioniert denn nicht?
Ich kenne das Teil nicht, aber vielleicht kann ich ja doch helfen :slight_smile:

Ein möglicher Fehler:
Wenn du ein zweidimensionales Array einfach einem anderen zuweist, erstellst du keine Kopie, sondern übergibst ein Pointer.
Also wenn du was in b änderst, änderst du es auch in cells sofort.

Müsstest dir so etwas in der Art schreiben.

  boolean[][] copy = new boolean[original.length][original[0].length];
  for (int i = 0; i < copy.length; i++) {
    for (int j = 0; j < copy[0].length; j++) {
      copy**[j] = original**[j];
    }
  }
  return copy;
}

und dann halt ganz am Anfang boolean[][]b = this.getCopy(cells);

@SlaterB Warum stimmt das nicht? Ich sehe da ehrlich gesagt keinen Fehler. Eine weitere Regel ist noch “eine tote Zelle mit genau 3 lebenden Nachbarn wird in der nächsten Generation neu geboren”.
@Apo Achso, ja ich denke das wird der Fehler sein. Hab es jetzt so gemacht, allerdings wird jetzt nicht mehr repaintet. Das Array in der Gui wo es gezeichnet wird scheint sich nicht mitzuändern, aber warum? Am Ende sage ich ja
einfach wieder cells = b. Oh, gerade nochmal was getestet, und es funktioniert jetzt. Ich lasse es trotzdem mal stehen, verstehen tu ich es nämlich trotzdem nicht.
Ich habe jetzt einfach die Änderungen direkt am Original gemacht, und die Nachbarn in der Kopie gezählt. Sollte doch eigentlich keinen Unterschied machen oder?

[QUOTE=Bene]
Ich habe jetzt einfach die Änderungen direkt am Original gemacht, und die Nachbarn in der Kopie gezählt. Sollte doch eigentlich keinen Unterschied machen oder?[/QUOTE]
richtig

Ich lasse es trotzdem mal stehen, verstehen tu ich es nämlich trotzdem nicht.

wie passt das zu „ja ich denke das wird der Fehler sein“ und deinem Umdreh-Versuch?

wenn du in eine Kopie schreibst ist am Ende wichtig, dass die GUI diese Kopie erhält,
Variablenzuweisungen reichen nicht unbedingt, je nachdem ob cells dort ein Instanzattribut ist oder nur eine lokale Variable einer Methode ohne Auswirkungen


@SlaterB Warum stimmt das nicht? Ich sehe da ehrlich gesagt keinen Fehler.

dann wird es wohl so sein dass da auch keiner ist :wink:
die weitere Regel hatte ich nicht direkt bedacht und das else als den 3er-Fall von 2+3 gesehen, ich wollte auf

if (aliveNeighbours<2 || aliveNeighbours > 3) {
  b**[k] = false;
} else {
  if(aliveNeighbours==3 oder 2){
    b**[k]=true;
  }
}

bzw. dann viel schöner

  b**[k] = aliveNeighbours == 2 || aliveNeighbours == 3;

hinaus,
aber die Voraussetzung ob Zelle lebend oder tot hatte ich nicht berücksichtigt, verzockt

  b**[k] = (b**[k] && aliveNeighbours == 2) || aliveNeighbours == 3;

wäre vielleicht noch eine korrekte Zeile wenn ich alles nun recht interpretiere, aber man muss es ja nicht unnötig kompliziert machen

Der Gui übergebe ich am Anfang im Konstruktor cells.
Wenn ich jetzt die Änderungen direkt an cells mache sind diese Änderungen auch in der Gui enthalten. Wenn ich aber die Kopie verändere und am Ende cells = kopie einsetze bleibt cells in der Gui im Anfangszustand.

Deine Lösung funktioniert, habe es mal so übernommen. Danke :wink:

was in der Variablen cells steht, interessiert die GUI eben nicht unbedingt,
sie hat den Inhalt von cells bekommen, nicht die cells-Variable

Aber ich verstehe halt nicht warum es dann funktioniert wenn ich die Änderungen direkt vornehme. Mal als konkretes Beispiel damit wir nicht aneinander vorbeireden:

cells**[k] = true;

wird auch in der Gui übernommen

b**[k] = true;
cells = b;

wird nicht übernommen.

es kommt auf dem Weg an

Object a = new Object();
Object b = a;
a.aenderung();

-> b enthält dasselbe Objekt wie a, Änderung in a sieht auch b

Object a = new Object();
Object b = a;
Object c = new Object();
c.aenderung();
a = c;
a.aenderung();

wen interessiert was in Variable a steht? b hat das ursprüngliche erste Objekt übernommen,
das Objekt, nicht die Variable,
wenn a anderen Inhalt enthält, dann interessiert das b nicht,
erst muss wieder dafür gesorgt werden, dass b das neue zweite Objekt bekommt, dann bemerkt auch b was

so ist es bei dir, die GUI muss das neue Array sehen, welche Funktion die Variable cell hat ist nicht ganz klar,
anscheinend nur eine Mittelposition wie hier a, es wird erst noch an die GUI übergeben (b),

wenn alle nur ein Objekt kennen ist es leicht, dann gibt es nur eins, Änderungen daran sehen alle

Ich muss mir das morgen nochmal genau angucken, denke aber ich hab’s verstanden. Danke :wink: