Beispiel Angabe

Kürzel:asciishop-A10-PP
Name:AsciiShop, Runde#10
Kette:Asciishop PP
Kategorie:Bldverarbeitung

Mitgelieferte Datei(en): Metric.java
Abzugebende Datei(en): BinaryOperation.java, ClearFactory.java, LoadOperation.java, FactoryException.java, AsciiPoint.java, AsciiImage.java, AsciiShop.java, LoadFactory.java, SaveOperation.java, SaveFactory.java, SearchOperation.java, SearchFactory.java, BinaryFactory.java, AverageOperation.java, FilterFactory.java, OperationException.java, Factory.java, Operation.java, CreateFactory.java, CreateOperation.java, UniqueCharsMetric.java, PixelCountMetric.java, MetricSet.java, MedianOperation.java, FilterOperation.java, ClearOperation.java, ReplaceFactory.java, ReplaceOperation.java
Optional abzugebende Datei(en): FillFactory.java, TransposeFactory.java, FillOperation.java, GrowRegionFactory.java, CircularBlockGenerator.java, BlockGenerator.java, XBlockGenerator.java, ReplicateBlockGenerator.java, AsciiStackNode.java, AsciiStack.java, GrowRegionOperation.java, SymmetricBlockGenerator.java, LineFactory.java, TransposeOperation.java, LineOperation.java
Ausführbar: AsciiShop

Die Klasse AsciiShop ist zu erstellen und soll eine ausführbare Klasse sein und muss daher die public static void main(String[] args) Methode beinhalten. Ihr Programm wird automatisch auf Korrektheit überprüft. Die Überprüfung erfolgt durch die Ausführung der als ausführbar bezeichneten Klasse (AsciiShop).

Kurzbeschreibung:

Zusätzlich zur den bisherigen Operationen des AsciiShop soll es nun auch möglich sein Bilder zur späteren Wiederverwendung in einer eigenen Collection zu sichern.

Lernziele:

Aufgabenstellung Klassen und Methoden Ein- und Ausgabedaten Bewertung und Kriterien
Hinweise FAQ Fehlerbehandlung Testen

 

Aufgabenstellung:

In dieser letzten Übungsrunde nutzen wir die Interfaces Factory und Operation um dem AsciiShop weitere Operationen hinzuzufügen. Diese sollen die Speicherung eines Bildes und das Suchen unter den gespeicherten Bilder ermöglichen. Zur Verwaltung gespeicherter Bilder wird eine spezielle eigens definierte Collectionklasse MetricSet benutzt. Die Aufgabe besteht aus mehreren Schritten:

Erweitern von LinkedHashSet

Die vordefinierte Klasse java.util.LinkedHashSet ist eine Implementierung einer Menge (Interface Set). Anders als bei Listen, haben Elemente eines Sets keine fixe durch einen Index bestimmte Reihenfolge (es gibt spezielle Sets deren Elemente geordnet sind, jedoch nicht über einen Index). Außerdem können nicht mehrere gleiche Elemente hinzugefügt werden. Genauer gesagt: ein Objekt kann nur hinzugefügt werden, wenn nicht bereits ein Objekt gibt, das diesem Objekt gleicht (die Gleichheit wird dabei mit der Methode equals geprüft). Der Vorteil von Sets sind schnelle Mengenoperationen, Sortierung und Suche nach Elementen.

Die Klasse LinkedHashSet<E> soll nun derart erweitert werden, dass die Suche nach ähnlichen Objekten im Set möglich wird. Dazu wird ein Distanzmaß, auch Metrik genannt, benötigt. Eine entsprechende Metrik wird durch das vorgegebene Interface Metric<E> festgelegt. Unterschiedliche Implementierungen von Metric<E> ermöglichen eine Suche anhand unterschiedlicher Bildmerkmale (siehe untenstehende Beschreibung).

Die folgenden Befehle sind zulässig, neue und veränderte Befehle sind farblich hervorgehoben, nicht mehr geforderte durchgestrichen:

Befehle und Operationen am Bild

weitere Befehle

Alle hier aufgeführten Befehle können in beliebiger Reihenfolge auftreten. So kann zum Beispiel nach dem ersten Befehl create erst print, danach load und danach wieder create folgen. Alle genannten Befehle haben entsprechende Klassen, die die Funktionalität implementieren.

 

Klassen und Methoden:

Die folgende Aufzählung umfasst geforderte Methoden, neue, veränderte und geerbte Methoden sind farblich hervorgehoben, gegenüber der Vorrunde nicht mehr geforderte durchgestrichen. Sie können nach Bedarf Hilfsmethoden und Methoden für freiwillige Aufgaben (Bonusaufgaben, Übungsaufgaben) hinzufügen. Achten Sie auf die korrekte Datenkapselung. Insbesondere sollen Sie sinnvolle Zugriffsmodifikatoren für Variablen (und Methoden) verwenden.

