Java Plotter - wan15.mnd.thm.dewan15.mnd.thm.de/plotter/cover.pdf · Java Plotter Stephan Euler...

60

Transcript of Java Plotter - wan15.mnd.thm.dewan15.mnd.thm.de/plotter/cover.pdf · Java Plotter Stephan Euler...

Java Plotter

Stephan Euler

TH-Mittelhessen

Fachbereich MND

Version 1.02

10. März 2014

ii

Inhaltsverzeichnis

1 Einleitung 1

2 Plotter 32.1 Erste Beispiele . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.2 Datensätze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.3 Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.4 Verfeinerte Darstellung . . . . . . . . . . . . . . . . . . . . . . . . 12

2.4.1 Linien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.4.2 Farben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142.4.3 Darstellungsbereich und Achsbeschriftung . . . . . . . . . 142.4.4 Löschen von Werten und Texten . . . . . . . . . . . . . . . 152.4.5 Bilder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162.4.6 Ein Plotter ist ein JPanel . . . . . . . . . . . . . . . . . . 162.4.7 Koordinatensystem . . . . . . . . . . . . . . . . . . . . . . 17

3 Beispiele mit Vererbung 193.1 Geometrische Formen . . . . . . . . . . . . . . . . . . . . . . . . . 193.2 Ameisen auf Irrwegen . . . . . . . . . . . . . . . . . . . . . . . . . 24

4 Beispiele mit Quell-Code 29LineStyle Demo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294.1 Maus Demo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304.2 Tic Tac Toe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324.3 Türme von Hanoi . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

5 Anwendungen rund um Plotter 395.1 Klasse Graphic . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395.2 Visualisierung von Sortierverfahren . . . . . . . . . . . . . . . . . 405.3 Plot aus Dateien . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

6 Aufgaben 45

Literaturverzeichnis 54

iii

iv INHALTSVERZEICHNIS

Kapitel 1

Einleitung

Java verfügt über eine umfangreiche Bibliothek von Klassen zur Gra�kprogram-mierung. Der Einstieg ist nicht wirklich schwierig, erfordert aber doch solideGrundkenntnisse. Andererseits ist es sicherlich motivierend, wenn man frühzeitigansprechende gra�sche Darstellungen erzeugen kann. Dieser Gedanke ist der Aus-gangspunkt für das Plotter-Projekt. Ziel ist es, eine möglichst einfache Schnitt-stelle zur gra�schen Programmierung anzubieten. Bereits beim Einstieg in dieProgrammierung sollen erste gra�schen Darstellungen wie z. B. Funktionsverläufeentstehen. Durch entsprechende Aufgaben kann damit der Umgang mit grund-legende Konzepten wie Variablen, Kontrollstrukturen, Methoden und Klassengeübt werden.

Kernstück des Projektes ist die Klasse Plotter. Ein Plotter-Objekt (vereinfachtgesprochen ein Plotter) dient als Hülle um die Zeichenmethoden. Gleichzeitigübernimmt es die Verwaltung der Daten. im einfachsten Fall schickt man einigeWerte an einen Plotter. Der Plotter speichert die Werte intern und erstellt darausautomatisch eine gra�sche Darstellung mit angepassten Wertebereichen.

Über den Schnell-Einstieg hinaus bietet der Plotter allerdings auch vielfältigeMöglichkeiten zur Verfeinerung der Darstellungen. Man kann Texte hinzufügen,Fonts, Zeichenstile und Farben ändern oder sogar Bilder einbauen.

Der Komfort ist allerdings nicht ganz umsonst. Der zusätzliche Rechen- undSpeicheraufwand hält sich meistens in Grenzen und wirkt sich nur bei sehr groÿenDatenmengen störend aus. Schwerwiegender ist, dass in manchen Situationen dieinterne Organisation des Plotters nicht optimal zur Aufgabenstellung passt. EineLösung unter direkter Verwendung der Java-Bibliothek ist dann einfacher. DerPlotter kann � und soll auch gar nicht � die Einarbeitung in die Java 2D-APIersetzen. Aber er bietet einen einfachen Einstieg und soll beim Erlernen von Javahelfen.

1

2 KAPITEL 1. EINLEITUNG

Kapitel 2

Plotter

Die Klasse Plotter bietet einfache Möglichkeiten zur graphischen Darstellung.Dadurch ist es Java-Anfängern möglich, frühzeitig auch ohne entsprechende Spe-zialkenntnisse ansprechende Anzeigen zu realisieren. Der Schwerpunkt liegt weni-ger auf ausgefeilten Darstellungsmöglichen. Vielmehr soll der Einstieg möglichsteinfach und intuitiv sein. Im folgenden werden zunächst anhand einiger Beispieledie prinzipielle Möglichkeiten gezeigt.

2.1 Erste Beispiele

Die Klasse Plotter ist im wesentlichen dazu gedacht, Kurven zu zeichnen. AlsEinstieg zeigt Listing 2.1 eine einfache Klasse mit einer Methode main() zur Dar-stellung der Funktion sin(x) im Bereich [−π, π]. Zur besseren Übersicht sind dieKlassen in mehrere Pakete (Package) eingeteilt. Die direkt zu Plotter gehörendenKlassen �nden sich in einem Paket plotter. Demgegenüber sind die Beispiele ineinem Paket demos zusammen gefasst. Wie in Zeile 1 festgelegt, gehört auch daserste Beispiel zu diesem Paket. Um auf die beiden benötigten Klassen aus demPaket plotter direkt zugreifen zu können, werden sie importiert.

Die eigentliche Verarbeitung erfolgt in der main-Methode. Zunächst wird einObjekt der Klasse Graphic angelegt. Die Klasse Graphic ist von JFrame aus derSwing-Bibliothek abgeleitet. Sie erstellt ein Hauptfenster und darin eingebettetein Plotter-Objekt sowie eine Statuszeile. Man kann einen Plotter auch in eigeneAnwendungen einbauen. Aber zur Vereinfachung übernimmt in unseren Beispie-len das Graphic-Objekt diese Aufgabe. Den implizit erzeugten Plotter erhält manüber eine Getter-Methode.

Nach diesen Vorbereitungen können wir Datenpunkte eingeben. Im Beispielwerden in einer Schleife Werte der Funktion sin(x) mit der Methode add anden Plotter übergeben. Wenn wie in dieser Form nur y-Werte übergeben wer-den, übernimmt der Plotter eine automatische Nummerierung. Die eingegebenen

3

4 KAPITEL 2. PLOTTER

Listing 2.1: Erstes Beispiel

1 package demos ;23 import p l o t t e r . Graphic ;4 import p l o t t e r . P l o t t e r ;56 public class Demo1 {78 public stat ic void main ( St r ing [ ] a rgs ) {9 Graphic graph ic = new Graphic ( "Demo 1" ) ;

10 P l o t t e r p l o t t e r = graphic . g e tP l o t t e r ( ) ;1112 for (double x=−Math . PI ; x<=Math . PI ; x+=0.01) {13 p l o t t e r . add ( Math . s i n (x ) ) ;14 }15 graph ic . r epa in t ( ) ;16 }17 }

Werte werden daher intern zu Wertepaaren in der Form

x y0 sin(−π)1 sin(−π + 0.01)2 sin(−π + 0.02). . . . . .

ergänzt. Sind alle Daten eingegeben, wird mit dem Aufruf der Methode repaint()eine Aktualisierung ausgelöst. Dabei bestimmt der Plotter anhand der vorliegen-den Daten den darzustellenden Bereich und trägt die Punkte dort ein. Bild 2.1zeigt das resultierende Fenster.

Das Beispiel zeigt, wie man mit minimalem Aufwand � einfach durch Ein-tragen von Werten � mit einem Plotter eine graphische Darstellung erhält. Aberselbst bei einfachen Programmierübungen wird man schnell eine verfeinerte Dar-stellung wünschen. Die Klasse Plotter stellt dazu eine ganze Reihe von Methodenzur Verfügung. Ausgehend von unserem ersten Beispiel werden wir einige Mög-lichkeiten durchgehen. Eine umfangreiche Beschreibung der einzelnen Methoden�ndet man in der Dokumentation.

In unserem Beispiel wird durch die automatische Nummerierung als x-Bereich0 bis 628 angegeben. Schöner wäre es, den tatsächlichen Bereich angezeigt zu be-kommen. Dazu muss man lediglich beim Eingeben der Werte die zugehörigen x-Werte mitgeben. Für diesen Fall gibt es eine andere Methode add(double x, double y)

2.2. DATENSÄTZE 5

Abbildung 2.1: Erstes Beispiel für Plotter

mit zwei Parametern. Eine entsprechend geänderte Klasse zeigt Listing 2.2Bei dieser Gelegenheit wird auch der Darstellungsbereich angepasst und die

Achsen werden beschriftet. Im einzelnen werden folgende Erweiterungen vorge-nommen:

• der x-Bereich wird um den Faktor 1.1 vergröÿert

• die Hauptachsen werden eingezeichnet

• für die y-Achse wird eine Unterteilung in Schritten von 0.25 gewählt

• auf der x-Achse sollen die Punkte −π,−π/2, 0, π/2, π markiert werden, dieentsprechenden Werte werden als Feld übergeben.

• für die Beschriftungen an der x-Achse sollen zwei Nachkommastellen ange-zeigt werden, Plotter verwendet das angegeben Format mit der Methodeprintf, um die Achsbeschriftungen zu erzeugen.

Die so ergänzte Darstellung zeigt Bild 2.2

2.2 Datensätze

Im nächsten Schritt soll zusätzlich die Cosinus-Funktion im gleichen Bereich dar-gestellt werden. Um beide Verläufe zu trennen, werden die beiden Datensätzegetrennt gehalten. Eine Möglichkeit ist, nach dem ersten Daten mit der MethodenextVector() den Beginn eines zweiten Datensatzes anzuzeigen. Mit dem Auf-ruf dieser Methode wird automatisch in Plotter ein neuer Datensatz angelegt.

6 KAPITEL 2. PLOTTER

Listing 2.2: Verbesserte Version mit x-Werten und Achsbeschriftungen

1 public stat ic void main ( St r ing [ ] a rgs ) {2 Graphic graph ic = new Graphic ( "Demo 2" ) ;3 P l o t t e r p l o t t e r = graphic . g e tP l o t t e r ( ) ;45 p l o t t e r . setXrange(−Math . PI ∗ 1 . 1 , Math . PI ∗ 1 .1 ) ;6 p l o t t e r . setXLine ( 0 ) ;7 p l o t t e r . setYLine ( 0 ) ;8 p l o t t e r . setAutoYgrid ( 0 . 2 5 ) ;9 double [ ] xgr id = {−Math . PI , −1, 0 , 1 , Math . PI } ;

10 p l o t t e r . setXLabelFormat ( "%.2 f " ) ;11 p l o t t e r . setXGrid ( xgr id ) ;1213 for (double x=−Math . PI ; x<=Math . PI ; x+=0.01) {14 p l o t t e r . add ( x , Math . s i n ( x ) ) ;15 }16 graph ic . r epa in t ( ) ;17 }

Abbildung 2.2: Darstellung durch Klasse Demo2

2.2. DATENSÄTZE 7

Nachfolgende Aufrufe von add werden dann automatisch diesem neuen Daten-satz zugeordnet. Mit den beiden Schleifen zusammen lässt sich dann schreiben:

for (double x=−Math . PI ; x<= Math . PI ; x+=0.01) {p l o t t e r . add ( x , Math . s i n (x ) ) ;

}p l o t t e r . nextVector ( ) ;for (double x=−Math . PI ; x<= Math . PI ; x+=0.01) {

p l o t t e r . add ( x , Math . cos ( x ) ) ;}

