i

Go Home als Programm

Ein Spiel-Objekt

Das Spiel im Codepad zu spielen ist zwar möglich, aber sehr mühsam und macht so nicht viel Spaß. Wir benötigen also ein Objekt, das uns die Steuerung des Spiels erleichtert. Ein Spiel-Objekt muss dazu natürlich die Figuren f1 und f2 kennen und wissen, welches die aktuellen Figuren sind, die gezogen werden sollen. Außerdem sollte gespeichert werden welcher Spieler gerade an der Reihe ist. Der Spieler wird durch seine Figur repräsentiert. Ein Objektdiagramm könnte also so aussehen: Objektdiagramm mit Spiel und Figuren

Aufgabe 1

Analyisiere das Objektdiagramm und beschreibe den aktuellen Spielzustand. (Welcher Spieler ist am Zug? Welche Figuren werden bewegt? In welche Richtung könnte der Spieler die Figuren bewegen?)

Eine Klasse für die Spiele-Logik

Die Beziehungen zwischen den Klassen Spiel und Figur kann und sollte man auch im Klassendiagramm ausdrücken. Man unterscheidet dabei kennt-Beziehungen und hat-Beziehungen. Bei einer kennt-Beziehung kennt ein Objekt ein anderes Objekt, beide sind aber unabhängig voneinander existenzfähig. Bei einer hat-Beziehung ist das besitzende Objekt meist auch für die Erzeugung der anderen Objekte zuständig. Im obigen Fall existieren hat-Beziehungen auf die Figuren f1 und f2, da das Spiel auch für die Erzeugung der Figuren zuständig ist und diese ein Teil des Spiels sind. Es existieren aber auch kennt-Beziehungen, da die aktuellen Spielfiguren ebenfalls bekannt sein müssen, aber nicht noch einmal erzeugt werden. Ob eine Beziehung eine kennt- oder hat-Beziehung ist, ist nicht immer eindeutig.

Man drückt die Beziehungen im Klassendiagramm folgendermaßen aus:

kennt und hat - Beziehung

In beiden Fällen äußert sich die Beziehung darin, dass ein Attribut benötigt wird, um die Referenz auf die anderen Objekte zu speichern.

Um auszudrücken wie diese Attribute benannt sein sollen, kann man die Enden der Beziehungspfeile auch beschriften. Die folgenden Klassendiagramme haben also eine ähnliche Aussagekraft:

kennt und hat mit Beschriftung

bzw.

kennt und hat mit expliziten Attributen

Aufgabe 2 - Beziehungen in Klassendiagrammen

Beschreibe die Unterschiede der drei dargestellten Klassendiagramme und bewerte die Stärken und Schwächen der unterschiedlichen Darstellungen.

Klassendiagramm

Insgesamt ergibt sich damit z.B. dieses Klassendiagramm (kein UML sondern Java-spezifisch):

Klassendiagramm gesamt

Die Figur-Klasse bleibt wie gehabt bestehen.

Die Spiel-Klasse erhält mehrere Referenzattribute für die Spielfiguren. Im Klassendiagramm sind diese durch die Pfeile dargestellt.

Im Konstruktor wird das Spiel initalisiert, also z.B. die Farben festgelegt und die Figuren erzeugt.

Um den aktuellen Zustand des Spiels auszugeben, soll es verschiedene Methoden geben, die z.B. den aktuell ziehenden Spieler, die zu bewegenden Figuren und das Spielfeld ausgeben.

Für den Benutzer am einfachsten ist es, wenn er sich nicht um die Koordinaten kümmern muss, um die Figuren zu bewegen. Deshalb gibt es vier verschiedene Methoden für die Bewegungen nach oben, rechts, unten und links.

Schließlich gibt es noch mehrere Methoden, die für die Steuerung des Spiels zuständig sind:

  • muenzenWerfen: Sorgt dafür, dass zwei zufällige Figuren bestimmt werden, die dann im nächsten Zug bewegt werden müssen.
  • spielIstFertig:Überprüft, ob einer der Spieler auf dem Home-Feld ist.
  • setzeNeuenSpieler:Wechselt den aktuellen Spieler.
  • neuenZugVorbereiten: Erledigt alles, was getan werden sollte, nachdem ein Spieler gezogen hat.

Grundgerüst

Zuerst müssen wir das Grundgerüst für die Klasse Spiel erstellen. Dazu gehört, dass wir die Attribute und den Konstruktor programmieren.

Aufgabe 3 - Grundgerüst implementieren

Erstelle eine neue Klasse Spiel in BlueJ. Implementiere die Attribute der Klasse und den Konstruktor. Im Konstruktor sollen die Figuren mit entsprechenden Farbbezeichnungen und Koordinaten erzeugt werden.

Hilfe
class Spiel
{
    Figur f1;
    ...
    Figur aktuelleFigur1;
    ...

    Spiel()
    {
        f1 = new Figur(...);
        ...
    }
}

druckeGewinner

Damit man das Spiel komfortabel spielen kann, muss natürlich eine übersichtliche Ausgabe des Spielzustands erfolgen. Dies erfolgt in unterschiedlichen Methoden, um flexibler zu sein und den Code übersichtlich zu halten. Wir beginnen mit der Methode druckeGewinner.

Um den Gewinner auszugeben, kann man folgendermaßen vorgehen:

druckeGewinner

Aufgabe 4

Implementiere die Methode druckeGewinner, so dass eine Ausgabe in der Art "Blau hat gewonnen!" oder "Rot hat gewonnen!" erfolgt, wenn es einen Gewinner gibt. Du kannst auch noch den Fall ergänzen, dass beide gleichzeitig auf dem Home-Feld angelangen.