AsciiShop
Diese Klasse ist ausführbar und beinhaltet daher die main-Methode. Sie verarbeitet die Eingaben, erzeugt das AsciiImage und gibt das Ergebnis aus. Methoden dieser Klasse lesen direkt von System.in ein und geben direkt auf System.out aus.
public static void main(String[] args)
liest die Daten und Befehle ein und gibt das Ergebnis aus.
AsciiImage
Diese Klasse repräsentiert ein ASCII-Bild, es speichert die Zeichen des Bildes und bietet entsprechende Methoden zur Modifikation und zur Abfrage von Eigenschaften, wie beispielsweise Höhe und Breite.
public AsciiImage(int width, int height, String charset)
erzeugt ein ASCII-Bild der spezifizierten Größe und mit dem angegebenen Zeichensatz. Anfangs sind alle Pixel auf den Wert hellsten Wert des Zeichensatzes (also dem letzten Zeichen des Strings) gesetzt. Überprüfen Sie an diese Stelle ob Breite und Höhe beide größer 0 sind und werfen Sie andernfalls eine IllegalArgumentException. Werfen Sie auch eine IllegalArgumentException, falls das charset ein Zeichen doppelt enthält oder gar keine Zeichen umfasst.
public AsciiImage(AsciiImage img)
ist ein Kopierkonstruktor. Er erzeugt ein neues AsciiImage mit dem gleichen Inhalt, wie das übergebene Bild.
public String getCharset()
gibt den Zeichensatz des Bildes als String zurück.
public int getHeight()
gibt die Höhe des Bildes (die Anzahl der Zeilen) zurück.
public char getPixel(int x, int y)
gibt das an den übergebenen Koordinaten/Indizes gespeicherte Zeichen zurück. Überprüfen Sie an dieser Stelle, ob die Indizies gültig sind und werfen Sie andernfalls eine IndexOutOfBoundsException.
public char getPixel(AsciiPoint p)
gibt, analog zur Methode public char getPixel(int x, int y), das Zeichen, an der durch p spezifizierten Stelle, zurück. Überprüfen Sie an dieser Stelle, ob die Indizies gültig sind und werfen Sie andernfalls eine IndexOutOfBoundsException.
public ArrayList<AsciiPoint> getPointList(char c)
gibt eine ArrayList aller Pixel eines bestimmten Zeichens zurück. In dieser ArrayList sind Objekte vom Typ AsciiPoint, sollte es keine Punkte mit dem angegebenen Zeichen geben, so soll eine leere Liste zurückgegeben werden. Verwenden Sie diese Methode überall dort, wo sie alle Pixel mit einem bestimmten Zeichen benötigen.
public int getWidth()
gibt die Breite des Bildes (die Länge der Zeilen) zurück.
public void setPixel(int x, int y, char c)
speichert an den übergebenen Koordinaten/Indizes das übergebene Zeichen. Überprüfen Sie an dieser Stelle, ob die Indizies gültig sind und werfen Sie andernfalls eine IndexOutOfBoundsException. Werfen Sie eine IndexOutOfBoundsException, falls das Zeichen c nicht dem Zeichensatz des Bildes entspricht (sprich nicht im charset enthalten ist).
public void setPixel(AsciiPoint p, char c)
speichert, analog zur Methode public char setPixel(int x, int y, char c), das übergebene Zeichen an der durch den p spezifizierten Stelle. Überprüfen Sie an dieser Stelle, ob die Indizies gültig sind und werfen Sie andernfalls eine IndexOutOfBoundsException. Werfen Sie eine IndexOutOfBoundsException, falls das Zeichen c nicht dem Zeichensatz des Bildes entspricht (sprich nicht im charset enthalten ist).
public String toString()
gibt eine lesbare Darstellung des ASCII-Bildes zurück. Die einzelnen Zeilen sollen dabei durch Zeilenumbrüche ‘\n’ getrennt werden.
public boolean equals(Object o)
Vergleicht das angegebene Bild mit diesem Bild und liefert true wenn Höhe und Breite übereinstimmen und der Pixelwert an jeder Position des angegebenen Bildes mit dem in diesem Bild übereinstimmt. Ansonsten wird false geliefert.
public int hashCode()
liefert den Hashcode diese Bildes, der der Summe der ASCII Codes aller Zeichen im Bild entspricht.
public int getUniqueChars()
liefert die Anzahl unterschiedlicher Zeichen im Bild zurück (Methode aus Runde 4).
AsciiPoint
Diese Klasse repräsentiert einen Punkt, spezifiziert durch zwei ganzzahlige Koordinaten. Diese Klasse ist unveränderlich (immutable), sprich die Koordinaten sollen nachträglich nicht mehr veränderbar sein. Stellen Sie dies durch den Einsatz geeigneter Modifier sicher.
public AsciiPoint(int x, int y)
erzeugt einen Punkt mit den angegebenen Koordinaten.
public int getX()
gibt die x-Koordinate des Punktes zurück.
public int getY()
gibt die y-Koordinate des Punktes zurück.
public String toString()
gibt eine lesbare Darstellung des Punktes in der Form (x,y) zurück.
AsciiStack
Diese Klasse implementiert einen Stack (vgl. Stapelspeicher), der seine Größe dynamisch anpasst. Er kann eine beliebige Anzahl an AsciiImage-Objekten speichern, wobei der Zugriff immer nur auf das oberste Element möglich ist. Sie können eine ihrer Implementierung dieser Klasse (ggfs. zusammen mit AsciiStackNode) aus den Vorrunden nutzen oder die vorgefertigte Klasse java.util.Stack verwenden.
public AsciiStack()
initialisiert den leeren Stack.
public boolean empty()
überprüft, ob zumindest ein Element am Stack liegt.
public AsciiImage pop()
gibt das oberste Element am Stack zurück und entfernt dieses. Liegt kein Element am Stack, so soll null zurückgegeben werden. Sind nach dem Entfernen mehr als increment Plätze leer, so soll der Stack um increment verkleinert werden. Jedoch soll der Stack nie kleiner als increment sein, sprich wenn alle Elemente entfernt wurden, soll die Kapazität des Stacks gleich increment sein.
public AsciiImage peek()
gibt das oberste Element am Stack zurück ohne es zu entfernen. Liegt nichts am Stack, so soll null zurückgegeben werden.
public void push(AsciiImage img)
legt ein AsciiImage oben auf den Stack. Ist der Stack zu diesem Zeitpunkt voll, so soll der Stack um increment vergrößert werden um so das Bild speichern zu können.
public int size()
gibt die Anzahl der im Stack belegten Plätze zurück.
Metric<T>
Ein Interface für eine Metrik (oder Halbmetrik) im mathematischen Sinn. Die Methode distance berechnet die (halb-)metrische Distanz zwischen zwei Argumenten.
public int distance(T o1, T o2)
Diese Distanzfunktion kann als Maß für die Ähnlichkeit der beiden Argumente benutzt werden. Bei der Implementierung müssen folgende Eigenschaften dieser Distanzfunktion sichergestellt werden:
  1. Semidefinitheit: distance(x,y) >= 0. Es sollte außerdem gelten: distance(x,y) == 0, wenn x.equals(y). Zu beachten ist, dass distance(x,y) == 0 auch dann erfüllt sein kann, wenn !x.equals(y) erfüllt ist (Halbmetrik).
  2. Symmetrie: distance(x,y) == distance(y,x)
  3. Dreiecksungleichung: distance(x,y) <= distance(x,z) + distance(z,y)
