Matroids Matheplanet Forum Index
Moderiert von matph
Informatik » Programmieren » Java: Objekte und Methoden (Game of Life)
Druckversion
Druckversion
Autor
Universität/Hochschule J Java: Objekte und Methoden (Game of Life)
curious_mind
Aktiv Letzter Besuch: im letzten Quartal
Dabei seit: 10.11.2012
Mitteilungen: 422
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Themenstart: 2021-01-19


Hallo,
ich lerne gerade Java und sitze an einer Programmieraufgabe, wo ich die Methode "nextGeneration" zu vervollständigen habe. (Der Code drum herum war also gegeben!).

Es geht um das "Game of Life", wo man ein Feld von Zellen erhält, die lebendig oder tot sein können und wo sich die nächste Generation von Zellen (also welche Zelle lebt oder tot ist) nach bestimmten Regeln ergibt.

Ich habe bisher nur imperativ programmiert und habe anscheinend ein ziemliches Verständnisproblem was Objekte und Methoden und ihre Beziehungen zueinander angeht.
Ich komme nicht darauf, wieso mein Programm nicht compilieren will, irgendwie werden meine Methoden nicht akzeptiert/als solche erkannt.

Vielleicht kann mir ja jemand (bitte mit Angabe der Zeilennummer) für Dummys erklären, was ich falsch mache. (P.S. Es kann sein, dass neben dem Methodenaufruf/-definitionsproblem noch zig weitere Fehler drin sind, aber das Methodenproblem ist das Wichtigste erstmal.)
Java
  1. package jfstpackage;
  2.  
  3. public class EA1_4_GameOfLife {
  4. boolean[][] feld = {{false, false, false, false, false},
  5. {false, false, true, false, false},
  6. {false, false, true, false, false},
  7. {false, false, true, false, false},
  8. {false, false, false, false, false}};
  9.  
  10. public static void main(String[] args) {
  11. EA1_4_GameOfLife myGame = new EA1_4_GameOfLife(); // Was passiert hier genau?
  12. for (int i = 0; i < 10; i++) {
  13. myGame.nextGeneration();
  14. myGame.print();
  15. System.out.println();
  16. }
  17. }
  18.  
  19. void print() {
  20. for (int i = 0; i < feld.length; i++) {
  21. for (int j = 0; j < feld[i].length; j++) {
  22. if (feld[i][j] == true)
  23. System.out.print("o ");
  24. else
  25. System.out.print(". ");
  26. }
  27. System.out.println();
  28. }
  29. }
  30.  
  31. void nextGeneration() {
  32. boolean[][] feldkopie = feld;
  33. // TO-DO : So durch das Feld laufen, dass die inneren Zellen nur getestet werden (Rand bleibt tot)
  34. for (int i = 0; i < feldkopie.length; i++) {
  35. for (int j = 0; j < feldkopie[i].length; j++) {
  36. // Fall: Lebende Zelle
  37. if (feldkopie[i][j] == true) {
  38. if (AnzNachbarn(i, j) == 2 || AnzNachbarn(i, j) == 3)
  39. feldkopie[i][j] = true;
  40. else
  41. feldkopie[i][j] = false;
  42. }
  43. // Fall: Tote Zelle
  44. else {
  45. if (AnzNachbarn(i, j) == 3)
  46. feldkopie[i][j] = true;
  47. }
  48. }
  49. } // end Feldtestung
  50.  
  51. // Methode, die die Anzahl der lebenden Nachbarzellen ermittelt
  52. int AnzNachbarn(int Zeile, int Spalte){
  53. int[][] zahlenfeld.InitWerte();
  54. // Methode, die Zahlenfeld mit Einsen und Nullen initialisieren soll
  55. void InitWerte () {
  56. for (int l = 0; l < feldkopie.length; l++)
  57. for (int k = 0; k < feldkopie[l].length; k++) {
  58. if (feldkopie[l][k] == true)
  59. zahlenfeld[l][k] = 1;
  60. else
  61. zahlenfeld[l][k] = 0;
  62. }
  63. }
  64. // Summe der lebenden Nachbarn ermitteln
  65. int SummeNachbarn = zahlenfeld[Zeile - 1, Spalte -1]+zahlenfeld[Zeile - 1, Spalte]
  66. +zahlenfeld[Zeile - 1, Spalte + 1]+
  67. zahlenfeld[Zeile, Spalte - 1]+zahlenfeld[Zeile, Spalte + 1]+
  68. zahlenfeld[Zeile + 1, Spalte - 1]+zahlenfeld[Zeile + 1, Spalte]+zahlenfeld[Zeile + 1, Spalte + 1];
  69. return SummeNachbarn;
  70. } // End AnzNachbarn
  71.  
  72. feld = feldkopie;
  73. } // end nextGeneration
  74. }
  75.  
  76.  



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
DerEinfaeltige
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 11.02.2015
Mitteilungen: 2758
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.1, eingetragen 2021-01-19


