Übungen zu Softwareentwicklung 1, WS 2011/12

Werbung
Übungen zu Softwareentwicklung 1, WS 2011/12
Übung 9
Name: ________________________________________ Abzugeben bis: Mi, 18.01.2012 (12:00)
Matrikelnummer: _______________________________ Bearbeitungsdauer in Stunden: _______
Nummer d. Übungsgruppe: ________________________ Name des Tutors: _________________
Name d. Übungsleiters: ___________________________ Punkte: _________________________
Aufgabe 1: Spezifische Simulation
12 Punkte
In dieser Aufgabe soll ein Java Programm implementiert werden, welches ein Ökosystem von
Pflanzen simuliert. Die in diesem Beispiel betrachteten systemischen Regeln sind frei erfunden und
entsprechen somit in keinster Weise naturwissenschaftlichen Tatsachen. Als Grundgerüst Ihrer
Implementierung finden Sie im Downloadbereich der aktuellen Übung die Klassen Simulation und
Environment sowie die abstrakte Klasse Plant.
Die Simulation soll auf dem Konzept eines sogenannten zellulären Automaten
(http://en.wikipedia.org/wiki/Cellular_automaton) basieren. Man verwendet eine 2D-Matrix als
Simulationsumgebung (Environment), wobei jedes Element bzw. jede Zelle dieser Matrix entweder
leer sein kann oder eine Pflanze (Plant) enthält. Die Entwicklung der Zellen hängt in jedem
Simulationsschritt vom derzeitigen Zustand bestimmter Nachbarzellen ab. Pflanzen haben dabei die
Möglichkeit zu wachsen (grow), sich zu vermehren (spawn) oder zu sterben (die). In diesem
einfachen Szenario sollen die beiden Pflanzenarten Blume (Flower) und Baum (Tree) modelliert
werden, die sich durch folgende Charakteristika voneinander unterscheiden.
• Pflanzenart (getTypeId() in Plant.java): Integer-Wert der Blumen von Bäumen
unterscheidet; Blume: 0 / Baum: 1
• Maximalgröße (getMaxSize() in Plant.java): bei Wachstum über diesen Wert hinaus stirbt
die Pflanze; Blume: 30 / Baum: 300
• Wachstumsrate (getMaxGrowthRate() in Plant.java): maximales Wachstum pro
Simulationsschritt; Blume: 5 / Baum: 10
• Vermehrungsdistanz (getMaxSeedDistance() in Plant.java): maximaler Radius innerhalb
dessen sich die Pflanze vermehren kann; Blume: 3 / Baum: 5
• Darstellungssymbol (getRenderChar() in Plant.java): einzelner Buchstabe, der zur
textuellen Darstellung der Simulationsumgebung dient; Blume: * / Baum: #
Implementieren Sie die Klassen Flower und Tree als nicht-abstrakte Subklassen von Plant derart,
dass die update-Methode bei jedem Simulationsschritt alle regelbasierten Aktionen der jeweiligen
Pflanze initiiert. Die Regeln sind wie folgt definiert:
• Blume: vermehrt sich falls es insgesamt <= 16 Blumen im Umkreis von 6 Zellen gibt oder
sich im Umkreis der eigenen Vermehrungsdistanz >= 3 Bäume befinden; stirbt falls es
insgesamt >= 10 Blumen im Umkreis der eigenen Vermehrungsdistanz gibt
• Baum: vermehrt sich falls es insgesamt <= 10 Bäume im Umkreis von 8 Zellen gibt oder
sich im Umkreis der eigenen Vermehrungsdistanz >= 12 Blumen befinden; stirbt falls es
insgesamt >= 8 Bäume im Umkreis der eigenen Vermehrungsdistanz gibt
• Alle Pflanzen wachsen bei jedem Simulationsschritt und sterben sobald sie ihre jeweilige
Maximalgröße überschritten haben
Benutzen Sie dabei die Methode getNumPlantsInRange der Klasse Environment um die Anzahl
bestimmter Pflanzenarten in der Umgebung zu evaluieren. Implementieren Sie in Ihren speziellen
Pflanzenklassen außerdem jeweils die clone-Methode, welche eine exakte Kopie des Objekts
zurückgibt und als Grundlage der Vermehrungsfunktionalität dient.
Die Klasse Simulation ist ein Testprogramm, das eine Simulationsumgebung der Dimension 40 x 20
anlegt und diese mit jeweils 5 zufällig platzierten Blumen und Bäumen ausstattet. Bei jedem Druck
der Eingabetaste wird ein Simulationsschritt ausgeführt bzw. mit q gefolgt von der Eingabetaste das
Programm beendet.
Die ersten 4 Simulationsschritte könnten bei einer Umgebungsdimension von 10 x 5 beispielsweise
folgendermaßen aussehen:
#
#
*##
* *
#
*
*
# # *
# *
*## *
*# * *
#
# # *
**
*## *
*# *# *
# * *
Aufgabe 2: Generische Simulation
**# # *
***
*## *
*# *# ***
#** *
12 Punkte
Anders als bei der spezifischen Simulation soll es hier ermöglicht werden neben Blumen und
Bäumen auch beliebige andere Pflanzenarten zu modellieren und zwar ohne dafür jeweils eine
spezielle Klasse anlegen zu müssen. Implementieren Sie dafür die Klasse GenericPlant als nichtabstrakte Subklasse von Plant, sodass diese sämtliche Pflanzen-Charakteristika (Pflanzenart,
Maximalgröße, etc.) als Memberattribute enthält, welche im Konstruktor definiert werden können.
Implementieren Sie in dieser Klasse die Methoden addSpawnRule und addDeathRule um das
dynamische Anlegen des Simulationsregelwerks zu ermöglichen. Um in weiterer Folge die
Entscheidung für Vermehrung bzw. Sterben treffen zu können sollen beide Methoden folgende
Parameter entgegennehmen:
int
int
int
int
range
neighborPlantTypeId
minNeighborPlants
maxNeighborPlants
//
//
//
//
für die Entscheidung relevanter Radius
gesuchter Pflanzentyp innerhalb des Radius
min. Zahl gefundener Pflanzen für pos. Entsch.
max. Zahl gefundener Pflanzen für pos. Entsch.
Legen Sie diese Regeldaten in geeigneten Datenstrukturen des Objekts ab, um sie in der updateMethode auslesen zu können. Dort sollen auf Basis der abgelegten Regeldaten Aktionen wie
Vermehren oder Sterben richtig ausgelöst werden. Die Regeln sind mit einem logischen Oder
verknüpft, d.h. sobald eine zutrifft wird die entsprechende Aktion bereits ausgelöst und keine
weitere Regel für die gleiche Aktion mehr geprüft.
Auch die generische Pflanze muss bei der Vermehrung die clone-Methode zur Verfügung stellen.
Vergessen Sie bei deren Implementierung nicht darauf, dass neben dem Kopieren der
Pflanzenattribute auch das Kopieren aller Regeldaten notwendig ist.
Adaptieren Sie die Testklasse Simulation derart, dass sie statt Flower und Tree nun die Klasse
GenericPlant dazu benutzt um Blumen und Bäume mit der gleichen Funktionalität wie vorher
nachzubilden. Legen Sie insbesondere auf das richtige Anlegen des Simulationsregelwerks Wert.
Hinweise zu Aufgabe 2:
Ein generisches Pflanzenobjekt kann natürlich nicht nur die Funktionalität der zuvor spezifizierten
Pflanzenarten Blume und Baum nachbilden, sondern auch beliebige neue Pflanzenarten definieren.
Der Grundgedanke von generischer Programmierung ist es, die Funktionalität so allgemein zu
entwerfen, dass Programmteile oder Klassen für unterschiedliche Spezialfälle einer bestimmten
Problemklasse wiederverwendet werden können. Je mehr unterschiedliche Spezialfälle es gibt desto
sinnvoller ist es eine generische Lösung anzustreben, anstatt jeden Fall spezifisch zu lösen.
Beispielsweise könnte man mittels GenericPlant die Pflanzenart Strauch wie folgt implementieren:
...
...
GenericPlant p = new GenericPlant(env, x, y, typeBush, 60, 8, 4, '~');
p.addSpawnRule(4, typeBush, 0, 5);
...
...
Das Ergebnis wäre eine Pflanze, die in der Simulationsumgebung an der Position x/y platziert ist,
die Typ ID von der Variable typeBush übernimmt und eine Maximalgröße von 60, eine
Wachstumsrate von 8 eine Vermehrungsdistanz von 4 sowie ein Darstellungssymbol von ~
aufweist. Darüber hinaus würde sich diese Pflanze in der Simulation genau dann vermehren, wenn
es im Umkreis von 4 Zellen maximal 5 Pflanzen dieser Art gibt.
Wichtige Anmerkungen zur Übung:
ƒ
Wir empfehlen auch weiterhin für Benutzereingaben (read-Operationen) die Input-Klasse zu
verwenden.
ƒ
Formatieren Sie Ihre Ausgabe der Programme so, dass diese den gegebenen Auszügen aus den
Programmabläufen aus der Übungsangabe entsprechen.
ƒ
Geben Sie für jede Aufgabe folgendes ab:
a) Lösungsidee (textuell)
b) Quelltext (Java-Programm inklusive Kommentaren)
c) Testplan (zum Testen der Grenzen und Sonderfälle des Programms)
d) Ausgabe des Programms für die Testfälle aus dem Testplan
ƒ
Achten Sie bei der Implementierung besonders auf die Verwendung adäquater Datentypen, die
Überprüfung der Benutzereingaben und die Ausgabe von Fehlermeldungen.
Herunterladen