Programmieren 2 SoSe 2022
Assignment 4
Ihre Abgabe muss aus einer einzelnen zip-Datei bestehen, die den Quellcode und ggf. ein PDF-Dokument bei Freitextaufgaben enthält. Beachten Sie, dass Dateien mit Umlauten im Dateinamen nicht hochgeladen werden können. Entfernen Sie die daher vor der Abgabe die Umlaute aus dem Dateinamen. Überprüfen Sie nach Ihrer Abgabe, ob der Upload erfolgreich war. Bei technischen Problemen, wenden Sie sich an Patric Plattner oder Dennis Stanke. Es wird eine Plagiatsüberprüfung durchgeführt. Gefundene Plagiate führen zum Ausschluss von der Veranstaltung. In dieser Veranstaltung wird ausschließlich die Java/JavaFX Version 17 verwendet. Code und Kompilate anderer Versionen sind nicht zulässig. Ihre Abgaben sollen die vorgegebenen Dateinamen verwenden. Wiederholter Verstoß gegen diese Regel kann zu Punktabzügen führen.
Info
Ab dieser Woche werden die Aufgabenstellungen offener sein, als in den Vorwochen. Wir wollen Ihnen die Möglichkeit geben, mehr eigene Problemlösungen zu finden, statt nach Anleitung zu Programmieren. Deshalb möchten wir Sie dazu ermutigen, sich zunächst eigene Gedanken zu einer Aufgabenstellung zu machen. Sollten Sie weiterhin Hilfe brauchen, wenden Sie sich bitte an das Stud.IP Forum der Übungsveranstaltung oder an die Online Sprechstunde.
Wir möchten Ihnen nahelegen, Ideen für die Bearbeitung von offeneren Aufgaben im Forum zu diskutieren. Das Posten von Lösungen zu Fragen und Codeausschnitten generell ist verboten, lediglich das Besprechen von Lösungsansätzen ist erlaubt.
Aufgabe 1: Labyrinth
In dieser Aufgabe sollen Sie ein Labyrinth in einer objekt-orientierten Denkweise modellieren und implementieren. Darüber hinaus sollen Sie ein Spiel implementieren, in dem Sie durch das Labyrinth gehen müssen, welches über die Kommandozeile gesteuert werden kann.
Schreiben Sie für alle Klassen, Methoden und Member-Variablen, die Sie erstellen oder ändern, JavaDoc Kommentare. Halten Sie sich an die JavaDoc Konventionen aus Assignment 3. Arbeiten Sie weiterhin in einer Packagestruktur mit dem gemeinsamen root package maze. Das bedeutet, dass Sie alle Klassen die Sie in dieser Aufgabe erstellen in das Package maze oder in Subpackages von maze legen sollen.
Wir wollen Sie auch noch vor der Aufgabe darauf hinweisen, dass diese Aufgabe sehr offen ist und von Ihnen abverlangt, dass sie kreative Problemlösung betreiben. Demnach werden wir in der Bewertung auch kulant sein, wenn Ihre Lösung nicht ganz den Anforderungen der Aufgabe entspricht, uns ist wichtig, dass Sie eigenständig Lösungen zu den Problemen entwickeln.
a) Modellieren Sie ein Labyrinth-Spiel in einem objektorientierten Stil. In dieser Aufgabe soll noch kein spielbares Spiel implementiert werden, sondern nur Klassen mit den Methoden um dieses Spiel spielen zu können. Das Labyrinth soll folgende Vorgaben erfüllen:
- Ein Spielfeld soll aus Tiles in einem Koordinatensystem bestehen. Es sollen mindestens die Tiles “Wand” und “Boden” existieren.
– (Optional) Implementieren Sie auch besondere Tiles, die besondere Effekte haben. Diesee Effekte sind nicht vorgegeben, aber hier sind ein paar Vorschläge:
∗ Der Spieler bewegt sich nun doppelt so schnell.
∗ Der Spieler bekommt Bonus-/Minuspunkte (falls Sie ein Punktesystem implementieren) ∗ Der Spieler kann für X Züge durch Wände laufen.
∗ Der Spieler bekommt ein “Game Over”, falls er auf dieses Tile tritt.
- Es soll einen Startpunkt und (mind.) einen Endpunkt auf einem Spielfeld geben.
- Ein Spieler soll sich über das Spielfeld bewegen können. Wie sich der Spieler über das Spielfeld bewegt ist nicht vorgegeben.
- (Optional) Sie können ein Punktesystem implementieren, sodass bestimmte Aktionen Punkte vergeben und bestimmte Aktionen Punkte abziehen.
– (Optional) Sie könnten dafür Beispielsweise Sammelgegenstände auf der Karte platzieren um Punkte zu sammeln.
- Der Spieler startet auf dem Startpunkt des Spielfelds und das Spiel endet, wenn der Spieler das Ziel erreicht.
– (Optional) Das Spiel könnte auch enden, wenn der Spieler auf bestimmte Felder tritt um ein Game Over zu bekommen.
Hier ein paar Tipps und Vorschläge zur Implementierung:
- Sie können die Vorgaben wie eine ToDo Liste verwenden um sicherzustellen, dass Sie die Vorgaben erfüllt haben.
- Machen Sie sich, bevor Sie anfangen zu programmieren, über folgende Aspekte Gedanken:
- – Was für Spielregeln wollen Sie verfolgen (z.B. was ihr spezielles Tile ist, oder ob Sie ein Punktesystem haben)?
- – Machen Sie sich eine Liste der verschiedenen Variablen, die den Zustand des Spiels ausmachen. Zum Zustand gehören alle Variablen, die sich während des Spiels durch Nutzereingaben ändern können.
- Überlegen Sie sich, wie Sie das Spielfeld modellieren wollen. Wie wollen Sie das Layout des Spielfeldes intern in der Klasse repräsentieren? Wie wollen Sie das Interface der Klasse gestalten, sodass Sie die Implementierungsdetails verstecken.
– Versuchen Sie möglichst wenig Spiellogik auf dem Spielfeld zu implementieren, sondern dem Spielfeld nur Eigenschaften zu geben, die die Spiellogik abfragen kann um Entscheidungen zu treffen. Beispiel: Die Logik, dass ein Spieler nicht in Wände laufen kann sollte nicht auf dem Spielfeld implementiert werden, aber das Spielfeld kann Auskunft darüber geben, ob auf eine Koordinate gelaufen werden darf.
• Überlegen Sie sich, wie sie den Zustand des Spiels auf Objekte/Klassen aufteilen wollen. Bedenken Sie, dass objektorientierter Stil bedeutet, dass Sie den Zustand des Programms nicht gesammelt an einem Ort (einer Klasse/einem Objekt) haben, sondern, dass Sie den Zustand in Klassen abkapseln.
Sie werden zwar keinen komplexen oder großen Zustand haben, aber denken Sie dennoch nach, wie Sie den Zustand in mehreren Klassen abkapseln können.
ein paar konkrete Vorschläge, wie Sie dieses Projekt anfbauen können:
Erstellen Sie eine Spielfeld Klasse, die das Layout des Spielfelds vorgibt.
Erstellen Sie die Klassen, die den Zustand des Spiels darstellen. Ein Beispiel für eine solche Klasse wäre die Player Klasse, die Informationen wie die Koordinaten, auf denen der Spieler steht, und evtl. eine Blickrichtung des Spielers, enthalten kann.
Erstellen Sie eine GameController Klasse, die das Zusammenspiel zwischen Spielfeld und den Zus- tandsklassen gerwährleistet. Diese Klasse soll dann auch alle Methoden zum Steuern des Spiels im Interface anbieten.
b) In der letzten Teilaufgabe haben Sie das Spiel implementiert und so gestaltet, dass Sie nun Methoden in bestimmten Klassen haben, sodass Sie das Spiel im Code steuern können. Erstellen Sie nun eine Klasse mit einer main Methode, in der Sie die nötigen Objekte erstellen um das Spiel spielen zu können und gestalten Sie ein Kommandozeileninterface, mit der das Spiel gespielt werden kann. Ein Beispiel, wie das Aussehen könnte, finden Sie im Anhang.
In dieser Woche sollen Sie ihre Implementierung für die Videothek Aufgabe aus der letzten Woche erweitern. Sollten Sie diese letzte Woche nicht bearbeitet haben, oder anderweitig damit Probleme gehabt haben, können Sie eine Musterlösung zu Assign- ment 3 im Stud.IP Dateibereich der Übung herunterladen (zu finden in VideoRental2.zip).
Schreiben Sie für alle Klassen, Methoden und Member-Variablen, die Sie erstellen oder ändern, JavaDoc Kommentare. Halten Sie sich an die JavaDoc Konventionen aus Assignment 3. Arbeiten Sie weiterhin in einer Packagestruktur mit dem gemeinsamen root package video_rental. Das bedeutet, dass Sie alle Klassen die Sie in dieser Aufgabe erstellen in das Package video_rental oder in Subpackages von video_rental legen sollen.
Wir wollen Sie auch noch vor der Aufgabe darauf hinweisen, dass diese Aufgabe sehr offen ist und von Ihnen abverlangt, dass sie kreative Problemlösung betreiben. Demnach werden wir in der Bewertung auch kulant sein, wenn Ihre Lösung nicht ganz den Anforderungen der Aufgabe entspricht, uns ist wichtig, dass Sie eigenständig Lösungen zu den Problemen entwickeln.
a) Sie haben in den letzten Wochen an zwei sehr ähnlichen Klassen gearbeitet: der DVD und CD Klasse. Ihnen wird wahrscheinlich schon aufgefallen sein, dass es sich dabei um zwei in weiten Teilen identische Klassen handelt. Refactoren Sie ihren Code so, dass es eine Klasse Medium gibt, von welcher DVD und CD erben (Refactoring bedeutet so viel wie Umschreiben und Umstrukturieren von Code).
Zur Erinnerung, die Klassen DVD und CD sollten in den vorangehenden Assignments folgende Eigenschaften haben:
• Den Titel des Gegenstandes
• Den Verleihpreis des Gegenstandes • Ob der Gegenstand im Angebot ist • Den rabattierten Preis
• EinepublicStringstr()Methode.
Darüber hinaus sollten in der Aufgabe aus dem dritten Assignment folgende Eigenschaften hinzugefügt werden:
• Eine Altersbeschränkung (In Form eines FSK Enums für DVDs und eines Explicit-Labels für CDs) • Mediumsspezifische Genres.
• Ob das Objekt ausgeliehen ist.
In diesem Assignment sollen Sie nun folgende Eigenschaften hinzufügen oder ändern: • Eine eindeutige ID für jedes Medium (als String)
– Hinweis: Die folgenden Spezifikationen zu der MBID und IMDb ID müssen Sie in diesem Assignment noch nicht prüfen, das kommt erst im Folgenden Assignment. Noch dürfen rein theoretisch beliebige Strings als Identifier benutzt werden.
– Eine CD soll eine MusicBrainz ID (MBID) haben (https://musicbrainz.org/doc/MusicBrainz_ Identifier)
– Eine DVD soll eine IMDb ID haben.
∗ Die IMDb ID bekommen Sie, indem Sie auf die IMDb Seite eines Filmes oder einer Serie gehen und in die URL schauen; Der Teil hinter “/title/” ist die IMDb ID dieses Mediums
∗ Als Beispiel: Die IMDb URL von dem Film Arrival ist https://www.imdb.com/title/tt2543164/ und die IMDb ID von Arrival ist tt2543164
- Eine CD soll nicht einfach nur einen “Titel” haben, sondern einen “Namen” und einen “Künstler”. Der Titel setzt sich dann aus dem “Namen” und dem “Künstler” zusammen. Beispiel: Künstler: “Radiohead”, Name: “In Rainbows” → Titel: “Radiohead - In Rainbows”.
- Ein Medium soll in der public String str() explizit angeben, um welchen Medientyp (z.B. DVD oder CD) es sich handelt, sollten Sie das die letzten Wochen noch nicht gemacht haben.
Die Medium Klasse soll auch sinnvolle Konstruktoren und Methodenimplementierungen haben und soll dazu genutzt werden, Medien abbilden zu können, die keine spezielle Subklasse haben wie beispielsweise Bücher. Dazu einige weitere Vorgaben und Hinweise
- Auch die Medium Klasse soll einen Medientypen haben. In der CD und DVD Klasse ist dies durch die Klasse vorgegeben, in der Medium Klasse hingegen hängt dies vom Objekt ab.
- Die ID für ein generisches Medium muss keiner Konvention folgen und kann ein beliebiger String sein.
Versuchen Sie bei dem erstellen der Medium Klasse so so viele Methoden wie möglich in dieser Klasse zu vere- inheitlichen und besondere Implementierungen von Methoden und zusätzliche Attribute in den Subklassen zu hinzuzufügen oder zu überschreiben.
Wichtig: Es gibt mehrere richtige Lösungen. Bitte versuchen Sie sich Gedanken zu machen, wie Sie dieses Problem am besten lösen können und modellieren Sie ihre Lösung so, wie Sie es für sinnvoll erachten. Sprechen Sie sich dabei bitte mit ihren Kommili- tonen ab um interessante Ideen für Ihre Implementierung aufzuschnappen (solange Sie keinen konkreten Code abschreiben). Solange die Tutoren merken, dass Sie sich Gedanken um ihre Modellierung der Vererbungsstruktur gemacht haben, indem Sie Fragen beant- worten können, weshalb Sie bestimmte Entscheidungen getroffen haben, werden Sie diese Teilaufgabe bestehen, also machen Sie das, was Sie für sinnvoll erachten.
b) Fügen Sie eine Klasse BluRay hinzu, welche von Medium erbt. Die BluRay Klasse soll erstmal dieselben Eigenschaften haben, die eine DVD hat, mit folgenden Unterschieden:
- Eine BluRay hat den Medientyp “BluRay”
- Da der Medientyp im Vergleich zur DVD recht neu ist, darf eine BluRay maximal um 20% rabattiert werden.
(Also beispielsweise darf eine BluRay, die 10e kostet nicht auf weniger als 8e rabattiert werden)
c) Sie haben in den vergangenen Assignments mehrere Methoden der Form public String str() erstellt um eine String-Repräsentation eines Objektes darzustellen. Implementieren Sie diese Methoden stattdessen als überschreiben der public String toString() Methode von der Object Klasse und ändern Sie entsprechend den Rest ihres Codes. Bedenken Sie dabei, dass toString() Javas Standardmechanismus zur Stringkonversion ist und damit einige Methoden garnicht benötigen, dass sie ein Objekt explizit in einen String umwandeln (Beispiel System.out.println()). Insbesondere sollen Sie auch für die Customer Klasse eine toString() Methode implementieren.
Aufgabe 3: Debugging
In diesen Aufgaben werden Sie einen fehlerhaften Java Codeabschnitt bekommen. Diese Fehler können syn- taktisch oder semantisch sein. Es kann sich dabei um Compiler- oder Laufzeitfehler handeln. Sie dürfen den Code kompilieren und ausführen um die Fehler zu finden. Arbeiten Sie in der Template-Datei Debug.java (zu finden in Debug03.zip). Diese finden Sie im Stud.IP. Nutzen Sie Kommentare, um die Fehler zu Kennzeichnen. Gegeben ist der folgende Codeabschnitt:
debug.Debug
1 package debug;
import debug.model.*;
2 public class Debug { public static void Animal[] animals animals[0] = new animals[1] = new animals[2] = new
3 main(String[] args) {
= new Animal[3]; Animal("Kangaroo Bob", 2, 2); Dog("Barks");
Monkey("King Kong");
4 for (int i = 0; i < animals.length; ++i) {
5 System.out.println(animals[i]);
6 } }
7 }
debug.Animal
1 package debug;
2 public class Animal { private String name_; private int legs_; private int arms_;
3 Animal(String name, int legs, int arms) { this.name_ = name;
this.legs_ = legs;
this.arms_ = arms;
4 }
5 Animal(String name) { this(name, 0, 0);
6 }
7 public String getName() { return this.name_;
8 }
9 public int getArms() { return this.arms_;
10 }
11 public int getLegs() { return this.legs_;
12 }
13 @Override
public String toString() {
14 return String.format("%s is an animal with %d legs and %d arms.", this.getName(), ?→ this.getLegs(), this.getArms());
15 } }
debug.model.Dog
1 package debug.model;
public class Dog extends Animal{
2 public Dog(String name) { super(name);
3 @Override
public String getName() {
4 return super.name_; }
5 @Override
public int getArms() {
6 return 4; }
7 @Override
public int getLegs() {
8 return 4; }
9 @Override
public String toString() {
10 return String.format("%s is a dog with %d legs and %d arms.", this.getName(), ?→ this.getArms(), this.getLegs());
11 }
12 }
debug.model.Monkey
1 package debug.model; import debug.Animal;
2 public class Monkey extends Animal { public Monkey(String name) {
3 super(name);
4 @Override
public String getName() {
5 return super.name_; }
6 @Override
7 public int getArms() {
8 return 2;
9 }
10 @Override
11 public int getLegs() {
12 return 2;
13 }
14 26 @Override
15 27 public String toString() {
16 28 return String.format("%s is a monkey with %d legs and %d arms.", this.getName(),
17 this.getLegs(), this.getArms());
a) Der Codeabschnitt enthält ca. 4 Fehler. Kompilieren und führen Sie den Code aus. Suchen Sie anhand der Fehlermeldungen des Compilers oder der Laufzeitfehlermeldungen Fehler im Code und korrigieren Sie diese. Kommentieren Sie am Ende der jeweiligen Zeile, was Sie korrigiert haben.