PixelCountMetric implements Metric<AsciiImage>
Eine einfache Metrik für Bilder, die Bildgrößen vergleicht.
public int distance(AsciiImage i1, AsciiImage i2)
liefert den Absolutbetrag der Differenz der Bildgrößen von i1 und i2. Mit Bildgröße ist das Produkt von Höhe mal Breite des Bildes gemeint.
UniqueCharsMetric implements Metric<AsciiImage>
Eine einfache Metrik für Bilder, die die Anzahl unterschiedlicher Zeichen vergleicht.
public int distance(AsciiImage i1, AsciiImage i2)
liefert den Absolutbetrag der Differenz der Anzahl unterschiedlicher Zeichen in einem Bild. Zur Berechnung der Anzahl unterschiedlicher Zeichen eines Bildes kann die Methode getUniqueChars() aus Runde 4 herangezogen werden.
MetricSet<E> extends LinkedHashSet<E>
Diese generische Klasse implementiert ein spezielles Set auf der Basis von LinkedHashSet mit der Besonderheit, dass in dem MetricSet mit Hilfe einer Metrik nach Objekten gesucht werden kann, die einem spezifizierten Objekt ähnlich sind. Beachten Sie dazu das Interface Metric. Die Klasse soll als Erweiterung der Klasse LinkedHashSet<E> definiert werden. Ein LinkedHashSet<E> ist Untertyp von HashSet<E> mit der Besonderheit, dass die Einfügereihenfolge der Elemente erhalten bleibt (siehe Hinweise). Es gibt Methoden, die von der Klasse LinkedHashSet bzw. deren direkten und indirekten Oberklassen geerbt werden und hier nicht explizit angegeben sind. Die für diese Aufgabe nützlichen geerbten Methoden sind im Folgenden angeführt (diese können genutzt werden, Überschreiben ist nicht gefragt). Für eine vollständige Auflistung der Methoden, siehe java.util.LinkedHashSet und Oberklasse java.util.HashSet.
public MetricSet()
initialisiert ein leeres MetricSet.
public MetricSet(Collection<? extends E> c)
initialisiert das MetricSet mit den Elementen aus c.
public MetricSet<E> search(E e, Metric<? super E> m)
liefert ein neues MetricSet zurück, in dem nur die Elemente enthalten sind, die die minimale Distanz zum spezifizierten Element e haben. Das kann auch nur ein Element sein. m ist die Metrik, die als Distanzmaß benutzt werden soll.
public boolean add(E e)
Stellt sicher, dass das spezifizierte Objekt e, in der Menge vorhanden ist. Genauer gesagt: Fügt das Element e dem Set hinzu, wenn es in diesem kein Element e2 gibt, sodass (e==null ? e2==null : e.equals(e2)). Liefert true wenn es hinzugefügt wurde und false wenn ein solches Element bereits vorhanden war.
public boolean addAll(Collection<? extends E> col)
Fügt alle Elemente von col dem Set hinzu. Liefert true wenn das Set dadurch verändert wurde und false, wenn alle Elemente bereits vorhanden waren.
public boolean contains(Object o)
Gibt an, ob das Objekt o in diesem Set enthalten ist, d.h., ob es in diesem Set ein Element e gibt, sodass (o==null ? e==null : o.equals(e)).
public Iterator<E> iterator()
liefert einen Iterator auf dem Set. Der Iterator durchmustert die Elemente des Set in der gleichen Reihenfolge, in der Sie dem Set hinzugefügt wurden.