1. Du definierst Funktionen innerhalb der Funktionskörper anderer Funktionen (52 + 55). Das ist so weder sinnvoll noch möglich.

2. Willst du ein Array "deep" kopieren (32), so musst du das explizit machen.

3. Du schreibst zwar, dass du den Rand nicht testen willst, tust es dann aber. Damit wirst du Indexfehler produzieren. (34+35)

4. "new" erzeugt eine neue Instanz eines Typs. (11)

5. if(bool==true) ist "doppelt gemoppelt". Einfach if(bool) reicht aus. (22+37+...)



Korrigieren könnte man es beispielsweise so:
Java
    void nextGeneration() {
        boolean[][] feldkopie = new boolean[feld.length][feld[0].length];
        // TO-DO : So durch das Feld laufen, dass die inneren Zellen nur getestet werden (Rand bleibt tot)
        for (int i = 1; i < feldkopie.length-1; i++) { // Rand ignorieren!
            for (int j = 1; j < feldkopie[i].length-1; j++) {// Rand ignorieren!
                // Fall: Lebende Zelle
                if (feld[i][j]) {
                    if (AnzNachbarn(i, j) == 2 || AnzNachbarn(i, j) == 3)
                        feldkopie[i][j] = true;
                    else
                        feldkopie[i][j] = false;
                }
                // Fall: Tote Zelle
                else {
                    if (AnzNachbarn(i, j) == 3)
                        feldkopie[i][j] = true;
                }
            }
        } // end Feldtestung
 
         feld = feldkopie;
    } // end nextGeneration
 
    // Methode, die die Anzahl der lebenden Nachbarzellen ermittelt
    int AnzNachbarn(int Zeile, int Spalte){
        int SummeNachbarn = 0;
        for (int y = Zeile-1; y <= Zeile+1; ++y){
            for (int x = Spalte-1; x <= Spalte+1; ++x){
                if (Spalte==x && Zeile==y) continue; // Feld selbst wird übersprungen
                if (feld[y][x]){
                    ++SummeNachbarn;
                }
            }
        }
        return SummeNachbarn;
    } // End AnzNachbarn
 



-----------------
Why waste time learning when ignorance is instantaneous?
- Bill Watterson -



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: im letzten Quartal
Dabei seit: 10.11.2012
Mitteilungen: 422
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.2, vom Themenstarter, eingetragen 2021-01-19


2021-01-19 13:42 - DerEinfaeltige in Beitrag No. 1 schreibt:
1. Du definierst Funktionen innerhalb der Funktionskörper anderer Funktionen (52 + 55). Das ist so weder sinnvoll noch möglich.

Also Funktionen/Methoden dürfen keine weiteren inneren Funktionen/Methoden enthalten?

Du hast die Initialisierung des Zahlenfelds ja vermieden, aber wenn ich diese Funktion noch wollte, hätte ich diese dann also außerhalb von der Funktion AnzNachbarn implementieren müssen, das hätte dann funktioniert?

