Tutoraufgabe 1 (Seiteneffekte):

Ähnliche Dokumente
Tutoraufgabe 1 (Seiteneekte):

Tutoraufgabe 1 (Pilze):

Programmierung WS12/13 Lösung - Übung 1 M. Brockschmidt, F. Emmes, C. Otto, T. Ströder

Methoden und Wrapperklassen

Java Übung. Übung 3. Werner Gaulke. 2. Mai Universität Duisburg-Essen Kommedia, Übung EinPro SS06, Einführung in Java - Übung.

Tutoraufgabe 1 (Zweierkomplement): Lösung: Programmierung WS16/17 Lösung - Übung 2

Institut für Informatik und Angewandte Kognitionswissenschaften

Implementieren von Klassen

Tutoraufgabe 1 (Überladen von Methoden):

Tutoraufgabe 1 (Fibonacci-Zahlen):

int i=1; //Integerzahl i anlegen und mit 1 initialisieren float wert; //Floatzahl deklarieren scanf( %f,&wert); //Wert über Tastatur eingeben

Einführung in die Programmierung für NF MI. Übung 04

Tag 4 Repetitorium Informatik (Java)

Institut für Programmierung und Reaktive Systeme 5. Dezember Programmieren I. 5. Übungsblatt

Aufgabenblatt 5. Kompetenzstufe 1. Allgemeine Informationen zum Aufgabenblatt:

Einstieg in die Informatik mit Java

Themen der Übung. Methoden und Wrapperklassen. Vorteile von Methoden. Methoden. Grundlagen

Objektorientierte Programmierung. Kapitel 22: Aufzählungstypen (Enumeration Types)

Institut für Informatik

Übungsblatt 2. Java Vorkurs (WS 2017)

Repetitorium Informatik (Java)

Tag 8 Repetitorium Informatik (Java)

Institut für Programmierung und Reaktive Systeme. Java 2. Markus Reschke

Tutoraufgabe 1 (Programmanalyse):

Ausgabe:

Grundlagen der OO- Programmierung in C#

EidP. Blocktutorium SS 2014

Einstieg in die Informatik mit Java

Methoden. Gerd Bohlender. Einstieg in die Informatik mit Java, Vorlesung vom

Objektorientiertes Programmieren (Java)

Tutoraufgabe 1 (Programmanalyse):

Vorbereitende Aufgaben

GI Vektoren

System.out.println("TEXT");

Aufgabenblatt 3. Kompetenzstufe 1. Allgemeine Informationen zum Aufgabenblatt:

2 Eine einfache Programmiersprache

Variablen. int Flugzeug. float. I write code Hund. String. long. Borchers: Programmierung für Alle (Java), WS 06/07 Kapitel

Institut für Programmierung und Reaktive Systeme. Java 6. Markus Reschke

CoMa 04. Java II. Paul Boeck. 7. Mai Humboldt Universität zu Berlin Institut für Mathematik. Paul Boeck CoMa 04 7.

Programmieren in Java -Eingangstest-

Die for -Schleife HEUTE. Schleifen. Arrays. Schleifen in JAVA. while, do reichen aus, um alle iterativen Algorithmen zu beschreiben

Übungsblatt 1. Java Vorkurs (WS 2017)

Martin Unold INFORMATIK. Geoinformatik und Vermessung

Tag 7 Repetitorium Informatik (Java)

JAVA für Nichtinformatiker - Probeklausur -

Grundlagen der Programmierung

Einführung in das Programmieren Probeklausur Lösungen

Einstieg in die Informatik mit Java

Software Entwicklung 1. Rekursion. Beispiel: Fibonacci-Folge I. Motivation. Annette Bieniusa / Arnd Poetzsch-Heffter

C# - Einführung in die Programmiersprache Methoden. Leibniz Universität IT Services

Tutoraufgabe 1 (Überladen von Methoden):

Tutoraufgabe 1 (Fibonacci-Zahlen):

Einstieg in die Informatik mit Java

Programmieren, Wintersemester 13/14 Übungsleiter: Sebastian Ebers Aufgabenblatt 3

Lösungshinweise/-vorschläge zum Übungsblatt 5: Software-Entwicklung 1 (WS 2017/18)

C++ Teil 2. Sven Groß. 16. Apr IGPM, RWTH Aachen. Sven Groß (IGPM, RWTH Aachen) C++ Teil Apr / 22

Informatik B von Adrian Neumann

II. Grundlagen der Programmierung. Beispiel: Merge Sort. Beispiel: Merge Sort (Forts. ) Beispiel: Merge Sort (Forts. )

Objektorientierung. Programmierstarthilfe WS 2010/11 Fakultät für Ingenieurwissenschaften und Informatik

Programmierung für Mathematik (HS13)

Übungsblatt 2. Java Vorkurs (WS 2015)

2 Teil 2: Nassi-Schneiderman

Grundlagen der Programmierung Teil1 Einheit III Okt. 2010

Arrays (Reihungen) Arrays (Reihungen) in Java: Syntax, Typisierung, Semantik.