druckeAktuellenSpieler

Die Ausgabe des aktuellen Spielers scheint zunächst sehr leicht.

void druckeAktuellenSpieler() {
        System.out.println("Am Zug ist " + aktuellerSpieler.farbe);
}

Allerdings funktioniert die Methode nicht wie erwartet, wenn der aktuelle Spieler noch nicht festgelegt wurde. Deshalb musst du die folgende Version der Methode verwenden:

void druckeAktuellenSpieler() {
    if(aktuellerSpieler != null) {
        System.out.println("Am Zug ist " + aktuellerSpieler.farbe);
    }
}

Aufgabe 5

Teste beide Versionen der Methode druckeAktuellenSpieler und erkläre den Unterschied. Gehe insbesondere auf die Bedeutung des Schlüsselwortes null ein.

druckeAktuelleFiguren

Ähnlich lässt sich die Anzeige der aktuell zu bewegenden Figuren erledigen:

private void druckeAktuelleFiguren() {
   System.out.println("Bewege " + aktuelleFigur1.farbe + " und " + aktuelleFigur2.farbe);
}

Aufgabe 7

Teste die Methode. Erkläre den Fehler und behebe ihn.

druckeSpielfeld

Schließlich benötigen wir noch eine Übersicht über das Spielfeld in der folgenden Art:

. . . . . 
. . . B . 
R . X . . 
. . . . . 
. . . . . 

Das Struktogramm verdeutlicht die Implementierungsidee:

druckeSpielfeld

Implementieren lässt sich die Methode auf folgende Art:

void druckeSpielfeld() {
    for(int y = 0; y <= 4; y++) {
        for(...) {
            if (x == 2 && y == 2 && !spielIstFertig())
                System.out.print("X ");
            else if (f1.x == x && f1.y == y && f2.x == x && f2.y == y)
                System.out.print( ... );
            else if( ... )
                System.out.print("B ");
            else if( ... )
                System.out.print("R ");
            else
                System.out.print(". ");
        }
        System.out.println();
    }
}

Aufgabe 8

Beschreibe die Funktionsweise der Methode und ergänze die Implementierung an den Stellen, an denen noch Platzhalter stehen.

muenzenWerfen

Bisher haben wir das Grundgerüst der Klasse erzeugt und Methoden geschrieben, um den aktuellen Spielzustand auszugeben. Spielen kann man das Spiel bis jetzt noch nicht. Das soll sich durch Implementierung der nächsten Methoden ändern.

Vor jedem Zug müssen zwei Münzen geworfen werden, um zu bestimmen, welche Figuren bewegt werden sollen, welche Figuren also die aktuelleFigur1 und die aktuelleFigur2 sind. Als Pseudocode könnte man das so formulieren:

Erzeuge zwei zufällige Zahlen zwischen 0 und 1
Wenn die erste Zahl 0 ist, dann ist aktuelleFigur1 f1, sonst f2
Wenn die zweite Zahl 0 ist, dann ist aktuelleFigur2 f1, sonst f2

Aufgabe 9

Implementiere die Methode muenzenWerfen.

nach...Bewegen

Wir benötigen nun noch Methoden, um die per Münzwurf ermittelten Figuren zu bewegen.

Aufgabe 10

Setze die entsprechenden Methoden für alle vier Richtungen um.

void nachObenBewegen() {
    aktuelleFigur1.gehe(0);
    aktuelleFigur2.gehe(0);
}

setzeNeuenSpieler

Die Methode setzeNeuenSpieler hat die Aufgabe den aktuellen Spieler zu tauschen. Dazu wird folgende Methode vorgeschlagen:

private void setzeNeuenSpieler() {
    if(aktuellerSpieler == f1)
        aktuellerSpieler = f2;
    else
        aktuellerSpieler = f1;
}

Aufgabe 11

Du erkennst vielleicht direkt das Problem des obigen Diagramms bei Spielbeginn. Falls nicht, kannst du die Methode wie oben dargestellt umsetzen und die Methode ein paar mal an einem neu erzeugten Spiel ausführen. Beschreibe das Problem und implementiere eine verbesserte Version. (Tipp: Welchen Wert hat aktuellerSpieler zu Beginn des Spiels?)

Spielverlauf automatisieren

Das Spiel ist nun im Prinzip fertig und spielbar. Wenn du möchtest, kannst du ein Spiel (evtl. auch teilweise) spielen. Du wirst merken, dass du im Prinzip immer wieder die gleichen Methoden aufrufst, oft auch in der gleichen Reihenfolge. Um den Komfort zu steigern, solltest du noch ein paar Ergänzungen am Spiel vornehmen.

Aufgabe 12 - spielIstFertig

Ergänze eine Methode, die feststellt, ob das Spiel fertig ist oder nicht. Das Spiel ist fertig, wenn f1 oder f2 gewonnen hat.

Aufgabe 13 - neuenZugVorbereiten

Die erforderlichen Aktionen, um einen neuen Zug vorzubereiten, lassen sich leicht automatisieren.

spiel fertig?
    ja: gebe Gewinner aus
    nein: tausche Spieler
          gebe aktuellen Spieler aus
          münzen werfen, um aktuelle Figuren zu bestimmen
          gebe aktuelle Figuren aus

drucke Spielfeld

Aufgabe 14 - Testen des Spiels

Spiele das Spiel :-)

Optional kannst du noch die nach außen nicht benötigten Methoden durch den Zugriffsmodifikator private "verstecken".

Suche

v
7.1.3.1.3
inf-schule.de/oop/java/beziehungen/gohome/programm
inf-schule.de/7.1.3.1.3
inf-schule.de/@/page/0shUaMO6XdKm63NQ

Rückmeldung geben