Conway's Game Of Life



  • Guten Morgen,

    zur Zeit programmiere ich aus Spaß an der Freude Conway's Game Of Life in C#.
    Momentan hab ich ein Logikproblem, was das Feld und die Zellen angeht. Mein Field hat ein Array von all ihren Zellen, die auf dem Feld liegen. Jede Cell hat dabei auch ein Array von Zellen und zwar für ihre Nachbarn. Das heißt jede Cell kennt ihre Nachbarn. Aber damit die Zelle weiß, welche ihre Nachbarn sind, brauch sie dafür Informationen von dem Field.
    Dabei gäbe es jetzt die Möglichkeit, dass jedes Cell-Objekt eine Referenz auf Field hat, was ich persönlich ziemlich hässlig fände.
    Hier mal ein Teil meines Codes für bessere Verständnis:

    public class Field
    {
        public Cell[] Cells { get; private set; }
        //...
    }
    
    public class Cell
    {
        private Cell[] _neighbours;
        //Lazy-Array
        public Cell[] Neighbours 
        {
            get
            {
                if(this._neighbours == null)
                    this._neighbours = this.GetNeighbours();
                return this._neighbours;
            }
            private set
            {
                this._neighbours = value;
            }
        }
        private Cell[] GetNeighbours()
        {
            /*
                Hier ist der kritische Punkt.
                Damit die Zelle von ihren Nachbarn weiß, muss ich Zugriff
                auf das Feld, oder zumindest auf das Array der Feldklasse haben.
                Da mein Neighbour-Array Lazy ist, kann ich auch nicht einfach aus
                der Feld-Klasse das Array der Zellen mitgeben.
                D.h., wenn Neighbours abgerufen wird und es ist == null,
                werden erst dann die Nachbarn ermittelt. GetNeighbours() ruft sich
                also irgendwann selbst auf.
            */
        }
    }
    

    Daher meine Frage, wie man das am besten lösen könnte, ohne das jede Zelle eine Referenz auf das Feld hat, oder auch kein Feldobjekt an die Methode mit übergebe. Ich bräuchte also eine Lösung, bei der solch eine Abhängigkeit beider Seiten nicht entsteht.

    Mit freundlichen Grüßen



  • Warum verwendest du nicht einfach ein 2D Array aus bool für dein Feld!?



  • Das hatte ich anfangs überlegt. Ich finde aber, dass es dann ein wenig kompliziert wird, wenn ich die Nachbarn herausfinden will. Mein Feld ist wie das bei einem Snake Spiel. Wenn eine Zelle ganz links ist, soll die Zelle ganz rechts der Nachbar sein. Und wenn ich für eine Zelle eine eigene Klasse habe, kann ich später besser auf die Nachbarn zugreifen, bzw. zählen, wieviele Nachbarn eine Zelle hat, statt mit Methoden in der Feldklasse. Außerdem bleibe ich dynamisch, wenn ich später meine Zellen in der Funktionalität erweitern möchte. Daher finde ich es persönlich etwas unschön, für eine Zelle keine eigene Klasse anzulegen.



  • Schonmal was von Modulo gehört? 😉

    Was für erweiterte Funktionalität stellst du dir denn für deine Zellen so vor, bzw. worin genau siehst du den Vorteil, die Zellen als Objekte eines eigenen Typs zu halten, die ihre Nachbarn kennen? Die Intelligenz steckt bei Conway's Life ja nicht in den Zellen, sondern in dem Ding das mit den Zellen arbeitet...



  • Das ist wohl ein Argument. Also wird hier keine OO-Regel gebrochen, wenn ich der Zelle keine eigene Klasse witme? Dann mach ich es anders. Worauf willst du aber mit dem Mudolo-Operator hinaus? Ich würde, um die Nachbarn zu ermitteln, wohl anders vorgehen.



  • Modulo ist genau was du brauchst, um den wrap-around am Rand zu erreichen...



  • Ich gehe in der Annahme das du hiervon redest: http://en.wikipedia.org/wiki/Modular_arithmetic
    Muss ich dann die Zellenposition % Feldlänge rechnen?
    Ich kenne mich auf dem Gebiet leider noch nicht so gut aus, deswegen fange ich mit solchen kleinen Sachen an.



  • FreakY<3Cpp schrieb:

    Muss ich dann die Zellenposition % Feldlänge rechnen?

    bingo 😉



  • Okay, so ganz verstehe ich aber noch nicht, wie ich das anwenden muss.
    Wenn meine Zelle die Position 0 hat und somit ganz links ist, ich als Nachbar dann die Zelle ganz rechts haben will, mit der Position 79 (Feldlänge = 80), gibt 0 % 79 = 0.
    Kann ich da nicht einfach etwas in dieser Art machen

    if(cell == cells.First())
    {
        left_neighbour = cells.Last();
    }
    


  • Du verwendest Modulo um deine Indizes im Bereich des Feldes zu halten. Wenn du den linken Nachbarn willst, musst du 1 abziehen bzw. die Feldbreite + 1 addieren.



  • Ah okay, verstanden. Danke für deine Hilfe.



  • Ich hab auch ein Spiel des Lebens (in C++) programmiert und das mit dem am einen Rand verschwinden und am anderen wieder auftauchen so gelöst:

    ...
    if(x < 0)x = Spielfeld_x + x;
    else if(x >= Spielfeld_x) x -= Spielfeld_x;
    if(y < 0)y = Spielfeld_y + y; 
    else if(y >= Spielfeld_y) y -= Spielfeld_y;
    ...
    

    ich hoffe ich konnte dir helfen.

    Mfg Daniel



  • dot schrieb:

    Warum verwendest du nicht einfach ein 2D Array aus bool für dein Feld!?

    Das würde ich auch machen.
    Und ich würde mir jedes modulo oder if für den Rand sparen mit dem Trick mit dem unsichtbaren Rand.
    Hoffe, das klappt, ich habe es noch nicht gemacht.

    Nehmen wir mal einen Gleiter in einem 3x3-Feld.

    +*+
    ++*
    ***
    

    Ich mache ein 5x5-Feld. Also rundherum einen Rand

    +++++
    ++*++
    +++*+
    +***+
    +++++
    

    Das ist nicht teuer. Aus einem 1000*1000-Feld würde nur ein 1002*1002-Feld werden, nur ein halbes Prozent Speicherverschenkung.
    Vor jedem Life-Lauf kopiere ich einfach den rechten sichtbaren Rand in den linken unsichtbaren Rand, den linken sichbaren Rand in den rechten unsichtbaren Rand, unten und oben auch.

    +***+
    ++*++
    *++*+
    *****
    ++*++
    

    Das kostet auch nicht lange Zeit, beim 1000*1000-Feld bloß 4000 Kopien, schon wieder nur ein halbes Prozent.

    Und dann kann ich im sichtbaren Ausschnitt zählen, ohne mich um den Rand zu kümmern.


Log in to reply