Workshop zu Folge 9.3 Überarbeitete Version vom Mai 2016

Ähnliche Dokumente
Schritt 1 - Ein Spielfeld

8.6 Visualisierung der Sortieralgorithmen

7.5 Mit bunten Kreisen spielen

Objektorientierte Programmierung OOP Objektorientierte Programmierung (OOP) mit Java

Vorlesung Informatik II

Java programmieren mit JavaKara. Eine Zusammenfassung in Beispielen

Universität Paderborn Prof. Dr. Stefan Böttcher. Kapitel 3: Java Applets

Einführung in die Programmierung für Nebenfach Medieninformatik. Beat Rossmy, Michael Kirsch

import java.applet.applet; import java.awt.*; public class Grow extends Applet { public void start() { setbackground(color.orange); } public void

Java Game Development Fabian Birzele Programmierpraktikum 2008 / 2009

Parallele Prozesse Prozeß Parallele Prozesse verzahnte Prozesse Nebenläufige Prozesse: Threads Vorlesung Software-Entwicklung / Folie 131 Ziele:

Einführung in die Programmierung für Nebenfach Medieninformatik. Beat Rossmy, Michael Kirsch

Probeklausur Informatik 2 Sommersemester 2013

Institut für Programmierung und Reaktive Systeme 25. Januar Programmieren I. Übungsklausur

Institut für Programmierung und Reaktive Systeme 17. Juli Programmieren II. Übungsklausur

Klassen und Objekte. Klassen sind Vorlagen für Objekte. Objekte haben. Attribute. Konstruktoren. Methoden. Merkblatt

Praktikum 4: Grafiken und Ereignisse

Felder. M. Jakob. 28. April Gymnasium Pegnitz

Der Ball kann angezeigt werden: anzeigen( ) {... } Der Ball kann z.b. seine Größe verändern: groesseaendern(int veraenderung) {... } usw.

Arbeitsblätter für die Lehrveranstaltung OOP JAVA 4

7. Arrays. Beim Deklarieren und Initialisieren der Liste bräuchte man oft zueinander sehr ähnlichen Code:

2 Eine einfache Programmiersprache

2 Eine einfache Programmiersprache. Variablen. Operationen Zuweisung. Variablen

M3 M4 M7 VORNAME: Gewinnt VERTIEFUNG:

Felder. Inhaltsverzeichnis. M. Jakob. 28. April Begriffsbildung. Verwendung von Feldern. Gymnasium Pegnitz

Einstieg in die Informatik mit Java

Institut für Programmierung und Reaktive Systeme 2. Februar Programmieren I. Übungsklausur

Programmieren in Java -Eingangstest-

Aufgabe 5.1 (Laboraufgabe, Nocheinmal ein wenig Graphik)

2 Eine einfache Programmiersprache

2 Eine einfache Programmiersprache

Dr. Monika Meiler. Inhalt

Keine Bepunktung! Betreutes Programmieren Vorlesung Informatik II, Blatt 12 SS 2011

AK-Automatisierungs und Kommunikationstechnik TI Technische Informatik. NWT Netzwerktechnik

Institut für Programmierung und Reaktive Systeme 7. Juli Programmieren II. Übungsklausur

Probeklausur Java Einführung in die Informatik. Wintersemester 2016/2017

Universität Augsburg, Institut für Informatik Sommersemester 2001 Prof. Dr. Martin Ester 08. Oktober Klausur II

Java: Eine kurze Einführung an Beispielen

Lösungsvorschläge zur Nachklausur zum Kurs 1618 Sommersemester 2001 am

Klausur Software-Entwicklung März 01

Softwaretechnik 1 Übung 5

Durch die Teil-von-Beziehung soll ausgedrückt werden, dass ein Objekt A als (physikalischer) Teil eines Objekts B angesehen wird. Insbesondere kann ei

Probeklausur Java Einführung in die Informatik. Wintersemester 2017/2018

3.2 Datentypen und Methoden

Greenfoot: Verzweigungen Nicolas Ruh und Dieter Koch

Greenfoot: Verzweigungen

ÜBUNGS-BLOCK 7 LÖSUNGEN

Probeklausur: Programmierung WS04/05

Institut für Programmierung und Reaktive Systeme 6. Juli Programmieren II. Übungsklausur

1 Klassen anlegen und Objekte erzeugen

Kapitel 18 Jetzt kommt Bewegung ins Spiel

Programmieren C: Schwerere Weihnachtsbeispiele

Lebenszyklus von Threads

Verkettete Datenstrukturen: Listen

// // // // // erstellt von W. Stickler import java.applet.*; import java.awt.*; import java.awt.image.*;

Abschlussklausur Lösung. Bitte in Druckschrift leserlich ausfüllen!

Einführung in die Programmierung für Nebenfach Medieninformatik. Beat Rossmy, Michael Kirsch

2 Eine einfache Programmiersprache

1 Klassen anlegen und Objekte erzeugen

Ein einfaches Adventure-Game für die Stufe EF, entwickelt von U. Helmich, inspiriert durch viele bekannte Spiele.

Klausur zur Lehrveranstaltung. Technische Informatik für Ingenieure WS 2008/09

Klausur zur Informatik A WS 2001/2002 Name: Korrektor: Punkte: a) Zeichnen Sie zu der nachstehenden Syntax in EBNF die passenden Syntaxdiagramme.

