Programmieren–Sommersemester 2015 - Übungsblatt 6

Werbung
Programmieren – Sommersemester 2015
Software-Design und Qualität (SDQ)
https://sdqweb.ipd.kit.edu/wiki/Programmieren
Prof. Dr. Ralf H. Reussner · Philipp Merkle · Kiana Rostami
Übungsblatt 6
Ausgabe: 29.06.2015 – 13:00
Abgabe: 13.07.2015 – 13:00
Bearbeitungshinweise
• Achten Sie darauf nicht zu lange Zeilen, Methoden und Dateien zu erstellen1
• Programmcode muss in englischer Sprache verfasst sein
• Kommentieren Sie Ihren Code angemessen: So viel wie nötig, so wenig wie möglich
• Wählen Sie geeignete Sichtbarkeiten für Ihre Klassen, Methoden und Attribute
• Verwenden Sie keine Klassen der Java-Bibliotheken ausgenommen Klassen der Pakete java.lang und
java.io, es sei denn die Aufgabenstellung erlaubt ausdrücklich weitere Pakete1
• Achten Sie auf fehlerfrei kompilierenden Programmcode1
• Halten Sie alle Whitespace-Regeln ein1
• Halten Sie die Regeln zu Variablen-, Methoden und Paketbenennung ein und wählen Sie aussagekräftige
Namen1
• Halten Sie die Regeln zu Javadoc-Dokumentation ein1
• Nutzen Sie nicht das default-Package1
• Halten Sie auch alle anderen Checkstyle-Regeln ein
Abgabemodalitäten
Die Praktomat-Abgabe wird am Montag, den 6. Juli, freigeschaltet. Geben Sie die Java-Klassen als *.javaDateien ab. Laden Sie die Terminal-Klasse nicht mit hoch.
Planen Sie für die Abgabe ausreichend Zeit ein, sollte der Praktomat Ihre Abgabe wegen einer Regelverletzung ablehnen.
Fehlerbehandlung
Ihr Programm soll auf ungültige Benutzereingaben mit einer aussagekräftigen Fehlermeldung reagieren.
Aus technischen Gründen muss eine Fehlermeldung unbedingt mit Error, beginnen. Eine Fehlermeldung führt nicht dazu, dass das Programm beendet wird; es sei denn, die nachfolgende Aufgabenstellung
verlangt dies ausdrücklich. Achten Sie inbesondere auch darauf, dass unbehandelte RuntimeExceptions,
bzw. Subklassen davon—sogenannte Unchecked Exceptions—nicht zum Abbruch des Programms führen.
1 Der
Praktomat wird die Abgabe zurückweisen, falls diese Regel verletzt ist.
Programmieren – Sommersemester 2015
A
29.06.2015 – 13:00
Expertensystem (20 Punkte + 4 Bonuspunkte)
Terminal-Klasse
Laden Sie für diese Aufgabe die Terminal-Klassea von unserer Homepage herunter und platzieren Sie
diese unbedingt im Paket edu.kit.informatik. Die Methode Terminal.readLine() liest eine Benutzereingabe von der Konsole und ersetzt System.in. Die Methode Terminal.printLine() schreibt eine
Ausgabe auf die Konsole und ersetzt System.out. Verwenden Sie für jegliche Konsoleneingabe oder
Konsolenausgabe die Terminal-Klasse. Verwenden Sie in keinem Fall System.in oder System.out.
Fehlermeldungen werden ausschließlich über Terminal.printLine() ausgegeben und müssen aus technischen Gründen unbedingt mit Error, beginnen.
Laden Sie die Terminal-Klasse niemals zusammen mit Ihrer Abgabe hoch.
a https://sdqweb.ipd.kit.edu/lehre/SS15-Programmieren/Terminal.java
Tagtäglich treffen wir eine Vielzahl an Entscheidungen, abhängig von unserer Umgebung, persönlichen Vorlieben
und weiteren Faktoren. Das beginnt schon mit der Entscheidung per Fuß, Fahrrad, Straßenbahn, Bahn, oder
mit dem PKW zum Campus zu gelangen. Abbildung 1 illustriert einen solchen Entscheidungsprozess. In diesem
Beispiel fließen Informationen über den momentanen Standort und die Wetteraussichten in die Entscheidung
ein. Ist der aktuelle Standort benachbart zum Campus, ist es am einfachsten zu Fuß zu gehen. Ist der aktuelle Standort hingegen weiter entfernt, aber immer noch im Gebiet des Karlsruher Verkehrsverbunds (KVV),
kommen abhängig vom Regenrisiko Fahrrad oder Straßenbahn in Frage. Außerhalb des KVV-Gebiets bleibt die
Wahl zwischen Zug und Auto, abhängig von der Entfernung zum nächsten Bahnhof.
Die in Abbildung 1 dargestellten Entscheidungsmöglichkeiten bezeichnet man als Entscheidungsbaum. Um
zu einer Entscheidung zu gelangen, startet man bei der zuoberst dargestellten Wurzel, beantwortet die darin
stehende Frage und verfolgt denjenigen Zweig, der mit der gegebenen Antwort beschriftet ist. Dies setzt man
so lange fort, bis man bei einem Blatt ankommt—einem Knoten, von dem aus keine weiteren Zweige ausgehen.
In einem solchen Blatt steht schließlich die Entscheidung, die zu den soeben gegebenen Antworten passt.
Solche Entscheidungsbäume können eingesetzt werden, um ein Expertensystem aufzubauen. Ein Expertensystem kann als Ersatz für einen menschlichen Experten dienen, indem es dessen Fachwissen abbildet. Das
Expertensystem stellt seinem Benutzer eine Reihe von aufeinander aufbauenden Fragen, um schließlich eine
fundierte Antwort zu liefern. Beispielsweise könnte ein medizinisches Expertensystem eine Reihe von Symptomen abfragen und als Antwort die wahrscheinlichsten Krankheitsursachen ausgeben.
Standort?
Campusnähe
Fuß
Innerhalb
KVV-Gebiet
Außerhalb
KVV-Gebiet
Regenrisiko?
Gering
Fahrrad
Entfernung Bahnhof?
Hoch
Straßenbahn
Nah
Bahn
Fern
PKW
Abbildung 1: Entscheidungsbaum zur Bestimmung eines Verkehrsmittels
Seite 2 von 8
Programmieren – Sommersemester 2015
29.06.2015 – 13:00
Ihre Aufgabe ist es, ein einfaches Expertensystem zu programmieren, das auf einem Entscheidungsbaum basiert. Der Entscheidungsbaum wird in einer Eingabedatei beschrieben und beim Programmstart übergeben.
Das Expertensystem stellt dem Benutzer eine Folge von Fragen und wartet jeweils auf eine Antwort des Benutzers, bevor—abhängig von der Antwort—die nächste Frage gestellt wird. Schließlich wird dem Benutzer eine
Entscheidung zurückgeliefert, die von den dessen Antworten abhängt. Diesen Programmablauf veranschaulicht
Abschnitt A.4.5.
A.1
Bäume und Entscheidungsbäume
Die im Folgenden eingeführten Begriffe sind zum besseren Verständnis zusätzlich in Abbildung 2 veranschaulicht.
Ein Baum ist ein gerichteter Graph mit genau einem Wurzelknoten. Ein Wurzelknoten besitzt als einziger
Knoten keine eingehende Kante. Ausgehend von der Wurzel ist jeder Knoten eines Baums auf genau einem Pfad
erreichbar (mit Ausnahme der Wurzel). Jede Kante zeigt von einem Elternknoten auf einen Kindknoten. Knoten
ohne Kinder werden als Blätter bezeichnet. Alle anderen Knoten bezeichnen wir als innere Knoten.
Ein Entscheidungsbaum ist ein spezieller Baum, dessen Knoten und Kanten beschriftet sind:
• Die Beschriftung eines inneren Knoten bezeichnen wir als Frage.
• Die Beschriftung einer Kante bezeichnen wir als Antwort.
• Die Beschriftung eines Blattes bezeichnen wir als Entscheidung.
In dieser Aufgabe trägt jeder Knoten zusätzlich eine eindeutige Identifikationsnummer (id), d.h. zwei verschiedene Knoten dürfen nicht die selbe Identifikationsnummer tragen.
A.2
Serialisierung eines Entscheidungsbaums
Unter einer Serialisierung verstehen wir im Rahmen dieser Aufgabe die textuelle Repräsentation eines Entscheidungsbaums: ein Format, um einen Entscheidungsbaum in eine Datei zu speichern bzw. aus einer Datei
auszulesen.
Eine gültige Serialisierung besteht aus drei oder mehreren Zeilen: einer Wurzel und mindestens zwei Kindknoten.
Jede Zeile beschreibt einen Knoten und—falls vorhanden—dessen eingehende Kante.
Die erste Zeile beschreibt die Wurzel:
<Identifikationsnummer>;<Knotenbeschriftung>
Standort?
(id=1)
(Wurzel-)Knoten
Campusnähe
Kante
Fuß
(id=2)
(Blatt-)Knoten
Entscheidung
Innerhalb
KVV-Gebiet
Frage
Regenrisiko?
(id=3)
Gering
Fahrrad
(id=4)
Antwort
Außerhalb
KVV-Gebiet
Entfernung Bahnhof?
(id=6)
Hoch
Straßenbahn
(id=5)
Nah
Bahn
(id=7)
Fern
PKW
(id=8)
Abbildung 2: Bestandteile eines Entscheidungsbaums am Beispiel von Abb. 1
Seite 3 von 8
Programmieren – Sommersemester 2015
29.06.2015 – 13:00
<Identifikationsnummer> ist ein Integer größer oder gleich 0. <Knotenbeschriftung> ist ein String, der
durch den regulären Ausdruck [a-zA-Z_?]+ beschrieben ist. Fragezeichen und Unterstriche gehören somit zu
den erlaubten Zeichen.
Alle weiteren Zeilen beschreiben jeweils einen inneren Knoten oder ein Blatt. Im Folgenden kürzen wir diesen
Knoten mit k ab.
<Identifikationsnummer>;<Knotenbeschriftung>;<Elternknoten-Id>;<Kantenbeschriftung>
<Identifikationsnummer> bezeichnet die Identifikationsnummer von k und ist ein Integer größer oder gleich
0. <Knotenbeschriftung> bezeichnet die in k gespeicherte Frage oder Entscheidung und ist ein String, der
durch den regulären Ausdruck [a-zA-Z_?]+ beschrieben ist. <Elternknoten-Id> bezeichnet die Identifikationsnummer des Elternknoten von k und ist ein Integer größer oder gleich 0. <Kantenbeschriftung> bezeichnet
die in der eingehenden Kante von k gespeicherte Antwort und ist ein String, der durch den regulären Ausdruck
[a-zA-Z_]+ beschrieben ist.
Zur Vereinfachung der Eingabeverarbeitung gilt darüber hinaus, dass alle Zeilen (mit Ausnahme der ersten
Zeile) so sortiert sind, dass ein Elternknoten stets vor seinen Kindknoten steht. Die Ausgabereihenfolge dieser
Kindknoten ist jedoch beliebig.
A.3
Kommandozeilenargumente
Ihr Programm nimmt als erstes und einziges Kommandozeilenargument einen Pfad auf eine Textdatei entgegen.
Diese Datei beschreibt einen Entscheidungsbaum und ist nach dem in Abschnitt A.2 eingeführten Format
aufgebaut.
Zum Einlesen einer Datei beachten Sie den Hinweis im Anhang.
Tritt beim Verarbeiten des Kommandozeilenarguments ein Fehler auf, so wird eine Fehlermeldung ausgegeben
und das Programm beendet sich mittels System.exit(1) .
A.4
Interaktive Benutzerschnittstelle
Nach dem Start nimmt Ihr Programm über die Konsole mittels Terminal.readLine() vier Befehle entgegen.
Nach Abarbeitung eines Befehls wartet das Programm auf weitere Befehle, bis das Programm irgendwann durch
quit beendet wird.
A.4.1
decide-Befehl
Der decide-Befehl startet einen Entscheidungsprozess. Ein Entscheidungsprozess ist ein Dialog zwischen dem
Programm und seinem Benutzer. Der Dialog beginnt, indem das Programm die im Wurzelknoten gespeicherte
Frage auf die Konsole ausgibt. In jeweils einer weiteren Zeile gibt das Programm alle auf diese Frage möglichen
Antworten auf die Konsole aus. Das Programm wartet nun auf eine Benutzereingabe zur Auswahl einer Antwort.
Sobald der Benutzer eine gültige Eingabe getätigt hat, verfolgt das Programm die zur Eingabe passende Kante
und arbeitet mit dessen Zielknoten bzw. Kindknoten weiter: die im Kindknoten gespeicherte Frage wird auf
die Konsole ausgegeben, zusammen mit den möglichen Antworten. Wieder wartet das Programm auf eine
Benutzereingabe zur Auswahl einer Antwort. Dieser Dialog wird so lange fortgesetzt, bis der Kindknoten ein
Blatt ist. Dann gibt das Programm die im Blatt stehende Entscheidung auf die Konsole aus. Ein solcher Dialog
ist in Abschnitt A.4.5 veranschaulicht.
Tätigt der Benutzer während des Dialogs eine unzulässige Eingabe, wird eine Fehlermeldung ausgegeben und
das Programm verlangt die Eingabe erneut. Die Frage bzw. mögliche Antworten wird jedoch nicht erneut
ausgegeben.
Während eines laufenden decide-Dialogs wird dieser Befehl nicht akzeptiert.
Seite 4 von 8
Programmieren – Sommersemester 2015
29.06.2015 – 13:00
Eingabeformat Der Befehl besitzt keine Parameter, so dass kein Eingabeformat spezifiziert wird.
Ausgabeformat einer Frage mit Antworten
<Fragetext>
[<Antwort-Id>] <Antworttext> (eine Zeile je möglicher Antwort bzw. je Kindknoten)
<Fragetext> ist die Beschriftung des Frageknotens. <Antworttext> ist die Beschriftung einer vom Frageknoten
ausgehenden Kante k. <Antwort-Id> ist die Identifizierungsnummer des Knotens, der von der ausgehenden
Kante k getroffen wird.
Eingabeformat einer Antwort
<Antwort-Id>
<Antwort-Id> ist—wie soeben definiert—die Identifizierungsnummer des Knotens, der von der ausgehenden
Kante k getroffen wird.
Ausgabeformat einer Entscheidung
Decision: <Entscheidungstext>
<Entscheidungstext> ist die Beschriftung des Entscheidungsknoten.
A.4.2
serialise-Befehl
Der serialise-Befehl serialisiert den beim Programmstart eingelesenen Entscheidungsbaum und gibt diesen
auf die Konsole aus2 . Dazu wird das in Abschnitt A.2 beschriebene Format genutzt.
Während eines laufenden decide-Dialogs wird dieser Befehl nicht akzeptiert.
Eingabeformat Der Befehl besitzt keine Parameter, so dass kein Eingabeformat spezifiziert wird.
Ausgabeformat Siehe Abschnitt A.2.
A.4.3
node-Befehl
Der node-Befehl gibt Informationen über einen bestimmten Knoten auf die Konsole aus.
Während eines laufenden decide-Dialogs wird dieser Befehl nicht akzeptiert.
Eingabeformat
node <Identifikationsnummer>
<Identifikationsnummer> ist die Identifikationsnummer des Knotens, zu dem Informationen zurückgeliefert
werden sollen.
Ausgabeformat
<Knotenart>;<Knotentext>;<Kinderanzahl>
<Knotenart> ist entweder Question , falls es sich bei dem angegebenen Knoten um einen inneren Knoten
handelt, oder Decision , falls es sich um einen Blattknoten handelt. <Knotentext> ist die Beschriftung des
angegebenen Knoten. <Kinderanzahl> ist die Anzahl der Kindknoten des angegebenen Knotens.
A.4.4
quit-Befehl
Dieser Befehl beendet das Programm. Dabei findet keine Konsolenausgabe statt.
Beachten Sie, dass dieser Befehl auch während eines laufenden decide-Dialogs akzeptiert wird.
2 Es
wird keine Punkte dafür geben, bei diesem Befehl einfach die eingelesene Datei auszugeben.
Seite 5 von 8
Programmieren – Sommersemester 2015
A.4.5
29.06.2015 – 13:00
Beispielinteraktionen
Beachten Sie im Folgenden, dass Eingabezeilen mit dem > -Zeichen eingeleitet werden, gefolgt von einem Leerzeichen. Diese beiden Zeichen sind ausdrücklich kein Bestandteil des eingegebenen Befehls, sondern dienen nur
der Unterscheidung zwischen Ein- und Ausgabe.
Das Beispiel aus Abbildung 1 wird im Folgenden leicht angepasst, weil das Eingabeformat weder Leerzeichen
noch Umlaute zulässt. Leerzeichen wurden durch Unterstriche ersetzt; Umlaute und ß durch deren Umschreibung
ae, oe, ue bzw. ss. Bindestriche entfallen.
Dialog am Beispiel von Abbildung 1
> decide
Standort?
[2] Campusnaehe
[3] Innerhalb_KVV_Gebiet
[6] Ausserhalb_KVV_Gebiet
> 6
Entfernung_Bahnhof?
[7] Nah
[8] Fern
> 7
Decision: Bahn
> quit
Eine mögliche Serialisierung des (angepassten) Beispiels aus Abbildung 1
> serialise
1;Standort?
6;Entfernung_Bahnhof?;1;Ausserhalb_KVV_Gebiet
7;Bahn;6;Nah
8;PKW;6;Fern
3;Regenrisiko?;1;Innerhalb_KVV_Gebiet
4;Fahrrad;3;Gering
5;Strassenbahn;3;Hoch
2;Fuss;1;Campusnaehe
> quit
node-Befehl am (angepassten) Beispiel aus Abbildung 1
> node 3
Question;Regenrisiko?;2
> quit
Beachten Sie bei obigem Beispiel, dass es eine Vielzahl an gültigen Serialisierungen gibt.
Seite 6 von 8
Programmieren – Sommersemester 2015
A.5
A.5.1
29.06.2015 – 13:00
Bonusaufgaben
frequency-Befehl (2 Bonuspunkte)
Sie können bis zu 2 Bonuspunkte erhalten, wenn Sie diesen Befehl implementieren. Geben Sie diese Erweiterung
zusammen mit Ihrem Programm ab; eine separate Abgabe ist nicht vorgesehen.
Der frequency-Befehl gibt für einen bestimmten Knoten auf die Konsole aus, wie häufig dieser Knoten seit
Programmstart als Antwort in einem decide-Dialog ausgewählt wurde. Entspricht dieser Knoten dem Wurzelknoten, gibt dieser Befehl stattdessen zurück, wie viele decide-Dialoge durchgeführt wurden.
Während eines laufenden decide-Dialogs wird dieser Befehl nicht akzeptiert.
Eingabeformat
frequency <Identifikationsnummer>
<Identifikationsnummer> ist die Identifikationsnummer des Knotens, dessen Auswahlhäufigkeit zurückgeliefert werden sollen.
Ausgabeformat
<Auswahlhäufigkeit>
<Auswahlhäufigkeit> ist ein Integer größer oder gleich 0 und gibt an, wie häufig dieser Knoten seit Programmstart als Antwort in einem decide-Dialog ausgewählt wurde.
A.5.2
probability-Befehl (2 Bonuspunkte)
Sie können bis zu 2 Bonuspunkte erhalten, wenn Sie diesen Befehl implementieren. Geben Sie diese Erweiterung
zusammen mit Ihrem Programm ab; eine separate Abgabe ist nicht vorgesehen.
Der probability-Befehl berechnet das Verhältnis der Auswahlhäufigkeit (vergleiche Abschnitt A.5.1) eines
bestimmten Knotens zur Gesamtanzahl durchgeführter decide-Dialoge. Wurde der decide-Dialog häufig aufgerufen, ergibt sich daraus die Wahrscheinlichkeit, dass ein Benutzer im Verlauf eines decide-Dialogs einen
bestimmten Knoten passieren wird (anders ausgedrückt, dass der Benutzer Antworten wählt, die zu diesem
Knoten führt).
Dieser Befehl ist erst zulässig, nachdem der decide-Dialog mindestens ein mal ausgeführt wurde.
Während eines laufenden decide-Dialogs wird dieser Befehl nicht akzeptiert.
Eingabeformat
probability <Identifikationsnummer>
freq = 4
prob = 100%
Standort?
(id=1)
Campusnähe
freq = 1
prob = 25%
Fuß
(id=2)
Innerhalb
KVV-Gebiet
Außerhalb
KVV-Gebiet
Regenrisiko?
(id=3)
freq = 2
prob = 50%
Gering
freq = 2
prob = 50%
Fahrrad
(id=4)
Entfernung Bahnhof?
(id=6)
Hoch
Straßenbahn
(id=5)
Nah
Bahn
(id=7)
freq = 1
prob = 25%
Fern
PKW
(id=8)
freq = 1
prob = 25%
Abbildung 3: Beispiel mit Auswahlhäufigkeiten (freq) und den sich daraus ergebenden Auswahlwahrscheinlichkeiten (prob) je Knoten. Für Knoten ohne Annotation ist die Anzeigehäufigkeit = 0.
Seite 7 von 8
Programmieren – Sommersemester 2015
29.06.2015 – 13:00
<Identifikationsnummer> ist die Identifikationsnummer des Knotens, dessen Auswahlwahrscheinlichkeit zurückgeliefert werden sollen.
Ausgabeformat
<Auswahlwahrscheinlichkeit>%
<Auswahlwahrscheinlichkeit> ist eine ganze Zahl zwischen 0 und 100; es wird auf die nächstkleinere ganze
Zahl abgerundet. Beachten Sie auch das abschließende Prozent-Zeichen.
Anhang: Zeilenweises Lesen einer Datei
Sie dürfen folgendes Code-Beispiel benutzen, um in einer Schleife die Zeilen aus einer gegebenen Datei auszulesen. Für die Fehlermeldungen wurden Konstanten benutzt, die Sie definieren und anpassen müssen. Das TODO
markiert die Stelle, an der Sie Ihren Code zum Verarbeiten der Zeile einhängen können. Schauen Sie zur Verarbeitung der Zeile die API-Dokumentation der String-Klasse3 an. Beachten Sie insbesondere die split-Methode.
Die für die Eingabe verwendeten Klassen finden Sie im Paket java.io4 .
public static void main(String[] args) {
if (args.length != 1) {
System.out.println(USAGE);
System.exit(1);
}
FileReader in = null;
try {
in = new FileReader(args[0]);
} catch (FileNotFoundException e) {
System.out.println(ERROR_MESSAGE);
System.exit(1);
}
BufferedReader reader = new BufferedReader(in);
try {
String line = reader.readLine();
while (line != null) {
// TODO: process line here
line = reader.readLine();
}
} catch (IOException e) {
System.out.println(ERROR_MESSAGE);
System.exit(1);
}
}
3 http://docs.oracle.com/javase/7/docs/api/java/lang/String.html
4 http://docs.oracle.com/javase/7/docs/api/java/io/package-summary.html
Seite 8 von 8
Herunterladen