2021-01-19 13:42 - DerEinfaeltige in Beitrag No. 1 schreibt:
2. Willst du ein Array "deep" kopieren (32), so musst du das explizit machen.
Was heißt "deep" kopieren?

2021-01-19 13:42 - DerEinfaeltige in Beitrag No. 1 schreibt:
3. Du schreibst zwar, dass du den Rand nicht testen willst, tust es dann aber. Damit wirst du Indexfehler produzieren. (34+35)
Nee, da steht ja "To-Do". Das war mir klar, dass das nicht fertig ist. Ich will erst mal das Problem mit den Methoden verstehen. Mir leuchtet nicht ein, wieso mein Programm so nicht erlaubt ist bzw. wo das Problem ist.

2021-01-19 13:42 - DerEinfaeltige in Beitrag No. 1 schreibt:
4. "new" erzeugt eine neue Instanz eines Typs. (11)
Ja, so steht das auch in jedem Lehrbuch. Und sagen tut mir das nix.


2021-01-19 13:42 - DerEinfaeltige in Beitrag No. 1 schreibt:
5. if(bool==true) ist "doppelt gemoppelt". Einfach if(bool) reicht aus. (22+37+...)
Das ist mir klar. Aber so ist es eindeutiger für mich.

Danke schon mal. :)

Nachtrag:
Du berechnest doch jetzt nur die Anzahl der Nachbarn, die ist aber immer 8. Ich will mit AnzNachbarn die Anzahl der lebenden Nachbarn.




Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
DerEinfaeltige
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 11.02.2015
Mitteilungen: 2758
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.3, eingetragen 2021-01-19


Man kann grundsätzlich auch Hilfsfunktionen innerhalb anderer Methoden/Funktionen definieren.
Das macht hier im Kontext nur keinen Sinn und ist allgemein keine Stärke von Java.

2. boolean[][] kopie = feld;
Dieser Code weist der Referenz kopie die Referenz feld zu.
kopie ist nun quasi identisch mit feld und jede Änderung der Form kopie[x][y] = neuer_wert verändert einfach das Array, auf das bereits feld verwiesen hat.
boolean[][] kopie = new boolean[feld.length][feld[0].length];
erzeugt hingegen ein neuer Feld gleicher Dimension und in Java automatisch mit false initialisiert. (letzteres ist hier egal)
Wenn du feld tatsächlich kopieren willst, musst du explizit zumindest jede Zeile mit arraycopy oder einfach jedes Feld per verschachtelter Schleifen kopieren.

4. EA1_4_GameOfLife myGame = new EA1_4_GameOfLife();
myGame ist eine Referenz auf ein Objekt vom Typ EA1_4_GameOfLife.
new EA1_4_GameOfLife() erzeugt ein neues Objekt dieses Typs, auf das die Referenz myGame nun zeigt und über welche das Objekt nun aufgerufen werden kann.
Vereinfacht:
- myGame ist die Speicheraddresse eines Objektes vom Typ EA1_4_GameOfLife
- new EA1_4_GameOfLife() reserviert den notwendigen Speicher, initialisiert das Objekt und gibt die Speicheraddresse zurück.
- Gibt es keine aktive Referenz mehr, wird der Speicherplatz bei Bedarf wieder automatisch freigegeben (kein delete/free/etc. notwendig)

5. Dieser if(myBool==true) ist schlechter Stil und zu vermeiden. Falls dir der Code if(myBool) unklar ist, so solltest du die Variable sinnvoll benennen. Hier konkret würde sich "isAlive" statt "feld" anbieten.
Dann hat man Code der Form if(isAlive[y][x]).
Das ist klar und verständlich zu lesen und viel besser als "falls istAmLeben istgleich wahr" ...


