Übungen zur Lehrveranstaltung
"Programmierkurs Java"
WS 1999/2000
FB Informatik
D. Boles
Übungsblatt 13
Ausgabe: 02.02.1999
Aufgabe 46 (Pakete): 25 Punkte
Schauen Sie sich die Klassen des JDK (Java Developer Kit) an. Sie finden die Paketbeschreibungen in vielen Büchern oder auch online bspw. auf dem Sun-Java-Server unter
http://java.sun.com:80/products/jdk/1.1/docs/api/packages.html.Schreiben Sie folgende Programme, indem Sie existierende Klassen des JDK nutzen:
(1) Schreiben Sie ein Programm, das berechnet, wieviele Minuten Sie aktuell alt sind (siehe Klassen
java.util.Calendar und java.util.Date).(2) Schreiben Sie ein Programm, das die Ziehung einer Lottozahl (Zahl zwischen 1 und 49) realisiert (siehe Klasse
java.util.Random).(3) Schreiben Sie ein Programm, das drei Integer-Objekte einliest, sie jeweils auf einen Stack legt und anschließend in der umgekehrten Reihenfolge wieder auf den Bildschirm ausgibt (siehe Klassen
java.lang.Integer und java.util.Stack).(4) Schreiben Sie ein Programm, das fünf String-Objekte einliest, sie in einem Vector-Objekt speichert und sie anschließend wieder auf dem Bildschirm ausgibt (siehe Klassen
java.lang.String und java.util.Vector).(5) Schreiben Sie ein Programm, das einen double-Wert vom Benutzer einliest und den sinus, cosinus und tangens sowie die Quadratwurzel auf dem Bildschirm ausgibt (siehe Klasse
java.lang.Math)Aufgabe 47 (Abstrakter Datentyp / Zugriffsrechte): 25 Punkte
In einem Programm soll ein abstrakter Datentyp
Uhrzeit verwendet werden. Dieser soll Uhrzeitwerte bis zum Sekundenbereich verwalten.Schreiben Sie eine Klasse, welche diesen ADT implementiert. Wählen Sie jeweils geeignete Zugriffsrechte für die Variablen und Methoden!
Auf dem Datentypen Uhrzeit sollen folgende Funktionen möglich sein:
a) Initialisieren eines neuen Uhrzeit-Objektes. Werte für Stunden, Minuten und Sekunden werden als Parameter angegeben.
b) Initialisieren eines neuen Uhrzeit-Objektes mit einem bereits existierenden (Copy-Konstruktor).
c) Clonieren eines Uhrzeit-Objektes (Überschreiben der geerbten Methode
clone von Object)d) Überprüfung, ob zwei Uhrzeit-Objekte identische Uhrzeiten repräsentieren (Überschreiben der geerbten Methode
equals von Object).e) Abfragen der Stunde einer Uhrzeit.
f) Erzeugen eines neuen Uhrzeit-Objektes durch Addition zweier existierender Uhrzeiten.
g) Addieren einer Minute zu einer Uhrzeit.
h) Konvertieren eines Uhrzeit-Objektes in einen String in der Form XX:XX:XX. (Überschreiben der geerbten Methode
toString von Object)i) Die Konstante "zwölf Uhr mittags".
Schreiben Sie ein kleines Testprogramm für den ADT
Uhrzeit, in dem alle Methoden der Klasse mindestens einmal aufgerufen werden!.Aufgabe 48 (Metamorphose-Spiel): 25 Punkte
Im Idealfall würde ein Spielprogramm folgendermaßen vorgehen: Zu einer gegebenen Stellung sucht es alle legalen Züge ("Denktiefe 1"). Dann sucht es für alle diese Züge jeweils alle möglichen Antwortzüge ("Denktiefe 2"), dann darauf wieder alle möglichen Antwortzüge ("Denktiefe 3"), usw. Jener (erste) Zug, bei dem alle möglichen Antworten zum Gewinn führen, wird ausgeführt. Angenommen, in einer Stellung sind durchschnittlich 15 Züge möglich. Dann ist die Zahl der Antwortzüge auf diese Züge 152 = 225 Züge. Die Zahl der Züge wäre dann 15Denktiefe. Soll unser Programm eine Denktiefe von nur 6 Zügen haben, d.h. jeder Spieler zieht 3 mal, so müßte es schon 156 = 11 Millionen Züge ausprobieren und diese Bedenkzeit wächst mit jeder zusätzlichen Denktiefe um das fünfzehnfache! Dies ist nicht mehr vollständig in akzeptabler Zeit zu berechnen.
Die meisten Spielprogramme arbeiten in etwa folgendermaßen: Für eine vorgegebene Denktiefe (z.B. 4) werden alle möglichen Zugfolgen berechnet. Die danach entstandenen Stellungen werden bewertet und dieser Wert als Wert der jeweiligen Zugfolge zurückgegeben. Der Zug, der die "beste" Bewertung der Zugfolge bekommt, wird als nächster Zug ausgewählt.
Schreiben Sie eine rekursive Methode
findeBestenSpielzug, die zu einem Spieler, der am Zug ist, zu einem gegebenen Brett, und einer Denktiefe den "besten" Zug (aus der Sicht des Programms) findet und ihn (zusammen mit einer Bewertung) zurückliefert. Dieser Zug kann dann von der Methode liefereNaechstenSpielzug Ihres Programms (siehe Aufgabe 41) zurückgeliefert werden. Die Methode ist bei geschickter Programmierung wesentlich kürzer, als Sie auf den ersten Blick denken mögen! Sie arbeitet folgendermaßen:Falls die Denktiefe den Wert 0 erreicht hat, wird der Stellungsbewerter aus Aufgabe 45 aufgerufen.
Ansonsten werden für den ziehenden Spieler alle legalen Züge ermittelt. Dann werden für alle diese legalen Züge jeweils folgende Anweisungen durchgeführt:
Das Brett wird kopiert, der Zug auf der Kopie ausgeführt und das entstandene Brett bewertet. Letzteres geschieht, indem die Methode
findeBestenSpielzug sich selber rekursiv aufruft (!), dann natürlich mit dem anderen Spieler am Zug und einer um eins verringerten Denktiefe. Falls dieser Zug besser war als der bisher beste (oder es der erste war, der probiert wurde), wird der Zug und die zugehörige Bewertung gemerkt.Wenn alle Züge so durchprobiert wurden, ist der beste Zug gefunden. Dieser wird von der Methode
findeBestenSpielzug zurückgegeben.Die Bewertung, wann ein Zug besser ist als ein anderer, folgt dem sogenannten Minimax-Prinzip, das an einem Beispiel verdeutlicht werden soll (das Prinzip ist auch für andere Spiele als Metamorphose gültig und wird hier nur skizziert): In der Ausgangsstellung (siehe Abb. 1) sei Spieler A am Zug. Es soll gezeigt werden, wie die fettgedruckten Stellungswerte von unten nach oben ermittelt werden. Das Prinzip ist, daß sich der Wert eines Zuges aus den Werten aller möglichen Antwortzüge ergibt, oder, falls die vorgegebene Denktiefe erreicht wurde, aus dem Wert des Stellungsbewerters.