Kapitel 9 Das Labyrinth

Graphical User Interfaces

Test-Klausuraufgaben Softwaretechnik Fachbereich BW, für WINFO

Grundlagen von C# - 2

Parallele Prozesse. Prozeß wartet

06 While-Schleifen. While-Schleifen 1/7 Wiederholung: Schleifen

2 Teil 2: Nassi-Schneiderman

Einführung in die Informatik - Teil 6a -

Inhaltsverzeichnis. Rechenmaschinen - EINFÜHRUNG IN DIE OOP MIT JAVA PI - KAPITEL 1: GRAFIK UND GUIS - V SEITE 1 VON 10 -

Übung Nr. 20 Freitag, 09:00-11:00 Uhr in E3.301

Javakurs für Fortgeschrittene

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

EAD II Übung 5. Graphische Benutzungsoberfläche mit BlueJ

Liste Programmieren Java Überblick

Anregungen zu Übung 2

Algorithmen und Programmierung. Zusatzaufgaben Java Tutorium 1

Algorithmen implementieren. Implementieren von Algorithmen

1. Teilklausur Gruppe A. Bitte in Druckschrift leserlich ausfüllen!

Einfache Arrays. Dr. Philipp Wendler. Zentralübung zur Vorlesung Einführung in die Informatik: Programmierung und Softwareentwicklung

Einstieg in die Informatik mit Java

Arrays. Theorieteil. Inhaltsverzeichnis. Begriffe. Programmieren mit Java Modul 3. 1 Modulübersicht 3

FAKULTÄT FÜR INFORMATIK

OOP Aufgabenblatt 7 6. Dezember 2013

einlesen n > 0? Ausgabe Negative Zahl

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

Technische Universität Braunschweig

Technische Universität Braunschweig Institut für Programmierung und Reaktive Systeme

Organisatorisches. Folien (u.a.) gibt's auf der Lva-Homepage zum Download

Beispielprüfung CuP WS 2015/2016

5 Das Projekt Apfelwein

1 Modellierung einer Uhr

Mussten wir eine ganze Reihe solcher Zahlen speichern, haben wir das eindimensionale Array verwendet.

Einführung in das Programmieren Probeklausur Lösungen

1. Klausur - Probeklausur

Neben der Verwendung von Klassen ist Vererbung ein wichtiges Merkmal objektorientierter

Programmiervorkurs Einführung in Java Tag 3

Transkript:

Workshop zu Folge 9.3 Überarbeitete Version vom Mai 2016 Schritt 1 - Ein Spielfeld Wir beginnen mit zwei einfachen Java-Klassen, dem eigentlichen Spielfeld und dem Applet zum Anzeigen des Spielfeldes. Hier zunächst der komplette Quelltext der Klasse Spielfeld: import java.util.random; import java.awt.*; public class Spielfeld int[][] feld; Random rand = new Random(); public Spielfeld() feld = new int [50][50]; int zufall = rand.nextint(10); if (zufall < 9) feld[x][y] = 0; else feld[x][y] = 1; public void anzeigen(graphics g) if (feld[x][y] == 1) g.setcolor(new Color(0,127,0)); else if (feld[x][y] == 0) g.setcolor(color.yellow); g.fillrect(50+x*8, 20+y*8,8,8); g.setcolor(new Color(127,127,127)); g.drawrect(50+x*8, 20+y*8,8,8); Die "lebendigen" Felder werden durch die Farbe Dunkelgrün und die "toten" Felder durch die Farbe Gelb repräsentiert. Es steht Ihnen frei, dies zu ändern. Seite 1 von 11

Schritt 2 - Das Applet import java.awt.*; import javax.swing.*; public class Anzeige extends JApplet Spielfeld welt; public void init() welt = new Spielfeld(); public void paint(graphics g) welt.anzeigen(g); Der Quelltext des Java-Applets ist recht kurz, aber so wollten wir das ja immer halten: Nur das Notwendigste soll in dem Applet-Quelltext stehen, alles andere soll in die untergeordneten Klassen ausgelagert werden. Und hier die Ausgabe, die uns das Applet liefert: 9.3-1 Die erzeugte Welt Seite 2 von 11

Schritt 3 - Berechnung der neuen Generation Wir wollen jetzt eine neue wichtige Methode in die Klasse Spielfeld einbauen: public void neuerzyklus() // temporäres Feld berechnen int s = nachbarsumme(x,y); if (s == 0) // wenn kein Nachbar lebt temp[x][y] = 0; // ist das nicht gut für die Zelle else if (s < 3) // wenn 1 oder 2 Nachbarn leben temp[x][y] = 1; // lebt unsere Zelle auch weiter else // wenn 3 oder 4 Nachbarn leben temp[x][y] = 0; // ist das zu viel Stress und die // Zelle stirbt. // tatsächliches Feld aktualisieren feld[x][y] = temp[x][y]; Sie sehen hier den Quelltext der Methode neuerzyklus(). Die beiden geschachtelten for-schleifen am Anfang der Methode untersuchen jede der 50 x 50 Zellen und ermitteln mithilfe einer noch zu entwickelnden sondierenden Methode nachbarsumme() die Zahl der lebenden Nachbarn für jede Zelle. Dabei wird von einer Torus-Welt ausgegangen. Wenn eine Zelle keinen lebenden Nachbarn hat (s == 0), so ist sie in der nächsten Generation tot. In dem Hilfs-Array temp wird das entsprechende Feld daher auf den Status 0 gesetzt. Hat eine Zelle bzw. ein Feld einen oder zwei lebende Nachbarn (s < 3), so wird der Status für die nächste Generation auf 1 gesetzt. Wenn beide vorherigen Bedingungen (s == 0) und (s < 3) nicht zutreffen, hat die Zelle drei oder vier lebende Nachbarn, und die Zelle stirbt im nächsten Zyklus. Wozu dient der Array temp, der hier benutzt wird? Der Hilfsarray temp wird zusammen mit dem Hauptarray feld am Anfang der Klasse Spielfeld deklariert: int[][] feld, temp; Um den Status eines Einzelfeldes in der Folgegeneration zu berechnen, werden die Zustände der vier Nachbarfelder in der aktuellen Generation ausgewertet. Würde nun der Zustand des gerade betrachteten Einzelfeldes sofort im Array feld geändert, so wäre die Berechnung für den rechten und den unteren Nachbarn dieses Einzelfeldes nicht mehr korrekt. Seite 3 von 11