Die folgenden Klassen dienen zur Umsetzung bestimmter Bildoperationen bzw. der Erzeugen dieser. Die Bildoperationen implementieren das Interface Operation, die erzeugenden Klassen das Interface Factory, entsprechend der weiter unten beschriebenen Interfaces.

AverageOperation extends FilterOperation
Diese Klasse glättet ein Bild mit einem 3x3-Mittelwertfilter.
public AverageOperation()
erzeugt eine neue AverageOperation.
public AsciiImage execute(AsciiImage img)
geerbt von FilterOperation
public int filter(int[] values)
führt mit dem übergebenen Block den Mittelwertfilter aus. Dafür wird das arithmetische Mittel (vgl. Arithmetisches_Mittel) der Helligkeitswerte bestimmt. Das Ergebnis wird mathematisch gerundet und als Ergebnis für diesen Block zurückgegeben.
BinaryFactory implements Factory
Diese Factory erzeugt BinaryOperations.
public BinaryFactory()
erzeugt eine neue BinaryFactory.
public Operation create(Scanner scanner) throws FactoryException
liest mit dem Scanner das Schwellwert Zeichen ein, erzeugt damit eine neue BinaryOperation und gibt diese zurück. Tritt beim Einlesen des Zeichens ein Fehler auf, so wird eine FactoryException geworfen.
BinaryOperation implements Operation
Diese Klasse wandelt ein AsciiImage in ein Binärbild um.
public BinaryOperation(char threshold)
erzeugt eine neue BinaryOperation mit dem entsprechenden Schwellwert.
public AsciiImage execute(AsciiImage img) throws OperationException
gibt ein neues AsciiImage zurück, das das Binärbild des übergebenen AsciiImage ist. Zur Umwandlung in ein Binärbild werden alle Zeichen, die im Zeichensatz des Bildes vor dem Schwellwert kommen, auf das dunkelste Zeichen gesetzt, alle Zeichen ab dem Schwellwert werden auf das hellste Zeichen gesetzt. Sollte das Schwellwertzeichen nicht im Zeichensatz des AsciiImage vorkommen, so wird eine OperationException geworfen.
ClearFactory implements Factory
Diese Factory erzeugt ClearOperations.
public ClearFactory()
erzeugt eine neue ClearFactory.
public Operation create(Scanner scanner)
erzeugt eine neue ClearOperation und gibt diese zurück.
ClearOperation implements Operation
Diese Klasse setzt alle Pixel des Bildes auf das hellste Zeichen.
public ClearOperation()
erzeugt eine neue ClearOperation.
public AsciiImage execute(AsciiImage img)
gibt ein neues AsciiImage zurück, das dem übergebenen AsciiImage entspricht, wobei alle Zeichen auf das hellste Zeichen, sprich dem letzten Zeichen im Zeichensatz des Bildes, gesetzt sind.
FilterFactory implements Factory
Diese Factory erzeugt MedianOperations und AverageOperations.
public FilterFactory()
erzeugt eine neue FilterFactory.
public Operation create(Scanner scanner) throws FactoryException
liest den nächsten String ein und gibt, je nach Parameter, eine neue MedianOperation (bei ‘median’) oder eine neue AverageOperation (bei ‘average’) zurück. Ist der Typ unbekannt, so wird eine FactoryException geworfen.
FilterOperation implements Operation
Diese abstrakte Klasse beinhaltet die Funktionalität, um das Bild zu durchlaufen und für jeden Pixel den benötigten Block an Nachbarpixeln zu bestimmen. Sie bietet mit der Methode filter eine Schablone (Template) für die konkreten Filter Operationen.
public FilterOperation()
Konstruktor der FilterOperation.
public AsciiImage execute(AsciiImage img)
führt den Blockfilter aus. Diese Methode muss von abgeleiteten Klassen nicht überschrieben werden. Die Methode durchläuft das Bild, bestimmt für jeden Pixel den Block an Nachbarpixeln und ruft damit dann die Methode filter auf. Das Ergebnis dieser Methode wird dann als neuer Pixel an der aktuellen Stelle gesetzt.
public abstract int filter(int[] values)
muss von den abgeleiteten Klassen implementiert werden. Sie führt die eigentliche Logik des Filters durch. Das übergebene Array umfasst die Helligkeitswerte der Pixel im Block Zeile für Zeile. Diese Methode gibt den berechneten Helligkeitswert für den neuen Pixel zurück.
LoadFactory implements Factory
Diese Factory erzeugt LoadOperations.
public LoadFactory()
erzeugt eine neue LoadFactory.
public Operation create(Scanner scanner) throws FactoryException
liest den eof-String ein und übergibt in einem String alle Zeilen bis zum abschließenden eof-String durch Zeilenumbrüche getrennt an den Konstruktor der LoadOperation. Tritt beim Einlesen ein Fehler auf (eof fehlt), so wird eine FactoryException geworfen.
LoadOperation implements Operation
Lädt zeilenweise vorliegende Bilddaten in ein AsciiImage.
public LoadOperation(String data)
erzeugt eine neue LoadOperation mit den entsprechenden Bilddaten. Diese Bilddaten liegen als String vor, wobei die Bildzeilen durch Zeilenumbrüche (‘\n’) getrennt sind.
public AsciiImage execute(AsciiImage img) throws OperationException
gibt ein neues AsciiImage zurück, das von Größe und Zeichensatz dem übergebenen AsciiImage entspricht und in das die Daten geladen wurden. Tritt beim Laden ein Fehler auf (zu wenige oder zu viele Daten bzw. ungültige Zeichen), so wird eine OperationException mit einer entsprechenden Fehlermeldung geworfen.
MedianOperation extends FilterOperation
Diese Klasse glättet ein Bild mit einem 3x3-Medianfilter (vgl. Rangordnungsfilter#Medianfilter).
public MedianOperation()
erzeugt eine neue MedianOperation.
public AsciiImage execute(AsciiImage img)
geerbt von FilterOperation
public int filter(int[] values)
führt mit dem übergebenen Block den Medianfilter aus. Die Pixel des Blocks werden nach ihrem Helligkeitswert sortiert. Der Median (also das in der sortierten Liste in der Mitte stehende Zeichen) für diesen Block wird als Ergebnis zurückgegeben.
ReplaceFactory implements Factory
Diese Factory erzeugt ReplaceOperations. Diese Klasse wurde zu Anschauungszwecken vollständig implementiert in Runde 8 zur Verfügung gestellt, sie können diese Klasse jedoch auch selber implementieren.
public ReplaceFactory()
erzeugt eine neue ReplaceFactory.
public Operation create(Scanner scanner) throws FactoryException
liest mit Hilfe des Scanners zwei Zeichen ein und gibt eine damit initialisierte neue ReplaceOperation zurück. Tritt beim Einlesen ein Fehler (zu wenig Parameter), so wird eine FactoryException geworfen.
ReplaceOperation implements Operation
Diese Klasse ersetzt alle Vorkommnisse eines Zeichens in einem Bild durch ein anderes Zeichen. Diese Klasse wurde zu Anschauungszwecken vollständig implementiert in Runde 7 zur Verfügung gestellt, sie können diese Klasse jedoch auch selber implementieren.
public ReplaceOperation(char oldChar, char newChar)
erzeugt eine neue ReplaceOperation die alle Zeichen oldChar durch newChar ersetzt.
public AsciiImage execute(AsciiImage img) throws OperationException
gibt ein neues AsciiImage zurück, in dem alle Vorkommnisse des Zeichen oldChar durch das Zeichen newChar ersetzt worden sind. Falls das neue Zeichen nicht im Zeichensatz des AsciiImage enthalten ist, soll eine neue OperationException mit entsprechender Fehlermeldung geworfen werden.
CreateFactory implements Factory
Diese Factory erzeugt CreateOperation.
public CreateFactory()
erzeugt eine neue CreateFactory.
public Operation create(Scanner scanner) throws FactoryException
liest mit Hilfe des Scanners Breite und Höhe und einen String ein und gibt eine damit initialisierte neue CreateOperation zurück. Tritt beim Einlesen ein Fehler (zu wenig Parameter, falsche Parameter), so wird eine FactoryException geworfen.
CreateOperation implements Operation
public CreateOperation(int width, int height, String charset)
erzeugt eine neue CreateOperation, die ein neues Bild mit angegebener Bildgöße und Zeichensatz erzeugt. Alle Pixel werden mit dem "hellsten" Zeichen, d.h. dem Zeichen mit größten Index in charset initialisiert.
public AsciiImage execute(AsciiImage img) throws OperationException
gibt ein neues AsciiImage zurück. Der Parameter wird ignoriert (beispielsweise kann auch null übergeben werden).
SaveFactory implements Factory
Diese Factory erzeugt SaveOperation.
public SaveFactory(MetricSet<AsciiImage> saved)
erzeugt eine neue SaveFactory. saved ist eine Referenz auf ein MetricSet, dem durch eine SaveOperation Bilder hinzugefügt werden sollen.
public Operation create(Scanner scanner) throws FactoryException
Erzeugt eine neue SaveOperation. .
SaveOperation implements Operation
public SaveOperation(MetricSet<AsciiImage> saved)
erzeugt eine neue SaveOperation. saved ist eine Referenz auf ein MetricSet, in dem die Bilder gespeichert werden sollen.
public AsciiImage execute(AsciiImage img) throws OperationException
speichert das spezifizierte Bild, d.h., stellt sicher, dass das spezifizierte Bild der dem Konstruktor übergebenen Set hinzugefügt wurde (Ist in diesem bereits ein Bild img2, so dass img2.equals(img), oder ist img == null wird kein neues Element hinzugefügt). Die Rückgabe der Methode ist eine Kopie des spezifizierten Bildes img.
public MetricSet<AsciiImage> getSaved()
liefert die Collection mit gespeicherten Bildern.
SearchFactory implements Factory
Diese Factory erzeugt SearchOperation.
public SearchFactory(MetricSet<AsciiImage> saved)
erzeugt eine neue SearchFactory. saved ist eine Referenz auf ein MetricSet, in dem sich die gespeicherten Bilder befinden.
public Operation create(Scanner scanner) throws FactoryException
Erzeugt eine neue SearchOperation. Dazu wird zunächst mit dem angegebenen Scanner ein String eingelesen, der angibt, welche Metrik benutzt werden soll ("pixelcount" oder "uniquechars"). Kann dieser String nicht eingelesen werden, oder ist der eingelesene String unbekannt, wird eine FactoryException geworfen.
SearchOperation implements Operation
public SearchOperation(MetricSet<AsciiImage> saved, Metric<AsciiImage> m)
initialisiert diese SearchOperation mit einer angegebenen Metrik. saved ist eine Referenz auf ein MetricSet, in dem sich die gespeicherten Bilder befinden. m ist die Metrik.
public AsciiImage execute(AsciiImage img) throws OperationException
liefert ein Bild mit minimaler Distanz zum spezifizierten Bild und liefert dieses als Kopie zurück. Gibt es mehrere gespeicherte Bilder mit minimaler Distanz, wird irgendeines dieser Bilder geliefert. Ist saved leer, wird eine OperationException geworfen.

Interfaces und Exceptions.

FactoryException extends Exception
Diese Klasse erweitert Exception und wird zum Behandeln aller Fehlerfälle, die in einer Factory, also beim Einlesen von Parametern oder dem Erzeugen eines Befehls, auftreten, eingesetzt. Sie können bei Bedarf auch noch weitere Konstruktoren definieren.
public FactoryException()
erzeugt eine leere FactoryException. Ruft den entsprechenden Super-Konstruktor in der Klasse Exception auf.
public FactoryException(String message)
erzeugt eine FactoryException mit der entsprechenden Fehlerbeschreibung. Ruft den entsprechenden Super-Konstruktor in der Klasse Exception auf.
Factory
Dieses Interface wird von allen Factories implementiert und definiert die Schnittstelle über die eine Operation bezogen werden kann. Bei Bedarf können Sie dies statt als Interface auch als abstrakte Klasse gestalten. Die Aufgabe der Factory ist es bei Bedarf Eingaben einzulesen und dann eine neue Operation zu erzeugen.
public Operation create(Scanner scanner) throws FactoryException
erzeugt ein neues Objekt vom Typ Operation. Welche konkrete Operation erzeugt wird, hängt von der implementierenden Factory ab. Bei Bedarf liest diese Methode vom übergebenen Scanner Parameter ein. Sollten Parameter fehlen oder von einem falschen Typ sein, so soll eine FactoryException geworfen werden.
OperationException extends Exception
Diese Klasse erweitert Exception und wird zum Behandeln aller Fehlerfälle, die beim Ausführen von Operationen auftreten, eingesetzt. Sie dürfen bei Bedarf auch noch weitere Konstruktoren definieren.
public OperationException()
erzeugt eine leere OperationException. Ruft den entsprechenden Super-Konstruktor in der Klasse Exception auf.
public OperationException(String message)
erzeugt eine OperatiOperationException mit der entsprechenden Fehlerbeschreibung. Ruft den entsprechenden Super-Konstruktor in der Klasse Exception auf.
Operation
Dieses Interface wird von allen Operationen implementiert und definiert eine Methode, die zum Ausführen der Operation dient. Dieses Interface wird zur Verfügung gestellt.
public AsciiImage execute(AsciiImage img) throws OperationException
führt die Operation aus und gibt das Ergebnis als neues AsciiImage zurück. Das übergebene AsciiImage wird von der Methode nicht verändert. Mögliche Parameter der Operation müssen im Konstruktor übergeben werden. Sollte beim Ausführen der Operation ein Fehler auftreten, so soll eine OperationException geworfen werden.

 

Hinweise:

Beachten Sie die allgemeinen Hinweise zur Installation und zur Ein-/Ausgabe, sowie zur Abgabe und zur Beurteilung in den FAQ.

Überschreiben von equals und hashCode

In der Klasse AsciiImage sollen die Methoden equals und hashCode redefiniert werden. Achten Sie auf korrektes Überschreiben (siehe Skriptum, Abschnitt 3.4.3).

Anmerkung zur Reihenfolge der Ausgabe bei printsaved

Es ist gefordert, dass die gespeicherten Bilder beim Befehl printsaved in der Reihenfolge ausgegeben werden, in der sie gespeichert wurden. Im Allgemeinen haben die Elemente eines Set keine Reihenfolge und es gibt keine Listen-Methoden wie first() oder get(index). Weiters ist es nicht sichergestellt, dass der Iterator eines Sets die Elemente in der Einfügereihenfolge liefert. Wenn zur Speicherung der Bilder der Untertyp LinkedHashSet benutzt wird, gibt es zwar auch keine Methode get(index), der Iterator liefert aber die Elemente in Einfügereihenfolge. Dies gilt natürlich auch für MetricSet, da diese Klasse in diesem Beispiel von LinkedHashSet abgeleitet wird und daher der Iterator der Oberklasse benutzt werden kann.

Anmerkung zu Unveränderbarkeit von Elementen eines Set

Die Elemente eines Set sollten unveränderbar sein, da das Verhalten eines Set nicht definiert ist, wenn eingefügte Objekte nachträglich verändert werden. Beispielsweise kann ein verändertes Element doppelt vorkommen (widerspricht der Philosophie eines Set) oder nicht mehr gefunden werden. Im Fall von AsciiImage sind die Elemente zwar veränderbar, jedoch gibt es in diesem Beispiel keine nachträglichen Änderungen am Bild, da jede Bildoperation ein neues Bild zurückliefert (Siehe Beschreibung des Interface Operation). Daher ist die Verwendung eines Set in diesem Beispiel zulässig.

Wenn Sie Fragen zur Implementierung oder auch zu Java haben, können Sie das Informatik-Forum nutzen. Im Rahmen der wöchentlichen Laborien stehen Tutoren für Fragen zur Verfügung.
Informatik-Forum Laborien

 

Eingabedaten:

Der erste Befehl muss create, gefolgt von Breite und Höhe sowie dem Zeichensatz des Bildes sein. Danach können in beliebiger Reihenfolge beliebige viele der oben definierten Befehle folgen. Sie dürfen davon ausgehen, dass die mittels load eingelesenen Bilddaten keine Leerzeichen enthalten. Sie können weiters davon ausgehen, dass die gesamte Eingabe nicht leer ist.

Ausgabedaten:

Bei jedem Aufruf von print soll das aktuell bearbeitete Bild korrekt formatiert und von einer Leerzeile gefolgt, ausgegeben werden. Wird undo eingegeben, so wird, falls der Stack leer ist, "STACK EMPTY" ausgegeben.

Bei jedem Aufruf von printsaved sollen untereinander alle gespeicherten Bilder in der Reihenfolge, in der sie gespeichert wurden, ausgegeben werden. Wurden zuvor keine Bilder gespeichert, soll "NO SAVED IMAGES" ausgegeben werden.

Fehlerbehandlung:

Geben Sie "INPUT MISMATCH" aus und brechen Sie die weitere Verarbeitung ab, falls einer der folgenden Fehler auftritt:

Geben Sie auch "INPUT MISMATCH" aus, falls bei der Erzeugung eines Befehls eine FactoryException auftritt. Geben Sie bei allen Fehlern, die in einer Operation Klasse ausgelöst werden (also bei denen eine OperationException geworfen wird), "OPERATION FAILED" aus und brechen Sie die weitere Verarbeitung ab. Dies sind insbesondere folgende Fälle:

Geben Sie "UNKNOWN COMMAND" aus und brechen Sie die weitere Verarbeitung ab, falls einer der folgenden Fehler auftritt:

Testen:


In
create 20 10 #WMBRXVYIti+=;:,.
load end
....................
........::;:........
.....++=;;=+tXt.....
...:t=:,.,:=+IVM;...
..,It+;:,::=tIVBR,..
..:XYti++++tIVRMB,..
...IBVVYYYYVRBB#I...
....t#BRRBBBBM#i....
......=VW##WV;......
....................
end
save
binary .
save
create 13 7 @8OCoc:.
load +++
.............
....cccoo:...
..cc...coOo..
.:Coc:coCO8:.
..o8OCOOO@o..
...:C8@8C....
.............
+++
save
printsaved
Out
....................
........::;:........
.....++=;;=+tXt.....
...:t=:,.,:=+IVM;...
..,It+;:,::=tIVBR,..
..:XYti++++tIVRMB,..
...IBVVYYYYVRBB#I...
....t#BRRBBBBM#i....
......=VW##WV;......
....................

....................
........####........
.....##########.....
...#####.########...
..################..
..################..
...##############...
....############....
......########......
....................

.............
....cccoo:...
..cc...coOo..
.:Coc:coCO8:.
..o8OCOOO@o..
...:C8@8C....
.............
Beschreibung Zuerst wird ein großes Bild erzeugt und gespeichert. Danach wird daraus ein Binärbild erzeugt und dieses gespeichert. Als drittes Bild wird ein kleineres Bild gespeichert. Danach werden die gespeicherten Bilder durch printsaved ausgegeben.


In
create 20 10 #WMBRXVYIti+=;:,.
load end
....................
........::;:........
.....++=;;=+tXt.....
...:t=:,.,:=+IVM;...
..,It+;:,::=tIVBR,..
..:XYti++++tIVRMB,..
...IBVVYYYYVRBB#I...
....t#BRRBBBBM#i....
......=VW##WV;......
....................
end
save
binary .
save
create 13 7 @8OCoc:.
load +++
.............
....cccoo:...
..cc...coOo..
.:Coc:coCO8:.
..o8OCOOO@o..
...:C8@8C....
.............
+++
save
create 13 7 #WMBRXVYIti+=;:,.
load ***
.............
...,=++tt:...
..++,.,=tXI..
.:Vi+;+iYRB:.
..IMVVVXR#I..
...:YMWMY,...
.............
***
search pixelcount
print
undo
search uniquechars
print
Out
.............
....cccoo:...
..cc...coOo..
.:Coc:coCO8:.
..o8OCOOO@o..
...:C8@8C....
.............

....................
........::;:........
.....++=;;=+tXt.....
...:t=:,.,:=+IVM;...
..,It+;:,::=tIVBR,..
..:XYti++++tIVRMB,..
...IBVVYYYYVRBB#I...
....t#BRRBBBBM#i....
......=VW##WV;......
....................
Beschreibung Zuerst wird ein großes Bild erzeugt und gespeichert. Danach wird aus diesem ein Binärbild erzeugt und dieses gespeichert. Als drittes Bild wird ein kleineres Bild gespeichert. Das erste gespeicherte Bild hat nun 17 unterschiedliche Zeichen, das zweite 2 (Binärbild) und das dritte 8. Nun wird ein weiteres Bild neu erzeugt und als Suchbild benutzt. Zuerst wird ein Bild ähnlicher Grße geliefert, danach ein Bild mit ähnlich vielen unterschiedlichen Zeichen.


Bemerkung: Diese Beispiele dienen nur zur Verdeutlichung der Spezifikation und müssen nicht korrekt formatiert sein. Die korrekte Formatierung entnehmen Sie bitte dem mitgelieferten Outputfile. Zum Testen Ihrer Lösung können Sie aus den mitgelieferten Eingabedaten wie folgt eine Ausgabedatei erzeugen:
java AsciiShop < asciishop-A10-PP.i1 > asciishop-A10-PP.out1

Das erzeugte File asciishop-A10-PP.out1 können Sie dann mit dem mitgelieferten Outputfile asciishop-A10-PP.o1 vergleichen.