# Textbasiertes Spiel



## David Nienhaus (9. Mai 2018)

Hallo, ich bin gerade dabei ein (sehr einfaches) textbasiertes Spiel zu programmieren.
Das ganze ist eine Praktikumsaufgabe, die ich vorbereiten muss. Ich habe einige Fragen bei denen ihr mir hoffentlich weiterhelfen könnt.

Erstmal eine grobe Beschreibung des Spiels:
Die Spielwelt besteht aus Räumen mit Türen, die zu anderen Räumen führen, zwischen denen man mit Befehlen wie go west navigieren kann. Soweit war das ganze bereits vorgegeben. Ich soll das Spiel jetzt erweitern mit Gegenständen, Falltüren, Charaktere und einer Karte.
Ich habe mich zuerst den Gegenständen und Charakteren gewidmet. Mein Code bisher:
https://github.com/DavidnHas/Spiel.git

An folgender Stelle tritt bei mir momentan ein Problem auf:
Die Methode nehmeGegenstand sorgt and der Stelle:
aktuellerSpieler.setzeInventar(gegenstand);
für eine Nullpointerexception
Ich verstehe nicht warum, da eine Zeile weiter
aktuellerRaum.löscheInhalt(gegenstand);
eigentlich der gleiche Aufbau genutzt wird, es hier aber keinen Fehler gibt.

Klasse Spiel:

```
class Spiel
{
    private Parser parser;
    private Raum aktuellerRaum;
    private Spieler aktuellerSpieler;
      
    /**
     * Erzeuge ein Spiel und initialisiere die interne Raumkarte.
     */
    public Spiel()
    {
        raeumeAnlegen();
        parser = new Parser();
    }

    /**
     * Erzeuge alle Räume und verbinde ihre Ausgänge miteinander.
     */
    private void raeumeAnlegen()
    {
        Raum r1, r2, r3, r4, r5 ,r6, r7, r8;
        Inventar i1, i2, i3, i4, i5, i6 ,i7, i8;
      
        i1 = new Inventar();
        i2 = new Inventar();
        i3 = new Inventar();
        i4 = new Inventar();
        i5 = new Inventar();
        i6 = new Inventar();
        i7 = new Inventar();
        i8 = new Inventar();
      
        r1 = new Raum("am Ausgang", i1);
        r2 = new Raum("in einem Kik", i2);
        r3 = new Raum("in einem REWE" ,i3);
        r4 = new Raum("bei den Toiletten",i4);
        r5 = new Raum("in einem McDonalds",i5);
        r6 = new Raum("in einer Abstellkammer",i6);
        r7 = new Raum("in einem K&K",i7 );
        r8 = new Raum("in einem Lagerraum",i8 );
      
      
        i2.befülleInventar("Tshirt");
      
        i3.befülleInventar("Apfel");
      
        i8.befülleInventar("Bier");
      
        r1.setzeAusgang("south", r3);

        r2.setzeAusgang("south", r4);

        r3.setzeAusgang("north", r1);
        r3.setzeAusgang("up" , r7);

        r4.setzeAusgang("north", r2);
        r4.setzeAusgang("up", r8);
      
        r5.setzeAusgang("south", r7);
        r5.setzeAusgang("east", r6);
      
        r6.setzeAusgang("west" , r5);
        r6.setzeAusgang("south", r8);

        r7.setzeAusgang("down", r3);
        r7.setzeAusgang("east", r8);
        r7.setzeAusgang("north", r5);
      
        r8.setzeAusgang("down", r4);
        r8.setzeAusgang("west", r7);
        r8.setzeAusgang("north", r6);

        aktuellerRaum = r8;
    }

  
    private void spielerAnlegen()
    {
       Spieler s1;
       Inventar iSpieler;
     
       iSpieler = new Inventar();
       s1 = new Spieler("Spieler", iSpieler );
     
       aktuellerSpieler = s1;
    }
  
    /**
     * Die Hauptmethode zum Spielen. Läuft bis zum Ende des Spiels
     * in einer Schleife.
     */
    public void spielen()
    {          
        willkommenstextAusgeben();

        // Die Hauptschleife. Hier lesen wir wiederholt Befehle ein
        // und führen sie aus, bis das Spiel beendet wird.
              
        boolean beendet = false;
        while (! beendet) {
            Befehl befehl = parser.liefereBefehl();
            beendet = verarbeiteBefehl(befehl);
        }
        System.out.println("Auf Wiedersehen!");
    }

    /**
     * Einen Begrüßungstext für den Spieler ausgeben.
     */
    private void willkommenstextAusgeben()
    {
        System.out.println();
        System.out.println("Sie haben sich in einem Einkaufszentrum verlaufen. ");
        System.out.println("Finden sie einen Weg hinaus. Viel Glück!");
        System.out.println("Tippen sie 'help', wenn Sie Hilfe brauchen.");
        System.out.println();
        System.out.println(aktuellerRaum.gibLangeBeschreibung());
    }

    /**
     * Verarbeite einen gegebenen Befehl (führe ihn aus).
     * Wenn der Befehl das Spiel beendet, wird 'true' zurückgeliefert,
     * andernfalls 'false'.
     */
    private boolean verarbeiteBefehl(Befehl befehl)
    {
        boolean moechteBeenden = false;

        if(befehl.istUnbekannt()) {
            System.out.println("Ich weiß nicht, was Sie meinen...");
            return false;
        }

        String befehlswort = befehl.gibBefehlswort();
        if (befehlswort.equals("help"))
            hilfstextAusgeben();
        else if (befehlswort.equals("go"))
            wechsleRaum(befehl);
        else if (befehlswort.equals("inspect"))
            inspiziereRaum(befehl);
        else if (befehlswort.equals("take"))
            nehmeGegenstand(befehl);
        else if (befehlswort.equals("quit")) {
            moechteBeenden = beenden(befehl);
        }
        return moechteBeenden;
    }

    // Implementierung der Benutzerbefehle:

    private void hilfstextAusgeben()
    {
        System.out.println();
        System.out.println("Ihnen stehen folgende Befehle zur Verfügung:");
        parser.zeigeBefehle();
    }

    /**
     * Versuche, den Raum zu wechseln. Wenn es einen Ausgang gibt,
     * wechsele in den neuen Raum, ansonsten gib eine Fehlermeldung
     * aus.
     */
    private void wechsleRaum(Befehl befehl)
    {
        if(!befehl.hatZweitesWort()) {
            // Gibt es kein zweites Wort, wissen wir nicht, wohin...
            System.out.println("Wohin möchten Sie gehen?");
            return;
        }

        String richtung = befehl.gibZweitesWort();

        // Wir versuchen den Raum zu verlassen.
        Raum naechsterRaum = aktuellerRaum.gibAusgang(richtung);

        if (naechsterRaum == null)
            System.out.println("Dort ist keine Tür!");
        else {
            aktuellerRaum = naechsterRaum;
            System.out.println(aktuellerRaum.gibLangeBeschreibung());
        }
    }
  
    private void nehmeGegenstand(Befehl befehl)
    {
       if(!befehl.hatZweitesWort()) {
            System.out.println("Was möchten Sie nehmen?");
            return;
        }
      
       String gegenstand = befehl.gibZweitesWort();
     
       if (aktuellerRaum.enthältGegenstand(gegenstand))
       {
           aktuellerSpieler.setzeInventar(gegenstand);
           aktuellerRaum.löscheInhalt(gegenstand);
        }
      
       else {
           System.out.println("Dieser Gegenstand existiert nicht");
        }
    }
  
    private void inspiziereRaum(Befehl befehl)
    {
        if(befehl.hatZweitesWort()) {
            System.out.println("Ich verstehe Sie nicht.");
            return;
        }
      
        System.out.println("Sie sehen folgende Gegenstände: "+ aktuellerRaum.gibInhaltAlsString());
    }
  

    /**
     * "quit" wurde eingegeben. Überprüfe den Rest des Befehls,
     * ob das Spiel wirklich beendet werden soll. Liefere 'true',
     * wenn der Befehl das Spiel beendet, 'false' sonst.
     */
    private boolean beenden(Befehl befehl)
    {
        if(befehl.hatZweitesWort()) {
            System.out.println("Was soll beendet werden?");
            return false;
        }
        else
            return true;  // Das Spiel soll beendet werden.
    }
}
```