Abb.1: Spielbaum
Spieler A habe in der fiktiven Ausgangsstellung drei legale Züge: 6D, 7A und 8B. Wenn er 6D ziehen würde, hätte Spieler B darauf zwei legale Antwortzüge: 6E oder 3C. Auf den ersten Zug davon hat Spieler A wieder zwei Zugmöglichkeiten: 6F oder 7A. Diese werden nun mit dem Stellungsbewerter bewertet (die fest vorgegebene Denktiefe ist hier 3). Der Stellungsbewerter ermittele für die nach der Zugfolge 6D-6E-6F entstandene Stellung den Wert 1 (fettgedruckte Zahl), die nach der Zugfolge 6D-6E-7A den Wert 3. Da Spieler A immer den besten Zug machen möchte und eine größere Zahl eine bessere Stellung für Spieler A verspricht, würde Spieler A, falls vorher 6D-6E gezogen würde, Zug 7A wählen, also den Zug, der die meisten Punkte ergibt. Aus der nach 6D-6E entstandenen Stellung heraus kann Spieler A nun im besten Fall einen Zug machen, der eine Stellung mit Wert 3 erlaubt. Dies ist damit auch der Wert des Zuges 6E für Spieler B in der darüberliegenden Ebene! Dort versucht Spieler B natürlich eine Stellung mit möglichst kleiner Zahl zu erreichen, d.h. er wählt den Zug, gegen den Spieler A den schlechtesten Antwortzug hat! Nun wird also zunächst der Wert für den Zug 3C ermittelt. Der beste Zug, den Spieler A nach Ausführung von 6D-3C machen kann, ergibt eine Stellung mit dem Wert 6 und ist deshalb schlechter für Spieler B. Also wählt Spieler B den Zug, dessen Antwort nur maximal 3 Punkte zuläßt: 6E. Dies ist dann wiederum auch der Wert des allerersten Zuges für Spieler A: 6D. Spieler A versucht nun wiederum, den Stellungswert zu maximieren. Die Werte für die anderen Züge mögen mit dem gleichen Verfahren 2 und 0 ergeben. Diese sind alle kleiner, also schlechter für Spieler A. Deshalb wird Spieler A letztendlich den ersten Zug, nämlich 6D als den besten Zug wählen. Dies ist das Ergebnis der
findeBestenSpielzug-Methode und wird zusammen mit dem Wert 3 zurückgeliefert. Jetzt zeigt sich, wie gut Ihr Stellungsbewerter arbeitet! Ergeben zwei Züge den gleichen Wert, so ist es egal, für welchen man sich entscheidet. Hier könnte allerdings auch ein Zufallszahlengenerator entscheiden, so daß Ihre findeBestenSpielzug-Methode auch mal andere, gleichwertige Züge findet.Machen Sie sich klar, daß jeder Teilbaum einen rekursiven Aufruf der Methode
findeBestenSpielzug mit verändertem Brett und veränderter Denktiefe darstellt und nur die Blätter einen Aufruf des Stellungsbewerters darstellen. Lassen Sie sich durch die Rekursion nicht verwirren. Wählen Sie zum Testen kleine Denktiefen (<4)! Falls die Rechenleistung es zuläßt, können Sie die Denktiefe erhöhen.Verbesserung: Diese Suchmethode, die ja alle Zugmöglichkeiten beachtet, wird in der Praxis "brute-force", Methode der brutalen Gewalt, genannt. Durch die Technik "alpha-beta-pruning", die gewisse Teile des Spielbaumes ausläßt, läßt sich die Geschwindigkeit drastisch erhöhen.
Tip: Verbessern Sie Ihr Programm auf die Art und Weise, daß Sie inkrementell jeweils zwei Versionen entwickeln, diese gegeneinander antreten lassen, die schlechtere verwerfen und die bessere weiter verbessern. Oder lassen Sie Ihre Programme zum Test einfach gegen die Programme Ihrer Kommilitonen antreten.
Aufgabe 49 (Metamorphose-Spiel / Pakete / Zugriffsrechte): 25 Punkte
Organisieren Sie Ihr Metamorphose-Spiel als Paket und passen Sie die Zugriffsrechte Ihrer Variablen und Methoden an. Beachten Sie folgendes:
/user/fb10/dibo/java/dibo/metamorphose/bin/metamorphose X.Y <gegner>.
Das heißt, hier wird immer der volle Klassennamen verlangt.
Wenn Sie kein eigenes Metamorphose-Spiel entwickelt haben, nehmen Sie bitte die in Aufgabe 40 zur Verfügung gestellten Klassen als Grundlage!