9.3-2 So darf man es nicht machen! Dieses Bild zeigt, was passieren würde, wenn man den Status des Feldes B2 sofort verändern würde. Im rechten Teil des Bildes sieht man, dass jetzt der Status des Feldes C2 falsch berechnet wird. Da B2 bereits (voreilig) den Folgezustand 1 angenommen hat, hat das Feld C2 plötzlich einen lebenden Nachbarn und nimmt daher den falschen Folgezustand 1 an. An sich hat das Feld C2 in der aktuellen Generation keinen lebenden Nachbarn (siehe linkes Teilbild), daher müsste der Folgezustand von C2 = 0 sein. Um den Status der Nachbarn zu berechnen, darf das Einzelfeld noch nicht seinen Status ändern, sondern muss den alten Status behalten. Der neue Status des Einzelfeldes wird vorübergehend in dem Hilfsarray temp gespeichert. Erst wenn die Berechnung für alle Felder abgeschlossen ist, werden alle Felder auf den berechneten und in temp zwischengespeicherten Status gesetzt: feld[x][y] = temp[x][y]; Seite 4 von 11

Übung Übung 9.3-1 (2 Punkte) Schreiben Sie jetzt die noch fehlende Methode nachbarsumme(), die die Zahl der lebenden Nachbarn eines Feldes zurück liefert. Jedes Feld hat genau vier Nachbarn: links, rechts, oben und unten, und die Rand- und Eckfelder sind mit den Feldern der gegenüberliegenden Seite verknüpft, wie bei einer Torus-Welt. Schritt 4 - Realisierung der Torus-Welt In den Quelltexten, die wir bisher besprochen haben, hat die Welt noch keinen Torus-Charakter. Die Zellen am linken Rand haben also keinen linken Nachbarn, die Zellen am rechten Rand keinen rechten Nachbarn. Gleiches gilt für die Zellen am oberen und am unteren Rand. Um eine Torus- Welt zu realisieren, gibt es grundsätzlich zwei Möglichkeiten. Möglichkeit 1 Wir schreiben eine Methode, welche den linken Rand der Welt mit dem rechten Rand verbindet und anschließend den oberen Rand mit dem unteren Rand. Diese Methode muss immer dann aufgerufen werden, wenn ein Zyklus abgeschlossen ist. Allerdings setzt dieses Verfahren einen etwas größeren zweidimensionalen Array voraus: Statt einem 50 x 50 Array verwenden wir einen 52 x 52 Array. 9.3-3 Die Ränder werden "verklebt" Das Bild 9.3-3 zeigt, wie dieses "Verkleben der Ränder" funktioniert, an einem 5 x 5 - Array. Rechts sieht man, wie gerade der Inhalt des Feldes 2,1 in das virtuelle Feld 2,6 kopiert wird. Das Feld 1,3 wird in das Feld 6,3 gesichert. Diese Kopieraktion muss natürlich für alle Randfelder durchgeführt werden, nicht nur für die zwei hier eingezeichneten. Da drängt sich doch sofort eine for-schleife auf, die das für uns erledigt, vielleicht auch zwei for-schleifen, eine für die senkrechten und eine für die waagerechten Randfelder. Seite 5 von 11

9.3-4 Die Zahl der Nachbarn kann leicht berechnet werden Das Bild 9.3-4 zeigt, dass jetzt die Zahl der Nachbarn eines beliebigen Feldes sehr einfach ermittelt werden kann, selbst wenn das Feld ein Eckfeld ist, wie das rot markierte. Möglichkeit 2 Wir schreiben uns private Hilfsmethoden wie beispielsweise nachbaroben(): private int nachbaroben(int x, int y) if (y == 0) return feld[x][49]; else return feld[x][y-1]; Der Vorteil ist der, dass wir die Ränder der Welt nicht verkleben müssen. Allerdings brauchen wir dann vier solcher Methoden, nämlich für jede Richtung eine. Mit Hilfe dieser privaten Methoden kann man dann die Zahl der lebenden Nachbarn genau so einfach berechnen wie mit dem ersten Verfahren. Seite 6 von 11