Klasse Spieler:

```
import java.util.*;
/**
* Beschreiben Sie hier die Klasse Spieler.
*
* @author (Ihr Name)
* @version (eine Versionsnummer oder ein Datum)
*/
public class Spieler
{
    // Instanzvariablen - ersetzen Sie das folgende Beispiel mit Ihren Variablen
    private String name;
    private Inventar inventar;
  
  
    /**
     * Konstruktor für Objekte der Klasse Spieler
     */
    public Spieler(String name, Inventar neuesInventar)
    {
        this.name = name;
        inventar = neuesInventar;
    }

    public void setzeInventar(String bezeichnung)
    {
       inventar.befülleInventar(bezeichnung);
    }
  
    public String gibNamen()
    {
        return name;
    }
  
    public void gibInventarInhalt()
    {
      inventar.inhaltAusgeben();
    }
  
    public void nehmen(Gegenstand bezeichnung)
    {
      
    }
 
    public void abgeben(Gegenstand bezeichnung)
    {
      
    }
  
    public Inventar getInventar(Inventar inventar)
    {
       return inventar;
    }
  
  
}
```

Klasse Inventar:

```
import java.util.*;
public class Inventar
{
   //private int anzahlGegenstände;
   ArrayList<String> inventarListe = new ArrayList<String>();
 
   public void befülleInventar(String bezeichnung)
   {
     inventarListe.add(bezeichnung);
   }

   public void entferneAusInventar(String bezeichnung)
   {
    inventarListe.remove(bezeichnung);
   }
 
   public boolean hatGegenstand(String bezeichnung)
   {
     if (inventarListe.contains(bezeichnung))
     return true;
     else
     return false;
   }
 
   public void inhaltAusgebenAlsString()
   {
     String ergebnis = "Inhalt: ";
        for (int i = 0;i<inventarListe.size();i++)
       {
        ergebnis += " " + inventarListe.get(i);
        System.out.println(ergebnis);
       }
   }
 
   public String inhaltAusgeben()
   {
       String ergebnis = "";
        for (int i = 0;i<inventarListe.size();i++)
       {
        ergebnis += " " + inventarListe.get(i);
       }
       return ergebnis;
   }
}
```

Klasse Raum:

```
import java.util.Set;
import java.util.HashMap;
import java.util.Iterator;

/*
* Diese Klasse modelliert Räume in der Welt von Zuul.
*
* Ein "Raum" repräsentiert einen Ort in der virtuellen Landschaft des
* Spiels. Ein Raum ist mit anderen Räumen über Ausgänge verbunden.
* Für jeden existierenden Ausgang hält ein Raum eine Referenz auf
* den benachbarten Raum.
*
* @author  Michael Kolling and David J. Barnes
* @version 1.0 (März 2003)
*/

class Raum
{
    private String beschreibung;
    private HashMap ausgaenge;
    private Inventar inventar;

    /**
     * Erzeuge einen Raum mit einer Beschreibung. Ein Raum
     * hat anfangs keine Ausgänge.
     * @param beschreibung enthält eine Beschreibung in der Form
     *        "in einer Küche" oder "auf einem Sportplatz".
     */
    public Raum(String beschreibung, Inventar rauminhalt)
    {
        this.beschreibung = beschreibung;
        ausgaenge = new HashMap();
        inventar = rauminhalt;
    }

    /**
     * Definiere einen Ausgang für diesen Raum.
     * @param richtung die Richtung, in der der Ausgang liegen soll
     * @param nachbar der Raum, der über diesen Ausgang erreicht wird
     */
    public void setzeAusgang(String richtung, Raum nachbar)
    {
        ausgaenge.put(richtung, nachbar);
    }

    public void setzeInhalt(String bezeichnung)
    {
        inventar.befülleInventar(bezeichnung);
    }
  
    public void löscheInhalt(String bezeichnung)
    {
        inventar.entferneAusInventar(bezeichnung);
    }
  
    public boolean enthältGegenstand(String bezeichnung)
    {
        return inventar.hatGegenstand(bezeichnung);
    }
  
    /**
     * Liefere die Beschreibung dieses Raums (die dem Konstruktor
     * übergeben wurde).
     */
    public String gibKurzbeschreibung()
    {
        return beschreibung;
      
    }

    /**
     * Liefere eine lange Beschreibung dieses Raums, in der Form:
     *     Sie sind in der Küche.
     *     Ausgänge: nord west
     */
    public String gibLangeBeschreibung()
    {
        return "Sie sind " + beschreibung + ".\n" + gibAusgaengeAlsString();
    }

    /**
     * Liefere eine Zeichenkette, die die Ausgänge dieses Raums
     * beschreibt, beispielsweise
     * "Ausgänge: north west".
     */
    private String gibAusgaengeAlsString()
    {
        String ergebnis = "Ausgänge:";
        Set keys = ausgaenge.keySet();
        for(Iterator iter = keys.iterator(); iter.hasNext(); )
            ergebnis += " " + iter.next();
        return ergebnis;
    }

    /**
     * Liefere den Raum, den wir erreichen, wenn wir aus diesem Raum
     * in die angegebene Richtung gehen. Liefere 'null', wenn in
     * dieser Richtung kein Ausgang ist.
     * @param richtung die Richtung, in die gegangen werden soll.
     */
    public Raum gibAusgang(String richtung)
    {
        return (Raum)ausgaenge.get(richtung);
    }
  
    public void gibInhalt()
    {
       inventar.inhaltAusgeben();
    }
  
    public String gibInhaltAlsString()
    {
        String ergebnis = inventar.inhaltAusgeben();
        return ergebnis;
    }
}
```