-----------------
Why waste time learning when ignorance is instantaneous?
- Bill Watterson -



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: im letzten Quartal
Dabei seit: 10.11.2012
Mitteilungen: 422
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.4, vom Themenstarter, eingetragen 2021-01-20


Hallo Einfältiger,

danke für deine Erklärungen!

2021-01-19 14:26 - DerEinfaeltige in Beitrag No. 3 schreibt:
Man kann grundsätzlich auch Hilfsfunktionen innerhalb anderer Methoden/Funktionen definieren.
Das macht hier im Kontext nur keinen Sinn und ist allgemein keine Stärke von Java.

Ja, es wird wohl noch etwas dauern, bis ich wirklich durchdringe, was das Objektorientierte Konzept so mit sich bringt und wieso das Eine oder Andere sich bei Java besonders lohnt oder eben nicht.

Trotzdem: Wenn es theoretisch ja geht, eine innere Funktion/Methode zu definieren, wieso will er es bei mir nicht compilieren? Ist meine Definition irgendwie falsch? Habe es auch mit einem private bzw. public davor versucht, vergebens. Kannst du mir zeigen, wie es gegangen wäre?

Zweite Frage: Hätte die Definition anders aussehen müssen, wenn ich die Methode außerhalb AnzNachbarn definiert hätte?

2021-01-19 14:26 - DerEinfaeltige in Beitrag No. 3 schreibt:
2. boolean[][] kopie = feld;
Dieser Code weist der Referenz kopie die Referenz feld zu.
kopie ist nun quasi identisch mit feld und jede Änderung der Form kopie[x][y] = neuer_wert verändert einfach das Array, auf das bereits feld verwiesen hat.

Oha, das war mir überhaupt nicht klar. Danke!

2021-01-19 14:26 - DerEinfaeltige in Beitrag No. 3 schreibt:
4. EA1_4_GameOfLife myGame = new EA1_4_GameOfLife();
myGame ist eine Referenz auf ein Objekt vom Typ EA1_4_GameOfLife.
new EA1_4_GameOfLife() erzeugt ein neues Objekt dieses Typs, auf das die Referenz myGame nun zeigt und über welche das Objekt nun aufgerufen werden kann.
Vereinfacht:
- myGame ist die Speicheraddresse eines Objektes vom Typ EA1_4_GameOfLife
- new EA1_4_GameOfLife() reserviert den notwendigen Speicher, initialisiert das Objekt und gibt die Speicheraddresse zurück.
- Gibt es keine aktive Referenz mehr, wird der Speicherplatz bei Bedarf wieder automatisch freigegeben (kein delete/free/etc. notwendig)

Kann ich mir diese Objekte quasi als Miniprogramme vorstellen? Es muss ja im Prinzip alles in einem Objekt definiert und implementiert werden, also kann man das äußerste Objekt public class XYZ mit der main-Methode ja als Programmgerüst auffassen, oder?

2021-01-19 14:26 - DerEinfaeltige in Beitrag No. 3 schreibt:
5. Dieser if(myBool==true) ist schlechter Stil und zu vermeiden. Falls dir der Code if(myBool) unklar ist, so solltest du die Variable sinnvoll benennen. Hier konkret würde sich "isAlive" statt "feld" anbieten.
Dann hat man Code der Form if(isAlive[y][x]).
Das ist klar und verständlich zu lesen und viel besser als "falls istAmLeben istgleich wahr" ...
Im Prinzip hatte ich ja schon versucht vom true/false wegzukommen und deshalb  ein Zahlenfeld aus Einsen und Nullen erstellen wollen. Um ein "isAlive[x][y]" Vergleich hinzubekommen, hätte ich aber wieder eine weitere Methode boolean isAlive(int x, int y) {...} unterbringen müssen. Der akzeptiert aber meine bereits existierenden Methoden schon nicht...





Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: im letzten Quartal
Dabei seit: 10.11.2012
Mitteilungen: 422
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.5, vom Themenstarter, eingetragen 2021-01-20


