Objektorientierte Programmierung
LVA 185.162, VL 2.0, 2009 W
| Ausgabe: | 09.12.2009 |
| reguläre Abgabe: | 16.12.2009, 13:45 Uhr |
| nachträgliche Abgabe: | 13.01.2010, 13:45 Uhr |
GartenSchlachtnachempfundenen Spiel versuchen verschiedene Gartentiere von einem Ende eines Weges durch den Garten an das andere Ende zu gelangen, um die dort wachsenden wohlschmeckenden Blumen zu fressen. Der Garten ist rechteckig und besteht ähnlich einem Schachbrett aus einer Anzahl an quadratischen Feldern. Ein Weg durch den Garten ist eine Folge von schlangenförmig aneinandergereihten Feldern mit einem Start- und einem Endfeld. Auf jedem Feld des Weges können sich beliebig viele Tiere befinden, auf jedem Feld außerhalb des Weges höchstens eine Kampfpflanze. Kampfpflanzen versuchen die Wanderung der Tiere zu verhindern, indem Sie Giftkapseln in ihrer Umgebung verstreuen. Es gibt verschiedene Arten von Kampfpflanzen, die sich in der Reichweite (= Größe des Quadrats rund um die Kampfpflanze, über das die Pflanze Giftkapseln gleichmäßig verstreut), der Stärke der Giftkapseln (= Giftmenge in der Kapsel) und der Zeit zum Produzieren von Giftkapseln (= Zeit zwischen dem Ausstreuen zweier Giftkapseln). Der Inhalt einer Giftkapsel landet auf genau einem Feld innerhalb der Reichweite der Giftpflanze. Dieses Feld wird in einer fixen Reihenfolge bestimmt, die alle Felder in der Reichweite der Pflanze einschließt. Die Tiere sind verschieden schnell unterwegs (abhängig von der Zeit, um auf das nächste Feld am Weg vorzurücken) und vertragen unterschiedliche Giftmengen, bevor sie vernichtet sind. Jedesmal, wenn ein Tier vorrückt, nimmt es die gesamte am neuen Feld liegende Giftmenge auf. Erreicht ein Tier das Ende des Weges, ist das Spiel beendet und der Spieler (der die Kampfpflanzen positioniert) hat verloren. Sind alle Tiere vernichtet, so ist das Spiel ebenso beendet und der Spieler hat gewonnen.
Simulieren sie das Spiel mittels eines nebenläufigen Java-Programms. Stellen sie dabei jedes Tier und jede Kampfpflanze durch einen eigenen Thread dar. Jedes Tier bewegt sich nach einer gewissen Zeit (wenige Millisekunden) von einem Feld des vorgegebenen Weges zum nächsten, jede Kampfpflanze platziert nach einer gewissen Zeit (wenige Millisekunden) die nächste Giftkapsel. Simulieren Sie Wartezeiten mittels der Methode Thread.sleep(n). Achtung: sleep behält alle Monitore (= Locks); Sie sollten sleep daher nicht innerhalb einer synchronized-Methode oder -Anweisung aufrufen wenn während der Wartezeit von anderen Threads aus auf dasselbe Objekt zugegriffen werden soll. Wenn ein Tier das Endfeld erreicht hat, geben Sie aus, welche Tiere noch leben und beenden alle Threads (Tiere und Pflanzen). Verwenden Sie Thread.interrupt() um einen Thread zu unterbrechen, geben Sie, falls es sich um ein Tier handelt, den Namen und die noch verbliebenen Lebenspunkte (= Giftmenge, die das Tier noch aufnehmen kann, bevor es vernichtet ist) aus, und beenden Sie den Thread. Wenn ein Tier die auf einem Feld liegende Giftmenge aufnimmt, reduzieren sich seine Lebenspunkte entsprechend. Wenn der Wert kleiner 0 wird, beenden Sie den Thread des Tieres. Stirbt das letzte Tier, beenden Sie alle Pflanzenthreads und geben Sie für jede Kampfpflanze aus, wieviele Giftkapseln sie produziert hat.
Die Klasse Test
soll (nicht interaktiv) Testläufe des Spiels durchführen und die Ergebnisse in allgemein verständlicher Form in der Standardausgabe darstellen.
Bitte achten Sie darauf, dass die Testläufe nach kurzer Zeit terminieren (maximal 10 Sekunden für alle zusammen).
Führen Sie mindestens drei Testläufe mit unterschiedlichen Einstellungen durch:
Testen Sie Ihre Lösung bitte rechtzeitig auf der g0, da es im Zusammenhang mit Nebenläufigkeit große Unterschiede zwischen den einzelnen Plattformen geben kann. Ein Programm, das auf einem Rechner problemlos funktioniert, kann auf einem anderen Rechner (durch winzige Unterschiede im zeitlichen Ablauf) plötzlich nicht mehr funktionieren.
Nebenläufigkeit kann die Komplexität eines Programms gewaltig erhöhen. Achten Sie daher besonders darauf, dass Sie den Programm-Code so klein und einfach wie möglich halten. Jede unnötige Anweisung kann durch zusätzliche Synchronisation (oder auch fehlende Synchronisation) eine versteckte Fehlerquelle darstellen und den Aufwand für die Fehlersuche um vieles stärker beeinflussen als in einem sequentiellen Programm.