Das funktioniert, ist aber nicht besonders elegant. Für eine kompaktere Lösungkann man gezielt Datensätze ansprechen. Dazu wird der Name des Datensatzesals zusätzlicher Parameter beim Aufruf von add angegeben. Aus dem Beispielwird dann

for (double x=−Math . PI ; x<= Math . PI ; x+=0.01) {p l o t t e r . add ( " s i n " , x , Math . s i n ( x ) ) ;p l o t t e r . add ( " cos " , x , Math . cos ( x ) ) ;

}

mit zwei Datensätzen sin und cos. Allgemein gilt:

• zu Beginn wird der interne Zähler für Datensätze auf 0 gesetzt. Der zu-gehörige Datensatz gilt als aktuell, wird aber erst mit dem ersten Zugri�tatsächlich angelegt.

• wechselt man mit der Methode nextVector zu einem anderen Datensatz,gilt dieser als aktuell.

• beim Aufruf von add ohne Bezeichnung wird der aktuelle Datensatz ver-wendet.

• beim Aufruf mit einem Bezeichner für einen Datensatz wird der Wert diesemDatensatz zugeordent. Er übernimmt aber nicht die Position des aktuellenDatensatzes.

• falls der Datensatz noch nicht vorhanden ist, wird er neu angelegt.

• die intern automatisch generierten Datensätze werden fortlaufend numme-riert. Die Zählung beginnt mit 0, beim Aufruf von nextVector() wird dienächstgröÿere freie Zahl gewählt.

Ein Datensatz wird durch eine Instanz der Klasse DataObject repräsentiert.Im wesentlichen besteht er aus einer Folge von Wertepaaren (x, y), ergänzt durchInformationen zur Dartsellung wie Farbe Linienart. Mit folgenden Methoden las-sen sich Wertepaare hinzufügen und löschen:

8 KAPITEL 2. PLOTTER

Methode Funktionsweise

void add( double x, double y) fügt das Wertepaar (x, y) anvoid addD( double dx, double dy) aus dem letzten Wert (x, y) wird (x +

dx, y + dy) berechnet und angehängtvoid removeOld(int n) löscht die ersten n Werte

Um alle Punkte eines Datensatzes gemeinsam zu verschieben, können O�set-Werte für x- und y-Richtung gesetzt werden. Mit den vier Methoden

void setxO�set(double xO�set) double getxO�set()void setyO�set(double yO�set) double getyO�set()

lassen sich die entsprechenden Werte setzen und auch wieder abfragen. In der Re-gel genügen die Methoden in der Klasse Plotter für alle Zugri�e auf die DataObject-Instanzen. Falls doch einmal erforderlich, erhält man mit

DataObject getDataObject ( )DataObject getDataObject ( S t r ing key )

eine Referenz auf das aktuelle oder ein spezielles DataObject.

2.3 Text

Mit der Methode

TextObject setText ( S t r ing s , double x , double y )

wird eine Zeichenkette an eine vorgegebene Position geschrieben. Im folgendenCode-Abschnitt wird als Beispiel der Text Hallo Friedberg sowie die Position (0, 0)verwendet. Zur Orientierung werden zusätzlich die beiden Achsen eingezeichnet.Wie Bild 2.3 zeigt, wird der Text um die angegebene Position zentriert.

// Gröÿe des Fens ters und Dar s t e l l u n g s b e r e i c hp l o t t e r . s e tP r e f e r r e dS i z e ( new Dimension ( 300 , 3 00 ) ) ;p l o t t e r . setRange ( −4, 4 ) ;graph ic . pack ( ) ;

// Linien durch Ursprungp l o t t e r . setXLine ( 0 ) ;p l o t t e r . setYLine ( 0 ) ;

// j e t z t Text e inze i chnenp l o t t e r . setText ( "Hal lo Fr iedberg " , 0 , 0 ) ;

Die Methode gibt eine Referenz auf ein TextObject zurück. Über diese Refe-renz kann man Farbe und Font ändern. Mit

2.3. TEXT 9

Abbildung 2.3: Einfache Ausgabe eines Textes

TextObject t2 = p l o t t e r . setText ( "T E S T" , 0 , 2 ) ;t2 . s e tCo lo r ( Color .BLACK) ;Font font = new Font ( " Ar i a l " , Font .BOLD, 16 ) ;t2 . setFont ( font ) ;

wird ein zweiter Text eingetragen, wobei anschlieÿend Farbe und Font geändertwerden (Bild 2.4). Alternativ könnte man auch bei zwei Varianten von setTextdirekt Farbe oder Farbe und Font angeben.

Jedes Text-Objekt beinhaltet auch die Informationen über seine Farbe undden Font. Beide Informationen lassen sich abfragen und auch dynamisch ändern.Diese Möglichkeit wird in

Font font = new Font ( " Ar i a l " , Font .BOLD, 16 ) ;TextObject t2 = p l o t t e r . setText ( "T E S T" , 0 , 2 ,

Color .BLACK, font ) ;for ( int s i z e =8; s i z e <60; s i z e += 1 ) {

Font f = t2 . getFont ( ) ;t2 . setFont ( f . der iveFont ( ( f loat ) s i z e ) ) ;S leep . s l e e p ( 2 0 0 ) ;graph ic . r epa in t ( ) ;

}

genutzt, um einen Text langsam anwachsen zu lassen. Die Methode sleep aus derHilfsklasse Sleep hält die Anwendung für entsprechend viele Millisekunden an.Damit können einfache Animationen realisiert werden. Ein etwas komplexeresBeispiel dafür ist die folgende Schlangen-Spriale:

10 KAPITEL 2. PLOTTER

Abbildung 2.4: Ausgabe mit vorgegebener Farbe und Font

public void t e x t Sp i r a l e ( ) {Graphic graph ic = new Graphic ( "Schlangen−Sp i r a l e " ) ;P l o t t e r p l o t t e r = graphic . g e tP l o t t e r ( ) ;p l o t t e r . setXLine ( 0 ) ;p l o t t e r . setYLine ( 0 ) ;p l o t t e r . setXrange (−1.25 , 1 . 2 5 ) ;p l o t t e r . setYrange (−1.25 , 1 . 2 5 ) ;

double r = 1 ; // Radiusdouble de l t a = 0 . 1 ; // Abstandint count = 0 ; // Anzahl von "O"−swhile ( r > 0) {

for (double t = 0 ; t < 2 ∗ Math . PI ; t += de l t a ) {p l o t t e r . setText ( "O" ,

r ∗ Math . s i n ( t ) , r ∗ Math . cos ( t ) ) ;r −= 0.1 ∗ de l t a / 2 / Math . PI ;graph ic . r epa in t ( ) ;S leep . s l e e p ( 3 0 ) ;++count ;i f ( count > 15) {

// ä l t e s t e s O durch ∗ e r s e t z enp l o t t e r . removeText ( "O" ) ;p l o t t e r . setText ( "∗" ,

r ∗ Math . s i n ( t − 15 ∗ de l t a ) ,

2.3. TEXT 11

Abbildung 2.5: Beispiel Schlangen-Spirale

r ∗ Math . cos ( t − 15 ∗ de l t a ) ) ;}

}}

}

Die einzelnen Punkte liegen auf einer Archimedischen Spirale. Die Koordinatenwerden gemäÿ den Parametergleichungen

x(t) = a · t · sin(t)y(t) = a · t · cos(t)

berechnet. Zunächst wird jeder Punkt durch ein O markiert. Sobald 15 Punkteerreicht sind (Variable count), werden die ältesten Zeichen wieder entfernt unddurch Sterne ersetzt. Dadurch entsteht der Eindruck einer Schlange, die sichentlang der Spirale bewegt und dabei ihre Bahn markiert. Eine Momentaufnahmeder Anwendung zeigt Bild 2.5.

Die Methode boolean removeText( String text ) entfernt das erste gefundeneTextobjekt mit dem angegebenen Inhalt. Der Wert false wird zurückgegeben,

12 KAPITEL 2. PLOTTER

falls kein solches Objekt gefunden wurde. Falls alle Vorkommen eines Textesgelöscht werden sollen, kann dies in einer Schleife in der Art

while ( p l o t t e r . removeText ( " ha l l o " ) ) {}

erfolgen. Mit removeAllText() werden alle Texte gelöscht. Die Koordinaten x undy des Mittelpunktes können über Getter und Setter abgefragt und neu gesetztwerden. Zur Vereinfachung stehen die beiden Methoden

• void setXY( double x, double y)

• void moveXY( double dx, double dy)

zur Verfügung. Damit werden entweder beide Koordinaten gleichzeitig neu gesetztoder um die angegebenen Werte dx und dy verschoben.

2.4 Verfeinerte Darstellung

Die beschriebenen Möglichkeiten erlauben es, schnell und einfach graphische Dar-stellungen zu erstellen. In vielen Fällen gewinnt allerdings die Darstellung durcheine gezielte Anpassung. Einige Möglichkeiten wurden bereits bei den bisherigenBeispielen gezeigt. In diesem Kapitel werden die in Plotter eingebauten Optionenvorgestellt.

2.4.1 Linien

Standardmäÿig werden die Datenpunkte mit einer Linie verbunden. Über dieMethode setDataLineStyle(LineStyle lineStyle ) können Alternativen gesetzt wer-den. Wie üblich wirkt die Methode auf den aktuellen Datensatz. Bei Bedarf kannin einer zweiten Varianten der Name eines Datensatzes explizit angegeben werden.Die möglichen Stile sind in der Klasse LineStyle de�niert. In der Abbildung 2.6sind für den Datensatz 0, 3, 9, 0 die resultierenden Darstellung zusammen gestellt.Der vollständige Quellcode für das Beispiel ist im Anhang (4.1). Die meisten Stilesollten weitgehend selbsterklärend sein. Ansonsten gilt:

DOT ein einzelner Punkt (Pixel) pro Datenpunkt. Im Beispiel sind die vierPunkt allerdings nur schlecht zu erkennen. Diese Darstellung ist eher sinn-voll, wenn man viele Punkte in der Ebene eintragen möchte (siehe Übung6.8).

SYMBOL der Datenpunkt wird durch einen Kreis repräsentiert. Die Gröÿe derKreise kann mit setSymbolSize(int symbolSize) (Angabe in Pixel) variiertwerden.

2.4. VERFEINERTE DARSTELLUNG 13

Abbildung 2.6: Verschiedene Werte von LineStyle

FILL die Methode �ll der Java-Bibliothekslasse Graphics2D wird auf den durchdie Datenpunkte de�nierten Polygonzug angewendet. Bei einem geschlosse-nen Polygonzug wird das Innere ausgefüllt, ansonsten die Fläche über derx-Achse.

VALUE der y-Wert wird als Zahl an die entsprechende Position geschrieben.

STAR der erste Punkte de�niert den Mittelpunkt, alle folgenden Punkte werdensternförmig durch eine Linie mit diesem Mittelpunkt verbunden.

HIDDEN die Werte werden nicht dargestellt. Damit kann man unsichtbarePunkte setzen, um den Wertebereich zu beein�ussen. Auÿerdem könnenkomplette Datensätze damit leicht aus- und eingeblendet werden.

Das Zeichnen der Linien kann in den zugrundeliegenden Java-Bibliotheksmethodenmittels eines Stroke-Objektes variiert werden. Mit der Methode setDataStroke(Stroke s)kann dementsprechend für jeden Datensatz ein solches Objekt übergeben werden.Beispielsweise wird mit der Anweisung

p l o t t e r . setDataStroke (new Bas icStroke ( 5 . f ) ) ;

