Subversion mit BlueJ, die Fortsetzung

Ich habe vor ein paar Jahren schon mal über Subversion mit BlueJ geschrieben, inzwischen habe ich das mit Schülern weiter erprobt und mit Peter Brichzin einen Workshop dazu auf der INFOS15 gehalten. Subversion: So heißt ein verbreitetetes System, mit dem verschiedene Autoren gleichzeitig an einem aus vielen Dateien bestehenden Progammierprojekt arbeiten können, so dass jeder jeweils die aktuelle Fassung der anderen Teammitglieder zur Verfügung hat.
Für den Workshop habe ich eine kleine Broschüre gemacht (ich mag Broschüren), hier ist deren Inhalt, falls mal jemand danach sucht.


Teil 1 – Auschecken

Teamarbeits-Menü einschalten

Bevor man den in BlueJ integrierten SVN-Client benutzen kann, muss man ihn frei­schalten. Dazu muss man im Menü unter „Werkzeuge > Einstellungen… > Inter­face“ ein Häkchen setzen bei „Teamarbeitswerkzeuge anzeigen“.

Erstmalig ein BlueJ-Projekt aus einem Reposito­ry aus­checken

Es ist egal, ob man an dieser Stelle mit einem bereits geöffneten BlueJ-Projekt arbeitet oder nicht, die neu heruntergeladenen Dateien werden auf jeden Fall als neues, eige­nes BlueJ-Projekt gespeichert.

Nach Auswahl des Menüpunkts „Werkzeuge > Teamarbeit > Arbeitskopie erstel­len…“ muss man die Serverangaben eingeben:

svn_anmelden

Das Passwort braucht man bei öffentlichen Repositories nur für das Hochladen; aller­dings verlangt BlueJ auf jeden Fall die Eingabe eines (auch beliebigen) Benutzerna­mens.

Danach kann man sich mit dem Knopf „Anzeigen“ die unter dieser Adresse gespei­cherten BlueJ-Projekte zeigen lassen:

svn_projektauswahl

Nach der Auswahl des BlueJ-Projekts, das man herunterladen möchte, wird man gebe­ten, einen Speicherort dafür anzugeben. Das heißt, die Dateien werden auf jeden Fall in einem neuen BlueJ-Projekt gespeichert.

Tipps:

  • Das Auschecken erfolgt üblicherweise nur einmal am Anfang. Da­nach lädt man nicht mehr das ganze Projekt neu vom Server herunter, sondern aktualisiert nur die auf dem Server geänderten Dateien oder fügt eigene Ände­rungen der Version auf dem Server hinzu.
  • Ausnahme: Wenn später einmal irgendetwas mit dem eigenen BlueJ-Projekt nicht funktioniert oder zu kompliziert wird, dann ist es manchmal einfacher, die Datei­en wieder ganz neu vom Server auszuchecken und mit einem neuen BlueJ-Pro­jekt weiterzuarbeiten. Man muss nur daran denken, das alte zu löschen.
  • Fehlerquelle: Beim Speichern reicht ein Laufwerksbuchstabe nicht, man muss einen Ordner angeben, in den dann der BlueJ-Projektordner gespeichert wird. Wenn man den Namen eines bereits existierenden BlueJ-Projekts angibt, kann das dazu führen, dass ein BlueJ-Projekt innerhalb eines anderen gespeichert wird (als package), was alles nur komplizierter macht.

Aufgabe: Checken Sie beliebige Projekte aus dem Server aus, aber auf jeden Fall das BlueJ-Projekt „SVN Aufgabe 1“ für den nächsten Schritt.


Teil 2 – Erstes Arbeiten

Benutzername und Passwort eingeben

Checken Sie das BlueJ-Projekt „SVN Aufgabe 1“ aus.

Bisher waren Benutzername und Passwort egal, aber ab diesem Zeitpunkt müssen Sie konkrete Daten eingeben. Wählen Sie dazu im Menü „Werkzeuge > Teamarbeit > Teamarbeitseinstellungen…“ und ergänzen Sie die fol­genden Informationen:

svn_teamarbeitseinstellungen

Der Benutzer ist „fortbildung“, das Passwort erfahren Sie mündlich.

Aktualisieren (update) und Abgeben (commit)

Aufgabe: Legen Sie in „SVN Aufgabe 1“ eine neue Klasse an, die das Interface „Tier“ implemen­tiert. Die Klasse „Loewe“ kann als Beispiel dienen. Sie machen es sich etwas einfacher, wenn Sie ein exotisches Tier wählen, weil Sie dadurch Konflikte mit anderen Projekt­mitarbeitern vermeiden.

svn_aufgabe1

Schritt 1: Bevor Sie Ihre Klasse hochladen, sollten Sie schauen, ob es inzwischen viel­leicht schon Beiträge anderer Projektmitarbeiter gibt. Wählen Sie dazu im seitlichen Menü unten „Aktualisieren…“ (englisch: „Update…“). Wenn inzwischen jemand an­deres die Klasse „Kakapo“ angelegt hat (ein flugunfähiger Papagei auf Neuseeland), wird Ih­nen folgender Dialog angezeigt:

svn_aktualisieren_kakapo

Wenn Sie das Aktualisieren bestätigen, wird der Kakapo Ihrem BlueJ-Projekt hinzuge­fügt.

Schritt 2: Laden Sie jetzt Ihre eigenen Änderungen (Ihre Klasse „Pinguin“ zum Beispiel) hoch. Wählen Sie dazu im seitlichen Menü unten „Abgeben…“ oder „Commit…“ Darauf erscheint eine Liste der von Ihnen geänderten Dateien. Fügen Sie einen Kom­mentar hinzu und geben Sie die Änderungen ab:

svn_abgeben_pinguin

Aufgabe: Führen Sie einige Updates und Commits durch. Wenn Sie auf Konflikte stoßen, ignorieren Sie sie bis zum nächsten Schritt.

Grundsätzliche Reihenfolge beim Arbeiten

Nach dem erstmaligen Auschecken des Projekts sieht das Arbeiten immer so aus:

  1. Update, um zu sehen, ob sich am Server etwas geändert hat.
  2. Eigenen Code ergänzen und testen.
  3. Commit – der findet nur statt, wenn es keine Konflikte mehr gibt.

svn_arbeitszyklus

Tipps und Regeln fürs Arbeiten mit Schülerinnen und Schülern:

  1. Einen Commit nur dann durchführen, wenn alle Klassen im BlueJ-Projekt fehlerfrei übersetzt werden.
  2. Um Konflikte zu vermeiden, sollte klar sein, welches Team oder welche ein­zelne Schülerin für welche Klasse oder Klassen zuständig sind. Und die Schüler müssen die Finger von den Klassen anderer Schüler lassen.
  3. Wenn eine Datei ganz gelöscht wurde, kann sie mit BlueJ nicht mehr aus dem Repository ergänzt werden. Man muss dann das Projekt komplett neu aus­checken und damit weitermachen, oder die fehlende Datei von dort ergänzen.

Teil 3 – Konflikte

Wenn mehrere Bearbeiter unabhängig von einander an einer Klasse arbeiten, kommt es zu einem Konflikt. Das SVN-System kann einfache Konflikte selbstständig auflösen, bei den meisten muss aber ein Benutzer entscheiden, welche der in Konflikt stehenden Versionen gelten soll.

Aufgabe: Checken Sie das Projekt „SVN Aufgabe 2“ aus und ergänzen Sie eine noch nicht vorhandene getter- oder setter-Methode für ein Attribut der Klasse „Held“. Führen Sie dann einen Commit durch (bzw. vorher ein eventuell einge­fordertes Update).

Fall 1: Die entstehenden Konflikte lassen sich automatisch lösen. Dann zeigt BlueJ – nach dem Aktualisieren – folgende Meldung, mit der man das automatische Zusammenführen bestätigen kann:

svn_konflikt1

Fall 2: Der Konflikt lässt sich nicht automatisch lösen, weil Attribute der Klasse be­troffen sind oder die Änderungen eine Methode betreffen. Dann meldet BlueJ den Kon­flikt so:

svn_konflikt2

Daraufhin lässt man sich die Konflikte anzeigen. Die in Konflikt stehenden Codestellen werden beide in einem BlueJ-Editorfenster angezeigt. Von den Zeichen <<<<<<< bis ======= steht die eine Fassung (die des aktuellen Benutzers), von den Zeichen ======= bis >>>>>>> steht die andere Fassung (die aktuell auf dem Server befindli­che). Der aktuelle Benutzer muss den Konflikt manuell lösen.

svn_konflikt3

Tipp:

  • Im Rahmen eines Workshops sind Konflikte schwer zu lösen: Wenn es einen Kon­flikt gibt, und mehrere Teilnehmer versuchen gleichzeitig, ihn zu lösen, gibt das nur noch mehr Durcheinander.
  • Beim Arbeiten mit Schülerinnen und Schülern ist es besser, wenn sich die Grup­pen auf einzelne Klassen spezialisieren, so dass Konflikte ganz vermieden werden.

Teil 4 – Der Server