Übungen Übung 9.3-2 (3 Punkte) Statten Sie das Applet mit einem Button "nächste Generation" oder "nächster Zyklus" aus. Wenn dieser Button geklickt wird, soll die Methode Spielfeld.neuerZyklus() ausgeführt werden. Durch die paint()-methode des Applets wird die Welt dann wieder neu gezeichnet. Vergessen Sie nicht den Aufruf von repaint() in der ActionPerformed()-Methode! Übung 9.3-3 (2 Punkte) Ergänzen Sie das Applet um einen zweiten Button "neues Spiel". Wenn dieser Button geklickt wird, so startet ein neues Spiel mit einer neuen Zufalls-Belegung der Felder. Seite 7 von 11

Exkurs für Experten Bisher hatten wir den Zustand der Felder in der nächsten Generation wie mithilfe einer komplizierten if-else-anweisung berechnet, welche die Übergangsfunktion des Automaten repräsentiert: int s = nachbarsumme(x,y); if (s == 0) temp[x][y] = 0; else if (s < 3) temp[x][y] = 1; else temp[x][y] = 0; Betrachten Sie nun eine alternative Möglichkeit: temp[x][y] = zustand[nachbarsumme(x,y)]; Diese drei Zeilen leisten genau das Gleiche wie der obige Quelltext. In einem neuen Array zustand, der aus genau fünf int-zahlen besteht, werden bei der Deklaration / Initialisierung die Folgezustände gespeichert: int[] zustand = 0,1,1,1,0; Diese Anweisung erfolgt am Anfang der Klasse Spielfeld bei der Deklaration der Attribute. Dieser Array ist nichts anderes als die Umsetzung der Tabelle mit der Übergangsfunktion: Zahl der lebenden Nachbarn = Index des Arrays zustand Neuer Zustand = Wert des jeweiligen Arrayelements 0 0 1 1 2 1 3 0 4 0 9.3-5 Die Übergangsfunktion, implementiert als Array Die Zahl der lebenden Nachbarn wird einfach als Index der Arrayelemente interpretiert, der neue Zustand ist dann der jeweilige Wert. Seite 8 von 11

Schritt 5- ein Timer Es ist schon sehr lästig, wenn man jedes Mal auf den Button "nächster Zyklus" klicken muss, um die nächste Generation der Felder zu berechnen. Viel schöner wäre es, wenn das Applet automatisch alle 200 Millisekunden oder alle 100 Millisekunden eine neue Generation berechnen und zeichnen würde. In Java geht das ohne Weiteres, man muss das Applet dazu mit einem Timer ausstatten. Die erforderlichen Komponenten finden wir in der Klasse Runnable, die wir in das Applet einbinden müssen: public class Anzeige extends JApplet implements ActionListener, Runnable Der Timer ist ein Attribut der Klasse Thread. Unter einem Thread versteht man einen Teil eines Prozesses, der gemeinsam mit anderen Threads vom Betriebssystem ausgeführt wird. Jeder Thread besitzt seinen eigenen Befehlszähler und seinen eigenen Stack, auf dem wichtige Informationen, zum Beispiel Zwischenergebnisse, abgelegt werden können. Weitere Erklärungen würden hier zu weit führen. Die Klasse Runnable stellt zwei wichtige Methoden zur Verfügung, die in dem Applet auf jeden Fall überschrieben werden müssen, sonst streikt der Compiler. Runnable ist eine abstrakte Klasse, stellt also nur leere Methoden bereit, die noch mit Inhalt gefüllt werden müssen - und das geschieht dann beim Überschreiben. Diese beiden Methoden heißen start() und run(). Die früher oft verwendete Methode stop() wird in aktuellen Java-Versionen nicht mehr verwendet. Deklaration des Timers Thread uhr; Das war ja kurz. Initialisierung des Timers Für die Initialisierung des Timers benötigen wir jetzt die start()-methode des Applets, die wir bisher ja immer gelöscht hatten. public void start() if (uhr == null); uhr = new Thread(this); uhr.start(); Falls also in start() festgestellt wird, dass noch kein Timer initialisiert wurde (uhr == null), so wird der Timer initialisiert und gestartet. Seite 9 von 11