die Breite der Linie auf den Wert 5 gesetzt. Die Klasse BasicStroke ist in derJava-Dokumentation beschrieben. Da sie nicht spezi�sch für Plotter ist, wird siehier nicht näher erläutert. Vielmehr beschränken wir uns auf ein weiteres, etwaskomplexeres Beispiel. Im folgenden Code-Abschnitt

f loat [ ] dash = { 20 , 10 , 10 , 10 } ;Stroke s = new Bas icStroke ( 3 . f , Bas i cStroke .CAP_BUTT,

Bas icStroke .JOIN_ROUND, 0 , dash , 0 ) ;p l o t t e r . setDataStroke ( s ) ;

wird durch die Vorgaben in Feld dash eine gestrichelte Linie in der Art (nicht mitexakten Gröÿenverhältnissen) � � � � festgelegt.

14 KAPITEL 2. PLOTTER

2.4.2 Farben

Jeder Datensatz hat eine eigene Farbe. Standardmäÿig wird jedem Datensatzbeim Anlegen eine neue Farbe aus einer Auswahl von derzeit 6 Farben zugewie-sen. Dieses Verhalten wird über eine interne Variable gesteuert. Mit den beidenMethoden

boolean i sAutoIncrementColor ( )void setAutoIncrementColor (boolean autoIncrementColor )

kann die automatische Farbzuweisung geprüft und geändert werden. Wird sieausgeschaltet, so erhalten alle weiteren Datensätze eine feste Standardfarbe. An-sonsten kann mit setDataColor(Color color) die Farbe des aktuellen Datensatzesverändert werden. Im Beispiel

p l o t t e r . setDataColor ( Color .GREEN) ;p l o t t e r . setDataColor ( "c" , new Color (200 ,0 ,0 ) ) ;

wird zunächst für den aktuellen Datensatz mit der Konstanten GREEN aus derKlasse Color die Farbe Grün gewählt. Alternativ kann man ein neues Color-Objekt übergeben. Im Beispiel wird ein Konstruktor eingesetzt, bei dem die Wertefür die drei Komponenten Rot, Grün und Blau als Zahlen zwischen 0 und 255 an-gegeben werden. Damit wird für den Datensatz mit dem Schlüssel c ein kräftigesRot ohne Anteile der anderen Farben eingestellt.

2.4.3 Darstellungsbereich und Achsbeschriftung

Ohne weitere Angaben berechnet Plotter automatisch aus dem Wertebereich dereingegebenen Daten den Darstellungsbereich. Stattdessen können mit folgendenMethoden die x- und y-Bereiche festgelegt werden:

void setRange (double min , double max)void setXRange (double min , double max)void setYRange (double min , double max)

Wurde mit setRange ein Bereich festgelegt, so ist die automatische Berechnungausgeschaltet. Insbesondere wird nicht überprüft, ob alle Datenpunkte innerhalbdes Bereichs liegen.

Die Namen der Methoden folgen einem festen Schema. Es gibt jeweils eineeigene Variante für x und y sowie eine zur einheitlichen Festlegung von beiden.Auch bei den noch im folgenden vorgestellten Methoden gibt es � mit Ausnahmevon setXLabel � jeweils diese Dreier-Gruppe. Zur Vereinfachung bezieht sich derText im weiteren nur auf die gemeinsame Variante.

• setAutoGrid(double autoGrid) Fügt Skalenstriche mit dem angegebenenAbstand ein

2.4. VERFEINERTE DARSTELLUNG 15

• setGrid(double[] g) Zeichnet an den Werten im Feld g Skalenstriche

• setXLabel(String[] label) Die übergebenen Zeichenketten werden zur Be-schriftung der Skalenstriche verwendet. Standardmäÿig werden die Zahlen-werte eingetragen.

• setLabelFormat(String string) Wenn ein Format gesetzt ist, wird die Ach-senbeschriftung für einen Wert w mit String.format(xLabelFormat, w) ge-neriert, ansonsten einfach mit ""+ w.

• setLine(double x) An dem angegebenen Wert wird eine horizontale be-ziehungsweise vertikale Linie eingetragen. Diese Methode kann mehrfachaufgerufen werden, um mehrere Linien zu erhalten.

• clearRange() Schaltet wieder zurück zur automatischen Berechnung.

2.4.4 Löschen von Werten und Texten

Eine Reihe von Methoden stehen zur Verfügung, um einzelne Punkte, ganze Da-tensätze oder Texte wieder zu löschen. Im einzelnen sind dies

• removeOld(int n) Löscht die n ältesten Werte des aktuellen Datensazes

• removeOld(String key, int n) das gleiche, aber für einen speziellen Daten-satz

• removeNew(int n) Löscht die n neuesten Werte des aktuellen Datensazes

• removeNew(String key, int n) das gleiche, aber für einen speziellen Daten-satz

• removeAll( ) Löscht alle Werte des aktuellen Datensazes

• removeAll(String key ) das gleiche, aber für einen speziellen Datensatz

• removeDataObject(String key) Ein kompletter Datensatz wird entfernt.

• removeAllDataObjects() Alle Datensätze werden entfernt.

• removeText(String string) Das erste Textobjekt mit dem angegebenen In-halt wird gelöscht.

• removeText(double x, double y) Das erste Textobjekt an der angegebe-nen Position wird gelöscht.

• removeAllText() Alle Textobjekte werden gelöscht.

16 KAPITEL 2. PLOTTER

Schlieÿlich kann durch eine entsprechende Methode der Klasse DataObject auchein einzelner Punkt gelöscht werden. Der folgende Code-Abschnitt zeigt, wie fürgegebene Koordinaten (wx,wy) der nächstgelegene Punkt gesucht und anschlie-ÿend entfernt wird:

DataObject dO = p l o t t e r . getDataSet ( ) ;Point next = dO. f indNext ( wx , wy ) ;dO. remove ( next ) ;

(Beispiel aus Maus-Demo 4.2).

2.4.5 Bilder

Bei Anwendungen wie Spiele möchte man Bilder zur Darstellung von Spielele-menten wie Felder oder Figuren verwenden. Im Projekt Plotter steht dazu eineKlasse ImageObject bereit. Eine Instanz dieser Klasse enthält ein Image-Objektsowie die dazu gehörige Position. Intern verwaltet ein Plotter eine Liste mit sol-chen Bildern. Derzeit sind lediglich zwei Methoden zum Einfügen von Bildernimplementiert:

ImageObject setImage ( S t r ing name , double i , double j )ImageObject setImage ( Image image , double i , double j )

Entweder man übergibt einen Dateinamen oder ein bereits vorhandenes Image-Objekt zusammen mit den Koordinaten des Mittelpunktes. Beide Methoden ge-ben die Referenz auf ein ImageObject zurück. Falls die Datei nicht geladen werdenkann, ist der Rückgabewert wie üblich null. Mit den üblichen Getter- und Setter-Methoden kann die Position eines Bildes abgefragt und verändert werden. Derfolgende Code-Abschnitt zeigt die einfache Bewegung eines Bildes in 20 Schritten:

S t r ing f i l ename = "o_kl . png" ;ImageObject i o = p l o t t e r . setImage ( f i l ename , 1 , 1 ) ;

double de l t a =0.1;for ( int t=0; t <20; t++ ) {

i o . setX ( i o . getX()+ de l t a ) ;i o . setY ( i o . getY()+ de l t a ) ;graph ic . r epa in t ( ) ;S leep . s l e e p ( 2 0 0 ) ;

}

2.4.6 Ein Plotter ist ein JPanel

Die Klasse Plotter ist von der Bibliotheksklasse JPanel abgeleitet. Damit stehenauch alle ö�entlichen Methoden dieser Klasse und ihrer Eltern zur Verfügung.

2.4. VERFEINERTE DARSTELLUNG 17

Beispielsweise werden mit

p l o t t e r . s e tP r e f e r r e dS i z e (new Dimension (340 , 3 4 0 ) ) ;p l o t t e r . setBackground ( Color .WHITE) ;

die Gröÿe und die Hintergrundfarbe eingestellt. Für interaktive Anwendungenkönnen die diversen Listener gesetzt werden. In der Maus-Demo 4.2 werden inAbhängigkeit von Maus-Klicks Punkte gelöscht oder � bei gedrückter Umschalt-Taste � eingefügt. Dazu wurde mit

p l o t t e r . addMouseListener ( this ) ;

der entsprechende Listener registriert.

2.4.7 Koordinatensystem

Dem Plotter zugrunde liegt ein Koordinatensystem mit dem kleinsten Wert linksunten. Alle Datenpunkte sowie die Mittelpunkte von Texten oder Bildern werdenin diesen so genannten Weltkoordinaten angegeben. Die Grenzen des Koordina-tensystems werden entweder automatisch aus den Werten berechnet oder könnenmit einer der setRange Methoden vorgegeben werden. Intern verwenden die Klas-sen aus der Java-Bibliothek ein Koordinatensystem, bei dem der Ursprung (0, 0)links oben liegt. Bei diesen Gerätekoordinaten liegen positive Werte dann in X-Richtung rechts und in Y-Richtung unten. Etwas vereinfacht entspricht bei derDarstellung am Bildschirm eine Einheit einem Pixel. Die Weltkoordinaten werdenals double-Werte mit entsprechender Genauigkeit gespeichert. Die Gerätekoordi-naten sind demgegenüber als int-Werte immer ganze Zahlen.

Der Plotter übernimmt die Umrechnung der Weltkoordinaten in die Gerä-tekoordinaten. Ändert man die Gröÿe des Fenster auf dem Bildschirm, wirddie Transformation automatisch angepasst. Daten, Texte und Bilder werden da-durch immer in der gleichen Relation zum Gesamtbild positioniert. Allerdingsgibt es auch Gröÿen, die direkt in Gerätekoordinaten angegeben werden. Hierzuzählen zunächst Fonts. Die Schriftgröÿen werden bei Änderungen der Fenster-gröÿen nicht automatisch angepasst. Diesen E�ekt zeigt Bild 2.7. Entsprechendverhalten sich die Symbole beim Zeichenstil SYMBOL � die Gröÿe kann mitsetSymbolSize(int symbolSize) gesetzt werden � sowie Bilder. Andererseits wirddie Länge der Skalenstriche sowie die Breite der Säulen im Stil HISTOGRAMdynamisch an die Fenstergröÿe angepasst.

Intern wird das Methodenpaar

int sca leX (double d)int sca leY (double d)

zur Umrechnung der Welt- in Gerätekoordinaten verwendet. Diese Methodensollten die Anwenderinnen eigentlich nie benötigen. Dagegen muss im Beispiel

18 KAPITEL 2. PLOTTER

Abbildung 2.7: Konstante Schriftgröÿe

Maus-Demo 4.2 aus den beim Mausklick gemeldeten Gerätekoordinaten auf dieWeltkoordinaten zurück gerechnet werden. Dazu stehen die beiden Methoden

double scaleXR ( int i )double scaleXR ( int i )

zur Verfügung. Der folgende Codeausschnitt zeigt den Ablauf:

int x , y ;x = e . getX ( ) ; // Gerätekoordinateny = e . getY ( ) ;

double wx = p l o t t e r . scaleXR (x ) ; // Weltkoordinatendouble wy = p l o t t e r . scaleYR (y ) ;

Kapitel 3

Beispiele mit Vererbung

3.1 Geometrische Formen

Bei der Einführung von Vererbung werden gerne geometrische Formen als Bei-spiel gewählt. Mit Hilfe des Plotters lassen sich die Formen leicht darstellen. Mankann daher ohne groÿen zusätzlichen Programmieraufwand die Klassen nutzen,um damit Bilder zu erstellen. In diesem Kapitel werden entsprechende Klassenentwickelt. Der Schwerpunkt liegt dabei auf der gra�schen Darstellung. Keines-wegs soll dies als Ersatz für eine Einführung in Vererbung dienen.

