Initial commit of the source files.

This commit is contained in:
Bernhard Tellenbach 2017-09-17 17:06:55 +02:00
parent a9fdcf84e0
commit 44babda114
7 changed files with 620 additions and 0 deletions

74
Befehl.java Normal file
View File

@ -0,0 +1,74 @@
/**
* Objekte dieser Klasse halten Informationen über Befehle,
* die der Benutzer eingegeben hat. Ein Befehl besteht momentan
* aus zwei Zeichenketten: einem Befehlswort und einem zweiten
* Wort. Beim Befehl "nimm karte" beispielsweise sind die beiden
* Zeichenketten "nimm" und "karte".
*
* Befehle werden von Benutzern dieser Klasse auf Gültigkeit
* überprüft. Wenn ein Spieler einen ungültigen Befehl eingegeben
* hat (ein unbekanntes Befehlswort), dann ist das Befehlswort <null>.
*
* Wenn der Befehl nur aus einem Wort bestand, dann ist das
* zweite Wort <null>.
*
* @author Michael Kölling und David J. Barnes
* @version 31.07.2011
*/
class Befehl
{
private String befehlswort;
private String zweitesWort;
/**
* Erzeuge ein Befehlsobjekt. Beide Wörter müssen angegeben werden,
* aber jedes oder beide dürfen 'null' sein.
* @param erstesWort Das erste Wort des Befehls. Sollte
* 'null' sein, wenn dieser Befehl als nicht
* vom Spiel erkannt gekennzeichnet werden soll.
* @param zweitesWort Das zweite Wort des Befehls.
*/
public Befehl(String erstesWort, String zweitesWort)
{
befehlswort = erstesWort;
this.zweitesWort = zweitesWort;
}
/**
* Liefere das Befehlswort (das erste Wort) dieses Befehls.
* Wenn der Befehl nicht verstanden wurde, ist das Ergebnis
* 'null'.
* @return Das Befehlswort.
*/
public String gibBefehlswort()
{
return befehlswort;
}
/**
* @return Das zweite Wort dieses Befehls. Liefere 'null', wenn
* es kein zweites Wort gab.
*/
public String gibZweitesWort()
{
return zweitesWort;
}
/**
* @return 'true', wenn dieser Befehl nicht verstanden wurde.
*/
public boolean istUnbekannt()
{
return (befehlswort == null);
}
/**
* @return 'true', wenn dieser Befehl ein zweites Wort hat.
*/
public boolean hatZweitesWort()
{
return (zweitesWort != null);
}
}

41
Befehlswoerter.java Normal file
View File

@ -0,0 +1,41 @@
/*
* Diese Klasse hält eine Aufzählung aller Befehlswörter, die dem
* Spiel bekannt sind. Mit ihrer Hilfe werden eingetippte Befehle
* erkannt.
*
* @author Michael Kölling und David J. Barnes
* @version 31.07.2011
*/
class Befehlswoerter
{
// ein konstantes Array mit den gültigen Befehlswörtern
private static final String gueltigeBefehle[] = {
"go", "quit", "help", "look"
};
/**
* Konstruktor - initialisiere die Befehlswörter.
*/
public Befehlswoerter()
{
// nichts zu tun momentan...
}
/**
* Prüfe, ob eine gegebene Zeichenkette ein gültiger
* Befehl ist.
* @return 'true', wenn die gegebene Zeichenkette ein gültiger
* Befehl ist, 'false' sonst.
*/
public boolean istBefehl(String eingabe)
{
for(int i = 0; i < gueltigeBefehle.length; i++) {
if(gueltigeBefehle[i].equals(eingabe))
return true;
}
// Wenn wir hierher gelangen, wurde die Eingabe nicht
// in den Befehlswörter gefunden.
return false;
}
}

66
Parser.java Normal file
View File