----------



## truesoul (9. Mai 2018)

Hallo.

Du rufst die Methode "spielerAnlegen" nirgends auf.
Denke das ist von dir nicht so gewünscht oder?

P. S
Es wäre immer ganz gut, wenn du den Stacktrace auch lieferst und uns sagst welche zeile es ist. 

Grüße


----------



## David Nienhaus (9. Mai 2018)

Ohman  Du hast vollkommen recht, danke!



> P. S
> Es wäre immer ganz gut, wenn du den Stacktrace auch lieferst und uns sagst welche zeile es ist.


Ja, das wäre wirklich besser, wie mache ich das?


----------



## truesoul (9. Mai 2018)

David Nienhaus hat gesagt.:


> Ohman  Du hast vollkommen recht, danke!
> 
> 
> Ja, das wäre wirklich besser, wie mache ich das?



Die Konsole zeigt dir die Fehlermeldung an. Die kopierst du und fügst du hier ein.


----------



## David Nienhaus (9. Mai 2018)

Alles klar!

Ich bin jetzt auf ein weiteres Problem gestoßen, diesmal allerdings ohne Fehlermeldung. 
Es passiert einfach nicht das was ich möchte.
Und zwar habe ich versucht eine Falltür zu implementieren.
Dazu habe ich die Klasse Raum um zwei Variablen 
falltür und falltürRichtung erweitert. Ein Raum kann also entweder eine Falltür haben oder nicht und man soll nur durch die Falltür fallen, wenn man eine bestimmte Richtung einschlägt, deshalb falltürRichtung.