Ausgangspunkt ist eine Klasse für einen einzelnen Punkt. Im Projekt Plottergibt es bereits eine entsprechende Klasse Point für die einzelnen Datenpunkt.Aber zur gröÿeren Klarheit führen wir eine eigene Klasse Punkt ein. Die Klassehat die beiden Attribute x und y für die Koordinaten, einen Konstruktor sowieeine Methode zum Bewegen des Punktes. Listing 3.1 zeigt die entsprechendeKlasse.

Listing 3.1: Klasse Punkt

1 package geod i r ek t ;23 public class Punkt {4 double x ;5 double y ;67 public Punkt (double x , double y ) {8 this . x = x ;9 this . y = y ;

10 }1112 public void bewegeUm(double dx , double dy ) {13 x += dx ;14 y += dy ;

19

20 KAPITEL 3. BEISPIELE MIT VERERBUNG

15 }16 }

Mit Hilfe von Punkten können nun Formen implementiert werden. Als erstesBeispiel betrachten wir eine Klasse Dreieck (Listing 3.2). Ein Dreieck besteht ausdrei Punkten, die im Konstruktor übergeben werden. Um den Code übersichtlichzu halten und später leichter verwenden zu können, werden die Punkte in einemFeld gespeichert. Die Methode bewegeUm reicht die Informationen an alle Punkteweiter.

Listing 3.2: Klasse Dreieck

1 package geod i r ek t ;23 import p l o t t e r . P l o t t e r ;45 public class Dreieck {6 Punkt [ ] punkte ;78 public Dreieck (Punkt p1 , Punkt p2 , Punkt p3 ) {9 punkte = new Punkt [ 3 ] ;

10 punkte [ 0 ] = p1 ;11 punkte [ 1 ] = p2 ;12 punkte [ 2 ] = p3 ;13 }1415 public void ze ichnen ( P l o t t e r p l o t t e r ) {16 p l o t t e r . nextVector ( ) ;17 for ( Punkt p : punkte ) {18 p l o t t e r . add ( p . x , p . y ) ;19 }20 p l o t t e r . add ( punkte [ 0 ] . x , punkte [ 0 ] . y ) ;21 }2223 public void bewegeUm(double dx , double dy ) {24 for (Punkt p : punkte ) {25 p . bewegeUm(dx , dy ) ;26 }27 }28 }

Beim Zeichnen gehen wir davon aus, dass eine Plotter-Instanz vorhanden istund die Methode eine Referenz darauf erhält. Dann wird ein neuer Datensatzangelegt und die Eckpunkte werden eingetragen. Mit dieser Implementierungkann das Dreieck wie eine Schablone verwendet werden. Wenn man eine Drei-

3.1. GEOMETRISCHE FORMEN 21

eck zeichnet, verschiebt und dann wieder zeichnet, bleibt die erste Darstellungerhalten und es werden insgesamt zwei Dreiecke gezeichnet. Das Dreieck-Objektbehält keine Informationen über die Zeichnung. Dieser lose Zusammenhang hältden Code einfach. Natürlich könnte man auch ein Konzept umsetzen, bei demzu jeder Instanz von Dreieck auch genau ein gezeichnetes Dreieck gehört. MitbewegeUm würde dann das Dreieck an der alten Stelle gelöscht und dann neugezeichnet werden.

Listing 3.3: Main-Methode in Klasse Maler

1 public stat ic void main ( St r ing [ ] a rgs ) {2 Graphic graph ic = new Graphic ( "Geometrie " ) ;3 P l o t t e r p l o t t e r = graphic . g e tP l o t t e r ( ) ;45 Punkt p1 = new Punkt (0 , 0 ) ;6 Punkt p2 = new Punkt (1 , 0 ) ;7 Punkt p3 = new Punkt ( 0 . 5 , 2 ) ;89 Dre ieck d1 = new Dreieck (p1 , p2 , p3 ) ;

10 d1 . ze ichnen ( p l o t t e r ) ;11 d1 . bewegeUm(0 . 2 , 0 . 2 ) ;12 d1 . ze ichnen ( p l o t t e r ) ;13 }

Nach dem gleichen Schema ist eine Klasse Kreis (Listing 3.4) geschrieben.Eine Kreis-Instanz wird dabei durch den Mittelpunkt sowie den Radius de�niert.Um die Vergleichbarkeit mit der Klasse Dreieck zu erhöhen, wird der Mittelpunktals erstes und einziges Element in einem Feld mit einem Punkt abgelegt.

Listing 3.4: Klasse Kreis

1 package geod i r ek t ;23 import p l o t t e r . P l o t t e r ;45 public class Kre i s {6 Punkt [ ] punkte ;7 double rad iu s ;89 public Kre i s (Punkt p1 , double rad iu s ) {

10 punkte = new Punkt [ 1 ] ;11 punkte [ 0 ] = p1 ;12 this . r ad iu s = rad iu s ;13 }1415 public void ze ichnen ( P l o t t e r p l o t t e r ) {

22 KAPITEL 3. BEISPIELE MIT VERERBUNG

16 p l o t t e r . nextVector ( ) ;17 for ( double t=0; t<2∗Math . PI ; t+=0.01 ) {18 double x = punkte [ 0 ] . x + rad iu s ∗ Math . cos ( t ) ;19 double y = punkte [ 0 ] . y + rad iu s ∗ Math . s i n ( t ) ;20 p l o t t e r . add ( x , y ) ;21 }22 }2324 public void bewegeUm(double dx , double dy ) {25 for (Punkt p : punkte ) {26 p . bewegeUm(dx , dy ) ;27 }28 }29 }

Man kann sich leicht vorstellen, wie weitere Formen wie Vierecke oder Ellip-sen ähnlich implementiert werden können. Allerdings beinhalten bereits Dreieckund Kreis doppelten Code � deutlicher Hinweis, dass Vererbung angebracht seinkönnte. Vergleicht man beide Klassen im Detail, so fällt auf

• beide Klassen beinhalten ein Feld punkte

• die Methoden zeichnen sind deutlich unterschiedlich

• die Methoden bewegeUm sind identisch

Daher bietet es sich an, die gemeinsamen Teile in eine Oberklasse auszulagern.Listing 3.5 zeigt eine entsprechende Klasse Form. Da wir davon ausgehen, dassjede daraus abgeleitet Klasse auch eine Methode zum Zeichnen benötigt, fügenwir eine entsprechende De�nition ein. Durch das Schlüsselwort abstract wird dieMethode abstrakt. Wir geben nur die Signatur an aber, aber keine Implemen-tierung. In Java ist eine Klasse mit mindestens einer abstrakten Methode selbstauch abstrakt. Von abstrakten Klassen können keine Instanzen angelegt werden.Erst wenn eine abgeleitete Klasse die abstrakten Methoden implementiert wirdsie konkret. In unserem Beispiel entspricht dies auch der Modellvorstellung. Eineallgemeine Form kann man nicht zeichnen, sondern nur Dreiecke, Kreise, etc.

Listing 3.5: Klasse Form

1 public abstract class Form2 {3 Punkt [ ] punkte ;45 abstract public void ze ichnen ( Ze ichner z ) ;67 public void bewegeUm( double dx , double dy ) {

3.1. GEOMETRISCHE FORMEN 23

8 for ( Punkt p : punkte ) {9 p . bewegeUm( dx , dy ) ;

10 }11 }12 }

Beispielhaft zeigt Listing 3.6 die neue Version von Dreieck als Unterklasse vonForm. Die Klasse besteht jetzt nur noch aus dem Konstruktor und der implemen-tierten Methode zeichnen. Alles andere ist bereits in der Oberklasse angelegt undwird von dort vererbt.

Listing 3.6: Klasse Dreieck abgeleitet von Form

1 package geod i r ek t ;23 import p l o t t e r . P l o t t e r ;45 public class Dreieck extends Form {67 public Dreieck (Punkt p1 , Punkt p2 , Punkt p3 ) {8 punkte = new Punkt [ 3 ] ;9 punkte [ 0 ] = p1 ;

10 punkte [ 1 ] = p2 ;11 punkte [ 2 ] = p3 ;12 }1314 public void ze ichnen ( P l o t t e r p l o t t e r ) {15 p l o t t e r . nextVector ( ) ;16 for ( Punkt p : punkte ) {17 p l o t t e r . add ( p . x , p . y ) ;18 }19 p l o t t e r . add ( punkte [ 0 ] . x , punkte [ 0 ] . y ) ;20 }21 }

Ähnlich können wir eine neue Version von Kreis als Unterklasse schreiben.Aufgrund der Vererbung ist dann sowohl ein Dreieck als auch ein Kreis eine Form.Wir können daher eine Variable vom Typ Form de�nieren und ihr eine Instanzeiner der konkreten Unterklassen zuweisen. Der Code-Abschnitte 3.7 zeigt dieseMöglichkeit. Zwei Variablen vom Typ Form � der Einfachheit halber als Feldzusammengefasst � werden einmal ein Dreieck und einmal ein Kreis zugewiesen.In der anschlieÿenden foreach-Schleife wird bei beiden Objekten die Methodezeichnen aufgerufen. Java prüft zur Laufzeit, um welche Objekte es sich handeltund ruft die dazu gehörige Methode auf.

24 KAPITEL 3. BEISPIELE MIT VERERBUNG

Diese Möglichkeit, unterschiedliche Datentypen über eine gemeinsame Ober-klasse anzusprechen, bezeichnet man als Polymorphismus (griechisch Vielgestal-tigkeit). Wichtig war allerdings, dass wir durch die abstrakte Methodende�nitionin der Oberklasse festgelegt haben, dass jede konkrete Unterklasse diese Metho-de implementiert. Ohne diese De�nition würde Java einen Fehler melden, da dieKlasse Form die Methode selbst nicht kennt � selbst wenn alle abgeleitete Klassenüber sie verfügen.

Listing 3.7: Formen

1 Form [ ] formen = new Form [ 2 ] ;2 formen [ 0 ] = new Dreieck ( p1 , p2 , p3 ) ;3 formen [ 1 ] = new Krei s ( mp, . 5 ) ;45 for ( Form form : formen ) {6 form . ze ichnen ( p l o t t e r ) ;7 }

3.2 Ameisen auf Irrwegen

In diesem Beispiel betrachten wir Ameisen, die sich auf einem quadratischenGitter bewegen. Eine Ameise blickt in eine der vier Hauptrichtungen. In je-dem Schritt geht sie ein Feld in Blickrichtung. Weiterhin ist jedes Feld entwederSchwarz oder Weiÿ. Die Ameise kann nach jedem Schritt ihre Blickrichtung än-dern. Dabei kann sie z. B. die Farbe ihres aktuellen Feldes berücksichtigen. ImDetail ist der Ablauf in jedem Schritt wie folgt:

1. die Ameise wählt eine neue Blickrichtung.

2. das aktuelle Feld wird umgefärbt (weiÿ nach schwarz beziehungsweise schwarznach weiÿ).

3. die Ameise geht einen Schritt.

Je nach Vorschrift zur Wahl der neuen Blickrichtung resultiert ein unterschiedli-ches Verhalten. Die nach Christopher Langton benannte Ameise verwendet fol-gende Regel:

• weiÿes Feld: drehe 90 Grad nach rechts

• schwarzes Feld: drehe 90 Grad nach links.

Die Langton-Ameise hat ein interessantes Verhalten. In den ersten etwa 10000Schritten bewegt sie sich in einem mehr oder weniger engen Gebiet rund um denAusgangspunkt. Dann beginnt sie mit dem Bau einer regelmäÿigen Struktur, die

3.2. AMEISEN AUF IRRWEGEN 25

Abbildung 3.1: Muster durch Langton-Ameise