@ -0,0 +1,66 @@
import java.util.Scanner;
import java.util.StringTokenizer;
/**
* Dieser Parser liest Benutzereingaben und wandelt sie in
* Befehle für das Adventure-Game um. Bei jedem Aufruf
* liest er eine Zeile von der Konsole und versucht, diese als
* einen Befehl aus bis zu zwei Wörtern zu interpretieren. Er
* liefert den Befehl als ein Objekt der Klasse Befehl zurück.
*
* Der Parser verfügt über einen Satz an bekannten Befehlen. Er
* vergleicht die Eingabe mit diesen Befehlen. Wenn die Eingabe
* keinen bekannten Befehl enthält, dann liefert der Parser ein als
* unbekannter Befehl gekennzeichnetes Objekt zurück.
*
* @author Michael Kölling und David J. Barnes
* @version 31.07.2011
*/
class Parser
{
private Befehlswoerter befehle; // hält die gültigen Befehlswörter
private Scanner leser; // Lieferant für eingegebene Befehle
/**
* Erzeuge einen Parser, der Befehle von der Konsole einliest.
*/
public Parser()
{
befehle = new Befehlswoerter();
leser = new Scanner(System.in);
}
/**
* @return Den nächsten Befehl des Benutzers.
*/
public Befehl liefereBefehl()
{
String eingabezeile; // für die gesamte Eingabezeile
String wort1 = null;
String wort2 = null;
System.out.print("> "); // Eingabeaufforderung
eingabezeile = leser.nextLine();
// Finde bis zu zwei Wörter in der Zeile
Scanner zerleger = new Scanner(eingabezeile);
if(zerleger.hasNext()) {
wort1 = zerleger.next(); // erstes Wort lesen
if (zerleger.hasNext()) {
wort2 = zerleger.next(); // zweites Wort lesen
// Hinweis: Wir ignorieren den Rest der Eingabezeile.
}
}
// Jetzt prüfen, ob der Befehl bekannt ist. Wenn ja, erzeugen
// wir das passende Befehl-Objekt. Wenn nicht, erzeugen wir
// einen unbekannten Befehl mit 'null'.
if(befehle.istBefehl(wort1)) {
return new Befehl(wort1, wort2);
}
else {
return new Befehl(null, wort2);
}
}
}

29
README.TXT Normal file
View File

@ -0,0 +1,29 @@
Projekt: Zuul-schlecht
Autoren: Michael Kölling und David J. Barnes
Dieses Projekt ist Teil des Zusatzmaterials zum Buch
Java lernen mit BlueJ - eine Einführung in die
objektorientierte Programmierung, 5. Auflage
David J. Barnes und Michael Kölling
Pearson Education Deutschland, 2012
Dieses Projekt ist das Grundgerüst für ein Adventure-Game.
In dieser Version hat es ein paar Räume und bietet dem Spieler die
Möglichkeit, sich zwischen diesen Räumen zu bewegen. Das ist alles.
Um ein Spiel zu starten, erzeugen Sie eine Instanz von 'Spiel' und rufen
die Methode 'spielen' auf.
Diese Version des Spiels enthält einige schlechte Entwurfsentscheidungen.
Sie sollte nicht als Basis für Erweiterungen am Projekt benutzt werden,
bevor diese problematischen Entwurfsentscheidungen korrigiert wurden.
Diese Version dient als ein Beispiel in der Diskussion über gute
und schlechte Entwürfe (Kapitel 6 im Buch).
In Kapitel 6 des Buches ist ausführlich beschrieben, welche Probleme
bestehen und wie sie behoben werden können.
Das Projekt 'Zuul-besser' enthält eine Version dieses Projektes mit
einer besser entworfenen Klassenstruktur, in der die im Buch
beschriebenen Schwächen behoben sind.

90
Raum.java Normal file
View File

