Hochschule Augsburg, Fakultät für Informatik Name:... Prüfung "Programmieren 2", IN2, SS 2016 Seite 1 von 8

Save this PDF as:
 WORD  PNG  TXT  JPG

Größe: px
Ab Seite anzeigen:

Download "Hochschule Augsburg, Fakultät für Informatik Name:... Prüfung "Programmieren 2", IN2, SS 2016 Seite 1 von 8"

Transkript

1 Prüfung "Programmieren 2", IN2, SS 2016 Seite 1 von 8 Datum, Uhrzeit: , Uhr Semester: IN2 Note:... Prüfer: Prof. Meixner Dauer: 60 Min. Hilfsmittel: keine Punkte:... Diese Prüfung umfasst 8 Seiten. Alle Aufgaben sind bezogen auf die Programmiersprache Java. Imports vom Packages oder Klassen brauchen in den Programmieraufgaben nicht angegeben zu werden. Ist eine Aufgabenstellung Ihrer Meinung nach nicht vollständig oder mehrdeutig, so treffen Sie entsprechende Annahmen. Die Aufgabe Es sollen Schritt für Schritt Grundelemente eines einfachen Spieles entwickelt werden, basierend auf folgender Spielidee: Als Spielfiguren bewegen sich Ameisen (Ant) über ein Spielfeld, das aus Rasterpunkten in einem Rechteck besteht. Auf diesen Rasterpunkten kann die Ameise auf zweierlei Spielelemente treffen: Brotkrümel (Breadcrumb), die aufgegessen werden können und so als Energielieferant dienen, sowie Krater (Crater), in die eine Ameise hineinfallen kann (Da wieder herauszuklettern kostet natürlich Energie und führt zu Erschöpfung). Im Folgenden wird im Detail erklärt, was dazu zu implementieren ist. 13 P. a) Positionen auf dem Spielfeldraster werden als Vektor, also als Paar von (ganzzahligen) Koordinaten (x,y) spezifiziert. Definieren Sie dafür eine unveränderbare Klasse (immutable class) XY mit Attributen und Verhalten wie folgt: Die o. g. Koordinaten. Ein geeigneter Konstruktor. Eine Konstante ZERO_ZERO für das Paar (0, 0) als XY-Objekt. Eine plus()-methode, die auf einen Vektor einen zweiten aufaddiert. Eine isinsiderectangle()-methode, die prüft, ob der Rasterpunkt in einem Rechteck liegt, dessen linke untere, sowie rechte obere Ecke als Parameter übergeben werden. Eine assertinsiderectangle()-methode, die wie in der Methode vorher ein Rechteck übergeben bekommt und eine ungeprüfte (unchecked) OutOfBoundsException wirft (versehen mit einer Fehlermeldung), falls der Punkt nicht in dem Rechteck liegt. Definieren Sie auch diese Exception-Klasse. Geeignete Überschreibungen von der tostring(), equals()- und hashcode()-methode.