Einstieg in die Informatik mit Java

5. Java Arrays und Strings

Java Cheatsheet. Mehrzeiliger Kommentar (beginnt mit /* und endet mit */)

Arbeitsblatt zu Methoden

1 Klassen und Objekte

Tag 4 Repetitorium Informatik (Java)

Umsetzung einer Klassenkarte in einer Programmiersprache

Wissenschaftliches Rechnen

Folienpaket 7 Themenschwerpunkte: Methoden in OOP /2016 Dr. Daniel Haase - Vorkurse Informatik V3/V4

Vorsichtige Programmierer verwenden Inkrement- Operatoren nicht in komplizierteren Ausdrücken

Probeklausur Informatik 2 Sommersemester 2013

Programmieren in Java

Prozeduren vs. Funktionen

Neben der Verwendung von Klassen ist Vererbung ein wichtiges Merkmal objektorientierter

JAVA - Methoden

3.2 Datentypen und Methoden

Grundlagen der Programmierung

Institut für Programmierung und Reaktive Systeme 20. November Programmieren I. 4. Übungsblatt

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

2 Eine einfache Programmiersprache

II. Grundlagen der Programmierung. 9. Datenstrukturen. Daten zusammenfassen. In Java (Forts.): In Java:

Martin Unold INFORMATIK. Geoinformatik und Vermessung

Tutoraufgabe 1 (Listen):

Transkript:

Prof. aa Dr. J. Giesl Programmierung WS12/13 M. Brockschmidt, F. Emmes, C. Otto, T. Ströder Tutoraufgabe 1 (Seiteneffekte): Betrachten Sie das folgende Programm: public class TSeiteneffekte { public static void main ( String [] args ) { [] ws = new [2]; ws [0] = new (); ws [1] = new (); ws [0]. i = 2; ws [1]. i = 1; f(ws [1], ws [1], ws [0]); f(ws [1], ws ); // Speicherzustand hier zeichnen public static void f( w1,... ws) { int sum = 0; // Speicherzustand hier zeichnen for ( int j = 0; j < ws. length ; j ++) { w = ws[j]; sum += w.i; w.i = j + 2; ws [0] = w1; w1 = ws [1]; w1.i = -sum ; public class { public int i; Es wird nun die Methode main ausgeführt. Stellen Sie den Speicher (d.h. alle (implizit) im Programm vorkommenden Arrays (außer args) und alle Objekte) an folgenden Programmstellen graphisch dar: nach der Deklaration von sum in jedem Aufruf der Methode f vor Ende der main Methode Lösung: 1

[] Methode main ws [0] int i 2 Methode f... w1 ws sum 0 [1] [] [0] int i 1 [1] [] Methode main ws [0] int i -3 Methode f w1 ws... [1] int i 2 sum 0 [] Methode main ws [0] int i 2 [1] int i 1 Aufgabe 2 (Seiteneffekte): Betrachten Sie das folgende Programm: public class HSeiteneffekte { public static void main ( String [] args ) { w1 = new (); w2 = w1; (2 + 2 + 2 = 6 Punkte) w1.i = 1; w2.i = 2; 2

3... Programmierung WS12/13 int x = 3; int [] a = { 4, 5 ; f(w2, x, a); f(w1, x, 6, a [1]); // Speicherzustand hier zeichnen public static void f( w, int x, int... a) { // Speicherzustand hier zeichnen x = a [0]; a [1] = w.i; w.i = x; public class { public int i; Es wird nun die Methode main ausgeführt. Stellen Sie den Speicher (d.h. alle (implizit) im Programm vorkommenden Arrays (außer args) und alle Objekte) an folgenden Programmstellen graphisch dar: bei jedem Aufruf der Methode f vor Ende der main Methode Lösung: Methode main w1 w2 x a int i 2 int[] [0] 4 [1] 5 Methode f w x a 3 3

3... Programmierung WS12/13 w1 Methode main w2 x a int i 4 int[] [0] 4 [1] 2 Methode f w x a 3 int[] [0] 6 [1] 2 w1 int i 6 Methode main w2 x 3 int[] a [0] 4 [1] 2 Tutoraufgabe 3 (Refactoring): In dieser Tutor- und der nachfolgenden Hausaufgabe betrachten wir die Datei Geometry.java, welche Sie von unserer Webseite herunterladen müssen. Diese benötigt zusätzlich die Datei Point.java, welche ebenfalls auf unserer Webseite herunterzuladen ist. Beim sogenannten Refactoring geht es darum, die Syntax eines Programms zu verändern, dabei aber die Semantik des Programms unverändert zu belassen. Ziel des Refactorings ist es, den Programmcode hinsichtlich seiner Les- und Wartbarkeit zu verbessern. Die vorgegebene Datei Geometry.java enthält eine main Methode, welche ein durch seine Eckpunkte bestimmtes Polygon im zweidimensionalen Raum einliest und es anschließend auf der Konsole ausgibt. Das gesamte Programm befindet sich hierbei in der main Methode, welche dadurch groß und unübersichtlich ist. Ein besserer Programmierstil ist es, wenn das Programm in mehrere Abschnitte unterteilt und in verschiedenen Methoden implementiert ist. So wird die Hauptstruktur direkt ersichtlich, das Programm kann schneller verstanden und eventuelle Fehler können leichter gefunden werden. Um die Größe einer Methode zu messen, existieren verschiedene Metriken. Eine solche Metrik ist die NCSS (Non-Commenting Source Statements) Metrik. Diese zählt die Anweisungen, Verzweigungen und Schleifen innerhalb einer Methode. Setzt man voraus, dass jede Schleife und jede Verzweigung Blockanweisungen benutzt (also z. B. Verzweigungen der Form if (Bedingung) {Anweisung(en), aber nicht der Form if (Bedingung) Anweisung;), so entspricht diese Metrik der Anzahl der Semikola am Ende von Anweisungen und der öffnenden geschweiften Klammern innerhalb einer Methode (d. h. die erste öffnende geschweifte Klammer des Methodenrumpfes selbst zählt nicht dazu). Die main Methode des gegebenen Programms hat eine NCSS von 35. 4

a) Im ersten Teil des Programms werden die vier Variablen minx, maxx, miny und maxy initialisiert und in der anschließenden Schleife mit den Extremkoordinaten (Minimum und Maximum) in beiden Dimensionen belegt. Schreiben Sie eine Klasse ExtremeCoordinates, welche vier nicht-statische int Attribute minx, maxx, miny und maxy hat. Schreiben Sie in dieser Klasse zusätzlich eine statische Methode create() mit Rückgabetyp ExtremeCoordinates, welche ein neues Objekt dieses Typs anlegt, alle seine Attribute mit 0 belegt und dieses Objekt dann zurück liefert. b) Lagern Sie nun den ersten Teil des Programms (vom Kommentar Eingabe der Punkte des Polygons und Bestimmung der Extremkoordinaten bis zum Kommentar Ausgabe des Polygons auf der Konsole ) in eine statische Methode input(point[] polygon) mit Rückgabetyp ExtremeCoordinates aus. Ersetzen Sie dabei die Initialisierung der Variablen minx, maxx, miny und maxy durch einen Aufruf der create() Methode aus der Klasse ExtremeCoordinates und die Belegung der ersetzten Variablen durch eine Belegung der entsprechenden Attribute im erzeugten ExtremeCoordinates Objekt. Liefern Sie dieses Objekt am Ende der Methode input zurück. In der main Methode müssen Sie ebenfalls alle Vorkommen der ersetzten Variablen durch Zugriffe auf die entsprechenden Attribute des zurückgelieferten ExtremeCoordinates Objektes ersetzen. c) Lagern Sie nun den zweiten Teil des Programms (ab dem Kommentar Ausgabe des Polygons auf der Konsole ) in eine statische Methode output(extremecoordinates ex, Point[] polygon) ohne Rückgabe aus. Sie benötigen nun in der main Methode keine Variable mehr, welche das in der input Methode erzeugte ExtremeCoordinates Objekt speichert, sondern können den Aufruf der input Methode direkt als erstes Argument der output Methode nutzen. Die NCSS der main Methode soll anschließend 3 betragen. Nun spiegelt die main Methode genau die oben beschriebene Struktur des Programms wider. Lösung: // kapselt Minima und Maxima in zwei Dimensionen public class ExtremeCoordinates { public int maxx ; public int maxy ; public int minx ; public int miny ; // Initialisierung der Extremkoordinaten public static ExtremeCoordinates create () { ExtremeCoordinates res = new ExtremeCoordinates (); res. minx = 0; res. maxx = 0; res. miny = 0; res. maxy = 0; return res ; public class Geometry { // Eingabe der Punkte des Polygons und Bestimmung der Extremkoordinaten public static ExtremeCoordinates input ( Point [] polygon ) { ExtremeCoordinates res = ExtremeCoordinates. create (); for ( int i = 0; i < polygon. length ; i++) { // Einlesen eines Punktes System. out. println (" Geben Sie die X- Koordinate des " + (i + 1) + "-ten Punktes ein."); int x = Integer. parseint ( System. console (). readline ()); System. out. println (" Geben Sie die Y- Koordinate des " + (i + 1) + "-ten Punktes ein."); int y = Integer. parseint ( System. console (). readline ()); polygon [i] = Point. create (x, y); // Update der Extremkoordinaten res. minx = Math. min ( res. minx, polygon [i]. x); res. miny = Math. min ( res. miny, polygon [i]. y); res. maxx = Math. max ( res. maxx, polygon [i]. x); res. maxy = Math. max ( res. maxy, polygon [i]. y); return res ; // Liest ein Polygon ein und gibt es auf der Konsole aus public static void main ( String [] args ) { 5

// Eingabe der Anzahl Punkte, welche das Polygon bestimmen, und Anlegen des zugehoerigen Arrays System. out. println (" Geben Sie die Anzahl an Punkten ein, welche das Polygon bestimmen sollen."); Point [] polygon = new Point [ Integer. parseint ( System. console (). readline ())]; Geometry. output ( Geometry. input ( polygon ), polygon ); // Ausgabe des Polygons auf der Konsole public static void output ( ExtremeCoordinates ex, Point [] polygon ) { System. out. println (); for ( int i = ex. maxy ; i >= ex. miny ; i - -) { for ( int j = ex. minx ; j <= ex. maxx ; j ++) { Point p = Point. create (j, i); // Test, ob Punkt in Polygon liegt boolean in = false ; double sum = 0.0; for ( int k = 0; k < polygon. length ; k++) { // Berechnung des Winkels zwischen den Punkten polygon [i], p und // polygon [i + 1 % polygon. length ] // Ergebnis liegt zwischen -179 und 180 ( positive Werte zeigen einen Winkel gegen den // Uhrzeigersinn an) Point v1 = polygon [k]. sub (p); Point v2 = polygon [( k + 1) % polygon. length ]. sub (p); float signum = Math. signum ( v1. determinant ( v2 )); double angle = Math. todegrees ( Math. acos (( v1. scalarproduct (v2 )) / (v1. norm () * v2. norm ()))); angle = signum == 0? Math. round ( angle ) : signum * angle ; // Sonderfall : Punkt liegt auf einer Ecke oder Kante des Polygons if (p. equals ( polygon [k]) angle == 180) { in = true ; break ; // Aufsummierung der Winkel sum = sum + angle ; // Ist Betrag der Winkelsumme 360 ( Rundung zur Steigerung der Robustheit gegenueber // Rundungsfehlern ) oder ist der Sonderfall eingetreten, so liegt der Punkt innerhalb des // Polygons System. out. print (( in Math. abs ( Math. round ( sum )) == 360)? "#" : " "); System. out. println (); System. out. println (); Aufgabe 4 (Refactoring): (1 + 4 = 5 Punkte) In dieser Hausaufgabe soll das Refactoring aus der vorigen Tutoraufgabe weitergeführt werden. Die dort ausgelagerten Methoden input(point[] polygon) und output(extremecoordinates ex, Point[] polygon) sind immer noch recht komplex und können weiter in sinnvolle Unterabschnitte gegliedert werden. Außerdem wollen wir ein wiederholtes Auftreten des gleichen komplexen Ausdrucks (sogenannte Code-Duplikation) eliminieren. a) Schreiben Sie eine Methode readint() vom Typ int, welche einen vom Benutzer eingegebenen int Wert einliest. Ersetzen Sie sämtliche Vorkommen des Ausdrucks durch Aufrufe Ihrer neuen Methode. Integer.parseInt(System.console().readLine()) b) Lagern Sie weitere Methoden in der Datei Geometry.java aus (ohne die Semantik zu verändern), sodass die NCSS jeder Methode in der resultierenden Datei jeweils höchstens 8 beträgt. Hinweise: Die Programmkommentare liefern gute Hinweise, welche Abschnitte sinnvoll als Methoden ausgelagert werden können (überall da, wo mindestens 4 Anweisungen oder Blöcke zu einem Kommentar gehören, lässt sich die NCSS durch Methodenauslagerung reduzieren). Überlegen Sie sich, welche Variablen innerhalb eines Code-Abschnitts und nach einem Code-Abschnitt benötigt werden. Aus diesen Informationen lassen sich die Argumente und Rückgabetypen der Methoden erschließen. 6

In Methoden kann eine Schleife durch die return Anweisung direkt verlassen werden. Dadurch kann die Verwendung der Variablen in vom Typ boolean in Kombination mit der break Anweisung vermieden werden. Lösung: public class Geometry { // Berechnung des Winkels zwischen den Punkten polygon [i], p und polygon [i + 1 % polygon. length ] // Ergebnis liegt zwischen -179 und 180 ( positive Werte zeigen einen Winkel gegen den Uhrzeigersinn // an) public static double angle ( Point p1, Point p2, Point p3) { Point v1 = p1. sub ( p2 ); Point v2 = p3. sub ( p2 ); float signum = Math. signum ( v1. determinant ( v2 )); double angle = Math. todegrees ( Math. acos (( v1. scalarproduct ( v2 )) / ( v1. norm () * v2. norm ()))); return signum == 0? Math. round ( angle ) : signum * angle ; // Test, ob Punkt in Polygon liegt public static boolean inpolygon ( Point p, Point [] polygon ) { double sum = 0.0; for ( int k = 0; k < polygon. length ; k++) { double angle = Geometry. angle ( polygon [k], p, polygon [( k + 1) % polygon. length ]); // Sonderfall : Punkt liegt auf einer Ecke oder Kante des Polygons if (p. equals ( polygon [k]) angle == 180) { return true ; // Aufsummierung der Winkel sum = sum + angle ; // Ist Betrag der Winkelsumme 360 ( Rundung zur Steigerung der Robustheit gegenueber // Rundungsfehlern ), so liegt der Punkt innerhalb des Polygons return Math. abs ( Math. round ( sum )) == 360; // Eingabe der Punkte des Polygons und Bestimmung der Extremkoordinaten public static ExtremeCoordinates input ( Point [] polygon ) { ExtremeCoordinates res = ExtremeCoordinates. create (); for ( int i = 0; i < polygon. length ; i++) { polygon [i] = Geometry. readpoint ( " Geben Sie die X- Koordinate des " + (i + 1) + "-ten Punktes ein.", " Geben Sie die Y- Koordinate des " + (i + 1) + "-ten Punktes ein."); Geometry. updateextremecoordinates (res, polygon [i ]); return res ; // Liest ein Polygon ein und gibt es auf der Konsole aus public static void main ( String [] args ) { // Eingabe der Anzahl Punkte, welche das Polygon bestimmen, und Anlegen des zugehoerigen Arrays System. out. println (" Geben Sie die Anzahl an Punkten ein, welche das Polygon bestimmen sollen."); Point [] polygon = new Point [ Geometry. readint ()]; Geometry. output ( Geometry. input ( polygon ), polygon ); // Ausgabe des Polygons auf der Konsole public static void output ( ExtremeCoordinates ex, Point [] polygon ) { System. out. println (); for ( int i = ex. maxy ; i >= ex. miny ; i - -) { for ( int j = ex. minx ; j <= ex. maxx ; j ++) { System. out. print ( Geometry. inpolygon ( Point. create (j, i), polygon )? "#" : " "); System. out. println (); System. out. println (); // Einlesen eines Integers von der Konsole public static int readint () { return Integer. parseint ( System. console (). readline ()); // Einlesen eines Punktes public static Point readpoint ( String frstmsg, String scndmsg ) { System. out. println ( frstmsg ); int x = Geometry. readint (); System. out. println ( scndmsg ); int y = Geometry. readint (); 7

return Point. create (x, y); // Update der Extremkoordinaten public static void updateextremecoordinates ( ExtremeCoordinates ex, Point p) { ex. minx = Math. min ( ex. minx, p.x); ex. miny = Math. min ( ex. miny, p.y); ex. maxx = Math. max ( ex. maxx, p.x); ex. maxy = Math. max ( ex. maxy, p.y); Tutoraufgabe 5 (Blümchen): In dieser Aufgabe soll eine einfache Gartensimulation erstellt werden. Hierbei hat der Benutzer die Aufgabe, sich um das Wohlergehen verschiedener Blümchen zu kümmern, indem er diese mit der richtigen Menge Wasser versorgt. Hierbei ist es auch möglich, dass Blümchen mehr Wasser bekommen, als sie speichern können, und deswegen sterben. Weiterhin ist es möglich, nach Einsatz eines Bienchenschwarms durch Bestäubung neue Blümchen zu erzeugen. In dieser Simulation sollen mehrere Blümchenbeete verwaltet werden, wobei jedes Beet mehrere Blümchen enthalten kann. Sowohl für die Anzahl der Beete als auch für die Anzahl der Blümchen pro Beet ist eine Maximalkapazität vorgegeben. Die Simulation verläuft in Tagesschritten. Die folgende Ausgabe ist ein Beispiel für einen möglichen Tagesablauf: Tag 2 bricht an! Deine Beete sehen aktuell so aus: Beet 1: (1) Rittersporn [6/20] (Verbrauch: 6) (3) Sumpf-Schwertlilie [5/32] (Verbrauch: 5) (1) Rittersporn [12/20] (Verbrauch: 6) (3) Sumpf-Schwertlilie [10/32] (Verbrauch: 5) (1) Rittersporn [12/20] (Verbrauch: 6) (3) Sumpf-Schwertlilie [10/32] (Verbrauch: 5) --- Beet 2: (0) Tulpe [19/40] (Verbrauch: 7) (0) Tulpe [19/40] (Verbrauch: 7) --- Beet 3: (3) Sumpf-Schwertlilie [17/32] (Verbrauch: 5) (0) Tulpe [19/40] (Verbrauch: 7) --- Moechtest du Beet 1 giessen (Wassermenge: 12)? (1 fuer ja, sonst nein) 1 Das Bluemchen (1) Rittersporn [12/20] (Verbrauch: 6) wurde ertraenkt! Das Bluemchen (1) Rittersporn [12/20] (Verbrauch: 6) wurde ertraenkt! Moechtest du Beet 2 giessen (Wassermenge: 12)? (1 fuer ja, sonst nein) 0 Moechtest du Beet 3 giessen (Wassermenge: 12)? (1 fuer ja, sonst nein) 0 Deine Beete sehen aktuell so aus: Beet 1: (1) Rittersporn [18/20] (Verbrauch: 6) (3) Sumpf-Schwertlilie [17/32] (Verbrauch: 5) (3) Sumpf-Schwertlilie [22/32] (Verbrauch: 5) (3) Sumpf-Schwertlilie [22/32] (Verbrauch: 5) --- Beet 2: (0) Tulpe [19/40] (Verbrauch: 7) 8

(0) Tulpe [19/40] (Verbrauch: 7) --- Beet 3: (3) Sumpf-Schwertlilie [17/32] (Verbrauch: 5) (0) Tulpe [19/40] (Verbrauch: 7) --- Moechtest du die Bienchen losschicken? (1 fuer ja, sonst nein) 1 In welchem Beet sollen die Bienchen starten? 2 In welchem Beet sollen die Bienchen ihre Reise beenden? 3 Durch das Wunder der Bestaeubung ist das neue Bluemchen (3) Sumpf-Schwertlilie [15/32] (Verbrauch: 5) entstanden! Durch das Wunder der Bestaeubung ist das neue Bluemchen (3) Sumpf-Schwertlilie [15/32] (Verbrauch: 5) entstanden! Druecke Enter, um den naechsten Tag zu beginnen. Der Typ eines jeden Blümchens ist durch den Aufzählungstypen (enum) Typ realisiert. In dieser Aufgabe wird auch häufig der Ordinalwert (berechnet durch typ.ordinal()) verwendet. Beachten Sie folgende Anforderungen an das System: Die Simulation soll in einzelnen Tagen ablaufen, wobei pro Tag folgende Schritte in dieser Reihenfolge durchgeführt werden: 1. Der aktuelle Tag wird angezeigt. 2. Alle Blümchen verbrauchen eine Tagesration Wasser. 3. Der Zustand der Beete wird ausgegeben. Bei jedem Blümchen wird jeweils der Ordinalwert des Typs (z.b. (1)), der Name (z.b. Rittersporn), der aktuelle Wasservorrat des Blümchens (z.b. 6), der maximale Wasservorrat, den das Blümchen verträgt (z.b. 20) sowie sein Tagesverbrauch an Wasser (z.b. Verbrauch: 6) angegeben. 4. Die Beete werden nach Wunsch des Benutzers gegossen. Hierdurch erhöht sich die Wassermenge jedes Blümchens im Beet um 12 Einheiten. Falls dadurch der maximal erlaubte Wasservorrat des Blümchens überschritten wird, stirbt es. 5. Der Zustand der Beete wird ausgegeben. 6. Auf Wunsch des Benutzers wird der Bienchenschwarm losgeschickt. Die Simulation endet, wenn kein Blümchen mehr existiert. Pro Tag wird der Wasserverbrauch der einzelnen Blümchen simuliert, indem der Wasservorrat pro Blümchen um den jeweiligen Tagesverbrauch verkleinert wird. Gibt es für ein Blümchen beim Wasserverbrauchen nicht genug Wasser in seinem aktuellen Vorrat, stirbt es und existiert ab diesem Zeitpunkt nicht mehr im entsprechenden Beet. Jeden Tag ist es pro Beet möglich, alle Blümchen in diesem Beet zu gießen. Es ist nicht möglich, nur einzelne Blümchen zu gießen, es werden immer alle Blümchen des Beetes gegossen. Wird ein Blümchen so stark gegossen, dass der Maximalvorrat überschritten wird, stirbt es und existiert ab diesem Zeitpunkt nicht mehr im entsprechenden Beet. Pro Tag ist es einmal möglich, den Bienchenschwarm loszuschicken. Dieser fliegt von einem Beet A zu einem Beet B, wobei A und B identisch sein dürfen. Für jedes Blümchenpaar a A und b B wird ein neues Blümchen in Beet B erzeugt, sofern der Ordinalwert des Typs von Blümchen a echt kleiner als der Ordinalwert des Typs von Blümchen b ist. Der Typ des neuen Blümchen ist durch (typ(a) + typ(b)) % MAX definiert, wobei typ(a) und typ(b) den Ordinalwert des Typs von Blümchen a bzw. b angeben und MAX die Anzahl verschiedener Blümchentypen ist (die verschiedenen Ordinalwerte der Typen sind also 0,..., MAX 1). Aus den Blümchen a A mit typ(a) = 2 und b B mit typ(b) = 3 9

entsteht also mit MAX = 4 ein Blümchen vom Typ (2 + 3) % 4 = 5 % 4 = 1. Beachten Sie, dass neue Blümchen erst zum Schluss dieser Prozedur zum Blümchenbeet B hinzugefügt werden! Wenn in einem Beet kein Platz für ein neues Blümchen ist, wird dieses neue Blümchen ignoriert und nicht eingepflanzt (Jedes Beet kann maximal 9 Blümchen enthalten). In den Informationen, die zu einem einzelnen Blümchen angezeigt werden, müssen folgende Angaben enthalten sein: Ordinalwert des Typs, Name, aktueller Wasservorrat, maximaler Wasservorrat, Verbrauch pro Tag. Das Sterben eines Blümchens kann dadurch realisiert werden, dass der entsprechende Speichereintrag auf null gesetzt wird. Jedes neue Blümchen hat am Anfang genug Wasser für exakt drei Tage. Wenn der erlaubte maximale Wasservorrat des Blümchen hierfür nicht groß genug ist, wird der erlaubte Wasservorrat stattdessen komplett gefüllt. Sie brauchen hier nicht alles selber zu programmieren, sondern sollen auf ein bereits erstelltes Programmgerüst zurückgreifen, welches Sie bei den Materialien zu dieser Übung von der Webseite der Vorlesung herunterladen können. Dieses besteht aus den Dateien Zufall.java (für Zufallszahlen), Bluemchen.java (welche ein Blümchen darstellt), Typ.java (welche die unterschiedlichen Typen von Blümchen darstellt), Bienchen.java (welche den Bienchenschwarm darstellt), Bluemchenbeet.java (welche ein Blümchenbeet darstellt) und Garten.java (welche die Benutzerschnittstelle zur Verfügung stellt). In den Dateien Bluemchen.java, Bienchen.java und Bluemchenbeet.java sind einige Stellen mit // TO DO markiert. An diesen Stellen sollen Sie Ihre eigene Implementierung einfügen. Modifizieren Sie keine anderen Stellen im Code und legen Sie auch keine weiteren Klassen bzw. Dateien an. Sie dürfen Hilfsmethoden zu den Klassen hinzufügen. Bedenken Sie bei der Konzeption Ihrer Lösung, welche der Attribute und Methoden in den von Ihnen erstellten Klassen statisch sein sollten. Hier dürfen (noch) alle Methoden und Attribute public sein. Beginnen Sie Ihre Bearbeitung mit den folgenden drei Methoden: Bluemchen.neuesBluemchen Bluemchen.toString Bluemchenbeet.neuesBluemchen Lösung: Die Lösung finden Sie in den Files Bienchen.java, Bluemchenbeet.java und Bluemchen.java. Aufgabe 6 (Müll): (1 + 1 + 1 + 3 + 1 + 1 + 3 + 3 = 14 Punkte) Wir beschäftigen uns in dieser Aufgabe mit einer Müllverwertungsfabrik. In dieser Fabrik wird Müll mit Müllwagen angeliefert und auf Müllbänder verteilt. Auf der Homepage zur Veranstaltung finden Sie die Dateien Muell.java, Fabrik.java, Wagen.java und Band.java. Laden Sie diese bitte herunter und verändern Sie diese wie in den folgenden Aufgabenteilen beschrieben. a) Für den Müll unterscheiden wir die Sorten Rest, Metall und Plastik. Schreiben Sie einen Aufzählungstypen (enum) Sorte, der diese drei Sorten abbildet. b) Ein Stück Müll bilden wir durch ein Objekt der Klasse Muell ab. Für jedes solche Objekt merken wir uns die Sorte und ob der Müll sauber ist. Hierfür existieren in der Klassendatei schon entsprechende Felder. Erweitern Sie die Klasse Muell um eine nicht-statische Methode tostring(), die (je nach Sorte des Mülls und der Sauberkeit) eine lesbare String-Darstellung wie in den folgenden Beispielen zurückgibt. Metall Plastik Rest Plastik (sauber) 10

c) In der Klasse Wagen ist die Methode zufallswagen vorgegeben, an der Sie nichts verändern müssen und sollen. Diese Methode erzeugt ein Objekt der Klasse Wagen, der einen Müllwagen mit zufälligem Müll als Inhalt repräsentiert. Hierfür wird die statische Methode fuersorte in der Klasse Muell aufgerufen, die noch nicht existiert und von Ihnen implementiert werden soll. Die Methode fuersorte bekommt einen int-wert von 0 bis einschließlich 2 und gibt abhängig von diesem Wert ein neues Muell-Objekt zurück. Dieses Objekt ist nicht sauber und hat die Sorte, die durch das int-argument definiert ist. Wenn also beispielsweise fuersorte mit dem Argument 1 aufgerufen wird und Plastik die zweite Sorte Müll ist, soll ein neues Muell-Objekt mit der Sorte Plastik zurückgegeben werden. Hinweis: Benutzen Sie die statische Methode values(), die in jedem Aufzählungstypen existiert und ein Array der einzelnen Aufzählungswerte zurückgibt. Das Argument können Sie als Index für dieses Array benutzen. d) Ein Müllband repräsentieren wir durch die Klasse Band. Die Datei enthält bereits die Deklaration eines Attributs vom Typ Muell[], das (analog zu den Wagen) benutzt wird, um den auf dem Band befindlichen Müll zu speichern. Für die nachfolgenden Aufgabenteile möchten wir uns anzeigen lassen, was für Müll in einem Wagen bzw. auf einem Band ist. Da beide Klassen Band und Wagen ein Array vom Typ Muell[] zum Speichern benutzen, bietet es sich an, eine Hilfsmethode zu schreiben. Diese Hilfsmethode soll ein Argument vom Typ Muell[] bekommen und einen String zurückliefern, der wie in folgendem Beispiel aufgebaut ist: Metall, Plastik (sauber), Rest, Rest, Plastik Für den Ergebnis-String werden also die tostring()-ausgaben der einzelnen Muell-Objekte entsprechend miteinander verbunden. Schreiben Sie diese Hilfsmethode mit dem Namen arraytostring in der Klasse Band und deklarieren Sie diese als static, wenn dies Sinn macht. Hinweis: Beachten Sie, dass das Array auch null-einträge enthalten kann und überspringen Sie diese! Erweitern Sie anschließend die Klassen Band und Wagen jeweils um eine Methode tostring(), die einen String entsprechend obiger Beschreibung zurückgibt. Verwenden Sie hierfür jeweils die Hilfsmethode! e) Für den Betrieb der Fabrik muss der Müll aus dem Wagen auf die Bänder verteilt werden. Schreiben Sie hierfür zuerst eine nicht-statische Methode leere() in der Klasse Wagen. Diese Methode soll ein Muell- Objekt aus dem inhalt-array zurückgeben und den Array-Eintrag auf null setzen. Nach entsprechend oft wiederholter Anwendung dieser Methode soll das Array also nur noch null enthalten. Falls das Array kein Muell-Objekt mehr enthält, soll die Methode leere() null zurückgeben. f) Schreiben Sie in der Klasse Band eine Methode drauf ohne Rückgabe. Diese Methode soll ein Muell- Objekt als Argument bekommen und dieses an einer freien Stelle (also mit Inhalt null) im inhalt-array des Bandes speichern. Wenn das Array keinen null-eintrag mehr enthält, soll nichts passieren. g) Verwenden Sie nun an der mit TODO markierten Stelle in der Klasse Fabrik die Methoden leere und drauf, um den Müll aus dem Wagen auf die Bänder bandeins und bandzwei zu verteilen. Wechseln Sie hierbei nach jedem Muell-Objekt das Band, so dass das erste, dritte,... Objekt dem ersten Band und das zweite, vierte,... Objekt dem zweiten Band hinzugefügt wird. Hinweis: Beachten Sie wieder, dass das Array auch null-einträge enthalten kann und überspringen Sie diese! Geben Sie vorher und nach jedem Hinzufügen aus, welchen Inhalt die Bänder und der Wagen haben. Orientieren Sie sich hierfür an der folgenden Beispielausgabe: Wagen: Rest, Plastik, Plastik, Metall, Plastik, Plastik, Rest, Metall, Plastik, Rest Band 1: Band 2: Wagen: Plastik, Plastik, Metall, Plastik, Plastik, Rest, Metall, Plastik, Rest 11