```
class Raum
{
    private String beschreibung;
    private HashMap ausgaenge; 
    private Inventar inventar;
    private boolean falltür = false;
    private String falltürRichtung;
   

    /**
     * Erzeuge einen Raum mit einer Beschreibung. Ein Raum
     * hat anfangs keine Ausgänge.
     * @param beschreibung enthält eine Beschreibung in der Form
     *        "in einer Küche" oder "auf einem Sportplatz".
     */
    public Raum(String beschreibung, Inventar rauminhalt)
    {
        this.beschreibung = beschreibung;
        ausgaenge = new HashMap();
        inventar = rauminhalt;
    }

    /**
     * Definiere einen Ausgang für diesen Raum.
     * @param richtung die Richtung, in der der Ausgang liegen soll
     * @param nachbar der Raum, der über diesen Ausgang erreicht wird
     */
    public void setzeAusgang(String richtung, Raum nachbar)
    {
        ausgaenge.put(richtung, nachbar);
    }

    public void setzeInhalt(String bezeichnung)
    {
        inventar.befülleInventar(bezeichnung);
    }
   
    public void löscheInhalt(String bezeichnung)
    {
        inventar.entferneAusInventar(bezeichnung);
    }
   
    public boolean enthältGegenstand(String bezeichnung)
    {
        return inventar.hatGegenstand(bezeichnung);
    }
   
    /**
     * Liefere die Beschreibung dieses Raums (die dem Konstruktor
     * übergeben wurde).
     */
    public String gibKurzbeschreibung()
    {
        return beschreibung;
       
    }

    /**
     * Liefere eine lange Beschreibung dieses Raums, in der Form:
     *     Sie sind in der Küche.
     *     Ausgänge: nord west
     */
    public String gibLangeBeschreibung()
    {
        return "Sie sind " + beschreibung + ".\n" + gibAusgaengeAlsString();
    }

    /**
     * Liefere eine Zeichenkette, die die Ausgänge dieses Raums
     * beschreibt, beispielsweise
     * "Ausgänge: north west".
     */
    private String gibAusgaengeAlsString()
    {
        String ergebnis = "Ausgänge:";
        Set keys = ausgaenge.keySet();
        for(Iterator iter = keys.iterator(); iter.hasNext(); )
            ergebnis += " " + iter.next();
        return ergebnis;
    }

    /**
     * Liefere den Raum, den wir erreichen, wenn wir aus diesem Raum
     * in die angegebene Richtung gehen. Liefere 'null', wenn in
     * dieser Richtung kein Ausgang ist.
     * @param richtung die Richtung, in die gegangen werden soll.
     */
    public Raum gibAusgang(String richtung)
    {
        return (Raum)ausgaenge.get(richtung);
    }
   
    public void gibInhalt()
    {
       inventar.inhaltAusgeben();
    }
   
    public String gibInhaltAlsString()
    {
        String ergebnis = inventar.inhaltAusgeben();
        return ergebnis;
    }
   
    public void setzeFalltür(String richtung)
    {
        falltür = true;
        falltürRichtung = richtung;
    }
   
    public boolean hatFalltür()
    {
        return falltür;
    }
   
    public String gibFalltürRichtung()
    {
        return falltürRichtung;
    }
}
```

Die Klasse Spiel habe ich dann wie folgt angepasst:
ich habe eine neue Variable aktionsRaum1 hinzugefügt die aussagt, ob in dem Raum eine Aktion wie z.B. eine Falltür vorhanden ist oder nicht. Dann sage ich in raeumeAnlegen:  r6.setzeFalltür("west");  um dem Raum 6 eine Falltür zu verpassen, die ausgelöst wird wenn man nach Westen gehen will. Dann setze ich noch aktionsRaum1 = r2; 
da sich Raum 2 in meiner Karte unter Raum 6 befindet.
Dann habe ich noch die Methode wechsleRaum erweitert mit einer weiteren if Bedingung.
Wenn der aktuelle Raum eine falltür hat und die eingegebene Richtung mit der falltürauslösenden Richtung übereinstimmt, dann will ich zu raum 2 springen. Da zu Raum 2 eigentlich keine Anbindung besteht, kann ich hier leider nicht mit der ursprünglichen Methode hingelanden.. bzw ich wüsste nicht wie, deshalt die Variable aktionsRaum. 



```
if(aktuellerRaum.hatFalltür() == true && richtung == aktuellerRaum.gibFalltürRichtung())
        {
          aktuellerRaum = aktionsRaum1;
          System.out.println(aktuellerRaum.gibLangeBeschreibung());
```
 