Ok, habe jetzt mal die Methoden alle auseinandergezogen, sodass es keine inneren gibt. Ich weiß, dass deine Lösung viel eleganter ist, aber dem Lernzweck halber, will ich meine Umsetzung mit dem Zahlenfeld und den vielen Methoden beibehalten.

Bleibt die Frage, wie ich die hätte noch verschachteln können.
Immerhin compiliert er jetzt und ich kann nachdenken, ob er das tut, was er soll.

Java
  1. public class EA1_4_GameOfLife {
  2. boolean[][] feld = {{false, false, false, false, false},
  3. {false, false, true, false, false},
  4. {false, false, true, false, false},
  5. {false, false, true, false, false},
  6. {false, false, false, false, false}};
  7.  
  8. public static void main(String[] args) {
  9. EA1_4_GameOfLife myGame = new EA1_4_GameOfLife();
  10. for (int i = 0; i < 10; i++) {
  11. myGame.nextGeneration();
  12. myGame.print();
  13. System.out.println();
  14. }
  15. }
  16.  
  17. void print() {
  18. for (int i = 0; i < feld.length; i++) {
  19. for (int j = 0; j < feld[i].length; j++) {
  20. if (feld[i][j] == true)
  21. System.out.print("o ");
  22. else
  23. System.out.print(". ");
  24. }
  25. System.out.println();
  26. }
  27. }
  28.  
  29. void nextGeneration() {
  30. boolean[][] feldkopie = new boolean[feld.length][feld[0].length];
  31. // So durch das Feld laufen, dass die inneren Zellen nur getestet werden (Rand bleibt tot)
  32. for (int i = 1; i < feldkopie.length - 1; i++) {
  33. for (int j = 1; j < feldkopie[i].length - 1; j++) {
  34. // Fall: Lebende Zelle
  35. if (feldkopie[i][j]) {
  36. if (AnzNachbarn(i, j) == 2 || AnzNachbarn(i, j) == 3)
  37. feldkopie[i][j] = true;
  38. else
  39. feldkopie[i][j] = false;
  40. }
  41. // Fall: Tote Zelle
  42. else {
  43. if (AnzNachbarn(i, j) == 3)
  44. feldkopie[i][j] = true;
  45. }
  46. }
  47. }
  48. feld = feldkopie;
  49. } // end nextGeneration
  50.  
  51. // Methode, die die Anzahl der lebenden Nachbarzellen ermittelt
  52. int AnzNachbarn(int Zeile, int Spalte) {
  53. int[][] Zahlenwerte = new int[feld.length][feld[0].length];
  54. InitWerte(Zahlenwerte);
  55.  
  56. // Summe der lebenden Nachbarn ermitteln
  57. int SummeNachbarn = 0;
  58. for (int x = Zeile-1; x <= Zeile+1; x++)
  59. for (int y = Spalte-1; y<=Spalte+1; y++)
  60. SummeNachbarn += Zahlenwerte[x][y];
  61. return SummeNachbarn;
  62. }
  63.  
  64. // Methode, die Zahlenfeld mit Einsen und Nullen initialisieren soll
  65. void InitWerte(int[][] zahlenfeld){
  66. for (int l = 0; l < feld.length; l++)
  67. for (int k = 0; k < feld[l].length; k++) {
  68. if (feld[l][k] == true)
  69. zahlenfeld[l][k] = 1;
  70. else
  71. zahlenfeld[l][k] = 0;
  72. }
  73. } // end InitWerte
  74. } // end public class



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
DerEinfaeltige
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 11.02.2015
Mitteilungen: 2758
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.6, eingetragen 2021-01-20


Sieht doch ganz vernünftig aus.

Ein "Verschachteln" der Methoden macht hier einfach keinen Sinn.

Um innere Funktionen zu definieren musst du in Java außerhalb ein Functional Interface definieren. (Das ist ein Interface oder eine abstrakte Klasse mit exakt einer Methode)