Band 1: Rest Band 2: Wagen: Plastik, Metall, Plastik, Plastik, Rest, Metall, Plastik, Rest Band 1: Rest Band 2: Plastik Wagen: Metall, Plastik, Plastik, Rest, Metall, Plastik, Rest Band 1: Rest, Plastik Band 2: Plastik Wagen: Plastik, Plastik, Rest, Metall, Plastik, Rest Band 1: Rest, Plastik Band 2: Plastik, Metall Wagen: Plastik, Rest, Metall, Plastik, Rest Band 1: Rest, Plastik, Plastik Band 2: Plastik, Metall Wagen: Rest, Metall, Plastik, Rest Band 1: Rest, Plastik, Plastik Band 2: Plastik, Metall, Plastik Wagen: Metall, Plastik, Rest Band 1: Rest, Plastik, Plastik, Rest Band 2: Plastik, Metall, Plastik Wagen: Plastik, Rest Band 1: Rest, Plastik, Plastik, Rest Band 2: Plastik, Metall, Plastik, Metall Wagen: Rest Band 1: Rest, Plastik, Plastik, Rest, Plastik Band 2: Plastik, Metall, Plastik, Metall Wagen: Band 1: Rest, Plastik, Plastik, Rest, Plastik Band 2: Plastik, Metall, Plastik, Metall, Rest h) Nachdem der Müll nun auf die Bänder verteilt ist, soll die Fabrik damit etwas machen. Schreiben Sie die Methode bearbeite ohne Rückgabe in der Klasse Fabrik. Diese Methode soll ein Array vom Typ Muell[] übergeben bekommen und darin alle Muell-Objekte der Sorte Metall entfernen (im Array durch null ersetzen) alle Muell-Objekte der Sorte Plastik reinigen (siehe unten) alle Muell-Objekte der Sorte Rest ignorieren alle null-einträge ignorieren Zum Reinigen der Plastik-Objekte schreiben Sie in der Klasse Muell die Methode reinige() und verwenden diese. Die Methode hat kein Argument und keine Rückgabe und setzt das Attribut sauber des jeweiligen Muell-Objekts auf true. Rufen Sie die Methode bearbeite nach Ihrem bisherigen Code in der main-methode der Klasse Fabrik auf und übergeben Sie das Muell-Array des zweiten Bandes. Geben Sie anschließend den Inhalt dieses Bandes aus. Daraus ergibt sich (als Fortsetzung des vorherigen Beispiels) diese Ausgabe: Band 2: Plastik (sauber), Plastik (sauber), Rest Lösung: Die Lösung finden Sie in den Files Band.java, Fabrik.java, Sorte.java und Wagen.java. 12