Man kann einen SVN-Server lokal im Netz installieren (etwa den Visual SVN Server https://www.visualsvn.com/server/ für Windows), aber eigentlich möchte man einen über das WWW erreichbaren Server. Dafür gibt es verschiedene kostenlose Anbieter, die aber alle das Problem haben, dass a) die Projekte öffentlich einsehbar sind (Vorteil: Keine Registrierung zum Aktualisieren nötig, Nachteil: Urheberrecht und Daten­schutz) und b) die Projektarbeiter alle eine Registrierung brauchen, wenn sie Commits durchführen sollen.
Unsere Projekte sind bei sourceforge.net gehostet. Ein SourceForge-Projekt kann man allerdings nicht so einfach wieder löschen, man muss eine Nachricht an einen Admi­nistrator schicken, der die Löschung einleitet. Die Inhalte des SourceForge-Projekts, also die BlueJ-Projekte, kann man natürlich jederzeit verändern.

Vorgehen:

  1. Registrierung bei SourceForge (einmalig) unter Angabe einer E-Mail-Adresse und eines Benutzernamens; das Passwort kann frei gewählt werden. Werden für Schüler Dummy-Accounts erstellt, besteht natürlich die Möglichkeit, dass sie E-Mail und Passwort ändern.

  2. Anmelden bei SourceForge und Anlegen eines neuen Projekts. Dabei enthält die voreingestellte Auswahl als Versionskontrolle nicht Subversion, sondern das jüngere Git. Außerdem kann man wählen, ob man ein Wiki, ein Forum, ein Ticketsystem oder andere Features haben möchte:
    svn_sourceforge

  3. Das SourceForge-Projekt ist zu Beginn ganz leer. Üblicherweise gibt es bei Subversion auf der obersten Ebene die Ordner „branches“, „tags“ und „trunk“; nur in letzterem werden die aktuellen Dateien gespeichert. Die anderen Ordner betreffen Subversion-Features, die von BlueJ nicht genutzt werden. Man kann also auf sie verzichten. Dann muss man nur:
    1. Ein neues BlueJ-Projekt anlegen.
    2. „Werkzeuge > Teamarbeit > Projekt gemeinsam nutzen…“ auswählen, Benutzername, Passwort und Serveradresse des SourceForge-Projekts eingeben. Das war’s schon.

  4.  Will man dennoch mit den Ordnern „branches“, „tags“ und „trunk“ arbeiten, etwa um in Zukunft die Möglichkeiten anderer Subversion-Clients zu nutzen, muss man einen externen SVN-Client benutzen; mit BlueJ alleine geht das nicht.
    1. Kommandozeilen-SVN-Client bei Linzux: Die bei SourceForge angegebenen Befehle eingeben.
    2. Mit einem anderen externen SVN-Client (etwa TortoiseSVN) eine temporä­re lokale Kopie des – vorerst noch leeren – Repository anlegen. Dann die drei Order lokal anlegen und auf den Server hochladen („commit“). laden. Danach wird die temporäre Kopie gelöschgt; die Ordner werden nur auf dem Server gebraucht.

Aufgabe: Legen Sie ein neues BlueJ-Projekt an und fügen Sie es mit „Werkzeuge > Teamarbeit > Projekt gemeinsam nutzen…“ dem SourceForge-Projekt svn.code.sf.net/p/fortbildung/code/ hinzu.

Tipps:

  • Jeder Projektmitarbeiter braucht einen eigenen Benutzernamen und ein eigenes Passwort, eventuell Dummy-Accounts für Schüler anlegen.
  • Ein möglichst kurzer Projektname erleichtert das Eingeben der Serveradresse in BlueJ.
  • Eine im Repository angelegte Datei (also auch Code) kann man nicht einfach wieder löschen. Grundsätzlich bleiben alle bisherigen Versionen von Textda­teien erhalten – man soll bei Subversion auch auf frühere Versionen zurückgrei­fen können soll, auch wenn BlueJ diese Funktion nicht unterstützt.

Teil 5 – Workflow für die Lehrkraft

Tortoise SVN – Update, Commit

Wenn man als Lehrkraft mehrer Projekte verwalten möchte, ist der in BlueJ integrierte SVN-Client umständlich, es empfiehlt sich die Verwendung eines eigenen SVN-Clients, für Windows z.B. TortoiseSVN (http://tortoisesvn.net/).

Damit kann man z.B. einen Ordner mit verschiedenen gesammelten BlueJ-Projekten mit einem SVN-Repository verknüpfen.

svn_tortoise_verzeichnisse

Nach Belieben markiert man einige der Verzeichnisse darin mit TortoiseSVN als „add to ignore list“, so dass diese Verzeichnisse eben nicht hochgeladen werden. Im Bild lie­gen nur die grünen Verzeichnisse auf dem Server und werden damit synchronisiert.

Man aktualisiert die BlueJ-Projekte jetzt nicht mehr von BlueJ aus (und kann das auch gar nicht), sondern über den eigenen Client, der sich in das Windows-Kontektmenü integriert:

svn_tortoise_update

Das Menü bietet noch weitere Möglichkeiten von Subversion, die für das Arbeiten in der Schule und mit BlueJ aber alle nicht nötig sind:

svn_tortoise_contextmenu

Tipps:

  • Wenn die Lehrkraft mit TortoiseSVN arbeitet, kann sie nicht wie die Schüler mit BlueJ arbeiten. Bei den Schülern hat jedes BlueJ-Projekt seine eigene .svn (ein verstecktes Verzeichnis mit SVN-Daten), bei der Lehrkraft gibt es ein .svn für das Verzeichnis mit den BlueJ-Projekten.
  • Will die Lehrkraft sich ein BlueJ-Projekt aus Schülersicht betrachten, muss sie das Projekt erst aus BlueJ heraus auschecken und kann das daraufhin neu ge­speicherte Projekt dann auch mit BlueJ committen. Das ist dann aber nicht das Projekt im eigentlichen zentralen BlueJ-Ordner des Lehrers.

Tortoise SVN – Eine lokale Kopie des Repository

Ganz am Anfang steht das Anlegen einer lokalen Kopie des Repository:

  • Optional: Legen Sie ein leeres Repository auf einem Server an.
  • Legen Sie ein Verzeichnis an für alle Projekte, die Sie zum Beispiel mit einer Schulklasse nutzen wollen, etwa „Klasse_10a“.
  • Wählen Sie für das Verzeichnis im Kontextmenü „SVN Checkout…“
    svn_tortoise_checkout
  • Geben Sie danach die URL des eben angelegten oder bereits existierenden Repository an:
    svn_tortoise_checkout2
  • Danach werden alle Verzeichnisse und Dateien im Repository – also in der Regel alle BlueJ-Projekte dort – in das gewählte Verzeichnis übertragen.
  • Ab jetzt kann das gewählte Verzeichnis mit dem Repository synchronisiert werden. Das geschieht über „SVN Update“ beziehungsweise „SVN Commit…“ im Kontextmenü.

Teil 6 – Erfahrungen

Rückmeldung aus der Praxis

  • Kommt bei Schülern sehr gut an.
  • Die Aktualisierung bestehender BlueJ-Projekte ist leichter als sie etwa bei Moodle aktuell zu halten
  • Am Anfang unbedingt im Computerraum gemeinsam machen; zu Hause kommt kaum einer allein zurecht
  • Gelegentlich gibt es ein unerklärtes write lock auf lokalem Projekt. Dann ein­fach neu auschecken und den bisher verwendeten BlueJ-Projekt-Ordner lö­schen.
  • Interessierte Schüler gehen ins Repository und blättern dort. („Wer hat die Da­tei gelöscht?“)
  • Für Projektarbeit enorm hilfreich. Der Austausch und die Koordination gehen sehr viel schneller und fehlerfreier als beim manuellen Dateienaustausch zwi­schen Teammitgliedern. Im Computerraum verständigt man sich durch kurzes Zwischenrufe „Habt ihr schon Update gemacht“ usw.
  • Oft arbeiten Schüler mit dem Account eines anderen Schülers, weil die Ab-/Anmeldung ihnen zu umständlich erscheint oder nicht alle ihre Zugangs­daten dabei haben.
  • Es ist vielleicht hilfreich, wenn Schülerinnen und Schüler erst einige Zeit lang nur BlueJ-Projekte auschecken (Aufgaben, Musterlösungen), und erst, wenn sie damit vertraut sind, Commits durchführen.
  • Schülerinnen und Schüler denken selten daran, einem Commit einen Kommen­tar hinzuzufügen.

Typische Probleme

  • Eingabe der korrekten Daten in BlueJ (Benutzername, Passwort) für manche schwierig, das Passwort wird vergessen oder nicht richtig aufgeschrieben – Schüler müssen sich ihre Zugangsdaten aufschreiben und jedesmal mitbringen.
  • Tatsächlich werden Schüler immer die Zugangsdaten ihrer Mitschüler nutzen. Das hat den Nachteil, dass man eventuelle Zugangsprobleme erst spät feststellt.
  • Manche Schüler hatten Schwierigkeiten, zu Hause die Teamarbeitseinstellun­gen in BlueJ einzuschalten, weil sie den Menüpunkt nicht gefunden haben, eventuell ist das Interface bei BlueJ auch auf englische Sprache eingestellt.
  • Die Arbeit mit dem in BlueJ integrierten und einem externen SVN-Client muss getrennt bleiben. Wenn der externe Client eine .svn-Datei in einem BlueJ-Pro­jekt entdeckt, führt das zu Problemen.
  • Gelegentlich kommt es aus irgendwelchen Gründen zu SVN-Fehlermeldungen des BlueJ-Clients (wie einem write lock, einem von BlueJ nicht genutzten und ansprechbaren SVN-Feature). Dann einfach das Projekt ganz neu auschecken, das alte lokale löschen und eventuelle Codeergänzungen noch einmal durch­führen.Cartoon http://xkcd.com/1597/
    Randall Munroe/xkcd, Creative Commons Attribution-NonCommercial 2.5
  • Enthält ein Verzeichnis Bilddateien, fügt Windows oft eine versteckte Datei „thumbs.db“ hinzu, die dann mit synchronisiert wird.

Zur Erinnerung und als Übersicht:

  • Checkout – macht man meist einmalig und lädt dabei alle Inhalte aus einem Repository in ein lokales Verzeichnis.
  • Update – führt man regelmäßig und insbesondere vor Beginn eigenen Arbeitens durch. Dabei werden lokale Fassungen eventuell durch aktuellere aus dem Repository ersetzt. Kann zu Konflikten führen.
  • Commit – führt man unmittelbar nach dem eigenen Arbeiten durch. Wenn inzwischen neuere Fassungen im Repository liegen, wird man stattdessen zu einem Update und anschließender Konfliktläsung gezwungen. Danach kann man den Commit noch einmal versuchen.

Teil 7 – Beispiele

Einfaches Tic-Tac-Toe mit Model-View-Controller

Als Fingerübung vor der eigentlichen Projektarbeit sollte ein Tic-Tac-Toe-Spiel pro­grammiert werden. Dazu wurde in einer Stunde ein Klassendiagramm erstellt, ange­fangen vom Model (was muss gespeichert werden?) über den View (was muss der er­fahren, um den Spielstand darstellen zu können?) bis hin zum Controller.

svn_mvc_tictactoe

Dann wurden drei Teams eingeteilt (Alpha, Bravo, Charlie); in jedem Team waren je­weils zwei bis drei Schülerinnen und Schüler für die konkrete Umsetzung der drei ab­strakten Klassen zuständig. So konnten über zwanzig Schüler weitgehend unab­hängig von den anderen arbeiten.

svn_mvc_bluej1

Am Schluss sah das Projekt so aus, alle drei Model-, View- und Controller-Implementierungen konnten untereinander ausgetauscht werden:

svn_mvc_bluej2

Größeres Programmierprojekt

Danach folgten acht Wochen Programmierprojekt in drei Gruppen zu jeweils 7-8 Mit­gliedern. Jede Gruppe arbeitete in einem eigenen BlueJ-Projekt.

svn_team_alpha

svn_team_bravo

svn_team_charlie


Nachtrag: Für kommende Versionen von BlueJ ist Git-Unterstützung angekündigt; Git ist ein etwas jüngeres System, das ähnliche Wünsche wie Subversion erfüllt. Für Mebis ist, wenn auch nicht in unmittelbarer Zukunft, FTP-Zugang angekündigt und die Möglichkeit, gemeinsam an Dokumenten zu arbeiten, „mit Versionskontrolle“. Ich kann mir nicht vorstellen, dass das Versionskontrolle im Sinn von Git oder Subversion ist – aber das wäre schon schön.

Mittlere Mathematik: Audioanalyse & Linktipp zu Fourier-Transformation

Wie es angefangen hat, weiß ich nicht mehr. Irgendwann in der Mitte wollte ich jedenfalls wissen, wie das mit dem automatischen Erkennen von Musikstücken geht – man spielt zehn oder zwanzig Sekunden eines Liedes vor, und das Handy meldet sich danach und sagt einem, von wem das Lied ist und wie es heißt.

Beim Googeln stieß ich auf diese phantastische Seite darüber, wie einer genau das in Java nachbaute. Einfach, nachvollziehbar, übersichtlich. Allerdings ist der Code nicht vollständig, das hängt auch mit Drohungen des Marktführers zusammen, das gegen Patente verstoßen werde. Nicht glaubwürdig, aber ich verstehe sehr gut, dass man da als kleiner Blogger vorsichtig ist.

Trotzdem habe ich den Code nach und nach vervollständigt und nachprogrammiert und dabei viel gelernt.

Schritt 1: Mikrofon anschließen und mit Java Ton vom Mikro aufnehmen

Funktioniert. Wie so eine Aufnahme aussieht, das kennt man aus dem Fernsehen:

audioanalyse1

Allerdings, wenn man mit der Lupe richtig nahe herangeht, sieht man, dass die Wellen, die man zu sehen meint, gar keine sind: Stattdessen sind einfach nur eine Menge von Punkten gespeichert, die in gleichmäßigem Abstand einer nach dem anderen eingezeichnet werden.

audioanalyse2

Das passiert nämlich beim Digitalisieren von Schallwellen. Es wird nämlich gar keine Schallwelle gespeichert, sondern in regelmäßigen Abständen gemessen, was gerade an Schall hereinkommt. Regelmäßige Abstände heißt: häufig misst man 44100 mal pro Sekunde. (Damit erwischt man Frequenzen von bis zu 22050 Hz.) Wie viel verschiedene Amplituden (also Lautstärken, die vertikale Position des eingetragenen Messpunkts) möglich sind, hängt von einem weiteren Wert ab. Reserviert man pro gespeichertem Punkt 1 Byte (8 bit), dann kann man zwischen 256 verschiedenen horizontalen Positionen wählen. Bei 2 Byte (16 bit) sind es schon 65536. Und wenn man richtig genau sein woll, nimmt man 4 Byte (32 bit) pro Punkt. Der Einfachkeit halber habe ich mit 8 bit pro Punkt gearbeitet, was sicher keine high-fidelity Aufnahme ermöglicht.

Gespeichert wird die Aufnahme also in einer langen Reihe von Bytes. Wenn man die Bytes als ganze Zahlen interpretiert, sieht ein Ausschnitt etwa so aus:

-50, -45, -37, -31, -26, -24, -25, -26, -26, -28, -26, -25, -22, -18, -11, -4, 5, 13, 20, 24, 29, 31, 33, 34, 32, 29, 23, 16, 7, 1, -4, -6, -8, -7, -8, -6, -5, -3, 1, 7, 12, 16, 16, 9, 0, -10, -20, -22, -19, -12, -1, 9, 16, 21, 22, 22, 21, 21, 19, 20, 19, 18, 18, 19, 20, 22, 22, 23, 20, 18, 14, 10, 3, -4, -11, -21, -31, -39, -49, -54, -59, -59, -59, -57, -51, -44, -32, -20, -5, 7, 18, 23, 22, 20, 15, 13, 13, 16, 24, 30, 36, 39, 41, 42, 43, 44, 45, 46, 45, 43, 39, 35, 29, 24, 17, 12, 4, -1, -7, -13, -19, -25, -32, -37, -43, -50, -55, -61, -64, -69, -71, -75, -74, -74, -69, -63, -55, -47, -42, -42, -43, -48, -52, -54, -52, -45, -37, -24, -14, -3, 5, 15, 21, 30, 35, 38, 40, 38, 33, 27, 19, 13, 4, -3, -11, -16, -22, -25, -30, -32, -35, -36, -38, -39, -40, -42, -46, -49, -55, -59, -63, -64, -63, -56, -48, -37, -26, -20, -14, -13, -12, -10, -8, -1, 5, 12, 17, 19, 21, 20, 22, 22, 24, 23, 23, 20, 20, 18, 18, 19, 19, 20, 19, 18, 16, 15, 12, 12, 10, 12, 15, 19, 24, 31, 36, 44, 48, 55, 60, 68, 75, 84, 91, 99, 101, 99, 94, 84, 76, 66, 61, 56, 50, 44, 34, 24, 11, 1, -10, -16, -24, -28, -32, -35, -36, -33, -30, -26, -22, -20, -17, -17, -14, -12, -9, -8, -5, -3, 0, 4, 11, 18, 28, 36, 42, 46, 49, 52, 57, 61, 66, 67, 68, 63, 58, 50, 46, 43, 43, 47, 49, 50, 46, 42, 36, 28, 23, 15, 7, -3, -16, -25, -34, -40, -41, -43, -44, -48, -55, -60, -65, -71, -74, -79, -84, -89, -94, -98

(Das sind 318 Punkte. Bei 44100 Punkten pro Sekunde macht das gut 0,007 Sekunden, bei 32000 Punkten pro Sekunde sind das knap 0,01 Sekunden.)

Wenn ich diese Zahlen in mein Tabellenkalkulationsprogramm eintrage und mir als Diagramm anzeigen lasse, sieht man, dass das tatsächlich irgendwie den im Audioprogramm dargestellten Werten entspricht:

audioanalyse3

(Tatsächlich exportiert mein Audioprogramm das 8-bit-Wav-Format nur als „unsigned“, das heißt ohne Vorzeichen, also zu lesen als Zahlen von 0 bis 255. Für Java musste ich das umrechnen, da Java grundsätzlich mit „signed“ Bytes arbeitet, die als Zahlen von -128 bis 127 zu lesen sind.)

Schritt 2: Umwandeln der gemessenen Zahlenwerte in Frequenzen

Man kann die Audioaufnahme beschreiben – und speichern – als einen Haufen Messpunkte, kontinuierlich aufeinanderfolgend in regelmäßigen Zeitabständen, so wie oben. Für manche Dinge ist diese Betrachtungsweise aber nicht so praktisch. Die folgende Aufnahme könnte man – statt auf Messpunkte zurückzugreifen – eleganter beschreiben als eine regelmäßige Schwingung.

audioanalyse4

Und die folgende Aneinanderreihung von Messpunkten kann man prägnant unter einem anderen Gesichtspunkt beschreiben als: eine regelmäßige Schwingung und gleichzeitg eine von doppelter so großer Frequenz. (Ein Ton und die Oktave darüber.)

audioanalyse5

Tatsächlich kann man jede beliebige Sammlung von Punkten als eine Überlagerung von Wellen darstellen. Selbst die komplizierte Sammlung von oben:

audioanalyse2

Tatsächlich lassen sich diese 318 Messpunkte auch darstellen als eine Überlagerung von (höchstens) 318 verschiedenen Schwingungen. Die Umwandlung von (in diesem Fall: n) Messpunkten in (in diesem Fall: n Schwingungen, mit relativen Frequenzen von 1 bis n) heißt Fourier-Transformation, und davon hört man gelegentlich Mathelehrer Anekdoten aus dem Studium erzählen.

Und weil ich wissen wollte, was es mit dieser Fourier-Transformation auf sich hat, bin ich auf diese Seite gestoßen: An Interactive Guide To The Fourier Transform.

Genial erklärt, jedenfalls für einen Laien wie mich. Hilfreich sind auch zwei hervorragende Werkzeuge zum Verständnis, eines erst im Anhang. Bei dem ersten kann man einfach eine Reihe von Messpunkten eingeben, egal welche, und das Programm spuckt die entsprechenden Schwingungen aus. (Und umgekehrt auch.) Die drei Punkte 1, 0, 2 trifft man mit der Kombinationen aus folgenden Wellen:

Der Inhalt ist nicht verfügbar.
Bitte erlaube Cookies, indem du auf Übernehmen im Banner klickst.

Quellcode, basierend hierauf. MIT License. Blogeintrag dazu.

Um wirklich schön damit zu spielen, muss man den verlinkten Beitrag lesen.
Beim anderen Programm sieht man gut, was Kreise und Schwingungen und überlagerte Schwingungen miteinander zu tun haben.

Außerdem habe ich mir auf der Seite gleich noch den Sinus erklären lassen und die Eulersche Zahl. Erhellend!

3. Wie es bei dem ursprünglichen Projekt weiter geht

Die gespeicherten Bytes (die Messpunkte) werden umgewandelt in Schwingungen. Das geht so: Man nimmt einen Packen Bytes, zum Beispiel 2048. Diesen Packen wandelt man um in 2048 Schwingungen, eine mit Frequenz 1, eine mit Frequenz 2, eine mit Frequenz 3 und so weiter. Zu jeder Frequenz gehört eine Amplitude (wie laut, also die vertikale Komponente) und die Phase. Wenn man den verlinkten Blogeintrag gelesen hat, ist das kein Problem mit der Phase – das ist die Verschiebung der Welle nach rechts oder links, was wichtig dafür ist, welche Wellen sich mit welchen anderen aufheben oder hochschaukeln. Jede Schwingung wird gespeichert als komplexe Zahl (auch die kann man sich schön erklären lassen). Wo also vorher 2048 Bytes da waren, sind jetzt 2048 komplexe Zahlen, jede für eine eigene Frequenz.

Auf Basis dieser 2048 Frequenzen, jeweils mit mehr oder weniger großer Amplitude, wird dann quasi ein Fingerabdruck der Aufnahme gemacht, der dann später mit einer gespeicherten Kartei solcher Fingerabdrücke verglichen wird. Wie das geht: anderes Thema.

Wer ist wichtig in einem Netz?

In der 11. Klasse beschäftigen sich Schüler in Informatik mit Graphen. Keine Funktionsgraphen, wie man sie aus der Mathematik kennt, sondern Graphen, die aus einem Haufen Knoten bestehen, die durch einen Haufen Kanten mehr oder weniger miteinander verbunden sind.

Es geht dabei vor allem darum, Situationen mit Graphen zu modellieren (also: Textaufgaben), und dieses Modell dann mit einem Computer umzusetzen. Nach dem Erzeugen des Graphen sollen die Schüler außerdem einige Methoden programmieren können, die man bei Graphen einsetzen kann.

Hier ist ein Beispielgraph:

graph_zentralitaet

Die Kanten sind der Einfachheit halber ungerichtet, gelten also in beide Richtungen, und ungewichtet, sind also alle gleich „lang“, was auch immer das konkret heißt. Sie könnten bedeuten: „hat Telefonnummer von“, oder „will sitzen neben“ oder „lässt Hausaufgaben abschreiben“.

Programmieraufgaben bei Graphen

Im Lehrplan steht eine Methode zur „Traversion“ oder zum „Durchlauf“ eines Graphen. Dabei muss man jeden Knoten mindestens einmal besuchen. Man kann sich so einen Graphen als Labyrinth vorstellen, jede Kante ist eine Wegstrecke im Labyrinth und jeder Knoten eine Weggabelung oder eine Sackgasse. Nach welchem Algorithmus geht man vor, wenn man wirklich überall im Labyrinth mal gewesen sein möchte, etwa um nach einem Schatz oder Ausgang zu suchen, und ohne einen Knoten zu übersehen?

Am einfachsten ist da wohl ein Algorithmus, der „Tiefensuche“ heißt, und deshalb programmiert man meist den. Ein anderer, der Dijkstra-Algorithmus, sagt einem darüber hinaus noch den kürzesten Weg (statt eines x-beliebigen) vom Startknoten zu den anderen Knoten.

Aber es gibt noch schöne andere Aufgaben, die man mit Schülern mit einem Graphen programmieren kann. Die folgenden beschäftigen sich alle damit, wie wichtig ein Knoten im Graphen ist.


1. Welcher Knoten ist am häufigsten mit anderen Knoten verbunden? (Bei gerichteten Graphen: zu welchem Knoten gehen am meisten Kanten hin, von welchem führen am meisten weg?) Damit misst man die Gradzentralität. Im Graph oben hat Linda eine degree centrality von 7. Vielleicht ist sie die beliebteste Schülerin?

2. Andererseits ist der beliebteste Schüler nicht unbedingt der wichtigste. Welcher Knoten ist derjenige, der allen anderen Knoten am nächsten ist? Man könnte sich das so vorstellen: Mit welchem Knoten müsste man beginnen, etwa mit einem Telefonanruf, der von Knoten zu Knoten weitergereicht wird, um am schnellsten alle anderen Knoten erreicht zu haben? Im Graph oben ist Oscar der einzige, der maximal 3 Schritte von jedem anderen Knoten entfernt ist.
Im Durchschnitt ist allerdings Quentin am besten vernetzt: die Summe aller kürzesten Wege von Quentin zu allen anderen Knoten beträgt 38, bei Oscar 47, bei Linda 45, und Urmel ist mit 97 am schlechtesten integriert. Diese Art von Zentralität heißt farness beziehungsweise closeness.
(Damit Schüler das berechnen können, müssen sie erst einmal eine Methode zur Berechnung des kürzesten Wegs haben. Dazu kommt man in der Schule oft nur theoretisch, die praktische Umsetzung in Programmcode kann man vorgeben.)

3. Oder ist der Schüler der wichtigste, der die anderen Knoten zusammenhält, ohne den am Ende der Graph in fast schon unabhängige Teilgraphen zerfällt? Das heißt betweenness centrality und wird gemessen an der Anzahl der kürzesten Wege, die durch diesen Knoten führen. Der Beispielgraph besteht aus 21 Knoten, es gibt also insgesamt 210 (Formel: n*(n-1)/2) verschiedene Knotenkombinationen und ebenso viele kürzeste Wege. Wenn man mal die abzieht, die ohnehin zu einem selber führen, dann gehen 254 dieser anderen Wege über Quentin, 158 über Oscar, 155 über Linda. Wenn ich mich nicht verrechnet habe, das ist kniffliger, als ich zuerst dachte, weil man im Prinzip nicht einen kürzesten, sondern alle kürzesten Pfade braucht (es kann ja gleich kurze geben). Auch hier braucht man wieder den Dijkstra.

4. Wenn Google Webseiten bewertet, die ja mit (gerichteten) Kanten mit anderen Webseiten verbunden sind, nimmt Google wiederum eine andere Möglichkeit, Zentralität zu messen. Die basiert auf etwas, das eigenvector centrality heißt, aber das erfordert einen neuen Unterpunkt.

Nachtrag: He, das Äquivalent zum Google PageRank zu berechnen, ist gar nicht so schwer, siehe Link in den Kommentaren. Auch wenn es bei einem ungerichteten Graphen vielleicht weniger Sinn macht: Linda hat den höchsten Rank, gefolgt von Ihsan, dann mit etwas Abstand Oscar.

Eigenvector Centrality, und Google

Nehmen wir mal diesen gerichteten Graphen hier:

graphen_beispiel

NikelsenH, Creative-Commons-Lizenz Namensnennung – Weitergabe unter gleichen Bedingungen 3.0 nicht portiert

Die höchste Betweenness hat 3, die geringste Farness ebenfalls, die meisten hinführenden Kanten hat 7. Wenn man sich jetzt vorstellt, die Knoten stellen Webseiten dar und die Kanten Links auf andere Webseiten, dann versucht Google herauszufinden, welcher Knoten wohl der wichtigste ist. Betweenness und Farness und Gradzentralität sagen da aber nicht viel aus. Zum Bewerten von Seiten nutzt Google noch weitere Kriterien, aber die Häufigkeit der Verlinkung, und die Qualität der verlinkenden Seiten, spielen eine zentrale Rolle. Und diese Art von Zentralität heißt eigenvector centrality.

Kurze Frage: Bei dem Beispielgraph mit den nummerierten Knoten: Welche davon hält Google für am wichtigsten, welche für weniger bedeutsam?
Antwort: Wikipedia, wo ich den Graphen herhabe, sagt: wichtig sind 7 und 8, am unwichtigsten 1 und 6.

Wie rechnet man das aus? Uh, mh, siehe Google. Irgendwann mache ich das nochmal, aber vorerst muss ich passen. Irgendwas mit Eigenvektor, Eigenwert, Matrizen und Vektoren. Geheime MMächte der Mathematik. Andererseits… umschrieben wird diese Eigenvektor-Zentralität oft als „Wahrscheinlichkeit, mit der man bei einem zufälligen Spaziergang im Graphen auf diesen Knoten stößt“. Wenn ich schon den Eigenvektor nicht programmieren kann: tausend Spaziergänge der Länge n in einem gegeben Graphen und zählen, wie oft ich bei einem Knoten vorbeikomme, das kann ich noch. Also tausendmal einen zufälligen Startknoten ausgewählt, tausendmal bis zu n Schritte spaziert – und es kommt tatsächlich heraus, dass ich bei 7 und 8 am häufigsten und bei 1 und 6 am seltensten war!

(Pro Spaziergang bin ich maximal einmal bei 5 oder 6, denn von da aus komme ich nicht mehr anderswohin, und zwischen und 7 und 8, wenn ich erst mal dahin gekommen bin, pendle ich dann ziemlich oft hin und her, weil ich ja sonst nirgendwo hin spazieren kann.)

Google selber muss den page rank einer Seite natürlich anhand des Graphen ausrechnen, die können nicht so experimentell herangehen wie ich. Die machen das mit Mathematik.

Die Google-Matrix

Einen Graphen kann man nicht nur als Zeichnung darstellen, sondern auch in einer Form namens Adjazenzmatrix. (Englisch: adjacent, nebeneinanderliegend.) Die sieht für den allerersten Graphen oben so aus, aus Platzgründen nur der Anfang:

    Arl Ben Car Dor Eli Fel Gue Hus Ihs Jak Kar Lin Mic 
Arl  0                               1          
Ben      0   1
Car      1   0
Dor              0                   1
Eli                  0       1
Fel                      0
Gue                  1       0                   1
Hus                              0               1
Ihs  1           1                   0   1  
Jak                                  1   0
Kar                                          0   1   1
Lin                          1   1           1   0   1
Mic                                          1   1   0

Eine 1 bedeutet, dass eine Kante von dem einen Knoten zum anderen existiert. Weil der Graph oben ungerichtet ist, ist die Adjazenmatrix symmetrisch zur Diagonalen, da wo die ganzen Nuller sind.
Google benutzt genau so Adjazenzmatrix, oder doch so eine ähnliche, um den page rank von Seiten zu bestimmen. Die ist natürlich Millionen von Zeilen breit und hoch. Und grün auf schwarz, wie sich das gehört.

600px-Googlematrixwikipedia2009

Google matrix of Wikipedia (2009), taken from L.Ermann, A.D.Chepelianksii, D.L.Shepelyansky, „Towards two-dimensional search engines‘, arXiv:1106.6215; http://arxiv.org/abs/1106.6215 (GNU Free Documentation License)

Links:

Codefunde, und Programmieranregungen

Zwei Funde aus der letzten Zeit, und beide kurz, quelloffen und verständlich.

1. A Dark Room

Ein minimalistisches Spiel, das mit Maus und später ein wenig Tastatur im Browser bedient wird. Nach den ersten Klicks befindet man sich in vertrauter Atmosphäre, ein textbasiertes City-Building-Spiel also, und doch… man beginnt in einem dark room, und muss erst einmal das Feuer anheizen. Eine Fremde kommt in die Hütte, wärmt sich, und stellt sich als builder heraus, die mit dem gesammelten Holz einfache Dinge bauen kann. Nach und nach kommen weitere Wanderer, eine zweite Hütte wird gebaut.

a_dark_room

Bereits bei den ersten, der interactive fiction nahen Formulierungen ahnt man, dass das irgendwie ein besonderes Spiel ist, und als das stellt es sich auch nach und nach heraus. „The light from the fire spills from the windows, out into the dark.“

Hier kann man das spielen: http://adarkroom.doublespeakgames.com/ Oder man folgt einfach dem Link dort zu GitHub, wo der Code des ganzen Projekts gespeichert ist und zum Beispiel als zip-Paket heruntergeladen werden kann. Das Programm ist in Javascript geschrieben, und es ist interessant, mal in den Quellcode zu schauen.
Außerdem sieht man daran gut, dass auch ein minimalistisches Spiel spannend sein kann. Zugegeben, es wird später noch ein wenig elaborierter. Sehr stimmungsvoll.

2. Tippfelher

Über diesen Tweet bin ich auf das Projekt gestoßen:

Auch hier ist das Projekt bei GitHub gespeichert, und man kann es sich dort anschauen oder herunterladen. Es ist in Python geschrieben, mit dem ich sehr viel vertrauter bin als mit Javascript. Der Hintergrund wird in diesem Blogeintrag erklärt. Die Kurzfassung: Das Programm liest einen Text ein und spuckt ihn mit Tippfehlern versehen wieder aus. Dazu gehören etwa eine fehlende Hochstelltaste bei Großbuchstaben und vertauschte Buchstaben, die auf der Tastatur nebeneinanderliegem. Bei Titel der Textdatei wird nur ein Buchstabe getauscht, wie man an der mitgelieferten Beispieldatei „Kakfa – Die Verwandlung.txt“ sieht.

Programmierprojekte, Ideen gesucht, und zwei tolle Programme für die Schule

Studierende für das Lehramt Informatik müssen laut Lehramtsprüfungsordnung ein Programmierprojekt vorweisen. Mit diesem zeigen sie, dass Sie selbstständig Prinzipien der Softwareentwicklung anwenden können – Entwicklungsmodelle, Testverfahren, Entwurfsmuster. Inhaltlich kann das alles mögliche sein, solange die Studierenden einen Betreuer für das Projekt finden. Ein potentieller solcher Betreuer bin ich. Ab und zu werde ich auch nach möglichen Themen für solche Programmierprojekte gefragt.

Programmieraufträge, die mich interessieren, betreffen hauptsächlich Software, die man irgendwie für die Schule nutzen könnte. Und oft, wenn mir da etwas Schönes einfällt, das es noch nicht gibt und das ein Student in einem Semester programmieren könnte und das für den Unterricht nützlich wäre – oft genug, wenn ich dann mal recherchiere, dann gibt es so eine Software schon. Zefix!

(Falls einer von euch einen Wunsch hat für eine Software, bitte mir sagen. Ich hab da eine Liste, auf die ich Ideen setze, die ich Studierenden anbiete.)

So ging es mir auch mit dieser Software:

1. Orinoco von Christoph Gräßl

(Link zur Seite)

Das ist das beste Programm zur Datenflussmodellierung, das ich für die Schule kenne. In Bayern braucht man das in der 9. Klasse.

Der Inhalt ist nicht verfügbar.
Bitte erlaube Cookies, indem du auf Übernehmen im Banner klickst.

Das Programm läuft – wichtig für die Schule – ohne Installation (wenn auch nur unter Windows). Mit Drag & Drop kann man Funktions-Ellipsen anlegen, Kästen für Ein- und Ausgabewert, und gerichtete Verbindungen dazwischen. Man kann außerdem probeweise Werte eingeben und sich alle Zwischenergebnisse anzeigen lassen, sogar animiert, so dass die Daten wirklich der Reihe nach von oben nach unten fließen. (Das sieht man hier natürlich nicht.)

promilleformel1

Wenn man die Funktion für die Berechnung des Blutalkoholgehalts gespeichert hat, kann man sie wie die anderen, vorgebenenen Standardfunktionen benutzen:

promilleformel2

Und als Term gibt er die Funktion auch aus:

Blutalkoholgehalt = PRODUKT(PRODUKT(Menge ; Alkoholgehalt) ; 0.8) / PRODUKT(WENN(Geschlecht = w ; 0.6 ; 0.7) ; Körpermasse)

Da fehlen mir eigentlich nur ein paar Kleinigkeiten. Datentypen. Die Möglichkeit, im umgekehrten Weg aus einer Termnotation die Grafik erstellen zu lassen. Aber im Prinzip wär’s das gewesen mit meiner Idee für mein Programmierprojekt.

2. AuDeSe – auch von Christoph Gräßl

(Vom gleichen Autor, auf der gleichen Seite.)

Der Inhalt ist nicht verfügbar.
Bitte erlaube Cookies, indem du auf Übernehmen im Banner klickst.

Programme zum Erstellen von endlichen Automaten kenne ich einige. Dieses hier ist einfach zu bedienen, die Grafik nicht ganz so schön wie bei Orinoco, aber okay. Hier ein kleiner Automat, der eine Wache in einem Comotuerspiel steuert. Normalerweise patroulliert die Wache um ihre Wachposition herum. Hört sie ein Geräusch, bleibt sie stehen, sieht sie einen Gegner, verfolgt sie ihn. Wenn Zeit vergeht, nähert sich die Wache wieder nach und der Normalität – solange der einmal gesehene Gegner in Reichweite ist, verfolgt sie ihn aber.

automat_wache_spiel

Das mit den Bedingungen ist noch nicht optimal gelöst, aber für die meisten Schulfälle reicht es.
Das besondere an diesem Programm: Es generiert sehr einfach den Java-Code zu dem entworfenen Automaten, und wenn man will, gleich das ganze BlueJ-Projekt dazu.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
public class AUTOMAT
{
 
    // Attribute
    private String Zustand;
 
    // Bedingungen
    private boolean nicht_in_Reichweite;
    private boolean in_Reichweite;
 
    // Methoden
 
    // Konstruktor
    public AUTOMAT()
    {
        // Startzustand setzen
        Zustand = "auf Patrouille";
        System.out.println("Startzustand: auf Patrouille");    }
 
    // Ausgelöste Aktion "stehen bleiben"
    private void stehen_bleiben( )
    {
        // Hier den Code für die ausgelöste Aktion eingeben!
        System.out.println("Ausgelöste Aktion stehen_bleiben() wurde aufgerufen!");
    }
 
    // Ausgelöste Aktion "Patrouille aufnehmen"
    private void Patrouille_aufnehmen( )
    {
        // Hier den Code für die ausgelöste Aktion eingeben!
        System.out.println("Ausgelöste Aktion Patrouille_aufnehmen() wurde aufgerufen!");
    }
 
    // Ausgelöste Aktion "verfolge Gegner"
    private void verfolge_Gegner( )
    {
        // Hier den Code für die ausgelöste Aktion eingeben!
        System.out.println("Ausgelöste Aktion verfolge_Gegner() wurde aufgerufen!");
    }
 
    // Ausgelöste Aktion "gehen nach Wachposition"
    private void gehen_nach_Wachposition( )
    {
        // Hier den Code für die ausgelöste Aktion eingeben!
        System.out.println("Ausgelöste Aktion gehen_nach_Wachposition() wurde aufgerufen!");
    }
 
    // Auslösende Aktion "hört Geräusch"
    public void hört_Geräusch()
    {
        if ( Zustand.equals("auf Patrouille"))
        {
            stehen_bleiben();
            Zustand = "misstrauisch";
            System.out.println("Neuer Zustand: misstrauisch");
            return;
        }
    }
 
    // Auslösende Aktion "Zeit vergeht"
    public void Zeit_vergeht()
    {
        if ( Zustand.equals("misstrauisch"))
        {
            Patrouille_aufnehmen();
            Zustand = "auf Patrouille";
            System.out.println("Neuer Zustand: auf Patrouille");
            return;
        }
        if ( Zustand.equals("verfolgend") && nicht_in_Reichweite==true)
        {
            gehen_nach_Wachposition();
            Zustand = "misstrauisch";
            System.out.println("Neuer Zustand: misstrauisch");
            return;
        }
        if ( Zustand.equals("verfolgend") && in_Reichweite==true)
        {
            verfolge_Gegner();
            Zustand = "verfolgend";
            System.out.println("Neuer Zustand: verfolgend");
            return;
        }
    }
 
    // Auslösende Aktion "sieht Gegner"
    public void sieht_Gegner()
    {
        if ( Zustand.equals("misstrauisch"))
        {
            verfolge_Gegner();
            Zustand = "verfolgend";
            System.out.println("Neuer Zustand: verfolgend");
            return;
        }
        if ( Zustand.equals("auf Patrouille"))
        {
            verfolge_Gegner();
            Zustand = "verfolgend";
            System.out.println("Neuer Zustand: verfolgend");
            return;
        }
    }
 
}

Ein Taschenrechner mit Java in der 10. Klasse (1)

Mit meiner 10. Klasse habe ich im ersten Halbjahr einen Taschenrechner programmiert, ziemlich bald, als Einstieg in die Algorithmik, die ich dafür dieses Jahr vorgezogen habe. Als BlueJ-Projekt sieht der Rechner so aus:

taschenrechner_bluej_rot

Objektorientiert programmieren heißt, dass man die Programmieraufgabe auf verschiedene, relativ unabhängige Einheiten verteilt. Der Bauplan für diese Einheiten heißt „Klasse“, und eben diese programmiert man.


1. Die Klasse GUI

Die Klasse GUI kann ein guter Schüler machen. Sie übernimmt das, was vom Programm äußerlich sichtbar ist. (GUI steht für Graphical User Interface.) Das ist quasi das Plastik-und-Alu-Gehäuse des Rechners. Den hat ein freiwilliger Schüler schon gleich am Anfang programmiert, und zwar mit dem Java-Editor. Dieses Programm von Gerhard Röhner ist eigens für Schulen und Schüler entwickelt, um leichter diese grafischen Benutzeroberflächen zu erstellen, die in Java, ehrlich gesagt, recht umständlich sind.

Die Klasse GUI braucht einen Bereich, in dem man die Ergebnisse anzeigen lassen kann (im Java-Editor-JFrame-Projekt: JLabel oder JTextField), und viele Knöpfe mit unterschiedlichen Beschriftungen (JButton). Nach diesen Angaben hat ein Schüler folgendes Taschenrechner-GUI angelegt, nachdem wir vorher noch ausgemacht hatten, welche Knöpfe es geben soll:

taschenrechner_gui_ansicht_leer

Ich hätte die Knöpfe anders platziert und benannt, aber hey, es ist nicht mein Taschenrechner. Und hier ist auch ein Vorteil des objektorientierten Programmierens: Wem dieses GUI nicht gefällt, der kann es einfach durch ein anderes, eigenes ersetzen, ohne dass die anderen am Programm beteiligten Klassen geändert werden müssen.

Noch passiert allerdings nichts, wenn man auf die Knöpfe drückt. Viel soll auch gar nicht passieren: für das Innenleben des Taschenrechners sind wieder andere Klassen zuständig. Der Taschenrechner muss nur Bescheid geben, welche Taste gedrückt ist, und zwar einem Objekt der Klasse Steuerung. Damit das geht, muss man die mit dem Java-Editor erstellte GUI-Klasse etwas ergänzen:

1. Ein GUI-Objekt muss ein Steuerung-Objekt kennen, dem es die Benachrichtigung schicken soll (Referenzattribut auf ein Objekt der Klasse Steuerung); das geht in einer Zeile:

Steuerung steuerung;

2. Wenn eine Taste gedrückt wird, muss an die Steuerung eine Nachricht gesendet werden. Die Vorarbeit dazu erledigt der Java-Editor, man muss nur – nach dem TODO-Kommentar – eine einzige Zeile in jeder Knopfgedrückt-Methode ergänzen (es gibt für jeden Knopf eine solche Methode):

private void jButton1_ActionPerformed(ActionEvent evt) {
  // TODO hier Quelltext einfügen
  senden ("1");
} // end of jButton1_ActionPerformed

Der Einfachheit halber benutzen alle diese Knopfdruckmethoden die ebenfalls zu ergänzende Sendemethode der Klasse GUI:

void senden(String s) {
  steuerung.empfangen(s);
}

Das war es fast. Damit das GUI auch Text ausgeben kann, muss man nur diese Methode ergänzen:

void ausgeben(String s) {
  ausgabefeld.setText(s);
}

Und damit ist die Klasse GUI fertig. Wenn eine Taste gedrückt wird, wird eine Nachricht an die verbundene Steuerung geschickt, und wenn man das GUI-Objekt anweist, Text auszugeben, dann macht es das. Mehr erwartet man von einer Taschenrechnerhülle nicht.


2. Die Klasse Steuerung

Diese Klasse sollte man den Schülern fertig vorgeben. Sie macht eigentlich gar nicht so viel, ist aber umständlicher zu programmieren, als man meint. Sie macht zwei Dinge: Erstens nimmt sie in Empfang, welche Nachrichten, also Tastendrucke, vom GUI gesendet werden. Und gleich darauf sagt sie der Steuerung, was diese anzeigen soll. Wenn am Anfang die Taste 1 gedrückt wird, soll das GUI „1“ anzeigen. Wenn danach die Taste 2 gedrückt wird, soll das GUI „12“ anzeigen. Wenn dann die Mal-Taste gedrückt wird, soll das GUI „*“ anzeigen. (Die bisher eingegebene Zahl 12 muss sich die Steuerung aber merken.) Und so weiter, bis es nach dem Eingeben der zweiten Zahl ans eigentliche Rechnen geht. Dieses Rechnen übernimmt dann wieder eine dritte Klasse, nämlich die Klasse Calculator.

Die Klasse Steuerung kann man sicher sauberer programmieren, als ich das getan habe. Sie muss sich im Prinzip zwei Zahlen merken können, eine erste und eine zweite. Dazu muss sie wissen, ob sie jetzt schon rechnen soll oder erst auf die Eingabe einer zweiten Zahl warten muss. Manchmal muss sie auch schon nach der Eingabe einer einzigen Zahl rechnen, nämlich bei allen Operationen mit nur einem Operanden – Quadratwurzel, Fakultät, Betrag und so weiter.

Ein Grund dafür, dass die Steuerung so arbeitet, ist folgender: Die Rechenarbeit soll ganz von der Klasse Calculator übernommen werden. Denn da schlägt die Stunde der Schüler.


3. Die Klasse Calculator und Unterklassen dazu

Die Klasse Calculator – beziehungsweise eine eigene Unterklasse dazu – ist die Klasse, mit der Schüler fast ausschließlich arbeiten. Sie enthält alle Rechenmethoden, die der Taschenrechner beherrscht. Über die muss man sich natürlich vorher verständigen, schon mal, damit es genügend Knöpfe dafür gibt. Da wären die Grundrechenarten, aber auch Wurzel, Potenzierung, Prozent, Betrag, Kehrwert und was es noch alles gibt. Ich habe auch noch ein paar exotische Sachen ergänzt (Collatz, Fibonacci, Primzahltest, größter gemeinsamer Teiler), auch wenn wir erst später im Schuljahr darauf zurückkommen werden:

taschenrechner_calculator

Im Klassendiagramm sind die Methoden alphabetisch sortiert, den Schülern muss man eine Liste mit einer anderen Reihenfolge vorgeben! Meine Liste war – leider erst am Ende der Sequenz – sortiert nach:

  • Einfach: Grundrechenarten (addieren, subtrahieren, multiplizieren, dividieren)
  • Leicht: negation, kehrwert, hochDrei, quadrat, prozent (wobei wir uns erst mal einigen mussten, was diese Prozenttaste bewirken soll)
  • Mit bedingter Anweisung: betrag
  • Mit while-Schleife: potenz. modulo, fakultaet, summeVonBis

Und so weiter. Die Schüler arbeiteten dann in ihrem eigenen Tempo und in ihrer eigenen Geschwindigkeit an diesen Methoden. Denn darum ging es eigentlich vor allem: Einführung in die Algorithmik und Kontrollstruktoren. Nur: ohne den graphischen Taschenrechnerkrimskrams drumherum macht das den Schülern viel weniger Spaß. Einige kamen nicht sehr weit über die Grundrechenarten hinaus, die meisten kamen bis Fakultät/Potenz, andere schlugen bei Wikipedia nach und fanden Lösungen für Wurzel und Sinus/Cosinus heraus. Die hatte ich nur aufgenommen, weil der GUI-Programmierer die vorgegeben hatte. Später im Jahr werde ich dann noch auf einige der exotischeren Methoden zurückkommen.

(Zur Klasse Taschenrechner: Die Klasse Calculator enthält zwar alle Methoden, aber sie funktionieren noch nicht richtig. Standardmäßig kommt dabei immer 99 heraus. Aufgabe der Schüler ist es, eine Unterklasse zu Calculator zu programmieren und die Methoden der Oberklasse durch ihre eigenen, verbesserten Methoden zu überschreiben. Sinnvoller wäre es natürlich gewesen, die Klasse Calculator als Interfache anzulegen. Aber dann müssten die Schüler immer wieder in den Code des Interface, um auszukommentieren, was sie noch nicht verbessert haben. Deshalb habe ich mich für diese eigentlich unelegante Lösung entschieden.)


4. Der Rest

Die Klasse Starter legt je ein Objekt der Klassen GUI, Steuerung und Calculator-Unterklasse an und macht sie miteinander bekannt. Sie enthält außerdem die main-Methode, mit der man den Taschenrechner auch außerhalb von BlueJ als echtes kleines Java-Programm unter Windows, Mac oder Linux laufen lassen kann.


Ziel der Sequenz: Einführung in Algorithmik und Programmierung. Daneben schon mal ein Vorgeschmack auf Vererbung und Referenzattribute. Außerdem sehen die Schüler bereits das objektorientierte Prinzip der Arbeitsteilung in Klassen angewendet. Gute Schüler können sich an ein GUI wagen, alle machen die algorithmisch interessanten Rechenmethoden, und der Verwaltungskram der Steuerung bleibt den Schülern verborgen.

Download des ganzen BlueJ-Projekts mit zwei Arbeitsblättern dazu.

(Fortsetzung morgen.)

Interactive Fiction in der Schule

Ich glaube, ich habe da etwas entdeckt, das mir viel Spaß machen wird. Über Text Adventures/Interactive Fiction habe ich ja vor ein paar Tagen geschrieben. Im Englischunterricht habe ich auch schon gelegentlich eine Zork-Stunde eingeschoben, und mit einer Unterstufenklasse, die ich in Informatik und Englisch hatte, habe ich selber mit dem Schreiben experimentiert.

Aber da geht noch mehr.

Einmal für den Literatur- und Fremdsprachenunterricht. Es gibt tolle Spiele: Manchmal muss man viele Rätsel lösen; bei anderen Spielen geht es darum, das historische New York kennenzulernen. Man schlüpft in die Rollen von Papageien oder Kleinkindern im Krabbelalter, mit entsprechend eingeschränkten Möglichkeiten, die Umwelt zu beeinflussen. Andere Werke sind Kurzgeschichten, paradoxe Parabeln und Verwirrspiele, avantgardistische Textexperimente. Auf Deutsch ist die Auswahl an Texten geringer, aber prinzipiell ist das gleiche möglich.

(Bald merkt man: Die Spiele leben nicht von den Rätseln, sondern von der Atmosphäre. Die wird anders erzeugt als in herkömmlicher Epik, ein paar Sätze reichen meist zur Beschreibung. Die Qualität des Schreibens zeigt sich auch darin, wie sehr die Erwartungen und Vermutungen des Spieler-Lesers vorausgeahnt werden; hier wird gleich unmittelbar auf die Reader-Response reagiert.)

Zum anderen kann man das Schreiben solcher Texte – vielleicht – für den Informatikunterricht nutzen. Geschrieben wird Interactive Fiction meist in eigenen, objektorientierten Programmiersprachen. In Inform 6 legt man ein Objekt so an:

Object Staff_Room "Staff Room"
     with
          description "A room for all the staff to meet and sit 
                and get a cup of coffee.",
          n_to hallway,
     has light;

Das sieht doch schon mal nach einer richtigen Programmiersprache aus. Aber in der Informatik geht es ja gar nicht so ums Programmieren. Es gibt auch Ansätze, informatische Konzepte ohne Programmiersprache zu lehren, zum Beispiel in einer Programmierumgebung, die ganz ohne Code und die entsprechenden Syntaxfehler auskommt, in der die Lernenden nur mit Drag-and-Drop arbeiten.

Eine andere Möglichkeit könnte Inform 7 sein. Da sehen die Zeilen Code, mit denen man den gleichen Raum wie oben erzeugt, so aus:

The Staff Room is a lighted room. "A room for all the staff to meet and sit and get a cup of coffee." North of the Staff Room is the Hallway.

Einfacher Inform-7-Code ist leicht zu schreiben, weil Inform 7 der natürlichen Sprache Englisch so nahe kommt wie wohl keine andere Programmiersprache. Deswegen lässt sich der Code auch sehr leicht lesen. Anspruchsvoller Inform-7-Code ist aus genau diesem Grund wohl schwerer zu schreiben, als man denkt. Zu sehr ist man versucht, einfach normales Englisch zu verwenden und übersieht dabei, dass Inform 7 trotz allem vielen Beschränkungen unterliegt. Aber dafür kann man sehr knapp und elegant formulieren:

Instead of a suspicious person (called the suspect) burning something which is evidence against the suspect when the number of people in the location is at least two, try the suspect going a random valid direction.

(Beispiel aus der pdf-Fassung von Ron Newcombs Inform 7 for Programmers.)

So komplexe Regeln für das Verhalten der Spielwelt wird man in der Schule kaum brauchen. Aber Zustandsautomaten gehen ganz schön, und die macht man zum Beispiel in der 10. Klasse. Da programmiert man zum Beispiel einen Aufzug mit drei Stockwerken/Zuständen. In Inform 7 legt man zuerst den Aufzug und die Knöpfe an, damit man in der Spielwelt auch etwas tun kann:

The elevator is an enterable, transparent container in the basement. It is not portable. The description is "An elevator with an up and a down button."
The up button is a thing in the elevator. It is scenery. The description is "An arrow pointing upwards."
The down button is a thing in the elevator. It is scenery. The description is "An arrow pointing downwards."
The elevator has a number called zustand. The zustand of the elevator is 1.

Und dann kommen die Regeln für die Zustandsübergänge:

Instead of pushing the up button when the player is in the elevator:
if the zustand of the elevator is 0:
now the zustand of the elevator is 1;
say "Going up. (Ground floor.)";
now the elevator is in the ground floor;
otherwise if the zustand of the elevator is 1:
now the zustand of the elevator is 2;
say "Going up. (First floor.)";
now the elevator is in the first floor;
otherwise:
say "Nothing happens."

Instead of pushing the down button when the player is in the elevator:
if the zustand of the elevator is 2:
now the zustand of the elevator is 1;
say "Going down. (Ground floor.)";
now the elevator is in the ground floor;
otherwise if the zustand of the elevator is 1:
now the zustand of the elevator is 0;
say "Going down. (Basement.)";
now the elevator is in the basement;
otherwise:
say "Nothing happens."

Eigentlich müssten die Knöpfe nicht nur im Aufzug sein, sondern auch außen. Aber das ist ja erst mal nur ein einfaches Modell.

Was auch noch gut geht mit Inform: Objekte, Attribute, Klassen, Vererbung, Datentypen; Modellierung, Relationen. Was vermutlich nicht so gut geht: Algorithmik, aber da bin ich noch am Herumprobieren.

Ich habe mal ein paar Seiten erstellt, die ich als Ausgangspunkt für meine Untersuchung von Inform 7 für die Schule nehmen möchte. Dort auch Links zu allem möglichen.

Bislang habe ich mit einer 10. Klasse zwischendurch mal Spiele in Inform 7 geschrieben; bisher ist nur ein kurzes Spiel online, von mir redigiert; ich hoffe, dass die anderen vor dem Schuljahresende auch fertig werden (von den Schülern selber noch redigiert).

Processing

Bei Zurück in die Schule gefunden: Processing, eine Java-Programmierumgebung, mit der man Bilder erzeugen kann. Processing ist eine Lernumgebung und Einführung in das (Java-)Programmieren. Man kann damit einerseits voll objektorientiert schreiben, andererseits kann man genauso gut ohne Objektkrams die vorhanden Methoden benutzen, deren Überbau wunderschön transparent ist.

(Fußnote: Transparent heißt überall anders soviel wie: „Durchsichtig, so dass man ins Innere blicken und die Zusammenhänge verstehen kann.“ In der Informatik heißt transparent allerdings: „Durchsichtig, so dass man hindurchschaut und nichts sieht, also quasi unsichtbar und vor leicht zu verwirrenden Augen verborgen.“)

Man kann mit Processing neue Bilder zeichnen oder bestehende Bilder bearbeiten. Das kann man statisch machen oder dynamisch: dann werden daraus bewegte Bilder, entweder automatisch oder durch den Benutzer mit Maus oder Tastatur gesteuert. So kann man auch ganze Simulationen entwerfen, wenn man möchte. Man kann sich auch eine Methode schreiben, um die ausgegebenen Bilder zu speichern, die sieht so aus:

void mousePressed() {
  save("bild.jpg");
}

Viel einfacher geht es wirklich nicht.

Ich wollte aber Filter schreiben, so wie man sie aus Bildbearbeitungsprogrammen kennt. Hier sind ein paar davon. Die Vorgehensweise ist meist die: Man lädt erst einmal das Originalbild in den Speicher und legt eine – noch leere – Zeichenfläche im gleichen Format an. Dann schaut man sich der Reihe nach jeden Pixel des Ursprungsbildes an, merkt sich dessen Farbe (bzw. den Rot-, Grün-, Blauanteil davon), verändert diese Farbe, und schreibt an dieselbe Position auf der Zeichenfläche einen Pixel mit der neuen Farbe.

1. Hier ein einfaches Weichzeichnen, das erste Bild ist das Original:

Man ändert dabei jede Farbe so, dass man sich von einem Pixel und allen seinen umliegenden Nachbarpixeln (im ersten Beispiel nur die direkt umliegenden, im zweiten auch die in etwas weiterem Abstand) die Durchschnittsfarbe ausrechnet und diese dem Pixel zuweist. Das macht man mit allen Pixeln so und heraus kommt eine Weichzeichnung.

2. Hier eine Gammakorrektur. Die dient zu einer differenzierten Aufhellung oder Abdunklung von Bildern. Dabei wird nicht jeder Pixel im gleichen Maß heller oder dunkler gemacht, sondern es werden zum Beispiel die dunklen Pixel mehr aufgehellt als die (ja eh schon hellen) helleren. Im ersten Bild mit gamma=0.5, im zweiten gamma = 1.5:

Hier sind einem die Nachbarn egal. Man wendet einfach auf den Rot-, Grün-, Blauteil jedes Pixels die überraschend einfache Funktion an:

farbeneu = (farbealt/255)gamma * 255

Die Zahl 255 kommt daher, weil es für jeden Farbton 255 Möglichkeiten gibt. Der Wert des ursprünglichen Blauanteils (von 0-255) wird durch 255 geteilt, womit man diesen Anteil auf eine Zahl zwischen 0 und 1 normalisiert hat. Das wird dann mit dem Gammawert potenziert (bzw. je nach Definition auch dessen Kehrwert) und dann mit dem letzten Faktor wieder auf den ursprünglichen Raum (zwischen 0 und 255) gestreckt.

3. Gemischte weitere Filter:

Der erste ist ein einfaches Schärfen: Man schaut sich wieder die Rot-, Grün- Blauwerte eines Pixels und seiner Nachbarn an und errechnet daraus wieder einen Durchschnitt. Allerdings werden vor der Berechnung die Nachbarn und der Pixel selber noch gewichtet: die Werte der 8 unmittelbaren Nachbarn werden zum Beispiel jeweils um 1 reduziert, die des zentralen Pixels um 9 erhöht – die Durchschnittswerte bleiben also gleich (das Bild wird insgesamt nicht heller oder dunkler), aber mit Betonung des Zentrums.

Der zweite zeichnet einfach an jede n-te Stelle des Bildes einen Kreis mit Durchmesser n von der Farbe des Pixels, der sich im Originalbild an dieser Stelle befindet.

Der dritte ist ein Mosaik. Man könnte zwar, ähnlich wie bei den Ellipsen, an jede n-te Stelle des Bildes ein Quadrat zeichnen, aber so wollte ich das nicht machen. Jeder Pixel sollte extra gezeichnet werden. Ich machte mir dazu folgende Skizze:

Der erste Pixel in der Reihe (in der 0-Spalte) sei zum Beispiel rot. Die beiden Pixel rechts daneben sollten dessen Farbe annehmen. Die Pixel in den Spalten 3-7 sollten die Farbe des Pixels in Spalte 5 annehmen, und so weiter. (Für die y-Koordinate analog, das habe ich bald gemerkt.)

Weil ich in Mathe nicht gut bin, zeichnete ich mir eine Tabelle auf: links die Position des Pixels, rechts die Position des Pixels, dessen Farbe angenommen werden sollte. f(linkeSpalte) = rechteSpalte. Der Rest ist einfach nur Rechnen. Mathekönner sehen das durch Überlegen, ich habe halt so lange herumgepfuscht, bis ich die entsprechende Funktion hatte. Die musste ich dann noch etwas verallgemeinern, damit sie nicht nur für die Rechnung mit den Mosaiksteinchen von Seitenlänge 5, sondern für beliebige Seitenlängen gilt. Sieht dann so aus:

xZentrumspixel = (x+size/2)/size*size bzw.
yZentrumspixel = (y+size/2)/size*size,

wobei size die Seitenlänge des Mosaiksteins ist. Und nein, das /size und *size kann man nicht einfach kürzen, da x eine Ganzzahl und die Divison in diesem Fall eine Ganzzahldivision ist – es wird immer abgerundet, der Rest verworfen.

Processing gibt’s für alle gängigen Betriebssystem, läuft unter Windows auch ohne Installationsrechte. Tutorials gibt es dort auch ein paar.

***

Anhang: So sieht ein vollständiger Sketch in Processing aus. Java-Code, ohne Klassendefinitionen, besteht aus 1 Attribut und den Methoden setup() und draw() und der Berechnungsmethode für das Mosaik, mosaik().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
PImage img; //Platz fuer das im Speicher gehaltene Bild
 
//einmaliges Aufrufen am Anfang
void setup() {
  img = loadImage("test.jpg"); //Laden des Bildes
  size(img.width, img.height); //Groesse der Zeichenflaeche
}
 
//das eigentliche Zeichnen
void draw() {
  //Pixel-Feld zur Verfuegung stellen
  loadPixels();
  //Zaehlschleife fuer alle Pixel mit x- und y-Koordinate
  for (int x = 0; x < img.width; x++) {
    for (int y = 0; y < img.height; y++ ) {
      //Berechnen der neuen Farbe - hier koennte man auch andere Methoden aufrufen
      color c = mosaik(x, y, 9);
      //Umrechnen der Koordinaten in Index des eindimensionalen Pixel-Felds
      int loc = x + y*img.width;
      //Aendern des Pixels im Pixel-Feld
      pixels[loc] = c;
    }
  }
  //Zeichnen aller Pixel
  updatePixels();
}
 
 
//Methode zur Farbberechnung beim Mosaik
color mosaik(int x, int y, int groesse) {
  //Koordinaten des Zentrums ermitteln
  int xZentrum = (x+groesse/2)/groesse*groesse;
  int yZentrum = (y+groesse/2)/groesse*groesse;
 
  //Umrechnen der Koordinaten in Index des eindimensionalen Pixel-Felds
  int loc = xZentrum + yZentrum*img.width;
 
  //sicher stellen, dass Bildgrenzen nicht ueberschritten werden
 loc = constrain(loc, 0, img.pixels.length-1);
 
  //Rot-, Gruen-, Blauanteile des Zentrumspixels speichern
  float rtotal = red(img.pixels[loc]);
  float gtotal = green(img.pixels[loc]);
  float btotal = blue(img.pixels[loc]);           
 
  // Rueckgabe der neuen Farbe
  return color(rtotal, gtotal, btotal);
}

Zustandsautomaten in der 10. Klasse

Erst etwas Theorie, später gibt es etwas zu sehen.

In der 10. Klasse entwirft und programmiert man einfache Zustandsautomaten. Die sehen auf dem Papier gerne mal so aus:

Der Automat (hier ein Fahrstuhl) kann sich in verschiedenen Zuständen befinden. Er beginnt im Zustand Erdgeschoss (deshalb zeigt da ein Pfeil hin). Es gibt noch zwei weitere Zustände, Keller und 1. Stock. Der Automat kann seinen Zustand ändern, das sind die Pfeile zwischen den Zuständen. Wenn der Automat im Zustand „Erdgeschoss“ ist und die Aktion „Pfeil nach oben drücken“ eintritt, dann springt der Automat in den Zustand „1. Stock“.

Es geht aber auch noch komplizierter:

In diesem Automaten geht es um ein Marsmännchen, das im Zustand Mars (Nr. 4) beginnt. Je nach Aktion (j für Jupiter, p für Pluto, w für Weltall und so weiter) springt das Marsmännchen in einen neuen Zustand, wenn dieser Zustandsübergang laut Diagramm möglich ist.
Allerdings gibt es noch zwei Feinheiten:
1. Für manche Zustandsübergänge gibt es eine Bedingung, die erfüllt sein muss. Diese Bedingungen sind in rot angegeben. Das Marsmännchen hat nämlich eine gewisse Sprungkraft, am Anfang 10. Vom Mars zum Jupiter springen kann es nur, wenn (neben der auslösenden Aktion j) seine Kraft mindestens 1 beträgt, sonst wird nichts daraus.
2. Und zuletzt gibt es manchmal, in dunkelgrün angegeben, noch weitere Aktionen, die neben dem Zustandsübergang ausgelöst werden. Im Fall vom Sprung von Mars zu Jupiter steht da etwa, dass sich die Kraft um 1 verringert, beim Sprung vom Weltall (Nr. 7) zum Mars (Nr. 4) sind es sogar 5 Punkte. Manche Reisen sind allerdings umsonst. Auftanken kann man nur auf dem Mond, wenn man den erreicht, wir die Kraft wieder auf 10 gesetzt. Wenn man irgendwo auf einem Planeten festsitzt und nicht genug Kraft hat um wegzukommen, ja, dann hat man Pech gehabt.

Einfacher ist das, wenn man es ausprobiert (Java-Applet, läuft also nicht überall):

Der Inhalt ist nicht verfügbar.
Bitte erlaube Cookies, indem du auf Übernehmen im Banner klickst.

Möglich sind die Eingaben: j, p, w (für Weltall), e, n (für Neumond), m und s – aber natürlich führen nicht alle immer zu einem Zustandsübergang.

Programmiert und gezeichnet haben den Marsmännchen-Automaten (abgesehen von der Ausgabe in einem Fenster, dazu später mehr) zwei Schülerinnen aus der 10. Klasse. Entstanden sind aber auch noch andere Automaten:

Der Inhalt ist nicht verfügbar.
Bitte erlaube Cookies, indem du auf Übernehmen im Banner klickst.

Der Inhalt ist nicht verfügbar.
Bitte erlaube Cookies, indem du auf Übernehmen im Banner klickst.

Weitere Automaten:

Programmiert haben die Schüler dabei nur den Automaten, und da vor allem die Zustandsübergangsmethode. Um die grafische Ausgabe habe ich mich gekümmert, und zwar so (siehe Eintrag zu MVC):


(Das ist kein Klassendiagramm, sondern die BlueJ-Oberfläche, gibt aber einen Eindruck der Verhältnisse wieder.)

  • Das Marsmännchen (oder was auch immer) hat eine Methode aktionEmpfangen(char). Je nach empfangener Aktion, abgekürzt durch einen einzelnen Buchstaben, ändert es seinen Zustand und teilt das daraufhin der Welt mit. Das Marsmännchen erbt nämlich vom Automaten auch die Sende-Fähigkeit.
  • Das Sekretariat (das auch ein Empfänger ist) empfängt die Nachricht über den neuen Zustand und wählt, dem Zustand entsprechend, eine neue Grafik aus, die dargestellt werden soll. Das ist die einzige Klasse, in der Schüler etwas schreiben müssen: die Namen der Grafiken.
  • Die Hauptarbeit der Darstellung übernimmt das Fenster. Der Fensterboss ist nur dazu da, damit man ein- und dasselbe Programm sowohl als Applet (also in einer Webseite) wie auch als eigenes Programm ausführen kann. Das Fenster stellt Textfelder und Knöpfe zur Verfügung. Wenn ein Knopf gedrückt wird, die Information und eventuell der Inhalt des Textfelds an die Steuerung.
  • Die Steuerung wertet die Eingabe aus. Standardmäßig werden nur Eingaben angenommen, die 1 Zeichen lang sind; alles andere führt zu einer Rückmeldung, dass etwas nicht stimmt. Dieses eine Zeichen wird dann an den Automaten, also das Marsmännchen, weitergeleitet, das daraufhin eventuell seinen Zustand ändert – und immer so weiter. (Man könnte die Steuerung auch zu einem echten Übersetzer machen: dann müsste der Benutzer ganze Wörter eintippen, also etwa „Gehe zum Jupiter“, und die Steuerung würde das in ein ‚j‘ übersetzen und das an den Automaten schicken.

Auf Interfaces (und Beobachtermuster) und Zustandsmodellierung mit eigenen Klassen habe ich verzichtet. Es reicht, wenn die Schüler in der 10. ein bisschen hineinschnuppern. Herunterladen kann man das BlueJ-Projekt hier (neue Version), es ist aber sehr spärlich kommentiert (auch die readme.txt lesen!), und im Fall des Fensters auch eher schlampig. GUIs interessieren mich wenig.
Wenn es nur um einfache Automaten ginge, könnte man den Schülern auch eine Benutzeroberfläche schreiben, wo sie nur ihre Bildernamen speichern und die Übergänge mit Mausklicks auswählen müssen, aber es geht ja auch darum, Programmierung zu üben.
Zustandsautomaten kann man immer mal brauchen. Aus einem Kommentar beim Kollegen embee habe den Hinweis auf die Rolle von Zustandsautomaten bei Comptuerspielen.

Wichtig war mir ansonsten auch, dass die Schüler ihr Produkt in einem kleinen Video vorstellen, auch wenn ich die nicht alle hier veröffentlichen darf.

Programmierprojekt in der Q11

Zum Ende der 11. Jahrgangsstufe müssen die Schüler im Informatik-Kurs an einem Projekt arbeiten. Dabei sollen die im Laufe des Jahres gelernten Datenstrukturen (Listen, Bäume) ebenso verwendet werden wie eine SQL-Datenbank, ansonsten ist man thematisch frei. Vorgeschlagen sind Sachen wie Reiseauskunft oder Kontoverwaltung, meine Schüler wollten etwas anderes machen.

Ich hatte zwei Gruppen. Die erste entwickelte ihr Kriegergame weiter, entstanden aus einer einfachen Übung zur Vererbung am Schuljahresanfang. Als Spiel simpel: zwei Rollenspielfiguren rüsten sich aus und hauen dann mit verschiedenen Methoden abwechseln aufeinander ein, bis einer verloren hat. Der Gewinner kriegt Geld und Erfahrungspunkte und kann sich mehr Ausrüstung kaufen; jeder Benutzer kann mehrere Spielfiguren haben, deren aktueller Zustand (Geld, Ausrüstung) in einer Datenbank gespeichert wird.

Kriegergame:
20 Klassen, davon 5 Interfaces
172 KB
~6190 Programmzeilen (2262 + GUI 3928), einschließlich javadoc und Leerzeilen

Programmiert wurde in Java in der Entwicklungsumgebung Eclipse; hier die grafische Darstellung der Klassen aus BlueJ:

Das Menü:

Der Kampf:

Der Shop:

Es gibt 5 verschiedene Charakterklassen (Hunter, Lich, Mage, Paladin, Tank), jeweils männlich oder weiblich; Ausrüstungsgegenstände; zum Teil animierte Angriffe, alles liebevoll grafisch aufbereitet. Überhaupt hat es Schülern die Grafik angetan, der größte Teil der Programmierarbeit entfiel auf die aufwendige Benutzeroberfläche. Mich selbst interessiert die am wenigsten, und fitzelig zu programmieren ist sie auch. Aber wenn’s Spaß macht.

Die andere Gruppe programmierte das Quiz „Wer wird Abiturient?“:

Quiz:
13 Klassen, davon 5 Interfaces
101 KB
~2863 Programmzeilen (1283 + GUI 1580), einschließlich javadoc und Leerzeilen

Auch hier wurde mit Eclipse gearbeitet; ein Überblick über die Klassen aus BlueJ:

Das Menü:

Eine erste Frage:

Nach den ersten sehr einfachen Fragen verlässt man die Grundschule und kann sich durch immer schwerere Fragen bis zum Abitur hocharbeiten. Die Fragen und Antworten und die Highscore-Liste sind jeweils in einer Datenbank gespeichert.

Bei beiden Projekten wurde mit den Entwurfsmustern Model-View-Controller und Beobachter gearbeitet. Insgesamt hatten die Schüler etwa neun Wochen Zeit, glaube ich.

Merken:

  • Je mehr Zeit man für das Projekt hat, desto besser. Wir hätten alle noch lange daran herumarbeiten können und wollen, ein paar erkannte Fehler sind noch drin und unerkannte sowieso. Eigentlich ist so etwas nichts für die letzten Wochen im Schuljahr, das müsste ein eigenes P-Seminar sein.
  • Das Arbeiten mit Datenbanken ist lästig. Zuerst hatte ich eine Datenbank im Web (wenn schon, denn schon), so dass die Schüler auch zu Hause daran arbeiten konnten. Das wäre für die Spiele auch schön gewesen, da es dadurch eine zentrale Benutzerverwaltung und eine zentrale Highscore-Liste gegeben hätte. Aber wenn man das Programm weitergibt, sind ja im Java-Quellcode die SQL-Zugangsdaten enthalten, und die will man nun mal nicht öffentlich haben. (Aus dem Bytecode wieder lesbaren Quellcode zu generieren, ist wohl recht leicht, wenn man nicht zusätzliche Verschlüsselungsschritte unternimmt.)
    Also hätte ein Java-Client auf den Server gemusst, der die Zugangsdaten verwaltet, nur dass bei mir kein Java läuft. Also dann doch eine lokal gespeicherte Datenbank. Microsoft Access ging recht schnell auch wenn manche Java-Versionen den Treiber bereits mitbringen, andere nicht. Einen Treiber für Open Office Base zu finden, dauerte lange, gelang aber doch. Nur dass das Open-Office-Format ein Zip-Format ist, auf dem Java nicht unmittelbar arbeiten kann – also müsste die .odb-Datei erst entpackt, dann bearbeitet, dann wieder gepackt werden, weil man nur im gepackten Zustand dann wieder mit Open-Office-Base darauf zugreifen kann.
  • Ich muss mir noch viel öfter Entwürfe zeigen lassen. Inzwischen ist StarUML auf unseren Rechnern installiert, damit geht das besser. Gefahr und Versuchung sind groß, dann doch einfach mal drauflos zu programmieren. Also: mehr Lenkung vor den Programmierphasen. Aber diese Sammelstunden kosten wieder Zeit.
  • Spiele sind eine gute Idee. Da kommen grafische Fähigkeiten zum Einsatz, und wer nicht gerne programmiert, kann Quizfragen heraussuchen und in die SQL-Datei eintippen. Irgendwas ist für jeden dabei.
  • Es ist ein fruchtloses Unterfangen, Schüler dazu bringen zu wollen, sich weniger auf die grafische Benutzeroberfläche zu konzentrieren.
  • Wichtig für die Arbeitsteilung: die Aufgaben müssen irgendwo im Web liegen, und die Schüler müssen sie selbst verwalten. Projektplanungssoftware wäre schön, aber es geht auch mit einem gemeinsamen GoogleDocs-Dokument:

    Schön, beim Mitlesen zwischendrin so Mitteilungen zu finden wie:

    !!Wichtig: Die Itemnamen dürfen maximal
    so lang sein wie „Sichel des Unterweltherschers“!!

  • Noten: Noten gab es keine darauf. Ich kann bei zwei derartig umfangreichen Projekten als nicht wirklich eingebundener Lehrer nicht mehr sinnvoll benoten. Eine Gesamtnote wäre möglich, die sich die Schüler dann untereinander aufteilen. Aber bei abiturrelevanten Noten wäre ich da sehr vorsichtig, am Ende führt das noch zu Streit. Aber es geht ja auch wunderbar ohne Noten.

Nachtrag: Jetzt auch als Video.

Der Inhalt ist nicht verfügbar.
Bitte erlaube Cookies, indem du auf Übernehmen im Banner klickst.

Der Inhalt ist nicht verfügbar.
Bitte erlaube Cookies, indem du auf Übernehmen im Banner klickst.

(Fortsetzung bei Youtube.)