wie eine Strasse von dem Ausgangspunkt weg führt. Von da an durchläuft sieeinen regelmäÿigen Zyklus von 104 Schritten, in dem die Ameisen-Strasse weitergebaut wird. bild 3.1 zeigt das nach etwa 12000 Schritten entstandene Muster.

Zur Implementierung einer entsprechenden Simulation werden folgende Klas-sen eingeführt:

• eine abstrakte Klasse Ant mit dem Grundverhalten jeder Ameise

• daraus abgeleitete Klassen mit konkreten Verhaltensweisen

• eine Klasse zur Steuerung der Simulation

Die Verwaltung der Felder soll der Plotter übernehmen. Die wesentlichen Teileder Basisklasse Ant sind in 3.8 dargestellt.

Listing 3.8: Klasse Ant

1 public abstract class Ant {2 public stat ic f ina l int NORTH = 0 ;3 public stat ic f ina l int WEST = 1 ;4 public stat ic f ina l int SOUTH = 2 ;5 public stat ic f ina l int EAST = 3 ;67 int d i r e c t i o n = WEST;8 int xpos = 0 ; // Ze i l e9 int ypos = 0 ; // Spa l t e

1011 abstract int newDirect ion ( P l o t t e r p l o t t e r ) ;

26 KAPITEL 3. BEISPIELE MIT VERERBUNG

1213 public void s tep ( P l o t t e r p l o t t e r ) {1415 d i r e c t i o n = newDirect ion ( p l o t t e r ) ;1617 DataObject dO = p l o t t e r . getDataObject ( ) ;18 i f (dO. conta in s ( xpos , ypos ) ) {19 dO. remove ( xpos , ypos ) ;20 } else {21 dO. add ( xpos , ypos ) ;22 }2324 i f ( d i r e c t i o n == NORTH) {25 ++ypos ;26 } else i f ( d i r e c t i o n == WEST) {27 −−xpos ;28 } else i f ( d i r e c t i o n == SOUTH) {29 −−ypos ;30 } else i f ( d i r e c t i o n == EAST) {31 ++xpos ;32 }33 }34 }

Die Methode step() führt die drei oben genannten Punkte jedes Schrittes durch.Der Richtungswechsel ist in eine abstrakte Methode ausgelagert, die jede konkreteabgeleitete Klasse implementieren muss. Der Plotter hält alle schwarzen Felder inseinem Datenobjekt. Ist das aktuelle Feld darunter, so wird es herausgenommen.Ist es umgekehrt nicht dabei � d. h. weiÿ � so wird es hinzugefügt.

Die abgeleitete Klasse Langton (3.9) implementiert den Richtungswechsel. Jenach Farbe des aktuellen Feldes wird dabei die Folgerichtung aus einem der beidenvorgegebenen Feldern gelesen.

Listing 3.9: Klasse Langton

1 public class Langton extends Ant {2 private int [ ] l e f t = { WEST, SOUTH, EAST, NORTH } ;3 private int [ ] r i g h t = { EAST, NORTH, WEST, SOUTH } ;45 @Override6 int newDirect ion ( P l o t t e r p l o t t e r ) {7 i f ( p l o t t e r . getDataObject ( ) . conta in s ( xpos , ypos ) ) {8 return l e f t [ d i r e c t i o n ] ;9 } else {

3.2. AMEISEN AUF IRRWEGEN 27

10 return r i g h t [ d i r e c t i o n ] ;11 }12 }13 }

Die Simulation selbst ist dann einfach. Nach dem Aufsetzen eines Plotters mitpasenden Einstellungen genügt der Code in 3.10 zur Simulation der ersten 12000Schritte. Die Variable show gibt dabei vor, nach wie vielen Schritten jeweils dieDarstellung aktualisiert werden soll.

Listing 3.10: Ausschnitt aus Klasse Simulation

1 Ant w i l l y = new Langton ( ) ;2 for ( int n = 1 ; n<12000; n++) {3 w i l l y . s tep ( p l o t t e r ) ;4 i f (n % show == 0) {5 p l o t t e r . s e tS ta tu sL ine ( "#s t ep s : " + n ) ;6 graph ic . r epa in t ( ) ;7 S leep . s l e e p ( 2 0 0 ) ;8 }9 }

Als Alternative zeigt 3.11 eine Ameise mit zufälligem Richtungswechsel. DieFarbe des aktuellen Feldes wird dabei einfach ignoriert. Diese Ameise simuliertdann eine Irrfahrt (random walk) auf einem unbeschränkten, zweidimensionalenGraphen. Eine wahrscheinlichkeitstheoretische Diskussion dieses Problems �ndetman z. B. im Buch von Häggström [Häg05].

Listing 3.11: Klasse RandomAnt

1 public class RandomAnt extends Ant {2 Random random = new Random ( ) ;34 @Override5 int newDirect ion ( P l o t t e r p l o t t e r ) {6 return random . next Int ( 4 ) ;7 }8 }

Ausgehend von diesen Klassen lassen sich viele Erweiterungen angehen. EinigeVorschläge dazu:

• implementieren Sie weitere Ameisen

� die nur einen begrenzten Raum (Quadrat, Kreis) betreten dürfen.

� mit einer Tendenz zu dem Ausgangspunkt oder weg vom Ausgangs-punkt (Ameisen mit Heim- oder Fernweh).

28 KAPITEL 3. BEISPIELE MIT VERERBUNG

� die bereits einmal betretene Felder meiden.

• was passiert, wenn man mehrere Ameisen gleichzeitig laufen lässt? VariierenSie Startpositionen und Anfangsrichtungen.

• Sobald die Langton-Ameise die Phase des Strassenbaus erreicht hat, nimmtdie Gesamtzahl der eingefärbten Felder linear zu. Wie ist Zusammenhangbei Zufallsameisen? Lassen Sie dazu die Anzahl der schwarzen Felder (plot-ter.getDataObject().getCount()) mit zunehmender Schrittzahl in einem wei-teren Plotter darstellen.

Kapitel 4

Beispiele mit Quell-Code

Listing 4.1: LineStyle Demo

1 package demos ;23 import java . awt . Color ;4 import java . awt . Dimension ;56 import p l o t t e r . DataObject ;7 import p l o t t e r . Graphic ;8 import p l o t t e r . L ineSty l e ;9 import p l o t t e r . P l o t t e r ;

1011 public class LineStyleDemo {12 Graphic graph ic = new Graphic ( " L ineSty l e Demo" ) ;13 P l o t t e r p l o t t e r = graph ic . g e tP l o t t e r ( ) ;1415 public stat ic void main ( St r ing [ ] a rgs ) {16 LineStyleDemo demo = new LineStyleDemo ( ) ;17 demo . e1 ( ) ;18 }1920 private void e1 ( ) {21 p l o t t e r . s e tP r e f e r r e dS i z e ( new Dimension ( 300 , 3 00 ) ) ;22 graph ic . pack ( ) ;2324 double [ ] werte = {0 , 3 , 9 , 0} ;25 double o f f s e t = 0 ;26 p l o t t e r . setSymbolSize ( 1 0 ) ;27 for ( L ineSty l e s t y l e : L ineSty l e . va lue s ( ) ) {28 St r ing name = s t y l e . name ( ) ;

29

30 KAPITEL 4. BEISPIELE MIT QUELL-CODE

29 i f ( name . equa l s ( "UNDEFINED" ) ) continue ;30 p l o t t e r . nextVector ( name ) ;31 p l o t t e r . add ( werte ) ;32 p l o t t e r . s e tDataLineSty l e ( s t y l e ) ;33 p l o t t e r . setDataColor ( Color .BLACK) ;34 DataObject d = p l o t t e r . getDataSet (name ) ;35 d . s e t xO f f s e t ( o f f s e t ) ;36 p l o t t e r . setText (name , o f f s e t+werte . l ength /2 . , −0.5) ;37 o f f s e t += werte . l ength ;38 }3940 graph ic . r epa in t ( ) ;41 }42 }

4.1 Maus Demo

Dieses Beispiel zeigt Koordinaten-Umrechnungen und Möglichkeiten zur Verän-derung eines Datenobjektes. Als Anwendung ist die Eingabe eines Funktionsver-laufs durch einzelne Stützstellen gedacht. In der vorliegenden Version werden dieeinzelnen Punkte als Polygon verbunden. Man könnte die Anwendung erweiternund Interpolationsfunktionen einzeichnen (siehe Übung 6.19).

Im Konstruktor (Listing 4.2) wird der Plotter vorbereitet:

• in die Statuszeile wird eine kleine Hilfe geschrieben

• als Zeichenstil wird die Kombination Linie mit Symbolen gewählt

• durch die beiden unsichtbaren Punkte (−1,−1) und (1, 1) wird die Zeichen-�äche auf den Wertebereich [−1, 1] eingestellt

• schlieÿlich registriert sich die Instanz von MouseDemo als Empfänger vonMaus-Ereignissen

Wurde eine Maustaste gedrückt und wieder losgelassen wird die Methode mouse-Clicked aufgerufen. Dort wird zunächst die Position des Mauszeigers abgefragt.Die erhaltenen Gerätekoordinaten werden dann in Weltkoordinaten umgerechnet.Zur Vereinfachung wird die Variablen dO als Referenz auf das aktuelle Datenob-jekt eingeführt. Abhängig davon, ob die linke oder rechte Taste gedrückt wurde,wird dann entweder ein neuer Punkt angefügt oder der nächstsgelegene Punktentfernt. Bei gedrückter Umschalt-Taste wird nach dem Löschen zusätzlich einneuer Punkt angefügt. Neue Punkte werde immer am Ende der Liste angehängt.

Für die Darstellung als Stützstellen einer Funktion müssen die Punkte in ei-ne aufsteigende Reihenfolge bezüglich der x-Komponente gebracht werden. Diese

4.1. MAUS DEMO 31

Aufgabe übernimmt die Methode sort() in der Klasse DataObject. Diese wie-derrum ruft die gleichnamige Methode der Bibliotheksklasse Collections auf, dieihrerseits die Methode compareTo in der Klasse Point (Listing 4.3) verwendet.

Listing 4.2: Maus-Demo