2 Prüfung "Programmieren 2", IN2, SS 2016 Seite 2 von 8 b) Ergänzen Sie folgende Enum-Definition geeignet, damit sie als typsichere Repräsentation der vier Richtungsvektoren für Ant-Bewegungen dienen kann. public enum Direction { RIGHT(new XY(1, 0)), LEFT(new XY(-1, 0)), UP(new XY(0, -1)), DOWN(new XY(0, 1)); 3 P.

3 Prüfung "Programmieren 2", IN2, SS 2016 Seite 3 von 8 c) Erstellen Sie einen JUnit-Test (Version min. JUnit 4), der die Logik der Methoden isinsiderectangle() und assertinsiderectangle() rudimentär austestet (Zwei signifikante Testfälle pro Methode sind ausreichend). import static org.junit.assert.*; import org.junit.test; public class XYTest { 7 P.

4 Prüfung "Programmieren 2", IN2, SS 2016 Seite 4 von 8 d) Nun werden für die das Spielbrett belegenden Elemente die Klassen BreadCrumb, Crater und Ant definiert. Gemeinsame Attribute und Verhalten sollen in eine Basisklasse Entity ausgelagert werden. Damit die Elemente für jeden Schritt im Rahmen der (externen) Game-Loop ihre zugehörigen Aktionen vornehmen können, ist eine Callback-Methode nextstep() (ohne Parameter) vorzusehen. Alle Elemente haben einen Aufenthaltsort (als XY-Objekt), sowie eine ganzzahlige Energie mit zugehöriger updateenergy()-methode. Für Ameisen ist das die insgesamt aufgesammelte Energie (beginnend mit einer als Konstante definierten Startenergie). Für einen Brotkrümel ist es der Nährwert in positiven Energieeinheiten. Dieser hat bei der Erzeugung eines Brotkrümels einen einheitlichen Wert und nimmt in jedem Spielschritt (wegen Austrocknung) um 1 ab, bis ein unterer Grenzwert erreicht ist. Die bei der Erstellung festgelegte individuelle und dann (aktuell) gleich bleibende negative Energie eines Kraters drückt aus, wie viel Energie es eine Ameise kostet, aus dem Krater herauszuklettern. Die Ameise braucht eine stärkere Interaktion mit dem Geschehen rundherum und bekommt daher bei der Erzeugung ein Objekt übergeben, das das Interface EntityContext(s. u.) erfüllt. Über die Methode public void requestnewmove(direction direction) soll von außen (als Folge einer Benutzereingabe oder einer Berechnung in einem BotController) vorgegeben werden können, welchen Schritt die Ameise als nächstes vollziehen soll. Endet in der vorgegebenen Richtung aus Sicht der Ameise das Spielfeld, soll die in a) definierte OutOfBoundsException geworfen werden. Andernfalls wird die gewünschte neue Position gemerkt, damit sie im folgenden Aufruf von nextstep() verarbeitet werden kann. Ebenfalls für Aufruf von außen (Kollisionslogik, s. u.) soll eine Methode stun() definiert werden, bei der per Übergabeparameter spezifiziert werden kann, wie viele Schritte die Ameise bewegungsunfähig ist. Es sollte nun evident sein, wie die Implementierung von nextstep() in der Klasse Ant unter Berücksichtigung der angeforderten neuen Position und des Stunned -Wertes aussieht. public interface EntityContext { XY getboardsize(); /** * executes move to targetxy on the board if possible and takes into account * collision rules if targetxy is already occupied by another entity * true if move to targetxy on board has been done, * otherwise ant must stay at the old position */ boolean trymove(ant ant, XY targetxy); } 20 P.

5 Prüfung "Programmieren 2", IN2, SS 2016 Seite 5 von 8

6 Prüfung "Programmieren 2", IN2, SS 2016 Seite 6 von 8 e) Nun soll eine Rumpfversion der Board-Klasse erstellt werden. Zur Verwaltung aller Spielelemente auf dem Brett soll eine Map namens entities verwendet werden, wobei als Key die Position (als XY-Objekt) des Entity und als Value das Entity selbst benutzt werden sollen. Im Konstruktor wird die Größe des Spielfeldes und die Anfangspopulation als Liste von Entities übergeben, deren Inhalt in die Map überführt werden soll. In der Methode trymove() sollen folgende Spielregeln in Code umgesetzt werden: Ist die Position targetxy frei, bewegt sich die Ameise auf dem Spielbrett dorthin. Befindet sich an der Stelle targetxy bereits eine andere Ameise, findet keine Bewegung statt. Ist dort ein Brotkrümel, geht die Ameise dorthin und isst den Krümel auf. Im Falle eines Kraters an der Stelle targetxy fällt die Ameise hinein, kann aber unter entsprechendem Energieeinsatz (s. o.) noch im selben Spielschritt wieder herausklettern und landet an derselben Stelle, von wo aus sie in den Krater hineingestürzt ist. Neben dem Energieverlust macht sich eine massive Erschöpfung bemerkbar, so dass die Ameise für nachfolgende 5 Spielschritte bewegungsunfähig (stunned) ist (vgl. Vorbereitungen in Teilaufgabe d). Erzeugen Sie zudem einen klassenspezifischen Logger und produzieren Sie exemplarisch eine geeignete Log- Meldung in Ihrem Code. Füllen Sie den nachfolgenden Code-Rahmen entsprechend. Als Gedächtnisstütze für den Umgang mit Maps und Listen dient folgendes Klassendiagramm. 12 P. public class Board implements EntityContext { public Board(XY size, List<Entity> entitylist) {

7 Prüfung "Programmieren 2", IN2, SS 2016 Seite 7 von 8 public XY getboardsize() { public boolean trymove(ant ant, XY targetxy) {

8 Prüfung "Programmieren 2", IN2, SS 2016 Seite 8 von 8 f) Der nächste Schritt wäre nun, eine JavaFX-GUI für das Rendern des Boards und das Steuern einer Ameise per Benutzereingabe (im Single-Player-Modus) aufzusetzen, sowie in einem Launcher diese GUI und die Game- Loop zu starten. Welche Threads sind damit im Spiel und wie könnten sich diese ins Gehege kommen? Identifizieren Sie konkret in Ihrem Code Stellen, wo die Nebenläufigkeit beim Speicherzugriff berücksichtigt werden müsste. Welche Maßnahmen würden Sie ergreifen (oder haben Sie evtl. oben schon ergriffen)? Hier sind nur textuelle Erläuterungen verlangt, kein Code! 5 P.