Die wichtige run-methode Betrachten wir nun die run()-methode, die wir ebenfalls neu schreiben (überschreiben) müssen: public void run() while (true) welt.neuerzyklus(); repaint(); try Thread.sleep(200); catch (InterruptedException e) Das zentrale Element der run()-methode ist eine endlose while-schleife; die Bedingung while(true) ist immer erfüllt, daher läuft die while-schleife ständig. Im Wesentlichen werden in der Schleife drei Anweisungen ausgeführt: 1. Zunächst wird Spielfeld.neuerZyklus() aufgerufen und damit die nächste Generation berechnet. 2. Mit dem repaint()-befehl wird das neue Spielfeld vom Applet gezeichnet. 3. Und mit der Thread.sleep()-Anweisung wird der Thread für eine kurze Zeitspanne (hier 200 Millisekunden) angehalten. Der Aufruf der sleep()-anweisung kann allerdings zu Problemen führen, vor allem, wenn mehrere Threads vom Betriebssystem gleichzeitig ausgeführt werden, was ja fast immer der Fall ist. Daher versucht das Programm mit try diese Anweisung auszuführen. Wenn der Versuch gelingt, ist alles gut. Wenn nicht, wird im catch-zweig eine interne Fehlerroutine aufgerufen. Nach 200 ms wird ein neuer Schleifendurchgang gestartet, eine neue Generation berechnet und gezeichnet. Dann wird wieder 200 ms gewartet, bis die Schleife erneut gestartet wird. Erst wenn der Benutzer das Java-Applet beendet, wird die while-schleife gestoppt. Seite 10 von 11

Übungen Übung 9.3-7 (4 Punkte) Bauen Sie die besprochenen Methoden in Ihr Applet ein, geben Sie den Buttons sinnvolle Namen und beobachten Sie den Verlauf des Automaten über mehrere Hundert Zyklen. Übung 9.3-8 (2 Punkte) Zeigen Sie mit dem g.drawstring()-befehl ständig die Zahl der bereits zurückgelegten Zyklen im Applet an! Achten Sie auf eine lesbare Ausgabe der Zahl! Übung 9.3-9 (2 Punkte) Probieren Sie andere (komplexere) Übergangsfunktionen in der Klasse Spielfeld aus und dokumentieren Sie Ihre Ergebnisse zum Beispiel durch Screenshots oder besser durch eine Präsentation vor dem Kurs. Übung 9.3-10 (2 Punkte) Experimentieren Sie mit mehr als zwei Zuständen, zum Beispiel "lebendig", "krank", "tot". Übung 9.3-11 (2 Punkte) Experimentieren Sie mit mehr als vier Nachbarn, indem Sie die diagonalen Nachbarn ebenfalls mit berücksichtigen. Übung 9.3-12 (2 Punkte) Berücksichtigen Sie in Ihrer komplexeren Übergangsfunktion den bisherigen Zustand der jeweiligen Zelle. Lebende Zellen sollen sich anders verhalten als tote Zellen. Damit ist der Kurs "Einführung in das Programmieren mit Java" für die Stufe EF beendet. Die Folge 9 werden viele EF-Kurse wahrscheinlich nicht mehr schaffen, was aber auch nicht schlimm ist; man kann die Folge 9 auch sehr gut als Einstieg für die Stufe Q1 verwenden. Seite 11 von 11