diff --git a/src/Gegenstand.java b/src/Gegenstand.java new file mode 100644 index 0000000..674e8bc --- /dev/null +++ b/src/Gegenstand.java @@ -0,0 +1,76 @@ +/** + * Diese Klasse modeliert einen Gegenstand + * mit seinem Namen und seiner Beschreibung sowie + * seinem Gewicht. + * + * @author tebe + * @version 1.0 + * + */ +public class Gegenstand { + private final String name; + private final String beschreibung; + private final int gewicht; + + /** + * Erzeugt einen Gegenstand mit Namen und + * Gewicht aber ohne genauere Beschreibung. + * + * Der Name darf nicht null sein und das + * Gewicht muss groesser als 0 sein. + * + * @param name Der Name des Gegenstands + * @param gewicht Das Gewicht des Gegenstands + */ + public Gegenstand(String name, int gewicht) { + this(name, "", gewicht); + } + + /** + * Erzeugt einen Gegenstand mit Namen und + * Gewicht und genauere Beschreibung. + * + * Name und Beschreibung duerfen nicht null sein und das + * Gewicht muss groesser als 0 sein. + * + * @param name Der Name des Gegenstands + * @param gewicht Das Gewicht des Gegenstands + */ + public Gegenstand(String name, String beschreibung, int gewicht){ + this.name = name; + this.gewicht = gewicht; + this.beschreibung = beschreibung; + if(! istDefinitionGueltig()) { + throw new IllegalArgumentException( + "Gegenstandsdefinition ist ungueltig."); + } + } + + private boolean istDefinitionGueltig(){ + return !(name == null || beschreibung == null || gewicht <= 0); + } + + /** + * @return Der Name des Gegenstands + */ + public String gibName() { + return name; + } + + /** + * Gibt die Beschreibung des Gegenstandes zurueck. + * Falls der Gegenstand ueber keine Beschreibung + * verfuegt, wird ein leerer String zurueckgegeben. + * @return Die Beschreibung des Gegenstands + */ + public String gibBeschreibung() { + return beschreibung; + } + + /** + * @return Das Gewicht des Gegenstands + */ + public int gibGewicht() { + return gewicht; + } +} diff --git a/src/Parser.java b/src/Parser.java new file mode 100644 index 0000000..04cf88c --- /dev/null +++ b/src/Parser.java @@ -0,0 +1,40 @@ +import java.util.Scanner; + +/** + * Dieser Parser liest Benutzereingaben und wandelt sie in Befehle um. Bei jedem + * Aufruf liest er eine Zeile von der Konsole und versucht, diese als einen + * Befehl aus bis zu zwei Woertern zu interpretieren. Er liefert den Befehl als + * ein Objekt der Klasse Befehl zurueck. + * + * Der Parser verfuegt ueber einen Satz an bekannten Befehlen. Er + * vergleicht die Eingabe mit diesen Befehlen. Wenn die Eingabe + * keinen bekannten Befehl enthaelt, dann liefert der Parser ein als + * unbekannter Befehl gekennzeichnetes Objekt zurueck. + * + * @author tebe + * @version 18.10.2013 + */ +class Parser { + // Lieferant fuer eingegebene Befehle + private Scanner leser = new Scanner(System.in); + + /** + * @return Der naechste Befehl des Benutzers. + */ + public Befehl liefereBefehl() { + Befehl befehl; + String eingabezeile; // fuer die gesamte Eingabezeile + + System.out.print("> "); // Eingabeaufforderung + eingabezeile = leser.nextLine(); + String[] woerter = eingabezeile.split(" "); + + if (woerter.length >= 2) { + befehl = new Befehl(woerter[0], woerter[1]); + } else { + befehl = new Befehl(woerter[0], null); + } + return befehl; + } + +} diff --git a/src/Person.java b/src/Person.java new file mode 100644 index 0000000..8c75c1e --- /dev/null +++ b/src/Person.java @@ -0,0 +1,46 @@ +import java.util.ArrayList; + +/** + * Diese Klasse modeliert eine Person, die einen Namen + * hat und einen Rucksack traegt. Im Rucksack kann sie + * Gegenstaende herumtragen. Gegenstaende sollen nur dann in den + * Rucksack gepackt werden, wenn der Rucksack nicht schwerer wird + * als die Tragkraft der Person. + * + * @author tebe + * @version 1.0 + * + */ +public class Person { + private final String name; + private final int tragkraft; + private final ArrayList rucksack = new ArrayList(); + + /** + * Erzeugt eine Person mit Namen und Tragkraft. + * @param tragkraft + */ + public Person(String name, int tragkraft) { + this.tragkraft = tragkraft; + this.name = name; + } + + public ArrayList getRucksack() { + return rucksack; + } + + /** + * Gibt die Tragkraft zurueck. + * @return Die Tragkraft + */ + public int gibTragkraft() { + return tragkraft; + } + + /** + * @return Der Name der Person + */ + public String gibName() { + return name; + } +} diff --git a/src/Raum.java b/src/Raum.java new file mode 100644 index 0000000..2532d97 --- /dev/null +++ b/src/Raum.java @@ -0,0 +1,169 @@ +import java.util.ArrayList; +import java.util.Set; +import java.util.HashMap; + +/** + * Diese Klasse modelliert Raeume in der Welt von Zuul. + * + * Ein "Raum" repraesentiert einen Ort in der virtuellen Landschaft des + * Spiels. Ein Raum ist mit anderen Raeumen ueber Ausgaenge verbunden. + * Fuer jeden existierenden Ausgang haelt ein Raum eine Referenz auf + * den benachbarten Raum. In einem Raum koennen sich Personen und + * Gegenstaende befinden. + * + * @author tebe (Original: Michael Koelling und David J. Barnes) + * @version 1.0 + */ + +class Raum +{ + private final String beschreibung; + private final ArrayList person = new ArrayList(); + private final ArrayList gegenstand = new ArrayList(); + private final HashMap ausgaenge = new HashMap(); + + /** + * Erzeuge einen Raum mit einer Beschreibung. Ein Raum + * hat anfangs keine Ausgaenge, Personen oder Gegenstaende. + * @param beschreibung enthaelt eine Beschreibung in der Form + * "in einer Kueche" oder "auf einem Sportplatz". + */ + public Raum(String beschreibung) + { + this.beschreibung = beschreibung; + } + + /** + * Definiere einen Ausgang fuer diesen Raum. + * @param richtung Die Richtung, in der der Ausgang liegen soll + * @param nachbar Der Raum, der ueber diesen Ausgang erreicht wird + */ + public void setzeAusgang(String richtung, Raum nachbar) + { + ausgaenge.put(richtung, nachbar); + } + + /** + * Die Person betritt den Raum und wird fortan als im Raum + * befindlich gelistet. + * @param person Person, welche den Raum betritt + */ + public void betreten(Person person) + { + this.person.add(person); + } + + /** + * Die Person mit der angegebenen Nummer wird aus dem Raum entfernt + * und wird fortan nicht mehr als im Raum befindlich gelistet. + * Falls eine Person mit dieser Nummer nicht existiert, wird 'null' + * zurueckgegeben. + * @param nummer Nummer der Person + * @return Person, die den Raum verlassen hat + */ + public Person verlassen(int nummer) + { + boolean ungueltigerIndex = person.isEmpty() || + nummer > person.size()-1 || nummer < 0; + return ungueltigerIndex ? null : person.remove(nummer); + } + + /** + * Der Gegenstand wird in den Raum gelegt und wird fortan als im + * Raum befindlich gelistet. + * @param gegenstand Gegenstand, welcher in den Raum gelegt wird + */ + public void hineinlegen(Gegenstand gegenstand) + { + this.gegenstand.add(gegenstand); + } + + /** + * Der Gegenstand mit der angegebenen Nummer wird aus dem Raum entfernt + * und wird fortan nicht mehr als im Raum befindlich gelistet. + * Falls ein Gegenstand mit dieser Nummer nicht existiert, wird 'null' + * zurueckgegeben. + * @param nummer Nummer des Gegenstands + * @return Gegenstand, der herausgenommen wurde + */ + public Gegenstand herausnehmen(int nummer) + { + boolean ungueltigerIndex = gegenstand.isEmpty() || + nummer > gegenstand.size()-1 || nummer < 0; + return ungueltigerIndex ? null : gegenstand.remove(nummer); + } + + /** + * @return Die kurze Beschreibung dieses Raums (die dem Konstruktor + * uebergeben wurde). + */ + public String gibKurzbeschreibung() + { + return beschreibung; + } + + /** + * Liefere eine lange Beschreibung dieses Raums, inkl. + * Beschreibung des Rauminhaltes (Gegenstaende, Personen,...). + * @return eine lange Beschreibung dieses Raumes. + */ + public String gibLangeBeschreibung() + { + return "Sie sind " + beschreibung + ".\n" + + gibAusgaengeAlsString() + + gibGegenstaendeAlsString() + + gibPersonenAlsString(); + } + + private String gibGegenstaendeAlsString() { + String text = "Keine Gegenstaende im Raum.\n"; + if(gegenstand.size()>0) { + int counter = 0; + text = "Gegenstaende im Raum:\n"; + for( Gegenstand objekt : gegenstand) { + text += " " + counter++ + ": " + objekt.gibName() + "\n"; + } + } + return text; + } + + private String gibPersonenAlsString() { + String text = "Keine Personen im Raum.\n"; + if(person.size()>0){ + text="Personen im Raum:\n"; + int counter = 0; + for( Person objekt : person) { + text += " " + counter++ + ": " + objekt.gibName() + "\n"; + } + } + return text; + } + + /** + * Liefere eine Zeichenkette, die die Ausgaenge dieses Raums + * beschreibt, beispielsweise + * "Ausgaenge: north west". + * @return eine Beschreibung der Ausgaenge dieses Raumes. + */ + private String gibAusgaengeAlsString() + { + String ergebnis = "Ausgaenge:"; + Set keys = ausgaenge.keySet(); + for(String ausgang : keys) + ergebnis += " " + ausgang; + return ergebnis + "\n"; + } + + /** + * 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. + * @return den Raum in der angegebenen Richtung. + */ + public Raum gibAusgang(String richtung) + { + return ausgaenge.get(richtung); + } +} + diff --git a/src/Spiel.java b/src/Spiel.java new file mode 100644 index 0000000..10dc8d7 --- /dev/null +++ b/src/Spiel.java @@ -0,0 +1,355 @@ +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; + +/** + * Dies ist die Hauptklasse der Anwendung "Die Welt von Zuul". + * "Die Welt von Zuul" ist ein sehr einfaches, textbasiertes Adventure-Game. Ein + * Spieler kann sich in einer Umgebung bewegen, die Kontrolle von anderen Personen + * im Raum uebernehmen und Gegenstaende einpacken, sofern seine Tragkraft ausreicht. + * Das Spiel sollte auf jeden Fall noch weiter ausgebaut werden, damit es interessanter wird! + * + * + * Diese Instanz dieser Klasse erzeugt und initialisiert alle anderen Objekte + * der Anwendung: Sie legt alle Raeume und einen Parser an und startet das + * Spiel. Sie wertet auch die Befehle aus, die der Parser liefert und sorgt fuer + * ihre Ausfuehrung. + * + * @author tebe (Original: Michael Koelling und David J. Barnes) + * @version 1.0 + */ + +public class Spiel { + private Parser parser; + private Raum aktuellerRaum; + private Person spieler; + + /** + * Erzeuge ein Spiel und initialisiere die Spielwelt. + */ + public Spiel() { + spielweltErzeugen(); + parser = new Parser(); + } + + /** + * Baut die Spielewelt auf. Erzeugt die Raeume mit Verbindungen und fuellt + * diese mit Personen und Gegenstaenden. + */ + private void spielweltErzeugen() { + spieler = new Person("Captain Kirk", 20); + ArrayList raeume = raeumeAnlegen(); + fuellenMitPersonen(raeume); + fuellenMitGegenstaenden(raeume); + } + + /** + * Erzeuge alle Raeume, verbinde ihre Ausgaenge miteinander. + * + * @return Die angelegten Raeume + */ + private ArrayList raeumeAnlegen() { + HashMap raum = new HashMap(); + // die Raeume erzeugen + raum.put("draussen", new Raum("vor dem Haupteingang der Universitaet")); + raum.put("hoersaal", new Raum("in einem Vorlesungssaal")); + raum.put("cafeteria", new Raum("in der Cafeteria der Uni")); + raum.put("labor", new Raum("in einem Rechnerraum")); + raum.put("buero", new Raum("im Verwaltungsbuero der Informatik")); + // die Ausgaenge initialisieren + raum.get("draussen").setzeAusgang("osten", raum.get("hoersaal")); + raum.get("draussen").setzeAusgang("sueden", raum.get("labor")); + raum.get("draussen").setzeAusgang("westen", raum.get("cafeteria")); + raum.get("hoersaal").setzeAusgang("westen", raum.get("draussen")); + raum.get("cafeteria").setzeAusgang("osten", raum.get("draussen")); + raum.get("labor").setzeAusgang("norden", raum.get("draussen")); + raum.get("labor").setzeAusgang("osten", raum.get("buero")); + raum.get("buero").setzeAusgang("westen", raum.get("labor")); + + // Startraum + aktuellerRaum = raum.get("draussen"); + ArrayList raumliste = new ArrayList(); + for (Raum r : raum.values()) { + raumliste.add(r); + } + return raumliste; + } + + /** + * Verteilt eine Anzahl Personen auf eine Liste von Raeumen. Die Zuteilung + * erfolgt auf Basis einer Zufallsstrategie. + * + * @param raum + * Liste der Raeume + */ + private void fuellenMitPersonen(ArrayList raum) { + ArrayList person = new ArrayList(); + person.add(new Person("Dr. Hans Muster", 40)); + person.add(new Person("Peter Stark", 80)); + person.add(new Person("Anna Pfister", 45)); + person.add(new Person("Prof. Dr. Luna Berger", 35)); + int counter = 0; + while (person.size() > 0) { + if (Math.random() > 0.5) { + raum.get(counter).betreten(person.get(0)); + person.remove(0); + } + counter = (counter + 1) % raum.size(); + } + } + + /** + * Verteilt eine Anzahl Gegenstaende auf eine Liste von Raeumen. Die + * Zuteilung erfolgt auf Basis einer Zufallsstrategie. + * + * @param raum + * Liste der Raeume + */ + private void fuellenMitGegenstaenden(ArrayList raum) { + ArrayList gegenstand = new ArrayList(); + gegenstand.add(new Gegenstand("Sehr schwerer Laserpointer", 1)); + gegenstand.add(new Gegenstand("Beamer", 12)); + gegenstand.add(new Gegenstand("Workstation", 10)); + gegenstand.add(new Gegenstand("Wandtafel", 250)); + gegenstand.add(new Gegenstand("Mineralwasser (6x1.5L)", 9)); + gegenstand.add(new Gegenstand("Laptoptasche mit Laptop", 5)); + gegenstand.add(new Gegenstand("Flipchart", 11)); + gegenstand.add(new Gegenstand("Whiteboard", 8)); + gegenstand.add(new Gegenstand("Toeggelikasten", 30)); + int counter = 0; + while (gegenstand.size() > 0) { + if (Math.random() > 0.5) { + raum.get(counter).hineinlegen(gegenstand.get(0)); + gegenstand.remove(0); + } + counter = (counter + 1) % raum.size(); + } + } + + /** + * Die Hauptmethode zum Spielen. Laeuft bis zum Ende des Spiels in einer + * Schleife. + */ + private void spielen() { + willkommenstextAusgeben(); + + // Die Hauptschleife. Hier lesen wir wiederholt Befehle ein + // und fuehren sie aus, bis das Spiel beendet wird. + boolean beendet = false; + while (!beendet) { + Befehl befehl = parser.liefereBefehl(); + beendet = verarbeiteBefehl(befehl); + } + System.out.println("Danke fuer dieses Spiel. Auf Wiedersehen."); + } + + /** + * Einen Begruessungstext fuer den Spieler ausgeben. + */ + private void willkommenstextAusgeben() { + System.out.println(); + System.out.println("Willkommen zu Zuul!"); + System.out + .println("Zuul ist ein neues, unglaublich langweiliges Spiel."); + System.out.println("Tippen sie '" + Befehlswort.HILFE + + "', wenn Sie Hilfe brauchen."); + System.out.println(); + System.out.println(aktuellerRaum.gibLangeBeschreibung()); + } + + /** + * Verarbeite einen gegebenen Befehl (fuehre ihn aus). + * + * @param befehl + * Der zu verarbeitende Befehl. + * @return 'true', wenn der Befehl das Spiel beendet, 'false' sonst. + */ + private boolean verarbeiteBefehl(Befehl befehl) { + boolean moechteBeenden = false; + + Befehlswort befehlswort = befehl.gibBefehlswort(); + + switch (befehlswort) { + case UNBEKANNT: + System.out.println("Ich weiss nicht, was Sie meinen..."); + break; + case UMSEHEN: + umsehen(); + break; + case HILFE: + hilfstextAusgeben(); + break; + case GEHE: + wechsleRaum(befehl); + break; + case BEENDEN: + moechteBeenden = beenden(befehl); + break; + case UEBERNIMM: + uebernimm(befehl); + break; + case NIMM: + nimm(befehl); + break; + default: + System.out.println("Befehlswort ohne zugehoerige Aktion."); + break; + } + return moechteBeenden; + } + + /** + * + */ + private void umsehen() { + System.out.println("Sie sind: " + spieler.gibName()); + System.out.println(aktuellerRaum.gibLangeBeschreibung()); + } + + /** + * Packt den spezifizierten Gegenstand in den Rucksack + * des Spielers und entfernt ihn aus dem aktuellen Raum. + * + * Falls der bezeichnete Gegenstand nicht vorhanden ist, aendert sich nichts. + * + * @param befehl Der auszufuehrende Befehl + */ + private void nimm(Befehl befehl) { + if (befehl.hatZweitesWort()) { + int kennummer = Integer.parseInt(befehl.gibZweitesWort()); + gegenstandEinpacken(kennummer); + } else { + System.out.println("Geben Sie die Nummer des Gegenstands an."); + } + } + + /** + * Packt den Gegenstand mit der gegebenen + * Nummer, falls vorhanden, in den Rucksack + * des Spielers und entfernt ihn aus dem aktuellen Raum. + * + * @param nummer Nummer des Gegenstands + */ + private void gegenstandEinpacken(int nummer) { + Gegenstand gegenstand = aktuellerRaum.herausnehmen(nummer); + if (gegenstand == null) { + System.out.println("Es gibt keinen Gegenstand mit dieser Nummer: " + + nummer); + } else { + if (spieler.gibTragkraft() >= berechneGewicht(spieler.getRucksack()) + gegenstand.gibGewicht()) { + System.out.println("Gegenstand eingepackt: " + gegenstand.gibName()); + spieler.getRucksack().add(gegenstand); + } else { + System.out + .println("Gegenstand konnte nicht eingepackt werden."); + aktuellerRaum.hineinlegen(gegenstand); + } + } + } + + /** + * Berechnet das Gewicht der Gegenstaende in dieser Liste + * @param rucksack Die Liste mit Gegenstaenden + * @return Das Gewicht der Gegenstaende + */ + private int berechneGewicht(ArrayList rucksack) { + int gewicht = 0; + for(Gegenstand gegenstand : rucksack) { + gewicht += gegenstand.gibGewicht(); + } + return gewicht; + } + + /** + * Uebernimmt die Kontrolle der spezifizierten Person. Der Spieler steuert + * anschliessend neu diese Person. + * + * Falls die bezeichnete Person nicht vorhanden ist, aendert sich nichts. + * + * @param befehl + * Der auszufuehrende Befehl + */ + private void uebernimm(Befehl befehl) { + if (befehl.hatZweitesWort()) { + int nummer = Integer.parseInt(befehl.gibZweitesWort()); + personUebernehmen( nummer); + } else + { + System.out.println("Geben Sie die Nummer der Person an."); + } + } + + /** + * Uebernimmt, falls vorhanden, die Kontrolle der + * Person mit der spezifizierten Nummer. + * + * @param nummer Nummer der Person + */ + private void personUebernehmen(int nummer) { + Person person = aktuellerRaum.verlassen(nummer); + if (person == null) { + System.out.println("Es gibt keine Person mit Nummer " + nummer); + } else { + aktuellerRaum.betreten(spieler); + spieler = person; + System.out.println("Sie kontrollieren nun " + spieler.gibName()); + } + } + + /** + * Gib Hilfsinformationen aus. Hier geben wir eine etwas alberne und unklare + * Beschreibung aus, sowie eine Liste der Befehlswoerter. + */ + private void hilfstextAusgeben() { + System.out.println("Sie haben sich verlaufen. Sie sind allein."); + System.out.println("Sie irren auf dem Unigelaende herum."); + System.out.println(); + befehleAusgeben(); + } + + /** + * Gibt eine Liste der vorhandenen Befehlswoerter aus. + */ + private void befehleAusgeben() { + System.out.println("Ihnen stehen folgende Befehle zur Verfuegung:"); + System.out.println(Befehlswort.gibBefehlsworteAlsText()); + } + + /** + * Versuche, in eine Richtung zu gehen. 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 moechten 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 Tuer!"); + } else { + aktuellerRaum = naechsterRaum; + System.out.println(aktuellerRaum.gibLangeBeschreibung()); + } + } + + /** + * Der Befehl zum Beenden wurde eingegeben. Ueberpruefe den Rest des + * Befehls, ob das Spiel wirklich beendet werden soll. + * + * @return '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; + } + } + +}