@ -0,0 +1,90 @@
import java.util.HashMap;
import java.util.Set;
/**
* 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.
* Mögliche Ausgänge liegen im Norden, Osten, Süden und Westen.
* Für jede Richtung hält ein Raum eine Referenz auf den
* benachbarten Raum.
*
* @author Michael Kölling und David J. Barnes
* @version 31.07.2011
*/
public class Raum {
private String beschreibung;
private HashMap<String, Raum> ausgaenge;
/**
* 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) {
this.beschreibung = beschreibung;
this.ausgaenge = new HashMap<>();
}
/**
* Definiert die Ausgänge dieses Raums.
*
* @param richtung
* Die Richtung (north, east, south, west)
* @param raum
* Der nächste Raum
*/
public void setzeAusgaenge(String richtung, Raum raum) {
ausgaenge.put(richtung, raum);
}
/**
* Gibt den Raum für eine Richtung zurück
*
* @param richtung
* Die Richtung (north, east, south, west)
* @return Der nächste Raum
*/
public Raum gibAusgang(String richtung) {
return ausgaenge.get(richtung);
}
/**
* @return die Beschreibung dieses Raums.
*/
public String gibBeschreibung() {
return beschreibung;
}
/**
* Liefert eine Beschreibung der Ausgänge dieses Raumes, bespielsweise
* "Ausgänge: north west".
*
* @return eine Beschreibung der verfügbaren Ausgänge
*/
public String gibAusgaengeAlsString() {
String resultat = "Ausgänge:";
Set<String> ausgaengeSet = ausgaenge.keySet();
for (String ausgang : ausgaengeSet) {
resultat += " " + ausgang;
}
return resultat;
}
/**
* Liefert eine lange Beschreibung dieses Raumes, in der Form
* Sie sind in der Küche
* Ausgänge: north west
*
* @return eine lange Beschreibung dieses Raumes.
*/
public String gibLangeBeschreibung() {
return "Sie sind " + beschreibung + ".\n" + gibAusgaengeAlsString();
}
}

217
Spiel.java Normal file
View File