1 public class MouseDemo implements MouseListener {2 Graphic graph ic = new Graphic ( "Mouse" ) ;3 P l o t t e r p l o t t e r = graphic . g e tP l o t t e r ( ) ;456 public MouseDemo( ) {7 graphic . s e tDe fau l tC loseOperat i on (8 WindowConstants .EXIT_ON_CLOSE) ;9 p l o t t e r . s e tS ta tu sL ine ( " c l i c k : l e f t : new point , "

10 + " r i gh t : d e l e t e , s h i f t−r i g h t : move to " ) ;1112 p l o t t e r . s e tDataLineSty l e ( L ineSty l e .BOTH) ;13 p l o t t e r . setSymbolSize ( 5 ) ;14 p l o t t e r . add ( "hidden" , −1. , −1 ) ;15 p l o t t e r . add ( "hidden" , 1 . , 1 ) ;16 p l o t t e r . s e tDataLineSty l e ( "hidden" , L ineSty l e .HIDDEN) ;17 p l o t t e r . addMouseListener ( this ) ;18 }1920 public stat ic void main ( St r ing [ ] a rgs ) {21 MouseDemo m = new MouseDemo ( ) ;22 m. graph ic . r epa in t ( ) ;23 }2425 @Override26 public void mouseClicked (MouseEvent e ) {27 System . out . p r i n t l n ( e ) ;28 int x , y ;29 x = e . getX ( ) ;30 y = e . getY ( ) ;31 System . out . p r i n t l n ( "Mouse r e l e a s e d : " + x + " , " + y ) ;32 System . out . p r i n t l n ( "#c l i c k s : " + e . getCl ickCount ( ) ) ;33 System . out . p r i n t l n ( "#button : " + e . getButton ( ) ) ;3435 double wx = p l o t t e r . scaleXR (x ) ;36 double wy = p l o t t e r . scaleYR (y ) ;37 System . out . p r i n t l n ( " in world coord . : "38 + wx + " , " + wy ) ;

32 KAPITEL 4. BEISPIELE MIT QUELL-CODE

3940 DataObject dO = p l o t t e r . getDataObject ( ) ;4142 i f ( e . getButton ( ) == 1 ) {43 dO. add ( wx , wy ) ;44 dO. s o r t ( ) ;45 } else {46 Point next = dO. f indNext ( wx , wy ) ;47 dO. remove ( next ) ;48 i f ( ( e . getModi f i e r sEx ( )49 & InputEvent .SHIFT_DOWN_MASK )50 == InputEvent .SHIFT_DOWN_MASK ) {51 dO. add ( wx , wy ) ;52 dO. s o r t ( ) ;53 }54 }55 graphic . r epa in t ( ) ;56 }5758 // n i ch t b e nö t i g t e Methoden aus MouseListener59 public void mouseEntered (MouseEvent e ) {}60 public void mouseExited (MouseEvent e ) {}61 public void mousePressed (MouseEvent e ) {}62 public void mouseReleased (MouseEvent e ) {}63 }

Listing 4.3: compareTo in Klasse Point

1 @Override2 public int compareTo ( Object arg0 ) {3 Point p2 = ( Point ) arg0 ;4 return Double . compare (x , p2 . x ) ;5 }

4.2 Tic Tac Toe

Als Beispiel für das Einbinden von Bildern wurde die Grundversion des SpielsTic Tac Toe realisiert. Auf einem 3×3-Brett markieren zwei Spieler abwechselndFelder. Um den Code übersichtlich zu halten, ist nur eine einfache Steuerung überdie Eingabe des Feldindexes implementiert. Listing 4.4 zeigt die Klasse. In derMethode demo() wird zuerst das Feld gezeichnet. Dabei wird jeweils der Indexeines Feldes zentral in das Feld geschrieben. Anschliessend wartet ein Scanner auf

4.2. TIC TAC TOE 33

Eingaben. Bei Eingabe eines Feldindexes wird der Text in diesem Feld entferntund stattdessen ein Bild eingezeichnet. Dabei wird mit jedem Zug zwischen einemKreuz und einem Kreis gewechselt. Nach drei Zügen erhält man beispielsweisefolgendes Bild:

Listing 4.4: Einfaches Tic Tac Toe Spiel

1 public class TicTacToe {2 Graphic graph ic = new Graphic ( "Tic Tac Toe Demo" ) ;3 P l o t t e r p l o t t e r = graphic . g e tP l o t t e r ( ) ;45 public stat ic void main ( St r ing [ ] a rgs ) {6 (new TicTacToe ( ) ) . demo ( ) ;7 }89 private void demo ( ) {

10 p l o t t e r . setRange (1 , 4 ) ;11 p l o t t e r . s e tP r e f e r r e dS i z e (new Dimension (340 , 3 4 0 ) ) ;12 p l o t t e r . setBackground ( Color .WHITE) ;13 graphic . pack ( ) ;1415 for ( int i = 2 ; i < 4 ; i++) {16 p l o t t e r . setXLine ( i ) ;17 p l o t t e r . setYLine ( i ) ;18 }1920 for ( int f e l d = 1 ; f e l d <= 9 ; f e l d++) {21 p l o t t e r . setText (22 "" + fe ld , ( f e l d − 1) % 3 + 1 . 5 ,23 ( f e l d − 1) / 3 + 1 . 5 ) ;24 }25

34 KAPITEL 4. BEISPIELE MIT QUELL-CODE

26 Scanner sc = new Scanner ( System . in ) ;27 for ( int zug = 1 ; zug <= 9 ; zug++) {28 System . out . p r i n t l n ( ">" ) ;29 int f e l d = sc . next Int ( ) ;30 St r ing f i l ename = "o_kl . png" ;31 i f ( zug % 2 == 0)32 f i l ename = "x_kl . png" ;33 p l o t t e r . removeText ( "" + f e l d ) ;34 p l o t t e r . setImage ( f i l ename ,35 ( f e l d − 1) % 3 + 1 . 5 ,36 ( f e l d − 1) / 3 + 1 . 5 ) ;37 p l o t t e r . r epa in t ( ) ;38 }39 sc . c l o s e ( ) ;40 }41 }

4.3 Türme von Hanoi

Beim Spiel Türme von Hanoi ist die Aufgabe, einen Stapel von Scheiben von einerStange A auf eine andere Stange C zu versetzten [GoA08]. Dabei gelten folgendeRegeln:

• neben dem Ausgangsstapel A und dem Zielstapel C steht ein Stapel B alsZwischenablage zur Verfügung.

• es dürfen stets nur kleinere auf gröÿeren Scheiben liegen.

• in jedem Zug wird die oberste Scheibe eines beliebigen Stabes auf einen derbeiden anderen Stäbe gelegt.

Diese Aufgabe wird oft als Beispiel für rekursive Lösungen verwendet. In der Tatlässt sich die Aufgabe N Scheiben von A nach C unmittelbar auf drei Schritteaufteilen:

1. N-1 Scheiben von A nach B

2. unterste Scheibe von A nach C

3. N-1 Scheiben von B nach C

Entsprechend kann die Teilaufgabe N-1 Scheiben von A nach B wiederum durchzwei Aktionen für jeweils N-2 Scheiben gelöst werden. Dieses Vorgehen wird durchdie rekursive Methode 4.5 implementiert. Die drei Stapelplätze sind hierbei mit

4.3. TÜRME VON HANOI 35

Abbildung 4.1: Zwischenstand bei Türme von Hanoi mit 20 Scheiben

0, 1 und 2 nummeriert und werden durch ein Feld von 3 Stapelspeichern (Stack)realisiert. Mit pop() wird das oberste Element von einem Stapel genommen undmit push() auf das Ziel gelegt.

Listing 4.5: Rekursive Lösung für Türme von Hanoi

1 void z i eh e ( int n , int von , int nach , int zwischen ) {2 i f (n > 0) {3 z i ehe (n − 1 , von , zwischen , nach ) ;4 tuerme [ nach ] . push ( tuerme [ von ] . pop ( ) ) ;5 z i ehe (n − 1 , zwischen , nach , von ) ;6 }7 }

Mit diesem Ansatz entstand die Klasse HanoiStack, bei der ein Plotter zurDarstellung des Ablaufs dient. Die Variable N gibt die Anzahl der Scheiben vor.Im Konstruktor werden die drei Stapelspeicher angelegt und der erste wird mitden WertenN,N−1, . . . , 1 gefüllt. Für jede Scheibe wird eine Farbe mit zufälligenRGB-Werten erzeugt. Nach jedem Zug wird die Methode zeichnen() aufgerufen,in der die Scheiben auf den drei Stangen als Rechtecke passender Gröÿe gezeichnetwerden. Bild 4.1 zeigt einen Zwischenstand beim Versetzen eines Stapels von 20Scheiben.

Listing 4.6: Türme von Hanoi

1 public class HanoiStack {2 private Graphic graphic = new Graphic ( "Türme von Hanoi" ) ;3 private Plo t t e r p l o t t e r = graph ic . g e tP l o t t e r ( ) ;4 private int sleepTime = 300 ;5 private int N = 5 ;

36 KAPITEL 4. BEISPIELE MIT QUELL-CODE

6 private Stack<Integer >[ ] tuerme = new Stack [ 3 ] ;7 private int anzah lS ch r i t t e = 0 ;8 private Color [ ] c o l o r s = new Color [N ] ;9

10 public stat ic void main ( St r ing [ ] a rgs ) {11 (new HanoiStack ( ) ) . demo ( ) ;12 }1314 public HanoiStack ( ) {15 graphic . s e tDe fau l tC loseOperat i on (16 WindowConstants .EXIT_ON_CLOSE) ;17 p l o t t e r . setXrange(−N, 3 .5 ∗ N) ;18 p l o t t e r . setYrange (0 , N + 1 ) ;19 p l o t t e r . s e tP r e f e r r e dS i z e (new Dimension (800 , 4 0 0 ) ) ;20 p l o t t e r . s e tDataL ineSty l e ( L ineSty l e . FILL ) ;21 graphic . pack ( ) ;2223 for ( int n = 0 ; n < 3 ; n++) {24 tuerme [ n ] = new Stack<Integer >() ;25 }26 Random r = new Random ( ) ;27 for ( int i = 0 ; i < N; i++) {28 tuerme [ 0 ] . push (N − i ) ;29 c o l o r s [ i ] = new Color (30 r . next Int (255) ,31 r . next Int (255) ,32 r . next Int (155) ) ;33 }3435 for ( int n = 0 ; n < 3 ; n++) {36 double x = n ∗ (N + 1 ) ;37 p l o t t e r . setXLine (x ) ;38 }39 }4041 void ze ichnen ( ) {42 p l o t t e r . c l e a rP lo tVec to r ( ) ;43 for ( int n = 0 ; n < 3 ; n++) {44 double x = n ∗ (N + 1 ) ;45 int s = 1 ;46 for ( int s che ibe : tuerme [ n ] ) {47 p l o t t e r . nextVector ( ) ;48 p l o t t e r . setDataColor ( c o l o r s [ s che ibe − 1 ] ) ;

4.3. TÜRME VON HANOI 37

49 p l o t t e r . add (x − s che ibe / 2 . , s++);50 p l o t t e r . addD( sche ibe , 0 ) ;51 p l o t t e r . addD(0 , . 5 ) ;52 p l o t t e r . addD(− sche ibe , 0 ) ;53 p l o t t e r . addD(0 , − .5) ;54 }55 }56 }5758 void z i eh e ( int n , int von , int nach , int zwischen ) {59 i f (n > 0) {60 z i ehe (n − 1 , von , zwischen , nach ) ;61 tuerme [ nach ] . push ( tuerme [ von ] . pop ( ) ) ;62 ze ichnen ( ) ;63 p l o t t e r . s e tS ta tu sL ine (64 "Zug Nr . " + anzah lS ch r i t t e ) ;65 graph ic . r epa in t ( ) ;66 S leep . s l e e p ( sleepTime ) ;67 z i eh e (n − 1 , zwischen , nach , von ) ;68 anzah lS ch r i t t e++;69 }70 }7172 private void demo ( ) {73 ze ichnen ( ) ;74 S leep . s l e e p (2 ∗ sleepTime ) ;75 z i ehe (N, 0 , 2 , 1 ) ;76 }77 }

38 KAPITEL 4. BEISPIELE MIT QUELL-CODE

Kapitel 5

Anwendungen rund um Plotter

5.1 Klasse Graphic

Die Klasse Graphic ist als einfacher Rahmen um einen Plotter gedacht. Sie enthältein JPanel in BorderLayout mit dem Plotter im Zentrum und einem JLabel imoberen Bereich. Dort wird die Statuszeile des Plotters eingetragen. Das einzigeMenü bietet die Auswahl zwischen Speichern in einer Bilddatei oder direktemAusdruck.

Diese Klasse soll einen leichten Einstieg bieten, so dass ein Plotter auch ohneKenntnisse in den Java-Klassen für gra�sche Benutzerober�ächen genutzt wer-den kann. Für anspruchsvollere Anwendungen ist es in der Regel sinnvoll, eineeigenständige Anwendung mit passender Benutzerober�äche zu entwickeln. AlsMittelweg für eine schnelle Umsetzung ohne grosse Ansprüche bietet die Graphic-Klasse zwei Erweiterungsmöglichkeiten. Zum einen kann man die Menüleiste umweitere Menüs ergänzen und zum anderen kann man Elemente in den oberenBereich einfügen. Dazu stehen die beiden Methoden

void addExternMenu ( JMenu menu )void addTopComponent (Component comp)

zur Verfügung. Im folgenden Code-Auszug werden beispielhaft ein

JTextFie ld xpos = new JTextFie ld ( " 0 , 0" ) ;. . .g raph ic . addTopComponent ( new JLabel ( " s t a r t : " ) ) ;g raph ic . addTopComponent ( xpos ) ;

ein JLabel für eine Beschriftung sowie ein JTextField als Eingabefeld angelegt.Bild 5.1 zeigt die resultierende Darstellung.

39

40 KAPITEL 5. ANWENDUNGEN RUND UM PLOTTER

Abbildung 5.1: Beispiel mit zusätzlichem Menü sowie Ein- und Ausgaben

5.2 Visualisierung von Sortierverfahren

Ausgehend von der Klasse Plotter wurde eine Visualisierung für Sortierverfahrenrealisiert. Dabei wird der Ablauf bei den wichtigsten Sortierverfahren anhandeines Feldes mit ganzen Zahlen dargestellt. Durch entsprechende Vorgaben kannausprobiert werden, inwieweit die Ausgangslage � bereits teilweise sortierte Felderoder umgekehrte Reihenfolge � sich auf den Ablauf auswirken.

Bild 5.2 zeigt Startfenster der Anwendung. In diesem Fenster kann man einSortierverfahren auswählen und die Startbedingungen vorgeben. Die Werte be-deuten

Groesse die Anzahl N der zu sortierenden Werte

Vorsortiert ein Teil des Feldes ist bereits sortiert

Füllmodus standardmäÿig (Zufall) enthält das zu sortierende Feld positive gan-ze Zahlen bis 32000. Alternativ kann man wählen

Zufall_10 Zufallszahlen bis 10

Permutation die Zahlen 0 bis N-1 in beliebiger Reihenfolge

Reverse die Zahlen N-1 bis 0

Sleep die Wartezeit zwischen 2 Schritten in Millisekunden. Dies entspricht nichtunbedingt einem elementaren Schritt im jeweiligen Algorithmus. So wirdbeispielsweise bei Bubble-Sort nicht jede Tauschaktion angezeigt sondernnur die Situation am Ende eines Durchgangs. Nach Setzen des KästchensDetails werden mehr Details angezeigt.

der Zeichenstil

Die Bilder 5.3 und 5.4 zeigen zwei Beispiele. In beiden Fällen wurde der Füllm-odus Permutation verwendet. Dabei liegen die sortiertenWerte auf einer Geraden,so dass der Fortschritt während der Verarbeitung besonders gut zu erkennen ist.

5.2. VISUALISIERUNG VON SORTIERVERFAHREN 41

Abbildung 5.2: Kontrollfenster für Sortier-Demo

Abbildung 5.3: Beispiel Selection-Sort

Abbildung 5.4: Beispiel Quick-Sort

42 KAPITEL 5. ANWENDUNGEN RUND UM PLOTTER

C-Programm =⇒ Datei =⇒ FilePlotter =⇒ Plotter

Abbildung 5.5: Ablauf vom C-Programm zum Plot

5.3 Plot aus Dateien

Die Klasse Plotter ist Basis für mehrere Anwendungen in Lehrveranstaltungen.In einführenden Veranstaltungen zur Programmiersprache C wird eine entspre-chende Klasse FilePlotter zur Darstellung von Daten aus C-Programmen ein-gesetzt. Als Schnittstelle dient eine Datei mit Steuerbefehlen und Werten. DasC-Programm schreibt die Informationen in eine Datei und führt dann über dieFunktion system die main-Methode der Klasse FilePlotter aus. Abbildung 5.5zeigt den entsprechenden Ablauf.

Um die Generierung der Datei einfach zu halten, wird ein schlichtes, zeilen-orientiertes Format verwendet. Ein #-Zeichen markiert eine Befehlszeile. Derzeitwerden folgende Befehle erkannt

• #xy Wechsel in xy-Modus, bei dem jeweils aufeinander folgende Werte alsKoordinate (x, y) interpretiert werden. Standardmäÿig wird jeder Wert alsy-Wert dargestellt und x wird durchgezählt.

• #next Beginnt einen neuen Datensatz.

• #range min max Setzt den Wertebereich auf die angegebenen Werte. Mitden Varianten xrange und yrange kann gezielt nur eine Achse gesetzt wer-den.

• #xline x Zeichnet eine Line bei dem angegebenen x-Wert.

• #yline y das gleiche für einen y-Wert. In diesem Fall werden x- und y-Achse gleich behandelt.

• #linestyle style Setzt für den aktuellen Datensatz den Zeichenstil (sieheKapitel 2.4).

• #color color Ändert die Farbe. Die Farbe kann entweder über den Namender Konstanten aus der Klasse Color oder eine RGB-Angabe als Octal- oderHexadezimal-Wert spezi�ziert werden. Beispielsweise sind green, 0177400und 0xff00 gültige Werte für die Farbe Grün.

Alle anderen Zeilen werden als Datenzeilen gelesen, wobei eine Zeile auch mehrereWerte beziehungsweise im xy-Modus Wertepaare enthalten darf. Listing 5.1 zeigtein entsprechendes C-Programm. Zunächst werden zwei Befehlszeilen zum Um-schalten in den xy-Modus und zum Setzen der Farbe geschrieben. Anschlieÿendfolgend die Werte i3 für i = −30,−29, . . . , 30.

5.3. PLOT AUS DATEIEN 43

Listing 5.1: C-Programm

1 // Zunaechst Datei t e s t . dat mit Werten f u e l l e n2 FILE ∗ fp ;3 fp = fopen ( " t e s t . dat" , "w" ) ;4 p r i n t f ( fp , "#xy\n" ) ; // Umschalten in xy−Modus5 p r i n t f ( fp , "#co l o r 0 x f f 0000 \n" ) ; // Farbe ro t6 // j e t z t Werte i ^3 sch re i b en7 for ( int i =−30; i <=30; i++ ) {8 f p r i n t f ( fp , "%d %g\n" , i , (double ) i ∗ i ∗ i ) ;9 }

10 f c l o s e ( fp ) ;1112 // J e t z t p l o t t e r au f ru f en13 // Pfad fü r java muss e v e n t u e l l angepass t werden14 system ( " java −cp p l o t t e r . j a r p l o t t e r . F i l eP l o t t e r t e s t . dat" ) ;

Die Datei besteht dann aus drei Befehlszeilen und den Zeilen mit den berech-neten Wertepaaren:

#xy

#color 0xff0000

#yline 0

-30 -27000

-29 -24389

-28 -21952

-27 -19683

-26 -17576

...

Diese Anordnung ist keineswegs zwingend. Befehlszeilen können auch zwischenDatenzeilen eingeschoben werden. Aus dem Bespiel ergibt sich schlieÿlich dieDarstellung in Bild 5.6

44 KAPITEL 5. ANWENDUNGEN RUND UM PLOTTER

Abbildung 5.6: Resultierende Darstellung aus C-Programm

Kapitel 6

Aufgaben

In diesem Kapitel sind einige Aufgaben rund um Plotter zusammengestellt. DieKoppelung mit dem Plotter sind unterschiedlich stark. Einige Aufgaben befassensich speziell mit den verschiedenen Möglichkeiten des Plotters. Andere verwendenihn lediglich zur Darstellung der Ergebnisse und können im Prinzip auch ohnePlotter eingesetzt werden. Die Aufgaben sind etwa nach ihrer zeitlichen Abfolgeim Rahmen von Einführungsvorlesungen geordnet.

Übung 6.1 Kennenlernen des PlottersSchreiben Sie eine erste Anwendung des Plotters zum Zeichnen einiger Buchsta-ben. Das Ergebnis kann z. B. wie folgt aussehen:

Als Basis können Sie den Java-Code

import java.awt.Color;

import plotter.Graphic;

import plotter.LineStyle;

import plotter.Plotter;

public class THM {

45

46 KAPITEL 6. AUFGABEN

public static void main(String[] args) {

Graphic graphic = new Graphic("Logo");

Plotter plotter = graphic.getPlotter();

// hier Aufrufe von plotter.add oder plotter.addD

// zum Zeichnen einbauen

// Aktualisieren lassen

plotter.repaint();

}

}

verwenden.

Übung 6.2 Landes�aggeLassen Sie mit dem Plotter eine Landes�agge nach Wahl zeichnen.

Übung 6.3 Einfache FunktionenVerwenden Sie folgende Methode,

public static void main(String[] args) {

Graphic graphic = new Graphic("Sinus");

Plotter plotter = graphic.getPlotter();

// Hier Berechnung einbauen

}

um den Verlauf der Funktionen

• ex, xex, 30e−x2

im Intervall [−3, 3] darzustellen. Verwenden Sie dazu die BibliotheksmethodeMath.exp(x).

Übung 6.4 pq-FormelSchreiben Sie ein Programm, das die Lösungen der quadratischen Gleichung

x2 + p · x+ q = 0

berechnet. Dabei soll q den festen Wert 0,1 haben und p in Schritten von 0,1von 0 bis 2 laufen. Prüfen Sie jeweils, ob eine reelle Lösung existiert. Falls ja,berechnen Sie die beiden Lösungen und lassen sie mit einem Plotter darstellen.Zur Kontrolle setzten Sie die gefundenen Werte in die Gleichung ein und gebendas Ergebnis ebenfalls aus. Im Fall von komplexen Lösungen geben Sie einenentsprechenden Hinweis aus.

47

Übung 6.5 Darlehen, 3 PunkteSie nehmen ein Annuitätendarlehen über 100000 Euro auf. Der jährliche Zins-satz beträgt 4,5%. Jeden Monate zahlen Sie eine Rate von 500 Euro. Diese Ratebeinhaltet zunächst die Zinsen für diesen Monat (4,5/12 auf Restguthaben). Mitdem verbleibenden Rest wird das Darlehen getilgt. Im ersten Monat beträgt derZins 100000∗0, 045/12 = 375. Dementsprechend wird das Darlehen um 125 Euroauf 99875 Euro vermindert. Im zweiten Monat muss dann nur noch für diesenBetrag Zinsen bezahlt werden.

Verfolgen Sie per Programm die Entwicklung des Darlehens. Berechnen Siedazu jeden Monat die verbliebene Restschuld und geben diesen Wert jeweils aus.Wie lange dauert es, das Darlehen zu tilgen? Wie viele Zinsen werden bis zumEnde insgesamt gezahlt worden sein? Lassen Sie den Verlauf von Darlehen undgezahlten Zinsen mit einem Plotter darstellen.

Übung 6.6 Min-MaxIn der folgenden Methode wird ein Feld mit zufälligen Werten gefüllt:

public static void auswerten() {

int anzahl = 10;

double[] werte = new double[anzahl];

for( int i=0; i<werte.length; i++) {

werte[i] = Math.random();

}

}

Geben Sie zunächst die Werte im Feld aus. Lassen Sie dann aus diesem Feldfolgende Gröÿen berechnen:

• Mittelwert

• kleinster Wert

• gröÿter Wert

Hinweis: Double.MAX_VALUE ist die gröÿte Zahl im Datentyp double.Die Werte und gefundenen Grenzen sollen schlieÿlich gra�sch dargestellt werden.Ein Beispiel:

48 KAPITEL 6. AUFGABEN

Übung 6.7 Felder als Zähler,Implementieren Sie auf der Basis der Methode Math.random() eine Würfel-Simulation, die Zahlen zwischen 1 und 6 erzeugt. Zählen Sie in einem Feld ent-sprechender Gröÿe, wie oft jede Zahl bei 10000 Würfen vorkommt. Lassen Sie diegezählten Häu�gkeiten mit Plotter als Histogramm darstellen.

Übung 6.8 Bestimmung der Zahl π durch ZufallsexperimenteBestimmen Sie durch Monte-Carlo-Simulationen eine Näherung für die Zahl π.

1. Betrachten Sie ein Quadrat der Seitenlänge 1, in dem ein Viertelkreis mitRadius 1 liegt. Die Fläche FQdes Quadrats ist 1, die des ViertelkreisesFV = π/4. Damit gilt die Beziehung π = 4 · FV /FQ. Lassen Sie zur experi-mentellen Bestimmung des Verhältnis FV /FQ zufällige Punkte im Intervall[0, 1; 0, 1] erzeugen und zählen, wie viele davon in den Viertelkreis fallen.Zur Veranschaulichung sollen die Punkte in unterschiedlichen Farben ineine entsprechende Darstellung eingetragen werden.

2. Die Wahrscheinlichkeit, dass zwei natürliche Zahlen n und m teilerfremdsind (d. h. GGT (n,m) = 1), beträgt 6/π2. Bestätigen Sie diese Aussagedurch eine Simulation. Lassen Sie dazu Paare von Zufallszahlen erzeugenund zählen, wie oft die Paare teilerfremd sind. Das Ergebnis (d. h. die Kon-vergenz gegen π) soll mittels Plotter gra�sch dargestellt werden.

Übung 6.9 SpielsimulationIn einer Freistunde tre�en sich 6 Studenten. Aus Langeweile beginnen sie eineinfaches Spiel: Jeder Spieler erhält eine der Nummern 1 bis 6. Dann wird ge-würfelt. Der Spieler mit der gewürfelten Nummer erhält einen Punkt. Dann wirdimmer wieder gewürfelt und die erzielten Punkte pro Spieler werden hochgezählt.Das Spiel ist zu Ende, sobald der erste Spieler 10 Punkte erreicht hat.

Um abzuschätzen, wie viele Spiele in einer Freistunde möglich sind, möchtendie Studenten die mittlere Dauer eines Spiels wissen. Minimum sind 10 Würfe(immer die selbe Zahl) und Maximum 55 Würfe (alle 6 Spieler haben 9 Punkte,der nächste Wurf entscheidet).

49

• Ermitteln Sie mit einem Simulationsprogramm die mittlere Anzahl von Wür-fen bis zum Ende.

• Wie verteilen sich die Anzahlen über die möglichen Werte 10 bis 55? LassenSie die Verteilung in einem Plotter darstellen.

• Wie ist das Ergebnis, wenn mehr Punkte zum Gewinn benötigt werden?

Übung 6.10 Collatz-FolgeGegeben ist eine positive ganze Zahl n. Dann soll mit diesem Startwert nachfolgender Vorschrift eine Folge berechnet werden:

n =

{n/2 : n gerade3 · n+ 1 : n ungerade

(6.1)

Die Folgen erreichen irgendwann den Wert 1 und laufen dann in eine Schleifemit der Folge 1 4 2. Als Beispiel erhält man für den Wert 11:

n=11: 34 17 52 26 13 40 20 10 5 16 8 4 2 1

1. Schreiben Sie eine Methode, die für gegebenes n die Anzahl A(n) der Schrit-te bis 1 zurück gibt (im Beispiel A(11) = 14).

2. Lassen Sie A(n) als Funktion von n plotten.

3. Zählen Sie, wie oft die einzelnen Längen vorkommen und lassen die Häu-�gkeit als Histogramm darstellen.

Übung 6.11 Hasen und FüchseIn der Wetterau leben Hasen und Füchse. Die Vermehrung hängt von der jewei-ligen Populationsgröÿe ab. Gibt es beispielsweise viele Hasen, �nden die Füchseviel Futter und vermehren sich gut. Dann gibt es allerdings viele Füchse und vieleHasen werden gefressen. Ein einfaches Modell für die Entwicklung der Popula-tionsgröÿen lässt sich folgendermaÿen beschreiben: Sei H die Anzahl der Hasenund F die Anzahl der Füchse. Dann gilt für das Folgejahr

H ′ = H + g ∗H − f ∗H ∗ FF ′ = F − s ∗ F + j ∗H ∗ F

mit

g : Geburtsrate der Hasenf : Fangrate Hasens : Sterberate der Füchsej : Jagderfolg der Füchse

Verwenden Sie die Werte

50 KAPITEL 6. AUFGABEN

H : 100F : 40g : 0.09f : 0.002s : 0.08j : 0.001

1. Lassen Sie die Zahl der Hasen und Füchse für die nächsten 500 Jahre be-rechnen und das Ergebnis mit Plotter darstellen. In der Gra�k sollen zu-nächst die beiden Verläufe einzeln eingezeichnet werden.

2. Auÿerdem soll (entweder im gleichen Fenster oder in einem anderen) derVerlauf als Ortskurve gezeichnete werden, wobei ein Wertepaar (H,F ) alsPunkt betrachtet wird. Verwenden Sie hierzu die Methode add( x, y ) desPlotters.

3. Führen Sie zusätzlich die Bedingung ein, dass es nie mehr als 50 Füchsegibt. Welchen Verlauf erhalten Sie nun?

Übung 6.12 QuadrateDie folgende Klasse zeichnet ein Quadrat:

import java.awt.Dimension;

public class Quadrat {

public static void main(String[] args) {

Graphic graphic = new Graphic("Kisten");

Plotter plotter = graphic.getPlotter();

// Einige Einstellungen, damit der Plot netter aussieht

plotter.setPreferredSize(new Dimension(500, 500));

graphic.pack();

plotter.setXrange(-10.5, 10.5);

plotter.setYrange(-10.5, 10.5);

double hoehe = 0.5;

plotter.add( -hoehe, -hoehe);

plotter.add( hoehe, -hoehe);

plotter.add( hoehe, hoehe);

plotter.add( -hoehe, hoehe);

plotter.add( -hoehe, -hoehe);

// bereit fuer naechsten Datensatz

plotter.nextVector();

// Repaint bewirkt, dass neu gezeichnet wird

graphic.repaint();

}

}

51

Schreiben Sie eine Schleife, um weitere Quadrate der Seitenlänge 1, 1.5, 2, 2.5, . . .zu zeichnen:

Verwenden Sie die Methode Sleep.sleep(int msec), um nach jedem Quadrateine kurze Wartezeit einzubauen. Dabei müssen Sie mit dem Aufruf graphic.repaint();nach jedem Quadrat die Darstellung aktualisieren lassen.

Übung 6.13 ComplexWir wollen eine Klasse für komplexe Zahlen entwickeln.

• Welche Attribute (Werte) benötigen wir?

• Welche Konstruktoren schlagen Sie vor?

Es sollen implementiert werden:

• Addition mit anderer komplexer Zahl

• Betrag

• Wurzel aus einer reellen Zahl

• eine schönere Version von toString(), Vorschlag:

� falls nur Realteil oder nur Imaginärteil, dann auch nur dieser

� ansonsten Realteil ± Imaginärteil

� Beispiele: 12, 4 + 7.3i, −32i

• eine Methode zur Berechnung der Exponential-Funktion

ea+ib = ea(cos b+ i sin b)

Lassen Sie dann alle Werte a = 0, b = 0, 0.03, 0.06, . . . , 2π berechnen undmit Plotter als Punkte in der komplexen Ebene darstellen. Verwenden Siedabei plotter.setDataLineStyle(LineStyle.SYMBOL);.

Beachten Sie dabei:

52 KAPITEL 6. AUFGABEN

• Welche Methoden sind Instanzmethoden und welche Klassenmethoden (sta-tic)?

• Schreiben Sie zu jeder Methode einen Kommentar nach der Javadoc-Konvention.

• Wie testen Sie, ob die Methoden richtig arbeiten?

Übung 6.14 Plotter 2DVerwenden Sie die Klasse Plotter um ein Feld mit Beschriftungen ähnlich zu

auszugeben.

Übung 6.15 Plotter MatrixSchreiben Sie � ausgehend von der Lösung zu 6.14 � eine Methode, um ein zwei-dimensionales Feld von int-Werten zwischen 0 und 9 darzustellen.

1. Füllen Sie ein Feld (Vorschlag Gröÿe 8× 8) mit zufälligen Zahlen.

2. Lassen Sie die Werte darstellen.

3. Lassen Sie in einer Schleife immer wieder neue Werte berechnen und dar-stellen. Tipps:

• plotter .removeAllText(); löschte alle Textobjekte.

• Sleep . sleep (500); lässt die Anwendung für 500 ms schlafen.

• ersetzen Sie den Wert 0 durch einen Punkt o. ä.

53

Übung 6.16 DamenIm Schachspiel ist die Dame die stärkste Figur. Sie kann in alle Richtungenhorizontal, vertikal und diagonal beliebig weit ziehen.

1. Schreiben Sie eine Methode, um eine Dame auf ein Feld eines Schachbrettszu setzen. Alle von der Dame erreichbaren Felder sollen auf den Wert 1gesetzt werden.

2. Lassen Sie das Feld darstellen. Beispiel:

3. Lassen Sie in einer Schleife immer wieder neue Positionen berechnen unddarstellen.

Übung 6.17 FormenErweitern Sie unser Geometrie-Projekt um weitere Formen (Klassen):

• (waagrechte) Ellipse

• Stern, Vorschlag, Kreise nur zur Hilfe:

54 KAPITEL 6. AUFGABEN

• eigene Ideen ???

Implementieren Sie jeweils eine Klasse mit den benötigten Eigenschaften undeiner passenden Methode zum Zeichnen.

Übung 6.18 MalenZeichnen Sie mit unseren Geometrie-Klassen ein kleines Bild mit einem Motivnach Wahl. Beispiel Burg mit Zufallswald:

Übung 6.19 InterpolationErgänzen Sie die Klasse MausDemo (Beispiel 4.1), so dass auch Interpolations-funktionen eingezeichnet werden.

Literaturverzeichnis

[GoA08] M. Gardner and Mathematical Association of America. Hexa�exagons,probability paradoxes, and the Tower of Hanoi: Martin Gardner's �rstbook of mathematical puzzles and games. New Martin Gardner mathe-matical library. Cambridge University Press, 2008.

[Häg05] O.. Häggström. Streifzüge durch die Wahrscheinlichkeitstheorie.Springer-Lehrbuch. Springer, 2005.

55

Index

abstrakte Methoden, 22Achsbeschriftung, 14addExternMenu, 39addTopComponent, 39Archimedische Spirale, 11autoIncrementColor, 14

Bilder, 16

Collatz-Folge, 49

Darstellungsbereich, 14DOT, 12

Farben, 14FilePlotter, 42FILL, 13

Gerätekoordinaten, 17getDataObject, 8GGT, 48Graphic, 3, 39

HIDDEN, 13HISTOGRAM, 17Histogramm, 48

Irrfahrt, 27

JPanel, 16

komplexe Zahlen, 51Koordinatensystem, 17

Landes�agge, 46Langton-Ameise, 24LineStyle Demo, 29

Maus-Demo, 30, 54

Monte-Carlo-Simulation, 48

package, 3Polymorphismus, 24

random walk, 27removeText, 11RGB-Werte, 35

setDataColor, 14setDataLineStyle, 12setRange, 14setText, 8sleep, 9Sortierverfahren, 40Stack, 35STAR, 13Stroke, 13SYMBOL, 12, 17

TextObject, 8Tic Tac Toe, 32Tuerme von Hanoi, 34

VALUE, 13

Weltkoordinaten, 17

56