```
class Spiel
{
    private Parser parser;
    private Raum aktuellerRaum;
    private Raum aktionsRaum1;
    private Spieler aktuellerSpieler;
       
    /**
     * Erzeuge ein Spiel und initialisiere die interne Raumkarte.
     */
    public Spiel()
    {
        raeumeAnlegen();
        spielerAnlegen();
        parser = new Parser();
    }

    /**
     * Erzeuge alle Räume und verbinde ihre Ausgänge miteinander.
     */
    private void raeumeAnlegen()
    {
        Raum r1, r2, r3, r4, r5 ,r6, r7, r8;
        Inventar i1, i2, i3, i4, i5, i6 ,i7, i8;
       
        i1 = new Inventar();
        i2 = new Inventar();
        i3 = new Inventar();
        i4 = new Inventar();
        i5 = new Inventar();
        i6 = new Inventar();
        i7 = new Inventar();
        i8 = new Inventar();
       
        r1 = new Raum("am Ausgang", i1);
        r2 = new Raum("in einem Kik", i2);
        r3 = new Raum("in einem REWE" ,i3);
        r4 = new Raum("bei den Toiletten",i4);
        r5 = new Raum("in einem McDonalds",i5);
        r6 = new Raum("in einer Abstellkammer",i6);
        r7 = new Raum("in einem K&K",i7 );
        r8 = new Raum("in einem Lagerraum",i8 );
       
       
        i2.befülleInventar("Tshirt");
       
        i3.befülleInventar("Apfel");
       
        i8.befülleInventar("Bier");
       
        r1.setzeAusgang("south", r3);

        r2.setzeAusgang("south", r4);

        r3.setzeAusgang("north", r1);
        r3.setzeAusgang("up" , r7);

        r4.setzeAusgang("north", r2);
        r4.setzeAusgang("up", r8);
       
        r5.setzeAusgang("south", r7);
        r5.setzeAusgang("east", r6);
       
        r6.setzeAusgang("west" , r5);
        r6.setzeAusgang("south", r8);
        r6.setzeFalltür("west");

        r7.setzeAusgang("down", r3);
        r7.setzeAusgang("east", r8);
        r7.setzeAusgang("north", r5);
       
        r8.setzeAusgang("down", r4);
        r8.setzeAusgang("west", r7);
        r8.setzeAusgang("north", r6);

        aktuellerRaum = r8;
        aktionsRaum1 = r2;
    }

   
   
    private void wechsleRaum(Befehl befehl)
    {
       if(!befehl.hatZweitesWort()) {
            // Gibt es kein zweites Wort, wissen wir nicht, wohin...
            System.out.println("Wohin möchten Sie gehen?");
            return;
        }
       
        String richtung = befehl.gibZweitesWort();

        // Wir versuchen den Raum zu verlassen.
       if(aktuellerRaum.hatFalltür() == true && richtung == aktuellerRaum.gibFalltürRichtung())
        {
          aktuellerRaum = aktionsRaum1;
          System.out.println(aktuellerRaum.gibLangeBeschreibung());
        }
        else {
        Raum naechsterRaum = aktuellerRaum.gibAusgang(richtung);

        if (naechsterRaum == null)
            System.out.println("Dort ist keine Tür!");
        else {
            aktuellerRaum = naechsterRaum;
            System.out.println(aktuellerRaum.gibLangeBeschreibung());
        }
        }
    }
```


Was jetzt allerdings passiert ist, dass meine if Bedingung ignoriert wird, ich lande trotzdem in Raum 5, welcher westlich von Raum 6 liegt...


----------



## fhoffmann (9. Mai 2018)

David Nienhaus hat gesagt.:


> richtung == aktuellerRaum.gibFalltürRichtung()


Strings müssen mit equals() verglichen werden.


----------



## VfL_Freak (9. Mai 2018)

Moin,
außerdem solltest Du Umlaute in Bezeichnern vermeiden !!
VG Klaus


----------



## David Nienhaus (9. Mai 2018)

Ahhh! Danke  

Und warum ist das mit den Umlauten eigentlich so? Ist mir schön öfter aufgefallen, hab aber nie den Nachteil verstanden


----------



## VfL_Freak (9. Mai 2018)

Moin,



David Nienhaus hat gesagt.:


> Und warum ist das mit den Umlauten eigentlich so? Ist mir schön öfter aufgefallen, hab aber nie den Nachteil verstanden


ich sag' mal so: es _*kann*_ Probleme bereiten, muss aber nicht!
In kann es dir auch nicht im Detail erklären, aber es hängten mit den Zeichentabellen zusammen, bei denen deutsche Umlaute (oder auch 'ß' aber sicher auch bspw. auch dänische und norwegische Sonderzeichen) Probleme bereiten können, da sie ja ASCII-mäßig sehr weit hinten liegen. Manche Compiler kommen damit nicht klar (oder kamen es zumindest früher nicht) !
Also besser nicht nutzen, dann bist Du auf der sicheren Seite 

VG Klaus


----------