@ -0,0 +1,217 @@
/**
* 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, mehr nicht. Das Spiel sollte auf
* jeden Fall ausgebaut werden, damit es interessanter wird!
*
* Zum Spielen muss eine Instanz dieser Klasse erzeugt werden und an ihr die
* Methode "spielen" aufgerufen werden.
*
* Diese Instanz erzeugt und initialisiert alle anderen Objekte der Anwendung:
* Sie legt alle Räume und einen Parser an und startet das Spiel. Sie wertet
* auch die Befehle aus, die der Parser liefert, und sorgt für ihre Ausführung.
*
* @author Michael Kölling und David J. Barnes
* @version 31.07.2011
*/
public class Spiel {
private final static String NORTH = "north";
private final static String EAST = "east";
private final static String SOUTH = "south";
private final static String WEST = "west";
private Parser parser;
private Raum aktuellerRaum;
/**
* 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 draussen, hoersaal, cafeteria, labor, buero;
draussen = new Raum("vor dem Haupteingang der Universität");
hoersaal = new Raum("in einem Vorlesungssaal");
cafeteria = new Raum("in der Cafeteria der Uni");
labor = new Raum("in einem Rechnerraum");
buero = new Raum("im Verwaltungsbüro der Informatik");
draussen.setzeAusgaenge(EAST, hoersaal);
draussen.setzeAusgaenge(SOUTH, labor);
draussen.setzeAusgaenge(WEST, cafeteria);
hoersaal.setzeAusgaenge(WEST, draussen);
cafeteria.setzeAusgaenge(EAST, draussen);
labor.setzeAusgaenge(NORTH, draussen);
labor.setzeAusgaenge(EAST, buero);
buero.setzeAusgaenge(WEST, labor);
aktuellerRaum = draussen;
}
/**
* 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("Danke für dieses Spiel. Auf Wiedersehen.");
}
/**
* Einen Begrüssungstext für 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 'help', wenn Sie Hilfe brauchen.");
System.out.println();
rauminfoAusgeben();
}
/**
* Verarbeite einen gegebenen Befehl (führe 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;
if (befehl.istUnbekannt()) {
System.out.println("Ich weiss 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("quit")) {
moechteBeenden = beenden(befehl);
}
return moechteBeenden;
}
// Implementierung der Benutzerbefehle:
/**
* Gib Hilfsinformationen aus. Hier geben wir eine etwas alberne und unklare
* Beschreibung aus, sowie eine Liste der Befehlswörter.
*/
private void hilfstextAusgeben() {
System.out.println("Sie haben sich verlaufen. Sie sind allein.");
System.out.println("Sie irren auf dem Unigelände herum.");
System.out.println();
System.out.println("Ihnen stehen folgende Befehle zur Verfügung:");
System.out.println(" go quit help");
}
/**
* 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 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;
rauminfoAusgeben();
}
}
/**
* "quit" wurde eingegeben. Überprüfe 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; // Das Spiel soll beendet werden.
}
}
private void rauminfoAusgeben() {
// Lösung A6
System.out.println(aktuellerRaum.gibLangeBeschreibung());
// Lösung A3
// System.out.println("Sie sind " + aktuellerRaum.gibBeschreibung());
// Lösung A5
// System.out.println(aktuellerRaum.gibAusgaengeAlsString());
// Lösung A3
// System.out.print("Ausgänge: ");
// if (aktuellerRaum.nordausgang != null) {
// System.out.print("north ");
// }
// if (aktuellerRaum.ostausgang != null) {
// System.out.print("east ");
// }
// if (aktuellerRaum.suedausgang != null) {
// System.out.print("south ");
// }
// if (aktuellerRaum.westausgang != null) {
// System.out.print("west ");
// }
// System.out.println();
// Lösung A4
// System.out.print("Ausgänge: ");
// if (aktuellerRaum.gibAusgang(NORTH) != null) {
// System.out.print("north ");
// }
// if (aktuellerRaum.gibAusgang(EAST) != null) {
// System.out.print("east ");
// }
// if (aktuellerRaum.gibAusgang(SOUTH) != null) {
// System.out.print("south ");
// }
// if (aktuellerRaum.gibAusgang(WEST) != null) {
// System.out.print("west ");
// }
// System.out.println();
}
}

103
package.bluej Normal file
View File

@ -0,0 +1,103 @@
#BlueJ package file
dependency1.from=Parser
dependency1.to=Befehlswoerter
dependency1.type=UsesDependency
dependency2.from=Parser
dependency2.to=Befehl
dependency2.type=UsesDependency
dependency3.from=Spiel
dependency3.to=Parser
dependency3.type=UsesDependency
dependency4.from=Spiel
dependency4.to=Raum
dependency4.type=UsesDependency
dependency5.from=Spiel
dependency5.to=Befehl
dependency5.type=UsesDependency
objectbench.height=100
objectbench.width=552
package.editor.height=497
package.editor.width=759
package.editor.x=662
package.editor.y=297
package.numDependencies=5
package.numTargets=6
package.showExtends=true
package.showUses=true
project.charset=windows-1252
readme.editor.height=526
readme.editor.width=748
readme.editor.x=991
readme.editor.y=186
target1.editor.height=526
target1.editor.width=748
target1.editor.x=574
target1.editor.y=47
target1.height=50
target1.name=Raum
target1.naviview.expanded=false
target1.showInterface=false
target1.type=ClassTarget
target1.typeParameters=
target1.width=80
target1.x=130
target1.y=220
target2.editor.height=984
target2.editor.width=1069
target2.editor.x=-1887
target2.editor.y=64
target2.height=50
target2.name=Spiel
target2.naviview.expanded=false
target2.showInterface=false
target2.type=ClassTarget
target2.typeParameters=
target2.width=80
target2.x=40
target2.y=70
target3.height=50
target3.name=Note
target3.showInterface=false
target3.type=EnumTarget
target3.typeParameters=
target3.width=80
target3.x=70
target3.y=10
target4.editor.height=526
target4.editor.width=748
target4.editor.x=0
target4.editor.y=0
target4.height=50
target4.name=Befehl
target4.showInterface=false
target4.type=ClassTarget
target4.typeParameters=
target4.width=80
target4.x=130
target4.y=150
target5.editor.height=526
target5.editor.width=748
target5.editor.x=3
target5.editor.y=81
target5.height=50
target5.name=Befehlswoerter
target5.naviview.expanded=false
target5.showInterface=false
target5.type=ClassTarget
target5.typeParameters=
target5.width=110
target5.x=320
target5.y=150
target6.editor.height=526
target6.editor.width=748
target6.editor.x=0
target6.editor.y=0
target6.height=50
target6.name=Parser
target6.naviview.expanded=false
target6.showInterface=false
target6.type=ClassTarget
target6.typeParameters=
target6.width=80
target6.x=230
target6.y=20