Dieser kannst du dann überall die gewünschte Funktion zuweisen.
Java
public class EA1_4_GameOfLife {
    boolean[][] feld = {{false, false, false, false, false},
            {false, false, true, false, false},
            {false, false, true, false, false},
            {false, false, true, false, false},
            {false, false, false, false, false}};
 
    public static void main(String[] args) {
        EA1_4_GameOfLife myGame = new EA1_4_GameOfLife();
        for (int i = 0; i < 10; i++) {
            myGame.nextGeneration();
            myGame.print();
            System.out.println();
        }
    }
 
    void print() {
        for (int i = 0; i < feld.length; i++) {
            for (int j = 0; j < feld[i].length; j++) {
                if (feld[i][j] == true)
                    System.out.print("o ");
                else
                    System.out.print(". ");
            }
            System.out.println();
        }
    }
 
    interface Funktion <S,T>{
        T anwenden(S x, S y);
    }
 
    void nextGeneration() {
        boolean[][] feldkopie = new boolean[feld.length][feld[0].length];
 
        Funktion<Integer,int[][]> InitWerte = (Zeilen, Spalten) -> {
            int[][] zahlenfeld = new int[Zeilen][Spalten];
            for (int l = 0; l < feld.length; l++)
                for (int k = 0; k < feld[l].length; k++) {
                    if (feld[l][k] == true)
                        zahlenfeld[l][k] = 1;
                    else
                        zahlenfeld[l][k] = 0;
                }
            return zahlenfeld;
        };
 
        Funktion<Integer,Integer> AnzNachbarn = (Zeile, Spalte) ->{
            int[][] Zahlenwerte = InitWerte.anwenden(feld.length,feld[0].length);
            // Summe der lebenden Nachbarn ermitteln
            int SummeNachbarn = 0;
            for (int x = Zeile-1; x <= Zeile+1; x++)
                for (int y = Spalte-1; y<=Spalte+1; y++)
                    SummeNachbarn += Zahlenwerte[x][y];
            return SummeNachbarn;
        };
 
        // So durch das Feld laufen, dass die inneren Zellen nur getestet werden (Rand bleibt tot)
        for (int i = 1; i < feldkopie.length - 1; i++) {
            for (int j = 1; j < feldkopie[i].length - 1; j++) {
                // Fall: Lebende Zelle
                if (feldkopie[i][j]) {
                    if (AnzNachbarn.anwenden(i, j) == 2 || AnzNachbarn.anwenden(i, j) == 3)
                        feldkopie[i][j] = true;
                    else
                        feldkopie[i][j] = false;
                }
                // Fall: Tote Zelle
                else {
                    if (AnzNachbarn.anwenden(i, j) == 3)
                        feldkopie[i][j] = true;
                }
            }
        }
        feld = feldkopie;
    } // end nextGeneration
 
} // end public class
 



-----------------
Why waste time learning when ignorance is instantaneous?
- Bill Watterson -



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: im letzten Quartal
Dabei seit: 10.11.2012
Mitteilungen: 422
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.7, vom Themenstarter, eingetragen 2021-01-21


Alles klar, vielen Dank! :)



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind hat die Antworten auf ihre/seine Frage gesehen.
curious_mind hat selbst das Ok-Häkchen gesetzt.
Neues Thema [Neues Thema]  Druckversion [Druckversion]

 


Wechsel in ein anderes Forum:
 Suchen    
 
All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest © 2001-2021 by Matroids Matheplanet
This web site was originally made with PHP-Nuke, a former web portal system written in PHP that seems no longer to be maintained nor supported. PHP-Nuke is Free Software released under the GNU/GPL license.
Ich distanziere mich von rechtswidrigen oder anstößigen Inhalten, die sich trotz aufmerksamer Prüfung hinter hier verwendeten Links verbergen mögen.
Lesen Sie die Nutzungsbedingungen, die Distanzierung, die Datenschutzerklärung und das Impressum.
[Seitenanfang]